Changeset View
Changeset View
Standalone View
Standalone View
sys/x86/x86/tsc.c
Show First 20 Lines • Show All 689 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
atomic_store_rel_64(&tsc_freq, new_freq); | atomic_store_rel_64(&tsc_freq, new_freq); | ||||
atomic_store_rel_64(&tsc_timecounter.tc_frequency, | atomic_store_rel_64(&tsc_timecounter.tc_frequency, | ||||
new_freq >> (int)(intptr_t)tsc_timecounter.tc_priv); | new_freq >> (int)(intptr_t)tsc_timecounter.tc_priv); | ||||
} | } | ||||
/* | /* | ||||
* Perform late calibration of the TSC frequency once ACPI-based timecounters | * Perform late calibration of the TSC frequency once ACPI-based timecounters | ||||
* are available. | * are available. At this point timehands are not set up, so we read the | ||||
* highest-quality timecounter directly rather than using (s)binuptime(). | |||||
*/ | */ | ||||
static void | void | ||||
tsc_calib(void *arg __unused) | tsc_calibrate(void) | ||||
{ | { | ||||
sbintime_t t_start, t_end; | struct timecounter *tc; | ||||
uint64_t freq_khz, tsc_start, tsc_end; | uint64_t freq_khz, tsc_start, tsc_end; | ||||
u_int t_start, t_end; | |||||
register_t flags; | register_t flags; | ||||
int cpu; | int cpu; | ||||
if (tsc_disabled) | if (tsc_disabled) | ||||
return; | return; | ||||
tc = atomic_load_ptr(&timecounter); | |||||
flags = intr_disable(); | flags = intr_disable(); | ||||
cpu = curcpu; | cpu = curcpu; | ||||
tsc_start = rdtsc_ordered(); | tsc_start = rdtsc_ordered(); | ||||
t_start = sbinuptime(); | t_start = tc->tc_get_timecount(tc) & tc->tc_counter_mask; | ||||
kib: Perhaps add a comment explaining why do you directly use tc_get_timecount(), instead of only… | |||||
intr_restore(flags); | intr_restore(flags); | ||||
DELAY(1000000); | DELAY(1000000); | ||||
thread_lock(curthread); | thread_lock(curthread); | ||||
sched_bind(curthread, cpu); | sched_bind(curthread, cpu); | ||||
flags = intr_disable(); | flags = intr_disable(); | ||||
tsc_end = rdtsc_ordered(); | tsc_end = rdtsc_ordered(); | ||||
t_end = sbinuptime(); | t_end = tc->tc_get_timecount(tc) & tc->tc_counter_mask; | ||||
intr_restore(flags); | intr_restore(flags); | ||||
sched_unbind(curthread); | sched_unbind(curthread); | ||||
thread_unlock(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; | |||||
} | |||||
tsc_update_freq(freq_khz * 1024); | freq_khz = tc->tc_frequency * (tsc_end - tsc_start) / (t_end - t_start); | ||||
tsc_update_freq(freq_khz); | |||||
tc_init(&tsc_timecounter); | tc_init(&tsc_timecounter); | ||||
set_cputicker(rdtsc, tsc_freq, !tsc_is_invariant); | set_cputicker(rdtsc, tsc_freq, !tsc_is_invariant); | ||||
} | } | ||||
SYSINIT(tsc_calib, SI_SUB_CLOCKS + 1, SI_ORDER_ANY, tsc_calib, NULL); | |||||
void | void | ||||
resume_TSC(void) | resume_TSC(void) | ||||
{ | { | ||||
#ifdef SMP | #ifdef SMP | ||||
int quality; | int quality; | ||||
/* If TSC was not good on boot, it is unlikely to become good now. */ | /* If TSC was not good on boot, it is unlikely to become good now. */ | ||||
▲ Show 20 Lines • Show All 200 Lines • Show Last 20 Lines |
Perhaps add a comment explaining why do you directly use tc_get_timecount(), instead of only saying it in the commit message.