> Date: Mon, 25 Apr 2022 16:19:45 +0200 > From: Claudio Jeker <cje...@diehard.n-r-g.com> > > 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.
Yes, that looks much better. ok kettenis@ > 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 */ > >