目录
中断的类型
中断一般分为异步中断(一般由硬件引起)和同步中断(一般由处理器本身引起)。
异步中断:CPU 处理中断的时间过长,所以先将硬件复位,使硬件可以继续做自己的工作。然后再适当时候处理中断请求中耗时的部分。
举个例子:网卡的工作原理
- 网卡收到数据包后,向 CPU 发出中断信号,请求处理接收到的数据包。
- CPU 将收到的数据包拷贝到内存后,即通知网卡继续工作。
- 至于数据包拷贝至内存后的处理会在适当的时候进行。
这样做避免了处理数据包时间过长导致网卡接收数据包速度变慢。
同步中断:CPU 处理完中断请求的所有工作后才反馈硬件
举个例子:系统异常处理(比如运算中的除0操作)
- 应用程序出现异常后,需要内核来处理。
- 内核调用响应的异常处理函数来处理异常。
- 处理完后终了应用程序或者给出 message。
同步中断应该处理很快就能完成的那种中断。
中断的上半部和下半部
中断处理对处理时间要求很高,如果一个中断要花费较长时间,那么中断处理一般分为两部分。
上半部只做一些必要的工作后,立即通知硬件自己继续则工作。
下半部是中断处理中耗时的部分,CPU 会在适当的时候去完成。当然这个适当的时候一般都很短。
中断相关函数
首先说明,不同的设备对应的中断不同,每个中断都通过一个唯一的数字标记。这些数字就是中断值,又被称为中断请求(irq)线,有了中断线我们就可以很容易分清谁是谁的中断了。
响应中断时,内核会执行一个函数,中断处理程序 ISR,一个设备的中断处理程序是这个设备驱动的一部分。
实现一个中断,主要需要知道 3 个函数:
- 注册中断的函数
- 释放中断的函数
- 中断处理程序的声明
注册中断的函数
位置:linux/interrupt.h inclue/linux/interrupt.h
定义如下:
/*
* irq - 表示要分配的中断号
* handler - 实际的中断处理回调函数
* flags - 标志位,表示此中断具有的特性
* name - 中断设备的 ASCII 表示,这些会被 /proc/irq 和 /proc/interrupts 文件使用
* dev - 用于共享中断线,多个中断程序共享一个中断线时(意思就是共用一个中断号),依靠 dev 来区别各个中断程序
* 返回值 - 0 if success
int request_irq(unsigned int irq,
irq_handler_t handler,
unsigned long flags,
const char* name,
void *dev)
这个函数可能睡眠,不允许在中断上下文/其他不允许阻塞的代码中运行。
释放中断的函数
定义比较简单
void free_irq(unsigned int irq, void *dev)
如果不是共享中断线,则直接删除 irq 对应的中断线。
如果是共享中断线,则判断此中断处理程序是否是中断线上最后一个中断处理程序,是就同时删除中断线和中断处理程序,不是就只删除中断处理程序。
中断程序的声明
声明格式如下:
/*
* 中断处理程序的声明
* @ irq - 中断处理程序(即request_irq()中handler)关联的中断号
* &dev - 与 request_irq() 中的一样,表示一个设备的结构体,用来区别哪个设备引发中断
* 返回值 - irqrenturn_t 类型,成功返回 IRQ_HANDLED 失败返回 IRQ_NONE
static irqreturn_t intr_handler(int, irq, void* dev);
中断处理机制
中断处理的过程主要涉及三个函数:
- do_IRQ 与体系结构有关,多所接收的中断进行应答
- handle_IRQ_event 调用中断线上所有中断处理
- ret_from_intr 恢复寄存器,将内核恢复到中断前的状态
处理流程如下:
完结。