summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2022-04-26 08:35:31 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2022-04-26 08:35:31 +0000
commitc24736a70fbbbed4de390c990ca6477a6f631ca7 (patch)
treebeab23cd22497f5ba771ed720a2319bc914fd212
parent53bbe915ab117c8d0c46aea5131ce48801d322ad (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.c12
-rw-r--r--sys/arch/amd64/amd64/identcpu.c69
-rw-r--r--sys/arch/amd64/include/cpu.h5
-rw-r--r--sys/arch/amd64/include/specialreg.h6
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 */