PCI: Do not poll for PME if the device is in D3cold [Linux 4.9.187]

This Linux kernel change "PCI: Do not poll for PME if the device is in D3cold" is included in the Linux 4.9.187 release. This change is authored by Mika Westerberg <mika.westerberg [at] linux.intel.com> on Wed Jun 12 13:57:39 2019 +0300. The commit for this change in Linux stable tree is 27639ae (patch) which is from upstream commit 000dd53. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream 000dd53.

PCI: Do not poll for PME if the device is in D3cold

commit 000dd5316e1c756a1c028f22e01d06a38249dd4d upstream.

PME polling does not take into account that a device that is directly
connected to the host bridge may go into D3cold as well. This leads to a
situation where the PME poll thread reads from a config space of a
device that is in D3cold and gets incorrect information because the
config space is not accessible.

Here is an example from Intel Ice Lake system where two PCIe root ports
are in D3cold (I've instrumented the kernel to log the PMCSR register
contents):

  [   62.971442] pcieport 0000:00:07.1: Check PME status, PMCSR=0xffff
  [   62.971504] pcieport 0000:00:07.0: Check PME status, PMCSR=0xffff

Since 0xffff is interpreted so that PME is pending, the root ports will
be runtime resumed. This repeats over and over again essentially
blocking all runtime power management.

Prevent this from happening by checking whether the device is in D3cold
before its PME status is read.

Fixes: 71a83bd727cc ("PCI/PM: add runtime PM support to PCIe port")
Signed-off-by: Mika Westerberg <[email protected]>
Reviewed-by: Lukas Wunner <[email protected]>
Cc: 3.6+ <[email protected]> # v3.6+
Signed-off-by: Rafael J. Wysocki <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

There are 7 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/pci/pci.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index ccbbd4c..a075337 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1786,6 +1786,13 @@ static void pci_pme_list_scan(struct work_struct *work)
             */
            if (bridge && bridge->current_state != PCI_D0)
                continue;
+           /*
+            * If the device is in D3cold it should not be
+            * polled either.
+            */
+           if (pme_dev->dev->current_state == PCI_D3cold)
+               continue;
+
            pci_pme_wakeup(pme_dev->dev, NULL);
        } else {
            list_del(&pme_dev->list);

Leave a Reply

Your email address will not be published. Required fields are marked *