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
This commit is contained in:
Bjorn Helgaas
2021-11-05 11:28:42 -05:00
3 changed files with 41 additions and 3 deletions

View File

@@ -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++]);

View File

@@ -125,6 +125,7 @@ void pci_msix_init(struct pci_dev *dev);
bool pci_bridge_d3_possible(struct pci_dev *dev);
void pci_bridge_d3_update(struct pci_dev *dev);
void pci_bridge_wait_for_secondary_bus(struct pci_dev *dev);
void pci_bridge_reconfigure_ltr(struct pci_dev *dev);
static inline void pci_wakeup_event(struct pci_dev *dev)
{

View File

@@ -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;