Host Bridge、枚举与 PCI 设备生命周期
1. 三类核心对象
struct pci_host_bridge:一个 Root Complex 对 PCI Core 的入口,提供配置访问ops、总线号范围、CPU/PCI 地址窗口和固件节点。struct pci_bus:一段 PCI 总线,保存number、primary/secondary/subordinate、上游桥、设备及子总线链表。struct pci_dev:一个 Function,而不是一张物理卡;0000:01:00.1会对应独立对象。
父子关系是:
1 | pci_host_bridge |
2. Host 注册主链
平台控制器准备好配置空间访问和地址窗口后调用:
1 | pci_host_probe() |
关键入口在probe.c:
pci_host_probe():3096 行;pci_scan_root_bus_bridge():3190 行;pci_scan_slot():2701 行。
Host Bridge 注册与设备扫描是两个阶段。前者把 Root Bus 纳入设备模型,后者才通过配置读发现 Function。
3. 单个 Function 如何被发现
扫描本质是配置空间访问,不是广播“请设备上报”:
1 | pci_scan_child_bus() |
第一次关键读取是偏移PCI_VENDOR_ID的 32 位值。无设备通常返回0xffffffff;CRS 响应则按超时策略重试。随后读取 Header Type、Class、BAR、Subsystem ID 和 Capability。
access.c中的pci_bus_read_config_*()最终调用bus->ops->read()。因此 PCI Core 决定“读哪个 BDF/偏移”,RK3588 DWC Host 决定“如何把它变成 CFG0/CFG1 事务”。
4. 桥递归
发现 PCI-to-PCI Bridge 后,pci_scan_bridge()处理:
- 读取或分配 secondary/subordinate bus number;
- 创建 subordinate
pci_bus; - 递归
pci_scan_child_bus(); - 回填 subordinate 范围;
- 后续资源阶段为桥配置 I/O、MEM、Prefetchable MEM 窗口。
PCIe Root Port、Downstream Port 在 Linux 枚举层仍按桥处理。典型点到点 PCIe 链路只扫描 Device 0,但 quirk、ARI 或扫描标志可改变策略。
5. 加入设备模型与驱动绑定
pci_device_add()先将对象加入 PCI 拓扑;pci_bus_add_devices()再递归调用pci_bus_add_device()。设备进入 Linux Driver Core 后:
1 | device_attach() |
__pci_register_driver()位于pci-driver.c:1447,把drv->driver.bus设为pci_bus_type并调用driver_register()。匹配依据静态pci_device_id、动态 ID 和driver_override,不是 DT compatible。
6. 引用、锁与并发
pci_dev_get()/pci_dev_put()保护pci_dev引用;pci_bus_sem保护全局和总线设备链表的读写;pci_lock_rescan_remove()串行化 rescan 与 remove;- 配置空间访问通常由
pci_lock串行化; - 遍历期间若跨越可能睡眠或设备删除的操作,必须持有引用,不能只保存裸指针。
search.c中的pci_get_device()、pci_get_slot()搜索的是已注册对象,并返回带引用的pci_dev。它们不会访问硬件。
7. 移除路径
remove.c的公开入口:
pci_stop_and_remove_bus_device():115 行;- 带全局 rescan/remove 锁版本:122 行。
逻辑分为 stop 和 remove:
1 | pci_stop_bus_device() |
必须先停止 DMA 和功能驱动,再拆资源与对象。物理拔卡、sysfs remove及错误恢复失败最终都可能进入该路径。
8. Rescan
rescan 在持pci_lock_rescan_remove()时重新扫描槽位或总线,并调用pci_bus_add_devices()。它只能发现“链路和供电已经可访问”的设备,不能替代控制器上电、PERST#释放或链路训练。
9. 生命周期不变量
- 配置访问可用后才能扫描;
- 桥下游对象不得晚于上游桥停止;
- BAR 与 IRQ 必须在设备注销前释放;
pci_driver->remove()返回后驱动不能继续 DMA;- sysfs rescan/remove 与热插拔必须使用同一全局锁避免重复对象和 use-after-free。
正在加载留言…