diff --git a/debian/changelog b/debian/changelog index 53071ae63..a2658a028 100644 --- a/debian/changelog +++ b/debian/changelog @@ -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 Sun, 09 Nov 2014 10:13:09 +0000 diff --git a/debian/patches/features/x86/apple-tb/pci-add-pci_fixup_suspend_late-quirk-pass.patch b/debian/patches/features/x86/apple-tb/pci-add-pci_fixup_suspend_late-quirk-pass.patch new file mode 100644 index 000000000..d0feb8813 --- /dev/null +++ b/debian/patches/features/x86/apple-tb/pci-add-pci_fixup_suspend_late-quirk-pass.patch @@ -0,0 +1,164 @@ +From: Andreas Noever +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 +Acked-by: Bjorn Helgaas +Signed-off-by: Greg Kroah-Hartman +--- + 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); diff --git a/debian/patches/features/x86/apple-tb/pci-suspend-resume-quirks-for-apple-thunderbolt.patch b/debian/patches/features/x86/apple-tb/pci-suspend-resume-quirks-for-apple-thunderbolt.patch new file mode 100644 index 000000000..8c05a5cf3 --- /dev/null +++ b/debian/patches/features/x86/apple-tb/pci-suspend-resume-quirks-for-apple-thunderbolt.patch @@ -0,0 +1,135 @@ +From: Andreas Noever +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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) + { diff --git a/debian/patches/series b/debian/patches/series index c8e9da709..3a949bff1 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -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