2. DTS中中断控制器的表示方法:interrupt-controller属性、#interrupt-cells属性的定义与作用

在设备树中,中断控制器(Interrupt Controller)是负责接收硬件中断信号并将其路由到CPU的硬件单元。为了在DTS中准确描述中断拓扑,必须使用两个核心属性:interrupt-controller和#interrupt-cells。这两个属性共同定义了中断控制器的身份标识与中断描述格式。

2.1 interrupt-controller属性:声明中断控制器身份

interrupt-controller是一个空值(无值)布尔属性。只要在某个设备节点中声明该属性,即表示该节点对应的硬件是一个中断控制器,能够接收并处理来自其他设备的中断请求。

  • 作用:标记节点为中断控制器,使其成为中断树中的父节点。
  • 语法:interrupt-controller;(无等号,无值)
  • 位置:通常放在中断控制器节点内部,与compatible、reg等属性并列。
关键点:一个SoC中可能存在多个中断控制器(如GIC、INTC、GPIO中断控制器),每个都必须显式声明interrupt-controller属性,否则其他设备无法通过interrupt-parent引用它。

2.2 #interrupt-cells属性:定义中断描述格式

#interrupt-cells是一个整数值属性,用于指定该中断控制器在interrupts属性中需要多少个u32(32位无符号整数)来描述一个中断源。这个值决定了中断描述符的“宽度”。

中断控制器类型 #interrupt-cells值 典型含义
ARM GIC(通用中断控制器) 3 中断类型(SPI/PPI/SGI)、中断号、触发类型与优先级标志
简单中断控制器(如GPIO) 2 中断号、触发类型(上升沿/下降沿/高电平/低电平)
极简中断控制器 1 仅中断号
经验法则:#interrupt-cells的值必须与中断控制器硬件手册中的中断描述格式严格一致。写错该值会导致中断号解析错位,系统无法正确响应中断。

2.3 典型节点定义示例

以下是一个ARM GIC中断控制器的标准DTS节点定义,展示了两个属性的配合使用:

gic: interrupt-controller@f1000000 {
    compatible = "arm,cortex-a15-gic";
    reg = <0x0 0xf1000000 0x0 0x10000>,
          <0x0 0xf1001000 0x0 0x2000>,
          <0x0 0xf1002000 0x0 0x2000>;
    interrupt-controller;        /* 声明本节点是中断控制器 */
    #interrupt-cells = <3>;      /* 每个中断描述需要3个cell */
    #address-cells = <2>;
    #size-cells = <2>;
};

当其他设备需要引用该GIC作为中断父节点时,其interrupts属性必须提供3个cell:

uart0: serial@f1010000 {
    compatible = "arm,pl011";
    reg = <0x0 0xf1010000 0x0 0x1000>;
    interrupt-parent = <&gic>;    /* 引用GIC */
    interrupts = <0 33 4>;        /* 类型=0(SPI), 中断号=33, 触发=4(高电平) */
};

2.4 两个属性的协同关系

下图展示了interrupt-controller与#interrupt-cells在中断树中的角色与数据流:

中断控制器节点属性协同关系图 中断控制器节点 interrupt-controller@f1000000 interrupt-controller; #interrupt-cells = <3>; compatible = "arm,cortex-a15-gic"; 定义中断描述格式 中断描述格式 interrupts = <0 33 4>; cell[0]: 中断类型 (0=SPI) cell[1]: 中断号 (33) cell[2]: 触发类型 (4=高电平) interrupt-parent = <&gic>; 外设节点 (UART) interrupts = <0 33 4>; 按#interrupt-cells解析 解析结果 中断控制器收到3个cell 正确映射到硬件中断线

2.5 常见错误与避坑指南

错误场景 错误表现 根本原因 解决方案
遗漏interrupt-controller 其他设备引用该节点时,内核报“not an interrupt controller” 节点未被标记为中断控制器 在节点内添加interrupt-controller;
#interrupt-cells值偏小 中断号解析错误,触发类型丢失 外设提供了3个cell,但控制器只声明了2个 将#interrupt-cells改为与硬件手册一致
#interrupt-cells值偏大 内核解析中断时读取越界,导致系统崩溃 外设只提供了2个cell,但控制器要求3个 减少#interrupt-cells或补全外设的interrupts属性
多中断控制器未区分 中断路由混乱,外设中断被错误控制器处理 多个中断控制器节点都未正确设置#interrupt-cells 为每个中断控制器独立设置正确的#interrupt-cells
重要警告:#interrupt-cells的值一旦确定,该中断控制器下所有外设的interrupts属性必须严格遵循该格式。混合使用不同格式会导致中断子系统初始化失败,且错误信息往往难以定位。

2.6 多中断控制器场景下的属性应用

在一个复杂的SoC中,可能存在多个中断控制器形成层级结构。每个中断控制器都必须独立声明interrupt-controller和#interrupt-cells。以下是一个包含GIC和GPIO中断控制器的示例:

/* 顶层GIC中断控制器 */
gic: interrupt-controller@f1000000 {
    compatible = "arm,cortex-a15-gic";
    reg = <0x0 0xf1000000 0x0 0x10000>;
    interrupt-controller;
    #interrupt-cells = <3>;
};

/* GPIO控制器,同时也是二级中断控制器 */
gpio0: gpio@f2000000 {
    compatible = "brcm,bcm2835-gpio";
    reg = <0x0 0xf2000000 0x0 0x1000>;
    gpio-controller;
    #gpio-cells = <2>;
    interrupt-controller;        /* GPIO也是中断控制器 */
    #interrupt-cells = <2>;      /* GPIO中断描述:中断号 + 触发类型 */
    interrupt-parent = <&gic>;   /* GPIO本身连接到GIC */
    interrupts = <0 100 4>;      /* GPIO向GIC报告的中断 */
};

在这个例子中,gpio0节点同时扮演两个角色:作为GIC的中断消费者(通过interrupt-parent和interrupts),以及作为其他外设的中断生产者(通过interrupt-controller和#interrupt-cells)。这种层级关系在嵌入式系统中非常常见。