linux 中断机制浅析

本文介绍了Linux内核中的中断处理机制,详细解析了中断描述符irq_desc的结构,并展示了如何通过不同函数来配置和管理中断。此外,还涉及了在setup_arch函数中初始化中断的相关过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载地址:http://blog.youkuaiyun.com/orz415678659/article/details/8721805

一、中断相关结构体

1.irq_desc中断描述符

  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;  
struct irq_desc {
#ifdef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
	struct irq_data	irq_data;
#else
	union {
		struct irq_data	irq_data;	//中断数据
		struct {
			unsigned int	irq;	//中断号
			unsigned int	node;	//节点号
			struct irq_chip	*chip;	//irq_chip
			void	*handler_data;	
			void	*chip_data;	
			struct msi_desc	*msi_desc;
#ifdef CONFIG_SMP
			cpumask_var_t	affinity;
#endif
		};
	};
#endif
	struct timer_rand_state *timer_rand_state;
	unsigned int	*kstat_irqs;
	irq_flow_handler_t	handle_irq;	//中断处理句柄
	struct irqaction	*action;	/* 中断动作列表 */
	unsigned int	status;		/* 中断状态 */
	unsigned int	depth;		/* nested irq disables */
	unsigned int	wake_depth;	/* nested wake enables */
	unsigned int	irq_count;	/* For detecting broken IRQs */
	unsigned long	last_unhandled;	/* Aging timer for unhandled count */
	unsigned int	irqs_unhandled;
	raw_spinlock_t	lock;
#ifdef CONFIG_SMP
	const struct cpumask	*affinity_hint;
#ifdef CONFIG_GENERIC_PENDING_IRQ
	cpumask_var_t	pending_mask;
#endif
#endif
	atomic_t	threads_active;
	wait_queue_head_t	wait_for_threads;
#ifdef CONFIG_PROC_FS
	struct proc_dir_entry	*dir;	//proc接口目录
#endif
	const char	*name;	//名字
} ____cacheline_internodealigned_in_smp;


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

  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. };  
struct irq_chip {	//芯片相关的处理函数集合
	const char	*name;	//"proc/interrupts/name"
#ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
	unsigned int	(*startup)(unsigned int irq);	
	void	(*shutdown)(unsigned int irq);	
	void	(*enable)(unsigned int irq);	
	void	(*disable)(unsigned int irq);	
	void	(*ack)(unsigned int irq);
	void	(*mask)(unsigned int irq);
	void	(*mask_ack)(unsigned int irq);
	void	(*unmask)(unsigned int irq);
	void	(*eoi)(unsigned int irq);
	void	(*end)(unsigned int irq);
	int		(*set_affinity)(unsigned int irq,const struct cpumask *dest);
	int		(*retrigger)(unsigned int irq);
	int		(*set_type)(unsigned int irq, unsigned int flow_type);
	int		(*set_wake)(unsigned int irq, unsigned int on);
	void	(*bus_lock)(unsigned int irq);
	void	(*bus_sync_unlock)(unsigned int irq);
#endif
	unsigned int	(*irq_startup)(struct irq_data *data);	//中断开始
	void	(*irq_shutdown)(struct irq_data *data);	//中断关闭
	void	(*irq_enable)(struct irq_data *data);	//中断使能
	void	(*irq_disable)(struct irq_data *data);	//中断禁用
	void	(*irq_ack)(struct irq_data *data);
	void	(*irq_mask)(struct irq_data *data);
	void	(*irq_mask_ack)(struct irq_data *data);
	void	(*irq_unmask)(struct irq_data *data);
	void	(*irq_eoi)(struct irq_data *data);
	int		(*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force);
	int		(*irq_retrigger)(struct irq_data *data);
	int		(*irq_set_type)(struct irq_data *data, unsigned int flow_type);
	int		(*irq_set_wake)(struct irq_data *data, unsigned int on);
	void	(*irq_bus_lock)(struct irq_data *data);
	void	(*irq_bus_sync_unlock)(struct irq_data *data);
#ifdef CONFIG_IRQ_RELEASE_METHOD
	void	(*release)(unsigned int irq, void *dev_id);
#endif
};


3.irqaction中断行动结构体

  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. };  
struct irqaction {
	irq_handler_t handler;	//中断处理函数
	unsigned long flags;	//中断标志
	const char *name;		//中断名
	void *dev_id;		//设备id号,共享中断用
	struct irqaction *next;	//共享中断类型指向下一个irqaction
	int irq;			//中断号
	struct proc_dir_entry *dir;	//proc接口目录
	irq_handler_t thread_fn;	//中断处理函数(线程)
	struct task_struct *thread;	//线程任务
	unsigned long thread_flags;	//线程标志
};

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

二、中断初始化工作

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

  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.         ]  
