Linux中断处理体系结构
struct irq_desc 、 structirq_chip 和 struct irqaction 3个数据结构构成了Linux中断处理体系结构。
下面分别介绍这3个结构:
Linux内核将所有的中断统一编号,使用一个irq_desc结构数组来描述这些中断;每个数组项对应一个中断,也可能是一组中断,它们共用相同的中断号,里面记录了中断的名称、中断状态、中断标记(比如中断类型、是否共享中断等),并提供了中断的低层硬件访问函数(清除、屏蔽、使能中断),提供了这个中断的处理函数入口,通过它可以调用用户注册的中断处理函数。
irq_desc结构的数据类型include/linux/irq.h中定义。
/**
*struct irq_desc - interrupt descriptor
*@irq: interrupt number for thisdescriptor
* @handle_irq: highlevelirq-events handler [if NULL, __do_IRQ()]
*@chip: low level interrupthardware access
*@action: the irq action chain
*@status: status information
* @name: flowhandler name for /proc/interrupts output
*/
struct irq_desc {
unsignedint irq;
// 当前中断的处理函数入口,它会调用action 成员中的用户定义的中断处理函数
irq_flow_handler_t handle_irq;
structirq_chip *chip; //低层的硬件访问
structirqaction *action; //IRQ action list 用户提供的中断处理函数链表
unsignedint status; //IRQ status
constchar *name; //中断的名称
};
handle_irq是这个或这组中断的处理函数入口。发生中断时,总入口函数asm_do_IRQ将根据中断号调用相应irq_desc数组项中handle_irq.handle_irq使用chip结构中的函数清除、屏蔽或者重新使能中断,还要调用用户在action链表中注册的中断处理函数。
irq_chip结构类型也是在include/linux/irq.h中定义,其中的成员大多用于操作底层硬件,比如设置寄存器以屏蔽中断,使能中断,清除中断等。
struct irq_chip {
const char *name;
unsigned int (*startup)(unsigned int irq);//启动中断,如果不设置,缺省为“enable
void (*shutdown)(unsigned int irq);/*关闭中断,如果不设置,缺省为"disable"*/
void (*enable)(unsigned int irq);// 使用中断,如果不设置,缺省为"unmask"
void (*disable)(unsigned int irq);//禁止中断,如果不设置,缺省为“mask”
void (*ack)(unsigned int irq);/*响应中断,通常是清除当前中断使得可以接收下一个中断*/
void (*mask)(unsigned int irq); //屏蔽中断源
void (*mask_ack)(unsigned int irq);//屏蔽和响应中断
void (*unmask)(unsigned int irq);//开启中断源
void (*eoi)(unsigned int irq);
};
irq_desc结构中的irqaction结构类型在include/linux/iterrupt.h中定义。用户注册的每个中断处理函数用一个irqaction结构来表示,一个中断比如共享中断可以有多个处理函数,它们的irqaction结构链接成一个链表,以action为表头。irqation结构定义如下:
struct irqaction {
irq_handler_t handler; //用户注册的中断处理函数
unsigned long flags; //中断标志,比如是否共享中断,电平触发还是边沿触发
const char *name; //用户注册的中断名字
void *dev_id; //用户传给上面的handler的参数,还可以用来区分共享中断
struct irqaction *next; //指向下一个用户注册函数的指针
int irq; //中断号
};
中断处理流程如下
(1)发生中断时,CPU执行异常向量vector_irq的代码
(2)在vector_irq里面,最终会调用中断处理的总入口函数asm_do_IRQ
(3)asm_do_IRQ根据中断号调用irq_desc数组项中的handle_irq。
(4)handle_irq会使用chip成员中的函数来设置硬件,比如清除中断、禁止中断、重新使能中断等
(5)handle_irq逐个调用用户在aciton链表中注册的处理函数
(1)发生中断时,CPU执行异常向量vector_irq的代码
(2)在vector_irq里面,最终会调用中断处理的总入口函数asm_do_IRQ
(3)asm_do_IRQ根据中断号调用irq_desc数组项中的handle_irq。
(4)handle_irq会使用chip成员中的函数来设置硬件,比如清除中断、禁止中断、重新使能中断等
(5)handle_irq逐个调用用户在aciton链表中注册的处理函数