summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/device/Kconfig7
-rw-r--r--src/device/pciexp_device.c28
-rw-r--r--src/include/device/pci_def.h5
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 */