start_kernel
	setup_arch			//设置全局init_arch_irq函数
		early_trap_init	//搬移向量表
	early_irq_init();	//初始化全局irq_desc数组
	init_IRQ();			//调用init_arch_irq函数
		[	//板级中断初始化常用到的API
		set_irq_chip
		set_irq_handler
		set_irq_chained_handler
		set_irq_flags
		set_irq_type
		set_irq_chip_data
		set_irq_data
		]

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

  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. }  
void __init setup_arch(char **cmdline_p)
{
	struct tag *tags = (struct tag *)&init_tags;
	struct machine_desc *mdesc;
	char *from = default_command_line;

	init_tags.mem.start = PHYS_OFFSET;
	unwind_init();
	setup_processor();
	mdesc = setup_machine(machine_arch_type);
	machine_name = mdesc->name;
	if (mdesc->soft_reboot)
		reboot_setup("s");
	if (__atags_pointer)
		tags = phys_to_virt(__atags_pointer);
	else if (mdesc->boot_params) {
#ifdef CONFIG_MMU
		if (mdesc->boot_params < PHYS_OFFSET ||mdesc->boot_params >= PHYS_OFFSET + SZ_1M) {
			printk(KERN_WARNING"Default boot params at physical 0x%08lx out of reach\n",mdesc->boot_params);
		} 
		else
#endif
		{
			tags = phys_to_virt(mdesc->boot_params);
		}
	}
#if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
	if (tags->hdr.tag != ATAG_CORE)
		convert_to_tag_list(tags);
#endif
	if (tags->hdr.tag != ATAG_CORE)
		tags = (struct tag *)&init_tags;
	if (mdesc->fixup)
		mdesc->fixup(mdesc, tags, &from, &meminfo);
	if (tags->hdr.tag == ATAG_CORE) {
		if (meminfo.nr_banks != 0)
			squash_mem_tags(tags);
		save_atags(tags);
		parse_tags(tags);
	}
	init_mm.start_code = (unsigned long) _text;
	init_mm.end_code   = (unsigned long) _etext;
	init_mm.end_data   = (unsigned long) _edata;
	init_mm.brk	   = (unsigned long) _end;
	strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
	strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
	*cmdline_p = cmd_line;
	parse_early_param();
	arm_memblock_init(&meminfo, mdesc);
	paging_init(mdesc);
	request_standard_resources(&meminfo, mdesc);
#ifdef CONFIG_SMP
	if (is_smp())
		smp_init_cpus();
#endif
	reserve_crashkernel();
	cpu_init();
	tcm_init();
	arch_nr_irqs = mdesc->nr_irqs;
	init_arch_irq = mdesc->init_irq;	//设置全局init_arch_irq函数
	//void (*init_arch_irq)(void) __initdata = NULL;
	system_timer = mdesc->timer;
	init_machine = mdesc->init_machine;
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
	conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
	conswitchp = &dummy_con;
#endif
#endif
	early_trap_init();//调用early_trap_init函数
}

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

  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. }  
void __init early_trap_init(void)
{
	unsigned long vectors = CONFIG_VECTORS_BASE;	//0xffff0000
	extern char __stubs_start[], __stubs_end[];
	extern char __vectors_start[], __vectors_end[];
	extern char __kuser_helper_start[], __kuser_helper_end[];
	int kuser_sz = __kuser_helper_end - __kuser_helper_start;

	memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);	//移动中断向量表
	memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);	//移动__stubs_start段
	memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
	kuser_get_tls_init(vectors);
	memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes,sizeof(sigreturn_codes));
	memcpy((void *)KERN_RESTART_CODE, syscall_restart_code,sizeof(syscall_restart_code));
	flush_icache_range(vectors, vectors + PAGE_SIZE);
	modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
}

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

  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. };  
struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {	
	[0 ... NR_IRQS-1] = {
		.status		= IRQ_DEFAULT_INIT_FLAGS,
		.handle_irq	= handle_bad_irq,
		.depth		= 1,
		.lock		= __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
	}
};

获取irq_desc数组项的宏

  1. #define irq_to_desc(irq)    (&irq_desc[irq])  
#define irq_to_desc(irq)	(&irq_desc[irq])

early_irq_init函数

  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. }  
int __init early_irq_init(void)	//初始化全局irq_desc数组
{
	int count, i, node = first_online_node;
	struct irq_desc *desc;

	init_irq_default_affinity();
	printk(KERN_INFO "NR_IRQS:%d\n", NR_IRQS);
	desc = irq_desc;	//获取全局irq_desc数组
	count = ARRAY_SIZE(irq_desc);	//获取全局irq_desc数组项个数
	for (i = 0; i < count; i++) {	//初始化全局irq_desc数组
		desc[i].irq_data.irq = i;
		desc[i].irq_data.chip = &no_irq_chip;
		desc[i].kstat_irqs = kstat_irqs_all[i];
		alloc_masks(desc + i, GFP_KERNEL, node);
		desc_smp_init(desc + i, node);
		lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
	}
	return arch_early_irq_init();
}

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

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

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

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

  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);  
