[IMX6DL]Linux内核 --- 中断流程小结

platform: imx6dl

os: Android 4.4

kernel branch: 3.0.35



初始化:
start_kernel -> main.c
    early_irq_init  irqdesc.c    //没有定义CONFIG_SPARSE_IRQ,使用的是静态分配irq_desc,并且初始化。
    init_IRQ ->    irq.c
        machine_desc->init_irq    ->    //调用平台相关的init_irq
            mx6_init_irq  ->
                mx6q_register_gpios -> devices.c
                    mxc_gpio_init ->        //一方面注册gpio,一方面配置对应的irq
                        irq_set_chip_and_handler ->    //设置对应的irq chip以及handler, handler为 handle_level_irq,这里申请的是非级联的中断,系统起来后可以被申请的。
                            irq_set_chip_and_handler_name ->
                                irq_set_chip
                                __irq_set_handler
                        irq_set_chained_handler    -> //这里设置的是级联的irq,比如gpio 0 ~ 15都是通过此node来进入系统的,此类irq不能再request,而且也不能创建kernel thread。对应handler是 mx3_gpio_irq_handler
                            __irq_set_handler ->
                                irq_settings_set_norequest //不能request
                                irq_settings_set_nothread    //不能有thread
                                

中断触发:
__irq_svc或者__irq_usr ->     entry-armv.S, 两者区别在于是内核空间还是用户空间触发的中断。
    irq_handler ->
        arch_irq_handler_default ->      entry-macro-multi.S //没有定义CONFIG_MULTI_IRQ_HANDLER,执行默认中断处理        
            asm_do_IRQ -> irq.c    //参数里已经有了irq number。
                handle_IRQ ->
                    irq_enter
                    generic_handle_irq ->
                        generic_handle_irq_desc ->
                            desc->handle_irq ->    先调用的是级联中断控制器的处理函数,即前面的mx3_gpio_irq_handler。
                                mx3_gpio_irq_handler -> gpio.c    得到具体的irq number号
                                    generic_handle_irq ->     再次调用
                                        generic_handle_irq_desc ->
                                            desc->handle_irq ->     这次调用的是非级联中断控制器的处理函数,即前面的handle_level_irq
                                                handle_level_irq -> chip.c
                                                    handle_irq_event -> handle.c
                                                        handle_irq_event_percpu ->
                                                            action->handler    如果有的话调用上半部中断处理程序
                                                            irq_wake_thread    -> 如果有的话唤醒内核中断线程
                                                                wake_up_process
                    irq_exit ->
                        invoke_softirq ->    softirq.c    //处理软中断,tasklet也是softirq的一种,也会走这个流程。此时硬件中断已经打开。
                            __do_softirq
                                

小结:
1. 首次申请中断时,默认情况中断是打开时能的。
2. 中断上半部要使用disable_irq_nosync()而不是disable_irq(),否则会导致死锁。
3. disable_irq()/enable_irq()可以多次嵌套调用,但是一定要在数量上配对。
4. 执行中断上半部时当前中断线是被屏蔽的,包括其他cpu,当前其他irq number不会被屏蔽。
5. 一个软中断不会抢占另一个软中断,唯一可抢占它的只有中断处理程序,因为在处理软中断处理程序的时候,
中断是开启的,但它和中断处理程序一样不能休眠。本地软中断被禁止,但是其他处理器上可执行软中断,
甚至是同类的中断,那么处理函数就会被执行两次,数据就会遭到破坏了。因此如果没必要,我们就用tasklet,
它的同一个处理函数不会在两个处理器上同时运行,这样也就避免了加锁的麻烦。



参考:

http://blog.csdn.net/DroidPhone/article/category/1118447

你可能感兴趣的:(linux,interrupt)