1、ASPM 概述:什么是 ASPM,PCIe 链路状态
各位好,今天我们聊聊 PCIe 链路里一个挺有意思的话题——ASPM。你打开 BIOS 里那个节能选项后,有时候链路会莫名其妙降速,甚至导致网卡丢包、SSD 掉盘。遇到这种问题,很多人第一反应是关掉它。但你想过没有?为什么 AS PM 会搞出这种麻烦?
我个人习惯,遇到链路降速,先别急着去调寄存器。先搞清楚 ASPM 到底是什么玩意,它控制着 PCIe 链路的哪几个状态。说白了,ASPM 就是让链路在不传输数据的时候,把部分收发器关掉或者降低时钟频率,省点电。但省电是有代价的——退出节能状态需要重新训练链路,这个训练过程会带来延迟。控制不好,就成了灾难。
我记得第一次排查一个 NVMe 盘读写性能突发下降的问题时,看了半天带宽都是正常的,但 IO 延时偶尔飙升到几百微秒。后来发现是 ASPM 的 L1 状态频繁进出,系统的 ASPM 策略太激进,加上盘的固件对 L1 退出处理不够快。从那以后,我每次调 ASPM 都会先看一眼链路实际状态。
1.1 PCIe 链路四大状态
一条 PCIe 链路可以工作在四种能耗等级下。从高到低排列:L0、L0s、L1、L2/L3。Linux 内核里你可以在 sysfs 里看到它们:/sys/bus/pci/devices/.../power/control。嗯,这里要注意,不是所有设备都支持所有状态。
| 状态 | 描述 | 功耗 | 退出延迟 | 是否保留上下文 |
|---|---|---|---|---|
| L0 | 全速工作,数据正常收发 | 高(~100%) | 纳秒级 | 完全保留 |
| L0s | 收发器独立低功耗,一端可停 | 中等(~70%) | 几十纳秒 | 保留 |
| L1 | 主时钟、锁相环可关,需协商 | 低(~10%) | 几微秒 | 部分保留 |
| L2/L3 | 辅助电源供电,几乎全关 | 极低(<1%) | 毫秒级+链路训练 | 丢失,需重新初始化 |
关键理解:L0 是性能基准。L0s 是快速小睡,L1 是深度小睡,L2/L3 就是关机重新开机的节奏。降速的根本原因,常常是链路在退出 L1/L2 时重新训练,导致短暂中断,被操作系统或者驱动判断为“不稳定”,从而协商到一个更低的速率或更窄的宽度。
1.2 L0s 和 L1:两种节能机制
ASPM 主要管两种节能方式:L0s 和 L1。L2/L3 一般需要操作系统或固件主动触发,比如进入 S3 睡眠。
- L0s:允许发送器或接收器单独进入空闲。举个例子,如果一个方向没有数据,那这个方向的收发器就可以停掉。退出时间很短,所以对性能影响很小。但我遇到过某些老旧网卡,L0s 一开就丢包,因为接收器还没准备好就来了报文。
- L1:链路两端都要同意才能进入。主时钟都停了,退出时需要通过链路训练序列重新握手。这就有风险了。你想想看,如果系统每秒进入 L1 几十次,每次退出都花 5~10μs,累积的延迟就非常可观。
踩坑提示:我曾经处理过一个 SSD 的案例,它的 BUG 是 L1 退出后没有正确恢复链路宽度,从 x4 降到了 x2。排查时用 lspci -vv 看到 LinkSta 里的 Negotiated Width 变成了 2,但 Capabilities 里支持 x4。后来在 BIOS 里禁用了 ASPM 就正常了。所以调试时一定要先看链路协商结果。
1.3 状态转换图
下面这张图展示了 ASPM 控制的链路状态迁移关系。正常情况下链路在 L0 全速运行,空闲时根据策略降到 L0s 或 L1,超长时间空闲或者系统进入休眠时落到 L2/L3。
图上箭头大致表示了常见的迁移路径。你可以看到,从 L0 可以降到 L0s 或 L1,但 L1 能进一步降到 L2/L3。反向迁移时,L0s/L1 回到 L0 相对快,L2/L3 回到 L0 就慢得多。这就是为什么操作系统无谓地让链路掉到 L2 之后,你可能感觉设备“消失”了几十毫秒。
1.4 ASPM 的软件控制
Linux 下我们主要通过 /sys/module/pcie_aspm/parameters/policy 来调整 ASPM 策略。常见的策略有:
- default:BIOS 指定的(通常比较保守)
- performance:禁止 ASPM,永远 L0
- powersave:尽量开启所有支持的节能状态
- powersupersave:甚至允许 L2/L3 主动进入
我曾经在调试服务器存储时,发现默认策略下磁盘带宽掉了一大截,用 cat /sys/module/pcie_aspm/parameters/policy 一看是 powersave,改成 performance 就恢复了。但更精准的做法是用 setpci 或内核提供的小工具逐设备控制。
注意:不要在生产环境无脑关 ASPM。现代设备,特别是笔记本和嵌入式系统,ASPM 开启后能省几十瓦功耗。关键是找到合适的策略和固件配合。如果你只是做功能验证,建议先打开内核调试信息:echo 'file drivers/pci/pcie/aspm.c +p' > /sys/kernel/debug/dynamic_debug/control
看链路状态切换是否频繁。
1.5 为什么要理解这些状态?
回到最开始的问题:ASPM 开启后链路降速,本质是链路在节能状态和全速状态之间切换时,没有按照预期恢复,或者切换本身引入了过多的延迟,导致对端或主机以为链路不可靠,从而协商降速。你只有理解了 L0、L0s、L1、L2/L3 的退出代价,以及它们是如何被触发的,才能快速定位瓶颈。
举个例子,某个 USB4 (其实是 PCIe 隧道) 设备在传输大文件时出现断流,用 lspci 看到链路频繁从 L0 跳到 L1。我检查发现系统的 L1 退出延迟设置太短,设备根本来不及完成一次 DMA 传输就被踢回 L0s,反复训练把链路搞崩了。最终调大了 L1 退出延迟的阈值,问题消失。你看,这些细节比直接关 ASPM 高明多了。
推荐工具:lspci -vv -s <设备BDF> 看 LinkCap 和 LinkSta,里面有 ASPM 支持能力和当前状态。实时监控可以用 watch -n 1 'lspci -s 设备 -vv | grep -E "L[0-9]|ASPM"'。
好了,本章先把 ASPM 的基础概念和链路状态讲清楚。后续我们会逐步深入到寄存器、驱动修改、以及实际案例分析。记住,遇到降速先看状态,再做判断。