码迷,mamicode.com
首页 > 系统相关 > 详细

linux 中断机制浅析

时间:2017-01-20 11:00:27      阅读:422      评论:0      收藏:0      [点我收藏+]

标签:mem   汇编   节点   设备id   nop   reads   位置   user   机制   

一、中断相关结构体

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\n",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\n", 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\n", 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\n", 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\n", 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\n", 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\n", 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)\n", 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)\n",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\n", irq);  
  8.         return -EINVAL;  
  9.     }  
  10.     if (!desc->irq_data.chip) {  
  11.         printk(KERN_ERR "BUG: bad set_irq_chip_data(IRQ#%d)\n", 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\n", 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\n",  
  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\n", irq);  
  102.         if (old_name)  
  103.             printk(KERN_ERR "current handler: %s\n", 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!\n", 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\n", 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_\name:                       /*构造了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_\name)  
  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\n", 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函数

整个中断的处理过程就是

技术分享

linux 中断机制浅析

标签:mem   汇编   节点   设备id   nop   reads   位置   user   机制   

原文地址:http://www.cnblogs.com/wanghuaijun/p/6321944.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!