PCI: Clear saved_state after the state has been restored
authorRafael J. Wysocki <rjw@sisk.pl>
Wed, 9 Sep 2009 21:49:59 +0000 (23:49 +0200)
committerJesse Barnes <jbarnes@virtuousgeek.org>
Mon, 14 Sep 2009 20:41:46 +0000 (13:41 -0700)
Some PCI devices fail if their standard configuration registers are
restored twice in a row.  Prevent this from happening by making
pci_restore_state() clear the saved_state flag of the device right
after the device's standard configuration registers have been
populated with the previously saved values.

Simplify PCI PM callbacks by removing the direct clearing of
state_saved from them, as it shouldn't be necessary any more (except
in pci_pm_thaw(), where it has to be cleared, so that the values saved
during the "freeze" phase of hibernation are not used later by mistake).

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
drivers/pci/pci-driver.c
drivers/pci/pci.c
drivers/pci/probe.c

index dbfc93cb5d011d52bae9c2aecb5ec3309139b1be..ffc15e97d11cd1765176489d12d8fa9cd9627df0 100644 (file)
@@ -445,8 +445,6 @@ static int pci_legacy_suspend(struct device *dev, pm_message_t state)
        struct pci_dev * pci_dev = to_pci_dev(dev);
        struct pci_driver * drv = pci_dev->driver;
 
-       pci_dev->state_saved = false;
-
        if (drv && drv->suspend) {
                pci_power_t prev = pci_dev->current_state;
                int error;
@@ -542,7 +540,6 @@ static int pci_restore_standard_config(struct pci_dev *pci_dev)
 static void pci_pm_default_resume_noirq(struct pci_dev *pci_dev)
 {
        pci_restore_standard_config(pci_dev);
-       pci_dev->state_saved = false;
        pci_fixup_device(pci_fixup_resume_early, pci_dev);
 }
 
@@ -608,8 +605,6 @@ static int pci_pm_suspend(struct device *dev)
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend(dev, PMSG_SUSPEND);
 
-       pci_dev->state_saved = false;
-
        if (!pm) {
                pci_pm_default_suspend(pci_dev);
                goto Fixup;
@@ -744,8 +739,6 @@ static int pci_pm_freeze(struct device *dev)
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend(dev, PMSG_FREEZE);
 
-       pci_dev->state_saved = false;
-
        if (!pm) {
                pci_pm_default_suspend(pci_dev);
                return 0;
@@ -821,6 +814,8 @@ static int pci_pm_thaw(struct device *dev)
                pci_pm_reenable_device(pci_dev);
        }
 
+       pci_dev->state_saved = false;
+
        return error;
 }
 
@@ -832,8 +827,6 @@ static int pci_pm_poweroff(struct device *dev)
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend(dev, PMSG_HIBERNATE);
 
-       pci_dev->state_saved = false;
-
        if (!pm) {
                pci_pm_default_suspend(pci_dev);
                goto Fixup;
index dcdfb2212ca38ed8e8b6ccf5a7dc8a4fdb6aad9d..6edecff0b41953a99b86c6edeb664325d7f14d90 100644 (file)
@@ -854,6 +854,7 @@ pci_restore_state(struct pci_dev *dev)
 
        if (!dev->state_saved)
                return 0;
+
        /* PCI Express register must be restored first */
        pci_restore_pcie_state(dev);
 
@@ -875,6 +876,8 @@ pci_restore_state(struct pci_dev *dev)
        pci_restore_msi_state(dev);
        pci_restore_iov_state(dev);
 
+       dev->state_saved = false;
+
        return 0;
 }
 
index 882383b61d301f49d933d06c8932f326639a6f47..8105e32117f67d8ce60317fb9a4151b305773434 100644 (file)
@@ -1032,6 +1032,9 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
        /* Fix up broken headers */
        pci_fixup_device(pci_fixup_header, dev);
 
+       /* Clear the state_saved flag. */
+       dev->state_saved = false;
+
        /* Initialize various capabilities */
        pci_init_capabilities(dev);