3、链路训练状态机(LTSSM)总览:11个状态跳转与触发条件

LTSSM 这玩意儿,说白了就是 PCIe 链路训练的「总导演」。从复位开始到链路稳定,每一步该干什么、出了错怎么退、什么时候往前跳,全由它说了算。我最早啃 SPEC 时对着状态图看了三天才理清,后来在逻辑分析仪上抓过实际跳转,嗯,发现 SPEC 画的图跟现实还是有那么点差距的——后面我会讲到。

3.1 11 个状态是哪些?

LTSSM 定义了一套有限状态机,总共 11 个状态。它们分成四大类:

  • 检测(Detect):物理链路是否存在?
  • 轮询(Polling):收发器基本通信能力测试。
  • 配置(Configuration):协商速率、宽度、反向等。
  • 恢复(Recovery):链路坏了想重连、或者要改速率。
  • 正常工作(L0、L0s、L1、L2):跑数据的省电模式。

我把所有状态列出来,方便你对照着记:

状态编号 状态名 归属类别 一句话作用
1 Detect 检测 检测对端是否存在(靠接收检测电路)
2 Polling 轮询 发送 TS1/TS2 训练序列,建立 Bit Lock 和 Symbol Lock
3 Configuration 配置 交换链路配置信息,完成宽度/速率协商
4 L0 正常 链路完全正常工作,数据随便跑
5 L0s 正常 单方向低功耗,另一方向还醒着
6 L1 正常 两方向都低功耗,需要唤醒退出
7 L2 正常 深度休眠,连主电源都可能关
8 Recovery 恢复 链接质量下降或要改速率时重新训练
9 Hot Reset 复位 收到复位命令后重置链路状态
10 Loopback 测试 发环回数据用于测试(平时很少见)
11 Disable 禁用 链路被强制关闭,不再训练

我在一次硬盘接口兼容性测试里,碰到过链路反复在 Polling 和 Configuration 之间来回跳,最后发现是 SerDes 的 CDR 锁定时间太长,导致训练序列没来得及对齐。那次排查让我彻底记住了这几个状态的前后顺序。

3.2 核心跳转路径——从清零到跑数据

一个典型的从复位到 L0 的路径是这样走的:

  1. Detect → 发送方定期发出脉冲,接收侧检测到 RC(接收检测) 信号就认为链路存在。
  2. Polling → 两边互发 TS1/TS2,完成 Bit Lock(位锁定)和 Symbol Lock(符号锁定)。这一步我们上一章刚讲过。
  3. Configuration → 通过 TS2 中的配置字段协商:8GT/s 还是 16GT/s?Lane 宽度是 x4 还是 x8?
  4. L0 → 配置完成,双方发 EIOS 进入正常数据流。

你可能会问:如果中途出错怎么办?比如 Polling 阶段收不到正确的 TS 序列?

LTSSM 的设计思想是「出错了就回退重试」,但不会退太多。具体的超时和重试次数在 SPEC 里都有规定。我记得有一个项目,FPGA 的 GTY 收发器在 Configuration 阶段因为 PLL 锁定抖动太大,导致链路在 Recovery 和 Configuration 之间死循环,最后我们不得不在 FPGA 里手动加上了一个 training retry counter——嗯,那是跟芯片工程师一起熬夜调出来的「土办法」。

💡 调试小技巧: 用逻辑分析仪抓 LTSSM 状态跳转时,别只看 TS 序列,同时抓一下 PHY_STATUS 和 LINK_UP 信号。很多时候硬件已经跳进了 L0,但 LinkUp 没拉起来——那是内部状态寄存器的同步问题。

3.3 11 个状态的完整跳转图

下面这张 SVG 图展示了 LTSSM 核心状态之间的典型跳转关系。注意我只画了常规路径(为了可读性),SPEC 里的完整跳转有几十条,别被吓到。

LTSSM 核心状态跳转总览 Detect Polling Configuration L0 Recovery L0s / L1 / L2 红色虚线 = 失败回退 绿色虚线 = 恢复成功 蓝色虚线 = 省电唤醒

3.4 触发条件:什么时候跳?

每个跳转背后都有明确的触发条件,我挑几个容易迷糊的讲一下:

  • Detect → Polling:Receiver Detect 成功,只要任一条 Lane 检测到对端存在就跳(不要求所有 Lane)。
  • Polling → Configuration:收到连续 8 个训练序列(TS1 或 TS2)并且 Symbol Lock 已经建立——注意,这里要求所有 Lane 都锁定了才跳。
  • Configuration → L0:双方都完成了速率和宽度协商,并且发送了 EIOS(进入空闲状态序列)。
  • L0 → Recovery:任意一条 Lane 的误码率高于阈值,或者收到对端发的训练序列。

有一个坑很多人踩过:Configuration 阶段有个“Equalization Phase”,在 8GT/s 以上必须做,如果主控端没发 Equalization TS2 或者 PHY 不支持,链路就会卡在 Configuration 里超时,然后跳回 Detect。我遇到过一块国产 SSD 控制器,它的 PHY 只支持到 5GT/s,插到 16GT/s 的槽位上就一直 Detecting→Polling→Configuration→Detect 循环,跑不起来。

⚠️ 实际排查经验: 如果看到链路在 Polling 和 Configuration 之间反复跳,先别急着怀疑硬件坏了。检查一下对端是否支持你当前试图协商的速率。很多低速设备只支持 2.5GT/s,插到高速主控上也会触发这种 loop。用 PCIe 分析仪抓一下训练序列里的 Speed Change 标志位,能马上定位问题。

3.5 我在项目中用的速查表

下面这个表我每次写训练程序前都会瞄一眼,它把“常见问题→可能卡的状态→典型根因”列出来了:

现象 停留状态 常见根因
链路从未拉起 Detect 接收检测电路故障、对端未上电、REFCLK 不对
一直发 TS1 没反应 Polling CDR 未锁定、差分信号摆幅小、PCB 走线过长
反复进入 Recovery Recovery → Polling 信号完整性差、ESD 击穿、插入损耗超标
训练完成但数据错误 L0 DP/N 极性接反、Lane 映射错误(多见 x4/x8 配置)

我个人习惯是把这张表贴在调试工位的墙上。有一次一个同事调了一整天没法让 NVMe SSD 被识别,我过去看了一眼——嗯,逻辑分析仪显示链路卡在 Polling,再查 CDR 锁定时间,发现 REFCLK 有 100ppm 频偏。调了时钟源的配置后,第一次训练就进了 L0。

LTSSM 总览就讲到这里。下一小节我们会深入每个状态的内部细节,特别是 Polling 阶段 Bit Lock 到 Symbol Lock 的微观过程——那才是真正的“坑”所在。