After I sent out my ksmn(4) diff to include cpu frequency sensors dlg@ told me that this is a generic way to find the cpu frequency on modern x86 cpus (both intel and amd support it).
So this diff cleans up the CPU frequency sensors and moves them to the cpu(4). I had to split the sensor attachement up since sensordev_install() calls into hotplug which does a selwakeup() and that call locks up (I guess it is the KERNEL_LOCK()). Moving that part of the code to cpu_attach() makes the problem go away. Tested on a AMD Ryzen Pro 5850U and an Intel Core i7-7500U. -- :wq Claudio Index: arch/amd64/amd64/cpu.c =================================================================== RCS file: /cvs/src/sys/arch/amd64/amd64/cpu.c,v retrieving revision 1.155 diff -u -p -r1.155 cpu.c --- arch/amd64/amd64/cpu.c 21 Feb 2022 11:03:39 -0000 1.155 +++ arch/amd64/amd64/cpu.c 25 Apr 2022 13:56:28 -0000 @@ -558,6 +558,11 @@ cpu_attach(struct device *parent, struct 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 #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 Index: arch/amd64/amd64/identcpu.c =================================================================== RCS file: /cvs/src/sys/arch/amd64/amd64/identcpu.c,v retrieving revision 1.122 diff -u -p -r1.122 identcpu.c --- arch/amd64/amd64/identcpu.c 20 Jan 2022 11:06:57 -0000 1.122 +++ arch/amd64/amd64/identcpu.c 25 Apr 2022 13:55:33 -0000 @@ -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 Index: arch/amd64/include/cpu.h =================================================================== RCS file: /cvs/src/sys/arch/amd64/include/cpu.h,v retrieving revision 1.141 diff -u -p -r1.141 cpu.h --- arch/amd64/include/cpu.h 31 Aug 2021 17:40:59 -0000 1.141 +++ arch/amd64/include/cpu.h 25 Apr 2022 11:11:47 -0000 @@ -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 Index: arch/amd64/include/specialreg.h =================================================================== RCS file: /cvs/src/sys/arch/amd64/include/specialreg.h,v retrieving revision 1.91 diff -u -p -r1.91 specialreg.h --- arch/amd64/include/specialreg.h 19 Nov 2021 04:00:53 -0000 1.91 +++ arch/amd64/include/specialreg.h 25 Apr 2022 11:16:43 -0000 @@ -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 */