// 参考: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,
};