内核对于中断的管理,最关键的数据结构就是irq_desc,在kernel/irq/irqdesc.c中:
struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = { [0 ... NR_IRQS-1] = { .handle_irq = handle_bad_irq, .depth = 1, .lock = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock), } };
这个我们就需要来看下内核的中断分发过程了。
二 中断的分发
中断是处理器核异常的一种,所以处理器设计中,外设中断引起处理器异常,处理器跳转到异常向量表的相应异常入口取指执行。
处理器的异常向量表也是软硬件结合很有意思的东西,有时间专门写一篇来记录,这里不详说了。
我们主要来看产生中断后,处理器跳转到中断异常入口后的执行流程。
(1)对于arm处理器,执行流程如下:
vector_irq ---> irq_handler ---> arch_irq_handler_default ---> asm_do_IRQ ---> handle_IRQ
在arch_irq_handler_default中调用get_irqnr_and_base获取中断号,传给asm_do_IRQ作为参数。
get_irqnr_and_base由板级支持包实现。
(2)对于ppc处理器,执行流程如下:
do_IRQ ---> ppc_md.get_irq ---> handle_one_irq
ppc_md.get_irq是由板级支持包中实现的设备描述符的获取中断号函数。
(3)对于mips处理器,执行流程如下:
handle_int ---> plat_irq_dispatch ---> do_IRQ
plat_irq_dispatch由班级支持包中实现。
上述的流程表示由异常入口函数开始,到调用handle_level_irq结束。
对于3款处理器平台,内核在中断分发上没有像中断初始化那样由通用函数到处理器平台函数最后到板级支持函数,而是每种处理器平台都不一样。上述函数的实现都在arch/xxx/kernel下,具体实现可以参考代码。
根据上面的分析可以看出,ARM MIPS PPC在中断分发中中断号的获取都是留给板级支持包来实现的。板级支持包中会读取中断控制器中相关寄存器来获取当前产生的中断情况,进而返回中断号。
所以结合中断初始化部分提出的问题,不管哪款处理器平台,如果我们想将35号中断的中断处理函数在注册时放在30号irq_desc中(方法是request_irq时中断号写30)。
那么在中断分发时,获取中断号函数中我们也需要进行修改,查询到中断控制器寄存器状态是产生35号中断,我们返回的中断号应该是30号!
但是,这样做并没有实际的应用意义,因为在实际开发中还是要尽量保证内核下irq_desc数组与硬件中断号表一一对应,这样驱动开发者在操作中断时就不需要关心内核中断号和硬件中断号的关系,而是直接使用硬件中断号来注册就可以了。
如果内核中断号和硬件中断号不一一对应,驱动开发者在编写驱动时还需要查找硬件中断号和内核中断号的映射表,增大了开发难度。
无论如何,借这个无聊的问题,还是搞清了内核中断的初始化和分发过程,也是很值得的
但求好事,莫问前程!
原文:http://blog.csdn.net/skyflying2012/article/details/46681675