3. LTSSM定时器的作用与分类

LTSSM这玩意儿,说白了就是个状态机。状态切换不能瞎跳,得有个「时间尺子」量着。这把尺子,就是定时器。

我刚开始接触PCIe时犯过一个错——觉得定时器配大点总没错,大不了多等会儿。结果板子上电后链路死活起不来。后来才明白,定时器不是越大越好,也不是越小越妙。你得懂它干嘛用的,才能配好它。

核心观点:LTSSM的每个状态转换,几乎都绑着一个定时器。这些定时器决定了链路什么时候该重试、什么时候该上报超时、什么时候该切到下一个状态。不懂定时器,你调不好链路。

3.1 定时器的本质与使命

每个定时器其实就是一个计数器。它按照本地参考时钟(通常是100MHz或125MHz)不停递减。减到0了,就触发一个超时事件。LTSSM根据这个事件决定下一步动作。

我记得有次客户反馈,说他们的板子在Gen3速率下时不时断链。我们抓了LTSSM的trace,发现是某个定时器提前溢出了。原本该跑100us的,实际跑了80us就跳了。嗯,这就是参考时钟抖动造的孽。所以你看,定时器不光值要配对,时钟源也得干净。

用公式来表达的话:

定时器实际时间 = 定时器配置值 × 时钟周期

举个例子,如果你配的寄存器值是10000,参考时钟是10ns,那这个定时器就是100us。这个换算关系,建议你记死了,后面调参天天用。

3.2 定时器的分类方式

我个人习惯把LTSSM的定时器按用途分成四类。这么做的好处是,你在定位问题时能快速锁定「是哪一类定时器出的问题」。

类别 代表定时器 主要用途 关注指标
超时类 TX_TIDS, RX_TIDS 检测链路卡死或对端无响应 超时阈值、重试次数
重试类 Completion Timer, Retry Buffer Timer 保证事务层的可靠传递 重试间隔、最大重试次数
采样类 RX_EIEOS Timer, TS1/TS2 Timer 判定信号稳定/训练完成 采样窗口宽度、判决阈值
电源管理类 L1 Entry Timer, L0s Entry Timer 控制省电状态进出时机 空闲等待时间、唤醒延迟

这四类定时器,设计初衷完全不同。超时类要求快——卡死了赶紧报,别傻等。重试类要求稳——丢了要重传,但不允许无限重传。采样类要求准——眼睛睁开时才能判。电源管理类要求省——能躺就躺,但不能把唤醒搞太慢。

调参口诀:超时宁小勿大,重试宁多勿少,采样宁稳勿急,省电宁慢勿漏。

3.3 四类定时器深入拆解

3.3.1 超时类定时器

这类定时器是链路的「看门狗」。最常见的两个:TX_TIDS和RX_TIDS。

  • TX_TIDS(Transmit Training Sequence Timer):发送端等待接收端回复的最大时间。如果在时间内没收到对端的训练序列,就判定超时,一般会切回Detect或Polling状态重来。
  • RX_TIDS(Receive Training Sequence Timer):接收端等待发送端持续发送训练序列的最长时间。超时时会上报链路不稳定。

我曾经在项目中遇到过RX_TIDS超时导致的「间歇性断链」。现象是链路在Gen3稳定,但Gen4就偶尔掉。查了之后发现,Gen4的速率更高,信号损耗更大,RX端收到的信号质量差,导致训练序列解码失败,跟不上超时阈值。我们把RX_TIDS从24us放宽到36us,问题解决了。代价是——链路训练时间增加了12us。这得权衡。

3.3.2 重试类定时器

事务层的东西,也跟LTSSM定时器挂钩?是的。你不能只看物理层。

Completion Timer就是个典型。它管理的是「我发出一个请求,最多等多久能收到回复」。超时未收到,就发起重试。这个定时器如果配得太小,链路还没走到L0呢就开始狂重试,把缓冲池塞爆。配得太大,真正丢了报文时你半天反应不过来。

注意:Completion Timer的基值是跟LTSSM状态联动的。在L0s或L1状态下,这个定时器要暂停,否则会误报超时。我记得有次验证时发现,用了ASPM后Completion Timer乱跳,就是因为没处理好暂停逻辑。

Retry Buffer Timer是用来控制重试间隔的。你不能连续重试,得留个喘气的时间。这个间隔通常跟TLP的payload大小相关。payload越大,间隔越大。我一般建议payload 128B时用2us间隔,payload 256B时用4us。这个配比经验值,是从实际测试中磨出来的。

3.3.3 采样类定时器

你想想看,链路刚上电时信号乱成狗,你怎么知道它稳定了?靠的是采样类定时器。

