Index: sys/x86/include/clock.h =================================================================== --- sys/x86/include/clock.h +++ sys/x86/include/clock.h @@ -28,6 +28,7 @@ void i8254_delay(int); void clock_init(void); void lapic_calibrate(void); +void tsc_calibrate(void); /* * Driver to clock driver interface. Index: sys/x86/isa/clock.c =================================================================== --- sys/x86/isa/clock.c +++ sys/x86/isa/clock.c @@ -413,6 +413,7 @@ td = curthread; + tsc_calibrate(); lapic_calibrate_timer(); cpu_initclocks_bsp(); CPU_FOREACH(i) { @@ -428,6 +429,7 @@ sched_unbind(td); thread_unlock(td); #else + tsc_calibrate(); lapic_calibrate_timer(); cpu_initclocks_bsp(); #endif Index: sys/x86/x86/tsc.c =================================================================== --- sys/x86/x86/tsc.c +++ sys/x86/x86/tsc.c @@ -697,21 +697,24 @@ * Perform late calibration of the TSC frequency once ACPI-based timecounters * are available. */ -static void -tsc_calib(void *arg __unused) +void +tsc_calibrate(void) { - sbintime_t t_start, t_end; + struct timecounter *tc; uint64_t freq_khz, tsc_start, tsc_end; + u_int t_start, t_end; register_t flags; int cpu; if (tsc_disabled) return; + tc = atomic_load_ptr(&timecounter); + flags = intr_disable(); cpu = curcpu; tsc_start = rdtsc_ordered(); - t_start = sbinuptime(); + t_start = tc->tc_get_timecount(tc) & tc->tc_counter_mask; intr_restore(flags); DELAY(1000000); @@ -721,19 +724,23 @@ flags = intr_disable(); tsc_end = rdtsc_ordered(); - t_end = sbinuptime(); + t_end = tc->tc_get_timecount(tc) & tc->tc_counter_mask; intr_restore(flags); sched_unbind(curthread); thread_unlock(curthread); - freq_khz = (SBT_1S / 1024) * (tsc_end - tsc_start) / (t_end - t_start); + if (t_end <= t_start) { + /* Assume that the counter has wrapped around at most once. */ + t_end += (uint64_t)tc->tc_counter_mask + 1; + } + + freq_khz = tc->tc_frequency * (tsc_end - tsc_start) / (t_end - t_start); - tsc_update_freq(freq_khz * 1024); + tsc_update_freq(freq_khz); tc_init(&tsc_timecounter); set_cputicker(rdtsc, tsc_freq, !tsc_is_invariant); } -SYSINIT(tsc_calib, SI_SUB_CLOCKS + 1, SI_ORDER_ANY, tsc_calib, NULL); void resume_TSC(void)