[PATCH v2 1/4] coresight: tmc-etr: Prevent per-thread events from sharing a sink

James Clark james.clark at linaro.org
Thu Jul 9 08:25:21 PDT 2026


Sinks are potentially shared between multiple ETMs, and even with
Coresight being an exclusive PMU, multiple per-thread events in parallel
are supported. If both of the events are owned by the same PID then the
sink becomes shared resulting in trace from the wrong thread appearing
in a per-thread buffer and WARNs in the driver being hit:

  $ perf test -w named_threads 2 10 &
  $ perf record -e cs_etm//u --per-thread --pid 984

  WARNING: drivers/hwtracing/coresight/coresight-tmc-etr.c:1654 at tmc_update_etr_buffer+0x328/0x348 [coresight_tmc], CPU#1: perf/686
  [...]
  Call trace:
   tmc_update_etr_buffer+0x328/0x348 [coresight_tmc] (P)
   etm_event_stop+0x1c8/0x260 [coresight]
   etm_event_del+0x20/0x38 [coresight]
   event_sched_out+0xc4/0x1c8
   group_sched_out+0x5c/0x170
   __pmu_ctx_sched_out+0xe8/0x148
   ctx_sched_out+0x12c/0x178
   perf_event_exit_task_context+0xb0/0x3a8
   perf_event_exit_task+0xa4/0x138
   do_exit+0x1cc/0x808
   do_group_exit+0x7c/0xb0
   get_signal+0x628/0x678
   arch_do_signal_or_restart+0x98/0x1b28
   exit_to_user_mode_loop+0x90/0x188
   el0_svc+0x1cc/0x260
   el0t_64_sync_handler+0x78/0x130
   el0t_64_sync+0x198/0x1a0

Fix it by returning -EBUSY if a second per-thread event tries to use the
same sink. Users will only be able to use per-thread mode reliably with
multiple threads on a system that has a dedicated sink per ETM. This
limitation hasn't changed since this fix, it just makes the behavior
more consistent.

Fixes: 8d03cfd16a72 ("coresight: tmc-etr: Add support for CPU-wide trace scenarios")
Signed-off-by: James Clark <james.clark at linaro.org>
---
 drivers/hwtracing/coresight/coresight-core.c    | 31 +++++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 20 +++++-----------
 drivers/hwtracing/coresight/coresight-tmc.h     |  1 +
 include/linux/coresight.h                       |  3 +++
 4 files changed, 41 insertions(+), 14 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index f7b1308a759c..9410af0de49c 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -2246,6 +2246,37 @@ int coresight_get_enable_clocks(struct device *dev, struct clk **pclk,
 }
 EXPORT_SYMBOL_GPL(coresight_get_enable_clocks);
 
+/*
+ * Returns true if a sink that's potentially connected to multiple ETMs can be
+ * used in parallel with another event.
+ */
+bool coresight_sink_can_share(struct perf_event *existing,
+			      struct perf_event *new)
+{
+	/*
+	 * Inheritance in per-CPU mode means an event might not have an owner,
+	 * but the parent will.
+	 */
+	struct perf_event *existing_root = existing->parent ?: existing;
+	struct perf_event *new_root = new->parent ?: new;
+
+	/*
+	 * In per-thread mode only one event can use a sink, otherwise a sink
+	 * shared by multiple ETMs could have trace from two different threads
+	 * in it from two different events.
+	 */
+	if (existing->cpu == -1)
+		return existing == new;
+
+	/*
+	 * In per-CPU mode allow the sink to be shared across events, userspace
+	 * expects data from multiple CPUs in a shared sink. The only
+	 * restriction is the events must have the same owner.
+	 */
+	return existing_root->owner == new_root->owner;
+}
+EXPORT_SYMBOL_GPL(coresight_sink_can_share);
+
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Pratik Patel <pratikp at codeaurora.org>");
 MODULE_AUTHOR("Mathieu Poirier <mathieu.poirier at linaro.org>");
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 361a433e6f0c..ea05fa3e7902 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -1736,7 +1736,6 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev,
 				    struct coresight_path *path)
 {
 	int rc = 0;
-	pid_t pid;
 	unsigned long flags;
 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 	struct perf_output_handle *handle = path->handle;
@@ -1754,30 +1753,24 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev,
 		goto unlock_out;
 	}
 
-	/* Get a handle on the pid of the session owner */
-	pid = etr_perf->pid;
-
 	/* Do not proceed if this device is associated with another session */
-	if (drvdata->pid != -1 && drvdata->pid != pid) {
+	if (drvdata->event &&
+	    !coresight_sink_can_share(drvdata->event, handle->event)) {
 		rc = -EBUSY;
 		goto unlock_out;
 	}
 
-	/*
-	 * No HW configuration is needed if the sink is already in
-	 * use for this session.
-	 */
-	if (drvdata->pid == pid) {
+	/*  No HW configuration is needed if the sink is already in use. */
+	if (csdev->refcnt) {
 		csdev->refcnt++;
 		goto unlock_out;
 	}
 
 	rc = tmc_etr_enable_hw(drvdata, etr_perf->etr_buf);
 	if (!rc) {
-		/* Associate with monitored process. */
-		drvdata->pid = pid;
 		coresight_set_mode(csdev, CS_MODE_PERF);
 		drvdata->perf_buf = etr_perf->etr_buf;
+		drvdata->event = handle->event;
 		csdev->refcnt++;
 	}
 
@@ -1821,11 +1814,10 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev)
 	/* Complain if we (somehow) got out of sync */
 	WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED);
 	tmc_etr_disable_hw(drvdata);
-	/* Dissociate from monitored process. */
-	drvdata->pid = -1;
 	coresight_set_mode(csdev, CS_MODE_DISABLED);
 	/* Reset perf specific data */
 	drvdata->perf_buf = NULL;
+	drvdata->event = NULL;
 
 	raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 319a354ede9f..220fe45fca83 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -275,6 +275,7 @@ struct tmc_drvdata {
 	struct etr_buf		*perf_buf;
 	struct tmc_resrv_buf	resrv_buf;
 	struct tmc_resrv_buf	crash_mdata;
+	struct perf_event	*event;
 };
 
 struct etr_buf_operations {
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index add0579cad88..916ea657a194 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -715,4 +715,7 @@ int coresight_etm_get_trace_id(struct coresight_device *csdev, enum cs_mode mode
 			       struct coresight_device *sink);
 int coresight_get_enable_clocks(struct device *dev, struct clk **pclk,
 				struct clk **atclk);
+bool coresight_sink_can_share(struct perf_event *existing,
+			      struct perf_event *new);
+
 #endif		/* _LINUX_COREISGHT_H */

-- 
2.34.1




More information about the linux-arm-kernel mailing list