mirror of
https://github.com/fail0verflow/switch-coreboot.git
synced 2025-05-04 01:39:18 -04:00
UPSTREAM: pciexp_device: Prevent race condition with retrain link
The PCIe specification[1] describes a race condition that
can occur when using the Retrain Link bit in the Link
Control Register.
The race condition is avoided by checking the retrain link
bit in the link status register and waiting until it is
set to 0, before initiating a new link retraining.
[1] PCI Express Base Specification Revision 3.0
Page 633
BUG=none
BRANCH=none
TEST=none
Change-Id: I9ebdb696f63706590bf864f4b3e11304a1f7a1b4
Signed-off-by: Patrick Georgi <pgeorgi@google.com>
Original-Commit-Id: bb5fb64e11
Original-Change-Id: I9d5840fb9a6e63838b5a4084d3bbe483f1d870ed
Original-Signed-off-by: Youness Alaoui <youness.alaoui@puri.sm>
Original-Reviewed-on: https://review.coreboot.org/19556
Original-Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Original-Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Original-Reviewed-by: Martin Roth <martinroth@google.com>
Reviewed-on: https://chromium-review.googlesource.com/531202
Commit-Ready: Patrick Georgi <pgeorgi@chromium.org>
Tested-by: Patrick Georgi <pgeorgi@chromium.org>
Reviewed-by: Patrick Georgi <pgeorgi@chromium.org>
This commit is contained in:
parent
815390c173
commit
06704b2270
1 changed files with 20 additions and 2 deletions
|
@ -50,16 +50,34 @@ unsigned int pciexp_find_extended_cap(device_t dev, unsigned int cap)
|
|||
#define PCIE_TRAIN_RETRY 10000
|
||||
static int pciexp_retrain_link(device_t dev, unsigned cap)
|
||||
{
|
||||
unsigned try = PCIE_TRAIN_RETRY;
|
||||
unsigned int try;
|
||||
u16 lnk;
|
||||
|
||||
/*
|
||||
* Implementation note (page 633) in PCIe Specification 3.0 suggests
|
||||
* polling the Link Training bit in the Link Status register until the
|
||||
* value returned is 0 before setting the Retrain Link bit to 1.
|
||||
* This is meant to avoid a race condition when using the
|
||||
* Retrain Link mechanism.
|
||||
*/
|
||||
for (try = PCIE_TRAIN_RETRY; try > 0; try--) {
|
||||
lnk = pci_read_config16(dev, cap + PCI_EXP_LNKSTA);
|
||||
if (!(lnk & PCI_EXP_LNKSTA_LT))
|
||||
break;
|
||||
udelay(100);
|
||||
}
|
||||
if (try == 0) {
|
||||
printk(BIOS_ERR, "%s: Link Retrain timeout\n", dev_path(dev));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Start link retraining */
|
||||
lnk = pci_read_config16(dev, cap + PCI_EXP_LNKCTL);
|
||||
lnk |= PCI_EXP_LNKCTL_RL;
|
||||
pci_write_config16(dev, cap + PCI_EXP_LNKCTL, lnk);
|
||||
|
||||
/* Wait for training to complete */
|
||||
while (try--) {
|
||||
for (try = PCIE_TRAIN_RETRY; try > 0; try--) {
|
||||
lnk = pci_read_config16(dev, cap + PCI_EXP_LNKSTA);
|
||||
if (!(lnk & PCI_EXP_LNKSTA_LT))
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Reference in a new issue