ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Gen6平台下PCIe L0p状态解析:原理、调试与实战

Gen6平台下PCIe L0p状态解析:原理、调试与实战 最近在调一块 Gen6 平台的时候我又跟 PCIe 的 L0p 状态杠上了。说实话以前做 Gen4/Gen5 老项目时这个状态我基本不怎么看反正链路忙时跑满idle 时靠 L0s 和 L1 就能交差。但到 PCIe 6.0 这一代链路速率直接干到 32 GT/s信号从 NRZ 换成了 PAM4芯片的功耗一下子就压不住了。板卡稍微跑点低负载流量散热片温度都能起来这时候才意识到链路电源管理里那个一直不被重视的 L0p反而成了必须正视的节电手段。这篇内容主要围绕“Gen6 下的 L0p”展开把 L0p 的原理、进入退出过程、在 Gen6 里的新坑以及我在实际调试中总结的排查方法串成一份偏实操的笔记。对做 FPGA PCIe 加速卡、服务器网卡、NVMe 控制器或者 PCIe 交换机的工程师来说应该能少走不少弯路。1. L0p 到底是干嘛的一个链路状态机里经常被忽略的状态1.1 LTSSM 中 L0p 的真正位置写过 PCIe 驱动或者抓过 LTSSM 状态的朋友都知道PCIe 的物理层状态机本身就有一堆状态大家最熟悉的是 L0、L0s、L1、L2/L3 这些。L0 是正常工作状态L0s 是低功耗待机快速恢复状态L1 是深度些的低功耗状态L2 基本是辅助电源都关了的状态。而 L0p全称是 L0 partial中文一般叫“部分活动链路状态”。要注意的是L0p 并不是像 L1/L2 那种独立的 LTSSM 状态它本质上属于 L0 的“子模式”。链路在 L0 状态下时不一定要拿满全部的通道lane做传输可以通过把一部分 lane 的发送器和接收器关掉让剩下的 lane 继续工作。这时链路的协议状态仍然是 L0物理介质上却只有部分 lane 在跑这个状态就是 L0p。为什么 Gen6 下 L0p 容易被拿出来单独讲最直接的原因是 PAM4 信号和 32 GT/s 速率把功耗推到了一个不该被忽略的量级。以前 Gen3/Gen4 时代一条 x16 链路全开的功耗也就那样大家习惯性把电源管理外包给 L0s 和 L1到了 Gen6PHY 的差分对功耗、PAM4 接收端的连续时间线性均衡器、FEC 编解码逻辑这些全加起来之后链路即使没有流量功耗也相当可观。1.2 L0p、L0s、L1 的区别别再搞混很多人一开始会把 L0p 和 L0s 弄混我觉得主要原因在于名字太像。实际上这两个机制完全不同L0s 是把每个 lane 的发送器静默接收端进入低功耗接收状态。L0s 里所有 lane 都可以关闭但链路本身不再传输有效数据退出时需要一段时间恢复。L0p 是保留部分 lane 传输有效数据其余 lane 关闭。链路里还有数据在跑只是带宽变小。L1 是把整条链路放到比 L0s 更低的功耗同时要求两端都进入特定的低功耗状态出口延迟更大。用仓库物流打比方L0s 是整个卸货平台都停工等你电话通知大家再来L0p 是平台还开着但只留几个装卸口其它装卸口暂时拉上帘子L1 是整个仓库差不多打烊连灯都关了有人来货时得先开总闸再开工。L0p 的好处是保留了有效数据传输能力因此低吞吐场景下不会因为退出链路状态而损失过多延迟。坏处是还是有一部分 lane 在工作功耗不会像 L1 那样降到很低。1.3 为什么低流量场景会想起用 L0p假设你现在跑一块 Gen6 x16 的加速卡多数业务场景下数据吞吐只有 50 GB/s远远没到链路极限。如果把链路直接切到 L1一旦来一个大任务重新回到 L0 的延迟可能会让业务产生明显的卡顿。如果什么都不做链路所有 lane 都跑着功耗就一直降不下来。L0p 的定位就在这两者之间降到 x8 甚至 x4 去应付低流量等活动数据量上来了再快速回到 x16。实际工程里L0p 的典型场景包括网卡队列空闲但链路不能断要保证首包时延。SSD/NVMe 盘使用率低主机端不需要那么多通道。多主机拓扑里某个根端口实际带宽需求有限不想让整条链路保持满带宽运转。FPGA 加速卡在等待的间隙用来处理器件空闲功耗和散热。2. Gen6 下 L0p 的特征变化与控制机制2.1 PAM4 信号带来的功耗和信号质量双重压力Gen6 相对 Gen5 最直观的变化就是上升到 PAM4 调制。PAM4 在同一个 symbol 里编码 2 bit理论上同样的通道速率下带宽翻倍但 PAM4 的噪声裕量比 NRZ 差不少。为了满足误码率Gen6 引入了前向纠错FEC同时 PHY 的均衡和发送端去加重也要比之前复杂得多。这事儿放到 L0p 里就出现了一个以前不太明显的耦合关系当你把部分 lane 关闭时剩下 lane 的功耗并不会等比例下降因为 PAM4 的 TX 驱动器、RX 的 CTLE/DFE 在活动 lane 上该开着还得开着。而关闭 lane 本身又会造成电源平面上的瞬态电流变化可能反过来影响活动 lane 的信号眼图。在调试时我印象很深的一个问题就是L0p 从 x8 切到 x4 的瞬间活动 lane 的误码率会突然升高。后来定位下去其实不是协议问题而是关闭 lane 的偏置电流跳变影响到同一 PLL 域里其它 lane 的时钟抖动。所以 Gen6 下做 L0p 电源完整性仿真和实测不能像以前那样只盯着功能还得看动态电流特性。2.2 FEC 与 L0p通道数变化会牵动编码分布PCIe 6.0 引入的 FEC 是基于固定长度的码字一般是固定符号数块来做的。在整条链路全宽度工作时FEC 码字会按照所有 lane 的并行数据一起打包这没什么问题。但在 L0p 状态下活动 lane 数变了每个 symbol 分布到 lane 上的逻辑就得跟着调整否则 FEC 保护的数据块就会错位。这也是 Gen6 平台在 L0p 实现上比 Gen5 更麻烦的地方。Gen5 之前没有这个强制的前向纠错机制lane 数的切换更多是 PHY 和链路训练的事到了 Gen6FEC 必须感知当前活动 lane 数并重新映射码字边界。所以很多控制器在 L0p 切换前后会强制先把当前 FEC 码字发完再做 lane 数调整否则收发两端对码字的起始位置理解不一致会直接翻车。2.3 非对称收发通道数L0p 特有的实用能力L0p 有一个容易被忽略但非常实用的能力允许发送方向保留的 lane 数和接收方向保留的 lane 数不一样。就是说Tx 可以按 x16 保留Rx 只按 x4 保留反过来也一样。这个特性叫非对称 L0p在 Gen6 下的典型用途就是应对明显不平衡的业务流量。举一个例子NVMe SSD 在做大量写入时主机往设备方向的数据量远大于设备往主机方向。为了省功耗可以把主机到设备的方向保留 x8设备到主机的方向只保留 x1 或 x2。虽然设备到主机的带宽低了但正好匹配当前业务的写突发特征。等读操作变多再把上行方向加宽。实际使用时要注意非对称 L0p 不是所有设备都支持也不是每个 PCIe 控制器都能灵活配置。硬件设计的时候需要看清楚端点的能力寄存器里有没有对应的 capability bit。2.4 Gen6 L0p 下各 lane 数的带宽变化参考把 Gen6 的带宽变化列成表方便后面设计时估算活动 lane 数数据速率单向典型适用场景x16约 128 GB/s全速传输GPU/AI 加速卡峰值场景x8约 64 GB/s中高负载突发读写较多的业务x4约 32 GB/s低延迟在线业务网卡空闲等待x2约 16 GB/s控制面和少量数据面混合部署x1约 8 GB/s纯管理流量、boot 阶段或低负载待机注意这个表算的是单向有效带宽。PCIe 是双工的两个方向的流量可以同时跑所以在规划功耗方案时两个方向占用 lane 的配置要分别评估这也是非对称 L0p 的价值所在。3. L0p 的进入、退出与工程实现要点3.1 进入 L0p 的条件与链路层协商L0p 不是随便哪个时刻都能进的。最基本的前提是当前链路处于 L0 状态并且链路速率在工作速率而不是降速速率。目标 lane 数必须是 2 的幂1、2、4、8受原始链路宽度限制。两端设备都支持 L0p并且支持对应的 lane 数组合。当前和目标的 lane 数变化不会超过设备能力位所规定的窗口。这些条件满足后进入 L0p 的过程一般由链路层发起。一端设备通过发送特定的链路报文向对端提出 lane 数变更请求对端在收到后确认然后两端在一段时间窗口内完成 lane 数切换。我自己的实际排查经验是L0p 频繁进入失败的情况绝大多数不是卡在协议报文的格式上而是卡在“两端对能力位的理解不一致”。尤其当你把不同厂商的 CPU 和 FPGA 或交换芯片接在一起L0p 的 capability 位定义和默认值有时候有差异导致某一边觉得自己支持 x8另一边却只支持到 x4。3.2 从 L0p 退出不是拨地而起而是有时序要求L0p 退出时需要把关闭的 lane 重新打开这个过程需要时间。关闭的 lane 接收端重新上电、重新做接收检测、再对同步头做锁定每一步都有具体的时序要求。退出时最怕的是业务已经来了但 lane 还没恢复导致缓冲区溢出丢包。在实际 IP 设计里通常会把 L0p 退出路径的延迟拆成几个等级从 x1 恢复到 x2因为只多一条 lane恢复速度很快。从 x8 恢复到 x16涉及驱动器重新上电和均衡收敛需要更多时间。如果设备刚从 L1 出来又马上进 L0p后续退出时间会更不可控。所以 Gen6 下如果做的是低延迟网络应用建议把 L0p 的最低保留 lane 数设置得高一点别为了那点功耗而把所有带宽都减到最小否则尾延迟非常难压。3.3 实测中怎么观察 L0p 是否真的生效判断 L0p 是否生效不能只看功耗表。我的习惯是先在逻辑分析仪或协议分析仪上抓 LTSSM 状态和链路训练序列。L0p 入口阶段你应该能看到链路仍然处于 L0 状态但活动 lane 数量发生了变化在协议分析仪的链路层窗口里也会看到由报文驱动的 lane 数变更。如果条件允许再用功耗分析仪把 PCIe 插槽的 12V 和 3.3V 电流分别抓出来。关注两个关键指标一是进入 L0p 后是否有若干个毫秒级的基本功耗下降二是退出 L0p 时有没有瞬间大电流尖峰。如果只有下降但退出时电流尖峰很大就要检查关闭 lane 的上电次序是否合理。4. 常见问题与排查技巧实录4.1 进入 L0p 后链路掉训练这个现象我在 FPGA 和 CPU 组合的平台里遇到过好几次。表现是设备进入 L0p 之后过了一段时间对端完全失去同步链路重新走了训练流程甚至降速到低速运行。排查顺序一般是先确认两端 L0p 能力位是否对齐。用配置空间读取能力位逐个比对。确认进入 L0p 时间点是否卡在某个 FEC 码字的中间。如果是基本都是硬件对 FEC 码字边界处理不对。确认是否因为关闭 lane 后剩余 lane 的发送端没有维持必要的 TS 序列或者对齐标记导致对端接收状态机误判。最后再检查电源纹波和地弹。对高速系统来说关闭 lane 带来的瞬态噪声影响信号质量真不是玄学。4.2 功耗没有降下来反而增加了有的项目开 L0p 之后整卡功耗不降反增这个坑最常见的原因是进出 L0p 太频繁。每进出一次PHY 就要做一次 lane 重新上电和均衡收敛这期间功耗可能比一直待在 L0 还高。如果业务流量本来就是碎包密集型L0p 开关次数居高不下功耗当然降不下来。解决办法是不要用简单的“链路低利用率”作为进入 L0p 的唯一判据而是加一个时间窗口比如链路利用率低于 10% 并且持续超过 50 微秒才允许进入。退出条件也可以带上迟滞避免在阈值附近来回抖动。4.3 退出 L0p 后出现误码退出 L0p 后误码率升高多半是链路均衡参数没有在 lane 重新启用时再次加载。Gen6 对均衡一致性要求更高有些实现为了省事关闭 lane 后直接把该 lane 的均衡寄存器配置清掉了重新打开时用默认值这跟对方保持的均衡参数就不一致短时间会出现 FEC 纠不过来或者误码。正确的做法是进入 L0p 时保留剩余 lane 以及已关闭 lane 的均衡参数副本退出时按原参数恢复。如果 IP 控制器不能自动保留那要在驱动或固件层做配置备份和恢复。4.4 L0p 退出延迟影响到业务尾延迟如果你做的是 RDMA 网卡或者高频交易这类低尾延迟场景L0p 的退出延迟必须进设计预算。常见调整手段有几个把 L0p 保留 lane 数从 x1 提到 x4减少恢复时的 lane 数跨度。在驱动里对预期的大流量事件做提前唤醒比如收到第一个报文时马上触发全部 lane 恢复。在硬件里做“先恢复 lane 再上报中断”的处理别让软件等到中断后才启动恢复流程。4.5 速查表L0p 排查对照现象可能原因解决倾向链路掉训练能力位不一致 / FEC 码字边界错位核对双方 capability检查码字处理逻辑误码率高均衡参数未恢复保留并恢复均衡寄存器配置功耗不降反增进出 L0p 太频繁增加进入迟滞时间窗口尾延迟超标保留 lane 数太少、退出时序太慢提高最低 lane 数提前唤醒恢复电流尖峰大关闭 lane 上电次序不合理优化电源门控和上电时序5. 这几种工具和平台背景建议提前熟悉如果你要在实物上验证 L0p手里最好有几个东西支持 Gen6 的协议分析仪、带电流探头的功耗分析仪以及能直接读 LTSSM 状态的调试工具。很多逻辑分析仪对 Gen6 的 32 GT/s 信号有点吃力实际抓取时尽量选支持 PAM4 的专用协议分析仪不然看到的数据可能已经是经过重定时或者经过错误修正后的结果未必反映真实链路行为。另外如果项目里有 PCIe switch也要重点看 switch 对 L0p 的处理方式。switch 的上行口和下行口可能各自维护独立的 L0p 状态但 switch 本身的数据通路是共享的一边进入 L0p 另一边未必能省电。更麻烦的是某些 switch 在内部做 packet arbitration 时并不会感知链路已经降到 x1导致大量帧堆积在端口缓冲里出现意料之外的延迟。我在一次测试里就碰到过交换机下行口进了 L0p上行口还全速跑结果某个队列的占用率高居不下出口延迟直接飙了几十倍。当时查了半天最后发现只要把下行口的 L0p 保留 lane 数从 x1 抬到 x4问题就没了。这种跟拓扑相关的细节在芯片手册里一般不会写得很直白实测数据才是真正靠谱的依据。6. 最后说点个人体会我在 Gen6 平台调试中最大的感受是L0p 已经从“可选项”变成了“必须项”。单纯靠 L0s 和 L1 做功耗管理的时代在 PAM4 面前真的不够用。但是 L0p 也是一个典型的“牵一发动全身”的状态从 FEC 映射到均衡参数从电源完整到链路层报文每一处都可能成为坑。如果你刚开始做 Gen6 的板卡或者控制器建议别等到芯片送到手再接 L0p而是在寄存器规划和 IP 选型阶段就把 L0p 能力位、lane 数组合、退出延迟这些定下来。等真实流量跑了再回头补代价通常比想象中大得多。最后再提一个小技巧调 L0p 时把链路利用率统计和功耗统计同步打点时间戳对齐到微秒级很多看似奇怪的功耗问题一对比曲线就立刻露馅了。
返回列表