Skip to content

Commit d3fcd73

Browse files
awilliambjorn-helgaas
authored andcommitted
PCI: Fix runtime PM race with PME polling
Testing that a device is not currently in a low power state provides no guarantees that the device is not imminently transitioning to such a state. Increment the PM usage counter before accessing the device. Since we don't wish to wake the device for PME polling, do so only if the device is already active by using pm_runtime_get_if_active(). Link: https://lore.kernel.org/r/20230803171233.3810944-3-alex.williamson@redhat.com Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
1 parent 5cd903b commit d3fcd73

File tree

1 file changed

+16
-7
lines changed

1 file changed

+16
-7
lines changed

drivers/pci/pci.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2415,25 +2415,34 @@ static void pci_pme_list_scan(struct work_struct *work)
24152415

24162416
mutex_lock(&pci_pme_list_mutex);
24172417
list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) {
2418-
if (pme_dev->dev->pme_poll) {
2419-
struct pci_dev *bridge;
2418+
struct pci_dev *pdev = pme_dev->dev;
2419+
2420+
if (pdev->pme_poll) {
2421+
struct pci_dev *bridge = pdev->bus->self;
2422+
struct device *dev = &pdev->dev;
2423+
int pm_status;
24202424

2421-
bridge = pme_dev->dev->bus->self;
24222425
/*
24232426
* If bridge is in low power state, the
24242427
* configuration space of subordinate devices
24252428
* may be not accessible
24262429
*/
24272430
if (bridge && bridge->current_state != PCI_D0)
24282431
continue;
2432+
24292433
/*
2430-
* If the device is in D3cold it should not be
2431-
* polled either.
2434+
* If the device is in a low power state it
2435+
* should not be polled either.
24322436
*/
2433-
if (pme_dev->dev->current_state == PCI_D3cold)
2437+
pm_status = pm_runtime_get_if_active(dev, true);
2438+
if (!pm_status)
24342439
continue;
24352440

2436-
pci_pme_wakeup(pme_dev->dev, NULL);
2441+
if (pdev->current_state != PCI_D3cold)
2442+
pci_pme_wakeup(pdev, NULL);
2443+
2444+
if (pm_status > 0)
2445+
pm_runtime_put(dev);
24372446
} else {
24382447
list_del(&pme_dev->list);
24392448
kfree(pme_dev);

0 commit comments

Comments
 (0)