Add PCI quirks for Apple Thunderbolt
svn path=/dists/sid/linux/; revision=22059
This commit is contained in:
parent
1372dfa284
commit
c5a1eeca82
|
@ -1,6 +1,9 @@
|
|||
linux (3.16.7-3) UNRELEASED; urgency=medium
|
||||
|
||||
* [x86] Enable THUNDERBOLT as module (Closes: #768653)
|
||||
* [x86] Complete Thunderbolt support on Apple computers (Closes: #768653)
|
||||
- PCI: Add pci_fixup_suspend_late quirk pass
|
||||
- PCI: Suspend/resume quirks for Apple thunderbolt
|
||||
- Enable THUNDERBOLT as module
|
||||
|
||||
-- Ben Hutchings <ben@decadent.org.uk> Sun, 09 Nov 2014 10:13:09 +0000
|
||||
|
||||
|
|
164
debian/patches/features/x86/apple-tb/pci-add-pci_fixup_suspend_late-quirk-pass.patch
vendored
Normal file
164
debian/patches/features/x86/apple-tb/pci-add-pci_fixup_suspend_late-quirk-pass.patch
vendored
Normal file
|
@ -0,0 +1,164 @@
|
|||
From: Andreas Noever <andreas.noever@gmail.com>
|
||||
Date: Tue, 3 Jun 2014 22:04:09 +0200
|
||||
Subject: [1/2] PCI: Add pci_fixup_suspend_late quirk pass
|
||||
Origin: https://git.kernel.org/linus/7d2a01b87f1682fde87461864e6682031bfaa0a9
|
||||
|
||||
Add pci_fixup_suspend_late as a new pci_fixup_pass. The pass is called
|
||||
from suspend_noirq and poweroff_noirq. Using the same pass for suspend
|
||||
and hibernate is consistent with resume_early which is called by
|
||||
resume_noirq and restore_noirq.
|
||||
|
||||
The new quirk pass is required for Thunderbolt support on Apple
|
||||
hardware.
|
||||
|
||||
Signed-off-by: Andreas Noever <andreas.noever@gmail.com>
|
||||
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
---
|
||||
drivers/pci/pci-driver.c | 18 ++++++++++++++----
|
||||
drivers/pci/quirks.c | 7 +++++++
|
||||
include/asm-generic/vmlinux.lds.h | 3 +++
|
||||
include/linux/pci.h | 12 +++++++++++-
|
||||
4 files changed, 35 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/pci/pci-driver.c
|
||||
+++ b/drivers/pci/pci-driver.c
|
||||
@@ -582,7 +582,7 @@ static int pci_legacy_suspend_late(struc
|
||||
WARN_ONCE(pci_dev->current_state != prev,
|
||||
"PCI PM: Device state not saved by %pF\n",
|
||||
drv->suspend_late);
|
||||
- return 0;
|
||||
+ goto Fixup;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -591,6 +591,9 @@ static int pci_legacy_suspend_late(struc
|
||||
|
||||
pci_pm_set_unknown_state(pci_dev);
|
||||
|
||||
+Fixup:
|
||||
+ pci_fixup_device(pci_fixup_suspend_late, pci_dev);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -734,7 +737,7 @@ static int pci_pm_suspend_noirq(struct d
|
||||
|
||||
if (!pm) {
|
||||
pci_save_state(pci_dev);
|
||||
- return 0;
|
||||
+ goto Fixup;
|
||||
}
|
||||
|
||||
if (pm->suspend_noirq) {
|
||||
@@ -751,7 +754,7 @@ static int pci_pm_suspend_noirq(struct d
|
||||
WARN_ONCE(pci_dev->current_state != prev,
|
||||
"PCI PM: State of device not saved by %pF\n",
|
||||
pm->suspend_noirq);
|
||||
- return 0;
|
||||
+ goto Fixup;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -775,6 +778,9 @@ static int pci_pm_suspend_noirq(struct d
|
||||
if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI)
|
||||
pci_write_config_word(pci_dev, PCI_COMMAND, 0);
|
||||
|
||||
+Fixup:
|
||||
+ pci_fixup_device(pci_fixup_suspend_late, pci_dev);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -999,8 +1005,10 @@ static int pci_pm_poweroff_noirq(struct
|
||||
if (pci_has_legacy_pm_support(to_pci_dev(dev)))
|
||||
return pci_legacy_suspend_late(dev, PMSG_HIBERNATE);
|
||||
|
||||
- if (!drv || !drv->pm)
|
||||
+ if (!drv || !drv->pm) {
|
||||
+ pci_fixup_device(pci_fixup_suspend_late, pci_dev);
|
||||
return 0;
|
||||
+ }
|
||||
|
||||
if (drv->pm->poweroff_noirq) {
|
||||
int error;
|
||||
@@ -1021,6 +1029,8 @@ static int pci_pm_poweroff_noirq(struct
|
||||
if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI)
|
||||
pci_write_config_word(pci_dev, PCI_COMMAND, 0);
|
||||
|
||||
+ pci_fixup_device(pci_fixup_suspend_late, pci_dev);
|
||||
+
|
||||
if (pcibios_pm_ops.poweroff_noirq)
|
||||
return pcibios_pm_ops.poweroff_noirq(dev);
|
||||
|
||||
--- a/drivers/pci/quirks.c
|
||||
+++ b/drivers/pci/quirks.c
|
||||
@@ -3038,6 +3038,8 @@ extern struct pci_fixup __start_pci_fixu
|
||||
extern struct pci_fixup __end_pci_fixups_resume_early[];
|
||||
extern struct pci_fixup __start_pci_fixups_suspend[];
|
||||
extern struct pci_fixup __end_pci_fixups_suspend[];
|
||||
+extern struct pci_fixup __start_pci_fixups_suspend_late[];
|
||||
+extern struct pci_fixup __end_pci_fixups_suspend_late[];
|
||||
|
||||
static bool pci_apply_fixup_final_quirks;
|
||||
|
||||
@@ -3083,6 +3085,11 @@ void pci_fixup_device(enum pci_fixup_pas
|
||||
end = __end_pci_fixups_suspend;
|
||||
break;
|
||||
|
||||
+ case pci_fixup_suspend_late:
|
||||
+ start = __start_pci_fixups_suspend_late;
|
||||
+ end = __end_pci_fixups_suspend_late;
|
||||
+ break;
|
||||
+
|
||||
default:
|
||||
/* stupid compiler warning, you would think with an enum... */
|
||||
return;
|
||||
--- a/include/asm-generic/vmlinux.lds.h
|
||||
+++ b/include/asm-generic/vmlinux.lds.h
|
||||
@@ -268,6 +268,9 @@
|
||||
VMLINUX_SYMBOL(__start_pci_fixups_suspend) = .; \
|
||||
*(.pci_fixup_suspend) \
|
||||
VMLINUX_SYMBOL(__end_pci_fixups_suspend) = .; \
|
||||
+ VMLINUX_SYMBOL(__start_pci_fixups_suspend_late) = .; \
|
||||
+ *(.pci_fixup_suspend_late) \
|
||||
+ VMLINUX_SYMBOL(__end_pci_fixups_suspend_late) = .; \
|
||||
} \
|
||||
\
|
||||
/* Built-in firmware blobs */ \
|
||||
--- a/include/linux/pci.h
|
||||
+++ b/include/linux/pci.h
|
||||
@@ -1483,8 +1483,9 @@ enum pci_fixup_pass {
|
||||
pci_fixup_final, /* Final phase of device fixups */
|
||||
pci_fixup_enable, /* pci_enable_device() time */
|
||||
pci_fixup_resume, /* pci_device_resume() */
|
||||
- pci_fixup_suspend, /* pci_device_suspend */
|
||||
+ pci_fixup_suspend, /* pci_device_suspend() */
|
||||
pci_fixup_resume_early, /* pci_device_resume_early() */
|
||||
+ pci_fixup_suspend_late, /* pci_device_suspend_late() */
|
||||
};
|
||||
|
||||
/* Anonymous variables would be nice... */
|
||||
@@ -1525,6 +1526,11 @@ enum pci_fixup_pass {
|
||||
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend, \
|
||||
suspend##hook, vendor, device, class, \
|
||||
class_shift, hook)
|
||||
+#define DECLARE_PCI_FIXUP_CLASS_SUSPEND_LATE(vendor, device, class, \
|
||||
+ class_shift, hook) \
|
||||
+ DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend_late, \
|
||||
+ suspend_late##hook, vendor, device, \
|
||||
+ class, class_shift, hook)
|
||||
|
||||
#define DECLARE_PCI_FIXUP_EARLY(vendor, device, hook) \
|
||||
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_early, \
|
||||
@@ -1550,6 +1556,10 @@ enum pci_fixup_pass {
|
||||
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend, \
|
||||
suspend##hook, vendor, device, \
|
||||
PCI_ANY_ID, 0, hook)
|
||||
+#define DECLARE_PCI_FIXUP_SUSPEND_LATE(vendor, device, hook) \
|
||||
+ DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend_late, \
|
||||
+ suspend_late##hook, vendor, device, \
|
||||
+ PCI_ANY_ID, 0, hook)
|
||||
|
||||
#ifdef CONFIG_PCI_QUIRKS
|
||||
void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
|
135
debian/patches/features/x86/apple-tb/pci-suspend-resume-quirks-for-apple-thunderbolt.patch
vendored
Normal file
135
debian/patches/features/x86/apple-tb/pci-suspend-resume-quirks-for-apple-thunderbolt.patch
vendored
Normal file
|
@ -0,0 +1,135 @@
|
|||
From: Andreas Noever <andreas.noever@gmail.com>
|
||||
Date: Tue, 3 Jun 2014 22:04:10 +0200
|
||||
Subject: [2/2] PCI: Suspend/resume quirks for Apple thunderbolt
|
||||
Origin: https://git.kernel.org/linus/1df5172c5c251ec24a1bd0f44fe38c841f384330
|
||||
|
||||
Add two quirks to support thunderbolt suspend/resume on Apple systems.
|
||||
We need to perform two different actions during suspend and resume:
|
||||
|
||||
The whole controller has to be powered down before suspend. If this is
|
||||
not done then the native host interface device will be gone after resume
|
||||
if a thunderbolt device was plugged in before suspending. The controller
|
||||
represents itself as multiple PCI devices/bridges. To power it down we
|
||||
hook into the upstream bridge of the controller and call the magic ACPI
|
||||
methods. Power will be restored automatically during resume (by the
|
||||
firmware presumably).
|
||||
|
||||
During resume we have to wait for the native host interface to
|
||||
reestablish all pci tunnels. Since there is no parent-child relationship
|
||||
between the NHI and the bridges we have to explicitly wait for them
|
||||
using device_pm_wait_for_dev. We do this in the resume_noirq phase of
|
||||
the downstream bridges of the controller (which lead into the
|
||||
thunderbolt tunnels).
|
||||
|
||||
Signed-off-by: Andreas Noever <andreas.noever@gmail.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
---
|
||||
drivers/pci/quirks.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 97 insertions(+)
|
||||
|
||||
--- a/drivers/pci/quirks.c
|
||||
+++ b/drivers/pci/quirks.c
|
||||
@@ -3006,6 +3006,103 @@ DECLARE_PCI_FIXUP_HEADER(0x1814, 0x0601,
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_REALTEK, 0x8169,
|
||||
quirk_broken_intx_masking);
|
||||
|
||||
+#ifdef CONFIG_ACPI
|
||||
+/*
|
||||
+ * Apple: Shutdown Cactus Ridge Thunderbolt controller.
|
||||
+ *
|
||||
+ * On Apple hardware the Cactus Ridge Thunderbolt controller needs to be
|
||||
+ * shutdown before suspend. Otherwise the native host interface (NHI) will not
|
||||
+ * be present after resume if a device was plugged in before suspend.
|
||||
+ *
|
||||
+ * The thunderbolt controller consists of a pcie switch with downstream
|
||||
+ * bridges leading to the NHI and to the tunnel pci bridges.
|
||||
+ *
|
||||
+ * This quirk cuts power to the whole chip. Therefore we have to apply it
|
||||
+ * during suspend_noirq of the upstream bridge.
|
||||
+ *
|
||||
+ * Power is automagically restored before resume. No action is needed.
|
||||
+ */
|
||||
+static void quirk_apple_poweroff_thunderbolt(struct pci_dev *dev)
|
||||
+{
|
||||
+ acpi_handle bridge, SXIO, SXFP, SXLV;
|
||||
+
|
||||
+ if (!dmi_match(DMI_BOARD_VENDOR, "Apple Inc."))
|
||||
+ return;
|
||||
+ if (pci_pcie_type(dev) != PCI_EXP_TYPE_UPSTREAM)
|
||||
+ return;
|
||||
+ bridge = ACPI_HANDLE(&dev->dev);
|
||||
+ if (!bridge)
|
||||
+ return;
|
||||
+ /*
|
||||
+ * SXIO and SXLV are present only on machines requiring this quirk.
|
||||
+ * TB bridges in external devices might have the same device id as those
|
||||
+ * on the host, but they will not have the associated ACPI methods. This
|
||||
+ * implicitly checks that we are at the right bridge.
|
||||
+ */
|
||||
+ if (ACPI_FAILURE(acpi_get_handle(bridge, "DSB0.NHI0.SXIO", &SXIO))
|
||||
+ || ACPI_FAILURE(acpi_get_handle(bridge, "DSB0.NHI0.SXFP", &SXFP))
|
||||
+ || ACPI_FAILURE(acpi_get_handle(bridge, "DSB0.NHI0.SXLV", &SXLV)))
|
||||
+ return;
|
||||
+ dev_info(&dev->dev, "quirk: cutting power to thunderbolt controller...\n");
|
||||
+
|
||||
+ /* magic sequence */
|
||||
+ acpi_execute_simple_method(SXIO, NULL, 1);
|
||||
+ acpi_execute_simple_method(SXFP, NULL, 0);
|
||||
+ msleep(300);
|
||||
+ acpi_execute_simple_method(SXLV, NULL, 0);
|
||||
+ acpi_execute_simple_method(SXIO, NULL, 0);
|
||||
+ acpi_execute_simple_method(SXLV, NULL, 0);
|
||||
+}
|
||||
+DECLARE_PCI_FIXUP_SUSPEND_LATE(PCI_VENDOR_ID_INTEL, 0x1547,
|
||||
+ quirk_apple_poweroff_thunderbolt);
|
||||
+
|
||||
+/*
|
||||
+ * Apple: Wait for the thunderbolt controller to reestablish pci tunnels.
|
||||
+ *
|
||||
+ * During suspend the thunderbolt controller is reset and all pci
|
||||
+ * tunnels are lost. The NHI driver will try to reestablish all tunnels
|
||||
+ * during resume. We have to manually wait for the NHI since there is
|
||||
+ * no parent child relationship between the NHI and the tunneled
|
||||
+ * bridges.
|
||||
+ */
|
||||
+static void quirk_apple_wait_for_thunderbolt(struct pci_dev *dev)
|
||||
+{
|
||||
+ struct pci_dev *sibling = NULL;
|
||||
+ struct pci_dev *nhi = NULL;
|
||||
+
|
||||
+ if (!dmi_match(DMI_BOARD_VENDOR, "Apple Inc."))
|
||||
+ return;
|
||||
+ if (pci_pcie_type(dev) != PCI_EXP_TYPE_DOWNSTREAM)
|
||||
+ return;
|
||||
+ /*
|
||||
+ * Find the NHI and confirm that we are a bridge on the tb host
|
||||
+ * controller and not on a tb endpoint.
|
||||
+ */
|
||||
+ sibling = pci_get_slot(dev->bus, 0x0);
|
||||
+ if (sibling == dev)
|
||||
+ goto out; /* we are the downstream bridge to the NHI */
|
||||
+ if (!sibling || !sibling->subordinate)
|
||||
+ goto out;
|
||||
+ nhi = pci_get_slot(sibling->subordinate, 0x0);
|
||||
+ if (!nhi)
|
||||
+ goto out;
|
||||
+ if (nhi->vendor != PCI_VENDOR_ID_INTEL
|
||||
+ || (nhi->device != 0x1547 && nhi->device != 0x156c)
|
||||
+ || nhi->subsystem_vendor != 0x2222
|
||||
+ || nhi->subsystem_device != 0x1111)
|
||||
+ goto out;
|
||||
+ dev_info(&dev->dev, "quirk: wating for thunderbolt to reestablish pci tunnels...\n");
|
||||
+ device_pm_wait_for_dev(&dev->dev, &nhi->dev);
|
||||
+out:
|
||||
+ pci_dev_put(nhi);
|
||||
+ pci_dev_put(sibling);
|
||||
+}
|
||||
+DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_INTEL, 0x1547,
|
||||
+ quirk_apple_wait_for_thunderbolt);
|
||||
+DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_INTEL, 0x156d,
|
||||
+ quirk_apple_wait_for_thunderbolt);
|
||||
+#endif
|
||||
+
|
||||
static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
|
||||
struct pci_fixup *end)
|
||||
{
|
|
@ -453,6 +453,8 @@ features/x86/apple-tb/0028-thunderbolt-select-CRC32-in-Kconfig.patch
|
|||
features/x86/apple-tb/0029-thunderbolt-Correct-the-size-argument-to-devm_kzallo.patch
|
||||
features/x86/apple-tb/0030-thunderbolt-Use-kcalloc.patch
|
||||
features/x86/apple-tb/0031-thunderbolt-Clear-hops-before-overwriting.patch
|
||||
features/x86/apple-tb/pci-add-pci_fixup_suspend_late-quirk-pass.patch
|
||||
features/x86/apple-tb/pci-suspend-resume-quirks-for-apple-thunderbolt.patch
|
||||
|
||||
# Add iwlwifi firmware monitor from 3.17
|
||||
features/all/iwlwifi-debug/iwlwifi-add-device-firmware-to-fw-error-dump-file.patch
|
||||
|
|
Loading…
Reference in New Issue