全部博文(165)
分类: LINUX
2010-06-09 15:35:39
linux中断处理体系结构
linux内核将所有的中断统一编号,使用一个irq_desc结构数组来描述这些中断。通过irq_desc结构数组就可以了解中断处理体系结构,irq_desc结构的数据类型在include/linux/irq.h中定义,如下所示:
struct irq_desc {
irq_flow_handler_t handle_irq; //当前中断的处理函数入口
struct irq_chip *chip; //低层的硬件访问
struct msi_desc *msi_desc;
void *handler_data;
void *chip_data;
struct irqaction *action; /* IRQ action list 用户提供的中断处理函数链表*/
unsigned int status; /* IRQ status */
unsigned int depth; /* nested irq disables */
unsigned int wake_depth; /* nested wake enables */
unsigned int irq_count; /* For detecting broken IRQs */
unsigned int irqs_unhandled;
unsigned long last_unhandled; /* Aging timer for unhandled count */
spinlock_t lock;
#ifdef CONFIG_SMP
cpumask_t affinity;
unsigned int cpu;
#endif
#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
cpumask_t pending_mask;
#endif
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *dir;
#endif
const char *name; //中断名称
} ____cacheline_internodealigned_in_smp;
上面结构数组中的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);
void (*end)(unsigned int irq);
void (*set_affinity)(unsigned int irq, cpumask_t dest);
int (*retrigger)(unsigned int irq);
int (*set_type)(unsigned int irq, unsigned int flow_type);
int (*set_wake)(unsigned int irq, unsigned int on);
/* Currently used only by UML, might disappear one day.*/
#ifdef CONFIG_IRQ_RELEASE_METHOD
void (*release)(unsigned int irq, void *dev_id);
#endif
/*
* For compatibility, ->typename is copied into ->name.
* Will disappear.
*/
const char *typename;
};
上面结构数组irq_desc中的irqaction结构类型在include/linux/interrupt.h中定义。用户注册的每个中断处理函数用一个irqaction结构来表示,一个中断可以有多个处理函数,他们的irqaction结构连接成一个链表,以action为表头。irqaction结构定义如下:
struct irqaction {
irq_handler_t handler;//用户注册的中断处理函数
unsigned long flags;//中断标志,比如是否共享中断标志,电平触发还是边沿触发
cpumask_t mask;//用于SMP(对称多处理系统)
const char *name;//用户注册的中断名字,在/proc/interrupts中可以看到
void *dev_id; //用户传给上面的handler的参数,还可以用来区分共享中断
struct irqaction *next;
int irq;//中断号
struct proc_dir_entry *dir;
};
综上,中断处理流程如下:
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逐个调用用户在action链表中注册的处理函数。
可见,中断体系结构的初始化就是构造这些数据结构,比如irq_desc数组项中的handle_irq,chip等成员,用户注册中断时就是构造action链表,用户卸载中断时就是从action链表中去除不需要的项。