2. Detect状态详解

Detect状态是LTSSM链路训练的起点。嗯,说白了,就是设备上电或复位后,要做的第一件事——看看对面有没有人。

我刚开始接触PCIe时,总觉得Detect就是个简单的“握手”动作。后来踩过坑才发现,就这么个状态机,里头的门道可真不少。咱们今天就来扒开看看。

2.1 Detect状态的核心使命

Detect状态的任务很简单:检测链路另一端是否存在。但你别小看这个“检测”,它是一切通信的基础。如果Detect没过,后面的Polling、Configuration想都别想。

具体来说,Detect要做三件事:

  • 发现对端——确认RX端有没有接上设备
  • 确定链路宽度——是x1、x2还是x4、x8
  • 触发后续状态机——成功后跳转到Polling,失败则保持或复位
我个人的经验:调试Detect异常时,最常用的手段就是看LTSSM寄存器。如果设备一直卡在Detect.Quiet,八成是电气层的问题。

2.2 Detect的子状态机

Detect内部还有两个子状态:Detect.Quiet 和 Detect.Active。它们交替运行,直到检测到对端或超时。

子状态 持续时间 动作 退出条件
Detect.Quiet 12ms(强制) 发射器处于电气空闲(Electrical Idle) 等待超时
Detect.Active 视情况而定 发射器发送Gen1 TS1序列 检测到对端响应或超时

你看这个表。Detect.Quiet要等12ms,这事儿很多人不理解。为什么必须等这么久?其实是为了保证对端已经完成复位,进入稳定状态。我遇上过一个项目,就是因为把12ms改短了,导致部分设备热插拔检测失败。

嗯,这里要注意——12ms是硬性规定,别想省。

2.3 Detect.Quiet深度解析

在Detect.Quiet里,发射器要干什么?什么都不干。说白了,就是“静默观察”。

发射器把差分信号驱动到共模电压,保持空闲状态。这时候,接收器是不是有信号?没有。所以我们要等12ms,确保对端也进入空闲状态。

我曾经踩过一个坑:某FPGA实现的PCIe软核,在Detect.Quiet期间没有真正进入电气空闲,而是留了一个小摆幅。结果对手设备一直检测不到,链路就是不起来。后来查了整整两天,才发现是发射器没关干净。

避坑指南:我曾经遇到过,Detect.Quiet状态下,发射器必须满足电气空闲的规范要求——差分电压小于65mV,持续至少100ns。千万别留尾巴。

2.4 Detect.Active深度解析

Detect.Quiet超时后,状态机自动进入Detect.Active。这时候,发射器开始发送Gen1速率的TS1序列。

你可能要问:为什么是Gen1?因为Gen1是基础速率,所有PCIe设备都支持。不管你是Gen2还是Gen3,第一次亮相都得说Gen1的“语言”。

TS1序列怎么发?每16个UI(单位间隔)发一次。每个TS1序列包含16个符号(Symbol),用于同步和训练。

// Detect.Active状态下的典型TS1序列格式(简版)
// 假设链路宽度为x4,每条Lane独立发送
Lane 0: TS1[0..15] -> 等待16UI -> TS1[0..15] -> ...
Lane 1: TS1[0..15] -> 等待16UI -> TS1[0..15] -> ...
Lane 2: TS1[0..15] -> 等待16UI -> TS1[0..15] -> ...
Lane 3: TS1[0..15] -> 等待16UI -> TS1[0..15] -> ...

接收器要干什么?它要监听,看能不能收到有效的TS1序列或者FTS(快速训练序列)。如果收到了,说明对端设备在线,链路宽度也存在了。

这里有个关键点:Detect.Active不会一直发。它有一个超时机制——通常是48ms(加上Quiet的12ms,总共60ms)。如果超时还没收到响应,状态机就回到Detect.Quiet重新来过。

你想想看,为什么要有超时?因为如果对端设备没上电、或者没接好,不能无限等下去。系统要尽快知道链路不通,然后去处理别的。

2.5 链路宽度检测的玄机

Detect状态还有一个隐藏任务——确定链路宽度。

主板上有多个Lane,但实际连接了多少条?是x1、x4还是x16?这需要在Detect阶段初步判断。

判断方法很简单:看哪个Lane收到了TS1。如果一个x16插槽只插了x1的卡,那只有Lane 0有信号,其他Lane都是空闲状态。接收器就知道,哦,原来只要用x1就行了。

但要注意:这只是初步判断。真正的宽度协商在后面的Configuration状态完成。Detect阶段只是“瞥一眼”,知道个大概。

我习惯的做法:在调试时,先看Detect状态退出的跳转目标。如果跳到了Polling,说明至少有一条Lane检测成功。如果跳回Detect,说明所有Lane都失败了。

2.6 Detect状态的配置寄存器

和Detect状态相关的寄存器,主要就是LTSSM相关的控制和状态寄存器。不同厂家实现略有差异,但核心概念一致。

寄存器 位域 描述
LTSSM Control Force Detect 强制进入Detect状态(用于调试)
LTSSM Status Current State 当前状态,0x0表示Detect
Detect Timeout 编程超时值 有些控制器允许修改超时参数

我记得有一次调试遇到奇怪问题:设备明明插好了,但链路死活不起来。后来读LTSSM寄存器,发现Current State一直在Detect.Quiet和Detect.Active之间来回跳,就是进不去Polling。原因是对端的Common Clock不稳定。

2.7 Detect状态流程图

下面这张图展示了Detect状态的核心流程,以及它和其他状态的衔接关系。我把它画成了清晰的分支结构,方便你对照理解。

Detect状态机流程图 Power On / Reset Detect.Quiet (12ms) 发射器处于电气空闲 Detect.Active 发送Gen1 TS1序列 收到TS1? (48ms超时) 超时/失败 成功 进入 Polling 链路训练开始 说明:Detect状态失败会重复尝试,直到成功或系统复位。每次周期约60ms。

2.8 常见故障排查

讲完流程,咱们聊聊实际项目中Detect出了问题的调试经验。我把最常见的几类故障列出来,你遇到了可以直接对号入座。

  • 卡在Detect.Quiet不动:检查上电时序和复位信号。我曾经遇到一个项目,PERST#信号波形不对,导致设备一直处于复位状态。
  • Detect.Quiet和Detect.Active反复跳:大概率是电气空闲检测条件没满足。查一下RX共模电压和差分幅值。
  • 检测成功但跳转到Polling后立刻失败:这是常见坑。Detect只是确认“有个东西在”,但Polling要做更精细的对齐和训练。如果时钟偏差太大,就会挂。
  • 部分Lane检测成功,部分失败:检查PCB走线。有一回我们遇到x8插槽只用了4条Lane,因为另外4条的电容焊错了。

我个人的排查顺序:看电源 -> 看复位 -> 看时钟 -> 看LTSSM寄存器。这个链跟Detect状态的依赖关系完全一致。一步错,步步错。

2.9 小结

Detect状态是LTSSM里最简单,也是最容易被忽视的状态。为什么?因为一旦你硬件设计正确,Detect几乎100%一次通过。但正因为如此,很多人不愿意花时间去理解它。

我认为,一个合格的PCIe工程师,应该对自己设计里每一个“理所当然”的环节都有深刻理解。Detect成功不是运气,是电气、时序、链路宽度等一系列因素恰到好处的结果。

下回你调试PCIe时,别忘了从Detect开始。用逻辑分析仪抓一下波形,看看Quiet时间够不够,Active的TS1发得有没有毛病。这些小细节,往往就是链路不起来的真正元凶。