* [PATCH v2 01/10] PM: EM: Add em.yaml and autogen files.
2025-06-13 9:44 [PATCH v2 00/10] PM: EM: Add netlink support for the energy model Changwoo Min
@ 2025-06-13 9:44 ` Changwoo Min
2025-06-13 9:44 ` [PATCH v2 02/10] PM: EM: Add a skeleton code for netlink notification Changwoo Min
` (9 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Changwoo Min @ 2025-06-13 9:44 UTC (permalink / raw)
To: lukasz.luba, rafael, len.brown, pavel
Cc: christian.loehle, tj, kernel-dev, linux-pm, sched-ext,
linux-kernel, Changwoo Min
Add a generic netlink spec in YAML format and autogenerate boilerplate
code using ynl-regen.sh to introduce a generic netlink for the energy
model. It allows a userspace program to read the performance domain and
its energy model. It notifies the userspace program when a performance
domain is created or deleted or its energy model is updated through a
multicast interface.
Specifically, it supports two commands:
- EM_CMD_GET_PDS: Get the list of information for all performance
domains.
- EM_CMD_GET_PD_TABLE: Get the energy model table of a performance
domain.
Also, it supports three notification events:
- EM_CMD_PD_CREATED: When a performance domain is created.
- EM_CMD_PD_DELETED: When a performance domain is deleted.
- EM_CMD_PD_UPDATED: When the energy model table of a performance domain
is updated.
Finally, update MAINTAINERS to include new files.
Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
Documentation/netlink/specs/em.yaml | 113 ++++++++++++++++++++++++++++
MAINTAINERS | 3 +
include/uapi/linux/energy_model.h | 62 +++++++++++++++
kernel/power/em_netlink_autogen.c | 48 ++++++++++++
kernel/power/em_netlink_autogen.h | 23 ++++++
5 files changed, 249 insertions(+)
create mode 100644 Documentation/netlink/specs/em.yaml
create mode 100644 include/uapi/linux/energy_model.h
create mode 100644 kernel/power/em_netlink_autogen.c
create mode 100644 kernel/power/em_netlink_autogen.h
diff --git a/Documentation/netlink/specs/em.yaml b/Documentation/netlink/specs/em.yaml
new file mode 100644
index 000000000000..9905ca482325
--- /dev/null
+++ b/Documentation/netlink/specs/em.yaml
@@ -0,0 +1,113 @@
+# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
+
+name: em
+
+doc: |
+ Energy model netlink interface to notify its changes.
+
+protocol: genetlink
+
+uapi-header: linux/energy_model.h
+
+attribute-sets:
+ -
+ name: pds
+ attributes:
+ -
+ name: pd
+ type: nest
+ nested-attributes: pd
+ multi-attr: true
+ -
+ name: pd
+ attributes:
+ -
+ name: pad
+ type: pad
+ -
+ name: pd-id
+ type: u32
+ -
+ name: flags
+ type: u64
+ -
+ name: cpus
+ type: string
+ -
+ name: pd-table
+ attributes:
+ -
+ name: pd-id
+ type: u32
+ -
+ name: ps
+ type: nest
+ nested-attributes: ps
+ multi-attr: true
+ -
+ name: ps
+ attributes:
+ -
+ name: pad
+ type: pad
+ -
+ name: performance
+ type: u64
+ -
+ name: frequency
+ type: u64
+ -
+ name: power
+ type: u64
+ -
+ name: cost
+ type: u64
+ -
+ name: flags
+ type: u64
+
+operations:
+ list:
+ -
+ name: get-pds
+ attribute-set: pds
+ doc: Get the list of information for all performance domains.
+ do:
+ reply:
+ attributes:
+ - pd
+ -
+ name: get-pd-table
+ attribute-set: pd-table
+ doc: Get the energy model table of a performance domain.
+ do:
+ request:
+ attributes:
+ - pd-id
+ reply:
+ attributes:
+ - pd-id
+ - ps
+ -
+ name: pd-created
+ doc: A performance domain is created.
+ notify: get-pd-table
+ mcgrp: event
+ -
+ name: pd-updated
+ doc: A performance domain is updated.
+ notify: get-pd-table
+ mcgrp: event
+ -
+ name: pd-deleted
+ doc: A performance domain is deleted.
+ attribute-set: pd-table
+ event:
+ attributes:
+ - pd-id
+ mcgrp: event
+
+mcast-groups:
+ list:
+ -
+ name: event
diff --git a/MAINTAINERS b/MAINTAINERS
index 99fbde007792..6d6d156ce011 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8865,6 +8865,9 @@ S: Maintained
F: kernel/power/energy_model.c
F: include/linux/energy_model.h
F: Documentation/power/energy-model.rst
+F: Documentation/netlink/specs/em.yaml
+F: include/uapi/linux/energy_model.h
+F: kernel/power/em_netlink_autogen.*
EPAPR HYPERVISOR BYTE CHANNEL DEVICE DRIVER
M: Laurentiu Tudor <laurentiu.tudor@nxp.com>
diff --git a/include/uapi/linux/energy_model.h b/include/uapi/linux/energy_model.h
new file mode 100644
index 000000000000..4ec4c0eabbbb
--- /dev/null
+++ b/include/uapi/linux/energy_model.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
+/* Do not edit directly, auto-generated from: */
+/* Documentation/netlink/specs/em.yaml */
+/* YNL-GEN uapi header */
+
+#ifndef _UAPI_LINUX_ENERGY_MODEL_H
+#define _UAPI_LINUX_ENERGY_MODEL_H
+
+#define EM_FAMILY_NAME "em"
+#define EM_FAMILY_VERSION 1
+
+enum {
+ EM_A_PDS_PD = 1,
+
+ __EM_A_PDS_MAX,
+ EM_A_PDS_MAX = (__EM_A_PDS_MAX - 1)
+};
+
+enum {
+ EM_A_PD_PAD = 1,
+ EM_A_PD_PD_ID,
+ EM_A_PD_FLAGS,
+ EM_A_PD_CPUS,
+
+ __EM_A_PD_MAX,
+ EM_A_PD_MAX = (__EM_A_PD_MAX - 1)
+};
+
+enum {
+ EM_A_PD_TABLE_PD_ID = 1,
+ EM_A_PD_TABLE_PS,
+
+ __EM_A_PD_TABLE_MAX,
+ EM_A_PD_TABLE_MAX = (__EM_A_PD_TABLE_MAX - 1)
+};
+
+enum {
+ EM_A_PS_PAD = 1,
+ EM_A_PS_PERFORMANCE,
+ EM_A_PS_FREQUENCY,
+ EM_A_PS_POWER,
+ EM_A_PS_COST,
+ EM_A_PS_FLAGS,
+
+ __EM_A_PS_MAX,
+ EM_A_PS_MAX = (__EM_A_PS_MAX - 1)
+};
+
+enum {
+ EM_CMD_GET_PDS = 1,
+ EM_CMD_GET_PD_TABLE,
+ EM_CMD_PD_CREATED,
+ EM_CMD_PD_UPDATED,
+ EM_CMD_PD_DELETED,
+
+ __EM_CMD_MAX,
+ EM_CMD_MAX = (__EM_CMD_MAX - 1)
+};
+
+#define EM_MCGRP_EVENT "event"
+
+#endif /* _UAPI_LINUX_ENERGY_MODEL_H */
diff --git a/kernel/power/em_netlink_autogen.c b/kernel/power/em_netlink_autogen.c
new file mode 100644
index 000000000000..a7a09ab1d1c2
--- /dev/null
+++ b/kernel/power/em_netlink_autogen.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
+/* Do not edit directly, auto-generated from: */
+/* Documentation/netlink/specs/em.yaml */
+/* YNL-GEN kernel source */
+
+#include <net/netlink.h>
+#include <net/genetlink.h>
+
+#include "em_netlink_autogen.h"
+
+#include <uapi/linux/energy_model.h>
+
+/* EM_CMD_GET_PD_TABLE - do */
+static const struct nla_policy em_get_pd_table_nl_policy[EM_A_PD_TABLE_PD_ID + 1] = {
+ [EM_A_PD_TABLE_PD_ID] = { .type = NLA_U32, },
+};
+
+/* Ops table for em */
+static const struct genl_split_ops em_nl_ops[] = {
+ {
+ .cmd = EM_CMD_GET_PDS,
+ .doit = em_nl_get_pds_doit,
+ .flags = GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = EM_CMD_GET_PD_TABLE,
+ .doit = em_nl_get_pd_table_doit,
+ .policy = em_get_pd_table_nl_policy,
+ .maxattr = EM_A_PD_TABLE_PD_ID,
+ .flags = GENL_CMD_CAP_DO,
+ },
+};
+
+static const struct genl_multicast_group em_nl_mcgrps[] = {
+ [EM_NLGRP_EVENT] = { "event", },
+};
+
+struct genl_family em_nl_family __ro_after_init = {
+ .name = EM_FAMILY_NAME,
+ .version = EM_FAMILY_VERSION,
+ .netnsok = true,
+ .parallel_ops = true,
+ .module = THIS_MODULE,
+ .split_ops = em_nl_ops,
+ .n_split_ops = ARRAY_SIZE(em_nl_ops),
+ .mcgrps = em_nl_mcgrps,
+ .n_mcgrps = ARRAY_SIZE(em_nl_mcgrps),
+};
diff --git a/kernel/power/em_netlink_autogen.h b/kernel/power/em_netlink_autogen.h
new file mode 100644
index 000000000000..78ce609641f1
--- /dev/null
+++ b/kernel/power/em_netlink_autogen.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
+/* Do not edit directly, auto-generated from: */
+/* Documentation/netlink/specs/em.yaml */
+/* YNL-GEN kernel header */
+
+#ifndef _LINUX_EM_GEN_H
+#define _LINUX_EM_GEN_H
+
+#include <net/netlink.h>
+#include <net/genetlink.h>
+
+#include <uapi/linux/energy_model.h>
+
+int em_nl_get_pds_doit(struct sk_buff *skb, struct genl_info *info);
+int em_nl_get_pd_table_doit(struct sk_buff *skb, struct genl_info *info);
+
+enum {
+ EM_NLGRP_EVENT,
+};
+
+extern struct genl_family em_nl_family;
+
+#endif /* _LINUX_EM_GEN_H */
--
2.49.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v2 02/10] PM: EM: Add a skeleton code for netlink notification.
2025-06-13 9:44 [PATCH v2 00/10] PM: EM: Add netlink support for the energy model Changwoo Min
2025-06-13 9:44 ` [PATCH v2 01/10] PM: EM: Add em.yaml and autogen files Changwoo Min
@ 2025-06-13 9:44 ` Changwoo Min
2025-06-13 9:44 ` [PATCH v2 03/10] PM: EM: Assign a unique ID when creating a performance domain Changwoo Min
` (8 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Changwoo Min @ 2025-06-13 9:44 UTC (permalink / raw)
To: lukasz.luba, rafael, len.brown, pavel
Cc: christian.loehle, tj, kernel-dev, linux-pm, sched-ext,
linux-kernel, Changwoo Min
Add a boilerplate code for netlink notification to register the new
protocol family. Also, initialize and register the netlink during booting.
The initialization is called at the postcore level, which is late enough
after the generic netlink is initialized.
Finally, update MAINTAINERS to include new files.
Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
MAINTAINERS | 2 +-
kernel/power/Makefile | 5 ++++-
kernel/power/em_netlink.c | 35 +++++++++++++++++++++++++++++++++++
kernel/power/em_netlink.h | 16 ++++++++++++++++
4 files changed, 56 insertions(+), 2 deletions(-)
create mode 100644 kernel/power/em_netlink.c
create mode 100644 kernel/power/em_netlink.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 6d6d156ce011..63f694ff1b8f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8867,7 +8867,7 @@ F: include/linux/energy_model.h
F: Documentation/power/energy-model.rst
F: Documentation/netlink/specs/em.yaml
F: include/uapi/linux/energy_model.h
-F: kernel/power/em_netlink_autogen.*
+F: kernel/power/em_netlink*.*
EPAPR HYPERVISOR BYTE CHANNEL DEVICE DRIVER
M: Laurentiu Tudor <laurentiu.tudor@nxp.com>
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 874ad834dc8d..284a760aade7 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -21,4 +21,7 @@ obj-$(CONFIG_PM_WAKELOCKS) += wakelock.o
obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
-obj-$(CONFIG_ENERGY_MODEL) += energy_model.o
+obj-$(CONFIG_ENERGY_MODEL) += em.o
+em-y := energy_model.o
+em-$(CONFIG_NET) += em_netlink_autogen.o em_netlink.o
+
diff --git a/kernel/power/em_netlink.c b/kernel/power/em_netlink.c
new file mode 100644
index 000000000000..f3fbfeff29a4
--- /dev/null
+++ b/kernel/power/em_netlink.c
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *
+ * Generic netlink for energy model.
+ *
+ * Copyright (c) 2025 Valve Corporation.
+ * Author: Changwoo Min <changwoo@igalia.com>
+ */
+
+#define pr_fmt(fmt) "energy_model: " fmt
+
+#include <linux/energy_model.h>
+#include <net/sock.h>
+#include <net/genetlink.h>
+#include <uapi/linux/energy_model.h>
+
+#include "em_netlink.h"
+#include "em_netlink_autogen.h"
+
+int em_nl_get_pds_doit(struct sk_buff *skb, struct genl_info *info)
+{
+ return -EOPNOTSUPP;
+}
+
+int em_nl_get_pd_table_doit(struct sk_buff *skb, struct genl_info *info)
+{
+ return -EOPNOTSUPP;
+}
+
+static int __init em_netlink_init(void)
+{
+ return genl_register_family(&em_nl_family);
+}
+postcore_initcall(em_netlink_init);
+
diff --git a/kernel/power/em_netlink.h b/kernel/power/em_netlink.h
new file mode 100644
index 000000000000..acd186c92d6b
--- /dev/null
+++ b/kernel/power/em_netlink.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *
+ * Generic netlink for energy model.
+ *
+ * Copyright (c) 2025 Valve Corporation.
+ * Author: Changwoo Min <changwoo@igalia.com>
+ */
+#ifndef _EM_NETLINK_H
+#define _EM_NETLINK_H
+
+#if defined(CONFIG_ENERGY_MODEL) && defined(CONFIG_NET)
+#else
+#endif
+
+#endif /* _EM_NETLINK_H */
--
2.49.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v2 03/10] PM: EM: Assign a unique ID when creating a performance domain.
2025-06-13 9:44 [PATCH v2 00/10] PM: EM: Add netlink support for the energy model Changwoo Min
2025-06-13 9:44 ` [PATCH v2 01/10] PM: EM: Add em.yaml and autogen files Changwoo Min
2025-06-13 9:44 ` [PATCH v2 02/10] PM: EM: Add a skeleton code for netlink notification Changwoo Min
@ 2025-06-13 9:44 ` Changwoo Min
2025-06-13 9:44 ` [PATCH v2 04/10] PM: EM: Expose the ID of a performance domain via debugfs Changwoo Min
` (7 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Changwoo Min @ 2025-06-13 9:44 UTC (permalink / raw)
To: lukasz.luba, rafael, len.brown, pavel
Cc: christian.loehle, tj, kernel-dev, linux-pm, sched-ext,
linux-kernel, Changwoo Min
It is necessary to refer to a specific performance domain from a
userspace. For example, the energy model of a particular performance
domain is updated.
To this end, assign a unique ID to each performance domain to address it,
and manage them in a global linked list to look up a specific one by
matching ID. IDA is used for ID assignment, and the mutex is used to
protect the global list from concurrent access.
Note that the mutex (em_pd_list_mutex) is not supposed to hold while
holding em_pd_mutex to avoid ABBA deadlock.
Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
include/linux/energy_model.h | 4 ++++
kernel/power/energy_model.c | 30 +++++++++++++++++++++++++++++-
2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h
index 7fa1eb3cc823..2f5c73fcdfe5 100644
--- a/include/linux/energy_model.h
+++ b/include/linux/energy_model.h
@@ -54,6 +54,8 @@ struct em_perf_table {
/**
* struct em_perf_domain - Performance domain
* @em_table: Pointer to the runtime modifiable em_perf_table
+ * @node: node in em_pd_list (in energy_model.c)
+ * @id: A unique ID number for each performance domain
* @nr_perf_states: Number of performance states
* @min_perf_state: Minimum allowed Performance State index
* @max_perf_state: Maximum allowed Performance State index
@@ -71,6 +73,8 @@ struct em_perf_table {
*/
struct em_perf_domain {
struct em_perf_table __rcu *em_table;
+ struct list_head node;
+ int id;
int nr_perf_states;
int min_perf_state;
int max_perf_state;
diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c
index ea7995a25780..58671ac142db 100644
--- a/kernel/power/energy_model.c
+++ b/kernel/power/energy_model.c
@@ -23,6 +23,16 @@
*/
static DEFINE_MUTEX(em_pd_mutex);
+/*
+ * Manage performance domains with IDs. One can iterate the performance domains
+ * through the list and pick one with their associated ID. The mutex serializes
+ * the list access. When holding em_pd_list_mutex, em_pd_mutex should not be
+ * taken to avoid potential deadlock.
+ */
+static DEFINE_IDA(em_pd_ida);
+static LIST_HEAD(em_pd_list);
+static DEFINE_MUTEX(em_pd_list_mutex);
+
static void em_cpufreq_update_efficiencies(struct device *dev,
struct em_perf_state *table);
static void em_check_capacity_update(void);
@@ -396,7 +406,7 @@ static int em_create_pd(struct device *dev, int nr_states,
struct em_perf_table *em_table;
struct em_perf_domain *pd;
struct device *cpu_dev;
- int cpu, ret, num_cpus;
+ int cpu, ret, num_cpus, id;
if (_is_cpu_device(dev)) {
num_cpus = cpumask_weight(cpus);
@@ -420,6 +430,13 @@ static int em_create_pd(struct device *dev, int nr_states,
pd->nr_perf_states = nr_states;
+ INIT_LIST_HEAD(&pd->node);
+
+ id = ida_alloc(&em_pd_ida, GFP_KERNEL);
+ if (id < 0)
+ return -ENOMEM;
+ pd->id = id;
+
em_table = em_table_alloc(pd);
if (!em_table)
goto free_pd;
@@ -444,6 +461,7 @@ static int em_create_pd(struct device *dev, int nr_states,
kfree(em_table);
free_pd:
kfree(pd);
+ ida_free(&em_pd_ida, id);
return -EINVAL;
}
@@ -639,6 +657,10 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
if (_is_cpu_device(dev))
em_check_capacity_update();
+ mutex_lock(&em_pd_list_mutex);
+ list_add_tail(&dev->em_pd->node, &em_pd_list);
+ mutex_unlock(&em_pd_list_mutex);
+
return ret;
}
EXPORT_SYMBOL_GPL(em_dev_register_perf_domain);
@@ -657,6 +679,10 @@ void em_dev_unregister_perf_domain(struct device *dev)
if (_is_cpu_device(dev))
return;
+ mutex_lock(&em_pd_list_mutex);
+ list_del_init(&dev->em_pd->node);
+ mutex_unlock(&em_pd_list_mutex);
+
/*
* The mutex separates all register/unregister requests and protects
* from potential clean-up/setup issues in the debugfs directories.
@@ -668,6 +694,8 @@ void em_dev_unregister_perf_domain(struct device *dev)
em_table_free(rcu_dereference_protected(dev->em_pd->em_table,
lockdep_is_held(&em_pd_mutex)));
+ ida_free(&em_pd_ida, dev->em_pd->id);
+
kfree(dev->em_pd);
dev->em_pd = NULL;
mutex_unlock(&em_pd_mutex);
--
2.49.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v2 04/10] PM: EM: Expose the ID of a performance domain via debugfs.
2025-06-13 9:44 [PATCH v2 00/10] PM: EM: Add netlink support for the energy model Changwoo Min
` (2 preceding siblings ...)
2025-06-13 9:44 ` [PATCH v2 03/10] PM: EM: Assign a unique ID when creating a performance domain Changwoo Min
@ 2025-06-13 9:44 ` Changwoo Min
2025-06-13 9:44 ` [PATCH v2 05/10] PM: EM: Add an iterator and accessor for the performance domain Changwoo Min
` (6 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Changwoo Min @ 2025-06-13 9:44 UTC (permalink / raw)
To: lukasz.luba, rafael, len.brown, pavel
Cc: christian.loehle, tj, kernel-dev, linux-pm, sched-ext,
linux-kernel, Changwoo Min
For ease of debugging, let's expose the assigned ID of a performance
domain through debugfs (e.g., /sys/kernel/debug/energy_model/cpu0/id).
Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
kernel/power/energy_model.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c
index 58671ac142db..6e5e70dbec88 100644
--- a/kernel/power/energy_model.c
+++ b/kernel/power/energy_model.c
@@ -126,6 +126,16 @@ static int em_debug_flags_show(struct seq_file *s, void *unused)
}
DEFINE_SHOW_ATTRIBUTE(em_debug_flags);
+static int em_debug_id_show(struct seq_file *s, void *unused)
+{
+ struct em_perf_domain *pd = s->private;
+
+ seq_printf(s, "%d\n", pd->id);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(em_debug_id);
+
static void em_debug_create_pd(struct device *dev)
{
struct em_dbg_info *em_dbg;
@@ -142,6 +152,8 @@ static void em_debug_create_pd(struct device *dev)
debugfs_create_file("flags", 0444, d, dev->em_pd,
&em_debug_flags_fops);
+ debugfs_create_file("id", 0444, d, dev->em_pd, &em_debug_id_fops);
+
em_dbg = devm_kcalloc(dev, dev->em_pd->nr_perf_states,
sizeof(*em_dbg), GFP_KERNEL);
if (!em_dbg)
--
2.49.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v2 05/10] PM: EM: Add an iterator and accessor for the performance domain.
2025-06-13 9:44 [PATCH v2 00/10] PM: EM: Add netlink support for the energy model Changwoo Min
` (3 preceding siblings ...)
2025-06-13 9:44 ` [PATCH v2 04/10] PM: EM: Expose the ID of a performance domain via debugfs Changwoo Min
@ 2025-06-13 9:44 ` Changwoo Min
2025-06-13 9:44 ` [PATCH v2 06/10] PM: EM: Implement em_nl_get_pds_doit() Changwoo Min
` (5 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Changwoo Min @ 2025-06-13 9:44 UTC (permalink / raw)
To: lukasz.luba, rafael, len.brown, pavel
Cc: christian.loehle, tj, kernel-dev, linux-pm, sched-ext,
linux-kernel, Changwoo Min
Add an iterator function (for_each_em_perf_domain) that iterates all the
performance domains in the global list. A passed callback function (cb) is
called for each performance domain.
Additionally, add a lookup function (em_perf_domain_get_by_id) that
searches for a performance domain by matching the ID in the global list.
Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
include/linux/energy_model.h | 15 +++++++++++++++
kernel/power/energy_model.c | 34 ++++++++++++++++++++++++++++++++++
2 files changed, 49 insertions(+)
diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h
index 2f5c73fcdfe5..ce70e664fcd4 100644
--- a/include/linux/energy_model.h
+++ b/include/linux/energy_model.h
@@ -341,6 +341,10 @@ struct em_perf_state *em_perf_state_from_pd(struct em_perf_domain *pd)
return rcu_dereference(pd->em_table)->state;
}
+int for_each_em_perf_domain(int (*cb)(struct em_perf_domain*, void *),
+ void *data);
+struct em_perf_domain *em_perf_domain_get_by_id(int id);
+
#else
struct em_data_callback {};
#define EM_ADV_DATA_CB(_active_power_cb, _cost_cb) { }
@@ -410,6 +414,17 @@ int em_update_performance_limits(struct em_perf_domain *pd,
}
static inline void em_adjust_cpu_capacity(unsigned int cpu) {}
static inline void em_rebuild_sched_domains(void) {}
+static inline
+int for_each_em_perf_domain(int (*cb)(struct em_perf_domain*, void *),
+ void *data)
+{
+ return -EINVAL;
+}
+static inline
+struct em_perf_domain *em_perf_domain_get_by_id(int id)
+{
+ return NULL;
+}
#endif
#endif
diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c
index 6e5e70dbec88..f125262a93c9 100644
--- a/kernel/power/energy_model.c
+++ b/kernel/power/energy_model.c
@@ -976,3 +976,37 @@ void em_rebuild_sched_domains(void)
*/
schedule_work(&rebuild_sd_work);
}
+
+int for_each_em_perf_domain(int (*cb)(struct em_perf_domain*, void *),
+ void *data)
+{
+ struct em_perf_domain *pd;
+
+ lockdep_assert_not_held(&em_pd_mutex);
+ guard(mutex)(&em_pd_list_mutex);
+
+ list_for_each_entry(pd, &em_pd_list, node) {
+ int ret;
+
+ ret = cb(pd, data);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+struct em_perf_domain *em_perf_domain_get_by_id(int id)
+{
+ struct em_perf_domain *pd;
+
+ lockdep_assert_not_held(&em_pd_mutex);
+ guard(mutex)(&em_pd_list_mutex);
+
+ list_for_each_entry(pd, &em_pd_list, node) {
+ if (pd->id == id)
+ return pd;
+ }
+
+ return NULL;
+}
--
2.49.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v2 06/10] PM: EM: Implement em_nl_get_pds_doit().
2025-06-13 9:44 [PATCH v2 00/10] PM: EM: Add netlink support for the energy model Changwoo Min
` (4 preceding siblings ...)
2025-06-13 9:44 ` [PATCH v2 05/10] PM: EM: Add an iterator and accessor for the performance domain Changwoo Min
@ 2025-06-13 9:44 ` Changwoo Min
2025-06-13 9:44 ` [PATCH v2 07/10] PM: EM: Implement em_nl_get_pd_table_doit() Changwoo Min
` (4 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Changwoo Min @ 2025-06-13 9:44 UTC (permalink / raw)
To: lukasz.luba, rafael, len.brown, pavel
Cc: christian.loehle, tj, kernel-dev, linux-pm, sched-ext,
linux-kernel, Changwoo Min
When a userspace requests EM_CMD_GET_PDS, the kernel responds with
information on all performance domains. The message format of the
response is as follows:
EM_A_PDS_PD (NLA_NESTED)*
EM_A_PD_PD_ID (NLA_U32)
EM_A_PD_FLAGS (NLA_U64)
EM_A_PD_CPUS (NLA_STRING)
where EM_A_PDS_PD can be repeated as many times as there are performance
domains, and EM_A_PD_CPUS is a hexadecimal string representing a CPU
bitmask.
Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
kernel/power/em_netlink.c | 82 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 81 insertions(+), 1 deletion(-)
diff --git a/kernel/power/em_netlink.c b/kernel/power/em_netlink.c
index f3fbfeff29a4..31b27c6fe3c9 100644
--- a/kernel/power/em_netlink.c
+++ b/kernel/power/em_netlink.c
@@ -17,9 +17,89 @@
#include "em_netlink.h"
#include "em_netlink_autogen.h"
+#define EM_A_PD_CPUS_LEN 256
+
+/*************************** Command encoding ********************************/
+static int __em_nl_get_pd_size(struct em_perf_domain *pd, void *data)
+{
+ char cpus_buf[EM_A_PD_CPUS_LEN];
+ int *tot_msg_sz = data;
+ int msg_sz, cpus_sz;
+
+ cpus_sz = snprintf(cpus_buf, sizeof(cpus_buf), "%*pb",
+ cpumask_pr_args(to_cpumask(pd->cpus)));
+
+ msg_sz = nla_total_size(0) + /* EM_A_PDS_PD */
+ nla_total_size(sizeof(u32)) + /* EM_A_PD_PD_ID */
+ nla_total_size_64bit(sizeof(u64)) + /* EM_A_PD_FLAGS */
+ nla_total_size(cpus_sz); /* EM_A_PD_CPUS */
+
+ *tot_msg_sz += nlmsg_total_size(genlmsg_msg_size(msg_sz));
+ return 0;
+}
+
+static int __em_nl_get_pd(struct em_perf_domain *pd, void *data)
+{
+ char cpus_buf[EM_A_PD_CPUS_LEN];
+ struct sk_buff *msg = data;
+ struct nlattr *entry;
+
+ entry = nla_nest_start(msg, EM_A_PDS_PD);
+ if (!entry)
+ goto out_cancel_nest;
+
+ if (nla_put_u32(msg, EM_A_PD_PD_ID, pd->id))
+ goto out_cancel_nest;
+
+ if (nla_put_u64_64bit(msg, EM_A_PD_FLAGS, pd->flags, EM_A_PD_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_A_PD_CPUS, cpus_buf))
+ goto out_cancel_nest;
+
+ nla_nest_end(msg, entry);
+
+ return 0;
+
+out_cancel_nest:
+ nla_nest_cancel(msg, entry);
+
+ return -EMSGSIZE;
+}
+
int em_nl_get_pds_doit(struct sk_buff *skb, struct genl_info *info)
{
- return -EOPNOTSUPP;
+ struct sk_buff *msg;
+ void *hdr;
+ int cmd = info->genlhdr->cmd;
+ int ret = -EMSGSIZE, msg_sz = 0;
+
+ for_each_em_perf_domain(__em_nl_get_pd_size, &msg_sz);
+
+ msg = genlmsg_new(msg_sz, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ hdr = genlmsg_put_reply(msg, info, &em_nl_family, 0, cmd);
+ if (!hdr)
+ goto out_free_msg;
+
+ ret = for_each_em_perf_domain(__em_nl_get_pd, msg);
+ if (ret)
+ goto out_cancel_msg;
+
+ genlmsg_end(msg, hdr);
+
+ return genlmsg_reply(msg, info);
+
+out_cancel_msg:
+ genlmsg_cancel(msg, hdr);
+out_free_msg:
+ nlmsg_free(msg);
+
+ return ret;
}
int em_nl_get_pd_table_doit(struct sk_buff *skb, struct genl_info *info)
--
2.49.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v2 07/10] PM: EM: Implement em_nl_get_pd_table_doit().
2025-06-13 9:44 [PATCH v2 00/10] PM: EM: Add netlink support for the energy model Changwoo Min
` (5 preceding siblings ...)
2025-06-13 9:44 ` [PATCH v2 06/10] PM: EM: Implement em_nl_get_pds_doit() Changwoo Min
@ 2025-06-13 9:44 ` Changwoo Min
2025-06-13 9:44 ` [PATCH v2 08/10] PM: EM: Implement em_notify_pd_deleted() Changwoo Min
` (3 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Changwoo Min @ 2025-06-13 9:44 UTC (permalink / raw)
To: lukasz.luba, rafael, len.brown, pavel
Cc: christian.loehle, tj, kernel-dev, linux-pm, sched-ext,
linux-kernel, Changwoo Min
When a userspace requests EM_CMD_GET_PD_TABLE with an ID of a performancei
domain, the kernel reports back the energy model table of the specified
performance domain. The message format of the response is as follows:
EM_A_PD_TABLE_PD_ID (NLA_U32)
EM_A_PD_TABLE_PS (NLA_NESTED)*
EM_A_PS_PERFORMANCE (NLA_U64)
EM_A_PS_FREQUENCY (NLA_U64)
EM_A_PS_POWER (NLA_U64)
EM_A_PS_COST (NLA_U64)
EM_A_PS_FLAGS (NLA_U64)
where EM_A_PD_TABLE_PS can be repeated as many times as there are
performance states (struct em_perf_state).
Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
kernel/power/em_netlink.c | 108 +++++++++++++++++++++++++++++++++++++-
1 file changed, 107 insertions(+), 1 deletion(-)
diff --git a/kernel/power/em_netlink.c b/kernel/power/em_netlink.c
index 31b27c6fe3c9..981bbf1f9a2f 100644
--- a/kernel/power/em_netlink.c
+++ b/kernel/power/em_netlink.c
@@ -102,9 +102,115 @@ int em_nl_get_pds_doit(struct sk_buff *skb, struct genl_info *info)
return ret;
}
+static struct em_perf_domain *__em_nl_get_pd_table_id(struct nlattr **attrs)
+{
+ struct em_perf_domain *pd;
+ int id;
+
+ if (!attrs[EM_A_PD_TABLE_PD_ID])
+ return NULL;
+
+ id = nla_get_u32(attrs[EM_A_PD_TABLE_PD_ID]);
+ pd = em_perf_domain_get_by_id(id);
+ return pd;
+}
+
+static int __em_nl_get_pd_table_size(const struct em_perf_domain *pd)
+{
+ int id_sz, ps_sz;
+
+ id_sz = nla_total_size(sizeof(u32)); /* EM_A_PD_TABLE_PD_ID */
+ ps_sz = nla_total_size(0) + /* EM_A_PD_TABLE_PS */
+ nla_total_size_64bit(sizeof(u64)) + /* EM_A_PS_PERFORMANCE */
+ nla_total_size_64bit(sizeof(u64)) + /* EM_A_PS_FREQUENCY */
+ nla_total_size_64bit(sizeof(u64)) + /* EM_A_PS_POWER */
+ nla_total_size_64bit(sizeof(u64)) + /* EM_A_PS_COST */
+ nla_total_size_64bit(sizeof(u64)); /* EM_A_PS_FLAGS */
+ ps_sz *= pd->nr_perf_states;
+
+ return nlmsg_total_size(genlmsg_msg_size(id_sz + ps_sz));
+}
+
+static int __em_nl_get_pd_table(struct sk_buff *msg, const struct em_perf_domain *pd)
+{
+ struct em_perf_state *table, *ps;
+ struct nlattr *entry;
+ int i;
+
+ if (nla_put_u32(msg, EM_A_PD_TABLE_PD_ID, pd->id))
+ goto out_err;
+
+ rcu_read_lock();
+ table = em_perf_state_from_pd((struct em_perf_domain *)pd);
+
+ for (i = 0; i < pd->nr_perf_states; i++) {
+ ps = &table[i];
+
+ entry = nla_nest_start(msg, EM_A_PD_TABLE_PS);
+ if (!entry)
+ goto out_unlock_ps;
+
+ if (nla_put_u64_64bit(msg, EM_A_PS_PERFORMANCE,
+ ps->performance, EM_A_PS_PAD))
+ goto out_cancel_ps_nest;
+ if (nla_put_u64_64bit(msg, EM_A_PS_FREQUENCY,
+ ps->frequency, EM_A_PS_PAD))
+ goto out_cancel_ps_nest;
+ if (nla_put_u64_64bit(msg, EM_A_PS_POWER,
+ ps->power, EM_A_PS_PAD))
+ goto out_cancel_ps_nest;
+ if (nla_put_u64_64bit(msg, EM_A_PS_COST,
+ ps->cost, EM_A_PS_PAD))
+ goto out_cancel_ps_nest;
+ if (nla_put_u64_64bit(msg, EM_A_PS_FLAGS,
+ ps->flags, EM_A_PS_PAD))
+ goto out_cancel_ps_nest;
+
+ nla_nest_end(msg, entry);
+ }
+ rcu_read_unlock();
+ return 0;
+
+out_cancel_ps_nest:
+ nla_nest_cancel(msg, entry);
+out_unlock_ps:
+ rcu_read_unlock();
+out_err:
+ return -EMSGSIZE;
+}
+
int em_nl_get_pd_table_doit(struct sk_buff *skb, struct genl_info *info)
{
- return -EOPNOTSUPP;
+ struct sk_buff *msg;
+ struct em_perf_domain *pd;
+ void *hdr;
+ int cmd = info->genlhdr->cmd;
+ int msg_sz, ret;
+
+ pd = __em_nl_get_pd_table_id(info->attrs);
+ if (!pd)
+ return -EINVAL;
+
+ msg_sz = __em_nl_get_pd_table_size(pd);
+
+ msg = genlmsg_new(msg_sz, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ hdr = genlmsg_put_reply(msg, info, &em_nl_family, 0, cmd);
+ if (!hdr)
+ goto out_free_msg;
+
+ ret = __em_nl_get_pd_table(msg, pd);
+ if (ret)
+ goto out_free_msg;
+
+ genlmsg_end(msg, hdr);
+ return genlmsg_reply(msg, info);
+
+out_free_msg:
+ nlmsg_free(msg);
+ return -EMSGSIZE;
}
static int __init em_netlink_init(void)
--
2.49.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v2 08/10] PM: EM: Implement em_notify_pd_deleted().
2025-06-13 9:44 [PATCH v2 00/10] PM: EM: Add netlink support for the energy model Changwoo Min
` (6 preceding siblings ...)
2025-06-13 9:44 ` [PATCH v2 07/10] PM: EM: Implement em_nl_get_pd_table_doit() Changwoo Min
@ 2025-06-13 9:44 ` Changwoo Min
2025-06-13 9:44 ` [PATCH v2 09/10] PM: EM: Implement em_notify_pd_created/updated() Changwoo Min
` (2 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Changwoo Min @ 2025-06-13 9:44 UTC (permalink / raw)
To: lukasz.luba, rafael, len.brown, pavel
Cc: christian.loehle, tj, kernel-dev, linux-pm, sched-ext,
linux-kernel, Changwoo Min
Add the event notification infrastructure and implement the event
notification for when a performance domain is deleted (EM_CMD_PD_DELETED).
The event contains the ID of the performance domain (EM_A_PD_TABLE_PD_ID)
so the userspace can identify the changed performance domain for further
processing.
Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
kernel/power/em_netlink.c | 56 +++++++++++++++++++++++++++++++++++++++
kernel/power/em_netlink.h | 18 +++++++++++++
2 files changed, 74 insertions(+)
diff --git a/kernel/power/em_netlink.c b/kernel/power/em_netlink.c
index 981bbf1f9a2f..4e34799fd1f8 100644
--- a/kernel/power/em_netlink.c
+++ b/kernel/power/em_netlink.c
@@ -213,6 +213,62 @@ int em_nl_get_pd_table_doit(struct sk_buff *skb, struct genl_info *info)
return -EMSGSIZE;
}
+
+/**************************** Event encoding *********************************/
+int em_notify_pd_created(const struct em_perf_domain *pd)
+{
+ return -EOPNOTSUPP;
+}
+
+int em_notify_pd_updated(const struct em_perf_domain *pd)
+{
+ return -EOPNOTSUPP;
+}
+
+static int __em_notify_pd_deleted_size(const struct em_perf_domain *pd)
+{
+ int id_sz = nla_total_size(sizeof(u32)); /* EM_A_PD_TABLE_PD_ID */
+
+ return nlmsg_total_size(genlmsg_msg_size(id_sz));
+}
+
+int em_notify_pd_deleted(const struct em_perf_domain *pd)
+{
+ struct sk_buff *msg;
+ int ret = -EMSGSIZE;
+ void *hdr;
+ int msg_sz;
+
+ if (!genl_has_listeners(&em_nl_family, &init_net, EM_NLGRP_EVENT))
+ return 0;
+
+ msg_sz = __em_notify_pd_deleted_size(pd);
+
+ msg = genlmsg_new(msg_sz, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ hdr = genlmsg_put(msg, 0, 0, &em_nl_family, 0, EM_CMD_PD_DELETED);
+ if (!hdr)
+ goto out_free_msg;
+
+ if (nla_put_u32(msg, EM_A_PD_TABLE_PD_ID, pd->id)) {
+ ret = -EMSGSIZE;
+ goto out_free_msg;
+ }
+
+ genlmsg_end(msg, hdr);
+
+ genlmsg_multicast(&em_nl_family, msg, 0, EM_NLGRP_EVENT, GFP_KERNEL);
+
+ return 0;
+
+out_free_msg:
+ nlmsg_free(msg);
+ return ret;
+}
+
+/**************************** Initialization *********************************/
static int __init em_netlink_init(void)
{
return genl_register_family(&em_nl_family);
diff --git a/kernel/power/em_netlink.h b/kernel/power/em_netlink.h
index acd186c92d6b..938c84ca1f40 100644
--- a/kernel/power/em_netlink.h
+++ b/kernel/power/em_netlink.h
@@ -10,7 +10,25 @@
#define _EM_NETLINK_H
#if defined(CONFIG_ENERGY_MODEL) && defined(CONFIG_NET)
+int em_notify_pd_created(const struct em_perf_domain *pd);
+int em_notify_pd_deleted(const struct em_perf_domain *pd);
+int em_notify_pd_updated(const struct em_perf_domain *pd);
+
#else
+static inline int em_notify_pd_created(const struct em_perf_domain *pd)
+{
+ return 0;
+}
+
+static inline int em_notify_pd_deleted(const struct em_perf_domain *pd)
+{
+ return 0;
+}
+
+static inline int em_notify_pd_updated(const struct em_perf_domain *pd)
+{
+ return 0;
+}
#endif
#endif /* _EM_NETLINK_H */
--
2.49.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v2 09/10] PM: EM: Implement em_notify_pd_created/updated().
2025-06-13 9:44 [PATCH v2 00/10] PM: EM: Add netlink support for the energy model Changwoo Min
` (7 preceding siblings ...)
2025-06-13 9:44 ` [PATCH v2 08/10] PM: EM: Implement em_notify_pd_deleted() Changwoo Min
@ 2025-06-13 9:44 ` Changwoo Min
2025-06-13 20:02 ` kernel test robot
2025-06-13 9:44 ` [PATCH v2 10/10] PM: EM: Notify an event when the performance domain changes Changwoo Min
2025-06-27 3:37 ` [PATCH v2 00/10] PM: EM: Add netlink support for the energy model Changwoo Min
10 siblings, 1 reply; 15+ messages in thread
From: Changwoo Min @ 2025-06-13 9:44 UTC (permalink / raw)
To: lukasz.luba, rafael, len.brown, pavel
Cc: christian.loehle, tj, kernel-dev, linux-pm, sched-ext,
linux-kernel, Changwoo Min
Implement two event notifications when a performance domain is created
(EM_CMD_PD_CREATED) and updated (EM_CMD_PD_UPDATED). The message format
of these two event notifications is the same as EM_CMD_GET_PD_TABLE --
containing the performance domain's ID and its energy model table.
Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
kernel/power/em_netlink.c | 38 ++++++++++++++++++++++++++++++++++++--
1 file changed, 36 insertions(+), 2 deletions(-)
diff --git a/kernel/power/em_netlink.c b/kernel/power/em_netlink.c
index 4e34799fd1f8..d42da92d1af4 100644
--- a/kernel/power/em_netlink.c
+++ b/kernel/power/em_netlink.c
@@ -215,14 +215,48 @@ int em_nl_get_pd_table_doit(struct sk_buff *skb, struct genl_info *info)
/**************************** Event encoding *********************************/
+static int __em_notify_pd_table(const struct em_perf_domain *pd, int ntf_type)
+{
+ struct sk_buff *msg;
+ int msg_sz, ret;
+ void *hdr;
+
+ if (!genl_has_listeners(&em_nl_family, &init_net, EM_NLGRP_EVENT))
+ return 0;
+
+ msg_sz = __em_nl_get_pd_table_size(pd);
+
+ msg = genlmsg_new(msg_sz, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ hdr = genlmsg_put(msg, 0, 0, &em_nl_family, 0, ntf_type);
+ if (!hdr)
+ goto out_free_msg;
+
+ ret = __em_nl_get_pd_table(msg, pd);
+ if (ret)
+ goto out_free_msg;
+
+ genlmsg_end(msg, hdr);
+
+ genlmsg_multicast(&em_nl_family, msg, 0, EM_NLGRP_EVENT, GFP_KERNEL);
+
+ return 0;
+
+out_free_msg:
+ nlmsg_free(msg);
+ return ret;
+}
+
int em_notify_pd_created(const struct em_perf_domain *pd)
{
- return -EOPNOTSUPP;
+ return __em_notify_pd_table(pd, EM_CMD_PD_CREATED);
}
int em_notify_pd_updated(const struct em_perf_domain *pd)
{
- return -EOPNOTSUPP;
+ return __em_notify_pd_table(pd, EM_CMD_PD_UPDATED);
}
static int __em_notify_pd_deleted_size(const struct em_perf_domain *pd)
--
2.49.0
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH v2 09/10] PM: EM: Implement em_notify_pd_created/updated().
2025-06-13 9:44 ` [PATCH v2 09/10] PM: EM: Implement em_notify_pd_created/updated() Changwoo Min
@ 2025-06-13 20:02 ` kernel test robot
0 siblings, 0 replies; 15+ messages in thread
From: kernel test robot @ 2025-06-13 20:02 UTC (permalink / raw)
To: Changwoo Min, lukasz.luba, rafael, len.brown, pavel
Cc: llvm, oe-kbuild-all, christian.loehle, tj, kernel-dev, linux-pm,
sched-ext, linux-kernel, Changwoo Min
Hi Changwoo,
kernel test robot noticed the following build warnings:
[auto build test WARNING on linus/master]
[also build test WARNING on v6.16-rc1 next-20250613]
[cannot apply to amd-pstate/linux-next amd-pstate/bleeding-edge]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Changwoo-Min/PM-EM-Add-em-yaml-and-autogen-files/20250613-174859
base: linus/master
patch link: https://lore.kernel.org/r/20250613094428.267791-10-changwoo%40igalia.com
patch subject: [PATCH v2 09/10] PM: EM: Implement em_notify_pd_created/updated().
config: i386-randconfig-001-20250614 (https://download.01.org/0day-ci/archive/20250614/202506140306.tuIoz8rN-lkp@intel.com/config)
compiler: clang version 20.1.2 (https://github.com/llvm/llvm-project 58df0ef89dd64126512e4ee27b4ac3fd8ddf6247)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250614/202506140306.tuIoz8rN-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202506140306.tuIoz8rN-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> kernel/power/em_netlink.c:234:6: warning: variable 'ret' is used uninitialized whenever 'if' condition is true [-Wsometimes-uninitialized]
234 | if (!hdr)
| ^~~~
kernel/power/em_netlink.c:249:9: note: uninitialized use occurs here
249 | return ret;
| ^~~
kernel/power/em_netlink.c:234:2: note: remove the 'if' if its condition is always false
234 | if (!hdr)
| ^~~~~~~~~
235 | goto out_free_msg;
| ~~~~~~~~~~~~~~~~~
kernel/power/em_netlink.c:221:17: note: initialize the variable 'ret' to silence this warning
221 | int msg_sz, ret;
| ^
| = 0
1 warning generated.
vim +234 kernel/power/em_netlink.c
215
216
217 /**************************** Event encoding *********************************/
218 static int __em_notify_pd_table(const struct em_perf_domain *pd, int ntf_type)
219 {
220 struct sk_buff *msg;
221 int msg_sz, ret;
222 void *hdr;
223
224 if (!genl_has_listeners(&em_nl_family, &init_net, EM_NLGRP_EVENT))
225 return 0;
226
227 msg_sz = __em_nl_get_pd_table_size(pd);
228
229 msg = genlmsg_new(msg_sz, GFP_KERNEL);
230 if (!msg)
231 return -ENOMEM;
232
233 hdr = genlmsg_put(msg, 0, 0, &em_nl_family, 0, ntf_type);
> 234 if (!hdr)
235 goto out_free_msg;
236
237 ret = __em_nl_get_pd_table(msg, pd);
238 if (ret)
239 goto out_free_msg;
240
241 genlmsg_end(msg, hdr);
242
243 genlmsg_multicast(&em_nl_family, msg, 0, EM_NLGRP_EVENT, GFP_KERNEL);
244
245 return 0;
246
247 out_free_msg:
248 nlmsg_free(msg);
249 return ret;
250 }
251
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2 10/10] PM: EM: Notify an event when the performance domain changes.
2025-06-13 9:44 [PATCH v2 00/10] PM: EM: Add netlink support for the energy model Changwoo Min
` (8 preceding siblings ...)
2025-06-13 9:44 ` [PATCH v2 09/10] PM: EM: Implement em_notify_pd_created/updated() Changwoo Min
@ 2025-06-13 9:44 ` Changwoo Min
2025-06-27 3:37 ` [PATCH v2 00/10] PM: EM: Add netlink support for the energy model Changwoo Min
10 siblings, 0 replies; 15+ messages in thread
From: Changwoo Min @ 2025-06-13 9:44 UTC (permalink / raw)
To: lukasz.luba, rafael, len.brown, pavel
Cc: christian.loehle, tj, kernel-dev, linux-pm, sched-ext,
linux-kernel, Changwoo Min
Send an event to userspace when a performance domain is created or deleted,
or its energy model is updated.
Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
kernel/power/energy_model.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c
index f125262a93c9..c72ac1585f59 100644
--- a/kernel/power/energy_model.c
+++ b/kernel/power/energy_model.c
@@ -17,6 +17,8 @@
#include <linux/sched/topology.h>
#include <linux/slab.h>
+#include "em_netlink.h"
+
/*
* Mutex serializing the registrations of performance domains and letting
* callbacks defined by drivers sleep.
@@ -350,6 +352,8 @@ int em_dev_update_perf_domain(struct device *dev,
em_table_free(old_table);
mutex_unlock(&em_pd_mutex);
+
+ em_notify_pd_updated(pd);
return 0;
}
EXPORT_SYMBOL_GPL(em_dev_update_perf_domain);
@@ -673,6 +677,7 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
list_add_tail(&dev->em_pd->node, &em_pd_list);
mutex_unlock(&em_pd_list_mutex);
+ em_notify_pd_created(dev->em_pd);
return ret;
}
EXPORT_SYMBOL_GPL(em_dev_register_perf_domain);
@@ -695,6 +700,8 @@ void em_dev_unregister_perf_domain(struct device *dev)
list_del_init(&dev->em_pd->node);
mutex_unlock(&em_pd_list_mutex);
+ em_notify_pd_deleted(dev->em_pd);
+
/*
* The mutex separates all register/unregister requests and protects
* from potential clean-up/setup issues in the debugfs directories.
--
2.49.0
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH v2 00/10] PM: EM: Add netlink support for the energy model.
2025-06-13 9:44 [PATCH v2 00/10] PM: EM: Add netlink support for the energy model Changwoo Min
` (9 preceding siblings ...)
2025-06-13 9:44 ` [PATCH v2 10/10] PM: EM: Notify an event when the performance domain changes Changwoo Min
@ 2025-06-27 3:37 ` Changwoo Min
2025-06-30 10:07 ` Lukasz Luba
10 siblings, 1 reply; 15+ messages in thread
From: Changwoo Min @ 2025-06-27 3:37 UTC (permalink / raw)
To: lukasz.luba, rafael, len.brown, pavel
Cc: christian.loehle, tj, kernel-dev, linux-pm, sched-ext,
linux-kernel, Rafael J. Wysocki
Gentle ping as it reaches 2-weeks.
@Lukasz, @Rafael -- I have a question related to the energy model
in general. As far as I understand, the energy model describes
the performance-energy consumption tradeoff when a single CPU in
a performance domain is running. However, in reality, SoCs may
have thermal constraints, which would result in additional
constraints. For example, running all CPUs with the highest
frequency may not be possible. My question is this: does kernel
maintain and use such (thermal?) constraints?
Regards,
Changwoo Min
On 6/13/25 18:44, Changwoo Min wrote:
> There is a need to access the energy model from the userspace. One such
> example is the sched_ext schedulers [1]. The userspace part of the
> sched_ext schedules could feed the (post-processed) energy-model
> information to the BPF part of the scheduler.
>
> Currently, debugfs is the only way to read the energy model from userspace;
> however, it lacks proper notification mechanisms when a performance domain
> and its associated energy model change.
>
> This patch set introduces a generic netlink for the energy model, as
> discussed in [2]. It allows a userspace program to read the performance
> domain and its energy model. It notifies the userspace program when a
> performance domain is created or deleted or its energy model is updated
> through a multicast interface.
>
> Specifically, it supports two commands:
> - EM_CMD_GET_PDS: Get the list of information for all performance
> domains.
> - EM_CMD_GET_PD_TABLE: Get the energy model table of a performance
> domain.
>
> Also, it supports three notification events:
> - EM_CMD_PD_CREATED: When a performance domain is created.
> - EM_CMD_PD_DELETED: When a performance domain is deleted.
> - EM_CMD_PD_UPDATED: When the energy model table of a performance domain
> is updated.
>
> This can be tested using the tool, tools/net/ynl/pyynl/cli.py, for example,
> with the following commands:
>
> $> tools/net/ynl/pyynl/cli.py \
> --spec Documentation/netlink/specs/em.yaml \
> --do get-pds
> $> tools/net/ynl/pyynl/cli.py \
> --spec Documentation/netlink/specs/em.yaml \
> --do get-pd-table --json '{"pd-id": 0}'
> $> tools/net/ynl/pyynl/cli.py \
> --spec Documentation/netlink/specs/em.yaml \
> --subscribe event --sleep 10
>
> [1] https://lwn.net/Articles/922405/
> [2] https://lore.kernel.org/lkml/a82423bc-8c38-4d57-93da-c4f20011cc92@arm.com/
>
> ChangeLog v1 -> v2:
> - Use YNL to generate boilerplate code. Overhaul the naming conventions
> (command, event, notification, attribute) to follow the typical
> conventions of other YNL-based netlink implementations.
> - Calculate the exact message size instead of using NLMSG_GOODSIZE
> when allocating a message (genlmsg_new). This avoids the reallocation
> of a message.
> - Remove an unnecessary function, em_netlink_exit(), and initialize the
> netlink (em_netlink_init) at em_netlink.c without touching energy_model.c.
>
> CC: Lukasz Luba <lukasz.luba@arm.com>
> CC: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> CC: Tejun Heo <tj@kernel.org>
> Signed-off-by: Changwoo Min <changwoo@igalia.com>
>
> Changwoo Min (10):
> PM: EM: Add em.yaml and autogen files.
> PM: EM: Add a skeleton code for netlink notification.
> PM: EM: Assign a unique ID when creating a performance domain.
> PM: EM: Expose the ID of a performance domain via debugfs.
> PM: EM: Add an iterator and accessor for the performance domain.
> PM: EM: Implement em_nl_get_pds_doit().
> PM: EM: Implement em_nl_get_pd_table_doit().
> PM: EM: Implement em_notify_pd_deleted().
> PM: EM: Implement em_notify_pd_created/updated().
> PM: EM: Notify an event when the performance domain changes.
>
> Documentation/netlink/specs/em.yaml | 113 ++++++++++
> MAINTAINERS | 3 +
> include/linux/energy_model.h | 19 ++
> include/uapi/linux/energy_model.h | 62 ++++++
> kernel/power/Makefile | 5 +-
> kernel/power/em_netlink.c | 311 ++++++++++++++++++++++++++++
> kernel/power/em_netlink.h | 34 +++
> kernel/power/em_netlink_autogen.c | 48 +++++
> kernel/power/em_netlink_autogen.h | 23 ++
> kernel/power/energy_model.c | 83 +++++++-
> 10 files changed, 699 insertions(+), 2 deletions(-)
> create mode 100644 Documentation/netlink/specs/em.yaml
> create mode 100644 include/uapi/linux/energy_model.h
> create mode 100644 kernel/power/em_netlink.c
> create mode 100644 kernel/power/em_netlink.h
> create mode 100644 kernel/power/em_netlink_autogen.c
> create mode 100644 kernel/power/em_netlink_autogen.h
>
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH v2 00/10] PM: EM: Add netlink support for the energy model.
2025-06-27 3:37 ` [PATCH v2 00/10] PM: EM: Add netlink support for the energy model Changwoo Min
@ 2025-06-30 10:07 ` Lukasz Luba
2025-07-02 1:02 ` Changwoo Min
0 siblings, 1 reply; 15+ messages in thread
From: Lukasz Luba @ 2025-06-30 10:07 UTC (permalink / raw)
To: Changwoo Min
Cc: christian.loehle, tj, pavel, len.brown, rafael, kernel-dev,
linux-pm, sched-ext, linux-kernel, Rafael J. Wysocki
Hi Changwoo,
On 6/27/25 04:37, Changwoo Min wrote:
> Gentle ping as it reaches 2-weeks.
My apologies for delay on that topic.
Let me have a look into this...
>
> @Lukasz, @Rafael -- I have a question related to the energy model
> in general. As far as I understand, the energy model describes
> the performance-energy consumption tradeoff when a single CPU in
> a performance domain is running. However, in reality, SoCs may
> have thermal constraints, which would result in additional
> constraints. For example, running all CPUs with the highest
> frequency may not be possible. My question is this: does kernel
> maintain and use such (thermal?) constraints?
That's true in real scenarios on mobile SoCs, running with max freq
on all CPUs is possible likely only for short period...
The Energy Model itself doesn't handle such situation. The code in
thermal framework and in Energy Aware Scheduler has feature to handle
it and know which top OPPs are not possible to be used.
Although, the EM in such situation is likely to be adjusted, because the
SoC temperature reaches high values. Especially if that heat was
generated by the GPU not CPUs themselves, then it's extra leakage will
be accounted and EM data modified in runtime.
Another scenario when the EM might be updated is when Middleware
will recognize a known 'scenario' e.g. long video conference
with camera in use (thus Image Signal Processor, which also can
heat the SoC, like GPU). Or a 'preferred profile' for light-weight
application using some HW decoding, e.g. video playback and
thus some CPUs are more preferred by EAS to be used in it (EM might
change the energy efficiency gently for such CPUs).
Regards,
Lukasz
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 00/10] PM: EM: Add netlink support for the energy model.
2025-06-30 10:07 ` Lukasz Luba
@ 2025-07-02 1:02 ` Changwoo Min
0 siblings, 0 replies; 15+ messages in thread
From: Changwoo Min @ 2025-07-02 1:02 UTC (permalink / raw)
To: Lukasz Luba
Cc: christian.loehle, tj, pavel, len.brown, rafael, kernel-dev,
linux-pm, sched-ext, linux-kernel, Rafael J. Wysocki
Hi Lukasz,
On 6/30/25 19:07, Lukasz Luba wrote:
>> @Lukasz, @Rafael -- I have a question related to the energy model
>> in general. As far as I understand, the energy model describes
>> the performance-energy consumption tradeoff when a single CPU in
>> a performance domain is running. However, in reality, SoCs may
>> have thermal constraints, which would result in additional
>> constraints. For example, running all CPUs with the highest
>> frequency may not be possible. My question is this: does kernel
>> maintain and use such (thermal?) constraints?
>
> That's true in real scenarios on mobile SoCs, running with max freq
> on all CPUs is possible likely only for short period...
>
> The Energy Model itself doesn't handle such situation. The code in
> thermal framework and in Energy Aware Scheduler has feature to handle
> it and know which top OPPs are not possible to be used.
>
> Although, the EM in such situation is likely to be adjusted, because the
> SoC temperature reaches high values. Especially if that heat was
> generated by the GPU not CPUs themselves, then it's extra leakage will
> be accounted and EM data modified in runtime.
>
> Another scenario when the EM might be updated is when Middleware
> will recognize a known 'scenario' e.g. long video conference
> with camera in use (thus Image Signal Processor, which also can
> heat the SoC, like GPU). Or a 'preferred profile' for light-weight
> application using some HW decoding, e.g. video playback and
> thus some CPUs are more preferred by EAS to be used in it (EM might
> change the energy efficiency gently for such CPUs).
Thank you for the explanation! Besides this, do you see anything that
needs to be addressed in the code? Of course, I expect there are. For
the one reported by the kernel test report, that is the obvious one, so
I will address it together with your and others' feedback
Regards,
Changwoo Min
^ permalink raw reply [flat|nested] 15+ messages in thread