3. 中断号与IRQ:中断号分配、IRQ编号、动态与静态中断号映射
中断号(Interrupt Number)是操作系统为每个硬件中断源分配的整数标识符,是驱动与中断控制器(Interrupt Controller)之间沟通的“门牌号”。在Linux内核中,中断号分为硬件中断号(HW IRQ)和软件中断号(Linux IRQ),两者通过映射机制关联。本章深入剖析中断号的分配策略、IRQ编号规则以及动态/静态映射的实现原理。
3.1 中断号的基本概念
中断号在系统中有两个层面的含义:
- 硬件中断号(HW IRQ):由芯片厂商定义,对应中断控制器(如GIC、IOAPIC)的物理输入引脚或SPI ID。
- 软件中断号(Linux IRQ):内核抽象出的逻辑中断号,驱动通过
request_irq()注册时使用的参数。
关键理解:驱动开发者通常只与软件中断号(Linux IRQ)打交道,硬件中断号由中断控制器驱动或设备树自动转换。
3.2 中断号分配方式
Linux内核支持三种中断号分配方式,适用于不同硬件平台和场景:
| 分配方式 | 描述 | 典型平台 | 优点 | 缺点 |
|---|---|---|---|---|
| 静态分配 | 中断号在编译时或设备树中固定指定 | ARM、RISC-V | 简单、可预测 | 灵活性差,易冲突 |
| 动态分配 | 内核运行时动态分配空闲中断号 | x86、PCIe设备 | 避免冲突,支持热插拔 | 中断号不固定,调试稍复杂 |
| 混合分配 | 部分固定,部分动态 | 嵌入式SoC | 兼顾稳定性和灵活性 | 管理复杂度增加 |
工程实践:在嵌入式Linux中,设备树(Device Tree)是静态分配中断号的主要载体。例如:
interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>; 表示使用SPI中断,硬件ID为42。
3.3 IRQ编号与中断域
现代Linux内核引入了中断域(irq_domain)机制,用于管理硬件中断号到Linux IRQ的映射。每个中断控制器对应一个中断域,域内维护一张映射表。
3.4 动态中断号映射
动态映射是irq_domain的核心能力,内核提供三种映射类型:
- 线性映射(Linear):预分配固定大小的数组,适用于中断源数量已知且较少的场景。
- 树形映射(Tree):使用基数树(radix tree)管理,适用于中断源数量大且稀疏的场景。
- 无映射(No Map):硬件中断号直接作为Linux IRQ,适用于x86等固定映射平台。
注意事项:动态映射虽然灵活,但可能导致中断号在每次启动时不同。调试时建议通过
/proc/interrupts查看当前映射关系。
3.5 静态中断号映射
静态映射通常用于嵌入式系统,中断号在设备树或板级文件中硬编码。典型流程如下:
- 设备树中通过
interrupts属性指定硬件中断号。 - 内核解析设备树,调用
irq_of_parse_and_map()建立映射。 - 驱动通过
platform_get_irq()获取Linux IRQ。
/* 设备树示例:UART设备中断 */
uart0: serial@10000000 {
compatible = "vendor,uart";
reg = <0x10000000 0x1000>;
interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
};
/* 驱动代码获取中断号 */
int irq_num;
irq_num = platform_get_irq(pdev, 0);
if (irq_num < 0) {
dev_err(&pdev->dev, "failed to get IRQ\n");
return irq_num;
}
/* 注册中断处理 */
ret = request_irq(irq_num, uart_isr, IRQF_TRIGGER_HIGH,
"uart_irq", dev_id);
3.6 中断号映射对比总结
| 特性 | 静态映射 | 动态映射 |
|---|---|---|
| 中断号确定性 | 固定,可预测 | 每次启动可能不同 |
| 适用平台 | ARM、RISC-V嵌入式 | x86、PCIe、热插拔设备 |
| 配置方式 | 设备树或板级文件 | 内核运行时自动分配 |
| 调试难度 | 低 | 中(需查看/proc/interrupts) |
| 资源占用 | 低(预分配数组) | 中(基数树或链表) |
| 灵活性 | 低 | 高 |
3.7 工程案例:查看中断号映射
在实际开发中,通过/proc/interrupts可以查看当前系统的中断号映射状态:
# cat /proc/interrupts
CPU0 CPU1
16: 12345 67890 GICv3 42 uart0
17: 0 0 GICv3 53 mmc0
18: 987 654 GICv3 67 eth0
输出字段说明:
- 第一列:Linux IRQ号(16、17、18)。
- CPU列:各CPU处理的中断次数。
- 中断控制器:GICv3。
- 硬件中断号:42、53、67。
- 设备名称:uart0、mmc0、eth0。
调试技巧:当驱动无法获取中断时,首先检查
/proc/interrupts中是否存在对应设备。若不存在,说明设备树或中断控制器驱动未正确注册映射。
3.8 本章小结
中断号是驱动与中断子系统交互的桥梁。理解静态与动态映射的差异,掌握irq_domain的工作原理,能够帮助开发者快速定位中断相关的问题。在嵌入式Linux中,设备树是静态映射的主要工具;而在x86/PCIe场景下,动态映射提供了更好的灵活性和可扩展性。