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在中断树中的角色与数据流:
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)。这种层级关系在嵌入式系统中非常常见。