- 论坛徽章:
- 0
|
/*
*By Neil Chiao (
neilchiao at gmail.com
)
*转载请注明出处:
neilengineer.cublog.cn
*/
在上次《Linux设备驱动简析--内核中的时间》一文中介绍了jiffies。
Jiffies是Linux内核中的时间单位,也就是内核计数器。每次时钟中断发生时,内核计数器(Jiffies)的值加1,这个值就是系统时钟的滴答数。
时钟中断由定时硬件以周期性的间隔产生,这个间隔由HZ值设定。ARM平台上默认的HZ值是100。
一、时钟驱动初始化调用机制
start_kernelà
asmlinkage void __init start_kernel(void)
{
……
setup_arch(&command_line);
……
time_init();
……
}
setup_archà
void __init setup_arch(char **cmdline_p)
{
……
init_arch_irq = mdesc->init_irq;
system_timer = mdesc->timer;
init_machine = mdesc->init_machine;
……
}
上述代码中mdesc->timer又是什么地方初始化呢?请继续阅读。
mdesc是 struct machine_desc结构体的指针,其初始化在setup_arch函数中:
mdesc = setup_machine(machine_arch_type);
上述代码在.arch.info段中寻找当前平台,找到后返回其所在位置(指针)。而指针所在地址之后的地址中保存的平台相关信息,如函数指针地址等在MACHINE_START宏中初始化,如xxx平台:
arch/arm/mach-xxx/xxx.c:
MACHINE_START(xxxx, "xxxx")
……
.timer = &xxx_timer,
……
MACHINE_END
MACHINE_START宏的定义:
#define MACHINE_START(_type,_name) \
const struct machine_desc __mach_desc_##_type \
__attribute__((__section__(".arch.info"))) = { \
.nr = MACH_TYPE_##_type, \
.name = _name,
简单地说,MACHINE_START宏把相关信息在LD时,放在了.arch.info段中。
而上述的xxx_timer结构定义一般如下:
struct sys_timer xxx_timer = {
.init =xxx_timer_init,
.offset = xxx_gettimeoffset,
};
xxx_timer_init函数中初始化并使能硬件时钟,注册中断处理函数等。
上述代码完成了system_timer的初始化,而实际的调用在time_init函数中:
start_kernelà
asmlinkage void __init start_kernel(void)
{
……
time_init();
……
}
二、时钟驱动简析
这里不此具体的驱动为例,说个大概吧。时钟驱动一般都会有如下的结构:
1、arch/arm/mach-xxx/xxx.c:
MACHINE_START(xxxx, "xxxx")
……
.timer = &xxx_timer,
……
MACHINE_END
2、xxx_timer的结构定义:
struct sys_timer xxx_timer = {
.init =xxx_timer_init,
.offset = xxx_gettimeoffset,
};
3、xxx_timer_init的实现
1)初始化timer的硬件,设置相关寄存器的值(包括时钟中断使能)
2)用类似setup_irq(IRQ_TIMERINT, &xxx_timer_irq);来注册时钟中断,其中xxx_timer_irq就是时钟中断发生时调用的ISR
4、中断处理函数xxx_timer_irq的实现
一般主要做下面几件事 :
1)write_seqlock(&xtime_lock);
2)清中断
3)timer_tick(regs);
4)write_sequnlock(&xtime_lock);
注意:好像从2.6.22开始,内核中的时钟相关机制有大的改变,有空的时候研究下。
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/91522/showart_1906446.html |
|