summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Yan <leo.yan@arm.com>2026-05-15 23:08:31 +0300
committerSuzuki K Poulose <suzuki.poulose@arm.com>2026-05-18 12:18:47 +0300
commit7bbe5a172376d1bbf5da4a68fee6d77ae5a03e55 (patch)
tree7fc9ceb3742567a55f80c99a40b6b08f337c2246
parent39c40892f1a45908fbc57c334ac503da0c80d77c (diff)
downloadlinux-7bbe5a172376d1bbf5da4a68fee6d77ae5a03e55.tar.xz
coresight: Add PM callbacks for sink device
Unlike system level sinks, per-CPU sinks may lose power during CPU idle states. Currently, this applies specifically to TRBE. This commit invokes save and restore callbacks for the sink in the CPU PM notifier. If the sink provides PM callbacks but the source does not, this is unsafe because the sink cannot be disabled safely unless the source can also be controlled, so veto low power entry to avoid lockups. Tested-by: James Clark <james.clark@linaro.org> Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com> Reviewed-by: James Clark <james.clark@linaro.org> Tested-by: Jie Gan <jie.gan@oss.qualcomm.com> Signed-off-by: Leo Yan <leo.yan@arm.com> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> Link: https://lore.kernel.org/r/20260515-arm_coresight_path_power_management_improvement-v14-24-f88c4a3ecfe9@arm.com
-rw-r--r--drivers/hwtracing/coresight/coresight-core.c35
1 files changed, 33 insertions, 2 deletions
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index fc60b72a4abf..e3de4b388372 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -1874,7 +1874,7 @@ static struct coresight_path *coresight_cpu_get_active_path(void)
/* Return: 1 if PM is required, 0 if skip, or a negative error */
static int coresight_pm_is_needed(struct coresight_path *path)
{
- struct coresight_device *source;
+ struct coresight_device *source, *sink;
if (this_cpu_read(percpu_pm_failed))
return -EIO;
@@ -1883,7 +1883,8 @@ static int coresight_pm_is_needed(struct coresight_path *path)
return 0;
source = coresight_get_source(path);
- if (!source)
+ sink = coresight_get_sink(path);
+ if (!source || !sink)
return 0;
/* pm_save_disable() and pm_restore_enable() must be paired */
@@ -1891,16 +1892,35 @@ static int coresight_pm_is_needed(struct coresight_path *path)
coresight_ops(source)->pm_restore_enable)
return 1;
+ /*
+ * It is not permitted that the source has no callbacks while the sink
+ * does, as the sink cannot be disabled without disabling the source,
+ * which may lead to lockups. Fix this by enabling self-hosted PM
+ * mode for ETM (see etm4_probe()).
+ */
+ if (coresight_ops(sink)->pm_save_disable &&
+ coresight_ops(sink)->pm_restore_enable) {
+ pr_warn_once("coresight PM failed: source has no PM callbacks; "
+ "cannot safely control sink\n");
+ return -EINVAL;
+ }
+
return 0;
}
static int coresight_pm_device_save(struct coresight_device *csdev)
{
+ if (!csdev || !coresight_ops(csdev)->pm_save_disable)
+ return 0;
+
return coresight_ops(csdev)->pm_save_disable(csdev);
}
static void coresight_pm_device_restore(struct coresight_device *csdev)
{
+ if (!csdev || !coresight_ops(csdev)->pm_restore_enable)
+ return;
+
coresight_ops(csdev)->pm_restore_enable(csdev);
}
@@ -1919,15 +1939,24 @@ static int coresight_pm_save(struct coresight_path *path)
to = list_prev_entry(coresight_path_last_node(path), link);
coresight_disable_path_from_to(path, from, to);
+ /*
+ * Save the sink. Most sinks do not implement a save callback to avoid
+ * latency from memory copying. We assume the sink's save and restore
+ * always succeed.
+ */
+ coresight_pm_device_save(coresight_get_sink(path));
return 0;
}
static void coresight_pm_restore(struct coresight_path *path)
{
struct coresight_device *source = coresight_get_source(path);
+ struct coresight_device *sink = coresight_get_sink(path);
struct coresight_node *from, *to;
int ret;
+ coresight_pm_device_restore(sink);
+
from = coresight_path_first_node(path);
/* Enable up to the node before sink */
to = list_prev_entry(coresight_path_last_node(path), link);
@@ -1940,6 +1969,8 @@ static void coresight_pm_restore(struct coresight_path *path)
return;
path_failed:
+ coresight_pm_device_save(sink);
+
pr_err("Failed in coresight PM restore on CPU%d: %d\n",
smp_processor_id(), ret);