2. Detect状态详解
Detect状态是LTSSM链路训练的起点。嗯,说白了,就是设备上电或复位后,要做的第一件事——看看对面有没有人。
我刚开始接触PCIe时,总觉得Detect就是个简单的“握手”动作。后来踩过坑才发现,就这么个状态机,里头的门道可真不少。咱们今天就来扒开看看。
2.1 Detect状态的核心使命
Detect状态的任务很简单:检测链路另一端是否存在。但你别小看这个“检测”,它是一切通信的基础。如果Detect没过,后面的Polling、Configuration想都别想。
具体来说,Detect要做三件事:
- 发现对端——确认RX端有没有接上设备
- 确定链路宽度——是x1、x2还是x4、x8
- 触发后续状态机——成功后跳转到Polling,失败则保持或复位
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期间没有真正进入电气空闲,而是留了一个小摆幅。结果对手设备一直检测不到,链路就是不起来。后来查了整整两天,才发现是发射器没关干净。
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阶段只是“瞥一眼”,知道个大概。
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状态的核心流程,以及它和其他状态的衔接关系。我把它画成了清晰的分支结构,方便你对照理解。
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发得有没有毛病。这些小细节,往往就是链路不起来的真正元凶。