summaryrefslogtreecommitdiff
path: root/drivers/pci/pcie/aspm.c
diff options
context:
space:
mode:
authorStefan Mätje <stefan.maetje@esd.eu>2019-03-29 18:07:35 +0100
committerBjorn Helgaas <bhelgaas@google.com>2019-04-06 09:25:47 -0500
commit4ec73791a64bab25cabf16a6067ee478692e506d (patch)
tree0ef29a9ccbd480436332dd50bfbcdf60667dc008 /drivers/pci/pcie/aspm.c
parent86fa6a344209d9414ea962b1f1ac6ade9dd7563a (diff)
PCI: Work around Pericom PCIe-to-PCI bridge Retrain Link erratum
Due to an erratum in some Pericom PCIe-to-PCI bridges in reverse mode (conventional PCI on primary side, PCIe on downstream side), the Retrain Link bit needs to be cleared manually to allow the link training to complete successfully. If it is not cleared manually, the link training is continuously restarted and no devices below the PCI-to-PCIe bridge can be accessed. That means drivers for devices below the bridge will be loaded but won't work and may even crash because the driver is only reading 0xffff. See the Pericom Errata Sheet PI7C9X111SLB_errata_rev1.2_102711.pdf for details. Devices known as affected so far are: PI7C9X110, PI7C9X111SL, PI7C9X130. Add a new flag, clear_retrain_link, in struct pci_dev. Quirks for affected devices set this bit. Note that pcie_retrain_link() lives in aspm.c because that's currently the only place we use it, but this erratum is not specific to ASPM, and we may retrain links for other reasons in the future. Signed-off-by: Stefan Mätje <stefan.maetje@esd.eu> [bhelgaas: apply regardless of CONFIG_PCIEASPM] Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> CC: stable@vger.kernel.org
Diffstat (limited to 'drivers/pci/pcie/aspm.c')
-rw-r--r--drivers/pci/pcie/aspm.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 4fa37622ad66..38e7017478b5 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -205,6 +205,15 @@ static bool pcie_retrain_link(struct pcie_link_state *link)
pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &reg16);
reg16 |= PCI_EXP_LNKCTL_RL;
pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
+ if (parent->clear_retrain_link) {
+ /*
+ * Due to an erratum in some devices the Retrain Link bit
+ * needs to be cleared again manually to allow the link
+ * training to succeed.
+ */
+ reg16 &= ~PCI_EXP_LNKCTL_RL;
+ pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
+ }
/* Wait for link training end. Break out after waiting for timeout */
start_jiffies = jiffies;