Jonathan Kollasch has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/42683 )
Change subject: pciexp: retrain PCIe link at lower speed if no link ......................................................................
pciexp: retrain PCIe link at lower speed if no link
Needed for PCIe x4 dual-port Marvell NIC (sky2) on Sandy/Ivy Bridge and 6-series PCH (if not other chipsets), where the link will not come up at 5GT/s (or 8GT/s?), but will if explicitly trained at 2.5GT/s.
Change-Id: I7ba15f7c13463356c6417f41b44d045aacfde4cc --- M src/device/pciexp_device.c M src/include/device/pci_def.h 2 files changed, 41 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/83/42683/1
diff --git a/src/device/pciexp_device.c b/src/device/pciexp_device.c index f04d865..aeb44f7 100644 --- a/src/device/pciexp_device.c +++ b/src/device/pciexp_device.c @@ -112,6 +112,38 @@ } }
+static void pciexp_limit_speed(struct device *dev, unsigned int cap) +{ + u16 x, y; + + x = pci_read_config16(dev, cap + PCI_EXP_FLAGS); + + /* is this new enough to support LNKCTL2? */ + if ((x & PCI_EXP_FLAGS_VERS) <= 1) + return; + + y = pci_read_config16(dev, cap + PCI_EXP_LNKCTL2); + y &= PCI_EXP_LNKCTL2_TLS; + + do { + /* link up? */ + x = pci_read_config16(dev, cap + PCI_EXP_LNKSTA); + x = (x & PCI_EXP_LNKSTA_LW) >> 4; + if (x > 0) + return; + + printk(BIOS_INFO, "%s: link down; retraining at target link speed %u\n", + dev_path(dev), y); + + x = pci_read_config16(dev, cap + PCI_EXP_LNKCTL2); + x &= ~PCI_EXP_LNKCTL2_TLS; + x |= y & PCI_EXP_LNKCTL2_TLS; + pci_write_config16(dev, cap + PCI_EXP_LNKCTL2, x); + + pciexp_retrain_link(dev, cap); + } while (--y > 0); +} + static void pciexp_enable_clock_power_pm(struct device *endp, unsigned int endp_cap) { /* check if per port clk req is supported in device */ @@ -488,6 +520,12 @@
void pciexp_scan_bridge(struct device *dev) { + unsigned int cap; + + cap = pci_find_capability(dev, PCI_CAP_ID_PCIE); + if (cap) + pciexp_limit_speed(dev, cap); + do_pci_scan_bridge(dev, pciexp_scan_bus); pciexp_enable_ltr(dev); } diff --git a/src/include/device/pci_def.h b/src/include/device/pci_def.h index 07ba4a2..b351e42 100644 --- a/src/include/device/pci_def.h +++ b/src/include/device/pci_def.h @@ -432,6 +432,7 @@ #define PCI_EXP_LNKCTL_CCC 0x40 /* Common Clock COnfiguration */ #define PCI_EXP_EN_CLK_PM 0x100 /* Enable Clock Power Management */ #define PCI_EXP_LNKSTA 18 /* Link Status */ +#define PCI_EXP_LNKSTA_LW 0x3F0 /* Link Width */ #define PCI_EXP_LNKSTA_LT 0x800 /* Link Training */ #define PCI_EXP_LNKSTA_SLC 0x1000 /* Slot Clock Configuration */ #define PCI_EXP_SLTCAP 20 /* Slot Capabilities */ @@ -446,6 +447,8 @@ #define PCI_EXP_RTCTL_CRSSVE 0x10 /* CRS Software Visibility Enable */ #define PCI_EXP_RTCAP 30 /* Root Capabilities */ #define PCI_EXP_RTSTA 32 /* Root Status */ +#define PCI_EXP_LNKCTL2 48 /* Link Control 2 */ +#define PCI_EXP_LNKCTL2_TLS 0x000f /* Target Link Speed */
/* Extended Capabilities (PCI-X 2.0 and Express) */ #define PCI_EXT_CAP_ID(header) (header & 0x0000ffff)