aboutsummaryrefslogtreecommitdiff
path: root/sys/x86
diff options
context:
space:
mode:
authorColin Percival <cperciva@FreeBSD.org>2022-01-10 01:22:20 +0000
committerColin Percival <cperciva@FreeBSD.org>2022-01-12 20:34:07 +0000
commitc2705ceaeb09d8579661097fd358ffb5defb5624 (patch)
tree746ab22dd8ded9efcc773b7eb7aa6289c9c3bc38 /sys/x86
parent12f747e6ff675edfc1f2f95f7fc435dc01e0c29c (diff)
Diffstat (limited to 'sys/x86')
-rw-r--r--sys/x86/x86/local_apic.c31
-rw-r--r--sys/x86/x86/tsc.c46
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);