2. 中断处理流程:中断注册与注销、中断处理函数原型、中断标志位(IRQF_SHARED等)、中断处理流程时序图

2.1 中断注册与注销

在 Linux 内核中,设备驱动程序通过 request_irq() 和 free_irq() 函数完成中断处理函数的注册与注销。这两个函数是中断子系统提供给驱动层的标准接口。

2.1.1 中断注册函数

int request_irq(unsigned int irq,
                irq_handler_t handler,
                unsigned long flags,
                const char *name,
                void *dev);
参数 说明
irq 中断号,由硬件平台决定或通过 platform_get_irq() 获取
handler 中断处理函数指针,类型为 irq_handler_t
flags 中断标志位,控制中断触发方式、共享属性等
name 设备名称,在 /proc/interrupts 中显示
dev 传递给中断处理函数的设备标识,共享中断时用于区分设备

2.1.2 中断注销函数

void free_irq(unsigned int irq, void *dev);
最佳实践:中断注册应在设备初始化成功、硬件准备就绪后调用;中断注销应在设备移除或驱动卸载时调用,且必须在释放可能触发中断的硬件资源之前完成。

2.2 中断处理函数原型

Linux 内核定义的中断处理函数原型如下:

typedef irqreturn_t (*irq_handler_t)(int irq, void *dev_id);

返回值类型 irqreturn_t 为枚举:

返回值 宏定义 含义
IRQ_NONE #define IRQ_NONE (0) 中断不是本设备产生的,继续传递给下一个共享处理函数
IRQ_HANDLED #define IRQ_HANDLED (1) 中断已被本设备处理,中断处理结束
IRQ_WAKE_THREAD #define IRQ_WAKE_THREAD (2) 唤醒中断线程化处理函数( threaded IRQ )
关键约束:中断处理函数运行在中断上下文中,必须遵循以下规则:
• 不能调用可能导致睡眠的函数(如 kmalloc(GFP_KERNEL)、mutex_lock()、copy_from_user())
• 不能访问用户空间内存
• 执行时间应尽可能短,通常只做最紧急的硬件操作
• 耗时任务应推迟到下半部( bottom half )处理

2.3 中断标志位详解

flags 参数通过位掩码组合控制中断行为,常用标志如下:

标志位 值 说明
IRQF_SHARED 0x00000001 允许多个设备共享同一中断线,必须配合 dev_id 参数使用
IRQF_TRIGGER_RISING 0x00000002 上升沿触发
IRQF_TRIGGER_FALLING 0x00000004 下降沿触发
IRQF_TRIGGER_HIGH 0x00000008 高电平触发
IRQF_TRIGGER_LOW 0x00000010 低电平触发
IRQF_ONESHOT 0x00000020 中断处理期间硬件中断线被屏蔽,处理完成后自动重新使能
IRQF_NO_SUSPEND 0x00000040 系统休眠时不关闭该中断
IRQF_TIMER 0x00000080 标记为定时器中断,用于系统时钟
共享中断注意事项:使用 IRQF_SHARED 时,所有共享该中断线的驱动必须都设置此标志。中断处理函数必须检查硬件状态寄存器,确认中断是否来自本设备,若不是则立即返回 IRQ_NONE。

2.4 中断处理流程时序图

下图展示了从硬件中断触发到中断处理完成的核心流程,包含上半部( top half )与下半部( bottom half )的协作关系:

中断处理流程时序图 硬件中断触发 中断控制器仲裁 CPU 保存上下文 上半部处理 调度下半部 CPU 恢复上下文 下半部执行 下半部完成 关键时序说明: • 上半部:关中断执行,仅处理紧急硬件操作 • 下半部:开中断执行,处理耗时任务( workqueue/tasklet ) • 整个中断处理期间,同 CPU 上的其他中断被屏蔽 时间 →

2.5 中断处理流程步骤清单

  1. 硬件中断触发:外设通过中断线向中断控制器发送中断信号。
  2. 中断控制器仲裁:中断控制器根据优先级选择最高优先级中断,向 CPU 发送中断请求。
  3. CPU 保存上下文:CPU 保存当前执行现场(寄存器、程序计数器等),跳转到中断向量表对应的入口地址。
  4. 上半部执行:调用 request_irq() 注册的处理函数,完成紧急硬件操作(如清除中断标志、读取 FIFO 数据)。
  5. 调度下半部:上半部返回前,通过 schedule_work() 或 tasklet_schedule() 调度下半部处理。
  6. CPU 恢复上下文:CPU 恢复被中断的进程上下文,继续执行原任务。
  7. 下半部执行:在合适的时机(如调度点、软中断),下半部处理函数在开中断环境下执行剩余工作。
性能指标:上半部执行时间应控制在微秒级,通常不超过 10μs;下半部执行时间可放宽到毫秒级,但应避免阻塞其他任务。workqueue 适合执行可能睡眠的长时间任务,tasklet 适合执行不可睡眠的短时间任务。