白话PCIe 第一季 第六篇 PCIe 枚举——原理与流程
本文部分图片为 AI 生成请注意甄别~一 PCIe 枚举机制1.1 枚举的定义与系统意义在计算机体系结构中PCIe 枚举Enumeration是系统初始化阶段最核心的软件过程。其本质是Root Complex (RC)及其上运行的系统软件BIOS对整个 PCIe 总线拓扑进行“扫描、识别、编号与资源分配”的全过程。当系统上电Power-on或热复位Hot Reset后硬件处于一种“失忆”状态拓扑未知RC 不知道下游连接了多少个设备是直连了 EP还是经过了多级 Switch。地址未映射设备内部的存储器如显存、寄存器虽然存在但在系统 CPU 的物理地址空间System Physical Address Map中尚未分配对应的访问窗口。CPU 此时发出的读写指令无法路由到目标设备。路由未建立所有的 Switch 和 Bridge 都没有被分配总线号Bus Number它们不知道该如何转发 TLPTransaction Layer Packet。因此枚举不仅仅是“发现设备”更是构建 PCIe 路由逻辑与地址解码逻辑的基石。没有成功的枚举PCIe 总线将仅仅是一堆物理连线无法进行任何有效的数据传输Memory/IO TLP。1.2 枚举的三大核心任务详解枚举过程是一个基于深度优先搜索 (DFS, Depth First Search)算法的递归流程主要包含三大任务任务一发现拓扑设备与总线编号PCIe 路由机制之一为基于 ID 的路由BDF: Bus, Device, Function。枚举的首要任务是为总线上的每一个桥Bridge/Switch Port和设备分配唯一的 Bus Number。初始状态RC 默认拥有 Bus 0。扫描动作RC 从 Bus 0 开始依次向 Device 0 ~ Device 31 发送Type 0 Configuration Read Request (CfgRd0)。设备响应如果收到Completion with Data (CplD)且 Vendor ID 非0xFFFF说明设备存在。如果收到Unsupported Request (UR)或超时Master Abort说明设备不存在。关键机制Type 1 Header 的总线号管理当 RC 扫描到一个Switch Upstream Port或Root Port它们都具有 Type 1 Header时意味着发现了一条新的总线。软件必须配置该 Bridge 的以下寄存器Primary Bus Number (PBN)该桥上游连接的总线号例如 0。Secondary Bus Number (SBN)该桥下游引出的新总线号软件分配例如 1。Subordinate Bus Number (SUB)该桥下游子树中最大的总线号。接着RC会继续向新发现的Bus0 向下探索与摸底。解析在 DFS 扫描初期RC 不知道下游有多深。因此通常先将 SUB 临时设为 0xFF这使得该桥能接收所有指向下游的配置包。当该分支扫描结束DFS 回溯时软件会将实际扫描到的最大 Bus Number 回填到 SUB 中完成路由封口。任务二资源需求探测 (BAR Sizing)系统必须精确知道每个 Function 需要多少内存空间以及这些空间的属性是否可预取、是 32 位还是 64 位。这一步通过操作BAR (Base Address Register)完成。确定BAR大小 - 探测算法 (The Write 1s Algorithm) 一个巧妙的软硬件握手协议Disable Decoding软件首先向 Command 寄存器写入 0禁止设备响应内存地址防止配置过程中的地址冲突。Write All 1s软件向 BAR 写入0xFFFFFFFF。Hardware Masking设备硬件根据设计需求强制将低位拉低为 0。例如设备需要 1MB 空间 (2^(20) Bytes)。硬件会将 BAR 的低 20 位Bit 19:0强行锁定为 0Read Only 0只允许高 12 位Bit 31:20被改写。BAR 低 4 位表示类型(设备出厂时写死表示需要的空间大小时被RC当作 4b0 处理)bit0 0 (Memory) /1 (IO)bit1-2 0 (32-bit) /2 (64-bit)bit3 0 (Non-Prefetchable) /1 (Prefetchable)。4.Read Back。软件读取 BAR。读回值为0xFFF00000计算空间时属性位被忽略。5.Calculate Size软件计算Size ~(Read_Value) 1。~0xFFF000000x000FFFFF10x00100000(1MB)。6.Restore软件计算完毕后必须恢复 BAR 的原始值或写入新分配的地址。注意BAR 不可重叠。64-bit BAR 需连续两个 BAR。为什么需要配置 BAR 空间BAR (Base Address Registers) 是配置空间中的寄存器偏移 0x10-0x24EP 有 6 个Bridge 有 2 个用于将设备的内部资源如内存、IO 端口、寄存器映射到系统的地址空间。主要原因地址映射PCIe 是地址路由协议RC 需要知道设备的地址范围才能发送 TLP 到 EP。BAR 定义了设备的 “窗口” base address size允许主机访问 EP 的内部空间e.g., DMA、寄存器读写。资源分配避免地址冲突。BIOS/OS 分配系统内存/IO 给 BAR确保设备可访问如 GPU BAR 映射显存。灵活性BAR 支持 32/64-bit 地址、Memory/IO 类型、Prefetchable可缓存适应不同设备需求。兼容性继承 PCI 传统支持 Plug-and-Play。不配置 BAR设备无法响应 Memory/IO TLP系统无法使用其资源。(Note每个PCIe设备至少有一个配置空间。一个PCIe设备可能具有多个功能Function比如既能当硬盘还能当网卡每个功能对应一个配置空间)任务三地址空间分配与映射 (Allocation Mapping)在探测完所有设备的资源需求后系统软件会在全局物理内存映射System Memory Map中划分窗口。Endpoint 配置系统找到一个对齐的空闲地址如0xA0000000将其写入 EP 的 BAR 中。此时EP 知道凡是目的地址在0xA0000000~0xA00FFFFF的 TLP都是发给我的。2. Bridge/Switch 配置 (Base/Limit 寄存器)这是 PCIe 树状路由的关键。每个 Bridge 必须配置Memory Base和Memory Limit寄存器。原则Bridge 的 Base/Limit 窗口必须完全覆盖其下游所有设备 BAR 范围的总和。路由逻辑当一个 Memory TLP 到达 Switch Ingress Port 时硬件检查Base TLP Address Limit。如果成立则转发到下游否则转发到上游或拒绝。3. 最终使能配置完成后软件向所有设备的 Command Register 的 Command Register 的 Memory Space Enable (MSE) 位写 1。至此数据通路正式打通。二 RC 与 EP 的交互视角枚举是一个RC 发起Request、EP 响应Completion的交互过程。为了讲清楚全流程将软硬件解耦。RC 侧Initiator由运行在 CPU 上的软件驱动(也可以理解为 AXI 总线侧)通过SoC上的 RC 硬件Port口发送CfgRd和CfgWrTLP。RC 需要维护一张虚拟的“总线图谱”。EP 侧Completer被动响应。硬件逻辑负责根据接收到的配置 TLP返回CplD带数据的完成报文或更新内部寄存器。该节为全流程视角部分内容与第一节内容重复。2.1 前置条件链路训练 (Link Training)在枚举开始前物理层必须完成训练。LTSSM (Link Training and Status State Machine) 必须进入L0 状态且 Data Link Layer 必须处于DL_Active状态。如果链路未训练完成RC 发出的配置包将有去无回Request Timeout。2.2 核心流程详解以下流程严格按照 DFS 算法顺序执行。阶段一发现与总线号分配这是枚举的第一步目的是给所有设备发“身份证”。RC 发起探测 (Scanning Bus 0)RC 默认拥有 Bus 0。它开始扫描 Bus 0 上的设备通常是 Root Port 或集成的 EP。动作RC 发送CfgRd0(Type 0 Configuration Read)读取 Device 0, Function 0 的Vendor ID (Offset 0x00)。EP 响应若设备存在返回CplD携带有效的 Vendor ID (非 0xFFFF)。若设备不存在返回UR(Unsupported Request) 或 RC 等待超时硬件层向软件返回0xFFFF。2. 识别设备类型 (Header Type)RC 读取Header Type Register (Offset 0x0E)。Bit 7判断是单功能 (0) 还是多功能 (1) 设备。如果是多功能RC 会继续扫描 Function 1~7。Bit 6:0判断配置空间布局。0x00(Type 0)Endpoint。扫描到此为止这是树的叶子节点。0x01(Type 1)Bridge (Switch/Root Port)。这是树的树枝意味着后面还有子总线需要继续深入扫描。3. 配置桥的总线号 (Bridge Bus Numbering - 关键)当 RC 发现一个 Type 1 Header例如 Root Port 或 Switch Upstream Port时必须配置其 Bus Number 寄存器以建立路由路径。Primary Bus Number桥上游的总线号例如 0。Secondary Bus Number桥下游即将扫描的新总线号例如分配为 1。Subordinate Bus Number这是难点。在扫描初期RC 不知道下游有多深因此通常先暂时设为0xFF或等于 Secondary Bus Number表示“涵盖所有下游”。等下游全部扫描完毕递归返回时再回填最大值。DFS 算法逻辑(按顺序)RC 遇到 Bridge- 分配 Secondary Bus N- 深入 Bus N- 扫描 Bus N 上的设备- 如果又遇到 Bridge- 分配 Secondary Bus N1- ...- 遇到 Endpoint (Type 0)- 返回- 更新上级 Bridge 的 Subordinate Bus Number。阶段二资源探测与分配 (BAR Sizing Allocation)当拓扑确定后软件再次遍历树进行资源分配。BAR Sizing (尺寸探测)RC 动作向 EP 的 BAR 寄存器写入全1(0xFFFFFFFF)。EP 动作硬件逻辑根据设计需求屏蔽低位。例如需要 1MB 空间低 20 位被 Mask 为 0仅高 12 位允许变为 1。RC 动作读取 BAR根据读回的值计算Size ~(Read_Value Mask) 1。同时检查低几位的属性Memory/IO, 32/64-bit, Prefetchable。地址分配 (Allocation)RC 动作在系统全局物理地址空间中寻找一块对齐且空闲的区域例如0xF0000000。RC 动作将0xF0000000写入 EP 的 BAR 寄存器。注意对于 64-bit BAR需要连续两次写操作低 32 位和高 32 位。桥的窗口配置 (Bridge Windows)对于 Switch 或 Root Port必须配置Memory Base/Limit和Prefetchable Memory Base/Limit寄存器。原则桥的窗口必须完全覆盖其下游所有设备申请的地址范围总和。路由依据当 TLP 到达桥时硬件检查地址是否落入 Base/Limit 范围内若是则向下转发。阶段三能力与功能使能 (Capabilities Enable)资源分完了最后一步是“激活”。MPS MRRS 配置RC 必须扫描路径上所有设备的Device Capabilities Register找到最小的Max_Payload_Size_Supported。然后配置所有设备的Device Control Register中的Max_Payload_Size确保路径上没有设备发送超过短板设备能力的包防止 Malformed TLP。配置Max_Read_Request_Size。中断配置 (MSI/MSI-X)RC 分配中断向量并将 Message Address 和 Data 填入 EP 的 MSI/MSI-X Capability 结构中。最终使能 (Bus Master / Memory Space Enable)RC 动作向 EP 的Command Register (Offset 0x04)写入Bit 1 (MSE): 置 1。允许 EP 响应 Memory TLP不做这一步设备对读写无响应。Bit 2 (BME): 置 1。允许 EP 发起 DMA不做这一步EP 发不出包。三 Synopsys PCIe VIP Enum sequence 解析接下来我们以s家用于RC VIP 枚举的sequence-svt_pcie_device_virtual_ep_enumeration_sequence 为例 (以下称Enum_seq)看看实际的 PCIe 工作中发起枚举RC 都做了哪些行为Enum_seq本质上就是一个 RC 端发起、对下游 EP 做枚举和资源配置的 sequence。Enum_seq 行为body()的主流程基本是1 检查链路状态。链路必须已经到 L0而且 VC0 初始化完成否则报错。2 记录目标设备的拓扑信息。把 bus_number、device_number、is_ep_device_vip 等信息写进 ep_enumeration_status。3 做 Function Discovery。探测 PF0..PFn 是否存在拿到有效 BDF判断单/多功能并确认目标 PCIe Capability.Device/Port Type 是否为 Endpoint。4 配置 PF BAR。扫描每个 function 的 BAR0-BAR5识别 32b/64b/MMIO/IO BAR大致算 aperture分配地址并回写 BAR。同时把地址空间范围记到 ep_enumeration_status 里。5 如果打开了 SR-IOV就继续配置 VF。包括找 SR-IOV capability、决定 NumVFs、First VF Offset、VF Stride、System Page Size、配置 VF BAR、可选给 VF 开 BME。6 可选采集 AtomicOp completer 能力。还可以顺手把 AtomicOp requester enable 打开。7 可选打开错误上报。包括 PCIe capability 里的错误上报位以及 AER 相关寄存器。8 可选遍历所有 Base/Extended Capability。把 capability 链表扫出来记录 capability ID 到 base address 的映射。9 获取 Extended VC / MFVC 信息。10 输出汇总并把 ep_enumeration_status 放进 config DB供后续 sequence 使用。总结为下面5条链路就绪检查确认物理链路已进入 L0 状态且 VC0 通道初始化完成这是收发配置报文Cfg TLP的绝对前提。身份与拓扑侦测扫描目标设备的 BDF探测物理功能PF0~PFn的存在性识别单/多功能架构并严格校验其 Endpoint 设备属性。核心资源分配遍历全部 PF BARBAR0~BAR5以探测空间大小并分配系统地址若设备支持 SR-IOV则同步完成虚拟功能VF的 BAR 与路由步进配置。高阶能力解析与使能顺藤摸瓜遍历设备的 Base 与 Extended Capability 链表记录能力集并按需开启 AER高级错误报告、AtomicOp原子操作等特权功能。状态建档与移交(VIP专用)将探测到的地址映射、拓扑结构及设备能力打包记录进 ep_enumeration_status并挂载至 UVM config_db 中作为路书供后续的数据业务 Sequence 调用。总结枚举不仅是软件的事PCIe 枚举虽然主要由系统软件驱动但它是软硬件紧密耦合的过程。对于EP 设计者必须保证 Configuration Space 的硬件逻辑能正确响应每一次读写尤其是 BAR 的掩码逻辑和 Command Register 的控制逻辑。对于RC 设计者必须保证 DFS 算法的健壮性能够应对复杂的拓扑和异常响应。对于验证工程师无论是站在 RC 还是 EP 的视角都需要通过 UVM Sequence 精确模拟枚举的每一步这是后续所有功能测试DMA、MSI、PM的基石当枚举出现问题也需要具备 Debug 定位问题的能力。(本文内容基于 PCIe Base Specification Revision 5.0 及 MindShare PCI Express Technology 3.0 整理)下期预告《基础-框架》 第七篇错误处理 (Error Handling)核心看点深度解析 AER (Advanced Error Reporting) 机制的工作流。剖析 Fatal 与 Non-Fatal 错误的界定标准与系统应对策略。谢谢观看~