Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3ad3f8ce authored by Qiang's avatar Qiang Committed by Bjorn Helgaas
Browse files

PCI/PME: Handle invalid data when reading Root Status



PCIe PME and native hotplug share the same interrupt number, so hotplug
interrupts are also processed by PME.  In some cases, e.g., a Link Down
interrupt, a device may be present but unreachable, so when we try to
read its Root Status register, the read fails and we get all ones data
(0xffffffff).

Previously, we interpreted that data as PCI_EXP_RTSTA_PME being set, i.e.,
"some device has asserted PME," so we scheduled pcie_pme_work_fn().  This
caused an infinite loop because pcie_pme_work_fn() tried to handle PME
requests until PCI_EXP_RTSTA_PME is cleared, but with the link down,
PCI_EXP_RTSTA_PME can't be cleared.

Check for the invalid 0xffffffff data everywhere we read the Root Status
register.

1469d17d ("PCI: pciehp: Handle invalid data when reading from
non-existent devices") added similar checks in the hotplug driver.

Signed-off-by: default avatarQiang Zheng <zhengqiang10@huawei.com>
[bhelgaas: changelog, also check in pcie_pme_work_fn(), use "~0" to follow
other similar checks]
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
parent 4113b0e6
Loading
Loading
Loading
Loading
+4 −1
Original line number Original line Diff line number Diff line
@@ -226,6 +226,9 @@ static void pcie_pme_work_fn(struct work_struct *work)
			break;
			break;


		pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta);
		pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta);
		if (rtsta == (u32) ~0)
			break;

		if (rtsta & PCI_EXP_RTSTA_PME) {
		if (rtsta & PCI_EXP_RTSTA_PME) {
			/*
			/*
			 * Clear PME status of the port.  If there are other
			 * Clear PME status of the port.  If there are other
@@ -273,7 +276,7 @@ static irqreturn_t pcie_pme_irq(int irq, void *context)
	spin_lock_irqsave(&data->lock, flags);
	spin_lock_irqsave(&data->lock, flags);
	pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta);
	pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta);


	if (!(rtsta & PCI_EXP_RTSTA_PME)) {
	if (rtsta == (u32) ~0 || !(rtsta & PCI_EXP_RTSTA_PME)) {
		spin_unlock_irqrestore(&data->lock, flags);
		spin_unlock_irqrestore(&data->lock, flags);
		return IRQ_NONE;
		return IRQ_NONE;
	}
	}