Skip to content

Commit f68dea1

Browse files
maciej-w-rozyckikwilczynski
authored andcommitted
PCI: Revert to the original speed after PCIe failed link retraining
When `pcie_failed_link_retrain' has failed to retrain the link by hand it leaves the link speed restricted to 2.5GT/s, which will then affect any device that has been plugged in later on, which may not suffer from the problem that caused the speed restriction to have been attempted. Consequently such a downstream device will suffer from an unnecessary communication throughput limitation and therefore performance loss. Remove the speed restriction then and revert the Link Control 2 register to its original state if link retraining with the speed restriction in place has failed. Retrain the link again afterwards so as to remove any residual state, waiting on LT rather than DLLLA to avoid an excessive delay and ignoring the result as this training is supposed to fail anyway. Fixes: a89c822 ("PCI: Work around PCIe link training failures") Link: https://lore.kernel.org/linux-pci/alpine.DEB.2.21.2408251412590.30766@angie.orcam.me.uk Reported-by: Matthew W Carlis <mattc@purestorage.com> Link: https://lore.kernel.org/r/20240806000659.30859-1-mattc@purestorage.com/ Link: https://lore.kernel.org/r/20240722193407.23255-1-mattc@purestorage.com/ Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org> Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Cc: <stable@vger.kernel.org> # v6.5+
1 parent 8037ac0 commit f68dea1

1 file changed

Lines changed: 10 additions & 1 deletion

File tree

drivers/pci/quirks.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,18 @@
6666
* apply this erratum workaround to any downstream ports as long as they
6767
* support Link Active reporting and have the Link Control 2 register.
6868
* Restrict the speed to 2.5GT/s then with the Target Link Speed field,
69-
* request a retrain and wait 200ms for the data link to go up.
69+
* request a retrain and check the result.
7070
*
7171
* If this turns out successful and we know by the Vendor:Device ID it is
7272
* safe to do so, then lift the restriction, letting the devices negotiate
7373
* a higher speed. Also check for a similar 2.5GT/s speed restriction the
7474
* firmware may have already arranged and lift it with ports that already
7575
* report their data link being up.
7676
*
77+
* Otherwise revert the speed to the original setting and request a retrain
78+
* again to remove any residual state, ignoring the result as it's supposed
79+
* to fail anyway.
80+
*
7781
* Return TRUE if the link has been successfully retrained, otherwise FALSE.
7882
*/
7983
bool pcie_failed_link_retrain(struct pci_dev *dev)
@@ -92,6 +96,8 @@ bool pcie_failed_link_retrain(struct pci_dev *dev)
9296
pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
9397
if ((lnksta & (PCI_EXP_LNKSTA_LBMS | PCI_EXP_LNKSTA_DLLLA)) ==
9498
PCI_EXP_LNKSTA_LBMS) {
99+
u16 oldlnkctl2 = lnkctl2;
100+
95101
pci_info(dev, "broken device, retraining non-functional downstream link at 2.5GT/s\n");
96102

97103
lnkctl2 &= ~PCI_EXP_LNKCTL2_TLS;
@@ -100,6 +106,9 @@ bool pcie_failed_link_retrain(struct pci_dev *dev)
100106

101107
if (pcie_retrain_link(dev, false)) {
102108
pci_info(dev, "retraining failed\n");
109+
pcie_capability_write_word(dev, PCI_EXP_LNKCTL2,
110+
oldlnkctl2);
111+
pcie_retrain_link(dev, true);
103112
return false;
104113
}
105114

0 commit comments

Comments
 (0)