aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Delco <delco@google.com>2026-03-26 17:30:31 +0000
committerAlexander Ziaee <ziaee@FreeBSD.org>2026-03-26 19:02:22 +0000
commit7e7d4e711ff94d114c93fd522d4125aa9bd9f5cd (patch)
tree75e6b4c11bb1f2eb8fc4d9caa02cc40399b4cc87
parentc505fc1468849150f48484b225b6476d8316de57 (diff)
x86: Handle when MPERF/APERF MSRs aren't writable
For performance and/or correct reasons some hypervisors allow MPERF/APERF MSRs to be read but not written to. This change modifies the handling of these MSRs to not rely on writes. This patch is part of Google Cloud Engine (GCE) C4-LSSD turnup. Sponsored by: Google Tested by: NetApp (previous) PR: 292808 MFC after: 3 days Co-authored-by: Jim Mattson <jmattson@google.com> Reviewed by: jrtc27, imp, kib, markj, olce, obiwac Differential Revision: https://reviews.freebsd.org/D55996
-rw-r--r--sys/x86/x86/cpu_machdep.c14
-rw-r--r--sys/x86/x86/tsc.c9
2 files changed, 13 insertions, 10 deletions
diff --git a/sys/x86/x86/cpu_machdep.c b/sys/x86/x86/cpu_machdep.c
index 775fee97d3cd..422bdf9cfb0d 100644
--- a/sys/x86/x86/cpu_machdep.c
+++ b/sys/x86/x86/cpu_machdep.c
@@ -423,7 +423,7 @@ int
cpu_est_clockrate(int cpu_id, uint64_t *rate)
{
uint64_t tsc1, tsc2;
- uint64_t acnt, mcnt, perf;
+ uint64_t acnt_start, acnt_end, mcnt_start, mcnt_end, perf;
register_t reg;
int error = 0;
@@ -453,20 +453,20 @@ cpu_est_clockrate(int cpu_id, uint64_t *rate)
/* Calibrate by measuring a short delay. */
reg = intr_disable();
if (tsc_is_invariant) {
- wrmsr(MSR_MPERF, 0);
- wrmsr(MSR_APERF, 0);
+ mcnt_start = rdmsr(MSR_MPERF);
+ acnt_start = rdmsr(MSR_APERF);
tsc1 = rdtsc();
DELAY(1000);
- mcnt = rdmsr(MSR_MPERF);
- acnt = rdmsr(MSR_APERF);
+ mcnt_end = rdmsr(MSR_MPERF);
+ acnt_end = rdmsr(MSR_APERF);
tsc2 = rdtsc();
intr_restore(reg);
- if (mcnt == 0) {
+ if (mcnt_end == mcnt_start) {
tsc_perf_stat = 0;
error = EOPNOTSUPP;
goto err;
}
- perf = 1000 * acnt / mcnt;
+ perf = 1000 * (acnt_end - acnt_start) / (mcnt_end - mcnt_start);
*rate = (tsc2 - tsc1) * perf;
} else {
tsc1 = rdtsc();
diff --git a/sys/x86/x86/tsc.c b/sys/x86/x86/tsc.c
index 3b873d9dae73..f88ce60c6319 100644
--- a/sys/x86/x86/tsc.c
+++ b/sys/x86/x86/tsc.c
@@ -433,6 +433,8 @@ probe_tsc_freq_late(void)
void
start_TSC(void)
{
+ uint64_t mperf, aperf;
+
if ((cpu_feature & CPUID_TSC) == 0 || tsc_disabled)
return;
@@ -442,11 +444,12 @@ start_TSC(void)
/*
* XXX Some emulators expose host CPUID without actual support
* for these MSRs. We must test whether they really work.
+ * They may also be read-only, so test for increment.
*/
- wrmsr(MSR_MPERF, 0);
- wrmsr(MSR_APERF, 0);
+ mperf = rdmsr(MSR_MPERF);
+ aperf = rdmsr(MSR_APERF);
DELAY(10);
- if (rdmsr(MSR_MPERF) > 0 && rdmsr(MSR_APERF) > 0)
+ if (rdmsr(MSR_MPERF) != mperf && rdmsr(MSR_APERF) != aperf)
tsc_perf_stat = 1;
}