diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2022-04-26 08:35:31 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2022-04-26 08:35:31 +0000 |
commit | c24736a70fbbbed4de390c990ca6477a6f631ca7 (patch) | |
tree | beab23cd22497f5ba771ed720a2319bc914fd212 | |
parent | 53bbe915ab117c8d0c46aea5131ce48801d322ad (diff) |
On CPUs that have MPERF/APERF support use that information to install a
cpu frequency sensor for each core. This works on many "modern" Intel and
AMD cpus (probably anything that has some kind of turbo mode).
OK kettenis@
-rw-r--r-- | sys/arch/amd64/amd64/cpu.c | 12 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/identcpu.c | 69 | ||||
-rw-r--r-- | sys/arch/amd64/include/cpu.h | 5 | ||||
-rw-r--r-- | sys/arch/amd64/include/specialreg.h | 6 |
4 files changed, 79 insertions, 13 deletions
diff --git a/sys/arch/amd64/amd64/cpu.c b/sys/arch/amd64/amd64/cpu.c index 30e734e407b..4778347a12e 100644 --- a/sys/arch/amd64/amd64/cpu.c +++ b/sys/arch/amd64/amd64/cpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.c,v 1.155 2022/02/21 11:03:39 mpi Exp $ */ +/* $OpenBSD: cpu.c,v 1.156 2022/04/26 08:35:30 claudio Exp $ */ /* $NetBSD: cpu.c,v 1.1 2003/04/26 18:39:26 fvdl Exp $ */ /*- @@ -558,6 +558,11 @@ cpu_attach(struct device *parent, struct device *self, void *aux) ci->ci_func = caa->cpu_func; ci->ci_handled_intr_level = IPL_NONE; +#ifndef SMALL_KERNEL + strlcpy(ci->ci_sensordev.xname, ci->ci_dev->dv_xname, + sizeof(ci->ci_sensordev.xname)); +#endif + #if defined(MULTIPROCESSOR) /* * Allocate UPAGES contiguous pages for the idle PCB and stack. @@ -663,6 +668,11 @@ cpu_attach(struct device *parent, struct device *self, void *aux) #if NVMM > 0 cpu_init_vmm(ci); #endif /* NVMM > 0 */ + +#ifndef SMALL_KERNEL + if (ci->ci_sensordev.sensors_count > 0) + sensordev_install(&ci->ci_sensordev); +#endif } static void diff --git a/sys/arch/amd64/amd64/identcpu.c b/sys/arch/amd64/amd64/identcpu.c index b67e177a686..060e73e7dd5 100644 --- a/sys/arch/amd64/amd64/identcpu.c +++ b/sys/arch/amd64/amd64/identcpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: identcpu.c,v 1.122 2022/01/20 11:06:57 bluhm Exp $ */ +/* $OpenBSD: identcpu.c,v 1.123 2022/04/26 08:35:30 claudio Exp $ */ /* $NetBSD: identcpu.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */ /* @@ -38,6 +38,8 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/atomic.h> +#include <sys/proc.h> #include <sys/sysctl.h> #include "vmm.h" @@ -246,7 +248,9 @@ cpu_amd64speed(int *freq) } #ifndef SMALL_KERNEL -void intelcore_update_sensor(void *args); +void intelcore_update_sensor(void *); +void cpu_hz_update_sensor(void *); + /* * Temperature read on the CPU is relative to the maximum * temperature supported by the CPU, Tj(Max). @@ -299,6 +303,44 @@ intelcore_update_sensor(void *args) } } +/* + * Effective CPU frequency measurement + * + * Refer to: + * 64-ia-32-architectures-software-developer-vol-3b-part-2-manual.pdf + * Section 14.2 and + * OSRR for AMD Family 17h processors Section 2.1.2 + * Round to 50Mhz which is the accuracy of this measurement. + */ +#define FREQ_50MHZ (50ULL * 1000000ULL * 1000000ULL) +void +cpu_hz_update_sensor(void *args) +{ + extern uint64_t tsc_frequency; + struct cpu_info *ci = args; + uint64_t mperf, aperf, mdelta, adelta, val; + unsigned long s; + + sched_peg_curproc(ci); + + s = intr_disable(); + mperf = rdmsr(MSR_MPERF); + aperf = rdmsr(MSR_APERF); + intr_restore(s); + + mdelta = mperf - ci->ci_hz_mperf; + adelta = aperf - ci->ci_hz_aperf; + ci->ci_hz_mperf = mperf; + ci->ci_hz_aperf = aperf; + + if (mdelta > 0) { + val = (adelta * 1000000) / mdelta * tsc_frequency; + val = ((val + FREQ_50MHZ / 2) / FREQ_50MHZ) * FREQ_50MHZ; + ci->ci_hz_sensor.value = val; + } + + atomic_clearbits_int(&curproc->p_flag, P_CPUPEG); +} #endif void (*setperf_setup)(struct cpu_info *); @@ -469,7 +511,7 @@ void identifycpu(struct cpu_info *ci) { uint64_t freq = 0; - u_int32_t dummy, val; + u_int32_t dummy, val, cpu_tpm_ecxflags = 0; char mycpu_model[48]; int i; char *brandstr_from, *brandstr_to; @@ -619,12 +661,15 @@ identifycpu(struct cpu_info *ci) } if (!strcmp(cpu_vendor, "GenuineIntel") && cpuid_level >= 0x06) { - CPUID(0x06, ci->ci_feature_tpmflags, dummy, dummy, dummy); + CPUID(0x06, ci->ci_feature_tpmflags, dummy, cpu_tpm_ecxflags, + dummy); for (i = 0; i < nitems(cpu_tpm_eaxfeatures); i++) if (ci->ci_feature_tpmflags & cpu_tpm_eaxfeatures[i].bit) printf(",%s", cpu_tpm_eaxfeatures[i].str); } else if (!strcmp(cpu_vendor, "AuthenticAMD")) { + CPUID(0x06, ci->ci_feature_tpmflags, dummy, cpu_tpm_ecxflags, + dummy); if (ci->ci_family >= 0x12) ci->ci_feature_tpmflags |= TPM_ARAT; } @@ -737,12 +782,9 @@ identifycpu(struct cpu_info *ci) #ifndef SMALL_KERNEL if (CPU_IS_PRIMARY(ci) && (ci->ci_feature_tpmflags & TPM_SENSOR)) { - strlcpy(ci->ci_sensordev.xname, ci->ci_dev->dv_xname, - sizeof(ci->ci_sensordev.xname)); ci->ci_sensor.type = SENSOR_TEMP; sensor_task_register(ci, intelcore_update_sensor, 5); sensor_attach(&ci->ci_sensordev, &ci->ci_sensor); - sensordev_install(&ci->ci_sensordev); } #endif @@ -762,12 +804,9 @@ identifycpu(struct cpu_info *ci) if (CPU_IS_PRIMARY(ci) && !strcmp(cpu_vendor, "CentaurHauls")) { ci->cpu_setup = via_nano_setup; #ifndef SMALL_KERNEL - strlcpy(ci->ci_sensordev.xname, ci->ci_dev->dv_xname, - sizeof(ci->ci_sensordev.xname)); ci->ci_sensor.type = SENSOR_TEMP; sensor_task_register(ci, via_update_sensor, 5); sensor_attach(&ci->ci_sensordev, &ci->ci_sensor); - sensordev_install(&ci->ci_sensordev); #endif } @@ -777,6 +816,16 @@ identifycpu(struct cpu_info *ci) #if NVMM > 0 cpu_check_vmm_cap(ci); #endif /* NVMM > 0 */ + + /* Check for effective frequency via MPERF, APERF */ + if ((cpu_tpm_ecxflags & TPM_EFFFREQ) && + ci->ci_smt_id == 0) { +#ifndef SMALL_KERNEL + ci->ci_hz_sensor.type = SENSOR_FREQ; + sensor_task_register(ci, cpu_hz_update_sensor, 1); + sensor_attach(&ci->ci_sensordev, &ci->ci_hz_sensor); +#endif + } } #ifndef SMALL_KERNEL diff --git a/sys/arch/amd64/include/cpu.h b/sys/arch/amd64/include/cpu.h index 4bc8627b554..0bf6cc41900 100644 --- a/sys/arch/amd64/include/cpu.h +++ b/sys/arch/amd64/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.141 2021/08/31 17:40:59 dv Exp $ */ +/* $OpenBSD: cpu.h,v 1.142 2022/04/26 08:35:30 claudio Exp $ */ /* $NetBSD: cpu.h,v 1.1 2003/04/26 18:39:39 fvdl Exp $ */ /*- @@ -196,6 +196,9 @@ struct cpu_info { struct ksensordev ci_sensordev; struct ksensor ci_sensor; + struct ksensor ci_hz_sensor; + u_int64_t ci_hz_mperf; + u_int64_t ci_hz_aperf; #if defined(GPROF) || defined(DDBPROF) struct gmonparam *ci_gmon; #endif diff --git a/sys/arch/amd64/include/specialreg.h b/sys/arch/amd64/include/specialreg.h index 6b32f07e2f4..34701ffb864 100644 --- a/sys/arch/amd64/include/specialreg.h +++ b/sys/arch/amd64/include/specialreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: specialreg.h,v 1.91 2021/11/19 04:00:53 guenther Exp $ */ +/* $OpenBSD: specialreg.h,v 1.92 2022/04/26 08:35:30 claudio 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 $ */ @@ -235,6 +235,8 @@ */ #define TPM_SENSOR 0x00000001 /* Digital temp sensor */ #define TPM_ARAT 0x00000004 /* APIC Timer Always Running */ +/* Thermal and Power Management (CPUID function 0x6) ECX bits */ +#define TPM_EFFFREQ 0x00000001 /* APERF & MPERF MSR present */ /* * "Architectural Performance Monitoring" bits (CPUID function 0x0a): @@ -369,6 +371,8 @@ #define MSR_PERFCTR0 0x0c1 #define MSR_PERFCTR1 0x0c2 #define MSR_FSB_FREQ 0x0cd /* Core Duo/Solo only */ +#define MSR_MPERF 0x0e7 +#define MSR_APERF 0x0e8 #define MSR_MTRRcap 0x0fe #define MTRRcap_FIXED 0x100 /* bit 8 - fixed MTRRs supported */ #define MTRRcap_WC 0x400 /* bit 10 - WC type supported */ |