时间子系统10_hpet时钟初始化

来源:互联网 发布:产品经理设计软件 编辑:程序博客网 时间:2024/05/18 02:08
//时钟mult :mult/2^shift = ns/cyc //参考:http://www.bluezd.info/archives/reg_clock_event_device_1//x86平台初始化//注:arch/x86/kernel/x86_init.c1.1 struct x86_init_ops x86_init __initdata = {...//时钟初始化.timers = {.setup_percpu_clockev= setup_boot_APIC_clock,.tsc_pre_init= x86_init_noop,.timer_init= hpet_time_init,},...};//时钟初始化//函数任务://1.初始化hpet时钟源,时钟事件设备//2.初始化tsc时钟源//调用路径start_kernel->time_init1.1 void __init time_init(void){//初始化hpet时钟源x86_init.timers.timer_init();tsc_init();}//初始化hpet//函数任务://1.注册hpet clocksource,hpet clockevent//2.注册时钟中断处理程序//调用路径:time_init->hpet_time_init2.1 void __init hpet_time_init(void){//注册hpet clocksource,hpet clockeventif (!hpet_enable())setup_pit_timer();//分配时钟中断setup_default_timer_irq();}//注册hpet时钟源//调用路径:hpet_time_init->hpet_enable->hpet_clocksource_register//函数任务://1.初始化hpet clocksource硬件设备//2.检查hpet计数器是否正常工作//2.1 等待200000 tsc,判断hpet计数是否变化//3.计算hpet mult值//4.向系统注册hpet时钟源2.2 static int hpet_clocksource_register(void){u64 start, now;cycle_t t1;//初始化hpet clocksource硬件设备hpet_restart_counter();//检测hpet计数器是否工作t1 = hpet_readl(HPET_COUNTER);rdtscll(start);//检测办法//200000tsc之后,判断hpet计数器是否发生变化do {rep_nop();rdtscll(now);} while ((now - start) < 200000UL);if (t1 == hpet_readl(HPET_COUNTER)) {printk(KERN_WARNING       "HPET counter not counting. HPET disabled\n");return -ENODEV;}//计算hpet clocksource的shift值clocksource_hpet.mult = div_sc(hpet_period, FSEC_PER_NSEC, HPET_SHIFT);//注册hpet时钟源clocksource_register(&clocksource_hpet);return 0;}//hpet时钟源2.3 static struct clocksource clocksource_hpet = {.name= "hpet",.rating= 250,//精度排名.read= read_hpet,.mask= HPET_MASK,.shift= HPET_SHIFT,.flags= CLOCK_SOURCE_IS_CONTINUOUS,//连续时钟源.resume= hpet_resume_counter,};//注册hpet 时钟事件设备//调用路径:hpet_time_init->hpet_enable->hpet_legacy_clockevent_register//函数任务://1.hpet clockevent硬件初始化//2.计算hpet mult//3.计算hpet cpu掩码//3.1 IO_APIC初始化完成后,设置hpet对所有cpu可用//4.计算hpet clockevent设备可重新编程的最大、最小时间间隔//5.设置hpet clockevent设备为全局事件设备//注://hpet clockevent存在可重新编程的上下时间间隔3.1 static void hpet_legacy_clockevent_register(void){//hpet clockevent硬件初始化hpet_enable_legacy_int();//计算hpet clockevent的multhpet_clockevent.mult = div_sc((unsigned long) FSEC_PER_NSEC,      hpet_period, hpet_clockevent.shift);//最大时间间隔hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,   &hpet_clockevent);//重新编程的最小时间间隔5ushpet_clockevent.min_delta_ns = 5000;//当io-apic初始化完成后,才会使hpet 服务于所有cpuhpet_clockevent.cpumask = cpumask_of(smp_processor_id());//注册hpet clockeventclockevents_register_device(&hpet_clockevent);//hpet作为全局时钟事件设备global_clock_event = &hpet_clockevent;}//hpet clockevent设备3.2 static struct clock_event_device hpet_clockevent = {.name= "hpet",.features= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,//支持周期和单触发模式.set_mode= hpet_legacy_set_mode,.set_next_event = hpet_legacy_next_event,//设置事件将要发生的时间.shift= 32,.irq= 0,//使用0号irq.rating= 50,};//时钟中断控制块4.1 static struct irqaction irq0  = {.handler = timer_interrupt,.flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,.name = "timer"};//设置时钟中断处理程序//调用路径:hpet_time_init->setup_default_timer_irq4.2 void __init setup_default_timer_irq(void){setup_irq(0, &irq0);}//时钟中断处理程序//函数任务://1.向中断控制器应答//2.通知全局时钟事件设备处理时间到期4.3 static irqreturn_t timer_interrupt(int irq, void *dev_id){//向中断控制器应答时钟中断if (timer_ack) {raw_spin_lock(&i8259A_lock);outb(0x0c, PIC_MASTER_OCW3);/* Ack the IRQ; AEOI will end it automatically. */inb(PIC_MASTER_POLL);raw_spin_unlock(&i8259A_lock);}//全局时钟源设备的时间处理函数global_clock_event->event_handler(global_clock_event);if (MCA_bus)outb_p(inb_p(0x61)| 0x80, 0x61);return IRQ_HANDLED;}
原创粉丝点击