時間子係統1_lapic時鍾初始化
// 參考:https://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,
};
最後更新:2017-04-03 14:54:27