summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2023-11-23 00:47:14 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2023-11-23 00:47:14 +0000
commit4dc1f9bbd45521b158d0d28024c5389dcb0dcbcc (patch)
treea30ab45bb3001f97f793ab715b3c6f333788e771 /sys
parentbdb693686b0886a864191d2787015f68f1d9552e (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.c164
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 */