x86: Defer early TSC timecounter calibration to SI_SUB_CPU
If we can't determine the TSC frequency using CPU registers, we need to
give a chance for Hyper-V drivers to register a timecounter (during
SI_SUB_HYPERVISOR) since an emulated 8254 might not be available.
Thus, split probe_tsc_freq() into early and late stages, and wait until
the latter to attempt calibration using a reference clock.
Fixes: 84369dd523
("x86: Probe the TSC frequency earlier")
Reported and tested by: khng, Shawn Webb
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D34444
This commit is contained in:
parent
f7a6dccf42
commit
075e2779ac
@ -240,7 +240,7 @@ tsc_freq_intel_brand(uint64_t *res)
|
||||
}
|
||||
|
||||
static void
|
||||
tsc_freq_8254(uint64_t *res)
|
||||
tsc_freq_tc(uint64_t *res)
|
||||
{
|
||||
uint64_t tsc1, tsc2;
|
||||
int64_t overhead;
|
||||
@ -262,8 +262,15 @@ tsc_freq_8254(uint64_t *res)
|
||||
tsc_freq = (tsc2 - tsc1 - overhead) * 10;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to determine the TSC frequency using CPUID or hypercalls. If successful,
|
||||
* this lets use the TSC for early DELAY() calls instead of the 8254 timer,
|
||||
* which may be unreliable or entirely absent on contemporary systems. However,
|
||||
* avoid calibrating using the 8254 here so as to give hypervisors a chance to
|
||||
* register a timecounter that can be used instead.
|
||||
*/
|
||||
static void
|
||||
probe_tsc_freq(void)
|
||||
probe_tsc_freq_early(void)
|
||||
{
|
||||
#ifdef __i386__
|
||||
/* The TSC is known to be broken on certain CPUs. */
|
||||
@ -364,7 +371,20 @@ probe_tsc_freq(void)
|
||||
if (bootverbose)
|
||||
printf("Early TSC frequency %juHz derived from CPUID\n",
|
||||
(uintmax_t)tsc_freq);
|
||||
} else if (tsc_skip_calibration) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we were unable to determine the TSC frequency via CPU registers, try
|
||||
* to calibrate against a known clock.
|
||||
*/
|
||||
static void
|
||||
probe_tsc_freq_late(void)
|
||||
{
|
||||
if (tsc_freq != 0)
|
||||
return;
|
||||
|
||||
if (tsc_skip_calibration) {
|
||||
/*
|
||||
* Try to parse the brand string to obtain the nominal TSC
|
||||
* frequency.
|
||||
@ -380,15 +400,24 @@ probe_tsc_freq(void)
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Calibrate against the 8254 PIT. This estimate will be
|
||||
* refined later in tsc_calib().
|
||||
* Calibrate against a timecounter or the 8254 PIT. This
|
||||
* estimate will be refined later in tsc_calib().
|
||||
*/
|
||||
tsc_freq_8254(&tsc_freq);
|
||||
tsc_freq_tc(&tsc_freq);
|
||||
if (bootverbose)
|
||||
printf(
|
||||
"Early TSC frequency %juHz calibrated from 8254 PIT\n",
|
||||
(uintmax_t)tsc_freq);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
start_TSC(void)
|
||||
{
|
||||
if ((cpu_feature & CPUID_TSC) == 0 || tsc_disabled)
|
||||
return;
|
||||
|
||||
probe_tsc_freq_late();
|
||||
|
||||
if (cpu_power_ecx & CPUID_PERF_STAT) {
|
||||
/*
|
||||
@ -401,13 +430,6 @@ probe_tsc_freq(void)
|
||||
if (rdmsr(MSR_MPERF) > 0 && rdmsr(MSR_APERF) > 0)
|
||||
tsc_perf_stat = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
start_TSC(void)
|
||||
{
|
||||
if ((cpu_feature & CPUID_TSC) == 0 || tsc_disabled)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Inform CPU accounting about our boot-time clock rate. This will
|
||||
@ -718,7 +740,7 @@ tsc_init(void)
|
||||
if ((cpu_feature & CPUID_TSC) == 0 || tsc_disabled)
|
||||
return;
|
||||
|
||||
probe_tsc_freq();
|
||||
probe_tsc_freq_early();
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user