Polling 状态概览:它在链路训练中的角色和常见问题

咱们先聊聊 Polling 状态。说白了,这是链路训练里最磨人的一个环节。我记得刚接手 PCIe 调试那会儿,十次卡死有七八次都卡在 Polling 上。为什么?因为它的工作模式决定了——它要反复试探对方,确认对方准备好了没有。

Polling 状态在链路训练状态机(LTSSM)里排第二位,在 Detect 之后。Detect 确认物理连接存在,Polling 就要开始握手了——发训练序列,收训练序列,看看能不能建立基本的速度协商。嗯,你可以把它想象成两个人初次握手:先把手伸出去,握一下,松一点,再握实。

这个过程本身不复杂,但坑特别多。我带你拆开看看。

Polling 干的活到底是什么?

Polling 阶段的目标就一个:让链路的发送端和接收端对齐基本的比特率和字符边界。它不涉及链路宽度协商或均衡,那些是后面的事。Polling 只关心——

  1. 发出 TS1 训练序列,周期性重复。
  2. 等待对方回复 TS1 或 TS2。
  3. 如果收到连续的、符合规范的 TS 序列,就认为链路质量达标。
  4. 然后跳转到 Configuration 状态,开始宽度的协商。

这是标准流程。但实际跑起来,卡在 Polling 几乎成了家常便饭。

子状态 动作 常见退出条件
Polling.Active 发送 TS1,等待接收 收到连续的 8-16 个 TS1 或 TS2
Polling.Configuration 发送 TS2,协商基本速度 完成速度协商后跳转 Configuration
Polling.Compliance 进入兼容性测试模式 收到退出指令或超时(通常 2ms)
Polling.Loopback 进入回环测试模式 收到回环退出序列

你可能会问:这么多子状态,哪个最容易卡?我个人经验,Polling.Active 排第一,Polling.Configuration 排第二。

为什么 Polling 容易卡?

原因归纳下来就几个:

  • 信号质量差:接收端看到的 TS 序列全是噪声,没办法锁定比特边界。
  • 时钟恢复失败:CDR(时钟数据恢复)没锁定,采样点偏移,收到的数据全是错的。
  • 对方设备行为异常:比如对面在某个子状态超时后重复重试,或者根本没有发出正确的 TS 序列。
  • 电气参数不匹配:驱动强度、去加重、接收端均衡系数没对准。

核心判断:Polling 卡顿的本质是“收发双方没对上眼”。只要有一方没收到有效的 TS 序列,链路就卡在原地不动。

我曾经在一个项目里遇到过特别奇葩的情况:两片 FPGA 直接对接,PCIe 链路死活过不了 Polling。示波器抓差分信号,波形看着没问题,但协议分析仪显示接收端一直在报“符号锁定失败”。查了三天,最后发现是参考时钟有 300ppm 的偏差——超出规范允许的 ±300ppm 上限。这叫“压线出界”,你说气不气人?

Polling 状态卡顿的表现

遇到卡顿,系统表现通常很一致:

  • LTSSM 状态寄存器一直显示 0x01(Polling)。
  • 数据链路层始终不跳转,链路未激活。
  • 驱动或操作系统超时后报错:PCIe link training timeout。
  • 部分设备会触发链路复位,然后重试——但重试还是卡在同一个地方。

小技巧:用逻辑分析仪抓 LTSSM 状态跳转,如果看到 Polling→Polling→Polling 不变化,先检查物理层信号质量,别急着调软件参数。

Polling 阶段的调试切入点

我个人习惯按这个顺序排查:

  1. 查时钟:测量参考时钟频率和抖动,确保在 ±300ppm 以内。
  2. 看眼图:用示波器看接收端的眼图,张开度够不够,有没有 ISI 或噪声。
  3. 调均衡:如果眼图闭合,尝试调整接收端 CTLE/DFE 参数。
  4. 抓协议:用协议分析仪看 TS 序列是否正确,是不是连续 16 个相同的 TS1。
  5. 看寄存器:读 PCIe 配置空间的 Link Status 寄存器,确认当前速度、宽度、状态。

注意:不要一上来就改链路速率或强制跳转状态。跳过 Polling 可能会导致后续 Configuration 阶段失败得更隐蔽。

下面这张图总结了 Polling 状态在 LTSSM 中的位置以及常见的卡顿原因。

Polling 状态在 LTSSM 中的角色与卡顿原因 Detect Polling.Active 发送/接收 TS1 序列 Polling.Configuration Polling.Compliance Polling.Loopback Configuration 常见卡顿原因 时钟偏差 >±300ppm → 信号质量差 → CDR 失锁 → TS 序列无法识别 → 链路卡死

避坑指南:那些年我踩过的 Polling 坑

我曾经被一个低级问题坑了两天——两根 PCIe 差分线在 PCB 上不等长,差了一百多 mil。当时理论计算出来的时延差不到 0.1UI,觉得无所谓。结果实际跑起来,Polling 总是偶尔过、偶尔不过,概率大概 30% 丢包。后来板子改版拉平等长,问题直接消失。

经验教训:Polling 阶段对信号完整性的敏感度极高。不要光看仿真,实物调试时一定要测眼图。眼图过不了,什么配置都白搭。

再一个常见的坑是:芯片内部的 CDR 锁定时间太长,超过了 Polling 阶段的超时时间。PCIe 规范要求从 Reset 退出到进入 Configuration 必须在 2ms 内完成,但某些芯片的 CDR 需要 1.5ms 才能锁定。这意味着留给 Polling 的窗口只有 500μs,稍微有点干扰就超时。我建议你拿到新芯片,先读一下 CDR Lock Time 的参数,心里有个底。

工具推荐:用 PCIe 协议分析仪的 “Eye Monitor” 功能可以直观看到每个 Lane 的眼图质量。我经常挂机让它连续跑 1 万次训练,看成功率。

最后说一个软件层面的思路。有些系统允许在固件里强制设置 Polling 的重试次数或超时时间。如果硬件上信号质量没问题,只是偶尔因为干扰丢一个 TS 序列,可以适当放宽超时阈值(比如从 2ms 放宽到 5ms)。但这招不能乱用——放宽太多,后级的 Configuration 也可能跟着出问题。

好了,Polling 状态概览就讲这么多。记住一点:碰到卡顿,先看物理层,再谈协议层。顺序走对了,问题至少能解决一半。