Polling状态:位锁定与符号锁定

Polling.L0 是 LTSSM 从 Detect 走出来后碰到的第一个正式状态。说白了,这步要是没过,后面全是白搭。我记得刚入行那会儿,Leader 丢给我一块 PCIe 板的调试,链路死活卡在 Polling,我盯着逻辑分析仪看了两天,才发现是位锁定没跑完。嗯,从那以后我对这个状态就特别敏感。

Polling 做的事其实很直白:发训练序列 TS1/TS2,收对方发的 TS1/TS2,同时把自己内部的接收逻辑调整到能正确抓取串行数据流。中间涉及两个关键动作——位锁定 和 符号锁定。它们不是并列关系,而是串行依赖:位锁定没完成,符号锁定根本没机会跑。

4.1 位锁定(Bit Lock)—— 找到数据的“节拍”

位锁定的本质,就是让接收端的时钟恢复电路跟发送端的串行比特流保持同步。PCIe 用的是 嵌入时钟 的差分信号,没有单独的时钟线。接收器只能靠数据边沿来恢复时钟。

标准做法是:接收 PLL 锁定输入信号的频率和相位,使采样点落在眼图中间。这阶段需要发送端持续送出 电气空闲退出序列(Electrical Idle Exit Sequence) 或稳定的 TS1/TS2。我见过不少板卡,就是因为发送端的预加重或去加重没配好,导致接收端 PLL 锁定失败,位锁定一直超时。

个人经验: 调试位锁定问题时,我习惯先用示波器看差分对上的眼图。眼图打开度 < 25% 基本就没戏,优先检查 TX 端驱动幅度和 EQ 设置。

位锁定成功后,接收器会给出 Bit Lock Done 信号。但注意,这只是拿到了频率同步,还没解决字节边界的问题——那得靠符号锁定。

4.2 符号锁定(Symbol Lock)—— 切分 10-bit 字符

PCIe 链路层跑的 8b/10b 编码。发送端把 8 位数据膨胀成 10 位,插入特殊控制字符(称为 K 码),比如 Comma(K28.5)。接收端得从无结构的比特流里找到 Comma 的位置,才能把 10-bit 边界对准。这个过程就叫符号锁定。

具体流程:

  • 连续检测到 2 个以上有效 Comma(K28.5) 且不存在运行差异(RD)错误
  • 接收器把 10-bit 滑动窗口对齐到 Comma 头部
  • 之后开始对后续 10-bit 进行 8b/10b 解码,验证每个符号是否合法
  • 如果连续若干符号解码正确,则宣告 Symbol Lock Done
⚠ 常见陷阱: 有些 FPGA 实现里 Comma 检测阈值写死了 1 个就通过。我曾经碰到过一个 Case,噪声刚好产生了一次假 Comma,导致符号锁定误触发,后续 TS1 序列解析全部乱掉。所以规范要求至少 2 个连续有效 Comma,别偷懒。

4.3 锁定后的交互:TS1/TS2 交换

位锁定和符号锁定完成后,Polling 状态就进入主交互阶段。两端的设备会互发 TS1 和 TS2 有序集,完成以下任务:

任务说明涉及的时间参数
链路速率协商通过 TS1 的速率 ID 字段(GEN1/2/3)确认双方支持的最高速率Polling.Active → Polling.Config 不超过 48 ms
通道对齐多通道链路上,每个 Lane 都锁定后,通过跨通道 Deskew 对齐Deskew 窗口一般在 8 个符号内完成
初始化 FC 信用交换 TS1 的初始流控信用,为后续数据发送做准备无严格超时,但通常随 TS1 一起发送
关键指标: 整个 Polling 状态(包含位锁定和符号锁定)的总耗时,规范要求小于 48 ms。超过这个时间,RC(Root Complex)会认为设备无响应,直接退回到 Detect。我调试过的一个国产 EP,位锁定花了 35 ms 才完成,结果 Link 频频训练失败,后来发现是 PLL 环路慢,换了电荷泵电容就解决了。

4.4 位锁定与符号锁定的调试方法

