Linux内核源码:2.6.35

工具:source insight 3

内核中断机制三大数据结构
irq_desc

 

  1. struct irq_desc {  
  2. unsigned int                irq;  
  3. irq_flow_handler_t        handle_irq;  
  4. struct irq_chip                *chip;  
  5. struct irqaction        *action;        /* IRQ action list */  


irq_chip

 

  1. struct irq_chip {  
  2. const char        *name;  
  3.         void                (*ack)(unsigned int irq);  
  4.         void                (*mask)(unsigned int irq);  
  5.         void                (*mask_ack)(unsigned int irq);  
  6.         void                (*unmask)(unsigned int irq);  
  7.         unsigned int        (*startup)(unsigned int irq);  
  8.         void                (*shutdown)(unsigned int irq);  
  9.         void                (*enable)(unsigned int irq);  
  10.         void                (*disable)(unsigned int irq);  


irqaction

 

  1. struct irqaction {  
  2.         irq_handler_t handler;  
  3.         unsigned long flags;  
  4.         const char *name;  
  5.         void *dev_id;  
  6.         struct irqaction *next;  
  7.         int irq;  
  8.         struct proc_dir_entry *dir;  
  9.         irq_handler_t thread_fn;  
  10.         struct task_struct *thread;  
  11.         unsigned long thread_flags;  
  12. };  

中断处理中,内核会在start_kernel函数中调用init_IRQ(arch/arm/kernel/irq.c)、和early_trap_init(start_kernel内通过调用setup_arch)来设置异常处理函数early_trap_init函数功能
early_trap_init函数是将异常向量和异常处理的汇编代码拷贝到内存中,其中异常向量是0xffff0000处,关键代码

 

  1. memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);  
  2. memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);  


这里,异常向量地址在arch/arm/kernel/entry-armv.S中,代码摘抄如下

 

  1.         .equ        stubs_offset, __vectors_start + 0x200 - __stubs_start  
  2.   
  3.         .globl        __vectors_start  
  4. __vectors_start:  
  5.  ARM(        swi        SYS_ERROR0        )  
  6.  THUMB(        svc        #0                )  
  7.  THUMB(        nop                        )  
  8.         W(b)        vector_und + stubs_offset  
  9.         W(ldr)        pc, .LCvswi + stubs_offset  
  10.         W(b)        vector_pabt + stubs_offset  
  11.         W(b)        vector_dabt + stubs_offset  
  12.         W(b)        vector_addrexcptn + stubs_offset  
  13.         W(b)        vector_irq + stubs_offset  
  14.         W(b)        vector_fiq + stubs_offset  
  15.   
  16.         .globl        __vectors_end  
  17. __vectors_end:  

init_IRQ函数功能
设置个中断号对应的中断状态,关键代码

 

  1. for (irq = 0; irq < NR_IRQS; irq++)  
  2.                irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE;\\设置中断状态  
  3. init_arch_irq();<span style="color: rgb(34, 34, 34); font-family: Helvetica, Arial, sans-serif; font-size: 14px; line-height: 22.383333206176758px;">/* 对应</span><span href="tag.php?name=%E8%8A%AF%E7%89 %87" class="t_tag" style="color: rgb(34, 34, 34); font- family: Helvetica, Arial, sans-serif; font-size: 14px; line- height: 22.366666793823242px; word-wrap: break- word; cursor: pointer; border-bottom-width: 1px; border-bottom- style: solid; border-bottom-color: rgb(255, 0, 0); white- space: nowrap;">芯 片</span><span style="color: rgb(34, 34, 34); font- family: Helvetica, Arial, sans-serif; font-size: 14px; line- height: 22.383333206176758px;">结构的中断初始化函数,每个架构不同*/</span>  

例如s3c64xx中的初始化函数

 

  1. void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid)  
  2. {  
  3.         printk(KERN_DEBUG "%s: initialising interrupts\n", __func__);  
  4.   
  5.         /* initialise the pair of VICs */  
  6.         vic_init(VA_VIC0, IRQ_VIC0_BASE, vic0_valid, 0);  
  7.         vic_init(VA_VIC1, IRQ_VIC1_BASE, vic1_valid, 0);  
  8.   
  9.         /* add the timer sub-irqs */  
  10.   
  11.         s3c_init_vic_timer_irq(IRQ_TIMER0_VIC, IRQ_TIMER0);  
  12.         s3c_init_vic_timer_irq(IRQ_TIMER1_VIC, IRQ_TIMER1);  
  13.         s3c_init_vic_timer_irq(IRQ_TIMER2_VIC, IRQ_TIMER2);  
  14.         s3c_init_vic_timer_irq(IRQ_TIMER3_VIC, IRQ_TIMER3);  
  15.         s3c_init_vic_timer_irq(IRQ_TIMER4_VIC, IRQ_TIMER4);  
  16.   
  17.         s3c_init_uart_irqs(uart_irqs, ARRAY_SIZE(uart_irqs));  
  18. }  


