> 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 */
> 
> 

Reply via email to