当我拿到一根 Link 卡在 Polling 时,我一般按以下顺序排查:

  1. 抓取 LTSSM 状态寄存器,确认是停在 Polling.Active 还是 Polling.Compliance。如果是 Compliance,可能是环回测试没关。
  2. 看眼图:用示波器测量差分对上的幅度和抖动。抖动 > 0.3 UI 基本就要查 REFCLK 和去耦合电容。
  3. 读接收器状态:检查 Bit Lock 和 Symbol Lock 标志位。如果 Bit Lock 一直未置位,可能是 PLL 失锁;如果 Bit Lock 置位了但 Symbol Lock 没置位,重点查 Comma 检测逻辑。
  4. 逻辑分析仪看 TS1/TS2 帧:确认对端有没有发出 TS1,格式对不对(比如 Lane 号、速率 ID)。我遇到过 EP 发出来的 TS1 速率 ID 全为 0,导致 RC 认为它只支持 GEN1,最后协商成了 GEN1 但 Link 宽度也错了。
避坑指南: 我曾经调试一块 Zynq 板卡,Symbol Lock 能锁定但数据总报解码错误。后来发现是 8b/10b 解码器里的 RD(运行差异)初始状态没对齐,导致第一个 K 码解析出错。解决方法是在 Symbol Lock 完成后先发一个 SKP(跳过)有序集,让两端的 RD 状态同步一次。

4.5 Polling 状态流转图

下面这张图展示了从电气空闲退出到位锁定、符号锁定,再到进入 Polling.Configuration 的完整路径。这种图在我当年的调试笔记里画了好多遍,每次都能帮我把根因定位快 30%。

Polling 状态:位锁定 & 符号锁定流转 Detect.Quiet Polling.Active 开始 发射 EIoS / TS1 位锁定 (PLL 锁定) Comma 检测 (K28.5) 符号锁定 TS1/TS2 交换 Polling.Config 超时 → Detect 说明: ● 位锁定必须在 38 ms 内完成,否则超时回到 Detect ● 符号锁定依赖至少 2 个连续 Comma,不可降低阈值

4.6 常见失败场景与对策

  • Bit Lock 超时: 检查接收差分对的交流耦合电容(典型值 100 nF,不能变 10 nF),同时确认 TX 端没有因为 PRBS 无效电平导致幅度溢出。
  • Symbol Lock 失败(Comma 没找到): 大概率是 8b/10b 编码极性搞反了——PCIe 的 Comma 在 +RD 和 -RD 下极性不同,有些接收器只认一种极性。我遇到过两次,都是因为硬核的 Comma 检测逻辑只实现了 +RD 版本,而发送端在 RD=-1 时发出的 Comma 被丢弃。解决办法是在发送端强制在发出 Comma 前复位 RD 为正。
  • Symbol Lock 成功后 TS1 解析不过: 看看 Lane 号对齐没有。多 Lane 场景下,每个 Lane 的符号锁定独立,但后续 Deskew 需要各 Lane 都锁定后才开始。如果一个 Lane 的符号锁定延迟过长,会导致整个链路超时。
  • NRZ 抖动超过 0.35 UI: 不是器件本身的输出抖动,就是 REFCLK 的相位噪声。我自己的 Debug 流程:先换单个干净 REFCLK(用信号源),如果锁定时间缩短,说明是时钟树的问题。
⚠ 不要在 Polling 状态忽视电气空闲: 如果发送端在 Polling.Active 期间突然切回电气空闲,接收端的 PLL 会瞬间失锁。我处理过一个 Case:EP 固件 bug,在发送 TS1 过程中被软复位,导致短暂插入了一串 电气空闲有序集(EIoS),RC 误以为 EP 要重新训练,链路直接回滚到 Detect。

好了,关于 Polling 的位锁定和符号锁定,核心就是 PLL 先跟上频率,Comma 再对齐边界,最后用 TS1/TS2 交换元数据。这三步每一环都不容闪失,而且调试时一定要结合示波器、逻辑分析仪和 LTSSM 状态寄存器的信息交叉验证。我没有那种偷懒的工具能一步到位,靠的就是对着规范一条一条对时序——嗯,有些经验,确实是靠踩坑换来的。