PCI/PM: Resume subordinate bus in bus type callbacks
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 14 Apr 2022 13:04:13 +0000 (15:04 +0200)
committerBjorn Helgaas <bhelgaas@google.com>
Thu, 5 May 2022 19:19:45 +0000 (14:19 -0500)
Calling pci_resume_bus() on the secondary bus from pci_power_up() as it is
done now is questionable, because it depends on the mandatory bridge
power-up delays that are only covered by the PCI bus type PM callbacks.

For this reason, move the subordinate bus resume to those callbacks too and
use the observation that if a bridge is being powered-up during resume from
system-wide suspend, it may be still desirable to runtime-resume its
subordinate bus after completing the system-wide transition (in case the
resume of the devices on that bus is skipped during it).

Link: https://lore.kernel.org/r/3190097.aeNJFYEL58@kreacher
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
drivers/pci/pci-driver.c
drivers/pci/pci.c

index 608ce87d0d4889dbfdf2883b042241bacd45d4da..ee5868810a5bb83741f8d430cc63987e8b56deb7 100644 (file)
@@ -564,6 +564,17 @@ static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
        pci_pme_restore(pci_dev);
 }
 
+static void pci_pm_bridge_power_up_actions(struct pci_dev *pci_dev)
+{
+       pci_bridge_wait_for_secondary_bus(pci_dev);
+       /*
+        * When powering on a bridge from D3cold, the whole hierarchy may be
+        * powered on into D0uninitialized state, resume them to give them a
+        * chance to suspend again
+        */
+       pci_resume_bus(pci_dev->subordinate);
+}
+
 #endif /* CONFIG_PM */
 
 #ifdef CONFIG_PM_SLEEP
@@ -939,7 +950,7 @@ static int pci_pm_resume_noirq(struct device *dev)
        pcie_pme_root_status_cleanup(pci_dev);
 
        if (!skip_bus_pm && prev_state == PCI_D3cold)
-               pci_bridge_wait_for_secondary_bus(pci_dev);
+               pci_pm_bridge_power_up_actions(pci_dev);
 
        if (pci_has_legacy_pm_support(pci_dev))
                return 0;
@@ -1326,7 +1337,7 @@ static int pci_pm_runtime_resume(struct device *dev)
        pci_pm_default_resume(pci_dev);
 
        if (prev_state == PCI_D3cold)
-               pci_bridge_wait_for_secondary_bus(pci_dev);
+               pci_pm_bridge_power_up_actions(pci_dev);
 
        if (pm && pm->runtime_resume)
                error = pm->runtime_resume(dev);
index 9ecce435fb3f125abb5ba52455d4a6d2f40fdcdf..e6c7f48e8b072c67ed57a5e52ea6471112b0636f 100644 (file)
@@ -1310,21 +1310,6 @@ static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
 int pci_power_up(struct pci_dev *dev)
 {
        pci_platform_power_transition(dev, PCI_D0);
-
-       /*
-        * Mandatory power management transition delays are handled in
-        * pci_pm_resume_noirq() and pci_pm_runtime_resume() of the
-        * corresponding bridge.
-        */
-       if (dev->runtime_d3cold) {
-               /*
-                * When powering on a bridge from D3cold, the whole hierarchy
-                * may be powered on into D0uninitialized state, resume them to
-                * give them a chance to suspend again
-                */
-               pci_resume_bus(dev->subordinate);
-       }
-
        return pci_raw_set_power_state(dev, PCI_D0);
 }