閱讀253 返回首頁    go 技術社區[雲棲]


時間子係統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

  上一篇:go 演講金口才培訓總結
  下一篇:go 【轉】ubuntu修改主機名