On Ryzen CPUs each CCD has a temp sensor. If the CPU has CCDs (which excludes Zen APU CPUs) this should show additional temp info. This is based on info from the Linux k10temp driver.
Additionally use the MSRs defined in "Open-Source Register Reference For AMD Family 17h Processors" to measure the CPU core frequency. That should be the actuall speed of the CPU core during the measuring interval. On my T14g2 the output is now for example: ksmn0.temp0 63.88 degC Tctl ksmn0.frequency0 3553141515.00 Hz CPU0 ksmn0.frequency1 3549080315.00 Hz CPU2 ksmn0.frequency2 3552369937.00 Hz CPU4 ksmn0.frequency3 3546055048.00 Hz CPU6 ksmn0.frequency4 3546854449.00 Hz CPU8 ksmn0.frequency5 3543869698.00 Hz CPU10 ksmn0.frequency6 3542551127.00 Hz CPU12 ksmn0.frequency7 4441623647.00 Hz CPU14 It is intresting to watch turbo kick in and how temp causes the CPU to throttle. I only tested this on systems with APUs so I could not thest the Tccd temp reporting. -- :wq Claudio Index: ksmn.c =================================================================== RCS file: /cvs/src/sys/dev/pci/ksmn.c,v retrieving revision 1.6 diff -u -p -r1.6 ksmn.c --- ksmn.c 11 Mar 2022 18:00:50 -0000 1.6 +++ ksmn.c 24 Apr 2022 16:47:08 -0000 @@ -20,6 +20,7 @@ #include <sys/systm.h> #include <sys/device.h> #include <sys/sensors.h> +#include <sys/timeout.h> #include <machine/bus.h> @@ -42,6 +43,7 @@ * [31:21] Current reported temperature. */ #define SMU_17H_THM 0x59800 +#define SMU_17H_CCD_THM(o, x) (SMU_17H_THM + (o) + ((x) * 4)) #define GET_CURTMP(r) (((r) >> 21) & 0x7ff) /* @@ -50,6 +52,8 @@ */ #define CURTMP_17H_RANGE_SEL (1 << 19) #define CURTMP_17H_RANGE_ADJUST 490 +#define CURTMP_CCD_VALID (1 << 11) +#define CURTMP_CCD_MASK 0x7ff /* * Undocumented tCTL offsets gleamed from Linux k10temp driver. @@ -75,13 +79,24 @@ struct ksmn_softc { pcitag_t sc_pcitag; int sc_tctl_offset; + unsigned int sc_ccd_valid; /* available Tccds */ + unsigned int sc_ccd_offset; + int sc_hz_count; - struct ksensor sc_sensor; struct ksensordev sc_sensordev; + struct ksensor sc_sensor; /* Tctl */ + struct ksensor sc_ccd_sensor[12]; /* Tccd */ + + struct timeout sc_hz_timeout; + struct ksensor *sc_hz_sensor; + struct cpu_info **sc_hz_cpu_info; }; int ksmn_match(struct device *, void *, void *); void ksmn_attach(struct device *, struct device *, void *); +uint32_t ksmn_read_reg(struct ksmn_softc *, uint32_t); +void ksmn_ccd_attach(struct ksmn_softc *, int); +void ksmn_hz_task(void *); void ksmn_refresh(void *); const struct cfattach ksmn_ca = { @@ -113,7 +128,12 @@ ksmn_attach(struct device *parent, struc struct ksmn_softc *sc = (struct ksmn_softc *)self; struct pci_attach_args *pa = aux; struct curtmp_offset *p; - extern char cpu_model[]; + CPU_INFO_ITERATOR cii; + struct cpu_info *ci = curcpu(); + struct ksensor *s; + extern char cpu_model[]; + int i; + sc->sc_pc = pa->pa_pc; sc->sc_pcitag = pa->pa_tag; @@ -122,6 +142,7 @@ ksmn_attach(struct device *parent, struc sizeof(sc->sc_sensordev.xname)); sc->sc_sensor.type = SENSOR_TEMP; + snprintf(sc->sc_sensor.desc, sizeof(sc->sc_sensor.desc), "Tctl"); sensor_attach(&sc->sc_sensordev, &sc->sc_sensor); /* @@ -136,6 +157,80 @@ ksmn_attach(struct device *parent, struc sc->sc_tctl_offset = p->tctl_offset; } + sc->sc_ccd_offset = 0x154; + + if (ci->ci_family == 0x17 || ci->ci_family == 0x18) { + switch (ci->ci_model) { + case 0x1: /* Zen */ + case 0x8: /* Zen+ */ + case 0x11: /* Zen APU */ + case 0x18: /* Zen+ APU */ + ksmn_ccd_attach(sc, 4); + break; + case 0x31: /* Zen2 Threadripper */ + case 0x60: /* Renoir */ + case 0x68: /* Lucienne */ + case 0x71: /* Zen2 */ + ksmn_ccd_attach(sc, 8); + break; + } + } else if (ci->ci_family == 0x19) { + uint32_t m = ci->ci_model; + + if ((m >= 0x40 && m <= 0x4f) || + (m >= 0x10 && m <= 0x1f) || + (m >= 0xa0 && m <= 0xaf)) + sc->sc_ccd_offset = 0x300; + + if ((m >= 0x10 && m <= 0x1f) || + (m >= 0xa0 && m <= 0xaf)) + ksmn_ccd_attach(sc, 12); + else + ksmn_ccd_attach(sc, 8); + } + + CPU_INFO_FOREACH(cii, ci) { + if (ci->ci_smt_id != 0) + continue; + sc->sc_hz_count++; + } + sc->sc_hz_sensor = mallocarray(sc->sc_hz_count, + sizeof(*sc->sc_hz_sensor), M_DEVBUF, M_WAITOK | M_ZERO); + sc->sc_hz_cpu_info = mallocarray(sc->sc_hz_count, + sizeof(*sc->sc_hz_cpu_info), M_DEVBUF, M_WAITOK | M_ZERO); + + i = 0; + CPU_INFO_FOREACH(cii, ci) { + if (ci->ci_smt_id != 0) + continue; + sc->sc_hz_cpu_info[i] = ci; + i++; + } + /* sort list of CPUs */ + for (i = 1; i < sc->sc_hz_count; i++) { + int j; + for (j = 0; j < sc->sc_hz_count - i; j++) { + if (CPU_INFO_UNIT(sc->sc_hz_cpu_info[j]) > + CPU_INFO_UNIT(sc->sc_hz_cpu_info[j + 1])) { + ci = sc->sc_hz_cpu_info[j]; + sc->sc_hz_cpu_info[j] = + sc->sc_hz_cpu_info[j + 1]; + sc->sc_hz_cpu_info[j + 1] = ci; + } + } + } + + for (i = 0; i < sc->sc_hz_count; i++) { + ci = sc->sc_hz_cpu_info[i]; + s = &sc->sc_hz_sensor[i]; + s->type = SENSOR_FREQ; + snprintf(s->desc, sizeof(s->desc), "CPU%d", CPU_INFO_UNIT(ci)); + sensor_attach(&sc->sc_sensordev, &sc->sc_hz_sensor[i]); + } + + timeout_set_proc(&sc->sc_hz_timeout, ksmn_hz_task, sc); + timeout_add_sec(&sc->sc_hz_timeout, 1); + if (sensor_task_register(sc, ksmn_refresh, 5) == NULL) { printf(": unable to register update task\n"); return; @@ -146,18 +241,78 @@ ksmn_attach(struct device *parent, struc printf("\n"); } +uint32_t +ksmn_read_reg(struct ksmn_softc *sc, uint32_t addr) +{ + uint32_t reg; + int s; + + s = splhigh(); + pci_conf_write(sc->sc_pc, sc->sc_pcitag, SMN_17H_ADDR_R, addr); + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, SMN_17H_DATA_R); + splx(s); + return reg; +} + +void +ksmn_ccd_attach(struct ksmn_softc *sc, int nccd) +{ + struct ksensor *s; + uint32_t reg; + int i; + + KASSERT(nccd > 0 && nccd < nitems(sc->sc_ccd_sensor)); + + for (i = 0; i < nccd; i++) { + reg = ksmn_read_reg(sc, SMU_17H_CCD_THM(sc->sc_ccd_offset, i)); + if (reg & CURTMP_CCD_VALID) { + sc->sc_ccd_valid |= (1 << i); + s = &sc->sc_ccd_sensor[i]; + s->type = SENSOR_TEMP; + snprintf(s->desc, sizeof(s->desc), "Tccd%d", i); + sensor_attach(&sc->sc_sensordev, s); + } + } +} + +void +ksmn_hz_task(void *arg) +{ + extern uint64_t tsc_frequency; + struct ksmn_softc *sc = arg; + struct cpu_info *ci; + struct ksensor *sens; + uint64_t mperf, aperf; + int i, s; + + for (i = 0; i < sc->sc_hz_count; i++) { + ci = sc->sc_hz_cpu_info[i]; + sens = &sc->sc_hz_sensor[i]; + if (!CPU_IS_RUNNING(ci)) + continue; + sched_peg_curproc(ci); + + s = splhigh(); + mperf = rdmsr(0xE7); + aperf = rdmsr(0xE8); + wrmsr(0xE7, 0); + wrmsr(0xE8, 0); + splx(s); + sens->value = ((aperf * tsc_frequency) / mperf) * 1000000; + } + + timeout_add_sec(&sc->sc_hz_timeout, 1); +} + void ksmn_refresh(void *arg) { struct ksmn_softc *sc = arg; struct ksensor *s = &sc->sc_sensor; pcireg_t reg; - int raw, offset = 0; - - pci_conf_write(sc->sc_pc, sc->sc_pcitag, SMN_17H_ADDR_R, - SMU_17H_THM); - reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, SMN_17H_DATA_R); + int i, raw, offset = 0; + reg = ksmn_read_reg(sc, SMU_17H_THM); raw = GET_CURTMP(reg); if ((reg & CURTMP_17H_RANGE_SEL) != 0) offset -= CURTMP_17H_RANGE_ADJUST; @@ -166,5 +321,16 @@ ksmn_refresh(void *arg) offset *= 100000; /* convert raw (in steps of 0.125C) to uC, add offset, uC to uK. */ - s->value = ((raw * 125000) + offset) + 273150000; + s->value = raw * 125000 + offset + 273150000; + + offset = CURTMP_17H_RANGE_ADJUST * 100000; + for (i = 0; i < nitems(sc->sc_ccd_sensor); i++) { + if (sc->sc_ccd_valid & (1 << i)) { + s = &sc->sc_ccd_sensor[i]; + reg = ksmn_read_reg(sc, + SMU_17H_CCD_THM(sc->sc_ccd_offset, i)); + s->value = (reg & CURTMP_CCD_MASK) * 125000 - offset + + 273150000; + } + } }