mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: James Clark <james.clark@linaro.org>
To: Suzuki K Poulose <suzuki.poulose@arm.com>,
	 Mike Leach <mike.leach@arm.com>, Leo Yan <leo.yan@arm.com>,
	 Suyash Mahar <smahar@meta.com>,
	Yeoreum Yun <yeoreum.yun@arm.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	 Qi Liu <liuqi115@huawei.com>, Junhao He <hejunhao3@huawei.com>,
	 coresight@lists.linaro.org,
	linux-arm-kernel@lists.infradead.org,
	 linux-kernel@vger.kernel.org,
	James Clark <james.clark@linaro.org>,
	 Jonathan Cameron <jic23@kernel.org>
Subject: [PATCH v4 06/10] coresight: tmc-etr: Reflect new sharing rules in allocator
Date: Fri, 16 Oct 2026 11:46:16 +0100	[thread overview]
Message-ID: <20261016-james-cs-multiple-per-threads-v4-6-dedf961aca0e@linaro.org> (raw)
In-Reply-To: <20261016-james-cs-multiple-per-threads-v4-0-dedf961aca0e@linaro.org>

The IDR map is now unused because only one owner can use a shared sink
at a time. Replace it with a single sink local buffer,
'shared_perf_buf'.

And now that we don't have the IDR map to store buffers for different
sessions, allocate a private buffer for 1:1 per-cpu sessions as well as
per-thread sessions. We didn't eliminate any allocations by sharing
buffers in 1:1 scenarios anyway, and we allow multiple per-cpu
PERF_ATTACH_TASK events. Obviously multiple users can't use a single
shared_perf_buf buffer, so use a per-event one.

Use the single-source classification saved during AUX admission so that
buffer allocation follows the same sharing mode as existing sessions.

Signed-off-by: James Clark <james.clark@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc-core.c |   4 +-
 drivers/hwtracing/coresight/coresight-tmc-etr.c  | 103 ++++++++---------------
 drivers/hwtracing/coresight/coresight-tmc.h      |  10 +--
 3 files changed, 43 insertions(+), 74 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index bc5a133ada3e..864da1eea52c 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -9,7 +9,6 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/device.h>
-#include <linux/idr.h>
 #include <linux/io.h>
 #include <linux/iommu.h>
 #include <linux/err.h>
@@ -832,8 +831,7 @@ static int __tmc_probe(struct device *dev, struct resource *res)
 		ret = tmc_etr_setup_caps(dev, devid, &desc.access);
 		if (ret)
 			goto out;
-		idr_init(&drvdata->idr);
-		mutex_init(&drvdata->idr_mutex);
+		mutex_init(&drvdata->perf_buf_mutex);
 		dev_list = "tmc_etr";
 		break;
 	case TMC_CONFIG_TYPE_ETF:
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 361a433e6f0c..b4b186c605c6 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -8,7 +8,6 @@
 #include <linux/coresight.h>
 #include <linux/dma-mapping.h>
 #include <linux/iommu.h>
-#include <linux/idr.h>
 #include <linux/mutex.h>
 #include <linux/refcount.h>
 #include <linux/slab.h>
@@ -1396,16 +1395,13 @@ alloc_etr_buf(struct tmc_drvdata *drvdata, struct perf_event *event,
 	return ERR_PTR(-ENOMEM);
 }
 
