diff options
| author | Colin Percival <cperciva@FreeBSD.org> | 2022-01-10 01:22:20 +0000 |
|---|---|---|
| committer | Colin Percival <cperciva@FreeBSD.org> | 2022-01-12 20:34:07 +0000 |
| commit | c2705ceaeb09d8579661097fd358ffb5defb5624 (patch) | |
| tree | 746ab22dd8ded9efcc773b7eb7aa6289c9c3bc38 /sys/x86 | |
| parent | 12f747e6ff675edfc1f2f95f7fc435dc01e0c29c (diff) | |
Diffstat (limited to 'sys/x86')
| -rw-r--r-- | sys/x86/x86/local_apic.c | 31 | ||||
| -rw-r--r-- | sys/x86/x86/tsc.c | 46 |
2 files changed, 27 insertions, 50 deletions
diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c index 23b780b121e1..4b66d10cb5ae 100644 --- a/sys/x86/x86/local_apic.c +++ b/sys/x86/x86/local_apic.c @@ -56,6 +56,7 @@ __FBSDID("$FreeBSD$"); #include <sys/smp.h> #include <sys/sysctl.h> #include <sys/timeet.h> +#include <sys/timetc.h> #include <vm/vm.h> #include <vm/pmap.h> @@ -64,6 +65,7 @@ __FBSDID("$FreeBSD$"); #include <machine/clock.h> #include <machine/cpufunc.h> #include <machine/cputypes.h> +#include <machine/fpu.h> #include <machine/frame.h> #include <machine/intr_machdep.h> #include <x86/apicvar.h> @@ -1000,30 +1002,39 @@ native_lapic_disable_pmc(void) #endif } +static uint64_t +cb_lapic_getcount(void) +{ + + return (APIC_TIMER_MAX_COUNT - lapic_read32(LAPIC_CCR_TIMER)); +} + static void lapic_calibrate_initcount(struct lapic *la) { - u_long value; + uint64_t freq; + + /* Calibrate the APIC timer frequency. */ + lapic_timer_set_divisor(2); + lapic_timer_oneshot_nointr(la, APIC_TIMER_MAX_COUNT); + fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX); + freq = clockcalib(cb_lapic_getcount, "lapic"); + fpu_kern_leave(curthread, NULL); - /* Start off with a divisor of 2 (power on reset default). */ + /* Pick a different divisor if necessary. */ lapic_timer_divisor = 2; - /* Try to calibrate the local APIC timer. */ do { - lapic_timer_set_divisor(lapic_timer_divisor); - lapic_timer_oneshot_nointr(la, APIC_TIMER_MAX_COUNT); - DELAY(1000000); - value = APIC_TIMER_MAX_COUNT - lapic_read32(LAPIC_CCR_TIMER); - if (value != APIC_TIMER_MAX_COUNT) + if (freq * 2 / lapic_timer_divisor < APIC_TIMER_MAX_COUNT) break; lapic_timer_divisor <<= 1; } while (lapic_timer_divisor <= 128); if (lapic_timer_divisor > 128) panic("lapic: Divisor too big"); + count_freq = freq * 2 / lapic_timer_divisor; if (bootverbose) { printf("lapic: Divisor %lu, Frequency %lu Hz\n", - lapic_timer_divisor, value); + lapic_timer_divisor, count_freq); } - count_freq = value; } static void diff --git a/sys/x86/x86/tsc.c b/sys/x86/x86/tsc.c index 3b2e044573f1..fa21d9c51fcb 100644 --- a/sys/x86/x86/tsc.c +++ b/sys/x86/x86/tsc.c @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include <sys/vdso.h> #include <machine/clock.h> #include <machine/cputypes.h> +#include <machine/fpu.h> #include <machine/md_var.h> #include <machine/specialreg.h> #include <x86/vmware.h> @@ -703,53 +704,18 @@ tsc_update_freq(uint64_t new_freq) void tsc_calibrate(void) { - struct timecounter *tc; - uint64_t freq, tsc_start, tsc_end; - u_int t_start, t_end; - register_t flags; - int cpu; + uint64_t freq; if (tsc_disabled) return; if (tsc_early_calib_exact) goto calibrated; - /* - * Avoid using a low-quality timecounter to re-calibrate. In - * particular, old 32-bit platforms might only have the 8254 timer to - * calibrate against. - */ - tc = atomic_load_ptr(&timecounter); - if (tc->tc_quality <= 0) - goto calibrated; - - flags = intr_disable(); - cpu = curcpu; - tsc_start = rdtsc_ordered(); - t_start = tc->tc_get_timecount(tc) & tc->tc_counter_mask; - intr_restore(flags); - - DELAY(1000000); - - thread_lock(curthread); - sched_bind(curthread, cpu); - - flags = intr_disable(); - tsc_end = rdtsc_ordered(); - t_end = tc->tc_get_timecount(tc) & tc->tc_counter_mask; - intr_restore(flags); - - sched_unbind(curthread); - thread_unlock(curthread); - - 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 = tc->tc_frequency * (tsc_end - tsc_start) / (t_end - t_start); - + fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX); + freq = clockcalib(rdtsc_ordered, "TSC"); + fpu_kern_leave(curthread, NULL); tsc_update_freq(freq); + calibrated: tc_init(&tsc_timecounter); set_cputicker(rdtsc, tsc_freq, !tsc_is_invariant); |
