// 参考:http://www.bluezd.info/archives/reg_clock_event_device_1 // x86平台初始化 // 注:arch/x86/kernel/x86_init.c 1.1 struct x86_init_ops x86_init __initdata = { ... //apic控制器初始化 .irqs = { .pre_vector_init = init_ISA_irqs, .intr_init = native_init_IRQ, .trap_init = x86_init_noop, }, ... }; // 中断初始化 // 调用路径:start_kernel->init_IRQ 1.2 void __init init_IRQ(void) { //中断初始化 ... x86_init.irqs.intr_init(); } // x86体系结构中断初始化 // 函数任务: // 1.初始化isa 0~15号中断 // 2.初始化apic中断 1.3 void __init native_init_IRQ(void) { int i; //初始化isa 0~15号中断 x86_init.irqs.pre_vector_init(); //初始化apic中断 apic_intr_init(); ... } // apic中断初始化 // 函数任务: // 1.smp 中断初始化 // 2.lapic时钟中断初始化 // 3.x86平台专用ipi // 4.其他 1.4 static void __init apic_intr_init(void) { //smp 中断初始化 smp_intr_init(); ... #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) //lapic时钟中断初始化 alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); //x86平台专用ipi alloc_intr_gate(X86_PLATFORM_IPI_VECTOR, x86_platform_ipi); ... #endif } // smp ipi中断初始化 // 函数任务: // 1.cpu间重调度ipi // 2.cpu间函数调用ipi // 3.系统关机,重启ipi // 4.其他 1.5 static void __init smp_intr_init(void) { #ifdef CONFIG_SMP #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) //cpu间重调度ipi,由wake_up驱动 alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); //cpu间函数调用ipi,通知其他cpu在中断上下文执行某函数 alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); alloc_intr_gate(CALL_FUNCTION_SINGLE_VECTOR, call_function_single_interrupt); //系统关机,重启ipi alloc_intr_gate(REBOOT_VECTOR, reboot_interrupt); #endif #endif } // lapic时钟中断 // 注:#define LOCAL_TIMER_VECTOR 0xef 1.6 void __irq_entry smp_apic_timer_interrupt(struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); //ack irq ack_APIC_irq(); //如果本cpu上运行idle进程,退出idle状态 exit_idle(); irq_enter(); //lapic的时钟处理函数 local_apic_timer_interrupt(); irq_exit(); set_irq_regs(old_regs); } // lapic时钟中断处理程序 // 函数任务: // 1.检查是否为错误的中断信号 // 1.1 lapic中断比lapic时钟源先使能,因此产生中断时, // 可能相应的事件处理函数还没有建立,此时,关闭时钟源,退出处理 // 2.统计apic中断次数 // 3.执行apic事件处理函数 1.7 static void local_apic_timer_interrupt(void) { int cpu = smp_processor_id(); //lapic per-cpu clockevent 设备 struct clock_event_device *evt = &per_cpu(lapic_events, cpu); //lapic中断比lapic时钟源先使能,因此产生中断时,可能相应的事件处理函数还没有建立 if (!evt->event_handler) { //错误的中断信号,关闭时钟源 pr_warning("Spurious LAPIC timer interrupt on cpu %d\n", cpu); lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt); return; } //apic中断统计 inc_irq_stat(apic_timer_irqs); //执行apic事件处理函数 evt->event_handler(evt); } // 创建lapic时钟源 // 函数任务: // 1.设置lapic服务当前cpu // 2.注册lapic设备 2.1 static void __cpuinit setup_APIC_timer(void) { //本cpu的lapic struct clock_event_device *levt = &__get_cpu_var(lapic_events); //lapic受省电模式C3的影响 if (cpu_has(¤t_cpu_data, X86_FEATURE_ARAT)) { lapic_clockevent.features &= ~CLOCK_EVT_FEAT_C3STOP; lapic_clockevent.rating = 150; } //lapic_clockevent作为所有lapic clockevent模板 memcpy(levt, &lapic_clockevent, sizeof(*levt)); //lapic服务的cpu levt->cpumask = cpumask_of(smp_processor_id()); //注册lapic设备 clockevents_register_device(levt); } // lapic clockevent设备 // 注:lapic在注册时,默认关闭状态 2.1 static struct clock_event_device lapic_clockevent = { .name = "lapic", .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY, .shift = 32, .set_mode = lapic_timer_setup, .set_next_event = lapic_next_event, .broadcast = lapic_timer_broadcast, .rating = 100, .irq = -1, };
时间: 2024-11-30 17:41:06