Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: Re-enable Downstream Port LTR after reset or hotplug

Per PCIe r5.0, sec 7.5.3.16, Downstream Ports must disable LTR if the link
goes down (the Port goes DL_Down status). This is a problem because the
Downstream Port's dev->ltr_path is still set, so we think LTR is still
enabled, and we enable LTR in the Endpoint. When it sends LTR messages,
they cause Unsupported Request errors at the Downstream Port.

This happens in the reset path, where we may enable LTR in
pci_restore_pcie_state() even though the Downstream Port disabled LTR
because the reset caused a link down event.

It also happens in the hot-remove and hot-add path, where we may enable LTR
in pci_configure_ltr() even though the Downstream Port disabled LTR when
the hot-remove took the link down.

In these two scenarios, check the upstream bridge and restore its LTR
enable if appropriate.

The Unsupported Request may be logged by AER as follows:

pcieport 0000:00:1d.0: AER: Uncorrected (Non-Fatal) error received: id=00e8
pcieport 0000:00:1d.0: PCIe Bus Error: severity=Uncorrected (Non-Fatal), type=Transaction Layer, id=00e8(Requester ID)
pcieport 0000:00:1d.0: device [8086:9d18] error status/mask=00100000/00010000
pcieport 0000:00:1d.0: [20] Unsupported Request (First)

In addition, if LTR is not configured correctly, the link cannot enter the
L1.2 state, which prevents some machines from entering the S0ix low power
state.

[bhelgaas: commit log]
Link: https://lore.kernel.org/r/20211012075614.54576-1-mingchuang.qiao@mediatek.com
Reported-by: Utkarsh H Patel <utkarsh.h.patel@intel.com>
Signed-off-by: Mingchuang Qiao <mingchuang.qiao@mediatek.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>

authored by

Mingchuang Qiao and committed by
Bjorn Helgaas
e1b0d0bb e4e737bb

+41 -3
+25
drivers/pci/pci.c
··· 1477 1477 return 0; 1478 1478 } 1479 1479 1480 + void pci_bridge_reconfigure_ltr(struct pci_dev *dev) 1481 + { 1482 + #ifdef CONFIG_PCIEASPM 1483 + struct pci_dev *bridge; 1484 + u32 ctl; 1485 + 1486 + bridge = pci_upstream_bridge(dev); 1487 + if (bridge && bridge->ltr_path) { 1488 + pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2, &ctl); 1489 + if (!(ctl & PCI_EXP_DEVCTL2_LTR_EN)) { 1490 + pci_dbg(bridge, "re-enabling LTR\n"); 1491 + pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2, 1492 + PCI_EXP_DEVCTL2_LTR_EN); 1493 + } 1494 + } 1495 + #endif 1496 + } 1497 + 1480 1498 static void pci_restore_pcie_state(struct pci_dev *dev) 1481 1499 { 1482 1500 int i = 0; ··· 1504 1486 save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); 1505 1487 if (!save_state) 1506 1488 return; 1489 + 1490 + /* 1491 + * Downstream ports reset the LTR enable bit when link goes down. 1492 + * Check and re-configure the bit here before restoring device. 1493 + * PCIe r5.0, sec 7.5.3.16. 1494 + */ 1495 + pci_bridge_reconfigure_ltr(dev); 1507 1496 1508 1497 cap = (u16 *)&save_state->cap.data[0]; 1509 1498 pcie_capability_write_word(dev, PCI_EXP_DEVCTL, cap[i++]);
+1
drivers/pci/pci.h
··· 125 125 bool pci_bridge_d3_possible(struct pci_dev *dev); 126 126 void pci_bridge_d3_update(struct pci_dev *dev); 127 127 void pci_bridge_wait_for_secondary_bus(struct pci_dev *dev); 128 + void pci_bridge_reconfigure_ltr(struct pci_dev *dev); 128 129 129 130 static inline void pci_wakeup_event(struct pci_dev *dev) 130 131 {
+15 -3
drivers/pci/probe.c
··· 2168 2168 * Complex and all intermediate Switches indicate support for LTR. 2169 2169 * PCIe r4.0, sec 6.18. 2170 2170 */ 2171 - if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT || 2172 - ((bridge = pci_upstream_bridge(dev)) && 2173 - bridge->ltr_path)) { 2171 + if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) { 2172 + pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, 2173 + PCI_EXP_DEVCTL2_LTR_EN); 2174 + dev->ltr_path = 1; 2175 + return; 2176 + } 2177 + 2178 + /* 2179 + * If we're configuring a hot-added device, LTR was likely 2180 + * disabled in the upstream bridge, so re-enable it before enabling 2181 + * it in the new device. 2182 + */ 2183 + bridge = pci_upstream_bridge(dev); 2184 + if (bridge && bridge->ltr_path) { 2185 + pci_bridge_reconfigure_ltr(dev); 2174 2186 pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, 2175 2187 PCI_EXP_DEVCTL2_LTR_EN); 2176 2188 dev->ltr_path = 1;