|
|
8dca8a |
From 560291389e33db108d2fb6d954ef059f953c6e33 Mon Sep 17 00:00:00 2001
|
|
|
8dca8a |
From: "Chang S. Bae" <chang.seok.bae@intel.com>
|
|
|
8dca8a |
Date: Fri, 11 Feb 2022 13:48:01 -0800
|
|
|
8dca8a |
Subject: [PATCH 06/14] Handle thermal events to mask CPUs
|
|
|
8dca8a |
|
|
|
8dca8a |
The Hardware Feedback Interface event is delivered as the Netlink's
|
|
|
8dca8a |
THERMAL_GENL_ATTR_CPU_CAPABILITY attribute. Add code to receive and parse
|
|
|
8dca8a |
these attributes: logical CPU number, performance, and efficiency
|
|
|
8dca8a |
enumeration values (0-1023).
|
|
|
8dca8a |
|
|
|
8dca8a |
When an event indicates CPU performance and efficiency are zeros, then the
|
|
|
8dca8a |
CPU needs to be banned from IRQs. Rebuild object tree to make this banned
|
|
|
8dca8a |
list effective.
|
|
|
8dca8a |
|
|
|
8dca8a |
Creating the banned CPU list here is a bit tricky here because the amount
|
|
|
8dca8a |
of data that each Netlink notification can carry out is not enough in some
|
|
|
8dca8a |
systems with many cores. This means the handler has to wait for multiple
|
|
|
8dca8a |
notifications to determine banned CPUs per thermal event.
|
|
|
8dca8a |
|
|
|
8dca8a |
Establish a logic to maintain the list based on the kernel behaviors. Also,
|
|
|
8dca8a |
always push the current list as of the banned CPUs, because there is no
|
|
|
8dca8a |
clear line whether each notification is at the end of a thermal event or
|
|
|
8dca8a |
not.
|
|
|
8dca8a |
|
|
|
8dca8a |
Signed-off-by: Chang S. Bae <chang.seok.bae@intel.com>
|
|
|
8dca8a |
---
|
|
|
8dca8a |
thermal.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++---
|
|
|
8dca8a |
1 file changed, 165 insertions(+), 7 deletions(-)
|
|
|
8dca8a |
|
|
|
8dca8a |
diff --git a/thermal.c b/thermal.c
|
|
|
8dca8a |
index 16a6f39..64a9cdf 100644
|
|
|
8dca8a |
--- a/thermal.c
|
|
|
8dca8a |
+++ b/thermal.c
|
|
|
8dca8a |
@@ -6,6 +6,7 @@
|
|
|
8dca8a |
|
|
|
8dca8a |
#include <stdio.h>
|
|
|
8dca8a |
|
|
|
8dca8a |
+#include <sys/sysinfo.h>
|
|
|
8dca8a |
#include <netlink/genl/genl.h>
|
|
|
8dca8a |
#include <netlink/genl/family.h>
|
|
|
8dca8a |
#include <netlink/genl/ctrl.h>
|
|
|
8dca8a |
@@ -14,8 +15,62 @@
|
|
|
8dca8a |
|
|
|
8dca8a |
cpumask_t thermal_banned_cpus;
|
|
|
8dca8a |
|
|
|
8dca8a |
-#define INVALID_NL_FD -1
|
|
|
8dca8a |
-#define MAX_RECV_ERRS 2
|
|
|
8dca8a |
+/* Events of thermal_genl_family */
|
|
|
8dca8a |
+enum thermal_genl_event {
|
|
|
8dca8a |
+ THERMAL_GENL_EVENT_UNSPEC,
|
|
|
8dca8a |
+ THERMAL_GENL_EVENT_TZ_CREATE, /* Thermal zone creation */
|
|
|
8dca8a |
+ THERMAL_GENL_EVENT_TZ_DELETE, /* Thermal zone deletion */
|
|
|
8dca8a |
+ THERMAL_GENL_EVENT_TZ_DISABLE, /* Thermal zone disabled */
|
|
|
8dca8a |
+ THERMAL_GENL_EVENT_TZ_ENABLE, /* Thermal zone enabled */
|
|
|
8dca8a |
+ THERMAL_GENL_EVENT_TZ_TRIP_UP, /* Trip point crossed the way up */
|
|
|
8dca8a |
+ THERMAL_GENL_EVENT_TZ_TRIP_DOWN, /* Trip point crossed the way down */
|
|
|
8dca8a |
+ THERMAL_GENL_EVENT_TZ_TRIP_CHANGE, /* Trip point changed */
|
|
|
8dca8a |
+ THERMAL_GENL_EVENT_TZ_TRIP_ADD, /* Trip point added */
|
|
|
8dca8a |
+ THERMAL_GENL_EVENT_TZ_TRIP_DELETE, /* Trip point deleted */
|
|
|
8dca8a |
+ THERMAL_GENL_EVENT_CDEV_ADD, /* Cdev bound to the thermal zone */
|
|
|
8dca8a |
+ THERMAL_GENL_EVENT_CDEV_DELETE, /* Cdev unbound */
|
|
|
8dca8a |
+ THERMAL_GENL_EVENT_CDEV_STATE_UPDATE, /* Cdev state updated */
|
|
|
8dca8a |
+ THERMAL_GENL_EVENT_TZ_GOV_CHANGE, /* Governor policy changed */
|
|
|
8dca8a |
+ THERMAL_GENL_EVENT_CAPACITY_CHANGE, /* CPU capacity changed */
|
|
|
8dca8a |
+ __THERMAL_GENL_EVENT_MAX,
|
|
|
8dca8a |
+};
|
|
|
8dca8a |
+#define THERMAL_GENL_EVENT_MAX (__THERMAL_GENL_EVENT_MAX - 1)
|
|
|
8dca8a |
+
|
|
|
8dca8a |
+/* Attributes of thermal_genl_family */
|
|
|
8dca8a |
+enum thermal_genl_attr {
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_UNSPEC,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_TZ,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_TZ_ID,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_TZ_TEMP,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_TZ_TRIP,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_TZ_TRIP_ID,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_TZ_TRIP_TYPE,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_TZ_TRIP_TEMP,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_TZ_TRIP_HYST,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_TZ_MODE,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_TZ_NAME,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_TZ_CDEV_WEIGHT,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_TZ_GOV,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_TZ_GOV_NAME,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_CDEV,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_CDEV_ID,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_CDEV_CUR_STATE,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_CDEV_MAX_STATE,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_CDEV_NAME,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_GOV_NAME,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_CAPACITY,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_CAPACITY_CPU_COUNT,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_CAPACITY_CPU_ID,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_CAPACITY_CPU_PERF,
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_CAPACITY_CPU_EFF,
|
|
|
8dca8a |
+ __THERMAL_GENL_ATTR_MAX,
|
|
|
8dca8a |
+};
|
|
|
8dca8a |
+#define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1)
|
|
|
8dca8a |
+
|
|
|
8dca8a |
+#define INVALID_NL_FD -1
|
|
|
8dca8a |
+#define MAX_RECV_ERRS 2
|
|
|
8dca8a |
+#define SYSCONF_ERR -1
|
|
|
8dca8a |
+#define INVALID_EVENT_VALUE -1
|
|
|
8dca8a |
|
|
|
8dca8a |
#define THERMAL_GENL_FAMILY_NAME "thermal"
|
|
|
8dca8a |
#define THERMAL_GENL_EVENT_GROUP_NAME "event"
|
|
|
8dca8a |
@@ -254,17 +309,115 @@ err_out:
|
|
|
8dca8a |
return error;
|
|
|
8dca8a |
}
|
|
|
8dca8a |
|
|
|
8dca8a |
-static int handle_thermal_event(struct nl_msg *msg __attribute__((unused)),
|
|
|
8dca8a |
- void *arg __attribute__((unused)))
|
|
|
8dca8a |
+enum {
|
|
|
8dca8a |
+ INDEX_CPUNUM,
|
|
|
8dca8a |
+ INDEX_PERF,
|
|
|
8dca8a |
+ INDEX_EFFI,
|
|
|
8dca8a |
+ INDEX_MAX
|
|
|
8dca8a |
+};
|
|
|
8dca8a |
+
|
|
|
8dca8a |
+/*
|
|
|
8dca8a |
+ * Single netlink notification is not guaranteed to fully deliver all of
|
|
|
8dca8a |
+ * the CPU updates per thermal event, due to the implementation choice in
|
|
|
8dca8a |
+ * the kernel code. So, this function is intended to manage a CPU list in a
|
|
|
8dca8a |
+ * stream of relevant notifications.
|
|
|
8dca8a |
+ */
|
|
|
8dca8a |
+static void update_banned_cpus(int cur_cpuidx, gboolean need_to_ban)
|
|
|
8dca8a |
{
|
|
|
8dca8a |
- log(TO_ALL, LOG_ERR, "thermal: not yet implemented to process thermal event.\n");
|
|
|
8dca8a |
- return NL_SKIP;
|
|
|
8dca8a |
+ static cpumask_t banmask = { 0 }, itrmask = { 0 };
|
|
|
8dca8a |
+ long max_cpunum = sysconf(_SC_NPROCESSORS_ONLN);
|
|
|
8dca8a |
+
|
|
|
8dca8a |
+ if (need_to_ban)
|
|
|
8dca8a |
+ cpu_set(cur_cpuidx, banmask);
|
|
|
8dca8a |
+
|
|
|
8dca8a |
+ cpu_set(cur_cpuidx, itrmask);
|
|
|
8dca8a |
+ if (cpus_weight(itrmask) < max_cpunum)
|
|
|
8dca8a |
+ return;
|
|
|
8dca8a |
+
|
|
|
8dca8a |
+ if (cpus_equal(thermal_banned_cpus, banmask))
|
|
|
8dca8a |
+ goto out;
|
|
|
8dca8a |
+
|
|
|
8dca8a |
+ cpus_copy(thermal_banned_cpus, banmask);
|
|
|
8dca8a |
+ need_rescan = 1;
|
|
|
8dca8a |
+out:
|
|
|
8dca8a |
+ cpus_clear(banmask);
|
|
|
8dca8a |
+ cpus_clear(itrmask);
|
|
|
8dca8a |
+}
|
|
|
8dca8a |
+
|
|
|
8dca8a |
+static int handle_thermal_event(struct nl_msg *msg, void *arg __attribute__((unused)))
|
|
|
8dca8a |
+{
|
|
|
8dca8a |
+ int event_data[INDEX_MAX] = { INVALID_EVENT_VALUE };
|
|
|
8dca8a |
+ struct nlattr *attrs[THERMAL_GENL_ATTR_MAX + 1];
|
|
|
8dca8a |
+ struct genlmsghdr *genlhdr;
|
|
|
8dca8a |
+ struct nlmsghdr *msnlh;
|
|
|
8dca8a |
+ struct nlattr *cap;
|
|
|
8dca8a |
+ int i, remain, rc;
|
|
|
8dca8a |
+ void *pos;
|
|
|
8dca8a |
+
|
|
|
8dca8a |
+ /* get actual netlink message header */
|
|
|
8dca8a |
+ msnlh = nlmsg_hdr(msg);
|
|
|
8dca8a |
+
|
|
|
8dca8a |
+ /* get a pointer to generic netlink header */
|
|
|
8dca8a |
+ genlhdr = genlmsg_hdr(msnlh);
|
|
|
8dca8a |
+ if (genlhdr->cmd != THERMAL_GENL_EVENT_CAPACITY_CHANGE) {
|
|
|
8dca8a |
+ log(TO_ALL, LOG_DEBUG, "thermal: no CPU capacity change.\n");
|
|
|
8dca8a |
+ return NL_SKIP;
|
|
|
8dca8a |
+ }
|
|
|
8dca8a |
+
|
|
|
8dca8a |
+ /* parse generic netlink message including attributes */
|
|
|
8dca8a |
+ rc = genlmsg_parse(
|
|
|
8dca8a |
+ msnlh, /* a pointer to netlink message header */
|
|
|
8dca8a |
+ 0, /* length of user header */
|
|
|
8dca8a |
+ attrs, /* array to store parsed attributes */
|
|
|
8dca8a |
+ THERMAL_GENL_ATTR_MAX, /* maximum attribute id as expected */
|
|
|
8dca8a |
+ NULL); /* validation policy */
|
|
|
8dca8a |
+ if (rc) {
|
|
|
8dca8a |
+ log(TO_ALL, LOG_ERR, "thermal: failed to parse message for thermal event.\n");
|
|
|
8dca8a |
+ return NL_SKIP;
|
|
|
8dca8a |
+ }
|
|
|
8dca8a |
+
|
|
|
8dca8a |
+ /* get start and length of payload section */
|
|
|
8dca8a |
+ cap = attrs[THERMAL_GENL_ATTR_CAPACITY];
|
|
|
8dca8a |
+ pos = nla_data(cap);
|
|
|
8dca8a |
+ remain = nla_len(cap);
|
|
|
8dca8a |
+
|
|
|
8dca8a |
+ for (i = 0; nla_ok(pos, remain); pos = nla_next(pos, &remain), i++) {
|
|
|
8dca8a |
+ gboolean valid_event = TRUE, need_to_ban;
|
|
|
8dca8a |
+ unsigned int value = nla_get_u32(pos);
|
|
|
8dca8a |
+ int idx = i % INDEX_MAX;
|
|
|
8dca8a |
+ int cur_cpuidx;
|
|
|
8dca8a |
+
|
|
|
8dca8a |
+ event_data[idx] = value;
|
|
|
8dca8a |
+
|
|
|
8dca8a |
+ if (idx != INDEX_EFFI)
|
|
|
8dca8a |
+ continue;
|
|
|
8dca8a |
+
|
|
|
8dca8a |
+ cur_cpuidx = event_data[INDEX_CPUNUM];
|
|
|
8dca8a |
+ valid_event = !!(cur_cpuidx <= NR_CPUS);
|
|
|
8dca8a |
+ if (!valid_event) {
|
|
|
8dca8a |
+ log(TO_ALL, LOG_WARNING, "thermal: invalid event - CPU %d\n",
|
|
|
8dca8a |
+ cur_cpuidx);
|
|
|
8dca8a |
+ continue;
|
|
|
8dca8a |
+ }
|
|
|
8dca8a |
+
|
|
|
8dca8a |
+ /*
|
|
|
8dca8a |
+ * A CPU with no performance and no efficiency cannot
|
|
|
8dca8a |
+ * handle IRQs:
|
|
|
8dca8a |
+ */
|
|
|
8dca8a |
+ need_to_ban = !!(!event_data[INDEX_PERF] && !event_data[INDEX_EFFI]);
|
|
|
8dca8a |
+ update_banned_cpus(cur_cpuidx, need_to_ban);
|
|
|
8dca8a |
+
|
|
|
8dca8a |
+ log(TO_ALL, LOG_DEBUG, "thermal: event - CPU %d, efficiency %d, perf %d.\n",
|
|
|
8dca8a |
+ cur_cpuidx, event_data[INDEX_PERF], event_data[INDEX_EFFI]);
|
|
|
8dca8a |
+ }
|
|
|
8dca8a |
+
|
|
|
8dca8a |
+ return NL_OK;
|
|
|
8dca8a |
}
|
|
|
8dca8a |
|
|
|
8dca8a |
static int handler_for_debug(struct nl_msg *msg __attribute__((unused)),
|
|
|
8dca8a |
void *arg __attribute__((unused)))
|
|
|
8dca8a |
{
|
|
|
8dca8a |
- return NL_SKIP;
|
|
|
8dca8a |
+ return NL_OK;
|
|
|
8dca8a |
}
|
|
|
8dca8a |
|
|
|
8dca8a |
/*
|
|
|
8dca8a |
@@ -274,6 +427,11 @@ static gboolean register_netlink_handler(void)
|
|
|
8dca8a |
{
|
|
|
8dca8a |
int rc;
|
|
|
8dca8a |
|
|
|
8dca8a |
+ if (sysconf(_SC_NPROCESSORS_ONLN) == SYSCONF_ERR) {
|
|
|
8dca8a |
+ log(TO_ALL, LOG_ERR, "thermal: _SC_NPROCESSORS_ONLN not available.\n");
|
|
|
8dca8a |
+ return TRUE;
|
|
|
8dca8a |
+ }
|
|
|
8dca8a |
+
|
|
|
8dca8a |
rc = nl_cb_set(callback, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, handler_for_debug, NULL);
|
|
|
8dca8a |
if (rc) {
|
|
|
8dca8a |
log(TO_ALL, LOG_ERR, "thermal: debug handler registration failed.\n");
|
|
|
8dca8a |
--
|
|
|
8dca8a |
2.33.1
|
|
|
8dca8a |
|