2. 设备树基础:设备树语法、节点、属性、reg、compatible、interrupts 等核心概念

设备树(Device Tree,DT)是一种描述硬件资源的数据结构,它使用节点(node)和属性(property)的树形层次结构,将不可枚举的硬件信息从内核代码中剥离出来。在 PCIe 控制器配置中,设备树是描述 RC(Root Complex)和 EP(Endpoint)拓扑、地址空间、中断路由的核心载体。本节将系统讲解设备树的语法、节点结构、关键属性及其在 PCIe 场景下的具体用法。

2.1 设备树语法基础

设备树源文件(.dts)采用一种类 C 的文本格式,经过 DTC(Device Tree Compiler)编译为二进制设备树 Blob(.dtb)。其基本语法规则如下:

  • 节点(Node):以 node-name@unit-address 形式定义,@ 后的地址用于区分同名节点。
  • 属性(Property):键值对,值可以是字符串、整数、字节数组、字符串列表等。
  • 标签(Label):为节点或属性起别名,便于引用,如 pcie0: pcie@1e0000000。
  • 包含文件:使用 #include 引入 .dtsi 头文件,实现 SoC 级复用。
  • 根节点:/ 表示设备树的根,所有设备节点挂载其下。
💡 实战要点:PCIe 控制器节点通常定义在 SoC 的 .dtsi 文件中,板级 .dts 通过 &pcie0 标签引用并覆盖属性,如 status = "okay" 使能控制器。

2.2 节点结构与层次关系

设备树节点形成一棵从根节点开始的树。每个节点代表一个硬件设备或总线,子节点表示挂载在该总线上的设备。PCIe 控制器节点通常位于 SoC 内部总线(如 AXI、AHB)之下,其子节点对应 PCIe 总线上的设备。

设备树节点层次结构(PCIe 场景) / (根节点) soc@0 pcie@1e0000000 (RC 模式) pci@0 (PCIe 总线域) ep@0 (Endpoint) bridge@1 (PCIe桥) 说明:PCIe 控制器节点下挂载 pci 总线节点,总线节点下再挂载 EP 或桥设备节点,形成三级层次

2.3 核心属性详解

设备树属性是描述设备特征的关键。以下表格列出了 PCIe 控制器配置中最常用的属性及其含义:

属性名 值类型 PCIe 场景含义 示例
compatible 字符串列表 匹配驱动,格式为 "vendor,device" "fsl,imx8mq-pcie"
reg 地址/长度对 定义控制器寄存器基址和配置空间 <0x1e0000000 0x100000>
interrupts 中断描述符 指定 PCIe 控制器中断号和触发类型 <0 0 4> (GIC SPI)
ranges 地址转换表 将 PCIe 总线地址映射到 CPU 地址空间 <0x81000000 0x0 0x40000000>
bus-range 整数对 PCIe 总线号范围 <0x00 0xff>
num-lanes 整数 PCIe 链路宽度 <4> (x4)
max-link-speed 整数 最大链路速度代次 <3> (Gen3)
status 字符串 设备使能/禁用 "okay" 或 "disabled"

2.4 reg 属性:地址空间描述

reg 属性是设备树中最核心的地址描述属性,它由一个或多个地址/长度对组成。对于 PCIe 控制器,reg 通常包含以下内容:

  • 控制器寄存器基址:DWC(DesignWare Core)或 PLDA 等 IP 核的配置寄存器空间。
  • 配置空间基址:ECAM(Enhanced Configuration Access Mechanism)映射的 PCIe 配置空间。
  • IO/内存空间基址:可选,用于非透明桥或特定 EP 场景。
pcie0: pcie@1e0000000 {
    compatible = "fsl,imx8mq-pcie";
    reg = <0x00 0x1e0000000 0x0 0x100000>,  // 控制器寄存器
          <0x00 0x1e0100000 0x0 0x100000>;  // 配置空间 ECAM
    reg-names = "dbi", "config";
    #address-cells = <3>;
    #size-cells = <2>;
    device_type = "pci";
    ranges = <0x81000000 0x0 0x00000000 0x0 0x40000000 0x0 0x00010000>,
             <0x82000000 0x0 0x40010000 0x0 0x40010000 0x0 0x3fff0000>;
    bus-range = <0x00 0xff>;
    num-lanes = <4>;
    max-link-speed = <3>;
    interrupts = <0 122 4>;
    interrupt-parent = <&gic>;
    status = "okay";
};
🔑 关键理解:#address-cells = <3> 表示 PCIe 地址使用 3 个 32 位单元描述(总线号+设备号+功能号+偏移),#size-cells = <2> 表示长度使用 64 位。这是 PCIe 设备树节点的标准配置。

2.5 compatible 属性:驱动匹配

compatible 属性是设备树与 Linux 驱动之间的桥梁。内核通过设备树匹配表中的 of_match_table 来查找对应的驱动。PCIe 控制器的 compatible 通常遵循 "vendor,soc-ip" 格式:

SoC/平台 compatible 字符串 对应驱动
NXP i.MX8MQ "fsl,imx8mq-pcie" dw_pcie_host.c / dw_pcie_ep.c
Xilinx ZynqMP "xlnx,zynqmp-pcie" pcie-xilinx.c
Rockchip RK3588 "rockchip,rk3588-pcie" pcie-dw-rockchip.c
Intel Agilex "intel,agilex-pcie" pcie-altera.c

