[PATCH v7 15/20] coresight: Control path during CPU idle
Leo Yan
leo.yan at arm.com
Fri Mar 20 10:42:57 PDT 2026
Control links and helpers on an active path during CPU idle.
The helper coresight_get_local_cpu_path() uses coresight_dev_lock to
exclusive access to the per-CPU source pointer, then retrieves the path
pointer (csdev->path). The path pointer is only set via an SMP
call on the local CPU, which is serialized with CPU PM notifiers.
If the CPU PM notifier retrieves a non-NULL path pointer, it is safe to
iterate over the path and control it up to the node before the sink to
avoid latency.
Since coresight_disable_path() does not handle a source device's
helpers, explicitly disable them alongside the source device.
Signed-off-by: Leo Yan <leo.yan at arm.com>
---
drivers/hwtracing/coresight/coresight-core.c | 72 ++++++++++++++++++++++++----
1 file changed, 63 insertions(+), 9 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 874bd87da2270fdbe6b32c2fa29292d7a26b8dc7..b888a31ca6abffe62e2264574a6d61b43184f600 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -113,6 +113,29 @@ struct coresight_device *coresight_get_percpu_source(int cpu)
return per_cpu(csdev_source, cpu);
}
+/*
+ * The source device's csdev->path is always set on the local CPU.
+ * CPU PM notifiers also run on the same CPU, so accesses to
+ * csdev->path are serialized.
+ *
+ * When the path is constructed, each component on the path takes module
+ * reference counts, and the source's csdev->path is set last. Therefore,
+ * when the CPU PM notifier retrieves the path on the local CPU, a non-NULL
+ * csdev->path guarantees that the path is safe to iterate over.
+ */
+static struct coresight_path *coresight_get_local_cpu_path(void)
+{
+ struct coresight_device *csdev;
+
+ guard(raw_spinlock_irqsave)(&coresight_dev_lock);
+
+ csdev = this_cpu_read(csdev_source);
+ if (!csdev)
+ return NULL;
+
+ return csdev->path;
+}
+
static struct coresight_device *coresight_get_source(struct coresight_path *path)
{
struct coresight_device *csdev;
@@ -1765,8 +1788,14 @@ static void coresight_release_device_list(void)
}
}
-static bool coresight_pm_is_needed(struct coresight_device *csdev)
+static bool coresight_pm_is_needed(struct coresight_path *path)
{
+ struct coresight_device *csdev;
+
+ if (!path)
+ return false;
+
+ csdev = coresight_get_source(path);
if (!csdev)
return false;
@@ -1792,33 +1821,58 @@ static void coresight_pm_device_restore(struct coresight_device *csdev)
coresight_ops(csdev)->pm_restore_enable(csdev);
}
-static int coresight_pm_save(struct coresight_device *source)
+static int coresight_pm_save(struct coresight_path *path)
{
- return coresight_pm_device_save(source);
+ struct coresight_device *source;
+ struct coresight_node *from, *to;
+ int ret;
+
+ source = coresight_get_source(path);
+ ret = coresight_pm_device_save(source);
+ if (ret)
+ return ret;
+
+ coresight_disable_helpers(source, path);
+
+ from = coresight_path_first_node(path);
+ /* Up to the node before sink to avoid latency */
+ to = list_prev_entry(coresight_path_last_node(path), link);
+ coresight_disable_path_from_to(path, from, to);
+
+ return 0;
}
-static void coresight_pm_restore(struct coresight_device *source)
+static void coresight_pm_restore(struct coresight_path *path)
{
+ struct coresight_device *source;
+ struct coresight_node *from, *to;
+
+ source = coresight_get_source(path);
+ from = coresight_path_first_node(path);
+ /* Up to the node before sink to avoid latency */
+ to = list_prev_entry(coresight_path_last_node(path), link);
+ coresight_enable_path_from_to(path, coresight_get_mode(source),
+ from, to);
+
coresight_pm_device_restore(source);
}
static int coresight_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
void *v)
{
- struct coresight_device *source =
- coresight_get_percpu_source(smp_processor_id());
+ struct coresight_path *path = coresight_get_local_cpu_path();
- if (!coresight_pm_is_needed(source))
+ if (!coresight_pm_is_needed(path))
return NOTIFY_OK;
switch (cmd) {
case CPU_PM_ENTER:
- if (coresight_pm_save(source))
+ if (coresight_pm_save(path))
return NOTIFY_BAD;
break;
case CPU_PM_EXIT:
case CPU_PM_ENTER_FAILED:
- coresight_pm_restore(source);
+ coresight_pm_restore(path);
break;
default:
return NOTIFY_DONE;
--
2.34.1
More information about the linux-arm-kernel
mailing list