aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci.c
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2021-11-05 11:28:42 -0500
committerBjorn Helgaas <bhelgaas@google.com>2021-11-05 11:28:42 -0500
commit5e19196c142f040a7d99bcc1540e2052c68231e8 (patch)
tree1888883b3d1171a426b68e49a624d5d8890e55c7 /drivers/pci/pci.c
parentMerge branch 'pci/acpi' (diff)
parentPCI: Re-enable Downstream Port LTR after reset or hotplug (diff)
downloadlinux-dev-5e19196c142f040a7d99bcc1540e2052c68231e8.tar.xz
linux-dev-5e19196c142f040a7d99bcc1540e2052c68231e8.zip
Merge branch 'pci/aspm'
- Re-enable LTR in Downstream Ports after it has been disabled by reset or hotplug to allow use of ASPM L1.2 again and prevent Unsupported Request errors when Endpoint sends LTR messages (Mingchuang Qiao) * pci/aspm: PCI: Re-enable Downstream Port LTR after reset or hotplug
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r--drivers/pci/pci.c25
1 files changed, 25 insertions, 0 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index ce2ab62b64cf..17e4341df0ff 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1477,6 +1477,24 @@ static int pci_save_pcie_state(struct pci_dev *dev)
return 0;
}
+void pci_bridge_reconfigure_ltr(struct pci_dev *dev)
+{
+#ifdef CONFIG_PCIEASPM
+ struct pci_dev *bridge;
+ u32 ctl;
+
+ bridge = pci_upstream_bridge(dev);
+ if (bridge && bridge->ltr_path) {
+ pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2, &ctl);
+ if (!(ctl & PCI_EXP_DEVCTL2_LTR_EN)) {
+ pci_dbg(bridge, "re-enabling LTR\n");
+ pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2,
+ PCI_EXP_DEVCTL2_LTR_EN);
+ }
+ }
+#endif
+}
+
static void pci_restore_pcie_state(struct pci_dev *dev)
{
int i = 0;
@@ -1487,6 +1505,13 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
if (!save_state)
return;
+ /*
+ * Downstream ports reset the LTR enable bit when link goes down.
+ * Check and re-configure the bit here before restoring device.
+ * PCIe r5.0, sec 7.5.3.16.
+ */
+ pci_bridge_reconfigure_ltr(dev);
+
cap = (u16 *)&save_state->cap.data[0];
pcie_capability_write_word(dev, PCI_EXP_DEVCTL, cap[i++]);
pcie_capability_write_word(dev, PCI_EXP_LNKCTL, cap[i++]);