在 Linux 系统中,设备通过 IRQ(中断请求)向系统发送信号,告诉 CPU 有事情需要处理。当设备需要 CPU 帮忙时,就会通过 IRQ 线发送一个中断信号。
CPU 接到信号后,会暂停当前工作,先把正在进行的任务状态保存起来,然后去处理设备请求。处理完设备的事情后,再恢复之前保存的任务状态,继续之前的工作。
因为设备太多,IRQ 线的数量也很多,CPU 直接管理所有中断会很麻烦。所以系统会用一个专门的设备(比如中断控制器)来帮 CPU 管理这些 IRQ 线。

三大核心结构体
struct irq_chip:直接操作中断控制器的硬件,比如控制中断的开启、关闭或触发等底层功能。struct irq_domain:负责把硬件设备产生的物理中断号,转换成 Linux 系统内部统一管理的中断号,就像给中断信号做翻译一样。struct irq_desc:记录每个中断的详细信息,比如中断是否被屏蔽、处理函数是什么,相当于中断的"档案卡片"。
一、中断控制器:irq_chip
中断控制器在内核中表示为 struct irq_chip 结构的实例,它描述实际硬件设备,以及 IRQ 内核使用的一些方法:
c
struct irq_chip {
struct device *parent_device;
const char *name;
void (*irq_enable)(struct irq_data *data);
void (*irq_disable)(struct irq_data *data);
void (*irq_ack)(struct irq_data *data);
void (*irq_mask)(struct irq_data *data);
void (*irq_unmask)(struct irq_data *data);
void (*irq_eoi)(struct irq_data *data);
int (*irq_set_affinity)(struct irq_data *data,
const struct cpumask *dest, bool force);
int (*irq_retrigger)(struct irq_data *data);
int (*irq_set_type)(struct irq_data *data, unsigned int flow_type);
int (*irq_set_wake)(struct irq_data *data, unsigned int on);
void (*irq_bus_lock)(struct irq_data *data);
void (*irq_bus_sync_unlock)(struct irq_data *data);
int (*irq_get_irqchip_state)(struct irq_data *data,
enum irqchip_irq_state which, bool *state);
int (*irq_set_irqchip_state)(struct irq_data *data,
enum irqchip_irq_state which, bool state);
unsigned long flags;
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
1、基础信息
parent_device:指向这个中断控制器所属上级设备的指针。name:在/proc/interrupts文件中显示的名称。
2、中断控制函数
irq_enable:启用中断的功能。irq_disable:禁用中断,阻止中断触发。irq_ack:在新中断刚发生时立即调用。irq_mask:屏蔽硬件中断源。irq_unmask:取消屏蔽,重新允许中断触发。
3、中断处理收尾
irq_eoi:表示"中断结束"(End Of Interrupt)。在中断服务完成后立即调用,用于重置控制器状态。
4、高级功能
irq_set_affinity:在多核(SMP)系统中设置中断处理的 CPU。irq_retrigger:强制重新触发已屏蔽的中断。irq_set_type:设置中断的触发类型(如电平触发或边沿触发)。
5、电源管理与状态
irq_set_wake:启用或禁用中断的"唤醒功能"。
6、总线访问控制
irq_bus_lock:锁定慢速总线(如 I2C)的访问权限。irq_bus_sync_unlock:同步并解锁之前锁定的总线。
二、中断控制器域:irq_domain
在 Linux 系统中,中断控制器需要管理硬件中断号与系统内部编号之间的对应关系。这个功能通过一个叫做 struct irq_domain 的结构体来实现。它的核心作用是:
基本功能
将物理硬件的中断号(硬件 IRQ)转换为系统内部统一管理的虚拟中断号(Linux IRQ),让操作系统能正确处理不同硬件的中断请求。
c
struct irq_domain {
// 区域名(比如"PCI 中断域")
const char *name;
// 操作函数集合(负责具体转换逻辑)
const struct irq_domain_ops *ops;
// 硬件相关私有数据(比如芯片型号信息)
void *host_data;
// 控制行为的标志位(比如是否启用某些特性)
unsigned int flags;
// 可选字段:
// 固件节点(记录硬件设备在固件中的位置信息)
struct fwnode_handle *fwnode;
// 其他扩展字段...
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
关键解释:
ops(操作集合):包含中断映射、分配等具体操作的函数。host_data:保存该域对应的硬件设备特定信息。fwnode:记录设备在固件(如 UEFI/Device Tree)中的位置。
中断控制器驱动程序需要通过特定函数创建和注册 irq_domain,常用方法有两种:
1、irq_domain_add_linear()(线性映射)
- 原理:使用一个固定大小的表格,表格的索引是硬件中断号(hwirq)。
- 适用场景:硬件中断数量较少且固定(比如 256 个以下)。
- 优点:查找速度快(直接通过表格索引),且只给实际使用的中断分配资源。
- 缺点:表格的大小需要和最大的 hwirq 号一样大,如果硬件中断号范围很大,会占用较多内存。
总结
这是大多数驱动程序的首选方法,适合中断数量少且明确的场景。
2、irq_domain_add_tree()(树形映射)
- 原理:用树结构来管理硬件中断号(hwirq)和 Linux 中断号的映射关系。
- 适用场景:硬件中断号可能非常大(比如超过几千),不适合用线性表格。
- 优点:不需要预先分配大表格,节省内存。
- 缺点:查找速度取决于树中已存在的节点数量。
总结
适合硬件中断号范围极大或不确定的场景,但实际使用较少。
三、描述 IRQ:irq_desc
1、irq_desc
Linux 系统通过 struct irq_desc 结构来管理每个中断(IRQ)。这个结构记录了中断的所有相关信息,比如处理函数、统计信息和硬件配置等。
关键字段解释:
| 字段 | 描述 |
|---|---|
irq_common_data | 存储与中断控制器硬件相关的通用数据 |
kstat_irqs | 记录每个 CPU 自系统启动以来收到的中断次数 |
handle_irq | 指向处理中断的主函数 |
action | 一个链表,存储所有注册到该中断的处理函数 |
irqs_unhandled | 统计未被正确处理的中断次数(调试用) |
lock | 多处理器系统的锁,确保中断处理在多核 CPU 下安全执行 |
threads_active | 记录当前有多少线程正在处理该中断 |
wait_for_threads | 等待队列,用于同步等待中断处理线程完成 |
nr_actions | 统计该中断下注册的处理函数数量 |
dir | 指向 /proc/irq/ 目录下该中断的文件节点 |
name | 中断的名称(如"eth0") |
2、中断操作结构(irqaction 结构)
每个注册的中断处理函数对应一个 struct irqaction 结构:
| 字段 | 描述 |
|---|---|
handler | 中断的直接处理函数(也称"硬中断处理程序") |
thread_fn | 线程化处理函数(可选),用于耗时操作 |
dev_id | 设备的唯一标识,用于区分共享中断的不同设备 |
name | 设备名称(如"USB 控制器") |
next | 链表指针,指向下一个共享该中断的 irqaction 结构 |
flags | 中断标志(如 IRQF_SHARED 表示共享中断) |
3、中断芯片数据(irq_data 结构)
struct irq_data 用于与硬件中断控制器交互:
| 字段 | 描述 |
|---|---|
irq | Linux 系统分配的中断号(如 16) |
hwirq | 硬件设备的物理中断号 |
chip | 中断控制器的驱动接口 |
domain | 负责将硬件中断号(hwirq)映射到 Linux 的中断号(irq) |
chip_data | 硬件控制器的私有数据 |