int set_irq_chip(unsigned int irq, struct irq_chip *chip)
{
	struct irq_desc *desc = irq_to_desc(irq);	//获取全局irq_desc数组项
	unsigned long flags;

	if (!desc) {
		WARN(1, KERN_ERR "Trying to install chip for IRQ%d\n", irq);
		return -EINVAL;
	}
	if (!chip)						//若irq_chip不存在
		chip = &no_irq_chip;		//设置为no_irq_chip
	raw_spin_lock_irqsave(&desc->lock, flags);
	irq_chip_set_defaults(chip);	//初始化irq_chip
	desc->irq_data.chip = chip;		//设置irq_desc->irq_data.chip
	raw_spin_unlock_irqrestore(&desc->lock, flags);
	return 0;
}
EXPORT_SYMBOL(set_irq_chip);

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

  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. }  
void irq_chip_set_defaults(struct irq_chip *chip)	//根据irq_chip的实际情况初始化默认方法
{
#ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
	if (chip->enable)	
		chip->irq_enable = compat_irq_enable;
	if (chip->disable)	
		chip->irq_disable = compat_irq_disable;
	if (chip->shutdown)	
		chip->irq_shutdown = compat_irq_shutdown;
	if (chip->startup)	
		chip->irq_startup = compat_irq_startup;
#endif
	if (!chip->irq_enable)		//使能中断
		chip->irq_enable = default_enable;
	if (!chip->irq_disable)		//禁用中断
		chip->irq_disable = default_disable;
	if (!chip->irq_startup)		//中断开始
		chip->irq_startup = default_startup;
	if (!chip->irq_shutdown)	//关闭中断
		chip->irq_shutdown = chip->irq_disable != default_disable ? chip->irq_disable : default_shutdown;

#ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
	if (!chip->end)
		chip->end = dummy_irq_chip.end;
	if (chip->bus_lock)
		chip->irq_bus_lock = compat_bus_lock;
	if (chip->bus_sync_unlock)
		chip->irq_bus_sync_unlock = compat_bus_sync_unlock;
	if (chip->mask)
		chip->irq_mask = compat_irq_mask;
	if (chip->unmask)
		chip->irq_unmask = compat_irq_unmask;
	if (chip->ack)
		chip->irq_ack = compat_irq_ack;
	if (chip->mask_ack)
		chip->irq_mask_ack = compat_irq_mask_ack;
	if (chip->eoi)
		chip->irq_eoi = compat_irq_eoi;
	if (chip->set_affinity)
		chip->irq_set_affinity = compat_irq_set_affinity;
	if (chip->set_type)
		chip->irq_set_type = compat_irq_set_type;
	if (chip->set_wake)
		chip->irq_set_wake = compat_irq_set_wake;
	if (chip->retrigger)
		chip->irq_retrigger = compat_irq_retrigger;
#endif
}

2.set_irq_handler和set_irq_chained_handler

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

  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. }  
static inline void set_irq_handler(unsigned int irq, irq_flow_handler_t handle)
{
	__set_irq_handler(irq, handle, 0, NULL);	//调用__set_irq_handler
}

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

  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. }  
static inline void set_irq_chained_handler(unsigned int irq,irq_flow_handler_t handle)
{
	__set_irq_handler(irq, handle, 1, NULL);	//调用__set_irq_handler
}

2.1 __set_irq_handler函数

  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);  
void __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,const char *name)
{
	struct irq_desc *desc = irq_to_desc(irq);	//获取全局irq_desc数组项
	unsigned long flags;

	if (!desc) {
		printk(KERN_ERR"Trying to install type control for IRQ%d\n", irq);
		return;
	}
	if (!handle)	//若没指定handle
		handle = handle_bad_irq;	//则设置为handle_bad_irq
	else if (desc->irq_data.chip == &no_irq_chip) {
		printk(KERN_WARNING "Trying to install %sinterrupt handler for IRQ%d\n", is_chained ? "chained " : "", irq);
		desc->irq_data.chip = &dummy_irq_chip;	//设置desc->irq_data.chip为dummy_irq_chip(空操作的irq_chip)
	}
	chip_bus_lock(desc);
	raw_spin_lock_irqsave(&desc->lock, flags);
	if (handle == handle_bad_irq) {
		if (desc->irq_data.chip != &no_irq_chip)
			mask_ack_irq(desc);
		desc->status |= IRQ_DISABLED;
		desc->depth = 1;
	}
	desc->handle_irq = handle;	//高级中断处理句柄
	desc->name = name;
	if (handle != handle_bad_irq && is_chained) {	//链接
		desc->status &= ~IRQ_DISABLED;
		desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;
		desc->depth = 0;
		desc->irq_data.chip->irq_startup(&desc->irq_data);
	}
	raw_spin_unlock_irqrestore(&desc->lock, flags);
	chip_bus_sync_unlock(desc);
}
EXPORT_SYMBOL_GPL(__set_irq_handler);

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

  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. }  
