[PATCH v1 2/2] PCI: PM: Resume bus after putting the bridge into D0 entirely
From: Rafael J. Wysocki
Date: Mon Apr 04 2022 - 11:42:42 EST
From: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
It is rather counter-intuitive to attempt to resume devices on a bus
segment before completing a transition of their parent bridge into
D0, so do that when the transition is complete.
This matters especially when the transition in question is not
successful, in which case it doesn't make sense to even try to
resume the child devices at all.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
---
drivers/pci/pci.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
Index: linux-pm/drivers/pci/pci.c
===================================================================
--- linux-pm.orig/drivers/pci/pci.c
+++ linux-pm/drivers/pci/pci.c
@@ -1310,15 +1310,24 @@ static int pci_dev_wait(struct pci_dev *
int pci_power_up(struct pci_dev *dev)
{
pci_power_t old_state = dev->current_state;
+ int ret;
pci_platform_power_transition(dev, PCI_D0);
+ /*
+ * For transitions from D3hot or deeper (including unknown), force
+ * PCI_PM_CTRL register write, D3*->D0 transition delay and BARS
+ * restoration.
+ */
+ if (old_state >= PCI_D3hot)
+ dev->current_state = PCI_D3hot;
+ ret = pci_raw_set_power_state(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) {
+ if (!ret && dev->runtime_d3cold) {
/*
* When powering on a bridge from D3cold, the whole hierarchy
* may be powered on into D0uninitialized state, resume them to
@@ -1327,15 +1336,7 @@ int pci_power_up(struct pci_dev *dev)
pci_resume_bus(dev->subordinate);
}
- /*
- * For transitions from D3hot or deeper and initial power-up, force
- * PCI_PM_CTRL register write, D3*->D0 transition delay and BARS
- * restoration.
- */
- if (old_state >= PCI_D3hot)
- dev->current_state = PCI_D3hot;
-
- return pci_raw_set_power_state(dev, PCI_D0);
+ return ret;
}
/**