]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/pci/pci-driver.c
PCI: PM: Avoid possible suspend-to-idle issue
[mirror_ubuntu-bionic-kernel.git] / drivers / pci / pci-driver.c
index 89e950d05297578b85bdfc46aae903454e39d3c6..2a35d16959be02c5fe463f920fd2967b516be427 100644 (file)
@@ -722,6 +722,8 @@ static int pci_pm_suspend(struct device *dev)
        struct pci_dev *pci_dev = to_pci_dev(dev);
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 
+       pci_dev->skip_bus_pm = false;
+
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend(dev, PMSG_SUSPEND);
 
@@ -815,7 +817,20 @@ static int pci_pm_suspend_noirq(struct device *dev)
                }
        }
 
-       if (!pci_dev->state_saved) {
+       if (pci_dev->skip_bus_pm) {
+               /*
+                * The function is running for the second time in a row without
+                * going through full resume, which is possible only during
+                * suspend-to-idle in a spurious wakeup case.  Moreover, the
+                * device was originally left in D0, so its power state should
+                * not be changed here and the device register values saved
+                * originally should be restored on resume again.
+                */
+               pci_dev->state_saved = true;
+       } else if (pci_dev->state_saved) {
+               if (pci_dev->current_state == PCI_D0)
+                       pci_dev->skip_bus_pm = true;
+       } else {
                pci_save_state(pci_dev);
                if (pci_power_manageable(pci_dev))
                        pci_prepare_to_sleep(pci_dev);