Commit 730643d3 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki Committed by Bjorn Helgaas

PCI/PM: Resume subordinate bus in bus type callbacks

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@kreacherSigned-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
parent 9a605831
...@@ -564,6 +564,17 @@ static void pci_pm_default_resume_early(struct pci_dev *pci_dev) ...@@ -564,6 +564,17 @@ static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
pci_pme_restore(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 */ #endif /* CONFIG_PM */
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
...@@ -939,7 +950,7 @@ static int pci_pm_resume_noirq(struct device *dev) ...@@ -939,7 +950,7 @@ static int pci_pm_resume_noirq(struct device *dev)
pcie_pme_root_status_cleanup(pci_dev); pcie_pme_root_status_cleanup(pci_dev);
if (!skip_bus_pm && prev_state == PCI_D3cold) 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)) if (pci_has_legacy_pm_support(pci_dev))
return 0; return 0;
...@@ -1326,7 +1337,7 @@ static int pci_pm_runtime_resume(struct device *dev) ...@@ -1326,7 +1337,7 @@ static int pci_pm_runtime_resume(struct device *dev)
pci_pm_default_resume(pci_dev); pci_pm_default_resume(pci_dev);
if (prev_state == PCI_D3cold) 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) if (pm && pm->runtime_resume)
error = pm->runtime_resume(dev); error = pm->runtime_resume(dev);
......
...@@ -1310,21 +1310,6 @@ static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout) ...@@ -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) int pci_power_up(struct pci_dev *dev)
{ {
pci_platform_power_transition(dev, PCI_D0); 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); return pci_raw_set_power_state(dev, PCI_D0);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment