diff mbox series

[08/11] PM: EM: Implement EM_GENL_CMD_PD_GET_ID.

Message ID 20250529001315.233492-9-changwoo@igalia.com
State New
Headers show
Series [01/11] PM: EM: Add ENERGY_MODEL_NETLINK Kconfig. | expand

Commit Message

Changwoo Min May 29, 2025, 12:13 a.m. UTC
When a userspace requests EM_GENL_CMD_PD_GET_ID, the kernel responds with
information on all performance domains. The message format of the response
is as follows:

EM_GENL_ATTR_PD (NLA_NESTED)
	EM_PD_ENTRY_GENL_ATTR_PD (NLA_NESTED)*
		EM_PD_GENL_ATTR_ID (NLA_U32)
		EM_PD_GENL_ATTR_FLAGS (NLA_U64)
		EM_PD_GENL_ATTR_CPUS (NLA_STRING)

Where EM_PD_ENTRY_GENL_ATTR_PD can be repeated as many times as there are
performance domains, and EM_PD_GENL_ATTR_CPUS is a hexadecimal string
representing a CPU bitmask.

Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
 include/uapi/linux/energy_model.h | 25 ++++++++++++++
 kernel/power/em_netlink.c         | 55 ++++++++++++++++++++++++++++++-
 2 files changed, 79 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/include/uapi/linux/energy_model.h b/include/uapi/linux/energy_model.h
index 42a19e614c7d..66339ace6fcb 100644
--- a/include/uapi/linux/energy_model.h
+++ b/include/uapi/linux/energy_model.h
@@ -10,10 +10,35 @@ 
 /* Attributes of em_genl_family */
 enum em_genl_attr {
 	EM_GENL_ATTR_UNSPEC,
+	EM_GENL_ATTR_PAD = EM_GENL_ATTR_UNSPEC,
+	EM_GENL_ATTR_PD,	/* Performance domain */
 	__EM_GENL_ATTR_MAX,
 };
 #define EM_GENL_ATTR_MAX (__EM_GENL_ATTR_MAX - 1)
 
+enum em_pd_entry_genl_attr {
+	EM_PD_ENTRY_GENL_ATTR_UNSPEC,
+	EM_PD_ENTRY_GENL_ATTR_PAD = EM_PD_ENTRY_GENL_ATTR_UNSPEC,
+	EM_PD_ENTRY_GENL_ATTR_PD,
+	__EM_PD_ENTRY_GENL_ATTR_MAX,
+};
+#define EM_PD_ENTRY_GENL_ATTR_MAX (__EM_PD_ENTRY_GENL_ATTR_MAX - 1)
+
+enum em_pd_genl_attr {
+	EM_PD_GENL_ATTR_UNSPEC,
+	EM_PD_GENL_ATTR_PAD = EM_PD_GENL_ATTR_UNSPEC,
+
+	/* Performance domain */
+	EM_PD_GENL_ATTR_ID,
+	EM_PD_GENL_ATTR_FLAGS,
+	EM_PD_GENL_ATTR_CPUS,
+
+	__EM_PD_GENL_ATTR_MAX,
+};
+#define EM_PD_GENL_ATTR_MAX (__EM_PD_GENL_ATTR_MAX - 1)
+
+#define EM_PD_CPUS_LENGTH		256
+
 /* Events of em_genl_family */
 enum em_genl_event {
 	EM_GENL_EVENT_UNSPEC,
diff --git a/kernel/power/em_netlink.c b/kernel/power/em_netlink.c
index edbaecebd0b4..ea975ca6272f 100644
--- a/kernel/power/em_netlink.c
+++ b/kernel/power/em_netlink.c
@@ -21,6 +21,8 @@  static const struct genl_multicast_group em_genl_mcgrps[] = {
 };
 
 static const struct nla_policy em_genl_policy[EM_GENL_ATTR_MAX + 1] = {
+	/* Performance domain */
+	[EM_GENL_ATTR_PD]			= { .type = NLA_NESTED },
 };
 
 struct param {
@@ -34,9 +36,60 @@  static struct genl_family em_genl_family;
 
 /*************************** Command encoding ********************************/
 
+static int __em_genl_cmd_pd_get_id(struct em_perf_domain *pd, void *data)
+{
+	char cpus_buf[EM_PD_CPUS_LENGTH];
+	struct sk_buff *msg = data;
+	struct nlattr *entry;
+
+	entry = nla_nest_start(msg, EM_PD_ENTRY_GENL_ATTR_PD);
+	if (!entry)
+		goto out_cancel_nest;
+
+	if (nla_put_u32(msg, EM_PD_GENL_ATTR_ID, pd->id))
+		goto out_cancel_nest;
+
+	if (nla_put_u64_64bit(msg, EM_PD_GENL_ATTR_FLAGS, pd->flags,
+			      EM_PD_GENL_ATTR_PAD))
+		goto out_cancel_nest;
+
+	snprintf(cpus_buf, sizeof(cpus_buf), "%*pb",
+		 cpumask_pr_args(to_cpumask(pd->cpus)));
+	if (nla_put_string(msg, EM_PD_GENL_ATTR_CPUS, cpus_buf))
+		goto out_cancel_nest;
+
+	nla_nest_end(msg, entry);
+
+	return 0;
+
+out_cancel_nest:
+	nla_nest_cancel(msg, entry);
+
+	return -EMSGSIZE;
+}
+
 static int em_genl_cmd_pd_get_id(struct param *p)
 {
-	return -ENOTSUPP;
+	struct sk_buff *msg = p->msg;
+	struct nlattr *start_pd;
+	int ret;
+
+	start_pd = nla_nest_start(msg, EM_GENL_ATTR_PD);
+	if (!start_pd)
+		return -EMSGSIZE;
+
+	ret = for_each_em_perf_domain(__em_genl_cmd_pd_get_id, msg);
+	if (ret)
+		goto out_cancel_nest;
+
+	nla_nest_end(msg, start_pd);
+
+	return 0;
+
+out_cancel_nest:
+	nla_nest_cancel(msg, start_pd);
+
+	return ret;
 }
 
 static int em_genl_cmd_pd_get_tbl(struct param *p)