
几天前我们一篇文章《一文讲懂主机启动时是如何给每个PCIe外设分配BDF的》,有工程师留言问:电脑加电启动的时候,PCIe是全部训练完再枚举,还是训练一个枚举一个?
我们这里结论先说:PCIe 在系统加电启动(boot)时,是"全部链路先训练完成(Link Training),再开始统一进行设备枚举(Enumeration)"。不是训练一个枚举一个。今天的文章将尽量给你一个清晰的解释,掌握这部分对于熟悉PCIe协议很有用。
1. 为什么必须全部训练完才能枚举?
因为枚举需要稳定的 PCIe 拓扑结构(Topology),包括:
-
哪些设备存在
-
每个设备是哪个 Bus/Device/Function
-
每条链路最终的速度、宽度(Gen / Lanes)
-
下游设备是否连通
-
Switch 的下游 port 是不是 active
如果链路没有全部训练成功(进入 L0),根本无法构建完整拓扑。
因此 PCIe Base Spec 要求在枚举开始前,所有链路必须完成 LTSSM → L0。
2. PCIe 链路训练(Link Training)发生在固件阶段(BIOS/UEFI 前期)
链路训练包含:
-
Detect
-
Polling
-
Configuration
-
Recovery(必要时)
-
L0(链路正常状态)
这是PCIE PHY + MAC(硬件自动完成),极少需要 CPU 参与。
训练过程与设备枚举(RC 软件过程)完全独立。
3. 训练完成之后,BIOS/UEFI 才开始做设备枚举 Enumeration
枚举过程包括:
(1) 为 Root Port 分配 Bus numbers
(2) 读取下游设备的 Header Type / Vendor ID
(3) 配置 BAR 寄存器
(4) 为整个系统分配 MMIO / IO space
(5) 初始化 Capabilities(MSI/MSI-X/ACS/ARI 等)
这一阶段属于 PCI Firmware Spec 定义的流程,在 BIOS 中由 RC(Root Complex)程序执行。
也就是说:
只有当所有链路都进入 L0,BIOS 才能完整看到整个 PCIe 拓扑,然后开始枚举。
4. 是否存在"训练一个,枚举一个"的例外?
正常 PC/服务器启动流程 ------ 不会!
但是有两种特殊例外情况值得你关注:
(A) 热插拔场景(Hot-Plug)
Hot-plug port 上:
-
Link Training 在设备插入后发生
-
RC 会动态枚举新增设备
但这是运行时行为,不属于系统加电启动流程。
(B) 某些 PCIe Switch 的"Port-by-port" 初始化
例如一些 Broadcom/PLX Switch 型号可能:
-
Port A 训练成功
-
内部 switch firmware 提前对下游 port 做一些预扫描
但这属于 Switch 内部行为,RC 枚举依然要等所有链路可用后才统一开始。
5. 所以启动流程可以总结为:
Step 1:加电
Step 2:所有 PCIe 端口开始 Link Training
-
PHY 完成 LTSSM 流程
-
链路进入 L0 或失败进入 Recovery
Step 3:所有链路稳定后,BIOS 才开始 PCI Bus enumeration
Step 4:初始化设备、分配 BAR、配置 MSI/MSI-X、ASPM 等
6. 在SerialTek PCIe协议分析仪上也能看到这个证据
你抓加电 trace 会看到:
✔ 一堆 Link Training(TS1/TS2、Equalization Phase 0/1/2)
✔ 全部 link 进入 L0
✔ 然后才出现 BIOS 的 Configuration TLPs(Type 0/Type 1)
例如:
-
Config Read Type 1 → 扫描 Bus
-
Config Read Type 0 → 针对 Endpoint
-
Memory Write → 写 BAR
这正是枚举开始的标志。
这很明确地说明:
枚举发生在所有链路训练之后。
总结 --- 面试级标准答案
PCIe 在系统加电启动时,所有链路必须先完成 Link Training(进入 L0),然后 Root Complex 才能进行统一的 Bus Enumeration。不会训练一个枚举一个。
例外仅在热插拔或某些 switch 的内部预处理流程,普通服务器/PC 不会边训练边枚举。