Linux中断处理体系结构

各种的异常的C处理函数可以分为5类,他们分布在不同的文件中。
1、在arch/arm/kernel/trapsc.c中
未定义指令异常,总入口函数为do_undefinstr.
2、在arch/arm/mm/fault.c中
与内存访问相关的异常的C处理函数,
3、在arch/arm/mm/irq.c中
中断处理函数
4、在arch/arm/kernel/aclls.S中
swi异常的处理函数执政被组织成一个表格:swi指令集起码的位[23:0]被用来作为索引。这样,通过不同的”swi index”指令就可以调用不同的swi异常处理函数,它们被称为系统调用,比如sys_open,sys_read,sys_write等。
5、没有使用的异常。

中断处理体系结构
Linux内核将所有的中断统一编号,使用一个irq_desc结构数组来描述这些中断:每个数组项对应一个中断(也有可能是一组中断,他们共用相同的中断号),里面记录了中断的名称,中断状态,中断标记(比如中断类型,是否共享中断等),并提供了中断的底层硬件访问函数(清除,屏蔽,使能中断),提供了这个中断的处理函数入口,通过它可以调用用户注册的中断处理函数。
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 IRQ状态*/

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;
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;

#ifdef CONFIG_PROC_FS
struct proc_dir_entry *dir;
#endif
const char name; /中断名称*/
} ____cacheline_internodealigned_in_smp;

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;
};

struct irqaction {
irq_handler_t handler; /用户注册的中断处理函数/
unsigned long flags; /中断标志,比如是否共享中断,电平触发还是边沿触发等/
cpumask_t mask; /用于SMP(对称多处理器系统)/
const char name; /用户注册的中断名字,”cat /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链表中去除不需要的项。

用户(即驱动程序)通过request_irq函数向内核注册中断处理函数,request_irq函数根据中断号找到irq_desc数组项,然后在它的action链表中添加一个表项。
int request_irq(unsigned int irq, irq_handler_t handler,
unsigned long irqflags, const char *devname, void *dev_id)
{

action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);

action->handler = handler;
action->flags = irqflags;
cpus_clear(action->mask);
action->name = devname;
action->next = NULL;
action->dev_id = dev_id;

retval = setup_irq(irq, action);

}
requset_irq函数首先使用这4个参数构造一个irqaction结构,然后调用setup_irq函数将它链入链表中;
setup_irq函数完成了3个功能:
1、将新建的irqaction结构链入irq_desc[irq]结构的action链表中。如果action链表为空,则直接链入。如果先判断新建的irqaction结构和链表中的irqaction结构所表示的中断类型是否一致:即是否都声明为“可共享的”,是否都是用相同的触发方式(电平,边沿,极性),如果一致,则将新建的irqaction结构链入。
2、设置irq_desc[irq]结构中chip成员的还没设置的指针,让它们只想一些默认函数。
3、设置中断的触发方式。
4、启动中断。

asm_do_IRQ是中断的C语言总入口函数;
中断是一种很稀缺的资源,当不再使用一个设备时,应该释放它占据的中断。这通过free_irq函数来实现;
void free_irq(unsigned int irq, void *dev_id)

你可能感兴趣的:(Linux驱动,linux)