Skip to content

Commit 7e7d4e7

Browse files
mattdelcoconcussious
authored andcommitted
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
1 parent c505fc1 commit 7e7d4e7

File tree

2 files changed

+13
-10
lines changed

2 files changed

+13
-10
lines changed

sys/x86/x86/cpu_machdep.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ int
423423
cpu_est_clockrate(int cpu_id, uint64_t *rate)
424424
{
425425
uint64_t tsc1, tsc2;
426-
uint64_t acnt, mcnt, perf;
426+
uint64_t acnt_start, acnt_end, mcnt_start, mcnt_end, perf;
427427
register_t reg;
428428
int error = 0;
429429

@@ -453,20 +453,20 @@ cpu_est_clockrate(int cpu_id, uint64_t *rate)
453453
/* Calibrate by measuring a short delay. */
454454
reg = intr_disable();
455455
if (tsc_is_invariant) {
456-
wrmsr(MSR_MPERF, 0);
457-
wrmsr(MSR_APERF, 0);
456+
mcnt_start = rdmsr(MSR_MPERF);
457+
acnt_start = rdmsr(MSR_APERF);
458458
tsc1 = rdtsc();
459459
DELAY(1000);
460-
mcnt = rdmsr(MSR_MPERF);
461-
acnt = rdmsr(MSR_APERF);
460+
mcnt_end = rdmsr(MSR_MPERF);
461+
acnt_end = rdmsr(MSR_APERF);
462462
tsc2 = rdtsc();
463463
intr_restore(reg);
464-
if (mcnt == 0) {
464+
if (mcnt_end == mcnt_start) {
465465
tsc_perf_stat = 0;
466466
error = EOPNOTSUPP;
467467
goto err;
468468
}
469-
perf = 1000 * acnt / mcnt;
469+
perf = 1000 * (acnt_end - acnt_start) / (mcnt_end - mcnt_start);
470470
*rate = (tsc2 - tsc1) * perf;
471471
} else {
472472
tsc1 = rdtsc();

sys/x86/x86/tsc.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,8 @@ probe_tsc_freq_late(void)
433433
void
434434
start_TSC(void)
435435
{
436+
uint64_t mperf, aperf;
437+
436438
if ((cpu_feature & CPUID_TSC) == 0 || tsc_disabled)
437439
return;
438440

@@ -442,11 +444,12 @@ start_TSC(void)
442444
/*
443445
* XXX Some emulators expose host CPUID without actual support
444446
* for these MSRs. We must test whether they really work.
447+
* They may also be read-only, so test for increment.
445448
*/
446-
wrmsr(MSR_MPERF, 0);
447-
wrmsr(MSR_APERF, 0);
449+
mperf = rdmsr(MSR_MPERF);
450+
aperf = rdmsr(MSR_APERF);
448451
DELAY(10);
449-
if (rdmsr(MSR_MPERF) > 0 && rdmsr(MSR_APERF) > 0)
452+
if (rdmsr(MSR_MPERF) != mperf && rdmsr(MSR_APERF) != aperf)
450453
tsc_perf_stat = 1;
451454
}
452455

0 commit comments

Comments
 (0)