关于设备树中PCIe根复合体节点ranges属性内核用途的疑问
问题:BIOS预分配PCIe地址后,Linux内核如何使用设备树的ranges属性?
以下是来自linux-5.15.68的arch/arm64/boot/dts/ti/k3-am64-main.dtsi的示例代码:
&cbass_main { ... skip ... pcie0_rc: pcie@f102000 { compatible = "ti,am64-pcie-host", "ti,j721e-pcie-host"; reg = <0x00 0x0f102000 0x00 0x1000>, <0x00 0x0f100000 0x00 0x400>, <0x00 0x0d000000 0x00 0x00800000>, <0x00 0x68000000 0x00 0x00001000>; reg-names = "intd_cfg", "user_cfg", "reg", "cfg"; ... skip ... #address-cells = <3>; #size-cells = <2>; ... skip ... msi-map = <0x0 &gic_its 0x0 0x10000>; ranges = <0x01000000 0x00 0x68001000 0x00 0x68001000 0x00 0x0010000>, <0x02000000 0x00 0x68011000 0x00 0x68011000 0x00 0x7fef000>; dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x00000010 0x0>; }; };
这段ranges属性定义了两个映射规则:
- 起始地址为0x68001000、大小64KiB的IO空间,映射到父总线地址0x68001000;
- 起始地址为0x68011000、大小0x7fef000的32位内存空间,映射到父总线地址0x68011000。
根据设备树文档,这些地址均为物理地址。已知BIOS会在枚举过程中为PCIe端点设备的BAR分配总线地址,该操作无需ranges信息,仅按需分配空闲地址范围。当Linux内核读取ranges属性时,BIOS或引导加载程序已为设备分配了与ranges中不同的PCIe地址,此时内核如何使用该ranges属性?
答案
- 校验地址合法性:内核会用
ranges定义的地址范围,检查BIOS分配的BAR地址是否落在PCIe根端口预定义的合法地址空间内。如果分配的地址超出范围,内核会判定地址非法,可能拒绝初始化设备或输出错误日志。 - 实现地址转换:
ranges的核心作用是定义PCIe总线地址到系统物理地址的映射规则。哪怕BIOS已经分配了总线地址,内核仍需要通过ranges来确定这些总线地址对应的系统物理地址,才能在内存中建立正确的映射,让内核和驱动访问到PCIe设备的寄存器或内存区域。 - 检测资源冲突:内核会基于
ranges规定的可用地址范围,排查BIOS分配的地址是否与系统其他设备的资源(如内存、外设地址)冲突。若发现冲突,内核可能尝试重新分配地址(部分场景支持)或记录冲突信息。 - 支撑DMA地址映射:配合
dma-ranges属性,ranges会帮助内核确定PCIe设备DMA操作的地址转换规则,确保设备能正确访问系统内存中的DMA缓冲区——哪怕BIOS已经分配了BAR地址,DMA的地址转换仍依赖这些预定义的映射范围。
内容的提问来源于stack exchange,提问作者Chan Kim
相关产品推荐
相关产品推荐

