閱讀211 返回首頁    go 阿裏雲 go 技術社區[雲棲]


時間子係統11_tsc時鍾初始化

//	tsc時鍾源初始化
//	調用路徑:time_init->tsc_init
//	函數任務:
//		1.矯正tsc,獲取tsc頻率,設置cpu頻率等於tsc頻率
//		2.初始化基於tsc的延遲函數
//		3.檢查tsc的特性
//			3.1 tsc之間是否同步
//				3.1.1 如果tsc之間不同步,標記tsc不穩定,設置rating=0
//			3.2 tsc是否穩定
//		4.注冊tsc時鍾源設備
1.1 void __init tsc_init(void)
{
	u64 lpj;
	int cpu;

	//矯正tsc,獲取tsc頻率
	tsc_khz = x86_platform.calibrate_tsc();
	//cpu頻率等於tsc頻率
	cpu_khz = tsc_khz;
	//計算輔助cycle到ns轉換的輔助參數scale
	for_each_possible_cpu(cpu)
		set_cyc2ns_scale(cpu_khz, cpu);
	//初始化基於tsc的延遲函數,ndely,udelay,mdelay
	use_tsc_delay();
	//檢查cpu之間tsc是否同步
	if (unsynchronized_tsc())
		mark_tsc_unstable("TSCs unsynchronized");
	//檢查tsc是否可靠
	check_system_tsc_reliable();
	//注冊tsc時鍾源設備
	init_tsc_clocksource();
}

//	延遲函數ndelay,udelay,mdelay
//		通過tsc實現短延遲
2.1 void use_tsc_delay(void)
{
	//通過tsc進行短延遲
	delay_fn = delay_tsc;
}
//	tsc延遲函數
//		通過rep_nop實現輪詢時的短延遲,查詢tsc時禁止內核搶占,確保不受不同cpu間影響。
2.2 static void delay_tsc(unsigned long loops)
{
	unsigned long bclock, now;
	int cpu;
	//短延遲,禁止內核搶占
	preempt_disable();
	//delay_tsc當前運行的cpu
	cpu = smp_processor_id();
	rdtsc_barrier();
	rdtscl(bclock);
	for (;;) {
		rdtsc_barrier();
		rdtscl(now);
		if ((now - bclock) >= loops)
			break;
		//允許rt策略進程運行
		preempt_enable();
		//空操作
		rep_nop();
		preempt_disable();

		//delay_tsc在運行過程中,可能會遷移到不同的cpu
		//tsc
		if (unlikely(cpu != smp_processor_id())) {
			loops -= (now - bclock);
			cpu = smp_processor_id();
			rdtsc_barrier();
			rdtscl(bclock);
		}
	}
	preempt_enable();
} 

//	檢查tsc是否同步
//	調用路徑:tsc_init->unsynchronized_tsc
//	檢查辦法:
//		1.如果apic在多塊板卡,則tsc不同步
//		2.如果cpuid顯示具有穩定的tsc,則tsc同步
//		3.intel cpu的tsc都是同步的
//		4.默認其他品牌的多核的tsc不同步
3.1 __cpuinit int unsynchronized_tsc(void)
{
	//如果apic分布在多塊板卡上,tsc可能不同步
	if (apic_is_clustered_box())
		return 1;
	//cpu具有穩定的tsc
	if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
		return 0;
	//intel cpu的tsc都是同步的
	if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) {
		//非intel cpu,如果cpu個數>1,則認為不同步
		if (num_possible_cpus() > 1)
			tsc_unstable = 1;
	}
	return tsc_unstable;
}

//	標記tsc不穩定
//	調用路徑:tsc_init->mark_tsc_unstable
//	函數任務:
//		1.如果tsc時鍾已經注冊,異步設置tsc的rating=0,標識其不穩定
//		2.如果tsc時鍾還未注冊,同步設置tsc的rating=0,標識其不穩定
3.2 void mark_tsc_unstable(char *reason)
{
	if (!tsc_unstable) {
		tsc_unstable = 1;
		sched_clock_stable = 0;
		//tsc已經注冊,
		if (clocksource_tsc.mult)
		{
			clocksource_mark_unstable(&clocksource_tsc);
		}
		//如果tsc時鍾源未注冊,修改rating為最低,從而不會被當做最佳的時鍾源
		else {
			clocksource_tsc.flags |= CLOCK_SOURCE_UNSTABLE;
			clocksource_tsc.rating = 0;
		}
	}
}



//	注冊tsc時鍾源
//	函數任務:
//		1.計算tsc的mult
//		2.檢查tsc是否穩定
//			2.1 如果tsc不穩定,降低其rating,清除時鍾源連續標誌
//		3.向係統注冊tsc clocksource
//	調用路徑:tsc_init->init_tsc_clocksource
4.1 static void __init init_tsc_clocksource(void)
{
	//計算tsc的mult
	clocksource_tsc.mult = clocksource_khz2mult(tsc_khz,
			clocksource_tsc.shift);
	//如果tsc的可靠性已經驗證,則清除 必須驗證 標記
	if (tsc_clocksource_reliable)
		clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
	
	//檢查tsc是否穩定
	//	在tsc_init前通過全局變量標記tsc是否穩定,可靠
	if (check_tsc_unstable()) {
		//如果tsc不穩定,則降低rating最低,清除連續標記
		clocksource_tsc.rating = 0;
		clocksource_tsc.flags &= ~CLOCK_SOURCE_IS_CONTINUOUS;
	}
	//向係統注冊tsc clocksource
	clocksource_register(&clocksource_tsc);
}

最後更新:2017-04-03 14:54:27

  上一篇:go BT656跟BT1120和BT709有什麼區別
  下一篇:go 時間子係統10_hpet時鍾初始化