PCI: Add pci_fixup_suspend_late quirk pass
authorAndreas Noever <andreas.noever@gmail.com>
Tue, 3 Jun 2014 20:04:09 +0000 (22:04 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 19 Jun 2014 21:08:41 +0000 (14:08 -0700)
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
drivers/pci/quirks.c
include/asm-generic/vmlinux.lds.h
include/linux/pci.h

index 3f8e3dbcaa7cbcc4d9cabb4b89685c56461f0a7d..d04c5adafc1655624a528fb1a77b5f49fbbc3472 100644 (file)
@@ -582,7 +582,7 @@ static int pci_legacy_suspend_late(struct device *dev, pm_message_t state)
                        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(struct device *dev, pm_message_t state)
 
        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 device *dev)
 
        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 device *dev)
                        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 device *dev)
        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 device *dev)
        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 device *dev)
        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);
 
index d0f69269eb6c4ced67b7ef688d20ff2bbd1f25cd..03266af20d5f238225958ddeb9084a7d96c734b4 100644 (file)
@@ -3018,6 +3018,8 @@ extern struct pci_fixup __start_pci_fixups_resume_early[];
 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;
 
@@ -3063,6 +3065,11 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
                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;
index 471ba48c7ae40608c540bfda459b33ae0f4bb3b7..47cd98656f9d2112600a651e6c4d3f0e1bed6aa7 100644 (file)
                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 */                                   \
index 466bcd111d85d80916af2f7592dec3c3c539e441..295d3a9d8ffe032e9d8cbaeb4659b643220c0fd6 100644 (file)
@@ -1477,8 +1477,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... */
@@ -1519,6 +1520,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,                     \
@@ -1544,6 +1550,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);