Chinaunix首页 | 论坛 | 博客
  • 博客访问: 492562
  • 博文数量: 52
  • 博客积分: 5017
  • 博客等级: 大校
  • 技术积分: 707
  • 用 户 组: 普通用户
  • 注册时间: 2008-01-20 11:34
文章分类
文章存档

2011年(1)

2008年(51)

我的朋友

分类: LINUX

2008-07-05 18:01:19

Kernel硬件中断的初始化流程
 
Porting kernel到一个全新的开发板时,通常hardware irq的初始化函数是要我们自己实现的。
那我们实现了自己硬件的中断初始化函数之后,内核是如何调用到它的呢?内核有自己的一套支持多平台的架构。

下面我们分析内核中断初始化的过程以及如何调用到一个新平台的irq初始化函数。
这里我们以s3c2410平台为例,他的中断初始化函数定义在:
/* arch/arm/mach-s3c2410/irq.c */
void __init s3c24xx_init_irq(void)
{
……
}
 
在arch/arm/mach-s3c2410/mach-smdk2410.c内通过MACHINE_START宏将s3c24xx_init_irq赋值给mach_desc结构体的.init_irq成员。
 

MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
        * to SMDK2410 */

 /* Maintainer: Jonas Dietsche */
 .phys_io = S3C2410_PA_UART,
 .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 .boot_params = S3C2410_SDRAM_PA + 0x100,
 .map_io = smdk2410_map_io,
 .init_irq = s3c24xx_init_irq,
 .init_machine = smdk_machine_init,
 .timer = &s3c24xx_timer,
MACHINE_END


注:MACHINE_START宏的作用是对mach_desc结构体进行初始化。mach_desc里定义了一些关键的体系架构相关的函数。Porting kernel到新平台时,这个结构体是非常关键的。
 
init_irq这个成员在系统初始化的时候会被赋值给init_arch_irq全局变量,如下:

/* arch/arm/kernel/setup.c */
void __init setup_arch(char **cmdline_p)
{
 ……
 cpu_init();
 
/*
  * Set up various architecture-specific pointers
  */

 init_arch_irq = mdesc->init_irq;
 system_timer = mdesc->timer;
 init_machine = mdesc->init_machine;
 ……
}


注:可以看到这里不仅初始化了init_arch_irq 全局变量,同时初始化了system_timer,init_machine等全局变量。这是kernel支持多平台的一种机制。当然这里system_timer和init_machine我不多描述,有兴趣的可以大家自己去看。机制和init_arch_irq大同小异。
 
init_arch_irq函数指针定义在体系架构无关的arch/arm/kernel/irq.c内
/* arch/arm/kernel/irq.c */
void (*init_arch_irq)(void) __initdata = NULL;
 
并且在init_IRQ函数内会去执行它。

/* arch/arm/kernel/irq.c */
void __init init_IRQ(void)
{
 int irq;
 for (irq = 0; irq < NR_IRQS; irq++)
  irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_DELAYED_DISABLE |
   IRQ_NOPROBE;
#ifdef CONFIG_SMP
 bad_irq_desc.affinity = CPU_MASK_ALL;
 bad_irq_desc.cpu = smp_processor_id();
#endif
 init_arch_irq();
}

 
那init_IRQ在哪里被调用呢? 我们猜想肯定是在系统初始化的时会调用它。
实际结果也正是,init_IRQ会在init/main.c里的start_kernel函数内被调用:
asmlinkage void __init start_kernel(void)
{
 ……
 trap_init();
 rcu_init();
 init_IRQ();
 pidhash_init();
 clockevents_init();
 init_timers();
 ……
}
这样,我们定义的新平台irq初始化函数就会在系统启动时被调用,对我们的硬件中断进行初始化后再去使用它。这里搞清楚了,再porting其他东西如GP Timer Driver等到新平台就变得清晰多了。
阅读(3077) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~