PCI PM: Introduce device flag wakeup_prepared
Rafael J. Wysocki [Tue, 8 Sep 2009 21:14:49 +0000 (23:14 +0200)]
Introduce a new PCI device flag, wakeup_prepared, to prevent PCI
wake-up preparation code from being executed twice in a row for the
same device and for the same purpose.

Reviewed-by: Matthew Garrett <mjg59@srcf.ucam.org>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>

drivers/pci/pci.c
include/linux/pci.h

index 84a6d6d..dcdfb22 100644 (file)
@@ -1225,6 +1225,10 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable)
        if (enable && !device_may_wakeup(&dev->dev))
                return -EINVAL;
 
+       /* Don't do the same thing twice in a row for one device. */
+       if (!!enable == !!dev->wakeup_prepared)
+               return 0;
+
        /*
         * According to "PCI System Architecture" 4th ed. by Tom Shanley & Don
         * Anderson we should be doing PME# wake enable followed by ACPI wake
@@ -1241,9 +1245,12 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable)
                error = platform_pci_sleep_wake(dev, true);
                if (ret)
                        ret = error;
+               if (!ret)
+                       dev->wakeup_prepared = true;
        } else {
                platform_pci_sleep_wake(dev, false);
                pci_pme_active(dev, false);
+               dev->wakeup_prepared = false;
        }
 
        return ret;
@@ -1365,6 +1372,7 @@ void pci_pm_init(struct pci_dev *dev)
        int pm;
        u16 pmc;
 
+       dev->wakeup_prepared = false;
        dev->pm_cap = 0;
 
        /* find PCI PM capability in list */
index d80ed87..f5c7cd3 100644 (file)
@@ -241,6 +241,7 @@ struct pci_dev {
        unsigned int    d1_support:1;   /* Low power state D1 is supported */
        unsigned int    d2_support:1;   /* Low power state D2 is supported */
        unsigned int    no_d1d2:1;      /* Only allow D0 and D3 */
+       unsigned int    wakeup_prepared:1;
 
 #ifdef CONFIG_PCIEASPM
        struct pcie_link_state  *link_state;    /* ASPM link state. */