[PATCH v8 18/23] coresight: Control path during CPU idle

Leo Yan leo.yan at arm.com
Wed Mar 25 07:26:55 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.

Signed-off-by: Leo Yan <leo.yan at arm.com>
---
 drivers/hwtracing/coresight/coresight-core.c | 70 ++++++++++++++++++++++++----
 1 file changed, 61 insertions(+), 9 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index a74a595dd61f1a004ee0ebc9600127c928ee9f16..5060ccbc8f4c82eb14ec081ec05709391a585a11 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -131,6 +131,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;
@@ -1768,8 +1791,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;
 
@@ -1795,33 +1824,56 @@ 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;
+
+	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