void set_irq_flags(unsigned int irq, unsigned int iflags)
{
	struct irq_desc *desc;
	unsigned long flags;

	if (irq >= nr_irqs) {
		printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
		return;
	}
	desc = irq_to_desc(irq);	//获取全局irq_desc数组项
	raw_spin_lock_irqsave(&desc->lock, flags);
	desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
	if (iflags & IRQF_VALID)
		desc->status &= ~IRQ_NOREQUEST;
	if (iflags & IRQF_PROBE)
		desc->status &= ~IRQ_NOPROBE;
	if (!(iflags & IRQF_NOAUTOEN))
		desc->status &= ~IRQ_NOAUTOEN;
	raw_spin_unlock_irqrestore(&desc->lock, flags);
}

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

  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);  
int set_irq_type(unsigned int irq, unsigned int type)
{
	struct irq_desc *desc = irq_to_desc(irq);	//获取全局irq_desc数组项
	unsigned long flags;
	int ret = -ENXIO;

	if (!desc) {
		printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq);
		return -ENODEV;
	}
	type &= IRQ_TYPE_SENSE_MASK;
	if (type == IRQ_TYPE_NONE)
		return 0;
	raw_spin_lock_irqsave(&desc->lock, flags);
	ret = __irq_set_trigger(desc, irq, type);	//调用__irq_set_trigger
	raw_spin_unlock_irqrestore(&desc->lock, flags);
	return ret;
}
EXPORT_SYMBOL(set_irq_type);

4.1 __irq_set_trigger函数

  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. }  
int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,unsigned long flags)
{
	int ret;
	struct irq_chip *chip = desc->irq_data.chip;

	if (!chip || !chip->irq_set_type) {
		pr_debug("No set_type function for IRQ %d (%s)\n", irq,chip ? (chip->name ? : "unknown") : "unknown");
		return 0;
	}
	ret = chip->irq_set_type(&desc->irq_data, flags);
	if (ret)
		pr_err("setting trigger mode %lu for irq %u failed (%pF)\n",flags, irq, chip->irq_set_type);
	else {
		if (flags & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
			flags |= IRQ_LEVEL;
		/* note that IRQF_TRIGGER_MASK == IRQ_TYPE_SENSE_MASK */
		desc->status &= ~(IRQ_LEVEL | IRQ_TYPE_SENSE_MASK);
		desc->status |= flags;
		if (chip != desc->irq_data.chip)
			irq_chip_set_defaults(desc->irq_data.chip);
	}
	return ret;
}

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

  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);  
int set_irq_chip_data(unsigned int irq, void *data)
{
	struct irq_desc *desc = irq_to_desc(irq);	//获取全局irq_desc数组项
	unsigned long flags;

	if (!desc) {
		printk(KERN_ERR"Trying to install chip data for IRQ%d\n", irq);
		return -EINVAL;
	}
	if (!desc->irq_data.chip) {
		printk(KERN_ERR "BUG: bad set_irq_chip_data(IRQ#%d)\n", irq);
		return -EINVAL;
	}
	raw_spin_lock_irqsave(&desc->lock, flags);
	desc->irq_data.chip_data = data;
	raw_spin_unlock_irqrestore(&desc->lock, flags);
	return 0;
}
EXPORT_SYMBOL(set_irq_chip_data);


6.set_irq_data

  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);  
int set_irq_data(unsigned int irq, void *data)
{
	struct irq_desc *desc = irq_to_desc(irq);	//获取全局irq_desc数组项
	unsigned long flags;

	if (!desc) {
		printk(KERN_ERR"Trying to install controller data for IRQ%d\n", irq);
		return -EINVAL;
	}
	raw_spin_lock_irqsave(&desc->lock, flags);
	desc->irq_data.handler_data = data;
	raw_spin_unlock_irqrestore(&desc->lock, flags);
	return 0;
}
EXPORT_SYMBOL(set_irq_data);

三、中断的申请与释放request_irq

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

  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. }  
static inline int __must_check request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)
{
	return request_threaded_irq(irq, handler, NULL, flags, name, dev);
}

1.1 request_threaded_irq函数

  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);  
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)
{
	struct irqaction *action;
	struct irq_desc *desc;
	int retval;

	if ((irqflags & IRQF_SHARED) && !dev_id)	//共享中断但没指定中断id
		return -EINVAL;
	desc = irq_to_desc(irq);	//获取全局irq_desc数组项
	if (!desc)
		return -EINVAL;
	if (desc->status & IRQ_NOREQUEST)	//中断不能被请求
		return -EINVAL;
	if (!handler) {	//没指定handler
		if (!thread_fn)	//但存在thread_fn
			return -EINVAL;
		handler = irq_default_primary_handler;	//则设置irq_default_primary_handler
	}
	action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);	//分配irqaction内存
	if (!action)
		return -ENOMEM;
	action->handler = handler;	//设置处理句柄
	action->thread_fn = thread_fn;	//设置线程函数NULL
	action->flags = irqflags;	//设置中断标志
	action->name = devname;		//设置设备名
	action->dev_id = dev_id;	//设置设备id
	chip_bus_lock(desc);
	retval = __setup_irq(irq, desc, action);	//-->__setup_irq
	chip_bus_sync_unlock(desc);
	if (retval)
		kfree(action);
#ifdef CONFIG_DEBUG_SHIRQ
	if (!retval && (irqflags & IRQF_SHARED)) {
		unsigned long flags;
		disable_irq(irq);
		local_irq_save(flags);
		handler(irq, dev_id);
		local_irq_restore(flags);
		enable_irq(irq);
	}
#endif
	return retval;
}
EXPORT_SYMBOL(request_threaded_irq);

 

1.2 __setup_irq函数

  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. }  
static int __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
{
	struct irqaction *old, **old_ptr;
	const char *old_name = NULL;
	unsigned long flags;
	int nested, shared = 0;
	int ret;

	if (!desc)
		return -EINVAL;
	if (desc->irq_data.chip == &no_irq_chip)
		return -ENOSYS;
	if (new->flags & IRQF_SAMPLE_RANDOM) {
		rand_initialize_irq(irq);
	}
	if ((new->flags & IRQF_ONESHOT) && (new->flags & IRQF_SHARED))
		return -EINVAL;
	nested = desc->status & IRQ_NESTED_THREAD;	//嵌套标志
	if (nested) {	//嵌套
		if (!new->thread_fn)	//且存在线程处理句柄
			return -EINVAL;
		new->handler = irq_nested_primary_handler;		//嵌套处理的句柄
	}
	if (new->thread_fn && !nested) {	//非嵌套且存在线程函数
		struct task_struct *t;

		t = kthread_create(irq_thread, new, "irq/%d-%s", irq,new->name);	//创建线程
		if (IS_ERR(t))
			return PTR_ERR(t);
		get_task_struct(t);
		new->thread = t;	//设置线程任务结构体
	}
	raw_spin_lock_irqsave(&desc->lock, flags);
	old_ptr = &desc->action;
	old = *old_ptr;
	if (old) {
		if (!((old->flags & new->flags) & IRQF_SHARED) || ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) {
			old_name = old->name;
			goto mismatch;
		}
#if defined(CONFIG_IRQ_PER_CPU)
		if ((old->flags & IRQF_PERCPU) != (new->flags & IRQF_PERCPU))
			goto mismatch;
#endif
		do {
			old_ptr = &old->next;
			old = *old_ptr;
		} while (old);
		shared = 1;	//共享中断标志
	}
	if (!shared) {	//非共享中断
		irq_chip_set_defaults(desc->irq_data.chip);		//设置默认的芯片处理函数
		init_waitqueue_head(&desc->wait_for_threads);
		if (new->flags & IRQF_TRIGGER_MASK) {	//设置触发方式
			ret = __irq_set_trigger(desc, irq,new->flags & IRQF_TRIGGER_MASK);
			if (ret)
				goto out_thread;
		} 
		else
			compat_irq_chip_set_default_handler(desc);
#if defined(CONFIG_IRQ_PER_CPU)
		if (new->flags & IRQF_PERCPU)
			desc->status |= IRQ_PER_CPU;
#endif
		desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | IRQ_ONESHOT |IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);
		if (new->flags & IRQF_ONESHOT)
			desc->status |= IRQ_ONESHOT;
		if (!(desc->status & IRQ_NOAUTOEN)) {
			desc->depth = 0;
			desc->status &= ~IRQ_DISABLED;
			desc->irq_data.chip->irq_startup(&desc->irq_data);
		} 
		else
			desc->depth = 1;
		if (new->flags & IRQF_NOBALANCING)
			desc->status |= IRQ_NO_BALANCING;
		setup_affinity(irq, desc);
	} 
	else if ((new->flags & IRQF_TRIGGER_MASK)&& (new->flags & IRQF_TRIGGER_MASK)!= (desc->status & IRQ_TYPE_SENSE_MASK)) {
		pr_warning("IRQ %d uses trigger mode %d; requested %d\n",
				irq, (int)(desc->status & IRQ_TYPE_SENSE_MASK),(int)(new->flags & IRQF_TRIGGER_MASK));
	}
	new->irq = irq;	//设置中断号
	*old_ptr = new;
	desc->irq_count = 0;
	desc->irqs_unhandled = 0;
	if (shared && (desc->status & IRQ_SPURIOUS_DISABLED)) {	//共享中断
		desc->status &= ~IRQ_SPURIOUS_DISABLED;
		__enable_irq(desc, irq, false);
	}
	raw_spin_unlock_irqrestore(&desc->lock, flags);
	if (new->thread)
		wake_up_process(new->thread);
	register_irq_proc(irq, desc);	//注册proc irq接口
	new->dir = NULL;
	register_handler_proc(irq, new);	//注册proc handler接口
	return 0;
mismatch:
#ifdef CONFIG_DEBUG_SHIRQ
	if (!(new->flags & IRQF_PROBE_SHARED)) {
		printk(KERN_ERR "IRQ handler type mismatch for IRQ %d\n", irq);
		if (old_name)
			printk(KERN_ERR "current handler: %s\n", old_name);
		dump_stack();
	}
#endif
	ret = -EBUSY;
out_thread:
	raw_spin_unlock_irqrestore(&desc->lock, flags);
	if (new->thread) {
		struct task_struct *t = new->thread;
		new->thread = NULL;
		if (likely(!test_bit(IRQTF_DIED, &new->thread_flags)))
			kthread_stop(t);
		put_task_struct(t);
	}
	return ret;
}

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

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

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

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

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

触发方式宏

  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 */  
#define IRQ_TYPE_NONE		0x00000000	/* Default, unspecified type */
#define IRQ_TYPE_EDGE_RISING	0x00000001	//上升沿触发
#define IRQ_TYPE_EDGE_FALLING	0x00000002	//下降沿触发
#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)	//双边沿触发
#define IRQ_TYPE_LEVEL_HIGH	0x00000004	//高电平有效
#define IRQ_TYPE_LEVEL_LOW	0x00000008	//低电平有效
#define IRQ_TYPE_SENSE_MASK	0x0000000f	/* Mask of the above */
#define IRQ_TYPE_PROBE		0x00000010	/* Probing in progress */


然后设计中断函数

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

    ......

    return IRQ_HANDLED;

}

2.释放中断

  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);  
void free_irq(unsigned int irq, void *dev_id)
{
	struct irq_desc *desc = irq_to_desc(irq);	//获取全局irq_desc数组项

	if (!desc)
		return;
	chip_bus_lock(desc);
	kfree(__free_irq(irq, dev_id));
	chip_bus_sync_unlock(desc);
}
EXPORT_SYMBOL(free_irq);

2.1 __free_irq

  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. }  
static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
{
	struct irq_desc *desc = irq_to_desc(irq);	//获取全局irq_desc数组项
	struct irqaction *action, **action_ptr;
	unsigned long flags;

	WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq);
	if (!desc)
		return NULL;
	raw_spin_lock_irqsave(&desc->lock, flags);
	action_ptr = &desc->action;
	for (;;) {
		action = *action_ptr;
		if (!action) {
			WARN(1, "Trying to free already-free IRQ %d\n", irq);
			raw_spin_unlock_irqrestore(&desc->lock, flags);
			return NULL;
		}
		if (action->dev_id == dev_id)	//找到匹配的id项
			break;
		action_ptr = &action->next;
	}
	*action_ptr = action->next;
#ifdef CONFIG_IRQ_RELEASE_METHOD
	if (desc->irq_data.chip->release)
		desc->irq_data.chip->release(irq, dev_id);
#endif
	if (!desc->action) {
		desc->status |= IRQ_DISABLED;
		if (desc->irq_data.chip->irq_shutdown)
			desc->irq_data.chip->irq_shutdown(&desc->irq_data);
		else
			desc->irq_data.chip->irq_disable(&desc->irq_data);
	}
#ifdef CONFIG_SMP
	if (WARN_ON_ONCE(desc->affinity_hint))
		desc->affinity_hint = NULL;
#endif
	raw_spin_unlock_irqrestore(&desc->lock, flags);
	unregister_handler_proc(irq, action);
	synchronize_irq(irq);
#ifdef CONFIG_DEBUG_SHIRQ
	if (action->flags & IRQF_SHARED) {
		local_irq_save(flags);
		action->handler(irq, dev_id);
		local_irq_restore(flags);
	}
#endif
	if (action->thread) {
		if (!test_bit(IRQTF_DIED, &action->thread_flags))
			kthread_stop(action->thread);
		put_task_struct(action->thread);
	}
	return action;
}


 

四、中断处理过程

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

  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:  
	.globl	__vectors_start
__vectors_start:
 ARM(	swi	SYS_ERROR0	)	/* swi指令 */
 THUMB(	svc	#0		)
 THUMB(	nop			)
	W(b)	vector_und + stubs_offset
	W(ldr)	pc, .LCvswi + stubs_offset
	W(b)	vector_pabt + stubs_offset
	W(b)	vector_dabt + stubs_offset
	W(b)	vector_addrexcptn + stubs_offset
	W(b)	vector_irq + stubs_offset	/* 中断向量表 */
	W(b)	vector_fiq + stubs_offset
	.globl	__vectors_end
__vectors_end:

2.vector_irq的定义声明

  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  
	.globl	__stubs_start
__stubs_start:
/*
 * Interrupt dispatcher
 */
	vector_stub irq, IRQ_MODE, 4	/*参看下面vector_stub宏的定义*/

	.long	__irq_usr			@  0  (USR_26 / USR_32)		/*usr模式下中断处理(见下面)*/
	.long	__irq_invalid		@  1  (FIQ_26 / FIQ_32)
	.long	__irq_invalid		@  2  (IRQ_26 / IRQ_32)
	.long	__irq_svc			@  3  (SVC_26 / SVC_32)		/*svc模式下中断处理(见下面)*/
	.long	__irq_invalid		@  4
	.long	__irq_invalid		@  5
	.long	__irq_invalid		@  6
	.long	__irq_invalid		@  7
	.long	__irq_invalid		@  8
	.long	__irq_invalid		@  9
	.long	__irq_invalid		@  a
	.long	__irq_invalid		@  b
	.long	__irq_invalid		@  c
	.long	__irq_invalid		@  d
	.long	__irq_invalid		@  e
	.long	__irq_invalid		@  f

3.vector_stub宏的定义

  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_stub irq, IRQ_MODE, 4*/
	.macro	vector_stub, name, mode, correction=0	
	.align	5

vector_\name:						/*构造了vector_irq*/
	.if \correction					/*if 4*/
	sub	lr, lr, #\correction
	.endif

	@ 
	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
	@ (parent CPSR)
	@
	stmia	sp, {r0, lr}		@ save r0, lr
	mrs	lr, spsr
	str	lr, [sp, #8]		@ save spsr

	@
	@ Prepare for SVC32 mode.  IRQs remain disabled.	准备切到svc模式
	@
	mrs	r0, cpsr
	eor	r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
	msr	spsr_cxsf, r0

	@ /*分支表必须紧接着这段代码*/
	@ the branch table must immediately follow this code
	@
	and	lr, lr, #0x0f
 THUMB(	adr	r0, 1f			)
 THUMB(	ldr	lr, [r0, lr, lsl #2]	)
	mov	r0, sp
 ARM(	ldr	lr, [pc, lr, lsl #2]	)
	movs	pc, lr			@ branch to handler in SVC mode	跳到分支表处
ENDPROC(vector_\name)

	.align	2
	@ handler addresses follow this label
1:
	.endm

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

4.__irq_usr

  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)  
__irq_usr:
		usr_entry
		kuser_cmpxchg_check
	
		get_thread_info tsk
#ifdef CONFIG_PREEMPT
		ldr r8, [tsk, #TI_PREEMPT]		@ get preempt count
		add r7, r8, #1			@ increment it
		str r7, [tsk, #TI_PREEMPT]
#endif
	
		irq_handler		/*跳转到irq_handler处理*/
#ifdef CONFIG_PREEMPT
		ldr r0, [tsk, #TI_PREEMPT]
		str r8, [tsk, #TI_PREEMPT]
		teq r0, r7
	 ARM(	strne	r0, [r0, -r0]	)
	 THUMB( movne	r0, #0		)
	 THUMB( strne	r0, [r0]	)
#endif
	
		mov why, #0
		b	ret_to_user
	 UNWIND(.fnend		)
	ENDPROC(__irq_usr)


5.__irq_svc

  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)  
__irq_svc:
		svc_entry
	
#ifdef CONFIG_TRACE_IRQFLAGS
		bl	trace_hardirqs_off
#endif
#ifdef CONFIG_PREEMPT
		get_thread_info tsk
		ldr r8, [tsk, #TI_PREEMPT]		@ get preempt count
		add r7, r8, #1			@ increment it
		str r7, [tsk, #TI_PREEMPT]
#endif
	
		irq_handler			/*跳转到irq_handler处理*/
#ifdef CONFIG_PREEMPT
		str r8, [tsk, #TI_PREEMPT]		@ restore preempt count
		ldr r0, [tsk, #TI_FLAGS]		@ get flags
		teq r8, #0				@ if preempt count != 0
		movne	r0, #0				@ force flags to 0
		tst r0, #_TIF_NEED_RESCHED
		blne	svc_preempt
#endif
		ldr r4, [sp, #S_PSR]		@ irqs are already disabled
#ifdef CONFIG_TRACE_IRQFLAGS
		tst r4, #PSR_I_BIT
		bleq	trace_hardirqs_on
#endif
		svc_exit r4 			@ return from exception
	 UNWIND(.fnend		)
	ENDPROC(__irq_svc)


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

  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  
	.macro	irq_handler
	get_irqnr_preamble r5, lr
1:	get_irqnr_and_base r0, r6, r5, lr
	movne	r1, sp
	@ r0保存了中断号,r1保存了保留现场的寄存器指针
	@ routine called with r0 = irq number, r1 = struct pt_regs *
	@
	adrne	lr, BSYM(1b)
	bne	asm_do_IRQ	/*********************跳转到asm_do_IRQ函数处理*/

#ifdef CONFIG_SMP
	/*
	 * XXX
	 *
	 * this macro assumes that irqstat (r6) and base (r5) are
	 * preserved from get_irqnr_and_base above
	 */
	ALT_SMP(test_for_ipi r0, r6, r5, lr)
	ALT_UP_B(9997f)
	movne	r0, sp
	adrne	lr, BSYM(1b)
	bne	do_IPI

#ifdef CONFIG_LOCAL_TIMERS
	test_for_ltirq r0, r6, r5, lr
	movne	r0, sp
	adrne	lr, BSYM(1b)
	bne	do_local_timer
#endif
9997:
#endif

	.endm


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

  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. }  
asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
	struct pt_regs *old_regs = set_irq_regs(regs);

	irq_enter();

	/*
	 * Some hardware gives randomly wrong interrupts.  Rather
	 * than crashing, do something sensible.
	 */
	if (unlikely(irq >= nr_irqs)) {	//中断号大于中断的个数
		if (printk_ratelimit())
			printk(KERN_WARNING "Bad IRQ%u\n", irq);
		ack_bad_irq(irq);
	} 
	else {
		generic_handle_irq(irq);	//通用中断处理函数
	}

	/* AT91 specific workaround */
	irq_finish(irq);

	irq_exit();
	set_irq_regs(old_regs);
}

8.generic_handle_irq函数

  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. }  
static inline void generic_handle_irq(unsigned int irq)
{
	generic_handle_irq_desc(irq, irq_to_desc(irq));	//调用了irq_to_desc获取全局irq_desc[irq]项
}

9.generic_handle_irq_desc函数

  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. }  
static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
{
#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ	//根据板级配置的设置若定义了
	desc->handle_irq(irq, desc);	//则只能用指定的handle_irq方法
#else
	if (likely(desc->handle_irq))	//若中断处理函数存在
		desc->handle_irq(irq, desc);	//则调用注册的中断处理函数(irq_desc[irq]->handle_irq(irq,desc))
	else
		__do_IRQ(irq);	//没指定中断处理函数的处理分支
#endif
}

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

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

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

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

10.__do_IRQ函数

  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. }  
unsigned int __do_IRQ(unsigned int irq)
{
	struct irq_desc *desc = irq_to_desc(irq);
	struct irqaction *action;
	unsigned int status;

	kstat_incr_irqs_this_cpu(irq, desc);
	if (CHECK_IRQ_PER_CPU(desc->status)) {
		irqreturn_t action_ret;
		if (desc->irq_data.chip->ack)
			desc->irq_data.chip->ack(irq);
		if (likely(!(desc->status & IRQ_DISABLED))) {
			action_ret = handle_IRQ_event(irq, desc->action);//调用handle_IRQ_event函数
			if (!noirqdebug)
				note_interrupt(irq, desc, action_ret);
		}
		desc->irq_data.chip->end(irq);
		return 1;
	}
	raw_spin_lock(&desc->lock);
	if (desc->irq_data.chip->ack)
		desc->irq_data.chip->ack(irq);
	status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
	status |= IRQ_PENDING; /* we _want_ to handle it */
	action = NULL;
	if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {
		action = desc->action;
		status &= ~IRQ_PENDING; /* we commit to handling */
		status |= IRQ_INPROGRESS; /* we are handling it */
	}
	desc->status = status;
	if (unlikely(!action))
		goto out;
	for (;;) {
		irqreturn_t action_ret;
		raw_spin_unlock(&desc->lock);
		action_ret = handle_IRQ_event(irq, action);//调用handle_IRQ_event函数
		if (!noirqdebug)
			note_interrupt(irq, desc, action_ret);
		raw_spin_lock(&desc->lock);
		if (likely(!(desc->status & IRQ_PENDING)))
			break;
		desc->status &= ~IRQ_PENDING;
	}
	desc->status &= ~IRQ_INPROGRESS;
out:
	desc->irq_data.chip->end(irq);
	raw_spin_unlock(&desc->lock);
	return 1;
}

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

11.handle_IRQ_event函数

  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. }  
irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
	irqreturn_t ret, retval = IRQ_NONE;
	unsigned int status = 0;

	do {
		trace_irq_handler_entry(irq, action);
		ret = action->handler(irq, action->dev_id);//调用了irqaction的handler方法
		trace_irq_handler_exit(irq, action, ret);
		switch (ret) {
		case IRQ_WAKE_THREAD:
			ret = IRQ_HANDLED;
			if (unlikely(!action->thread_fn)) {
				warn_no_thread(irq, action);
				break;
			}
			if (likely(!test_bit(IRQTF_DIED,
					     &action->thread_flags))) {
				set_bit(IRQTF_RUNTHREAD, &action->thread_flags);
				wake_up_process(action->thread);
			}
		case IRQ_HANDLED:
			status |= action->flags;
			break;

		default:
			break;
		}
		retval |= ret;
		action = action->next;
	} while (action);

	if (status & IRQF_SAMPLE_RANDOM)
		add_interrupt_randomness(irq);
	local_irq_disable();
	return retval;
}

这里调用的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个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值