中断处理流程
一  发生中断时,CPU执行异常向量vector_irq的代码, 即异常向量表中的中断异常的代码,它是一个跳转指令,跳去执行真正的中断处理程序
二   在vector_irq里面,最终会调用中断处理的总入口函数

asm_do_IRQ,调用代码

 

  1. adrne        lr, BSYM(1b)  
  2. bne        asm_do_IRQ  

三   asm_do_IRQ根据中断号irq来调用相应的irq_desc

 

  1. asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)  
  2. {        if (unlikely(irq >= NR_IRQS)) {  
  3.                 if (printk_ratelimit())  
  4.                         printk(KERN_WARNING "Bad IRQ%u\n", irq);  
  5.                 ack_bad_irq(irq);  
  6.         } else {  
  7.                 generic_handle_irq(irq);  
  8.         }  
  9. }  


generic_handle_irq(irq)函数实现在这

 

  1. static inline void generic_handle_irq(unsigned int irq)  
  2. {  
  3.         generic_handle_irq_desc(irq, irq_to_desc(irq));  
  4. }  


再进一步跟踪下去

 

  1. static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)  
  2. {  
  3. #ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ  
  4.         desc->handle_irq(irq, desc);  
  5. #else  
  6.         if (likely(desc->handle_irq))  
  7.                 desc->handle_irq(irq, desc);  
  8.         else  
  9.                 __do_IRQ(irq);  
  10. #endif  
  11. }  


里 面的desc->handle_irq(irq, desc);即调用irq_desc中的handle_irq(不同的中断会有与其对应的irq_desc结构,所以asm_do_IRQ会根据不同的中 断号来调用相应的handle_irq),接下去handle_irq会调用chip成员中的函数来进行一些硬件设置,在调用用户在action链表中注册的处理函数

 

  1. s3c_init_vic_timer_irq(IRQ_TIMER0_VIC, IRQ_TIMER0);  


这个函数的实现如下

 

  1. void __init s3c_init_vic_timer_irq(unsigned int parent_irq,  
  2.                                    unsigned int timer_irq)  
  3. {  
  4.         struct irq_desc *desc = irq_to_desc(parent_irq);  
  5.   
  6.         set_irq_chained_handler(parent_irq, s3c_irq_demux_vic_timer);  
  7.   
  8.         set_irq_chip(timer_irq, &s3c_irq_timer);  
  9.         set_irq_handler(timer_irq, handle_level_irq);  
  10.         set_irq_flags(timer_irq, IRQF_VALID);  
  11.   
  12.         desc->handler_data = (void *)timer_irq;  
  13. }  


调用irqaction中的handler,set_irq_handler(timer_irq, handle_level_irq);/*用户注册的中断处理函数*/
函数功能实现代码

  1. __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,  
  2.                   const char *name)  
  3. {  
  4.         struct irq_desc *desc = irq_to_desc(irq);  
  5.         unsigned long flags;  
  6.   
  7.         if (!desc) {  
  8.                 printk(KERN_ERR  
  9.                        "Trying to install type control for IRQ%d\n", irq);  
  10.                 return;  
  11.         }  
  12.   
  13.         if (!handle)  
  14.                 handle = handle_bad_irq;  
  15.         else if (desc->chip == &no_irq_chip) {  
  16.                 printk(KERN_WARNING "Trying to install %sinterrupt handler "  
  17.                        "for IRQ%d\n", is_chained ? "chained " : "", irq);  
  18.                 /* 
  19.                  * Some ARM implementations install a handler for really dumb 
  20.                  * interrupt hardware without setting an irq_chip. This worked 
  21.                  * with the ARM no_irq_chip but the check in setup_irq would 
  22.                  * prevent us to setup the interrupt at all. Switch it to 
  23.                  * dummy_irq_chip for easy transition. 
  24.                  */  
  25.                 desc->chip = &dummy_irq_chip;  
  26.         }  
  27.   
  28.         chip_bus_lock(irq, desc);  
  29.         raw_spin_lock_irqsave(&desc->lock, flags);  
  30.   
  31.         /* Uninstall? */  
  32.         if (handle == handle_bad_irq) {  
  33.                 if (desc->chip != &no_irq_chip)  
  34.                         mask_ack_irq(desc, irq);  
  35.                 desc->status |= IRQ_DISABLED;  
  36.                 desc->depth = 1;  
  37.         }  
  38.         desc->handle_irq = handle;  
  39.         desc->name = name;  
  40.   
  41.         if (handle != handle_bad_irq && is_chained) {  
  42.                 desc->status &= ~IRQ_DISABLED;  
  43.                 desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;  
  44.                 desc->depth = 0;  
  45.                 desc->chip->startup(irq);  
  46.         }  
  47.         raw_spin_unlock_irqrestore(&desc->lock, flags);  
  48.         chip_bus_sync_unlock(irq, desc);  
  49. }  


