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
next prev 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®