diff options
author | Mingchuang Qiao <mingchuang.qiao@mediatek.com> | 2021-10-12 15:56:14 +0800 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2021-10-19 15:57:44 -0500 |
commit | e1b0d0bb2032d18c7718168e670d8d3f31e552d7 (patch) | |
tree | 00368c636824f0872211ca0fd1304d78c5e78c06 /drivers/pci/probe.c | |
parent | e4e737bb5c170df6135a127739a9e6148ee3da82 (diff) | |
download | linux-e1b0d0bb2032d18c7718168e670d8d3f31e552d7.tar.gz linux-e1b0d0bb2032d18c7718168e670d8d3f31e552d7.tar.bz2 linux-e1b0d0bb2032d18c7718168e670d8d3f31e552d7.zip |
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>
Diffstat (limited to 'drivers/pci/probe.c')
-rw-r--r-- | drivers/pci/probe.c | 18 |
1 files changed, 15 insertions, 3 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index d9fc02a71baa..258350f80f6c 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2168,9 +2168,21 @@ static void pci_configure_ltr(struct pci_dev *dev) * Complex and all intermediate Switches indicate support for LTR. * PCIe r4.0, sec 6.18. */ - if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT || - ((bridge = pci_upstream_bridge(dev)) && - bridge->ltr_path)) { + if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) { + pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, + PCI_EXP_DEVCTL2_LTR_EN); + dev->ltr_path = 1; + return; + } + + /* + * If we're configuring a hot-added device, LTR was likely + * disabled in the upstream bridge, so re-enable it before enabling + * it in the new device. + */ + bridge = pci_upstream_bridge(dev); + if (bridge && bridge->ltr_path) { + pci_bridge_reconfigure_ltr(dev); pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_LTR_EN); dev->ltr_path = 1; |