[PATCH] pmdomain: core: Add tracepoints for domain state changes
DORMANTno replies
From: Abel Vesa <hidden>
Date: 2026-09-24 15:07:43
Also in:
linux-pm, lkml
Subsystem:
generic pm domains, the rest, tracing · Maintainers:
Ulf Hansson, Linus Torvalds, Steven Rostedt, Masami Hiramatsu
Power domain state changes are difficult to correlate with device activity using snapshots of the genpd debugfs state alone. Add tracepoints for domain initialization, power-on and power-off operations, and performance-state changes. Record the domain name and initial power and performance states at initialization. For power operations, record the idle-state index and return value, and for performance-state changes, record the requested state and return value. Emit the operation tracepoints on both success and failure paths, including power notifier failures and performance-state rollback paths, to make failed transitions visible alongside successful ones. Assisted-by: LLM Signed-off-by: Abel Vesa <redacted> --- drivers/pmdomain/core.c | 27 +++++++++---- include/trace/events/genpd.h | 94 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 7 deletions(-)
diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c
index b99c2dcf3d8f..62bd29e5918d 100644
--- a/drivers/pmdomain/core.c
+++ b/drivers/pmdomain/core.c@@ -28,6 +28,9 @@ #include <trace/events/ipi.h> +#define CREATE_TRACE_POINTS +#include <trace/events/genpd.h> + /* Provides a unique ID for each genpd device */ static DEFINE_IDA(genpd_ida);
@@ -485,7 +488,7 @@ static int _genpd_set_performance_state(struct generic_pm_domain *genpd, if (ret) { if (link) goto rollback_parents_up; - return ret; + goto out; } }
@@ -499,15 +502,18 @@ static int _genpd_set_performance_state(struct generic_pm_domain *genpd, } genpd->performance_state = state; - return 0; + ret = 0; + goto out; rollback_parents_up: list_for_each_entry_continue_reverse(link, &genpd->child_links, child_node) _genpd_rollback_parent_state(link, depth); - return ret; + goto out; rollback_parents_down: list_for_each_entry_continue(link, &genpd->child_links, child_node) _genpd_rollback_parent_state(link, depth); +out: + trace_genpd_set_performance_state(dev_name(&genpd->dev), state, ret); return ret; }
@@ -842,7 +848,7 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed) GENPD_NOTIFY_OFF, NULL); ret = notifier_to_errno(ret); if (ret) - return ret; + goto trace; if (!genpd->power_on) goto out;
@@ -873,10 +879,13 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed) out: raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_ON, NULL); genpd->synced_poweroff = false; - return 0; + ret = 0; + goto trace; err: raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_OFF, NULL); +trace: + trace_genpd_power_on(dev_name(&genpd->dev), state_idx, ret); return ret; }
@@ -893,7 +902,7 @@ static int _genpd_power_off(struct generic_pm_domain *genpd, bool timed) GENPD_NOTIFY_ON, NULL); ret = notifier_to_errno(ret); if (ret) - return ret; + goto trace; if (!genpd->power_off) goto out;
@@ -924,9 +933,12 @@ static int _genpd_power_off(struct generic_pm_domain *genpd, bool timed) out: raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_OFF, NULL); - return 0; + ret = 0; + goto trace; busy: raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_ON, NULL); +trace: + trace_genpd_power_off(dev_name(&genpd->dev), state_idx, ret); return ret; }
@@ -2529,6 +2541,7 @@ int pm_genpd_init(struct generic_pm_domain *genpd, return ret; mutex_lock(&gpd_list_lock); + trace_genpd_init(dev_name(&genpd->dev), !is_off, genpd->performance_state); list_add(&genpd->gpd_list_node, &gpd_list); mutex_unlock(&gpd_list_lock); genpd_debug_add(genpd);
diff --git a/include/trace/events/genpd.h b/include/trace/events/genpd.h
new file mode 100644
index 000000000000..e2970be0796a
--- /dev/null
+++ b/include/trace/events/genpd.h@@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM genpd + +#if !defined(_TRACE_GENPD_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_GENPD_H + +#include <linux/tracepoint.h> + +TRACE_EVENT(genpd_init, + + TP_PROTO(const char *name, bool on, unsigned int performance_state), + + TP_ARGS(name, on, performance_state), + + TP_STRUCT__entry( + __string(name, name) + __field(bool, on) + __field(unsigned int, performance_state) + ), + + TP_fast_assign( + __assign_str(name); + __entry->on = on; + __entry->performance_state = performance_state; + ), + + TP_printk("%s on=%d performance_state=%u", __get_str(name), + __entry->on, __entry->performance_state) +); + +/* state_idx identifies the idle state entered or exited. */ +DECLARE_EVENT_CLASS(genpd_power, + + TP_PROTO(const char *name, unsigned int state_idx, int ret), + + TP_ARGS(name, state_idx, ret), + + TP_STRUCT__entry( + __string(name, name) + __field(unsigned int, state_idx) + __field(int, ret) + ), + + TP_fast_assign( + __assign_str(name); + __entry->state_idx = state_idx; + __entry->ret = ret; + ), + + TP_printk("%s state_idx=%u ret=%d", __get_str(name), + __entry->state_idx, __entry->ret) +); + +DEFINE_EVENT(genpd_power, genpd_power_on, + + TP_PROTO(const char *name, unsigned int state_idx, int ret), + + TP_ARGS(name, state_idx, ret) +); + +DEFINE_EVENT(genpd_power, genpd_power_off, + + TP_PROTO(const char *name, unsigned int state_idx, int ret), + + TP_ARGS(name, state_idx, ret) +); + +TRACE_EVENT(genpd_set_performance_state, + + TP_PROTO(const char *name, unsigned int state, int ret), + + TP_ARGS(name, state, ret), + + TP_STRUCT__entry( + __string(name, name) + __field(unsigned int, state) + __field(int, ret) + ), + + TP_fast_assign( + __assign_str(name); + __entry->state = state; + __entry->ret = ret; + ), + + TP_printk("%s state=%u ret=%d", __get_str(name), + __entry->state, __entry->ret) +); + +#endif /* _TRACE_GENPD_H */ + +/* This part must be outside protection. */ +#include <trace/define_trace.h>
--- base-commit: 3d7783543c2646af69ad65825e810060494bea21 change-id: 20260924-add-pmdomain-tracepoints-15254f2cd40f Best regards, -- Abel Vesa [off-list ref]