diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2023-11-23 00:47:14 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2023-11-23 00:47:14 +0000 |
commit | 4dc1f9bbd45521b158d0d28024c5389dcb0dcbcc (patch) | |
tree | a30ab45bb3001f97f793ab715b3c6f333788e771 /sys | |
parent | bdb693686b0886a864191d2787015f68f1d9552e (diff) |
expose the state of thermal zones as kstats.
this makes it a bit more obvious how much head room you have for
things like cpu performance scaling.
the information provided at the moment is more useful for developers
working on cpu scaling, but it should improve as i get my head
around more of these things.
patrick@ and kettenis@ like the idea.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/ofw/ofw_thermal.c | 164 |
1 files changed, 155 insertions, 9 deletions
diff --git a/sys/dev/ofw/ofw_thermal.c b/sys/dev/ofw/ofw_thermal.c index e8531d5ae43..5c42992407c 100644 --- a/sys/dev/ofw/ofw_thermal.c +++ b/sys/dev/ofw/ofw_thermal.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ofw_thermal.c,v 1.7 2020/12/31 11:11:22 kettenis Exp $ */ +/* $OpenBSD: ofw_thermal.c,v 1.8 2023/11/23 00:47:13 dlg Exp $ */ /* * Copyright (c) 2019 Mark Kettenis * @@ -15,12 +15,16 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "kstat.h" + #include <sys/types.h> #include <sys/systm.h> #include <sys/malloc.h> #include <sys/stdint.h> #include <sys/task.h> #include <sys/timeout.h> +#include <sys/sched.h> +#include <sys/kstat.h> #include <machine/bus.h> @@ -36,6 +40,7 @@ LIST_HEAD(, cooling_device) cooling_devices = struct taskq *tztq; struct trippoint { + int tp_node; int32_t tp_temperature; uint32_t tp_hysteresis; int tp_type; @@ -48,6 +53,14 @@ struct trippoint { #define THERMAL_HOT 3 #define THERMAL_CRITICAL 4 +static const char *trip_types[] = { + [THERMAL_NONE] = "none", + [THERMAL_ACTIVE] = "active", + [THERMAL_PASSIVE] = "passive", + [THERMAL_HOT] = "hot", + [THERMAL_CRITICAL] = "critical", +}; + struct cmap { uint32_t *cm_cdev; uint32_t *cm_cdevend; @@ -82,8 +95,16 @@ struct thermal_zone { LIST_HEAD(, cdev) tz_cdevs; int32_t tz_temperature; + + struct rwlock tz_lock; + struct kstat *tz_kstat; }; +#if NKSTAT > 0 +static void thermal_zone_kstat_attach(struct thermal_zone *); +static void thermal_zone_kstat_update(struct thermal_zone *); +#endif /* NKSTAT > 0 */ + LIST_HEAD(, thermal_zone) thermal_zones = LIST_HEAD_INITIALIZER(thermal_zones); @@ -324,6 +345,9 @@ thermal_zone_poll(void *arg) out: tz->tz_temperature = temp; +#if NKSTAT > 0 + thermal_zone_kstat_update(tz); +#endif if (tz->tz_tp && tz->tz_tp->tp_type == THERMAL_PASSIVE) polling_delay = tz->tz_polling_delay_passive; else @@ -331,6 +355,23 @@ out: timeout_add_msec(&tz->tz_poll_to, polling_delay); } +static int +thermal_zone_triptype(const char *prop) +{ + size_t i; + + for (i = 0; i < nitems(trip_types); i++) { + const char *name = trip_types[i]; + if (name == NULL) + continue; + + if (strcmp(name, prop) == 0) + return (i); + } + + return (THERMAL_NONE); +} + void thermal_zone_init(int node) { @@ -351,6 +392,7 @@ thermal_zone_init(int node) tz = malloc(sizeof(struct thermal_zone), M_DEVBUF, M_ZERO | M_WAITOK); tz->tz_node = node; + rw_init(&tz->tz_lock, "tzlk"); OF_getprop(node, "name", &tz->tz_name, sizeof(tz->tz_name)); tz->tz_name[sizeof(tz->tz_name) - 1] = 0; @@ -394,17 +436,11 @@ thermal_zone_init(int node) break; } tp = &tz->tz_trips[i]; + tp->tp_node = node; tp->tp_temperature = temp; tp->tp_hysteresis = OF_getpropint(node, "hysteresis", 0); OF_getprop(node, "type", type, sizeof(type)); - if (strcmp(type, "active") == 0) - tp->tp_type = THERMAL_ACTIVE; - else if (strcmp(type, "passive") == 0) - tp->tp_type = THERMAL_PASSIVE; - else if (strcmp(type, "hot") == 0) - tp->tp_type = THERMAL_HOT; - else if (strcmp(type, "critical") == 0) - tp->tp_type = THERMAL_CRITICAL; + tp->tp_type = thermal_zone_triptype(type); tp->tp_phandle = OF_getpropint(node, "phandle", 0); tp++; } @@ -465,6 +501,10 @@ thermal_zone_init(int node) if (tz->tz_polling_delay > 0) timeout_add_msec(&tz->tz_poll_to, tz->tz_polling_delay); LIST_INSERT_HEAD(&thermal_zones, tz, tz_list); + +#if NKSTAT > 0 + thermal_zone_kstat_attach(tz); +#endif } void @@ -480,3 +520,109 @@ thermal_init(void) for (node = OF_child(node); node != 0; node = OF_peer(node)) thermal_zone_init(node); } + +#if NKSTAT > 0 + +static const char * +thermal_zone_tripname(int type) +{ + if (type >= nitems(trip_types)) + return (NULL); + + return (trip_types[type]); +} + +struct thermal_zone_kstats { + struct kstat_kv tzk_name; /* istr could be short */ + struct kstat_kv tzk_temp; + struct kstat_kv tzk_tp; + struct kstat_kv tzk_tp_type; + struct kstat_kv tzk_cooling; +}; + +static void +thermal_zone_kstat_update(struct thermal_zone *tz) +{ + struct kstat *ks = tz->tz_kstat; + struct thermal_zone_kstats *tzk; + + if (ks == NULL) + return; + + tzk = ks->ks_data; + + rw_enter_write(&tz->tz_lock); + if (tz->tz_temperature == THERMAL_SENSOR_MAX) + tzk->tzk_temp.kv_type = KSTAT_KV_T_NULL; + else { + tzk->tzk_temp.kv_type = KSTAT_KV_T_TEMP; + kstat_kv_temp(&tzk->tzk_temp) = 273150000 + + 1000 * tz->tz_temperature; + } + + if (tz->tz_tp == NULL) { + kstat_kv_u32(&tzk->tzk_tp) = 0; + strlcpy(kstat_kv_istr(&tzk->tzk_tp_type), "none", + sizeof(kstat_kv_istr(&tzk->tzk_tp_type))); + } else { + int triptype = tz->tz_tp->tp_type; + const char *tripname = thermal_zone_tripname(triptype); + + kstat_kv_u32(&tzk->tzk_tp) = tz->tz_tp->tp_node; + + if (tripname == NULL) { + snprintf(kstat_kv_istr(&tzk->tzk_tp_type), + sizeof(kstat_kv_istr(&tzk->tzk_tp_type)), + "%u", triptype); + } else { + strlcpy(kstat_kv_istr(&tzk->tzk_tp_type), tripname, + sizeof(kstat_kv_istr(&tzk->tzk_tp_type))); + } + } + + kstat_kv_bool(&tzk->tzk_cooling) = (tz->tz_cm != NULL); + + getnanouptime(&ks->ks_updated); + rw_exit_write(&tz->tz_lock); +} + +static void +thermal_zone_kstat_attach(struct thermal_zone *tz) +{ + struct kstat *ks; + struct thermal_zone_kstats *tzk; + static unsigned int unit = 0; + + ks = kstat_create("dt", 0, "thermal-zone", unit++, KSTAT_T_KV, 0); + if (ks == NULL) { + printf("unable to create thermal-zone kstats for %s", + tz->tz_name); + return; + } + + tzk = malloc(sizeof(*tzk), M_DEVBUF, M_WAITOK|M_ZERO); + + kstat_kv_init(&tzk->tzk_name, "name", KSTAT_KV_T_ISTR); + strlcpy(kstat_kv_istr(&tzk->tzk_name), tz->tz_name, + sizeof(kstat_kv_istr(&tzk->tzk_name))); + kstat_kv_init(&tzk->tzk_temp, "temperature", KSTAT_KV_T_NULL); + + /* XXX dt node is not be the most useful info here. */ + kstat_kv_init(&tzk->tzk_tp, "trip-point-node", KSTAT_KV_T_UINT32); + kstat_kv_init(&tzk->tzk_tp_type, "trip-type", KSTAT_KV_T_ISTR); + strlcpy(kstat_kv_istr(&tzk->tzk_tp_type), "unknown", + sizeof(kstat_kv_istr(&tzk->tzk_tp_type))); + + kstat_kv_init(&tzk->tzk_cooling, "active-cooling", KSTAT_KV_T_BOOL); + kstat_kv_bool(&tzk->tzk_cooling) = 0; + + ks->ks_softc = tz; + ks->ks_data = tzk; + ks->ks_datalen = sizeof(*tzk); + ks->ks_read = kstat_read_nop; + kstat_set_rlock(ks, &tz->tz_lock); + + tz->tz_kstat = ks; + kstat_install(ks); +} +#endif /* NKSTAT > 0 */ |