2.6 interrupts 属性:中断路由

PCIe 控制器的中断描述涉及多个层级。设备树中的 interrupts 属性定义控制器本身的中断(如 MSI 中断、错误中断),而 PCIe 设备的中断通过 interrupt-map 和 interrupt-map-mask 属性进行路由。

PCIe 中断路由与设备树属性关系 pcie@1e0000000 interrupts = <0 122 4> gic (中断控制器) interrupt-parent = <&gic> pci@0 (总线域) interrupt-map-mask = <0 0 0 7> ep@0 (Endpoint) interrupts = <1 0 0 1> interrupt-map INTA → GIC 122 INTB → GIC 123 INTC → GIC 124 INTD → GIC 125 说明:PCIe 控制器中断直接连接 GIC;总线域内设备中断通过 interrupt-map 映射到 GIC 的不同 SPI 中断线

2.7 其他关键属性

除了上述核心属性,PCIe 设备树节点还包含以下重要属性:

  • ranges:定义 PCIe 总线地址到 CPU 物理地址的转换规则。格式为 <child-bus-address parent-address length>,其中 child-bus-address 包含地址类型标志(如 0x81000000 表示 IO 空间,0x82000000 表示 64 位内存空间)。
  • dma-ranges:描述 PCIe 设备 DMA 地址到 CPU 地址的映射,用于 IOMMU/SMMU 场景。
  • msi-parent:指定 MSI 中断控制器,如 GICv3 ITS 或专用 MSI 控制器。
  • num-ib-windows / num-ob-windows:DWC 控制器特有的 inbound/outbound 窗口数量配置。
  • snps,enable-cdm-check:DWC 控制器特有的 CDM(Configuration Dependent Module)检查使能。

2.8 RC 模式与 EP 模式的设备树差异

PCIe 控制器可以配置为 RC(Root Complex)或 EP(Endpoint)模式,两种模式在设备树中的描述存在显著差异:

配置项 RC 模式 EP 模式
device_type "pci" 不设置或 "pci-ep"
ranges 必须定义,映射 PCIe 地址到 CPU 通常不定义,由 RC 端分配地址
bus-range 定义总线号范围 不定义,EP 不管理总线
num-lanes 定义链路宽度 定义链路宽度
max-link-speed 定义最大速度 定义最大速度
interrupts 控制器中断 + MSI 控制器中断 + 传统 INTx
ep-gpios 不适用 EP 复位/使能 GPIO
子节点 挂载 PCIe 总线设备 无子节点,或挂载 EP 功能接口
// RC 模式设备树片段
pcie_rc: pcie@1e0000000 {
    compatible = "fsl,imx8mq-pcie";
    device_type = "pci";
    reg = <0x00 0x1e0000000 0x0 0x100000>,
          <0x00 0x1e0100000 0x0 0x100000>;
    ranges = <0x81000000 0x0 0x00000000 0x0 0x40000000 0x0 0x00010000>,
             <0x82000000 0x0 0x40010000 0x0 0x40010000 0x0 0x3fff0000>;
    bus-range = <0x00 0xff>;
    num-lanes = <4>;
    max-link-speed = <3>;
    interrupts = <0 122 4>;
    status = "okay";
};

// EP 模式设备树片段
pcie_ep: pcie-ep@1e0000000 {
    compatible = "fsl,imx8mq-pcie-ep";
    reg = <0x00 0x1e0000000 0x0 0x100000>,
          <0x00 0x1e0100000 0x0 0x100000>;
    num-lanes = <4>;
    max-link-speed = <3>;
    interrupts = <0 122 4>;
    ep-gpios = <&gpio3 20 GPIO_ACTIVE_LOW>;
    status = "okay";
};
⚠️ 常见错误:在 EP 模式节点中错误地添加 device_type = "pci" 或 ranges 属性,会导致内核枚举 PCIe 总线时产生地址映射冲突。EP 模式应避免使用这些 RC 专属属性。

2.9 设备树编译与调试

编写完 .dts 文件后,需要通过 DTC 编译为 .dtb 文件。以下是常用命令和调试技巧:

  • 编译:dtc -I dts -O dtb -o output.dtb input.dts
  • 反编译:dtc -I dtb -O dts -o output.dts input.dtb
  • 检查语法:dtc -I dts -O dtb -o /dev/null input.dts(无输出表示语法正确)
  • 内核调试:在内核启动参数中添加 earlycon 和 of_devlink 可查看设备树解析日志。
  • 用户空间查看:ls /proc/device-tree/ 可查看当前系统加载的设备树结构。
🔧 实战建议:在开发阶段,建议在 .dts 中使用 status = "disabled" 禁用 PCIe 控制器,待确认其他硬件正常后再使能。同时使用 reg-names 属性为每个 reg 段命名,提高代码可读性。

2.10 本章小结

设备树是嵌入式 Linux 系统中描述 PCIe 控制器配置的核心语言。本章涵盖了以下关键知识点:

  • 设备树的基本语法和节点层次结构,以及 PCIe 场景下的三级节点模型。
  • 核心属性 compatible、reg、interrupts 在 PCIe 控制器中的具体含义和用法。
  • RC 模式与 EP 模式在设备树描述上的关键差异,以及常见配置陷阱。
  • 设备树编译、反编译和调试的基本方法。