1. 中断基础概念:中断向量、中断号、中断上下文、中断处理流程

中断是硬件与软件交互的核心机制,也是 Linux 驱动响应外部事件的最高效途径。理解中断的底层概念,是后续进行中断与 tasklet 性能调优的基石。本节将系统梳理中断向量、中断号、中断上下文以及完整的中断处理流程。

1.1 中断向量与中断号

中断向量和中断号是中断系统的两个关键标识,但它们在硬件和软件层面有不同的含义。

概念 定义 作用域 典型范围
中断向量 CPU 架构定义的、指向中断服务程序(ISR)入口地址的索引或指针 硬件/CPU 架构层 0~255(x86 实模式)
中断号(IRQ) Linux 内核为每个中断源分配的软件抽象编号 操作系统/驱动层 0~NR_IRQS-1(通常 0~15 为传统 IRQ)

关键区别:中断向量由 CPU 厂商定义,用于硬件查找 ISR;中断号由内核管理,用于驱动注册和中断路由。在 x86 架构中,中断向量 0x20~0x2F 通常映射到 IRQ 0~15。

调优提示:在 /proc/interrupts 中看到的编号是中断号(IRQ),而非中断向量。驱动开发中只需关注中断号,中断向量由内核和硬件自动处理。

1.2 中断上下文

中断上下文是 Linux 内核中一个特殊的执行环境,与进程上下文有本质区别。

  • 进程上下文:可以睡眠、可以调度、可以访问用户空间、持有锁时可以阻塞。
  • 中断上下文:不可睡眠、不可调度、不可访问用户空间、持有锁时必须使用 spinlock。
特性 进程上下文 中断上下文
可睡眠 是 否
可调度 是 否
访问用户空间 是 否
锁类型 mutex/semaphore spinlock
当前进程指针 有效 无效(指向被中断进程)

常见错误:在中断上下文中调用 kmalloc(GFP_KERNEL) 或 mutex_lock() 会导致内核崩溃。必须使用 GFP_ATOMIC 和 spin_lock()。

1.3 中断处理流程

从硬件触发中断到驱动 ISR 执行完毕,整个流程分为硬件阶段和软件阶段。

核心原则:中断处理必须快——上半部(Top Half)只做最紧急的硬件操作,耗时工作推迟到下半部(Bottom Half)如 tasklet、workqueue 中完成。

1.3.1 完整中断处理流程步骤

  1. 硬件触发:外设通过中断线向中断控制器(如 APIC、GIC)发送电平或边沿信号。
  2. 中断控制器仲裁:中断控制器根据优先级选择最高优先级中断,向 CPU 发送中断请求。
  3. CPU 响应:CPU 保存当前上下文(寄存器、程序计数器),查找中断向量表,跳转到通用中断入口。
  4. 内核通用入口:保存所有寄存器,调用 handle_irq() 或 do_IRQ(),根据中断号查找已注册的 IRQ 描述符。
  5. 调用驱动 ISR:内核调用驱动注册的 request_irq() 回调函数(上半部)。
  6. 上半部执行:驱动 ISR 执行硬件操作(如读取状态寄存器、清除中断标志),返回 IRQ_HANDLED 或 IRQ_WAKE_THREAD。
  7. 下半部调度:如果 ISR 返回 IRQ_WAKE_THREAD,内核调度 threaded IRQ;如果使用 tasklet,则在软中断上下文中执行。
  8. 恢复现场:CPU 恢复寄存器,返回被中断的进程继续执行。

1.3.2 中断处理流程 SVG 架构图

Linux 中断处理完整流程 Linux 中断处理完整流程 ① 外设触发中断信号 ② 中断控制器仲裁与转发 ③ CPU 保存上下文,查向量表 ④ 内核通用入口 do_IRQ() ⑤ 驱动 ISR 上半部执行 ⑥ 下半部调度(tasklet/threaded IRQ) ⑦ CPU 恢复现场,返回进程 性能关键点 上半部必须极短 耗时操作推迟到下半部 中断上下文约束 不可睡眠 使用 spinlock

1.4 中断处理流程中的关键数据结构

内核使用 irq_desc 结构体管理每个中断号的状态、处理函数和标志位。

// include/linux/irqdesc.h (简化)
struct irq_desc {
    struct irq_data      irq_data;       // 硬件相关数据
    unsigned int         __percpu *kstat_irqs; // 中断统计
    irq_flow_handler_t   handle_irq;     // 中断流处理函数
    struct irqaction    *action;         // 驱动注册的 action 链表
    unsigned int         status_use_accessors; // 状态标志
    const char          *name;           // 中断名称
    struct proc_dir_entry *dir;          // /proc/irq 目录
};

调优切入点:通过 /proc/interrupts 观察每个 CPU 上的中断分布,可以判断是否存在中断负载不均。后续章节将介绍如何使用 irqbalance 和 smp_affinity 进行调优。

1.5 中断处理流程总结

阶段 执行者 耗时要求 可调度 典型操作
硬件触发 外设 + 中断控制器 纳秒级 否 信号传输、优先级仲裁
CPU 响应 CPU 硬件 纳秒级 否 保存上下文、查向量表
内核通用入口 内核代码 微秒级 否 查找 irq_desc、调用 handle_irq
驱动 ISR 上半部 驱动代码 微秒级(必须短) 否 读状态寄存器、清中断标志
下半部调度 内核软中断/tasklet 毫秒级 否(软中断) 数据拷贝、协议处理
恢复现场 CPU 硬件 纳秒级 否 恢复寄存器、返回进程