
目录概述一、原理1.1 PCIe 分层与错误检测位置1.2 错误的严重程度分类1.3 Receiver Error 与 Lane Error 从哪里来1.4 链路训练与均衡1.5 错误上报路径1.6 sticky 位1.7 AER 控制权Firmware First 与 OS Native二、现场数据解读2.1 链路协商2.2 错误记录2.3 lane 分布的意义2.4 与本问题无关的字段三、排查流程3.1 总体思路3.2 寄存器地址3.3 第一步记录基线3.4 第二步清零3.5 第三步空闲观察3.6 第四步只读压测3.7 第五步 (可选)验证训练阶段四、结果判断与后续Lane Margining五、小结概述一块 Gen4 x4 NVMe SSD (01:00.0) 接在 Intel Root Port 00:06.0 下。lspci -vvv显示链路协商正常但两端都记录了 Correctable Error两个方向都有 Receiver Error (RxErr)Root Port 接收方向 4 条 lane 全部报 Lane ErrorRoot Port 收到过多次 ERR_COR来源是它自己平台没有把 AER 交给 OSdmesg 看不到任何记录这些错误位都是 sticky 的只说明发生过不说明正在发生。本文先讲清这些字段背后的原理再给出一套可复现的排查流程。一、原理1.1 PCIe 分层与错误检测位置PCIe 协议分三层每层负责检测不同类型的错误层职责典型错误AER 中的位置事务层 (Transaction Layer)TLP 的组装、路由、完成Unsupported Request、Completion Timeout、Malformed TLPUESta数据链路层 (Data Link Layer)LCRC 校验、ACK/NAK、重传Bad TLP、Bad DLLP、Replay Timeout、Replay RolloverCESta物理层 (Physical Layer)编码、成帧、时钟恢复、链路训练Receiver ErrorCEStaReceiver Error 属于最底层的物理层错误是信号质量问题最直接的反映。1.2 错误的严重程度分类类别含义恢复方式Correctable硬件能自动恢复数据不受影响数据链路层重传或错误发生在非数据时段Uncorrectable Non-Fatal某个事务失败链路本身仍可用由软件或驱动处理Uncorrectable Fatal链路或设备不可靠通常需要复位链路本文涉及的错误全部是 CorrectableUESta 两端都是干净的。Correctable 错误不会造成数据损坏但频繁出现意味着链路余量不足会带来重传开销严重时可能演变成不可纠正错误或链路掉速。1.3 Receiver Error 与 Lane Error 从哪里来Gen4 使用 128b/130b 编码每 128 bit 数据前加 2 bit 同步头 (Sync Header)01表示数据块10表示有序集块 (Ordered Set)。接收端在以下情况会判定为接收错误同步头不是01或10帧结构错误例如 Framing Token 不合法块对齐丢失弹性缓冲区上溢或下溢 (两端时钟偏差超出补偿能力)两类状态位的区别CESta 的 RxErr按端口记录不区分是哪条 lane。Lane Error Status位于 Secondary PCI Express 扩展能力中8GT/s 及以上速率才有每条 lane 一个位能定位到具体 lane。RxErr 能被纠正的原因是如果错误破坏了某个 TLP接收端的 LCRC 校验会失败数据链路层回 NAK发送端重传。如果错误发生在空闲符号或训练序列上根本不涉及数据。两端 CESta 中只有 RxErr没有 BadTLP、BadDLLP 等数据链路层错误。这说明物理层错误没有波及到实际数据包或者发生在链路训练阶段这一点与训练残留的推测相符。1.4 链路训练与均衡链路建立由物理层的状态机 LTSSM 控制主要状态Detect → Polling → Configuration → L0 (正常工作) ↕ Recovery (速率切换、均衡、错误恢复)上电后链路总是先以 Gen1 (2.5GT/s) 建立然后经 Recovery 状态逐级切换到目标速率。Gen3 及以上每次提速都要做均衡 (Equalization)阶段作用Phase 0下游端口把预设 (Preset) 告知上游端口Phase 1双方用初始预设建立可用链路Phase 2上游端口调整下游端口的发送端参数Phase 3下游端口调整上游端口的发送端参数均衡期间发送端会尝试不同的去加重和预冲参数其中一些组合信号质量较差接收端在这段时间记录到 Receiver Error 和 Lane Error 很常见。由于这个过程对所有 lane 同时进行留下的记录通常也覆盖全部 lane。本例中 LnkSta2 显示EqualizationComplete Phase1 Phase2 Phase3均衡完整走完链路最终稳定在 Gen4。1.5 错误上报路径一个 Correctable 错误从发生到被 OS 看到要经过以下链条设备检测到错误 │ ├─→ 置位 CESta 对应位、DevSta.CorrErr (总会发生未被 CEMsk 屏蔽时) │ ▼ DevCtl.CorrErr 使能 ──否──→ 结束只留寄存器记录 │是 ▼ 向上游发送 ERR_COR 消息 (Root Port 自身出错时视同内部收到一条消息) │ ▼ Root Port 置位 RootSta.CERcvd记录 ErrorSrc (再次收到时置位 MultCERcvd) │ ▼ RootCmd.CERptEn 使能 ──否──→ 结束只留寄存器记录 │是 ▼ 产生 MSI 中断 → Linux AER 驱动 → dmesg 日志 sysfs 计数对照本例SSDDevCtl 错误上报关闭链条在第二步就断了所以它的 RxErr 不会报给 Root Port。Root PortDevCtl 使能自身错误写入了 RootSta 和 ErrorSrc (0030 即 00:06.0)但 RootCmd 全部关闭链条在最后一步断开OS 收不到中断。1.6 sticky 位sticky 指寄存器位被硬件置 1 后一直保持直到软件主动清除或设备彻底断电。它只记录从上次清零以来至少发生过一次没有时间和次数信息。属性含义例子RW1C硬件置 1 后保持软件写 1 清零复位后清零DevSta 的 CorrErr / NonFatalErr / FatalErrRW1CS在 RW1C 基础上带 Sticky普通复位清不掉AER 的 CESta / UESta、Root Error Status、Lane Error StatusRW1CS 位在以下情况下保留原值Hot Reset、链路断开重连FLR (Function Level Reset)有辅助电源 (Vaux) 时的平台复位例如部分主板的热重启清除方式只有两种软件向该位写 1或无辅助电源的冷复位。这样设计是为了保留事故现场系统复位恢复后仍能读到出错记录。代价是看到时无法判断它是刚发生的还是开机训练甚至上次开机留下的。1.7 AER 控制权Firmware First 与 OS NativeAER 由谁处理是开机时固件和 OS 通过 ACPI_OSC方法协商的模式谁处理错误错误去向OS NativeLinux AER 驱动dmesg、sysfsaer_dev_*计数Firmware FirstBIOS / BMCBMC 事件日志 (SEL)部分通过 APEI/GHES 转发到 dmesg都不接管无人处理只留在寄存器里本例的 RootCmd 全关说明 OS 没有拿到控制权。消费级主板上常见的情况是固件既不交给 OS自己也不处理。核实方法dmesg | grep -i -E _OSC|AER|GHES内核参数pcie_portsnative可以强制 OS 接管但它绕过了固件协商可能与固件行为冲突不建议作为常规手段。二、现场数据解读2.1 链路协商项目值判断Root Port LnkCap32GT/s, x16, Port #13可拆分的 Gen5 宽端口LnkSta16GT/s x4 (downgraded)正常受 SSD 的 Gen4 x4 能力限制LnkCtl2 Target Link Speed16GT/sBIOS 把目标速率设为 Gen4DLActive / 均衡DLActivePhase 1/2/3 完成链路正常工作MaxPayload两端均为 256B一致CommClk两端均为 CommClk-未启用公共时钟downgraded 是 lspci 用 LnkSta 与本端 LnkCap 比较得出的Root Port 支持 Gen5 x16SSD 只支持 Gen4 x4这里的降级是预期行为。公共时钟只有两端 LnkSta 都报告 SlotClk软件才会置位 CommClk。本例 Root Port 是 SlotClkSSD 是 SlotClk-所以链路工作在独立时钟模式两端各自使用本地参考时钟对时钟质量和弹性缓冲区补偿更敏感。这本身不是故障但如果错误持续出现可以列为怀疑点。2.2 错误记录SSD 侧 (01:00.0)字段值含义CEStaRxErrRoot Port → SSD 方向发生过接收错误DevCtl错误上报关闭不会向上游发 ERR_CORLaneErrStat0无 lane 级记录Root Port 侧 (00:06.0)字段值含义DevStaCorrErr发生过可纠正错误CEStaRxErrSSD → Root Port 方向发生过接收错误CEMskAdvNonFatalErr仅屏蔽 Advisory Non-Fatal不影响 RxErrLaneErrStatLaneErr at lane: 0 1 2 34 条 lane 都出现过错误RootStaCERcvd MultCERcvd收到过多次 ERR_CORErrorSrc ERR_COR0030bus 0, dev 6, fn 0即 Root Port 自身UESta全部为 -无不可纠正错误2.3 lane 分布的意义模式常见原因单条或少数 lane某条走线、连接器某个触点、某个 lane 的均衡结果差全部 lane共性原因速率切换和均衡过程、参考时钟、供电、整个连接器接触不良本例是全 lane加上没有数据链路层错误更偏向训练阶段残留。但 sticky 位不带时间信息必须清零后复查才能下结论。2.4 与本问题无关的字段ACS 支持但未启用只影响设备直通时的 IOMMU 分组。PTM 已启用精确时间测量与存储链路健康无关。端口归属SSD 具体接在哪个 M.2 位或转接卡上需要对照主板手册确认。三、排查流程3.1 总体思路sticky 位只能回答有没有发生过所以流程的核心是清零制造一个已知的观察窗口再看错误是否重新出现。分空闲和负载两段是为了区分链路本身不稳和负载下余量不足。读取当前状态记录基线 │ ▼ 清零所有 sticky 错误位 ──→ 确认清零成功 │ ▼ 空闲观察 5 分钟 ──出现错误──→ 物理层问题检查硬件 │无 ▼ 只读压测 5 分钟 ──出现错误──→ 余量不足做 Lane Margining │无 ▼ (可选) 触发重训练 ──出现错误──→ 确认错误来自训练阶段 │ ▼ 结论链路运行健康3.2 寄存器地址所有状态位都通过 setpci 按能力结构 偏移定位避免硬编码绝对地址寄存器位置属性Device StatusPCIe Capability 0x0ARW1CLink ControlPCIe Capability 0x10RWCorrectable Error StatusAER 0x10RW1CSRoot Error StatusAER 0x30RW1CSLane Error StatusSecondary PCIe (ExtCap ID 0x0019) 0x08RW1CSsetpci 中CAP_EXP表示 PCIe CapabilityECAP_AER表示 AERECAP0019按 ID 定位 Secondary PCIe 扩展能力。3.3 第一步记录基线lspci -vvv -s 00:06.0 rp_before.txt lspci -vvv -s 01:00.0 ssd_before.txt保留清零前的完整输出方便事后对比。3.4 第二步清零# Correctable Error Status setpci -s 01:00.0 ECAP_AER0x10.L0xffffffff setpci -s 00:06.0 ECAP_AER0x10.L0xffffffff # Root Error Status (仅 Root Port 有) setpci -s 00:06.0 ECAP_AER0x30.L0xffffffff # Device Status 低 4 位错误标志 setpci -s 01:00.0 CAP_EXP0x0a.W0x000f setpci -s 00:06.0 CAP_EXP0x0a.W0x000f # Lane Error Status setpci -s 00:06.0 ECAP00190x08.L0xffffffff setpci -s 01:00.0 ECAP00190x08.L0xffffffff # 确认已清零 lspci -vvv -s 00:06.0 | grep -E DevSta|CESta|RootSta|LaneErr lspci -vvv -s 01:00.0 | grep -E DevSta|CESta|LaneErr原理RW1C / RW1CS 位写 1 清零、写 0 无效所以写全 1 可以一次清掉所有错误位不会误改其他位。这些操作需要 root 权限只清状态不改变链路配置。如果 setpci 提示找不到ECAP0019说明该设备没有 Secondary PCIe 扩展能力跳过即可。3.5 第三步空闲观察sleep 300 lspci -vvv -s 00:06.0 | grep -E CESta|RootSta|LaneErr lspci -vvv -s 01:00.0 | grep -E CESta|LaneErr空闲时链路上几乎只有 SKP 有序集和电气空闲 (本例 ASPM 关闭链路一直处于 L0)。如果这时也出错说明信号质量在无负载状态下就不达标。3.6 第四步只读压测fio --nameseqread --filename/dev/nvme0n1 --rwread --bs128k \ --iodepth64 --numjobs4 --direct1 --ioenginelibaio \ --runtime300 --time_based --group_reporting --readonly lspci -vvv -s 00:06.0 | grep -E CESta|RootSta|LaneErr lspci -vvv -s 01:00.0 | grep -E CESta|LaneErr参数说明--rwread --bs128k大块顺序读让 SSD → Root Port 方向持续满载这正是 Root Port 报 Lane Error 的方向。--direct1绕过页缓存保证每次读都走 PCIe。--readonlyfio 拒绝任何写操作对系统盘也安全。负载下 SSD 控制器功耗和温度上升供电噪声和串扰增加余量不足的链路会在这时暴露问题。建议同时用nvme smart-log /dev/nvme0记录温度便于关联。3.7 第五步 (可选)验证训练阶段清零后手动触发一次链路重训练再立即查看错误位# 清零 (同 3.4)然后置位 Link Control 的 Retrain Link (bit 5) setpci -s 00:06.0 CAP_EXP0x10.W0x0020:0x0020 # 等待训练完成后查看 sleep 1 lspci -vvv -s 00:06.0 | grep -E LnkSta|CESta|LaneErr值:掩码语法只修改 bit 5不影响 ASPM 等其他控制位。如果重训练后立即出现与开机时相同的模式 (RxErr 且 4 条 lane 全报)就能确认原来的记录来自训练过程。重训练期间盘会短暂不可访问。如果这是系统盘存在 I/O 超时甚至文件系统出错的风险建议在非系统盘或维护窗口里进行。四、结果判断与后续现象结论下一步空闲和压测都没有再出现错误来自开机训练链路运行健康无需处理可定期复查空闲时就出现物理层问题明显重新插拔、换 M.2 槽位、换盘交叉对比只在压测时出现信号余量不足做 Lane Margining可尝试更新 BIOS 和 SSD 固件只有少数 lane 出现局部问题重点检查连接器和对应走线Lane Margining两端都支持 Lane Margining at the Receiver。它的原理是让接收端在不中断链路的前提下逐步偏移采样点的时间和电压位置找到开始出错的边界从而量化眼图余量。pciutils 3.11 及以上自带pcilmr# 列出支持 Margining 的链路 pcilmr --scan # 对 00:06.0 下游链路做扫描 pcilmr 00:06.0Margining 需要链路工作在 16GT/s 及以上。扫描过程中测到边界时可能会产生新的错误记录建议在压测结论之后单独进行并在维护窗口里执行。如果余量明显偏低常见的缓解手段有更换 M.2 位置 (优先直连 CPU 的插槽)、移除转接卡、在 BIOS 中把该端口限制为更低速率作为对照实验。五、小结链路协商没有问题Gen4 x4 是 SSD 的能力上限。两端的 RxErr 和 Root Port 的全 lane Lane Error 都是物理层的 Correctable 错误由硬件自动恢复没有伴随数据链路层错误模式上更像开机均衡阶段的残留。