aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAndreas Noever <andreas.noever@gmail.com>2014-06-03 16:04:10 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-06-19 17:12:26 -0400
commit1df5172c5c251ec24a1bd0f44fe38c841f384330 (patch)
tree6ef651bcd83df4201b74178a617f6da5a57fe7d3 /drivers
parent7d2a01b87f1682fde87461864e6682031bfaa0a9 (diff)
PCI: Suspend/resume quirks for Apple thunderbolt
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/quirks.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 03266af20d5f..ca8a171f9689 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -2986,6 +2986,103 @@ DECLARE_PCI_FIXUP_HEADER(0x1814, 0x0601, /* Ralink RT2800 802.11n PCI */
2986DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_REALTEK, 0x8169, 2986DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_REALTEK, 0x8169,
2987 quirk_broken_intx_masking); 2987 quirk_broken_intx_masking);
2988 2988
2989#ifdef CONFIG_ACPI
2990/*
2991 * Apple: Shutdown Cactus Ridge Thunderbolt controller.
2992 *
2993 * On Apple hardware the Cactus Ridge Thunderbolt controller needs to be
2994 * shutdown before suspend. Otherwise the native host interface (NHI) will not
2995 * be present after resume if a device was plugged in before suspend.
2996 *
2997 * The thunderbolt controller consists of a pcie switch with downstream
2998 * bridges leading to the NHI and to the tunnel pci bridges.
2999 *
3000 * This quirk cuts power to the whole chip. Therefore we have to apply it
3001 * during suspend_noirq of the upstream bridge.
3002 *
3003 * Power is automagically restored before resume. No action is needed.
3004 */
3005static void quirk_apple_poweroff_thunderbolt(struct pci_dev *dev)
3006{
3007 acpi_handle bridge, SXIO, SXFP, SXLV;
3008
3009 if (!dmi_match(DMI_BOARD_VENDOR, "Apple Inc."))
3010 return;
3011 if (pci_pcie_type(dev) != PCI_EXP_TYPE_UPSTREAM)
3012 return;
3013 bridge = ACPI_HANDLE(&dev->dev);
3014 if (!bridge)
3015 return;
3016 /*
3017 * SXIO and SXLV are present only on machines requiring this quirk.
3018 * TB bridges in external devices might have the same device id as those
3019 * on the host, but they will not have the associated ACPI methods. This
3020 * implicitly checks that we are at the right bridge.
3021 */
3022 if (ACPI_FAILURE(acpi_get_handle(bridge, "DSB0.NHI0.SXIO", &SXIO))
3023 || ACPI_FAILURE(acpi_get_handle(bridge, "DSB0.NHI0.SXFP", &SXFP))
3024 || ACPI_FAILURE(acpi_get_handle(bridge, "DSB0.NHI0.SXLV", &SXLV)))
3025 return;
3026 dev_info(&dev->dev, "quirk: cutting power to thunderbolt controller...\n");
3027
3028 /* magic sequence */
3029 acpi_execute_simple_method(SXIO, NULL, 1);
3030 acpi_execute_simple_method(SXFP, NULL, 0);
3031 msleep(300);
3032 acpi_execute_simple_method(SXLV, NULL, 0);
3033 acpi_execute_simple_method(SXIO, NULL, 0);
3034 acpi_execute_simple_method(SXLV, NULL, 0);
3035}
3036DECLARE_PCI_FIXUP_SUSPEND_LATE(PCI_VENDOR_ID_INTEL, 0x1547,
3037 quirk_apple_poweroff_thunderbolt);
3038
3039/*
3040 * Apple: Wait for the thunderbolt controller to reestablish pci tunnels.
3041 *
3042 * During suspend the thunderbolt controller is reset and all pci
3043 * tunnels are lost. The NHI driver will try to reestablish all tunnels
3044 * during resume. We have to manually wait for the NHI since there is
3045 * no parent child relationship between the NHI and the tunneled
3046 * bridges.
3047 */
3048static void quirk_apple_wait_for_thunderbolt(struct pci_dev *dev)
3049{
3050 struct pci_dev *sibling = NULL;
3051 struct pci_dev *nhi = NULL;
3052
3053 if (!dmi_match(DMI_BOARD_VENDOR, "Apple Inc."))
3054 return;
3055 if (pci_pcie_type(dev) != PCI_EXP_TYPE_DOWNSTREAM)
3056 return;
3057 /*
3058 * Find the NHI and confirm that we are a bridge on the tb host
3059 * controller and not on a tb endpoint.
3060 */
3061 sibling = pci_get_slot(dev->bus, 0x0);
3062 if (sibling == dev)
3063 goto out; /* we are the downstream bridge to the NHI */
3064 if (!sibling || !sibling->subordinate)
3065 goto out;
3066 nhi = pci_get_slot(sibling->subordinate, 0x0);
3067 if (!nhi)
3068 goto out;
3069 if (nhi->vendor != PCI_VENDOR_ID_INTEL
3070 || (nhi->device != 0x1547 && nhi->device != 0x156c)
3071 || nhi->subsystem_vendor != 0x2222
3072 || nhi->subsystem_device != 0x1111)
3073 goto out;
3074 dev_info(&dev->dev, "quirk: wating for thunderbolt to reestablish pci tunnels...\n");
3075 device_pm_wait_for_dev(&dev->dev, &nhi->dev);
3076out:
3077 pci_dev_put(nhi);
3078 pci_dev_put(sibling);
3079}
3080DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_INTEL, 0x1547,
3081 quirk_apple_wait_for_thunderbolt);
3082DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_INTEL, 0x156d,
3083 quirk_apple_wait_for_thunderbolt);
3084#endif
3085
2989static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, 3086static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
2990 struct pci_fixup *end) 3087 struct pci_fixup *end)
2991{ 3088{