Patch "PCI: Fix active state requirement in PME polling" has been added to the 6.6-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    PCI: Fix active state requirement in PME polling

to the 6.6-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     pci-fix-active-state-requirement-in-pme-polling.patch
and it can be found in the queue-6.6 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit b1a86f1dcf68fc3fa015b77a1b3ebc1f0ae1ae60
Author: Alex Williamson <alex.williamson@xxxxxxxxxx>
Date:   Tue Jan 23 11:55:31 2024 -0700

    PCI: Fix active state requirement in PME polling
    
    [ Upstream commit 41044d5360685e78a869d40a168491a70cdb7e73 ]
    
    The commit noted in fixes added a bogus requirement that runtime PM managed
    devices need to be in the RPM_ACTIVE state for PME polling.  In fact, only
    devices in low power states should be polled.
    
    However there's still a requirement that the device config space must be
    accessible, which has implications for both the current state of the polled
    device and the parent bridge, when present.  It's not sufficient to assume
    the bridge remains in D0 and cases have been observed where the bridge
    passes the D0 test, but the PM state indicates RPM_SUSPENDING and config
    space of the polled device becomes inaccessible during pci_pme_wakeup().
    
    Therefore, since the bridge is already effectively required to be in the
    RPM_ACTIVE state, formalize this in the code and elevate the PM usage count
    to maintain the state while polling the subordinate device.
    
    This resolves a regression reported in the bugzilla below where a
    Thunderbolt/USB4 hierarchy fails to scan for an attached NVMe endpoint
    downstream of a bridge in a D3hot power state.
    
    Link: https://lore.kernel.org/r/20240123185548.1040096-1-alex.williamson@xxxxxxxxxx
    Fixes: d3fcd7360338 ("PCI: Fix runtime PM race with PME polling")
    Reported-by: Sanath S <sanath.s@xxxxxxx>
    Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218360
    Signed-off-by: Alex Williamson <alex.williamson@xxxxxxxxxx>
    Signed-off-by: Bjorn Helgaas <bhelgaas@xxxxxxxxxx>
    Tested-by: Sanath S <sanath.s@xxxxxxx>
    Reviewed-by: Rafael J. Wysocki <rafael@xxxxxxxxxx>
    Cc: Lukas Wunner <lukas@xxxxxxxxx>
    Cc: Mika Westerberg <mika.westerberg@xxxxxxxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 59d6cb1a3a9d..06fc6f532d6c 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2434,29 +2434,36 @@ static void pci_pme_list_scan(struct work_struct *work)
 		if (pdev->pme_poll) {
 			struct pci_dev *bridge = pdev->bus->self;
 			struct device *dev = &pdev->dev;
-			int pm_status;
+			struct device *bdev = bridge ? &bridge->dev : NULL;
+			int bref = 0;
 
 			/*
-			 * If bridge is in low power state, the
-			 * configuration space of subordinate devices
-			 * may be not accessible
+			 * If we have a bridge, it should be in an active/D0
+			 * state or the configuration space of subordinate
+			 * devices may not be accessible or stable over the
+			 * course of the call.
 			 */
-			if (bridge && bridge->current_state != PCI_D0)
-				continue;
+			if (bdev) {
+				bref = pm_runtime_get_if_active(bdev, true);
+				if (!bref)
+					continue;
+
+				if (bridge->current_state != PCI_D0)
+					goto put_bridge;
+			}
 
 			/*
-			 * If the device is in a low power state it
-			 * should not be polled either.
+			 * The device itself should be suspended but config
+			 * space must be accessible, therefore it cannot be in
+			 * D3cold.
 			 */
-			pm_status = pm_runtime_get_if_active(dev, true);
-			if (!pm_status)
-				continue;
-
-			if (pdev->current_state != PCI_D3cold)
+			if (pm_runtime_suspended(dev) &&
+			    pdev->current_state != PCI_D3cold)
 				pci_pme_wakeup(pdev, NULL);
 
-			if (pm_status > 0)
-				pm_runtime_put(dev);
+put_bridge:
+			if (bref > 0)
+				pm_runtime_put(bdev);
 		} else {
 			list_del(&pme_dev->list);
 			kfree(pme_dev);




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux