标签:class 调用顺序 数组声明 屏蔽 clu current ip) method use
1.中断处理体系结构
Linux内核将所有中断统一编号,使用一个irq_desc结构数组来描述这些中断。
数组声明在/linux/kernel/irq/handle.c中,其中#define NR_IRQS 128,定义在/linux/include/asm/irq.h中
1 /* 2 * Linux has a controller-independent interrupt architecture. 3 * Every controller has a ‘controller-template‘, that is used 4 * by the main code to do the right thing. Each driver-visible 5 * interrupt source is transparently wired to the appropriate 6 * controller. Thus drivers need not be aware of the 7 * interrupt-controller. 8 * 9 * The code is designed to be easily extended with new/different 10 * interrupt controllers, without having to do assembly magic or 11 * having to touch the generic code. 12 * 13 * Controller mappings for all interrupt sources: 14 */ 15 struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = { 16 [0 ... NR_IRQS-1] = { 17 .status = IRQ_DISABLED, 18 .chip = &no_irq_chip, 19 .handle_irq = handle_bad_irq, 20 .depth = 1, 21 .lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock), 22 #ifdef CONFIG_SMP 23 .affinity = CPU_MASK_ALL 24 #endif 25 } 26 };
1 struct irq_desc { 2 irq_flow_handler_t handle_irq; 3 struct irq_chip *chip; 4 struct msi_desc *msi_desc; 5 void *handler_data; 6 void *chip_data; 7 struct irqaction *action; /* IRQ action list */ 8 unsigned int status; /* IRQ status */ 9 10 unsigned int depth; /* nested irq disables */ 11 unsigned int wake_depth; /* nested wake enables */ 12 unsigned int irq_count; /* For detecting broken IRQs */ 13 unsigned int irqs_unhandled; 14 spinlock_t lock; 15 #ifdef CONFIG_SMP 16 cpumask_t affinity; 17 unsigned int cpu; 18 #endif 19 #if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE) 20 cpumask_t pending_mask; 21 #endif 22 #ifdef CONFIG_PROC_FS 23 struct proc_dir_entry *dir; 24 #endif 25 const char *name; 26 } ____cacheline_internodealigned_in_smp;
handle_irq是这个或这组中断的处理函数入口。发生中断时,总入口函数asm_do_IRQ将根据中断号调用相应irq_desc数组项中handle_irq.
typedef void fastcall (*irq_flow_handler_t)(unsigned int irq, struct irq_desc *desc);
handle_irq使用chip结构中的函数清除、屏蔽或者重新使能中断,还要调用用户在action链表中注册的中断处理函数。irq_chip结构类型也是在include/linux/irq.h中定义,其中的成员大多用于操作底层硬件,比如设置寄存器以屏蔽中断,使能中断,清除中断等。注意这里的成员name会出现在/proc/interrupts中。
struct irq_chip { const char *name; 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); void (*set_affinity)(unsigned int irq, cpumask_t 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); /* Currently used only by UML, might disappear one day.*/ #ifdef CONFIG_IRQ_RELEASE_METHOD void (*release)(unsigned int irq, void *dev_id); #endif /* * For compatibility, ->typename is copied into ->name. * Will disappear. */ const char *typename; };
irq_desc结构中的irqaction结构类型在include/linux/iterrupt.h中定义。用户注册的每个中断处理函数用一个irqaction结构来表示,一个中断比如共享中断可以有多个处理函数,它们的irqaction结构链接成一个链表,以action为表头。irqation结构在linux/include/linux/interrupt.h中定义如下:
typedef irqreturn_t (*irq_handler_t)(int, void *); struct irqaction { irq_handler_t handler; unsigned long flags; cpumask_t mask; const char *name; void *dev_id; struct irqaction *next; int irq; struct proc_dir_entry *dir; };
irq_desc结构数组、它的成员“struct irq_chip *chip” "struct irqaction *action",这3种数据结构构成了中断处理体系的框架。下图中描述了Linxu中断处理体系结构的关系图:
void __init init_IRQ(void) { int irq; for (irq = 0; irq < NR_IRQS; irq++) irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE; #ifdef CONFIG_SMP bad_irq_desc.affinity = CPU_MASK_ALL; bad_irq_desc.cpu = smp_processor_id(); #endif init_arch_irq(); }
下面简单分析下init_arch_irq();的获取过程及调用顺序
1 /* 2 init_arch_irq()的由来 3 定义一个空函数指针void (*init_arch_irq)(void) __initdata = NULL; 4 */ 5 asmlinkage void __init start_kernel(void) 6 -->setup_arch(&command_line); 7 -->init_arch_irq = mdesc->init_irq; 8 -->init_IRQ(); 9 -->init_arch_irq()//即mdesc->init_irq=s3c24xx_init_irq
上述machine_desc结构在/linux/arch/arm/mach-s3c2410/mach-bast.c如下宏中获得,后面会分析machine_desc结构。
MACHINE_START(BAST, "Simtec-BAST") //Maintainer: Ben Dooks <ben@simtec.co.uk> .phys_io = S3C2410_PA_UART, .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, .boot_params = S3C2410_SDRAM_PA + 0x100, .map_io = bast_map_io, .init_irq = s3c24xx_init_irq, .init_machine = bast_init, .timer = &s3c24xx_timer, MACHINE_END
对于S3C2440开发板,这个函数就是s3c24xx_init_irq,移植machine_desc结构中的init_irq成员就指向这个函数s3c24xx_init_irq函数在arch/arm/plat-s3c24xx/irq.c中定义,它为所有中断设置了芯片相关的数据结构(irq_desc[irq].chip),设置了处理函数入口(irq_desc[irq].handle_irq)。
标签:class 调用顺序 数组声明 屏蔽 clu current ip) method use
原文地址:http://www.cnblogs.com/yangjiguang/p/7631539.html