RX_EIEOS Timer用于判定接收端是否检测到了EIEOS(Electrical Idle Exit Ordered Set)。这个东西是链路从电气空闲退出的标志。你要是把这个定时器配小了,信号抖一下就被当成退出信号,链路就跟着瞎切。配大了,退出信号真的来了你不理它,响应延迟飙升。

PCIe Spec对EIEOS的判决窗口有严格规定——必须连续检测到4个正确的EIEOS码型才算有效。所以这个定时器的设计值通常是四个码型的传输时间之和,再加20%的余量。我建议Gen3及以下按60ns配,Gen4及以上按30ns配。速率高了,码型变快了,定时器也得跟着缩。

TS1/TS2 Timer用来控制训练序列的持续时间。训练序列发得不够长,对端可能收不到;发得太长,浪费时间。这个值在Equalization阶段特别关键,因为要完成系数交换和相位校准。我记得有次调Gen4的Equalization,就是因为TS2的发送窗口太短,导致发送端还没发完所有系数就被打断了。调大之后,链路稳定到飞起。

3.3.4 电源管理类定时器

这类定时器决定了你的链路有多省电。

L1 Entry Timer表示链路空闲多久后才允许进入L1状态。配小了,链路频繁进出L1,响应延迟高;配大了,链路一直不睡,功耗降不下来。这个值通常在1ms到10ms之间。我个人习惯的做法是:先设成5ms,然后跑流量测试,看有没有因为进L1而丢包;没有的话慢慢往下压,直到出现性能拐点为止。

L0s Entry Timer比L1的更快,是微秒级的。L0s是ASPM的第一个省电层级,进出都很快。但注意,L0s只能在不同通道间独立进入,所以如果你做多通道聚合,L0s的定时器得每通道单独配。这很坑,因为很多IP默认是全通道共享的。我踩过这个坑——一条通道空闲时不该进的也进了,因为别的通道的定时器触发了。

3.4 定时器在Reset场景下的行为

定时器不是永远都在跑的。它受Reset信号影响。

  • Fundamental Reset:所有定时器强制复位到默认值。等于从头来过。
  • Function Reset:只复位跟该Function相关的定时器(比如Completion Timer),其他定时器不受影响。你得确认哪些定时器是per-function的,哪些是全局的。
  • Hot Reset:LTSSM回到Detect状态,所有链路层定时器复位,但事务层定时器(比如Completion Timer)视实现而定。我建议统一复位,省得麻烦。

经验法则:做验证时,第一个测例一定是Hot Reset后检查所有定时器值是否回到预设值。我见过三颗不同厂家的芯片,有两颗在Hot Reset后漏了复位某个Register。这属于基本错误,但就是会在实际项目中反复出现。

3.5 定时器参数之间的关联

你以为每个定时器都是独立的?太天真了。它们之间有耦合关系。

  • L1 Entry Timer & L0s Entry Timer:如果L0s的入口时间比L1小很多,链路会先进入L0s,短期内不会进L1。如果你想让链路快速进入L1省电,就得人为拉大L0s的入口时间。
  • TX_TIDS & Completion Timer:链路层和事务层的超时链是串起来的。TX_TIDS超时会导致链路重训练,这期间Completion Timer还在跑。如果重训练时间超过Completion Timer的阈值,事务层会误认为报文丢了。这个时间窗口,你得算清楚。
  • TS Timer & Equalization Phase:Equalization阶段需要多次交换系数,TS Timer的持续时间必须大于系数交换的总时间。否则就会出现系数还没换完,TS Timer先爆了的情况。我曾经把这个链条画成一张时序图,给软件团队看,他们才明白为什么寄存器配得不一样就会出问题。

下面这张图是LTSSM定时器的整体分类和作用框架,建议你看图的时候想想刚才讲的内容。

LTSSM定时器分类与作用框架 LTSSM定时器 超时类 TX_TIDS / RX_TIDS 重试类 Completion / Retry Buffer 采样类 RX_EIEOS / TS1/TS2 电源管理类 L1 Entry / L0s Entry 定时器间存在耦合关系 • 电源管理定时器影响L0s/L1的进出时机 • 超时定时器与重试定时器有超时链耦合 • 采样定时器决定Equalization过程是否完整 • Reset类型影响各定时器的复位范围

说到底,LTSSM的定时器不是孤立存在的。你在改一个值的时候,要看看它跟周边的定时器有没有联动关系。我看过很多调参数的工程师,上来就改寄存器,改完发现别的地方又冒出来新问题。这就是没理清定时器的分类和作用框架。

嗯,我建议你先把这四类定时器的默认值从Spec里拎出来,列个表,然后对照你项目的链路预算和时钟精度,逐项过一遍。这样再去调参,心里就有底了。