From: cheloha Date: Mon, 24 Oct 2022 00:56:33 +0000 (+0000) Subject: tsc: AMD Family 17h, 19h: compute frequency from Core::X86::Msr:PStateDef X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=8cc9615794e40e0af7194d606ce26e2632e0829a;p=openbsd tsc: AMD Family 17h, 19h: compute frequency from Core::X86::Msr:PStateDef Compute the TSC frequency on AMD family 17h and 19h CPUs using the PStateDef MSRs. Link 1: https://marc.info/?l=openbsd-tech&m=166394236029484&w=2 Link 2: https://marc.info/?l=openbsd-tech&m=166446065916283&w=2 Test list: https://marc.info/?l=openbsd-tech&m=166646389821326&w=2 Reviewed by kettenis@ using the AMD documents cited in the comments. Maybe reviewed by mlarkin@? I can't remember. He seemed supportive of the idea at least. ok kettenis@ --- diff --git a/sys/arch/amd64/amd64/tsc.c b/sys/arch/amd64/amd64/tsc.c index 7e5c414cc00..a3086a47def 100644 --- a/sys/arch/amd64/amd64/tsc.c +++ b/sys/arch/amd64/amd64/tsc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tsc.c,v 1.29 2022/09/22 04:57:08 robert Exp $ */ +/* $OpenBSD: tsc.c,v 1.30 2022/10/24 00:56:33 cheloha Exp $ */ /* * Copyright (c) 2008 The NetBSD Foundation, Inc. * Copyright (c) 2016,2017 Reyk Floeter @@ -100,6 +100,67 @@ tsc_freq_cpuid(struct cpu_info *ci) return (0); } +uint64_t +tsc_freq_msr(struct cpu_info *ci) +{ + uint64_t base, def, divisor, multiplier; + + if (strcmp(cpu_vendor, "AuthenticAMD") != 0) + return 0; + + /* + * All 10h+ CPUs have Core::X86::Msr:HWCR and the TscFreqSel + * bit. If TscFreqSel hasn't been set, the TSC isn't advancing + * at the core P0 frequency and we need to calibrate by hand. + */ + if (ci->ci_family < 0x10) + return 0; + if (!ISSET(rdmsr(MSR_HWCR), HWCR_TSCFREQSEL)) + return 0; + + /* + * In 10h+ CPUs, Core::X86::Msr::PStateDef defines the voltage + * and frequency for each core P-state. We want the P0 frequency. + * If the En bit isn't set, the register doesn't define a valid + * P-state. + */ + def = rdmsr(MSR_PSTATEDEF(0)); + if (!ISSET(def, PSTATEDEF_EN)) + return 0; + + switch (ci->ci_family) { + case 0x17: + case 0x19: + /* + * PPR for AMD Family 17h [...]: + * Models 01h,08h B2, Rev 3.03, pp. 33, 139-140 + * Model 18h B1, Rev 3.16, pp. 36, 143-144 + * Model 60h A1, Rev 3.06, pp. 33, 155-157 + * Model 71h B0, Rev 3.06, pp. 28, 150-151 + * + * PPR for AMD Family 19h [...]: + * Model 21h B0, Rev 3.05, pp. 33, 166-167 + * + * OSRR for AMD Family 17h processors, + * Models 00h-2Fh, Rev 3.03, pp. 130-131 + */ + base = 200000000; /* 200.0 MHz */ + divisor = (def >> 8) & 0x3f; + if (divisor <= 0x07 || divisor >= 0x2d) + return 0; /* reserved */ + if (divisor >= 0x1b && divisor % 2 == 1) + return 0; /* reserved */ + multiplier = def & 0xff; + if (multiplier <= 0x0f) + return 0; /* reserved */ + break; + default: + return 0; + } + + return base * multiplier / divisor; +} + void tsc_identify(struct cpu_info *ci) { @@ -118,6 +179,8 @@ tsc_identify(struct cpu_info *ci) tsc_is_invariant = 1; tsc_frequency = tsc_freq_cpuid(ci); + if (tsc_frequency == 0) + tsc_frequency = tsc_freq_msr(ci); if (tsc_frequency > 0) delay_init(tsc_delay, 5000); } diff --git a/sys/arch/amd64/include/specialreg.h b/sys/arch/amd64/include/specialreg.h index e7bc30f27b7..cbde6cf9b02 100644 --- a/sys/arch/amd64/include/specialreg.h +++ b/sys/arch/amd64/include/specialreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: specialreg.h,v 1.94 2022/08/30 17:09:21 dv Exp $ */ +/* $OpenBSD: specialreg.h,v 1.95 2022/10/24 00:56:33 cheloha Exp $ */ /* $NetBSD: specialreg.h,v 1.1 2003/04/26 18:39:48 fvdl Exp $ */ /* $NetBSD: x86/specialreg.h,v 1.2 2003/04/25 21:54:30 fvdl Exp $ */ @@ -540,6 +540,10 @@ */ #define MSR_HWCR 0xc0010015 #define HWCR_FFDIS 0x00000040 +#define HWCR_TSCFREQSEL 0x01000000 + +#define MSR_PSTATEDEF(_n) (0xc0010064 + (_n)) +#define PSTATEDEF_EN 0x8000000000000000ULL #define MSR_NB_CFG 0xc001001f #define NB_CFG_DISIOREQLOCK 0x0000000000000004ULL