Skip to content

Commit 8037ac0

Browse files
maciej-w-rozyckikwilczynski
authored andcommitted
PCI: Clear the LBMS bit after a link retrain
The LBMS bit, where implemented, is set by hardware either in response to the completion of retraining caused by writing 1 to the Retrain Link bit or whenever hardware has changed the link speed or width in attempt to correct unreliable link operation. It is never cleared by hardware other than by software writing 1 to the bit position in the Link Status register and we never do such a write. We currently have two places, namely apply_bad_link_workaround() and pcie_failed_link_retrain() in drivers/pci/controller/dwc/pcie-tegra194.c and drivers/pci/quirks.c respectively where we check the state of the LBMS bit and neither is interested in the state of the bit resulting from the completion of retraining, both check for a link fault. And in particular pcie_failed_link_retrain() causes issues consequently, by trying to retrain a link where there's no downstream device anymore and the state of 1 in the LBMS bit has been retained from when there was a device downstream that has since been removed. Clear the LBMS bit then at the conclusion of pcie_retrain_link(), so that we have a single place that controls it and that our code can track link speed or width changes resulting from unreliable link operation. Fixes: a89c822 ("PCI: Work around PCIe link training failures") Link: https://lore.kernel.org/r/alpine.DEB.2.21.2408091133140.61955@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> Cc: <stable@vger.kernel.org> # v6.5+
1 parent 8400291 commit 8037ac0

1 file changed

Lines changed: 9 additions & 1 deletion

File tree

drivers/pci/pci.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4717,7 +4717,15 @@ int pcie_retrain_link(struct pci_dev *pdev, bool use_lt)
47174717
pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_RL);
47184718
}
47194719

4720-
return pcie_wait_for_link_status(pdev, use_lt, !use_lt);
4720+
rc = pcie_wait_for_link_status(pdev, use_lt, !use_lt);
4721+
4722+
/*
4723+
* Clear LBMS after a manual retrain so that the bit can be used
4724+
* to track link speed or width changes made by hardware itself
4725+
* in attempt to correct unreliable link operation.
4726+
*/
4727+
pcie_capability_write_word(pdev, PCI_EXP_LNKSTA, PCI_EXP_LNKSTA_LBMS);
4728+
return rc;
47214729
}
47224730

47234731
/**

0 commit comments

Comments
 (0)