Skip to content

Commit 17369d7

Browse files
rafaeljwgregkh
authored andcommitted
PCI: Restore config space on runtime resume despite being unbound
[ Upstream commit 5775b84 ] We leave PCI devices not bound to a driver in D0 during runtime suspend. But they may have a parent which is bound and can be transitioned to D3cold at runtime. Once the parent goes to D3cold, the unbound child may go to D3cold as well. When the child goes to D3cold, its internal state, including configuration of BARs, MSI, ASPM, MPS, etc., is lost. One example are recent hybrid graphics laptops which cut power to the discrete GPU when the root port above it goes to ACPI power state D3. Users may provoke this by unbinding the GPU driver and allowing runtime PM on the GPU via sysfs: The PM core will then treat the GPU as "suspended", which in turn allows the root port to runtime suspend, causing the power resources listed in its _PR3 object to be powered off. The GPU's BARs will be uninitialized when a driver later probes it. Another example are hybrid graphics laptops where the GPU itself (rather than the root port) is capable of runtime suspending to D3cold. If the GPU's integrated HDA controller is not bound and the GPU's driver decides to runtime suspend to D3cold, the HDA controller's BARs will be uninitialized when a driver later probes it. Fix by saving and restoring config space over a runtime suspend cycle even if the device is not bound. Acked-by: Bjorn Helgaas <[email protected]> Tested-by: Peter Wu <[email protected]> # Nvidia Optimus Tested-by: Lukas Wunner <[email protected]> # MacBook Pro Signed-off-by: Rafael J. Wysocki <[email protected]> [lukas: add commit message, bikeshed code comments for clarity] Signed-off-by: Lukas Wunner <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/92fb6e6ae2730915eb733c08e2f76c6a313e3860.1520068884.git.lukas@wunner.de Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 6ab31bb commit 17369d7

File tree

1 file changed

+11
-6
lines changed

1 file changed

+11
-6
lines changed

drivers/pci/pci-driver.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,11 +1140,14 @@ static int pci_pm_runtime_suspend(struct device *dev)
11401140
int error;
11411141

11421142
/*
1143-
* If pci_dev->driver is not set (unbound), the device should
1144-
* always remain in D0 regardless of the runtime PM status
1143+
* If pci_dev->driver is not set (unbound), we leave the device in D0,
1144+
* but it may go to D3cold when the bridge above it runtime suspends.
1145+
* Save its config space in case that happens.
11451146
*/
1146-
if (!pci_dev->driver)
1147+
if (!pci_dev->driver) {
1148+
pci_save_state(pci_dev);
11471149
return 0;
1150+
}
11481151

11491152
if (!pm || !pm->runtime_suspend)
11501153
return -ENOSYS;
@@ -1195,16 +1198,18 @@ static int pci_pm_runtime_resume(struct device *dev)
11951198
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
11961199

11971200
/*
1198-
* If pci_dev->driver is not set (unbound), the device should
1199-
* always remain in D0 regardless of the runtime PM status
1201+
* Restoring config space is necessary even if the device is not bound
1202+
* to a driver because although we left it in D0, it may have gone to
1203+
* D3cold when the bridge above it runtime suspended.
12001204
*/
1205+
pci_restore_standard_config(pci_dev);
1206+
12011207
if (!pci_dev->driver)
12021208
return 0;
12031209

12041210
if (!pm || !pm->runtime_resume)
12051211
return -ENOSYS;
12061212

1207-
pci_restore_standard_config(pci_dev);
12081213
pci_fixup_device(pci_fixup_resume_early, pci_dev);
12091214
__pci_enable_wake(pci_dev, PCI_D0, true, false);
12101215
pci_fixup_device(pci_fixup_resume, pci_dev);

0 commit comments

Comments
 (0)