• linux 中断机制浅析


    一、中断相关结构体

    1.irq_desc中断描述符

    [cpp] view plain copy
    1. struct irq_desc {  
    2. #ifdef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED  
    3.     struct irq_data irq_data;  
    4. #else  
    5.     union {  
    6.         struct irq_data irq_data;   //中断数据  
    7.         struct {  
    8.             unsigned int    irq;    //中断号  
    9.             unsigned int    node;   //节点号  
    10.             struct irq_chip *chip;  //irq_chip  
    11.             void    *handler_data;    
    12.             void    *chip_data;   
    13.             struct msi_desc *msi_desc;  
    14. #ifdef CONFIG_SMP  
    15.             cpumask_var_t   affinity;  
    16. #endif  
    17.         };  
    18.     };  
    19. #endif  
    20.     struct timer_rand_state *timer_rand_state;  
    21.     unsigned int    *kstat_irqs;  
    22.     irq_flow_handler_t  handle_irq; //中断处理句柄  
    23.     struct irqaction    *action;    /* 中断动作列表 */  
    24.     unsigned int    status;     /* 中断状态 */  
    25.     unsigned int    depth;      /* nested irq disables */  
    26.     unsigned int    wake_depth; /* nested wake enables */  
    27.     unsigned int    irq_count;  /* For detecting broken IRQs */  
    28.     unsigned long   last_unhandled; /* Aging timer for unhandled count */  
    29.     unsigned int    irqs_unhandled;  
    30.     raw_spinlock_t  lock;  
    31. #ifdef CONFIG_SMP  
    32.     const struct cpumask    *affinity_hint;  
    33. #ifdef CONFIG_GENERIC_PENDING_IRQ  
    34.     cpumask_var_t   pending_mask;  
    35. #endif  
    36. #endif  
    37.     atomic_t    threads_active;  
    38.     wait_queue_head_t   wait_for_threads;  
    39. #ifdef CONFIG_PROC_FS  
    40.     struct proc_dir_entry   *dir;   //proc接口目录  
    41. #endif  
    42.     const char  *name;  //名字  
    43. } ____cacheline_internodealigned_in_smp;  


    2.irq_chip 芯片相关的处理函数集合

    [cpp] view plain copy
    1. struct irq_chip {   //芯片相关的处理函数集合  
    2.     const char  *name;  //"proc/interrupts/name"  
    3. #ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED  
    4.     unsigned int    (*startup)(unsigned int irq);     
    5.     void    (*shutdown)(unsigned int irq);    
    6.     void    (*enable)(unsigned int irq);      
    7.     void    (*disable)(unsigned int irq);     
    8.     void    (*ack)(unsigned int irq);  
    9.     void    (*mask)(unsigned int irq);  
    10.     void    (*mask_ack)(unsigned int irq);  
    11.     void    (*unmask)(unsigned int irq);  
    12.     void    (*eoi)(unsigned int irq);  
    13.     void    (*end)(unsigned int irq);  
    14.     int     (*set_affinity)(unsigned int irq,const struct cpumask *dest);  
    15.     int     (*retrigger)(unsigned int irq);  
    16.     int     (*set_type)(unsigned int irq, unsigned int flow_type);  
    17.     int     (*set_wake)(unsigned int irq, unsigned int on);  
    18.     void    (*bus_lock)(unsigned int irq);  
    19.     void    (*bus_sync_unlock)(unsigned int irq);  
    20. #endif  
    21.     unsigned int    (*irq_startup)(struct irq_data *data);  //中断开始  
    22.     void    (*irq_shutdown)(struct irq_data *data); //中断关闭  
    23.     void    (*irq_enable)(struct irq_data *data);   //中断使能  
    24.     void    (*irq_disable)(struct irq_data *data);  //中断禁用  
    25.     void    (*irq_ack)(struct irq_data *data);  
    26.     void    (*irq_mask)(struct irq_data *data);  
    27.     void    (*irq_mask_ack)(struct irq_data *data);  
    28.     void    (*irq_unmask)(struct irq_data *data);  
    29.     void    (*irq_eoi)(struct irq_data *data);  
    30.     int     (*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force);  
    31.     int     (*irq_retrigger)(struct irq_data *data);  
    32.     int     (*irq_set_type)(struct irq_data *data, unsigned int flow_type);  
    33.     int     (*irq_set_wake)(struct irq_data *data, unsigned int on);  
    34.     void    (*irq_bus_lock)(struct irq_data *data);  
    35.     void    (*irq_bus_sync_unlock)(struct irq_data *data);  
    36. #ifdef CONFIG_IRQ_RELEASE_METHOD  
    37.     void    (*release)(unsigned int irq, void *dev_id);  
    38. #endif  
    39. };  


    3.irqaction中断行动结构体

    [cpp] view plain copy
    1. struct irqaction {  
    2.     irq_handler_t handler;  //中断处理函数  
    3.     unsigned long flags;    //中断标志  
    4.     const char *name;       //中断名  
    5.     void *dev_id;       //设备id号,共享中断用  
    6.     struct irqaction *next; //共享中断类型指向下一个irqaction  
    7.     int irq;            //中断号  
    8.     struct proc_dir_entry *dir; //proc接口目录  
    9.     irq_handler_t thread_fn;    //中断处理函数(线程)  
    10.     struct task_struct *thread; //线程任务  
    11.     unsigned long thread_flags; //线程标志  
    12. };  

     在整个中断系统中将勾勒出以下的关系框图

    二、中断初始化工作

     从start_kernel看起,大致按以下的分支顺序初始化

    [cpp] view plain copy
    1. start_kernel  
    2.     setup_arch          //设置全局init_arch_irq函数  
    3.         early_trap_init //搬移向量表  
    4.     early_irq_init();   //初始化全局irq_desc数组  
    5.     init_IRQ();         //调用init_arch_irq函数  
    6.         [   //板级中断初始化常用到的API  
    7.         set_irq_chip  
    8.         set_irq_handler  
    9.         set_irq_chained_handler  
    10.         set_irq_flags  
    11.         set_irq_type  
    12.         set_irq_chip_data  
    13.         set_irq_data  
    14.         ]  

    1.在setup_arch中主要是设置全局init_arch_irq函数

    [cpp] view plain copy
    1. void __init setup_arch(char **cmdline_p)  
    2. {  
    3.     struct tag *tags = (struct tag *)&init_tags;  
    4.     struct machine_desc *mdesc;  
    5.     char *from = default_command_line;  
    6.   
    7.     init_tags.mem.start = PHYS_OFFSET;  
    8.     unwind_init();  
    9.     setup_processor();  
    10.     mdesc = setup_machine(machine_arch_type);  
    11.     machine_name = mdesc->name;  
    12.     if (mdesc->soft_reboot)  
    13.         reboot_setup("s");  
    14.     if (__atags_pointer)  
    15.         tags = phys_to_virt(__atags_pointer);  
    16.     else if (mdesc->boot_params) {  
    17. #ifdef CONFIG_MMU  
    18.         if (mdesc->boot_params < PHYS_OFFSET ||mdesc->boot_params >= PHYS_OFFSET + SZ_1M) {  
    19.             printk(KERN_WARNING"Default boot params at physical 0x%08lx out of reach ",mdesc->boot_params);  
    20.         }   
    21.         else  
    22. #endif  
    23.         {  
    24.             tags = phys_to_virt(mdesc->boot_params);  
    25.         }  
    26.     }  
    27. #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)  
    28.     if (tags->hdr.tag != ATAG_CORE)  
    29.         convert_to_tag_list(tags);  
    30. #endif  
    31.     if (tags->hdr.tag != ATAG_CORE)  
    32.         tags = (struct tag *)&init_tags;  
    33.     if (mdesc->fixup)  
    34.         mdesc->fixup(mdesc, tags, &from, &meminfo);  
    35.     if (tags->hdr.tag == ATAG_CORE) {  
    36.         if (meminfo.nr_banks != 0)  
    37.             squash_mem_tags(tags);  
    38.         save_atags(tags);  
    39.         parse_tags(tags);  
    40.     }  
    41.     init_mm.start_code = (unsigned long) _text;  
    42.     init_mm.end_code   = (unsigned long) _etext;  
    43.     init_mm.end_data   = (unsigned long) _edata;  
    44.     init_mm.brk    = (unsigned long) _end;  
    45.     strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);  
    46.     strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);  
    47.     *cmdline_p = cmd_line;  
    48.     parse_early_param();  
    49.     arm_memblock_init(&meminfo, mdesc);  
    50.     paging_init(mdesc);  
    51.     request_standard_resources(&meminfo, mdesc);  
    52. #ifdef CONFIG_SMP  
    53.     if (is_smp())  
    54.         smp_init_cpus();  
    55. #endif  
    56.     reserve_crashkernel();  
    57.     cpu_init();  
    58.     tcm_init();  
    59.     arch_nr_irqs = mdesc->nr_irqs;  
    60.     init_arch_irq = mdesc->init_irq; //设置全局init_arch_irq函数  
    61.     //void (*init_arch_irq)(void) __initdata = NULL;  
    62.     system_timer = mdesc->timer;  
    63.     init_machine = mdesc->init_machine;  
    64. #ifdef CONFIG_VT  
    65. #if defined(CONFIG_VGA_CONSOLE)  
    66.     conswitchp = &vga_con;  
    67. #elif defined(CONFIG_DUMMY_CONSOLE)  
    68.     conswitchp = &dummy_con;  
    69. #endif  
    70. #endif  
    71.     early_trap_init();//调用early_trap_init函数  
    72. }  

    1.1.early_trap_init主要挪移了中断向量表到特定位置

    [cpp] view plain copy
    1. void __init early_trap_init(void)  
    2. {  
    3.     unsigned long vectors = CONFIG_VECTORS_BASE;    //0xffff0000  
    4.     extern char __stubs_start[], __stubs_end[];  
    5.     extern char __vectors_start[], __vectors_end[];  
    6.     extern char __kuser_helper_start[], __kuser_helper_end[];  
    7.     int kuser_sz = __kuser_helper_end - __kuser_helper_start;  
    8.   
    9.     memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);  //移动中断向量表  
    10.     memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);    //移动__stubs_start段  
    11.     memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);  
    12.     kuser_get_tls_init(vectors);  
    13.     memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes,sizeof(sigreturn_codes));  
    14.     memcpy((void *)KERN_RESTART_CODE, syscall_restart_code,sizeof(syscall_restart_code));  
    15.     flush_icache_range(vectors, vectors + PAGE_SIZE);  
    16.     modify_domain(DOMAIN_USER, DOMAIN_CLIENT);  
    17. }  

    2.early_irq_init 初始化全局irq_desc数组
    在(kernel/irqs/irqdesc.c)中定义了全局irq_desc数组

    [cpp] view plain copy
    1. struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {      
    2.     [0 ... NR_IRQS-1] = {  
    3.         .status     = IRQ_DEFAULT_INIT_FLAGS,  
    4.         .handle_irq = handle_bad_irq,  
    5.         .depth      = 1,  
    6.         .lock       = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),  
    7.     }  
    8. };  

    获取irq_desc数组项的宏

    [cpp] view plain copy
    1. #define irq_to_desc(irq)    (&irq_desc[irq])  

    early_irq_init函数

    [cpp] view plain copy
    1. int __init early_irq_init(void) //初始化全局irq_desc数组  
    2. {  
    3.     int count, i, node = first_online_node;  
    4.     struct irq_desc *desc;  
    5.   
    6.     init_irq_default_affinity();  
    7.     printk(KERN_INFO "NR_IRQS:%d ", NR_IRQS);  
    8.     desc = irq_desc;    //获取全局irq_desc数组  
    9.     count = ARRAY_SIZE(irq_desc);   //获取全局irq_desc数组项个数  
    10.     for (i = 0; i < count; i++) {    //初始化全局irq_desc数组  
    11.         desc[i].irq_data.irq = i;  
    12.         desc[i].irq_data.chip = &no_irq_chip;  
    13.         desc[i].kstat_irqs = kstat_irqs_all[i];  
    14.         alloc_masks(desc + i, GFP_KERNEL, node);  
    15.         desc_smp_init(desc + i, node);  
    16.         lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);  
    17.     }  
    18.     return arch_early_irq_init();  
    19. }  

    3.init_IRQ函数调用全局init_arch_irq函数,进入板级初始化

    [cpp] view plain copy
    1. void __init init_IRQ(void)  
    2. {  
    3.     init_arch_irq();    //调用板级驱动的中断初始化函数  
    4. }  

    4.板级中断初始化常用到的API

    1.set_irq_chip 通过irq中断号获取对应全局irq_desc数组项,并设置其irq_data.chip指向传递进去的irq_chip指针

    [cpp] view plain copy
    1. int set_irq_chip(unsigned int irq, struct irq_chip *chip)  
    2. {  
    3.     struct irq_desc *desc = irq_to_desc(irq);   //获取全局irq_desc数组项  
    4.     unsigned long flags;  
    5.   
    6.     if (!desc) {  
    7.         WARN(1, KERN_ERR "Trying to install chip for IRQ%d ", irq);  
    8.         return -EINVAL;  
    9.     }  
    10.     if (!chip)                      //若irq_chip不存在  
    11.         chip = &no_irq_chip;        //设置为no_irq_chip  
    12.     raw_spin_lock_irqsave(&desc->lock, flags);  
    13.     irq_chip_set_defaults(chip);    //初始化irq_chip  
    14.     desc->irq_data.chip = chip;      //设置irq_desc->irq_data.chip  
    15.     raw_spin_unlock_irqrestore(&desc->lock, flags);  
    16.     return 0;  
    17. }  
    18. EXPORT_SYMBOL(set_irq_chip);  

    1.1 irq_chip_set_defaults 根据irq_chip的实际情况初始化默认方法

    [cpp] view plain copy
    1. void irq_chip_set_defaults(struct irq_chip *chip)   //根据irq_chip的实际情况初始化默认方法  
    2. {  
    3. #ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED  
    4.     if (chip->enable)      
    5.         chip->irq_enable = compat_irq_enable;  
    6.     if (chip->disable)     
    7.         chip->irq_disable = compat_irq_disable;  
    8.     if (chip->shutdown)    
    9.         chip->irq_shutdown = compat_irq_shutdown;  
    10.     if (chip->startup)     
    11.         chip->irq_startup = compat_irq_startup;  
    12. #endif  
    13.     if (!chip->irq_enable)       //使能中断  
    14.         chip->irq_enable = default_enable;  
    15.     if (!chip->irq_disable)      //禁用中断  
    16.         chip->irq_disable = default_disable;  
    17.     if (!chip->irq_startup)      //中断开始  
    18.         chip->irq_startup = default_startup;  
    19.     if (!chip->irq_shutdown) //关闭中断  
    20.         chip->irq_shutdown = chip->irq_disable != default_disable ? chip->irq_disable : default_shutdown;  
    21.   
    22. #ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED  
    23.     if (!chip->end)  
    24.         chip->end = dummy_irq_chip.end;  
    25.     if (chip->bus_lock)  
    26.         chip->irq_bus_lock = compat_bus_lock;  
    27.     if (chip->bus_sync_unlock)  
    28.         chip->irq_bus_sync_unlock = compat_bus_sync_unlock;  
    29.     if (chip->mask)  
    30.         chip->irq_mask = compat_irq_mask;  
    31.     if (chip->unmask)  
    32.         chip->irq_unmask = compat_irq_unmask;  
    33.     if (chip->ack)  
    34.         chip->irq_ack = compat_irq_ack;  
    35.     if (chip->mask_ack)  
    36.         chip->irq_mask_ack = compat_irq_mask_ack;  
    37.     if (chip->eoi)  
    38.         chip->irq_eoi = compat_irq_eoi;  
    39.     if (chip->set_affinity)  
    40.         chip->irq_set_affinity = compat_irq_set_affinity;  
    41.     if (chip->set_type)  
    42.         chip->irq_set_type = compat_irq_set_type;  
    43.     if (chip->set_wake)  
    44.         chip->irq_set_wake = compat_irq_set_wake;  
    45.     if (chip->retrigger)  
    46.         chip->irq_retrigger = compat_irq_retrigger;  
    47. #endif  
    48. }  

    2.set_irq_handler和set_irq_chained_handler

    这两个函数的功能是:根据irq中断号,获取对应全局irq_desc数组项,并将数组项描述符的handle_irq中断处理函数指针指向handle
    如果是chain类型则添加数组项的status状态IRQ_NOREQUEST和IRQ_NOPROBE属性

    [cpp] view plain copy
    1. static inline void set_irq_handler(unsigned int irq, irq_flow_handler_t handle)  
    2. {  
    3.     __set_irq_handler(irq, handle, 0, NULL);    //调用__set_irq_handler  
    4. }  

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    [cpp] view plain copy
    1. static inline void set_irq_chained_handler(unsigned int irq,irq_flow_handler_t handle)  
    2. {  
    3.     __set_irq_handler(irq, handle, 1, NULL);    //调用__set_irq_handler  
    4. }  

    2.1 __set_irq_handler函数

    [cpp] view plain copy
    1. void __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,const char *name)  
    2. {  
    3.     struct irq_desc *desc = irq_to_desc(irq);   //获取全局irq_desc数组项  
    4.     unsigned long flags;  
    5.   
    6.     if (!desc) {  
    7.         printk(KERN_ERR"Trying to install type control for IRQ%d ", irq);  
    8.         return;  
    9.     }  
    10.     if (!handle)    //若没指定handle  
    11.         handle = handle_bad_irq;    //则设置为handle_bad_irq  
    12.     else if (desc->irq_data.chip == &no_irq_chip) {  
    13.         printk(KERN_WARNING "Trying to install %sinterrupt handler for IRQ%d ", is_chained ? "chained " : "", irq);  
    14.         desc->irq_data.chip = &dummy_irq_chip;   //设置desc->irq_data.chip为dummy_irq_chip(空操作的irq_chip)  
    15.     }  
    16.     chip_bus_lock(desc);  
    17.     raw_spin_lock_irqsave(&desc->lock, flags);  
    18.     if (handle == handle_bad_irq) {  
    19.         if (desc->irq_data.chip != &no_irq_chip)  
    20.             mask_ack_irq(desc);  
    21.         desc->status |= IRQ_DISABLED;  
    22.         desc->depth = 1;  
    23.     }  
    24.     desc->handle_irq = handle;   //高级中断处理句柄  
    25.     desc->name = name;  
    26.     if (handle != handle_bad_irq && is_chained) {   //链接  
    27.         desc->status &= ~IRQ_DISABLED;  
    28.         desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;  
    29.         desc->depth = 0;  
    30.         desc->irq_data.chip->irq_startup(&desc->irq_data);  
    31.     }  
    32.     raw_spin_unlock_irqrestore(&desc->lock, flags);  
    33.     chip_bus_sync_unlock(desc);  
    34. }  
    35. EXPORT_SYMBOL_GPL(__set_irq_handler);  

    3.set_irq_flags 根据irq号获取全局irq_desc数组项,并设置其status标志(中断标志)

    [cpp] view plain copy
    1. void set_irq_flags(unsigned int irq, unsigned int iflags)  
    2. {  
    3.     struct irq_desc *desc;  
    4.     unsigned long flags;  
    5.   
    6.     if (irq >= nr_irqs) {  
    7.         printk(KERN_ERR "Trying to set irq flags for IRQ%d ", irq);  
    8.         return;  
    9.     }  
    10.     desc = irq_to_desc(irq);    //获取全局irq_desc数组项  
    11.     raw_spin_lock_irqsave(&desc->lock, flags);  
    12.     desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;  
    13.     if (iflags & IRQF_VALID)  
    14.         desc->status &= ~IRQ_NOREQUEST;  
    15.     if (iflags & IRQF_PROBE)  
    16.         desc->status &= ~IRQ_NOPROBE;  
    17.     if (!(iflags & IRQF_NOAUTOEN))  
    18.         desc->status &= ~IRQ_NOAUTOEN;  
    19.     raw_spin_unlock_irqrestore(&desc->lock, flags);  
    20. }  

    4.set_irq_type根据irq号获取全局irq_desc数组项,并设置其status标志(中断触发类型)

    [cpp] view plain copy
    1. int set_irq_type(unsigned int irq, unsigned int type)  
    2. {  
    3.     struct irq_desc *desc = irq_to_desc(irq);   //获取全局irq_desc数组项  
    4.     unsigned long flags;  
    5.     int ret = -ENXIO;  
    6.   
    7.     if (!desc) {  
    8.         printk(KERN_ERR "Trying to set irq type for IRQ%d ", irq);  
    9.         return -ENODEV;  
    10.     }  
    11.     type &= IRQ_TYPE_SENSE_MASK;  
    12.     if (type == IRQ_TYPE_NONE)  
    13.         return 0;  
    14.     raw_spin_lock_irqsave(&desc->lock, flags);  
    15.     ret = __irq_set_trigger(desc, irq, type);   //调用__irq_set_trigger  
    16.     raw_spin_unlock_irqrestore(&desc->lock, flags);  
    17.     return ret;  
    18. }  
    19. EXPORT_SYMBOL(set_irq_type);  

    4.1 __irq_set_trigger函数

    [cpp] view plain copy
    1. int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,unsigned long flags)  
    2. {  
    3.     int ret;  
    4.     struct irq_chip *chip = desc->irq_data.chip;  
    5.   
    6.     if (!chip || !chip->irq_set_type) {  
    7.         pr_debug("No set_type function for IRQ %d (%s) ", irq,chip ? (chip->name ? : "unknown") : "unknown");  
    8.         return 0;  
    9.     }  
    10.     ret = chip->irq_set_type(&desc->irq_data, flags);  
    11.     if (ret)  
    12.         pr_err("setting trigger mode %lu for irq %u failed (%pF) ",flags, irq, chip->irq_set_type);  
    13.     else {  
    14.         if (flags & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))  
    15.             flags |= IRQ_LEVEL;  
    16.         /* note that IRQF_TRIGGER_MASK == IRQ_TYPE_SENSE_MASK */  
    17.         desc->status &= ~(IRQ_LEVEL | IRQ_TYPE_SENSE_MASK);  
    18.         desc->status |= flags;  
    19.         if (chip != desc->irq_data.chip)  
    20.             irq_chip_set_defaults(desc->irq_data.chip);  
    21.     }  
    22.     return ret;  
    23. }  

    5.set_irq_chip_data 根据irq号获取全局irq_desc数组项,并设置其irq_data的chip_data

    [cpp] view plain copy
    1. int set_irq_chip_data(unsigned int irq, void *data)  
    2. {  
    3.     struct irq_desc *desc = irq_to_desc(irq);   //获取全局irq_desc数组项  
    4.     unsigned long flags;  
    5.   
    6.     if (!desc) {  
    7.         printk(KERN_ERR"Trying to install chip data for IRQ%d ", irq);  
    8.         return -EINVAL;  
    9.     }  
    10.     if (!desc->irq_data.chip) {  
    11.         printk(KERN_ERR "BUG: bad set_irq_chip_data(IRQ#%d) ", irq);  
    12.         return -EINVAL;  
    13.     }  
    14.     raw_spin_lock_irqsave(&desc->lock, flags);  
    15.     desc->irq_data.chip_data = data;  
    16.     raw_spin_unlock_irqrestore(&desc->lock, flags);  
    17.     return 0;  
    18. }  
    19. EXPORT_SYMBOL(set_irq_chip_data);  


    6.set_irq_data

    [cpp] view plain copy
    1. int set_irq_data(unsigned int irq, void *data)  
    2. {  
    3.     struct irq_desc *desc = irq_to_desc(irq);   //获取全局irq_desc数组项  
    4.     unsigned long flags;  
    5.   
    6.     if (!desc) {  
    7.         printk(KERN_ERR"Trying to install controller data for IRQ%d ", irq);  
    8.         return -EINVAL;  
    9.     }  
    10.     raw_spin_lock_irqsave(&desc->lock, flags);  
    11.     desc->irq_data.handler_data = data;  
    12.     raw_spin_unlock_irqrestore(&desc->lock, flags);  
    13.     return 0;  
    14. }  
    15. EXPORT_SYMBOL(set_irq_data);  

    三、中断的申请与释放request_irq

    1.申请中断(主要是分配设置irqaction结构体)

    [cpp] view plain copy
    1. static inline int __must_check request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)  
    2. {  
    3.     return request_threaded_irq(irq, handler, NULL, flags, name, dev);  
    4. }  

    1.1 request_threaded_irq函数

    [cpp] view plain copy
    1. int request_threaded_irq(unsigned int irq, irq_handler_t handler,irq_handler_t thread_fn, unsigned long irqflags,const char *devname, void *dev_id)  
    2. {  
    3.     struct irqaction *action;  
    4.     struct irq_desc *desc;  
    5.     int retval;  
    6.   
    7.     if ((irqflags & IRQF_SHARED) && !dev_id)    //共享中断但没指定中断id  
    8.         return -EINVAL;  
    9.     desc = irq_to_desc(irq);    //获取全局irq_desc数组项  
    10.     if (!desc)  
    11.         return -EINVAL;  
    12.     if (desc->status & IRQ_NOREQUEST)    //中断不能被请求  
    13.         return -EINVAL;  
    14.     if (!handler) { //没指定handler  
    15.         if (!thread_fn) //但存在thread_fn  
    16.             return -EINVAL;  
    17.         handler = irq_default_primary_handler;  //则设置irq_default_primary_handler  
    18.     }  
    19.     action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); //分配irqaction内存  
    20.     if (!action)  
    21.         return -ENOMEM;  
    22.     action->handler = handler;   //设置处理句柄  
    23.     action->thread_fn = thread_fn;   //设置线程函数NULL  
    24.     action->flags = irqflags;    //设置中断标志  
    25.     action->name = devname;      //设置设备名  
    26.     action->dev_id = dev_id; //设置设备id  
    27.     chip_bus_lock(desc);  
    28.     retval = __setup_irq(irq, desc, action);    //-->__setup_irq  
    29.     chip_bus_sync_unlock(desc);  
    30.     if (retval)  
    31.         kfree(action);  
    32. #ifdef CONFIG_DEBUG_SHIRQ  
    33.     if (!retval && (irqflags & IRQF_SHARED)) {  
    34.         unsigned long flags;  
    35.         disable_irq(irq);  
    36.         local_irq_save(flags);  
    37.         handler(irq, dev_id);  
    38.         local_irq_restore(flags);  
    39.         enable_irq(irq);  
    40.     }  
    41. #endif  
    42.     return retval;  
    43. }  
    44. EXPORT_SYMBOL(request_threaded_irq);  

     

    1.2 __setup_irq函数

    [cpp] view plain copy
    1. static int __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)  
    2. {  
    3.     struct irqaction *old, **old_ptr;  
    4.     const char *old_name = NULL;  
    5.     unsigned long flags;  
    6.     int nested, shared = 0;  
    7.     int ret;  
    8.   
    9.     if (!desc)  
    10.         return -EINVAL;  
    11.     if (desc->irq_data.chip == &no_irq_chip)  
    12.         return -ENOSYS;  
    13.     if (new->flags & IRQF_SAMPLE_RANDOM) {  
    14.         rand_initialize_irq(irq);  
    15.     }  
    16.     if ((new->flags & IRQF_ONESHOT) && (new->flags & IRQF_SHARED))  
    17.         return -EINVAL;  
    18.     nested = desc->status & IRQ_NESTED_THREAD;   //嵌套标志  
    19.     if (nested) {   //嵌套  
    20.         if (!new->thread_fn) //且存在线程处理句柄  
    21.             return -EINVAL;  
    22.         new->handler = irq_nested_primary_handler;       //嵌套处理的句柄  
    23.     }  
    24.     if (new->thread_fn && !nested) { //非嵌套且存在线程函数  
    25.         struct task_struct *t;  
    26.   
    27.         t = kthread_create(irq_thread, new, "irq/%d-%s", irq,new->name); //创建线程  
    28.         if (IS_ERR(t))  
    29.             return PTR_ERR(t);  
    30.         get_task_struct(t);  
    31.         new->thread = t; //设置线程任务结构体  
    32.     }  
    33.     raw_spin_lock_irqsave(&desc->lock, flags);  
    34.     old_ptr = &desc->action;  
    35.     old = *old_ptr;  
    36.     if (old) {  
    37.         if (!((old->flags & new->flags) & IRQF_SHARED) || ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) {  
    38.             old_name = old->name;  
    39.             goto mismatch;  
    40.         }  
    41. #if defined(CONFIG_IRQ_PER_CPU)  
    42.         if ((old->flags & IRQF_PERCPU) != (new->flags & IRQF_PERCPU))  
    43.             goto mismatch;  
    44. #endif  
    45.         do {  
    46.             old_ptr = &old->next;  
    47.             old = *old_ptr;  
    48.         } while (old);  
    49.         shared = 1; //共享中断标志  
    50.     }  
    51.     if (!shared) {  //非共享中断  
    52.         irq_chip_set_defaults(desc->irq_data.chip);      //设置默认的芯片处理函数  
    53.         init_waitqueue_head(&desc->wait_for_threads);  
    54.         if (new->flags & IRQF_TRIGGER_MASK) {    //设置触发方式  
    55.             ret = __irq_set_trigger(desc, irq,new->flags & IRQF_TRIGGER_MASK);  
    56.             if (ret)  
    57.                 goto out_thread;  
    58.         }   
    59.         else  
    60.             compat_irq_chip_set_default_handler(desc);  
    61. #if defined(CONFIG_IRQ_PER_CPU)  
    62.         if (new->flags & IRQF_PERCPU)  
    63.             desc->status |= IRQ_PER_CPU;  
    64. #endif  
    65.         desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | IRQ_ONESHOT |IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);  
    66.         if (new->flags & IRQF_ONESHOT)  
    67.             desc->status |= IRQ_ONESHOT;  
    68.         if (!(desc->status & IRQ_NOAUTOEN)) {  
    69.             desc->depth = 0;  
    70.             desc->status &= ~IRQ_DISABLED;  
    71.             desc->irq_data.chip->irq_startup(&desc->irq_data);  
    72.         }   
    73.         else  
    74.             desc->depth = 1;  
    75.         if (new->flags & IRQF_NOBALANCING)  
    76.             desc->status |= IRQ_NO_BALANCING;  
    77.         setup_affinity(irq, desc);  
    78.     }   
    79.     else if ((new->flags & IRQF_TRIGGER_MASK)&& (new->flags & IRQF_TRIGGER_MASK)!= (desc->status & IRQ_TYPE_SENSE_MASK)) {  
    80.         pr_warning("IRQ %d uses trigger mode %d; requested %d ",  
    81.                 irq, (int)(desc->status & IRQ_TYPE_SENSE_MASK),(int)(new->flags & IRQF_TRIGGER_MASK));  
    82.     }  
    83.     new->irq = irq;  //设置中断号  
    84.     *old_ptr = new;  
    85.     desc->irq_count = 0;  
    86.     desc->irqs_unhandled = 0;  
    87.     if (shared && (desc->status & IRQ_SPURIOUS_DISABLED)) {  //共享中断  
    88.         desc->status &= ~IRQ_SPURIOUS_DISABLED;  
    89.         __enable_irq(desc, irq, false);  
    90.     }  
    91.     raw_spin_unlock_irqrestore(&desc->lock, flags);  
    92.     if (new->thread)  
    93.         wake_up_process(new->thread);  
    94.     register_irq_proc(irq, desc);   //注册proc irq接口  
    95.     new->dir = NULL;  
    96.     register_handler_proc(irq, new);    //注册proc handler接口  
    97.     return 0;  
    98. mismatch:  
    99. #ifdef CONFIG_DEBUG_SHIRQ  
    100.     if (!(new->flags & IRQF_PROBE_SHARED)) {  
    101.         printk(KERN_ERR "IRQ handler type mismatch for IRQ %d ", irq);  
    102.         if (old_name)  
    103.             printk(KERN_ERR "current handler: %s ", old_name);  
    104.         dump_stack();  
    105.     }  
    106. #endif  
    107.     ret = -EBUSY;  
    108. out_thread:  
    109.     raw_spin_unlock_irqrestore(&desc->lock, flags);  
    110.     if (new->thread) {  
    111.         struct task_struct *t = new->thread;  
    112.         new->thread = NULL;  
    113.         if (likely(!test_bit(IRQTF_DIED, &new->thread_flags)))  
    114.             kthread_stop(t);  
    115.         put_task_struct(t);  
    116.     }  
    117.     return ret;  
    118. }  

    代码可以去细究,主要功能是填充irqaction

    在设备驱动程序中申请中断可以这么申请

    (eg:request_irq(1, &XXX_interrupt,IRQF_TRIGGER_RISING,"nameXXX", (void*)0))

    第一个参数是中断号,第二个参数是中断处理函数,第三个参数是中断标志(上升沿),第四个是名字,第五个是设备id(非共享中断设置成(void*)0)即可

    共享中断情况下要将第三个参数添加IRQF_SHARED标志,同时要给他制定第五个参数设备id

    触发方式宏

    [cpp] view plain copy
    1. #define IRQ_TYPE_NONE       0x00000000  /* Default, unspecified type */  
    2. #define IRQ_TYPE_EDGE_RISING    0x00000001  //上升沿触发  
    3. #define IRQ_TYPE_EDGE_FALLING   0x00000002  //下降沿触发  
    4. #define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)   //双边沿触发  
    5. #define IRQ_TYPE_LEVEL_HIGH 0x00000004  //高电平有效  
    6. #define IRQ_TYPE_LEVEL_LOW  0x00000008  //低电平有效  
    7. #define IRQ_TYPE_SENSE_MASK 0x0000000f  /* Mask of the above */  
    8. #define IRQ_TYPE_PROBE      0x00000010  /* Probing in progress */  


    然后设计中断函数

    static irqreturn_t XXX_interrupt(int irq, void *arg){

        ......

        return IRQ_HANDLED;

    }

    2.释放中断

    [cpp] view plain copy
    1. void free_irq(unsigned int irq, void *dev_id)  
    2. {  
    3.     struct irq_desc *desc = irq_to_desc(irq);   //获取全局irq_desc数组项  
    4.   
    5.     if (!desc)  
    6.         return;  
    7.     chip_bus_lock(desc);  
    8.     kfree(__free_irq(irq, dev_id));  
    9.     chip_bus_sync_unlock(desc);  
    10. }  
    11. EXPORT_SYMBOL(free_irq);  

    2.1 __free_irq

    [cpp] view plain copy
    1. static struct irqaction *__free_irq(unsigned int irq, void *dev_id)  
    2. {  
    3.     struct irq_desc *desc = irq_to_desc(irq);   //获取全局irq_desc数组项  
    4.     struct irqaction *action, **action_ptr;  
    5.     unsigned long flags;  
    6.   
    7.     WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context! ", irq);  
    8.     if (!desc)  
    9.         return NULL;  
    10.     raw_spin_lock_irqsave(&desc->lock, flags);  
    11.     action_ptr = &desc->action;  
    12.     for (;;) {  
    13.         action = *action_ptr;  
    14.         if (!action) {  
    15.             WARN(1, "Trying to free already-free IRQ %d ", irq);  
    16.             raw_spin_unlock_irqrestore(&desc->lock, flags);  
    17.             return NULL;  
    18.         }  
    19.         if (action->dev_id == dev_id)    //找到匹配的id项  
    20.             break;  
    21.         action_ptr = &action->next;  
    22.     }  
    23.     *action_ptr = action->next;  
    24. #ifdef CONFIG_IRQ_RELEASE_METHOD  
    25.     if (desc->irq_data.chip->release)  
    26.         desc->irq_data.chip->release(irq, dev_id);  
    27. #endif  
    28.     if (!desc->action) {  
    29.         desc->status |= IRQ_DISABLED;  
    30.         if (desc->irq_data.chip->irq_shutdown)  
    31.             desc->irq_data.chip->irq_shutdown(&desc->irq_data);  
    32.         else  
    33.             desc->irq_data.chip->irq_disable(&desc->irq_data);  
    34.     }  
    35. #ifdef CONFIG_SMP  
    36.     if (WARN_ON_ONCE(desc->affinity_hint))  
    37.         desc->affinity_hint = NULL;  
    38. #endif  
    39.     raw_spin_unlock_irqrestore(&desc->lock, flags);  
    40.     unregister_handler_proc(irq, action);  
    41.     synchronize_irq(irq);  
    42. #ifdef CONFIG_DEBUG_SHIRQ  
    43.     if (action->flags & IRQF_SHARED) {  
    44.         local_irq_save(flags);  
    45.         action->handler(irq, dev_id);  
    46.         local_irq_restore(flags);  
    47.     }  
    48. #endif  
    49.     if (action->thread) {  
    50.         if (!test_bit(IRQTF_DIED, &action->thread_flags))  
    51.             kthread_stop(action->thread);  
    52.         put_task_struct(action->thread);  
    53.     }  
    54.     return action;  
    55. }  


     

    四、中断处理过程

     1.当有中断发生时,程序会到__vectors_star去查找向量表(arch/arm/kernel/entry-armv.S)

    [cpp] view plain copy
    1. .globl  __vectors_start  
    2. _vectors_start:  
    3. ARM(    swi SYS_ERROR0  )   /* swi指令 */  
    4. THUMB(  svc #0      )  
    5. THUMB(  nop         )  
    6. W(b)    vector_und + stubs_offset  
    7. W(ldr)  pc, .LCvswi + stubs_offset  
    8. W(b)    vector_pabt + stubs_offset  
    9. W(b)    vector_dabt + stubs_offset  
    10. W(b)    vector_addrexcptn + stubs_offset  
    11. W(b)    vector_irq + stubs_offset   /* 中断向量表 */  
    12. W(b)    vector_fiq + stubs_offset  
    13. .globl  __vectors_end  
    14. _vectors_end:  

    2.vector_irq的定义声明

    [cpp] view plain copy
    1.     .globl  __stubs_start  
    2. __stubs_start:  
    3. /* 
    4.  * Interrupt dispatcher 
    5.  */  
    6.     vector_stub irq, IRQ_MODE, 4    /*参看下面vector_stub宏的定义*/  
    7.   
    8.     .long   __irq_usr           @  0  (USR_26 / USR_32)     /*usr模式下中断处理(见下面)*/  
    9.     .long   __irq_invalid       @  1  (FIQ_26 / FIQ_32)  
    10.     .long   __irq_invalid       @  2  (IRQ_26 / IRQ_32)  
    11.     .long   __irq_svc           @  3  (SVC_26 / SVC_32)     /*svc模式下中断处理(见下面)*/  
    12.     .long   __irq_invalid       @  4  
    13.     .long   __irq_invalid       @  5  
    14.     .long   __irq_invalid       @  6  
    15.     .long   __irq_invalid       @  7  
    16.     .long   __irq_invalid       @  8  
    17.     .long   __irq_invalid       @  9  
    18.     .long   __irq_invalid       @  a  
    19.     .long   __irq_invalid       @  b  
    20.     .long   __irq_invalid       @  c  
    21.     .long   __irq_invalid       @  d  
    22.     .long   __irq_invalid       @  e  
    23.     .long   __irq_invalid       @  f  

    3.vector_stub宏的定义

    [cpp] view plain copy
    1.     /*vector_stub irq, IRQ_MODE, 4*/  
    2.     .macro  vector_stub, name, mode, correction=0     
    3.     .align  5  
    4.   
    5. vector_ ame:                       /*构造了vector_irq*/  
    6.     .if correction                 /*if 4*/  
    7.     sub lr, lr, #correction  
    8.     .endif  
    9.   
    10.     @   
    11.     @ Save r0, lr_<exception> (parent PC) and spsr_<exception>  
    12.     @ (parent CPSR)  
    13.     @  
    14.     stmia   sp, {r0, lr}        @ save r0, lr  
    15.     mrs lr, spsr  
    16.     str lr, [sp, #8]        @ save spsr  
    17.   
    18.     @  
    19.     @ Prepare for SVC32 mode.  IRQs remain disabled.    准备切到svc模式  
    20.     @  
    21.     mrs r0, cpsr  
    22.     eor r0, r0, #(mode ^ SVC_MODE | PSR_ISETSTATE)  
    23.     msr spsr_cxsf, r0  
    24.   
    25.     @ /*分支表必须紧接着这段代码*/  
    26.     @ the branch table must immediately follow this code  
    27.     @  
    28.     and lr, lr, #0x0f  
    29.  THUMB( adr r0, 1f          )  
    30.  THUMB( ldr lr, [r0, lr, lsl #2]    )  
    31.     mov r0, sp  
    32.  ARM(   ldr lr, [pc, lr, lsl #2]    )  
    33.     movs    pc, lr          @ branch to handler in SVC mode 跳到分支表处  
    34. ENDPROC(vector_ ame)  
    35.   
    36.     .align  2  
    37.     @ handler addresses follow this label  
    38. 1:  
    39.     .endm  

    这几段汇编的大致意思是中断发生会跳到vector_irq去执行,vector_irq根据情况会跳到__irq_usr或__irq_svc执行

    4.__irq_usr

    [cpp] view plain copy
    1. __irq_usr:  
    2.         usr_entry  
    3.         kuser_cmpxchg_check  
    4.       
    5.         get_thread_info tsk  
    6. #ifdef CONFIG_PREEMPT  
    7.         ldr r8, [tsk, #TI_PREEMPT]      @ get preempt count  
    8.         add r7, r8, #1          @ increment it  
    9.         str r7, [tsk, #TI_PREEMPT]  
    10. #endif  
    11.       
    12.         irq_handler     /*跳转到irq_handler处理*/  
    13. #ifdef CONFIG_PREEMPT  
    14.         ldr r0, [tsk, #TI_PREEMPT]  
    15.         str r8, [tsk, #TI_PREEMPT]  
    16.         teq r0, r7  
    17.      ARM(   strne   r0, [r0, -r0]   )  
    18.      THUMB( movne   r0, #0      )  
    19.      THUMB( strne   r0, [r0]    )  
    20. #endif  
    21.       
    22.         mov why, #0  
    23.         b   ret_to_user  
    24.      UNWIND(.fnend      )  
    25.     ENDPROC(__irq_usr)  


    5.__irq_svc

    [cpp] view plain copy
    1. __irq_svc:  
    2.         svc_entry  
    3.       
    4. #ifdef CONFIG_TRACE_IRQFLAGS  
    5.         bl  trace_hardirqs_off  
    6. #endif  
    7. #ifdef CONFIG_PREEMPT  
    8.         get_thread_info tsk  
    9.         ldr r8, [tsk, #TI_PREEMPT]      @ get preempt count  
    10.         add r7, r8, #1          @ increment it  
    11.         str r7, [tsk, #TI_PREEMPT]  
    12. #endif  
    13.       
    14.         irq_handler         /*跳转到irq_handler处理*/  
    15. #ifdef CONFIG_PREEMPT  
    16.         str r8, [tsk, #TI_PREEMPT]      @ restore preempt count  
    17.         ldr r0, [tsk, #TI_FLAGS]        @ get flags  
    18.         teq r8, #0              @ if preempt count != 0  
    19.         movne   r0, #0              @ force flags to 0  
    20.         tst r0, #_TIF_NEED_RESCHED  
    21.         blne    svc_preempt  
    22. #endif  
    23.         ldr r4, [sp, #S_PSR]        @ irqs are already disabled  
    24. #ifdef CONFIG_TRACE_IRQFLAGS  
    25.         tst r4, #PSR_I_BIT  
    26.         bleq    trace_hardirqs_on  
    27. #endif  
    28.         svc_exit r4             @ return from exception  
    29.      UNWIND(.fnend      )  
    30.     ENDPROC(__irq_svc)  


    6.不管是__irq_svc或是__irq_usr都会调用到irqhandler

    [cpp] view plain copy
    1.     .macro  irq_handler  
    2.     get_irqnr_preamble r5, lr  
    3. 1:  get_irqnr_and_base r0, r6, r5, lr  
    4.     movne   r1, sp  
    5.     @ r0保存了中断号,r1保存了保留现场的寄存器指针  
    6.     @ routine called with r0 = irq number, r1 = struct pt_regs *  
    7.     @  
    8.     adrne   lr, BSYM(1b)  
    9.     bne asm_do_IRQ  /*********************跳转到asm_do_IRQ函数处理*/  
    10.   
    11. #ifdef CONFIG_SMP  
    12.     /* 
    13.      * XXX 
    14.      * 
    15.      * this macro assumes that irqstat (r6) and base (r5) are 
    16.      * preserved from get_irqnr_and_base above 
    17.      */  
    18.     ALT_SMP(test_for_ipi r0, r6, r5, lr)  
    19.     ALT_UP_B(9997f)  
    20.     movne   r0, sp  
    21.     adrne   lr, BSYM(1b)  
    22.     bne do_IPI  
    23.   
    24. #ifdef CONFIG_LOCAL_TIMERS  
    25.     test_for_ltirq r0, r6, r5, lr  
    26.     movne   r0, sp  
    27.     adrne   lr, BSYM(1b)  
    28.     bne do_local_timer  
    29. #endif  
    30. 9997:  
    31. #endif  
    32.   
    33.     .endm  


    7.就这样进入了c处理的阶段asm_do_IRQ

    [cpp] view plain copy
    1. asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)  
    2. {  
    3.     struct pt_regs *old_regs = set_irq_regs(regs);  
    4.   
    5.     irq_enter();  
    6.   
    7.     /* 
    8.      * Some hardware gives randomly wrong interrupts.  Rather 
    9.      * than crashing, do something sensible. 
    10.      */  
    11.     if (unlikely(irq >= nr_irqs)) {  //中断号大于中断的个数  
    12.         if (printk_ratelimit())  
    13.             printk(KERN_WARNING "Bad IRQ%u ", irq);  
    14.         ack_bad_irq(irq);  
    15.     }   
    16.     else {  
    17.         generic_handle_irq(irq);    //通用中断处理函数  
    18.     }  
    19.   
    20.     /* AT91 specific workaround */  
    21.     irq_finish(irq);  
    22.   
    23.     irq_exit();  
    24.     set_irq_regs(old_regs);  
    25. }  

    8.generic_handle_irq函数

    [cpp] view plain copy
    1. static inline void generic_handle_irq(unsigned int irq)  
    2. {  
    3.     generic_handle_irq_desc(irq, irq_to_desc(irq)); //调用了irq_to_desc获取全局irq_desc[irq]项  
    4. }  

    9.generic_handle_irq_desc函数

    [cpp] view plain copy
    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); //则只能用指定的handle_irq方法  
    5. #else  
    6.     if (likely(desc->handle_irq))    //若中断处理函数存在  
    7.         desc->handle_irq(irq, desc); //则调用注册的中断处理函数(irq_desc[irq]->handle_irq(irq,desc))  
    8.     else  
    9.         __do_IRQ(irq);  //没指定中断处理函数的处理分支  
    10. #endif  
    11. }  

    这里有了分支关键看CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ的设置

    如果设置为1,则只调用中断描述符的handle_irq方法

    如果设置为0,则如果中断描述符存在handle_irq方法则调用该方法,如果没有则调用__do_IRQ()

    中断描述符handle_irq方法,一般是芯片厂商写好的,先看看__do_IRQ()吧

    10.__do_IRQ函数

    [cpp] view plain copy
    1. unsigned int __do_IRQ(unsigned int irq)  
    2. {  
    3.     struct irq_desc *desc = irq_to_desc(irq);  
    4.     struct irqaction *action;  
    5.     unsigned int status;  
    6.   
    7.     kstat_incr_irqs_this_cpu(irq, desc);  
    8.     if (CHECK_IRQ_PER_CPU(desc->status)) {  
    9.         irqreturn_t action_ret;  
    10.         if (desc->irq_data.chip->ack)  
    11.             desc->irq_data.chip->ack(irq);  
    12.         if (likely(!(desc->status & IRQ_DISABLED))) {  
    13.             action_ret = handle_IRQ_event(irq, desc->action);//调用handle_IRQ_event函数  
    14.             if (!noirqdebug)  
    15.                 note_interrupt(irq, desc, action_ret);  
    16.         }  
    17.         desc->irq_data.chip->end(irq);  
    18.         return 1;  
    19.     }  
    20.     raw_spin_lock(&desc->lock);  
    21.     if (desc->irq_data.chip->ack)  
    22.         desc->irq_data.chip->ack(irq);  
    23.     status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);  
    24.     status |= IRQ_PENDING; /* we _want_ to handle it */  
    25.     action = NULL;  
    26.     if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {  
    27.         action = desc->action;  
    28.         status &= ~IRQ_PENDING; /* we commit to handling */  
    29.         status |= IRQ_INPROGRESS; /* we are handling it */  
    30.     }  
    31.     desc->status = status;  
    32.     if (unlikely(!action))  
    33.         goto out;  
    34.     for (;;) {  
    35.         irqreturn_t action_ret;  
    36.         raw_spin_unlock(&desc->lock);  
    37.         action_ret = handle_IRQ_event(irq, action);//调用handle_IRQ_event函数  
    38.         if (!noirqdebug)  
    39.             note_interrupt(irq, desc, action_ret);  
    40.         raw_spin_lock(&desc->lock);  
    41.         if (likely(!(desc->status & IRQ_PENDING)))  
    42.             break;  
    43.         desc->status &= ~IRQ_PENDING;  
    44.     }  
    45.     desc->status &= ~IRQ_INPROGRESS;  
    46. out:  
    47.     desc->irq_data.chip->end(irq);  
    48.     raw_spin_unlock(&desc->lock);  
    49.     return 1;  
    50. }  

    .__do_IRQ函数主要是调用handle_IRQ_event来处理中断

    11.handle_IRQ_event函数

    [cpp] view plain copy
    1. irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)  
    2. {  
    3.     irqreturn_t ret, retval = IRQ_NONE;  
    4.     unsigned int status = 0;  
    5.   
    6.     do {  
    7.         trace_irq_handler_entry(irq, action);  
    8.         ret = action->handler(irq, action->dev_id);//调用了irqaction的handler方法  
    9.         trace_irq_handler_exit(irq, action, ret);  
    10.         switch (ret) {  
    11.         case IRQ_WAKE_THREAD:  
    12.             ret = IRQ_HANDLED;  
    13.             if (unlikely(!action->thread_fn)) {  
    14.                 warn_no_thread(irq, action);  
    15.                 break;  
    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.         case IRQ_HANDLED:  
    23.             status |= action->flags;  
    24.             break;  
    25.   
    26.         default:  
    27.             break;  
    28.         }  
    29.         retval |= ret;  
    30.         action = action->next;  
    31.     } while (action);  
    32.   
    33.     if (status & IRQF_SAMPLE_RANDOM)  
    34.         add_interrupt_randomness(irq);  
    35.     local_irq_disable();  
    36.     return retval;  
    37. }  

    这里调用的irqaction的handler方法就是调用了之前设备驱动中用request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)

    申请中断时传递进来的第二个参数的函数
    其实很多芯片厂商在编写中断描述符handle_irq方法的时候也会调用到handle_IRQ_event函数

    整个中断的处理过程就是

  • 相关阅读:
    冲刺第一天
    就用户界面和体验评价搜狗输入法
    学习进度条10
    典型用户及用户场景描述
    学习进度条09
    冲刺阶段第八天
    对石家庄铁道大学网站的UI分析
    学习进度条(第八周)
    冲刺阶段第七天
    冲刺阶段第六天
  • 原文地址:https://www.cnblogs.com/wanghuaijun/p/6321944.html
Copyright © 2020-2023  润新知