-static struct etr_buf *
-get_perf_etr_buf_cpu_wide(struct tmc_drvdata *drvdata,
-			  struct perf_event *event, int nr_pages,
-			  void **pages, bool snapshot)
+static struct etr_buf *get_perf_shared_etr_buf(struct tmc_drvdata *drvdata,
+					       struct perf_event *event,
+					       int nr_pages, void **pages,
+					       bool snapshot)
 {
-	int ret;
-	pid_t pid = task_pid_nr(event->owner);
 	struct etr_buf *etr_buf;
 
-retry:
 	/*
 	 * An etr_perf_buffer is associated with an event and holds a reference
 	 * to the AUX ring buffer that was created for that event.  In CPU-wide
@@ -1424,64 +1420,45 @@ get_perf_etr_buf_cpu_wide(struct tmc_drvdata *drvdata,
 	 * allocated for this session.  If so it is shared with this event,
 	 * otherwise it is created.
 	 */
-	mutex_lock(&drvdata->idr_mutex);
-	etr_buf = idr_find(&drvdata->idr, pid);
+	mutex_lock(&drvdata->perf_buf_mutex);
+	etr_buf = drvdata->shared_perf_buf;
 	if (etr_buf) {
 		refcount_inc(&etr_buf->refcount);
-		mutex_unlock(&drvdata->idr_mutex);
-		return etr_buf;
+		goto out;
 	}
 
 	/* If we made it here no buffer has been allocated, do so now. */
-	mutex_unlock(&drvdata->idr_mutex);
-
 	etr_buf = alloc_etr_buf(drvdata, event, nr_pages, pages, snapshot);
-	if (IS_ERR(etr_buf))
-		return etr_buf;
-
-	/* Now that we have a buffer, add it to the IDR. */
-	mutex_lock(&drvdata->idr_mutex);
-	ret = idr_alloc(&drvdata->idr, etr_buf, pid, pid + 1, GFP_KERNEL);
-	mutex_unlock(&drvdata->idr_mutex);
-
-	/* Another event with this session ID has allocated this buffer. */
-	if (ret == -ENOSPC) {
-		tmc_free_etr_buf(etr_buf);
-		goto retry;
-	}
-
-	/* The IDR can't allocate room for a new session, abandon ship. */
-	if (ret == -ENOMEM) {
-		tmc_free_etr_buf(etr_buf);
-		return ERR_PTR(ret);
-	}
-
-
+	if (!IS_ERR(etr_buf))
+		drvdata->shared_perf_buf = etr_buf;
+out:
+	mutex_unlock(&drvdata->perf_buf_mutex);
 	return etr_buf;
 }
 
-static struct etr_buf *
-get_perf_etr_buf_per_thread(struct tmc_drvdata *drvdata,
-			    struct perf_event *event, int nr_pages,
-			    void **pages, bool snapshot)
-{
-	/*
-	 * In per-thread mode the etr_buf isn't shared, so just go ahead
-	 * with memory allocation.
-	 */
-	return alloc_etr_buf(drvdata, event, nr_pages, pages, snapshot);
-}
-
 static struct etr_buf *
 get_perf_etr_buf(struct tmc_drvdata *drvdata, struct perf_event *event,
 		 int nr_pages, void **pages, bool snapshot)
 {
-	if (event->cpu == -1)
-		return get_perf_etr_buf_per_thread(drvdata, event, nr_pages,
-						   pages, snapshot);
+	struct coresight_perf_session_id *session = &drvdata->csdev->perf_sink_id_map.session;
 
-	return get_perf_etr_buf_cpu_wide(drvdata, event, nr_pages,
-					 pages, snapshot);
+	/*
+	 * Migratable events and 1:1 sinks use private buffers. Don't create a
+	 * drvdata->shared_perf_buf because these type of events support
+	 * multiple concurrent users. The path's session reference keeps the
+	 * saved single-source classification stable throughout this allocation.
+	 */
+	if (event->cpu == -1 || session->single_source)
+		return alloc_etr_buf(drvdata, event, nr_pages, pages, snapshot);
+
+	/*
+	 * Sharing rules defined in coresight_trace_id_perf_start() mean that
+	 * only one user can own the sink now, so we can allocate a sink local
+	 * bounce buffer. If that user had requested events with different aux
+	 * sizes, we'll use the size of the first event to create the buffer.
+	 */
+	return get_perf_shared_etr_buf(drvdata, event, nr_pages, pages,
+				       snapshot);
 }
 
 static struct etr_perf_buffer *
