[PATCH v2 24/28] coresight: Add PM callbacks for percpu sink
From: Leo Yan
Date: Tue Jul 01 2025 - 11:01:08 EST
Unlike a system level's sink, the per-CPU sink may lose power during CPU
idle states. Currently, this refers specifically to TRBE as the sink.
This commit registers save and restore callbacks for the per-CPU sink
via the PM notifier.
There are no changes to the coresight_enable_helpers() function; the
code movement is solely for compilation purposes.
Signed-off-by: Leo Yan <leo.yan@xxxxxxx>
---
drivers/hwtracing/coresight/coresight-core.c | 101 +++++++++++++++++++++------
include/linux/coresight.h | 4 ++
2 files changed, 82 insertions(+), 23 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 7693a0eade1a8de6d0960d66f6de682b5d5aff17..9978737d21177ab7cfcd449cf67a0b0736fcca5a 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -391,6 +391,25 @@ static void coresight_disable_helper(struct coresight_device *csdev, void *data)
helper_ops(csdev)->disable(csdev, data);
}
+static int coresight_enable_helpers(struct coresight_device *csdev,
+ enum cs_mode mode, void *data)
+{
+ int i, ret = 0;
+ struct coresight_device *helper;
+
+ for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
+ helper = csdev->pdata->out_conns[i]->dest_dev;
+ if (!helper || !coresight_is_helper(helper))
+ continue;
+
+ ret = coresight_enable_helper(helper, mode, data);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static void coresight_disable_helpers(struct coresight_device *csdev, void *data)
{
int i;
@@ -478,6 +497,43 @@ static void coresight_restore_source(struct coresight_device *csdev)
source_ops(csdev)->restore(csdev);
}
+static int coresight_save_percpu_sink(struct coresight_device *csdev)
+{
+ int ret;
+
+ if (csdev && sink_ops(csdev)->save) {
+ ret = sink_ops(csdev)->save(csdev);
+ if (ret)
+ return ret;
+
+ coresight_disable_helpers(csdev, NULL);
+ }
+
+ /* Return success if callback is not supported */
+ return 0;
+}
+
+static int coresight_restore_percpu_sink(struct coresight_device *csdev,
+ struct coresight_path *path,
+ enum cs_mode mode)
+{
+ int ret = 0;
+
+ if (csdev && sink_ops(csdev)->restore) {
+ ret = coresight_enable_helpers(csdev, mode, path);
+ if (ret)
+ return ret;
+
+ ret = sink_ops(csdev)->restore(csdev);
+ if (ret) {
+ coresight_disable_helpers(csdev, path);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
/*
* coresight_disable_path_from : Disable components in the given path beyond
* @nd in the list. If @nd is NULL, all the components, except the SOURCE are
@@ -551,25 +607,6 @@ void coresight_disable_path(struct coresight_path *path)
}
EXPORT_SYMBOL_GPL(coresight_disable_path);
-static int coresight_enable_helpers(struct coresight_device *csdev,
- enum cs_mode mode, void *data)
-{
- int i, ret = 0;
- struct coresight_device *helper;
-
- for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
- helper = csdev->pdata->out_conns[i]->dest_dev;
- if (!helper || !coresight_is_helper(helper))
- continue;
-
- ret = coresight_enable_helper(helper, mode, data);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
static int _coresight_enable_path(struct coresight_path *path,
enum cs_mode mode, void *sink_data,
bool in_idle)
@@ -1667,9 +1704,12 @@ EXPORT_SYMBOL_GPL(coresight_alloc_device_name);
static int coresight_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
void *v)
{
+ int ret;
unsigned int cpu = smp_processor_id();
struct coresight_device *source = per_cpu(csdev_source, cpu);
struct coresight_path *path;
+ struct coresight_device *sink;
+ enum cs_mode mode;
if (!coresight_need_save_restore_source(source))
return NOTIFY_OK;
@@ -1682,18 +1722,33 @@ static int coresight_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
if (WARN_ON(!path))
return NOTIFY_BAD;
+ sink = coresight_get_sink(path);
+ mode = coresight_get_mode(source);
+
switch (cmd) {
case CPU_PM_ENTER:
if (coresight_save_source(source))
return NOTIFY_BAD;
- coresight_disable_path_from(path, NULL, true);
+ ret = 0;
+ if (coresight_is_percpu_sink(sink))
+ ret = coresight_save_percpu_sink(sink);
+ else
+ coresight_disable_path_from(path, NULL, true);
+
+ if (ret) {
+ coresight_restore_source(source);
+ return NOTIFY_BAD;
+ }
break;
case CPU_PM_EXIT:
case CPU_PM_ENTER_FAILED:
- if (_coresight_enable_path(path,
- coresight_get_mode(source),
- NULL, true))
+ if (coresight_is_percpu_sink(sink))
+ ret = coresight_restore_percpu_sink(sink, path, mode);
+ else
+ ret = _coresight_enable_path(path, mode, NULL, true);
+
+ if (ret)
return NOTIFY_BAD;
coresight_restore_source(source);
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index f52e834640b72534ea83ab223aae7544b195bbaa..e551a36c40cc2311cd72948b799db5425b93fe68 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -363,6 +363,8 @@ enum cs_mode {
* @alloc_buffer: initialises perf's ring buffer for trace collection.
* @free_buffer: release memory allocated in @get_config.
* @update_buffer: update buffer pointers after a trace session.
+ * @save: save context for a sink.
+ * @restore: restore context for a sink.
*/
struct coresight_ops_sink {
int (*enable)(struct coresight_device *csdev, enum cs_mode mode,
@@ -375,6 +377,8 @@ struct coresight_ops_sink {
unsigned long (*update_buffer)(struct coresight_device *csdev,
struct perf_output_handle *handle,
void *sink_config);
+ int (*save)(struct coresight_device *csdev);
+ int (*restore)(struct coresight_device *csdev);
};
/**
--
2.34.1