目录
1. 分层:不要把所有现象都算到 Lane 上
2. Lane 上实际传的是什么
3. 时钟、复位和供电
4. 链路训练状态机
Detect
Polling
Configuration:宽度、反转和极性
Recovery:升速和重训练
5. 均衡在补偿什么
四相分别由谁主导
均衡结果写在哪
6. L0 之后的两层
7. 低功耗和几种复位
8. 配置空间怎么读
9. 和 Lane 无关、但会影响性能的配置
10. 一份正常 Gen4 x4 里哪些异常才算数
11. 按场景排查
12. 结论
一条 PCIe Link 最终显示成什么样,是电气检测、低速训练、宽度编号、升速、均衡和两层协议栈依次完成的结果。Lane 数只是其中一项。下面按信号、状态机、均衡、进入 L0 之后的协议,以及常见故障场景说明这些读数分别代表什么。
1. 分层:不要把所有现象都算到 Lane 上
从金手指到 NVMe 命令,经过五层:
| 层 | 负责什么 | 失败时通常看到 |
|---|---|---|
| 供电、时钟、复位 | 3.3 V、100 MHz 参考时钟、PERST# | 配置空间完全不出现 |
| 电气 / 逻辑物理层 | 差分信号、编码、Lane、速率、均衡 | 降速、降宽、RxErr、链路反复训练 |
| 数据链路层 | 序列号、LCRC、ACK/NAK、重放、流控信用 | BadTLP、BadDLLP、Replay Timeout |
| 事务层 | Memory Read/Write、Completion | Completion Timeout、Unsupported Request |
| NVMe | 队列、门铃、PRP/SGL、命名空间 | I/O timeout、控制器复位;LnkSta可能仍正常 |
带宽不够时,先看LnkSta是不是仍为满速满宽。是,就离开 Lane 这一层,去查 Max Payload、Tag、队列、温度和盘内通道。不是,才沿训练和物理连接往下查。
2. Lane 上实际传的是什么
一条 Lane 是两对差分线,收发同时进行,所以是全双工。x4 是四条这样的 Lane 组成一条 Link,不是把一条 Lane 分成四股。
接收端看的是正负两线的电压差。两边同时抬高或降低的共模噪声会被抵消。发送端串联交流耦合电容,只传递跳变,不传递直流电平。对端接有终端时,Detect 阶段的充电特征与开路不同;开路就被当成“这条 Lane 没有设备”。
速率的单位是 GT/s,表示每秒原始比特,不是每秒字节。编码开销如下:
| 代 | 速率 | 编码 | 效率 |
|---|---|---|---|
| Gen1 | 2.5 GT/s | 8b/10b | 80% |
| Gen2 | 5 GT/s | 8b/10b | 80% |
| Gen3 | 8 GT/s | 128b/130b | 约 98.5% |
| Gen4 | 16 GT/s | 128b/130b | 约 98.5% |
| Gen5 | 32 GT/s | 128b/130b | 约 98.5% |
单向理论带宽:
GT/s × Lane 数 × 编码效率 / 8Gen4 x4 约为 7.88 GB/s(十进制),约 7.34 GiB/s。这是物理层数据速率。门铃、命令、完成项、短包和流控都会再占掉一部分,所以顺序读写略低于此仍可能完全正常。
Gen1/2 用 8b/10b,每个字节变成 10 比特,并用极性失衡约束帮助接收端保持锁定。Gen3 起改用 128b/130b:128 比特数据加 2 比特同步头。同步头区分数据块和有序集,不再靠 8b/10b 那种逗号符号。
链路上除了事务包,还有只在物理层使用的有序集:
| 有序集 | 作用 |
|---|---|
| TS1 / TS2 | 训练。携带链路号、Lane 号、速率、FTS 数量、均衡阶段和系数 |
| SKP | 补偿两端时钟的微小频差,由弹性缓冲吸收 |
| EIOS | 通知对端“我将进入电气空闲” |
| EIEOS | 从电气空闲返回时,给接收端一个容易锁定的固定图案 |
| FTS | 从很浅的 L0s 恢复时,帮助接收端重新锁定 |
| SDS | 训练结束、正式数据流开始前的起始标记 |
SKP 不是用户数据。独立且带扩频的参考时钟频差更大,需要更密的 SKP 和更深的弹性缓冲。缓冲溢出或抽空,会记成接收错误。
3. 时钟、复位和供电
差分 Lane 之外,还有三样东西决定训练能不能开始。
参考时钟通常是 100 MHz,有三种架构:
- 共同时钟:主板把同一路时钟送给 Root Port 和 SSD,多数还带扩频。两端的
CommClk都应置位,再重训练,退出低功耗状态的时序才匹配。 - 独立时钟、不扩频(SRNS):两端各有时钟源,频差较小。
- 独立时钟、各自扩频(SRIS):频差最大,对弹性缓冲要求最高。
SlotClk+表示设备使用插槽提供的时钟。它和CommClk+同时出现,才是典型的共同时钟。两个都是减号,表示独立时钟;链路已经稳定时,不要为了把这两个比特“改成加号”去重训练。时钟架构判断错了,余量会变差。
PERST#有效期间,设备停在确定状态,不会开始 Detect。释放顺序应是电源和时钟先稳定,再释放复位。转接卡把PERST#一直拉住,软件侧就是设备消失,没有任何LnkSta。
3.3 V跌落不一定造成永久掉速。它可能只在上电瞬间制造一次接收错误,也可能在负载电流升高后让设备掉线。M.2 还有功耗档。盘的峰值超过插槽供给时,表现可以很像链路闪断,但重新枚举后的速率和宽度仍是满的。
4. 链路训练状态机
上电后的主路径:
电源、参考时钟稳定 │ PERST# 释放 │ Detect 逐 Lane 判断有没有终端 │ Polling 2.5 GT/s 上交换 TS1/TS2,完成位锁定和块锁定 │ Configuration 协商宽度、Lane 编号、极性 │ L0 @ 2.5 GT/s 先建立一条可用的低速链路 │ Recovery 按能力和目标速率升速 │ Equalization 8 GT/s 及以上才有 │ L0 @ 目标速率 配置空间稳定可读无论设备最终是 Gen3、Gen4 还是 Gen5,第一段通信一定发生在 2.5 GT/s。最终显示 16 GT/s,只说明后面的升速和均衡成功了。
Detect
发送端先处于电气空闲,再发出接收端检测脉冲,通过交流耦合电容观察对端终端。有终端才进入后续训练。x4 里只有两条能检测到,后面最多协商成 x2。接触不良、转接卡断线、插槽本身没布线,在这里就被当成 Lane 不存在,而不是“训练失败”。
Polling
Polling.Active 连续发送 TS1。双方都收到对方后进入 Polling.Configuration,用 TS2 确认,然后离开 Polling。这一阶段完成位锁定;128b/130b 下还要完成块锁定。锁定失败就没有机会谈宽度。
Polling 里还有 Compliance 子状态,用于一致性测试夹具。普通 SSD 正常启动不会停在那里。
Configuration:宽度、反转和极性
- Linkwidth.Start / Accept:两端在 TS 里宣告支持的宽度。下游端口根据实际检测到的 Lane 提议,上游端口接受一个共同支持的合法宽度。合法值是 x1、x2、x4、x8、x12、x16、x32。消费级 SSD 一般最高 x4。
- Lanenum.Wait / Accept:给留下的 Lane 分配逻辑编号,并识别整组反转。
- Complete / Idle:TS2 确认,数据链路层准备进入活动状态,随后到达 2.5 GT/s 的 L0。
两种看起来像布线错误、实际合法的情况:
- 极性翻转:同一对差分线的 P/N 接反。训练图案可以发现,接收端内部交换,不降宽。
- Lane 反转:下游 Lane0 接到上游最后一条 Lane。状态机整组重编号,x4 仍然是 x4。
宽度变小,说明有 Lane 没检测到,或者检测到了但中途失去锁定,只能用剩余 Lane 重新接受一个更窄的宽度。它不是极性问题。
服务器 CPU 还可以做Bifurcation。一个 x16 控制器在复位前被拆成 x8x8 或 x4x4x4x4,每段是独立 Link,各自训练。SSD 不能在训练中把相邻两段合成一条 x8。BIOS 拆分方式和背板布线不一致时,典型现象是降宽,或者部分盘完全不出现。
术语方向要固定:
- 下游端口靠近主机,是 CPU Root Port 或 Switch 的下行口。
- 上游端口靠近设备,SSD 端点上的 PCIe 口就是上游端口。
“主机发往 SSD”是下游发送、上游接收。“SSD 发往主机”相反。后面的均衡和报错方向都按这个区分。
Recovery:升速和重训练
低速 L0 建立后,如果LnkCap支持更高速率,而且LnkCtl2的 Target Link Speed 也允许,链路进入 Recovery:
- RcvrLock:重新锁定,并用 TS 协商目标速率。
- Speed:发送端进入电气空闲,两端切换时钟和速率,再用 EIEOS 帮助对方重新锁定。
- 目标不低于 8 GT/s 时进入Equalization。
- RcvrCfg / Idle:确认新速率可用,返回 L0。
8 GT/s 失败通常退回 5 或 2.5 GT/s;16 GT/s 失败可以停在 8 GT/s。所以“能力是 Gen4,实际是 Gen3”有两种完全不同的原因:目标速率根本没允许 16 GT/s,或者允许了,但这一代的均衡没通过。
运行中的误码、对端要求、改宽度或再切速,也会从 L0 进入 Recovery。短暂经过是正常机制。反复进入并且回不到原来的速率和宽度,才是不稳定。
5. 均衡在补偿什么
到 8 GT/s 以后,过孔、连接器、长走线和背板会明显削弱高频。接收端眼图闭上后,单靠加大摆幅没有用,因为高频和低频一起被通道改变了。
发送端用三游标均衡:
- 预游标:提前改变边沿,补偿尚未到达的码间干扰。
- 主游标:当前比特的主要能量。
- 后游标:削弱拖尾,也就是去加重。
若干合法组合被定义成预设P0–P10。预设只是起点,随后还可以按单个游标增减,这叫系数调整。主游标与前后游标要满足幅度和比例限制,不能任意加大。
接收端再做两类处理:
- CTLE是模拟高频提升,能把眼图张开,但也会放大噪声。
- DFE用已经判决的前几个比特估计拖尾,从当前比特里减掉。它不按 CTLE 那种方式放大噪声,但判决错了会把错误往后传。
参数取决于这块板的通道,没有一组可以写死的最优值。每次升到 8、16 或 32 GT/s,都要重新做。
四相分别由谁主导
| 阶段 | 实际动作 | 优化方向 |
|---|---|---|
| Phase 0 | 下游端口按预设发送。上游端口只调自己的接收端,先可靠识别 TS1 | 主机 → SSD,初步接收恢复 |
| Phase 1 | 交换预设,上游端口也开始按预设发送。目标是双向都能稳定接收训练序列,还不追求最佳眼图 | 双向先达到“能通信” |
| Phase 2 | 下游端口要求上游端口调整发送端 | SSD → 主机 |
| Phase 3 | 上游端口要求下游端口调整发送端 | 主机 → SSD |
Phase 2 和 Phase 3 的主从关系不能记反。主机收不好 SSD 的数据,对应 Phase 2;SSD 收不好主机的数据,对应 Phase 3。TS1 里的 EC 字段用00、01、10、11表示当前阶段。任一阶段不能维持可靠的训练通信,这一代速率失败,链路退回较低速率。
路径上还可以有Retimer。它含时钟恢复和重新发送,把一条长通道拆成两段分别均衡。协议能检测到一个或两个 Retimer。Redriver 只做模拟放大,训练状态不会把它报告成 Retimer。能力位只说明“我能报告”,状态位才说明“这次检测到了”。没有 Retimer 不是故障;长背板本应有 Retimer 却没有,Gen4 失败、Gen3 成功才是典型现象。
均衡结果写在哪
LnkSta2的 Equalization Complete 和 Phase1/2/3,记录的是8 GT/s那一次,不是 16 GT/s。16 GT/s 的对应位在 Physical Layer 16.0 GT/s Status,lspci里通常是Phy16Sta一类字段;32 GT/s 还有另一组。
因此:
- 链路当前是 16 GT/s,只看
LnkSta2全成功,只能证明 8 GT/s 曾经成功。 - 16 GT/s 是否走完,要看
Phy16Sta的 EquComplete 和 Phase1/2/3。 - 这些位表示最近一次结果,停在 L0 后不会自动清除。
- 同时没有 Link Equalization Request,才表示硬件没有请求软件再安排一次均衡。
6. L0 之后的两层
物理层进入 L0,只说明比特和块已经稳定。
数据链路层给每个事务包加序列号和 LCRC。对端用 ACK 或 NAK DLLP 回应。NAK、LCRC 错误或重放计时器到期,发送端从重放缓冲重传。偶发误码通常停在这一层,表现为可纠正错误。重放次数滚翻,或重放计时器超时,说明误码已经连续到影响传输。
事务层使用信用流控。转发、非转发和完成这三类,Header 与 Data 信用分开。信用暂时耗尽时,链路速率不变,吞吐会停。信用用完却不再更新,是流控协议错误,不是降速,也不会把 x4 变成 x1。
NVMe 使用其中几种事务:
- 主机写门铃、写寄存器:主机发出的小 Memory Write。
- 主机读寄存器:Memory Read 加 Completion。
- SSD 读取命令、PRP/SGL,以及主机写盘时读取主机内存:SSD 主动发出 Memory Read。
- SSD 把读出的数据写回主机:SSD 发出 Memory Write。
- 完成队列项:也是 SSD 写到主机内存。
所以“盘读主机内存”才受 SSD 作为请求方的 Tag 数量限制;“盘把数据写给主机”不受这个数量限制。
7. 低功耗和几种复位
ASPM 是运行中的链路省电,不是系统睡眠本身:
- L0s很浅,方向可以单独进入。退出要靠 FTS。FTS 数量不够,接收端就锁不回。现在的 SSD 很多不支持它。
- L1双向都进入电气空闲,恢复更慢。
- L1.1 / L1.2进一步关闭共模电压或时钟,依赖
CLKREQ#。退出异常时表现为随机超时或掉盘。
LnkCap写着 ASPM not supported,同时LnkCtl是 Disabled,就不要从 L1 开始排查。
几种复位的影响不同:
| 复位 | 链路是否重新训练 | 速率宽度是否可能变化 |
|---|---|---|
PERST# | 一定 | 会重新协商 |
| Hot Reset | 会离开 L0 再回来 | 会重新协商 |
| Function Level Reset | 重置 NVMe 功能 | 通常不变 |
| D3hot / 系统睡眠后恢复 | 可能重新训练 | 可能停在更低速率 |
故障前后各读一次LnkSta。没变,优先查控制器、固件和供电;变了,优先查训练、时钟和信道。
8. 配置空间怎么读
设备出现在lspci里,只说明它曾经到达 L0。判断当前链路,看两端的这些字段:
| 字段 | 含义 |
|---|---|
LnkCap | 硬件上限:最高速率、最大宽度、ASPM |
LnkCap2 | 支持的速率向量,以及是否支持 Retimer 报告 |
LnkCtl2 | 软件允许尝试的目标速率。低于能力时,不会去练更高代 |
LnkSta | 当前速率和宽度。(ok)表示达到该端能力,downgraded才是降级 |
LnkSta2 | 8 GT/s 均衡结果、均衡请求、Retimer 是否检测到 |
Phy16Sta | 16 GT/s 均衡结果,不能用LnkSta2代替 |
LaneErrStat | 哪一条 Lane 的接收端记过错误 |
UESta/CESta | 不可纠正错误和可纠正错误,都是粘滞位 |
端点上一些减号没有诊断意义:
TrErr-是早期规范遗留位,现在固定为 0。Train-只给下游端口表示“正在训练”。DLActive-只由下游端口报告数据链路层活动。端点即使完全正常也是 0。Surprise-属于下游端口的热插拔状态。
能读到配置空间并且nvme已绑定,本身就说明链路当前可访问。不要用端点的DLActive-判断断链。要看这个状态,去读上游端口。
错误有方向。SSD 的RxErr只代表主机发往 SSD 的方向;主机收 SSD 的错误记在 Root Port 或 Switch 下行口。只看盘,会漏掉一半信道。
CEMsk某位为减,只说明这种错误没有被屏蔽。DevCtl的CorrErr-则表示设备不被允许向上游发送可纠正错误消息。配置空间里可以有加号,内核日志却是空的。
9. 和 Lane 无关、但会影响性能的配置
Max Payload是一个事务包最多携带的数据。路径上每一跳取最小值。能力 512、实际启用 256,通常是上游某跳只保证 256。它降低一点包效率,不改变LnkSta。不要用setpci把它改大。
Max Read Request是请求方希望一次读多少。完成包仍按 Max Payload 拆开。它不要求整条路径相同,也不代表链路宽度。
Tag是 SSD 作为请求方时,未完成的非转发事务数量。5-bit 大约 32 个,8-bit 扩展到 256 个。直连 CPU、往返时间不到 1 µs 时,Gen4 x4 需要同时在途的数据大约只有几 KB 到十来 KB,32 个 Tag 通常够用。中间经过多层 Switch、往返到数微秒时,32 个 Tag 乘以较小的读请求长度,才可能限制“SSD 读主机内存”的吞吐。Tag 不够不会把训练结果变成 x2。
10. 一份正常 Gen4 x4 里哪些异常才算数
设 NVMe 端点是01:00.0,驱动已绑定,读数是:
LnkCap:16 GT/s、x4、不支持 ASPM。LnkCtl2:目标就是 16 GT/s。LnkSta:16GT/s (ok), Width x4 (ok)。LnkSta2:8 GT/s 四相成功,无均衡请求。Phy16Sta:16 GT/s 四相也成功,无均衡请求。LaneErrStat为 0,UESta全未置位。SlotClk-、CommClk-:独立参考时钟。- Max Payload 能力 512、启用 256。
- 扩展 Tag 未启用。
这表示当前就是满速满宽。单向上限约 7.88 GB/s。顺序带宽明显低于此,不再查 Lane。独立时钟、端点上的DLActive-、没有 Retimer、256 字节 Payload,都不能单独解释成降速。
若唯一异常是:
DevSta: CorrErr+ CESta: RxErr+ BadTLP- BadDLLP- Rollover- Timeout-它表示 SSD 接收端曾经见到一次物理层接收错误。旁边没有坏 TLP、坏 DLLP 和重放超时,不可纠正错误也为空,所以数据链路层没有进入连续重放。可纠正状态是粘滞的,上电、插拔或一次电源抖动都会留下这个加号。
它还不能证明盘坏或槽坏。下一步是看反方向,清除后复测。清除是对 AER 状态位写 1,不是改速率:
lspci -PP -s 01:00.0 lspci -tv dmesg -T | grep -iE 'aer|pcie|nvme|01:00.0' setpci -s 01:00.0 ECAP_AER+0x10.L=0xffffffff # 对上游端口的 AER 不可纠正/可纠正状态也做同样的清除 # 再做一段实际读写 lspci -s 01:00.0 -vv | grep -E 'LnkSta|LnkSta2|Phy16|CESta|UESta|LaneErr'同时读lspci -PP给出的上游端口。清除后不再增加,可以忽略。空闲也快速增加,或同时出现BadDLLP、Replay Timeout、Completion Timeout,再查金手指、转接卡、背板和供电。高负载下偶发,而两端始终是16GT/s (ok), Width x4 (ok),只说明余量一般。生产环境不要用setpci修改目标速率、Max Payload 或 ASPM。
11. 按场景排查
速度下降,宽度仍是 x4。先看两端LnkCtl2。目标被限制在 8 GT/s,就去查 BIOS 和平台,而不是盘。目标已是 16 GT/s,却停在 8 GT/s,再看Phy16Sta停在哪一相。长背板、延长线、无 Retimer 的转接卡,是这一类的常见原因。锁回 Gen3 后错误消失,问题在信道余量。
宽度下降,速度仍高。优先查物理连接和拓扑:金手指、M.2 座、转接卡断 Lane、插槽只布了 x2、相邻插槽共用 Lane、Bifurcation 与背板不一致。极性翻转和 Lane 反转不会造成降宽。换到已知按 x4 布线的直连槽后恢复,就不是 SSD 端口能力的问题。
设备完全不出现。没有配置空间可读。查 3.3 V、参考时钟、PERST#、BIOS 是否关闭插槽,以及转接板键位。这是 Detect 之前或 Detect 失败,不是LnkSta降级。
运行中掉盘。温度节流时速率和宽度通常不变。链路闪断则上游端口会出现链路下降或 Surprise Down,NVMe 同时报超时或控制器复位。支持 ASPM 的设备,可以把 ASPM 临时关闭做对比;能力里写着不支持,就不要从这里开始。还要区分功耗不足:掉线后重新枚举仍是满速满宽,更像供电或复位,不像均衡。
只在一个方向报错。SSD 只有RxErr,上游端口干净:查主机发往 SSD 的发送端、连接器和 SSD 接收端。上游端口有接收错误,SSD 干净:查反方向,也就是均衡 Phase 2 优化的那一路。某一位在LaneErrStat里反复置位,查对应 Lane 的接触或走线,而不是整条链路降速。
可纠正错误变成不可纠正错误。BadTLP或BadDLLP开始伴随 Replay Timeout、Replay Rollover,说明重放已经救不回来。再出现 Completion Timeout 或 Data Link Protocol Error,NVMe 命令会失败。此时先保留两端lspci和内核日志,再复位;只重启机器会把粘滞位清掉。
睡眠或热复位后停在 Gen1。看目标速率有没有被软件改低,以及参考时钟是否在恢复时晚于PERST#。这是重新训练没有升速,不是 NAND 变慢。
性能低,但两端已经是 Gen4 x4。按这个顺序排除:
- 温度和电源状态是否降频,固件是否在稳态而不是 SLC cache 阶段。
- IO 大小、队列深度、线程和测试区间是否足够大。
- 盘接在 CPU 直连 Lane,还是接在芯片组后面。芯片组上行和多个设备共享带宽。
- Max Payload 是否异常地只有 128 字节。256 字节很少单独造成数量级下降。
- 只有跨 Switch、延迟明显偏大时,才评估 32 个 Tag。
- 最后才看 NVMe 的队列数、MDTS、LBA 格式和主机调度器。
一个槽正常、另一个槽降级。用同一块盘交换。问题跟着槽走,查布线、Bifurcation 和转接卡;问题跟着盘走,再查盘的金手指和固件。不要同时更换盘、线和 BIOS,否则无法归因。
12. 结论
Lane 是一条全双工差分通道,Link 是若干 Lane 在同一速率下训练出来的整条连接。训练先在 2.5 GT/s 完成检测、锁定、宽度和编号,进入 L0 后再升速;8 GT/s 及以上还要按四相均衡。Phase 2 优化 SSD 到主机,Phase 3 优化主机到 SSD。LnkSta才是当前速率和宽度;LnkSta2的均衡位属于 8 GT/s,16 GT/s 要另看Phy16Sta。
端点上的DLActive、训练位和独立参考时钟,不能单独当成故障。NAND 通道、Tag 和 Max Payload 影响性能,不改变已经完成的训练结果。一个孤立且能清除的RxErr+,只是一次粘滞记录;它与降速、降宽、重放超时或对端错误同时出现时,才说明这条信道需要继续查。