diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/device/Kconfig | 7 | ||||
-rw-r--r-- | src/device/pciexp_device.c | 28 | ||||
-rw-r--r-- | src/include/device/pci_def.h | 5 |
3 files changed, 40 insertions, 0 deletions
diff --git a/src/device/Kconfig b/src/device/Kconfig index b9284cbcb3..c0ba3d1614 100644 --- a/src/device/Kconfig +++ b/src/device/Kconfig @@ -654,6 +654,13 @@ config PCIEXP_DEFAULT_MAX_RESIZABLE_BAR_BITS endif # PCIEXP_SUPPORT_RESIZABLE_BARS +config PCIEXP_LANE_ERR_STAT_CLEAR + prompt "Enable Clear PCIe Lane Error Status" + bool + default n + help + Clear the PCIe Lane Error Status at the end of link training. + config PCIEXP_HOTPLUG prompt "Enable PCIe Hotplug Support" bool diff --git a/src/device/pciexp_device.c b/src/device/pciexp_device.c index 6023497241..b03089b8f6 100644 --- a/src/device/pciexp_device.c +++ b/src/device/pciexp_device.c @@ -532,6 +532,30 @@ static void pciexp_set_max_payload_size(struct device *root, unsigned int root_c printk(BIOS_INFO, "PCIe: Max_Payload_Size adjusted to %d\n", (1 << (max_payload + 7))); } +/* + * Clear Lane Error State at the end of PCIe link training. + * Lane error status is cleared if PCIEXP_LANE_ERR_STAT_CLEAR is set. + * Lane error is normal during link training, so we need to clear it. + * At this moment, link has been used, but for a very short duration. + */ +static void clear_lane_error_status(struct device *dev) +{ + u32 reg32; + u16 pos; + + pos = pciexp_find_extended_cap(dev, PCI_EXP_SEC_CAP_ID, 0); + if (pos == 0) + return; + + reg32 = pci_read_config32(dev, pos + PCI_EXP_SEC_LANE_ERR_STATUS); + if (reg32 == 0) + return; + + printk(BIOS_DEBUG, "%s: Clear Lane Error Status.\n", dev_path(dev)); + printk(BIOS_DEBUG, "LaneErrStat:0x%x\n", reg32); + pci_write_config32(dev, pos + PCI_EXP_SEC_LANE_ERR_STATUS, reg32); +} + static void pciexp_tune_dev(struct device *dev) { struct device *root = dev->bus->dev; @@ -561,6 +585,10 @@ static void pciexp_tune_dev(struct device *dev) if (CONFIG(PCIEXP_ASPM)) pciexp_enable_aspm(root, root_cap, dev, cap); + /* Clear PCIe Lane Error Status */ + if (CONFIG(PCIEXP_LANE_ERR_STAT_CLEAR)) + clear_lane_error_status(root); + /* Adjust Max_Payload_Size of link ends. */ pciexp_set_max_payload_size(root, root_cap, dev, cap); diff --git a/src/include/device/pci_def.h b/src/include/device/pci_def.h index 0eedd513b2..64c1ac24b1 100644 --- a/src/include/device/pci_def.h +++ b/src/include/device/pci_def.h @@ -469,6 +469,11 @@ #define PCIE_EXT_CAP_LTR_ID 0x0018 #define PCIE_EXT_CAP_RESIZABLE_BAR 0x0015 +/* Secondary PCI Express Extended Capability Structure */ +#define PCI_EXP_SEC_CAP_ID 0x19 +#define PCI_EXP_SEC_LNK_CTL3 4 /* Link Control 3 */ +#define PCI_EXP_SEC_LANE_ERR_STATUS 8 /* Lane Error Status */ + /* Advanced Error Reporting */ #define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */ #define PCI_ERR_UNC_TRAIN 0x00000001 /* Training */ |