[PATCH v3 1/9] PCI/PM: Resume subordinate bus in bus type callbacks

From: Rafael J. Wysocki
Date: Thu Apr 14 2022 - 10:00:35 EST


From: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>

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).

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
Reviewed-by: Mika Westerberg <mika.westerberg@xxxxxxxxxxxxxxx>
---

v1 -> v3:
* Added R-by from Mika.

---
drivers/pci/pci-driver.c | 15 +++++++++++++--
drivers/pci/pci.c | 15 ---------------
2 files changed, 13 insertions(+), 17 deletions(-)

Index: linux-pm/drivers/pci/pci-driver.c
===================================================================
--- linux-pm.orig/drivers/pci/pci-driver.c
+++ linux-pm/drivers/pci/pci-driver.c
@@ -559,6 +559,17 @@ static void pci_pm_default_resume_early(
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

#ifdef CONFIG_PM_SLEEP
@@ -934,7 +945,7 @@ static int pci_pm_resume_noirq(struct de
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;
@@ -1321,7 +1332,7 @@ static int pci_pm_runtime_resume(struct
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: linux-pm/drivers/pci/pci.c
===================================================================
--- linux-pm.orig/drivers/pci/pci.c
+++ linux-pm/drivers/pci/pci.c
@@ -1310,21 +1310,6 @@ static int pci_dev_wait(struct pci_dev *
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);
}