里面会根据中断号调用到desc中的handle_irq,desc->handle_irq = handle;
[irq].handle_irq,对于电平触发中断,这个入口通常为handle_level_irq,对于边沿触发中断,这个入口通常为handle_edge_irq

 handle_level_irq函数实现

 

  1. handle_level_irq(unsigned int irq, struct irq_desc *desc)  
  2. {  
  3.         struct irqaction *action;  
  4.         irqreturn_t action_ret;  
  5.   
  6.         raw_spin_lock(&desc->lock);  
  7.         mask_ack_irq(desc, irq);  
  8.   
  9.         if (unlikely(desc->status & IRQ_INPROGRESS))  
  10.                 goto out_unlock;  
  11.         desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);  
  12.         kstat_incr_irqs_this_cpu(irq, desc);  
  13.   
  14.         /* 
  15.          * If its disabled or no action available 
  16.          * keep it masked and get out of here 
  17.          */  
  18.         action = desc->action;  
  19.         if (unlikely(!action || (desc->status & IRQ_DISABLED)))  
  20.                 goto out_unlock;  
  21.   
  22.         desc->status |= IRQ_INPROGRESS;  
  23.         raw_spin_unlock(&desc->lock);  
  24.   
  25.         action_ret = handle_IRQ_event(irq, action);  
  26.         if (!noirqdebug)  
  27.                 note_interrupt(irq, desc, action_ret);  
  28.   
  29.         raw_spin_lock(&desc->lock);  
  30.         desc->status &= ~IRQ_INPROGRESS;  
  31.   
  32.         if (!(desc->status & (IRQ_DISABLED | IRQ_ONESHOT)))  
  33.                 unmask_irq(desc, irq);  
  34. out_unlock:  
  35.         raw_spin_unlock(&desc->lock);  
  36. }  


里面 action_ret = handle_IRQ_event(irq, action);
handle_IRQ_event(irq, action)函数里面实现:
irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)

 

    1. do {  
    2.                 trace_irq_handler_entry(irq, action);  
    3.                 ret = action->handler(irq, action->dev_id);/*调用用户注册函数,action是用irqaction类型,等同于irqaction->handler*/  
    4.                 trace_irq_handler_exit(irq, action, ret);  
    5.   
    6.                 switch (ret) {  
    7.                 case IRQ_WAKE_THREAD:  
    8.   
    9.                         ret = IRQ_HANDLED;  
    10.   
    11.                         if (unlikely(!action->thread_fn)) {  
    12.                                 warn_no_thread(irq, action);  
    13.                                 break;  
    14.                         }  
    15.   
    16.   
    17.                         if (likely(!test_bit(IRQTF_DIED,  
    18.                                              &action->thread_flags))) {  
    19.                                 set_bit(IRQTF_RUNTHREAD, &action->thread_flags);  
    20.                                 wake_up_process(action->thread);  
    21.                         }  
    22.   
    23.                         /* Fall through to add to randomness */  
    24.                 case IRQ_HANDLED:  
    25.                         status |= action->flags;  
    26.                         break;  
    27.   
    28.                 default:  
    29.                         break;  
    30.                 }  
    31.   
    32.                 retval |= ret;  
    33.                 action = action->next; /*依次调用用户注册的函数,进入下一个*/  
    34.         } while (action); 
posted on 2013-02-17 20:59  爱哎唉  阅读(280)  评论(0)    收藏  举报