1.链路的训练硬件上电后自发行为 不需要软件参与当外部 PCIe 设备链路训练成功LTSSM → L0后链路状态进入L0状态这个是host 能够枚举到pcie 外设的前提。只有进入L0阶段 RC才能发送TLP报文给pcie设备读取PCIE的BAR 寄存器 获取pcie设备信息多级拓扑Root Port → Switch → EP的时候每一段物理链路都必须进入 L0任意一段不通下游设备全不可见L0: 正常工作模式L0S 省电模式L1 休眠L2:深度休眠2. 从 Bus0 开始遍历所有 Device / FunctionPCIe 固定寻址规则Bus0~2558 位Device0~315 位Function0~73 位内核循环for (bus 0; ...) for (dev 0; dev 32; dev) for (fn 0; fn 8; fn)对每个(bus, dev, fn)做一件事读配置空间偏移 0x00 的 Vendor IDPCIe 兼容 PCI 的配置空间寻址机制。在标准的32位配置地址寄存器Configuration Address Register中地址被划分为以下几个部分表格字段位数 (Bits)范围说明Reserved7-保留位Bus Number80 ~ 255总线号(决定最大支持256条总线)Device Number50 ~ 31设备号 (每条总线最多32个设备)Function Number30 ~ 7功能号 (每个设备最多8个功能)Register Offset60 ~ 63寄存器偏移 (指向配置空间内的具体寄存器需左移2位)3. 判断设备是否存在最关键一步读到0xFFFF无设备 / 无响应→ 跳过读到有效 Vendor ID非全 1存在设备→ 内核创建pci_dev结构体4. 区分是「端点 EP」还是「桥 Bridge」读配置空间0x0E寄存器Header TypeType 0 (00h)→ Endpoint普通外设网卡、GPU、FPGA、USB 控制器Type 1 (01h)→ PCIe BridgeRoot Port、Switch 上游 / 下游口5. 如果是桥Type1→ 分配新总线递归扫描下游这是PCIe 树形拓扑能被扫全的核心给桥分配Primary Bus当前总线上游Secondary Bus新总线号下游总线起点Subordinate Bus预留最大总线号以Secondary Bus为新根递归执行步骤 2~4扫完下游回到上一级继续扫这就是为什么 Switch 下面的设备也能被扫到桥 通往新一层总线的 “门”6. 收集所有设备后统一分配资源内核遍历所有pci_dev做解析 BAR大小、类型、预取、32/64 位分配物理地址MMIO避免冲突分配 MSI/MSI-X 中断向量配置 PCIe 能力PCIe Link、Power、MSI-X 等7. 设备与驱动匹配 → 调用你的 probe内核拿着设备的Vendor IDDevice IDClass CodeSubsystem ID去匹配内核中所有pci_driver的id_table匹配成功就调用pcie的probe函数 加载驱动。pcie设备的地址空间和BAR 寄存器BAR 放在 PCIe 设备配置空间里的「地址资源申请表」枚举的过程本质就是 主机读取PCI 配置空间Type0 头对应 EndpointType1 头对应 Switch / 桥获取设备信息、类型和BAR 寄存器 同时给BAR寄存器分配内存。过程读Vendor ID判断设备是否存在读Header Type区分 Type0 / Type1读Class Code / Device ID识别设备类型读BAR获知需要多大内存空间给soc内部地址空间中给pcie bar寄存器分配地址并把这个地址回写到BAR 寄存器中。 相当于完成地址映射。若为 Type1 桥 → 分配总线号递归扫下游什么是pcie配置空间---》每个pcie设备欸有自己的配置空间 soc 范围pcie的配置空间获取pcie 设备的类型、BAR寄存器。SOC 怎么获取到pcie 设备的配置空间 地址--》是soc的pcie 基地址遍历pcie 拓扑接口获取的bus等信息。每个设备的具体配置地址 soc pcie的基地址 按 Bus/Dev/Fn 计算的偏移Pcie的配置空间有哪些格式---》PCI 配置空间只有两种头格式Type 0 Header给PCIe Endpoint终端设备用Type 1 Header给PCIe Bridge桥设备用配置空间和BAR 寄存器 布局AR 寄存器Base Address Register总结BAR 是PCI/PCIe 终端设备Type 0 配置头配置空间中偏移 0x10~0x24最多 6 个的专用寄存器是设备与主机约定物理地址资源的硬件接口包含地址属性32/64 位、预取、内存 / I/O 类型和主机分配的物理基地址。pci_host_probe的宏观职责和代码的物理动作完美对应了起来pci_scan_root_bus_bridge(bridge)→ 对应你标注的“扫描root和ep”。这是发现阶段内核通过读取配置空间把整棵总线树和设备节点“摸”出来。pci_bus_assign_resources(bus)→ 对应你标注的“分配各个ep的bar 地址空间”。这是分配阶段内核把实际物理地址基地址写入每个 EP 设备的 BAR 寄存器让它们能真正被 CPU 访问到。这两个函数就是内核初始化 PCIe 总线的两大核心支柱先扫描后分配。主机给 BAR 寄存器分配并回写物理地址后就拥有了与 PCIe 设备通信的「硬件地址入口」驱动通过 BAR 映射的地址访问设备寄存器既可以下发控制配置也能间接完成网络数据等大量数据的传输这是 PCIe 设备工作的基础。其中Type0 Header最多有6个BAR而Type1 Header最多有两个BAR。这就意味着对于Endpoint来说最多可以拥有6个不同的地址空间。但是实际应用中基本上不会用到6个一般是1-3个BAR假设插了一块 博通switch 网卡枚举阶段系统读到 VID8086、DID10BF、Class0200 → 识别是 博通 网卡系统给 BAR0/BAR1 分配物理地址回写 BAR 寄存器加载 博通专用驱动 → 驱动里写死了 “BAR0 是控制寄存器BAR1 是 DMA 描述符”驱动通过 BAR0 配置网卡、通过 BAR1 设置数据包缓冲区实现收发包个人理解配置空间里面很多信息 其中就有bar寄存器地址。 我们知道bar 寄存器地址后 soc 先向bar寄存器写0xFFFFFFFF看看返回多少个0确定需要分配多大ram 空间 soc 配置分配地址以后 把ram 地址写入到bar 寄存器。 这样bar 地址就映射到了soc内部的ram区域 可以通过这个ram 区域和pcie 通信。完整流程可以这样看RC 写 BAR 0xFFFFFFFF ↓ EP 硬件把低位不可写位清零返回掩码 ↓ RC 算出 BAR 大小 ↓ RC/OS 在系统物理地址空间分配一段对齐地址 ↓ RC 把物理基地址写回 BAR ↓ 使能 Command Register 的 Memory Space Enable ↓ CPU 访问该物理地址 → RC 转发成 PCIe Memory TLP → EP 内部寄存器 看一下RC 驱动代码 pci_host_probe(host)pci_host_probe的宏观职责和代码的物理动作完美对应了起来pci_scan_root_bus_bridge(bridge)→ 对应你标注的“扫描root和ep”。这是发现阶段内核通过读取配置空间把整棵总线树和设备节点“摸”出来。pci_bus_assign_resources(bus)→ 对应你标注的“分配各个ep的bar 地址空间”。这是分配阶段内核把实际物理地址基地址写入每个 EP 设备的 BAR 寄存器让它们能真正被 CPU 访问到。这两个函数就是内核初始化 PCIe 总线的两大核心支柱先扫描后分配。