@@ -1508,7 +1485,7 @@ tmc_etr_setup_perf_buf(struct tmc_drvdata *drvdata, struct perf_event *event,
 done:
 	/*
 	 * Keep a reference to the ETR this buffer has been allocated for
-	 * in order to have access to the IDR in tmc_free_etr_buffer().
+	 * in order to clear the shared buffer in tmc_free_etr_buffer().
 	 */
 	etr_perf->drvdata = drvdata;
 	etr_perf->etr_buf = etr_buf;
@@ -1543,28 +1520,22 @@ static void tmc_free_etr_buffer(void *config)
 {
 	struct etr_perf_buffer *etr_perf = config;
 	struct tmc_drvdata *drvdata = etr_perf->drvdata;
-	struct etr_buf *buf, *etr_buf = etr_perf->etr_buf;
+	struct etr_buf *etr_buf = etr_perf->etr_buf;
 
 	if (!etr_buf)
 		goto free_etr_perf_buffer;
 
-	mutex_lock(&drvdata->idr_mutex);
+	mutex_lock(&drvdata->perf_buf_mutex);
 	/* If we are not the last one to use the buffer, don't touch it. */
 	if (!refcount_dec_and_test(&etr_buf->refcount)) {
-		mutex_unlock(&drvdata->idr_mutex);
+		mutex_unlock(&drvdata->perf_buf_mutex);
 		goto free_etr_perf_buffer;
 	}
 
-	/* We are the last one, remove from the IDR and free the buffer. */
-	buf = idr_remove(&drvdata->idr, etr_perf->pid);
-	mutex_unlock(&drvdata->idr_mutex);
-
-	/*
-	 * Something went very wrong if the buffer associated with this ID
-	 * is not the same in the IDR.  Leak to avoid use after free.
-	 */
-	if (buf && WARN_ON(buf != etr_buf))
-		goto free_etr_perf_buffer;
+	/* Clear the CPU-wide cache before freeing its last reference. */
+	if (drvdata->shared_perf_buf == etr_buf)
+		drvdata->shared_perf_buf = NULL;
+	mutex_unlock(&drvdata->perf_buf_mutex);
 
 	tmc_free_etr_buf(etr_perf->etr_buf);
 
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 319a354ede9f..95e5623ea881 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -8,7 +8,6 @@
 #define _CORESIGHT_TMC_H
 
 #include <linux/dma-mapping.h>
-#include <linux/idr.h>
 #include <linux/miscdevice.h>
 #include <linux/mutex.h>
 #include <linux/refcount.h>
@@ -235,8 +234,8 @@ struct tmc_resrv_buf {
  * @etr_caps:	Bitmask of capabilities of the TMC ETR, inferred from the
  *		device configuration register (DEVID)
  * @etr_mode:	User preferred mode of the ETR device, default auto mode.
- * @idr:	Holds etr_bufs allocated for this ETR.
- * @idr_mutex:	Access serialisation for idr.
+ * @shared_perf_buf: CPU-wide perf buffer shared by this ETR's owner.
+ * @perf_buf_mutex: Protects shared_perf_buf and its reference count.
  * @sysfs_buf:	SYSFS buffer for ETR.
  * @perf_buf:	PERF buffer for ETR.
  * @resrv_buf:  Used by ETR as hardware trace buffer and for trace data
@@ -269,8 +268,9 @@ struct tmc_drvdata {
 	u32			trigger_cntr;
 	u32			etr_caps;
 	enum etr_mode		etr_mode;
-	struct idr		idr;
-	struct mutex		idr_mutex;
+	struct etr_buf		*shared_perf_buf;
+	/* Protects shared_perf_buf and its reference count. */
+	struct mutex		perf_buf_mutex;
 	struct etr_buf		*sysfs_buf;
 	struct etr_buf		*perf_buf;
 	struct tmc_resrv_buf	resrv_buf;

-- 
2.43.0


  parent reply	other threads:[~2026-10-16 10:46 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-16 10:46 [PATCH v4 00/10] coresight: Prevent per-thread events from sharing a sink James Clark
2026-10-16 10:46 ` [PATCH v4 01/10] coresight: configfs: Don't assume active until cscfg_mgr is set James Clark
2026-10-16 10:46 ` [PATCH v4 02/10] coresight: etm-perf: Remove workqueue for freeing AUX data James Clark
2026-10-16 10:46 ` [PATCH v4 03/10] coresight: etm-perf: Serialize AUX topology access James Clark
2026-10-16 10:46 ` [PATCH v4 04/10] coresight: etm-perf: Reject event if building path fails James Clark
2026-10-16 10:46 ` [PATCH v4 05/10] coresight: etm-perf: Prevent sink sharing at setup time James Clark
2026-10-16 10:46 ` James Clark [this message]
2026-10-16 10:46 ` [PATCH v4 07/10] coresight: tmc-etr: Remove sharing guards from ETR James Clark
2026-10-16 10:46 ` [PATCH v4 08/10] coresight: tmc-etf: Remove sharing guards from ETF James Clark
2026-10-16 10:46 ` [PATCH v4 09/10] coresight: etb10: Remove sharing guards from ETB10 James Clark
2026-10-16 10:46 ` [PATCH v4 10/10] coresight: ultrasoc-smb: Remove sharing guards from SMB James Clark

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261016-james-cs-multiple-per-threads-v4-6-dedf961aca0e@linaro.org \
    --to=james.clark@linaro.org \
    --cc=coresight@lists.linaro.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=hejunhao3@huawei.com \
    --cc=jic23@kernel.org \
    --cc=leo.yan@arm.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=liuqi115@huawei.com \
    --cc=mike.leach@arm.com \
    --cc=smahar@meta.com \
    --cc=suzuki.poulose@arm.com \
    --cc=yeoreum.yun@arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®