BAR、桥窗口与地址资源分配

BAR、桥窗口与地址资源分配

1. 三种地址

PCI 资源分析必须区分:

  1. 设备 BAR 中保存的 PCI Bus Address;
  2. Root Complex outbound window 接收的 CPU Physical Address;
  3. 内核struct resource记录的 CPU 侧资源区间。

Host Bridge window 的 offset 用于pcibios_resource_to_bus()pcibios_bus_to_resource()转换。RK3588 上还需由 DWC iATU 把 CPU 地址窗口变成 PCIe Memory/IO/CFG 事务。

2. BAR 探测

probe.c中的pci_read_bases()读取 BAR。标准 BAR 大小探测通常是:

1
2
3
4
5
保存 BAR
写全 1
读回硬件实现的地址掩码
恢复 BAR
由掩码计算 size

代码还需处理:

  • I/O BAR 与 Memory BAR;
  • 32 位与成对的 64 位 BAR;
  • Prefetchable 属性;
  • Expansion ROM;
  • 固件已分配、未分配及冲突资源;
  • 桥窗口和 SR-IOV VF BAR。

探测时必须谨慎控制PCI_COMMAND_MEMORY/IO解码,避免设备把探测值当成有效地址响应。

3. Host 窗口

控制器驱动解析 DT ranges或 ACPI _CRS,将窗口加入pci_host_bridge->windows。Root Bus 注册时转换为pci_bus可用资源池。

bus.c提供:

  • pci_add_resource_offset():登记窗口及 CPU/PCI offset;
  • pci_bus_add_resource():向总线加入资源;
  • pci_bus_alloc_resource():在父窗口中按大小、对齐和 flags 分配。

它只提供资源树操作原语,不负责整棵拓扑的分配策略。

4. 两阶段桥资源算法

PCI_PROBE_ONLY路径通常执行:

1
2
3
4
5
6
7
pci_bus_size_bridges(root)
-> 自底向上统计每座桥下游需求
-> 计算 IO/MEM/PREFETCH 窗口大小和对齐

pci_bus_assign_resources(root)
-> 自顶向下从父窗口分配桥窗口
-> 再分配下游设备 BAR

setup-bus.c负责全树策略。桥窗口必须先覆盖下游 BAR,且 64 位 prefetch 窗口、CardBus、热插拔预留空间及资源重分配会改变 sizing。

pci_assign_unassigned_bus_resources()位于setup-bus.c:2538,用于新增设备或局部 rescan 后的未分配资源。

5. 单 BAR 落地

setup-res.c负责:

1
2
3
4
5
6
7
pci_assign_resource(dev, bar)
-> 选择父资源窗口
-> pci_bus_alloc_resource()
-> pci_update_resource()
-> CPU resource 转换为 bus address
-> 写 BAR/ROM 配置寄存器
-> claim 到 iomem/ioport resource tree

64 位 BAR 写入时要考虑高低 32 位顺序及 decode 状态。若写回读验不一致,代码会报告 BAR 更新失败;此时不能只看lspci显示的数值,还应检查 Host window 与 iATU 是否覆盖该区间。

6. Claim 与 Assign 的区别

  • Claim:接受固件已有地址,并尝试挂入内核资源树;
  • Assign:内核选择新地址并写回设备;
  • PCI_PROBE_ONLY常用于固件资源不可随意改变的平台;
  • pci=realloc=on允许在桥窗口不足等情况下尝试重分配;
  • CONFIG_PCI_REALLOC_ENABLE_AUTO可在 SR-IOV BAR 缺少空间时自动开启策略。

资源冲突并不一定表示 BAR 本身错误,也可能是 DT ranges、固件保留区或两个 Host Bridge 窗口重叠。

7. 驱动使用资源

功能驱动典型顺序:

1
2
3
4
5
pci_enable_device_mem()
-> pci_request_regions()
-> dma_set_mask_and_coherent()
-> pci_set_master()
-> pci_iomap()/devm_pci_iomap_regions()

pci_enable_device*()增加 enable 计数并设置 Command 寄存器的 I/O 或 MEM decode;pci_set_master()设置 Bus Master 位。仅完成枚举不会自动授权某个功能驱动使用全部 BAR。

remove 顺序应反向执行,并先停止设备 DMA:

1
2
3
4
5
stop DMA/IRQ
-> pci_clear_master()
-> unmap
-> pci_release_regions()
-> pci_disable_device()

8. RK3588 DWC iATU

DWC Host 使用 outbound iATU:

  • CFG0:访问直连下游设备配置空间;
  • CFG1:访问桥后多级总线;
  • MEM/IO:CPU 对 BAR 的访问转换为 PCIe TLP。

因此“Link Up 但 VID 读为0xffffffff”常查 CFG ATU;“可以枚举但 BAR MMIO 超时”常查 MEM window、DT ranges及 outbound ATU,而不是重复修改枚举逻辑。

9. 常见故障

现象 重点检查
BAR ... no space Host ranges大小、桥窗口、64 位/32 位约束
can't claim BAR iomem 冲突、固件保留、重复窗口
桥后设备无资源 subordinate bridge window sizing
BAR 可见但访问异常 DWC outbound iATU、设备供电、MEM decode
VF 创建失败 -ENOSPC SR-IOV VF BAR 与上游桥预留空间

文章互动

阅读 --

留言

0 条留言

正在加载留言…