Skip to content

Commit 4828149

Browse files
computersforpeaceSasha Levin
authored andcommitted
PCI/PM: Prevent runtime suspend until devices are fully initialized
[ Upstream commit 51c0996 ] Previously, it was possible for a PCI device to be runtime-suspended before it was fully initialized. When that happened, the suspend process could save invalid device state, for example, before BAR assignment. Restoring the invalid state during resume may leave the device non-functional. Prevent runtime suspend for PCI devices until they are fully initialized by deferring pm_runtime_enable(). More details on how exactly this may occur: 1. PCI device is created by pci_scan_slot() or similar 2. As part of pci_scan_slot(), pci_pm_init() puts the device in D0 and prevents runtime suspend prevented via pm_runtime_forbid() 3. pci_device_add() adds the underlying 'struct device' via device_add(), which means user space can allow runtime suspend, e.g., echo auto > /sys/bus/pci/devices/.../power/control 4. PCI device receives BAR configuration (pci_assign_unassigned_bus_resources(), etc.) 5. pci_bus_add_device() applies final fixups, saves device state, and tries to attach a driver The device may potentially be suspended between qualcomm-linux#3 and qualcomm-linux#5, so this is racy with user space (udev or similar). Many PCI devices are enumerated at subsys_initcall time and so will not race with user space, but devices created later by hotplug or modular pwrctrl or host controller drivers are susceptible to this race. More runtime PM details at the first Link: below. Link: https://lore.kernel.org/all/0e35a4e1-894a-47c1-9528-fc5ffbafd9e2@samsung.com/ Signed-off-by: Brian Norris <briannorris@chromium.org> [bhelgaas: update comments per https://lore.kernel.org/r/CAJZ5v0iBNOmMtqfqEbrYyuK2u+2J2+zZ-iQd1FvyCPjdvU2TJg@mail.gmail.com] Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260122094815.v5.1.I60a53c170a8596661883bd2b4ef475155c7aa72b@changeid Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent d6e866f commit 4828149

2 files changed

Lines changed: 15 additions & 1 deletion

File tree

drivers/pci/bus.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/of.h>
1515
#include <linux/of_platform.h>
1616
#include <linux/platform_device.h>
17+
#include <linux/pm_runtime.h>
1718
#include <linux/proc_fs.h>
1819
#include <linux/slab.h>
1920

@@ -378,6 +379,13 @@ void pci_bus_add_device(struct pci_dev *dev)
378379
put_device(&pdev->dev);
379380
}
380381

382+
/*
383+
* Enable runtime PM, which potentially allows the device to
384+
* suspend immediately, only after the PCI state has been
385+
* configured completely.
386+
*/
387+
pm_runtime_enable(&dev->dev);
388+
381389
if (!dn || of_device_is_available(dn))
382390
pci_dev_allow_binding(dev);
383391

drivers/pci/pci.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3225,8 +3225,14 @@ void pci_pm_init(struct pci_dev *dev)
32253225
poweron:
32263226
pci_pm_power_up_and_verify_state(dev);
32273227
pm_runtime_forbid(&dev->dev);
3228+
3229+
/*
3230+
* Runtime PM will be enabled for the device when it has been fully
3231+
* configured, but since its parent and suppliers may suspend in
3232+
* the meantime, prevent them from doing so by changing the
3233+
* device's runtime PM status to "active".
3234+
*/
32283235
pm_runtime_set_active(&dev->dev);
3229-
pm_runtime_enable(&dev->dev);
32303236
}
32313237

32323238
static unsigned long pci_ea_flags(struct pci_dev *dev, u8 prop)

0 commit comments

Comments
 (0)