1. 功能定义
该函数属于 Linux 内核 PCI 子系统,核心功能是为 PCI 总线及其下级设备动态分配未分配的硬件资源(I/O 端口、内存地址、IRQ 等)。
应用场景:系统启动时或热插拔设备后,统一协调 PCI 总线资源。
2. 代码逻辑分解
步骤 1:同步控制
down_read(&pci_bus_sem);
//...
up_read(&pci_bus_sem);
- 目的:通过读写信号量
pci_bus_sem
保护 PCI 总线遍历操作的原子性 - 必要性:防止在遍历总线时发生设备热插拔或配置修改
步骤 2:遍历桥接设备
for_each_pci_bridge(dev, bus)
if (pci_has_subordinate(dev))
__pci_bus_size_bridges(dev->subordinate, &add_list);
- 宏展开:
for_each_pci_bridge(dev, bus)
展开为遍历bus
下所有类型为 PCI 桥的设备pci_has_subordinate(dev)
检查桥设备是否有下级总线(即dev->subordinate
是否非空)
- 关键操作:
__pci_bus_size_bridges()
递归计算下级总线所需资源,并将需要额外资源的设备加入add_list
步骤 3:资源分配
__pci_bus_assign_resources(bus, &add_list, NULL);
- 内部行为:
- 遍历
add_list
中的设备 - 调用
pci_setup_bridge()
配置桥设备的窗口寄存器 - 通过
pci_assign_resource()
为设备分配实际资源
- 遍历
步骤 4:完整性校验
BUG_ON(!list_empty(&add_list));
- 设计意图:断言
add_list
必须为空,若不为空则触发内核崩溃 - 隐含逻辑:所有资源请求必须在此函数内处理完毕,否则存在逻辑漏洞
3. 关键数据结构
结构体 | 作用 |
---|---|
struct pci_bus | 描述 PCI 总线的拓扑结构,包含设备列表、资源树等信息 |
struct pci_dev | 描述 PCI 设备,包含厂商 ID、配置空间指针、资源需求等 |
struct list_head | 内核链表实现,add_list 用于临时存储需要扩展资源的设备 |
4. 调用链示例
pci_assign_unassigned_bus_resources()
├─ __pci_bus_size_bridges() -- 资源需求计算
│ ├─ pbus_size_io() -- 计算 I/O 空间需求
│ ├─ pbus_size_mem() -- 计算内存空间需求
│ └─ pci_bridge_check_ranges() -- 检查桥接器资源限制
└─ __pci_bus_assign_resources() -- 实际资源分配
├─ pci_assign_resource() -- 内核资源分配器接口
└─ pci_setup_bridge() -- 配置桥接器的窗口寄存器
5. 典型问题场景
- 资源冲突:当多个设备请求相同资源范围时,可能触发
BUG_ON
或资源分配失败 - 调试方法:
# 查看 PCI 资源分配日志 dmesg | grep -i "pci_resource" # 检查具体设备资源分配情况 lspci -vvv -s 00:1f.2
6. 代码设计亮点
- 递归处理:通过桥接设备的下级总线递归调用,支持多层 PCI 拓扑
- 动态链表:使用
add_list
动态记录资源需求,避免静态数组限制 - 原子性保障:读写信号量确保资源计算与分配的原子性
该函数体现了 Linux 内核按需动态分配的设计哲学,与早期 BIOS 静态分配方案相比,显著提高了 PCI 设备兼容性和资源利用率。