All CoreSight compliant components have an implementation defined number
of 0 to 8 claim tag bits in the claim tag registers.
These are used to claim the CoreSight resources by system agents.
ARM recommends implementions have 4 claim tag registers.
The CoreSight drivers implement a 2 claim tag bit protocol to allow
self hosted and external debug agents to manage access to the hardware.
However, if there are less than 2 claim tags available the protocol
incorrectly returns an error on device claim, as no checks are made.
If insufficient claim tags are present in a component then the protocol
must return success on claim / disclaim to allow components to be used
normally.
Changes read the CLAIMSET bits to establish the number of available tags,
and adjust the claim returns accordingly.
Applies to coresignt/next
Mike Leach (1):
coresight: fix issue where coresight component has no claimtags
drivers/hwtracing/coresight/coresight-core.c | 26 ++++++++++++++++++++
drivers/hwtracing/coresight/coresight-priv.h | 8 ++++++
2 files changed, 34 insertions(+)
--
2.32.0
Do some cleanups then add a new format attribute to set the timestamp
interval for ETMv4 in Perf mode. The current interval is too high for
most use cases, and particularly on the FVP the number of timestamps
generated is excessive.
Although it would be good to make only SYNC timestamps the default and
have counter timestamps opt-in, this would be a breaking change. We
can always do that later, or disable counter timestamps from Perf.
This is added as an event format attribute, rather than a Coresight
config because it's something that the driver is already configuring
automatically in Perf mode with any unused counter, so it's not possible
to modify this with a config.
Applies to coresight/next
Signed-off-by: James Clark <james.clark(a)linaro.org>
---
Changes in v3:
- Move the format attr definitions to coresight-etm-perf.h we can
compile on arm32 without #ifdefs - (Leo)
- Convert the new #ifdefs to a single one in an is_visible() function so
that the code is cleaner - (Leo)
- Drop the change to remove the holes in struct etmv4_config as they
were grouped by function - (Mike)
- Link to v2: https://lore.kernel.org/r/20250814-james-cs-syncfreq-v2-0-c76fcb87696d@lina…
Changes in v2:
- Only show the attribute for ETMv4 to improve usability and fix the
arm32 build error. Wrapping everything in
IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X) isn't ideal, but the -perf.c
file is shared between ETMv3 and ETMv4, and there is already precedent
for doing it this way.
- Link to v1: https://lore.kernel.org/r/20250811-james-cs-syncfreq-v1-0-b001cd6e3404@lina…
---
James Clark (5):
coresight: Change syncfreq to be a u8
coresight: Repack struct etmv4_drvdata
coresight: Refactor etm4_config_timestamp_event()
coresight: Add format attribute for setting the timestamp interval
coresight: docs: Document etm4x ts_interval
Documentation/trace/coresight/coresight.rst | 14 +++
drivers/hwtracing/coresight/coresight-etm-perf.c | 16 ++-
drivers/hwtracing/coresight/coresight-etm-perf.h | 7 ++
drivers/hwtracing/coresight/coresight-etm4x-core.c | 110 +++++++++++++--------
drivers/hwtracing/coresight/coresight-etm4x.h | 61 +++++++-----
5 files changed, 143 insertions(+), 65 deletions(-)
---
base-commit: 01f96b812526a2c8dcd5c0e510dda37e09ec8bcd
change-id: 20250724-james-cs-syncfreq-7c2257a38ed3
Best regards,
--
James Clark <james.clark(a)linaro.org>
On Tue, Oct 21, 2025 at 09:56:43AM +0800, Jie Gan wrote:
[...]
> > diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> > index b07fcdb3fe1a..d0fac958c614 100644
> > --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> > +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> > @@ -1241,6 +1241,8 @@ static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
> > struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> > struct etr_buf *sysfs_buf = NULL, *new_buf = NULL, *free_buf = NULL;
> > + WARN_ON(coresight_get_mode(csdev) != CS_MODE_SYSFS);
>
> I think we should check the WARN_ON result and exit if there is an error?
When run at here, it should be in Sysfs mode. Here the check is for
debugging purpose in case any mismatch.
[...]
> > +static void tmc_release_mode(struct coresight_device *csdev, enum cs_mode mode)
> > +{
> > + struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> > +
> > + scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock);
> > +
> > + if (WARN_ON(coresight_get_mode(csdev) != mode))
> > + return;
>
> the mode here could be set to any CS_MODE, so I think it's possible to
> encounter the secenario below:
>
> coresight_get_mode(csdev) == CS_MODE_DISABLED, mode == CS_MODE_DISABLED,
>
> With the condition, the csdev->refcnt will go to negative number?
The parameter "mode" might cause complexity, will drop it. The
correctness will be ensured by the callers.
Thanks for review!
Leo
On Mon, Oct 20, 2025 at 05:06:46PM +0800, Xiaoqi Zhuang wrote:
> When ETR is enabled as CS_MODE_SYSFS, if the buffer size is changed
> and enabled again, currently sysfs_buf will point to the newly
> allocated memory(buf_new) and free the old memory(buf_old). But the
> etr_buf that is being used by the ETR remains pointed to buf_old, not
> updated to buf_new. In this case, it will result in a memory
> use-after-free issue.
I struggled to understand how to reproduce the issue under the condition
"if the buffer size is changed and enabled again."
I don't think the flow below where the trace is re-enabled would cause
an issue:
- Step 1: Enable trace path between ETM0 -> ETR0;
- Step 2: Change the buffer size for ETR0;
- Step 3: Disable trace path between ETM0 -> ETR0;
- Step 4: Enable again trace path between ETM0 -> ETR0.
In this case, step3 releases the buffer and update "drvdata->etr_buf" to
NULL, and step 4 allocates a new buffer and assign it to
"drvdata->etr_buf".
The problem should occur when operating on two trace paths, E.g.,
- Step 1: Enable trace path between ETM0 -> ETR0;
- Step 2: Change the buffer size for ETR0;
- Step 3: Enable trace path between ETM1 -> ETR0;
In step3, the driver releases the existed buffer and allocate a new one.
At the meantime, "drvdata->etr_buf" still holds the buffer allocated in
step 1.
> Fix this by checking ETR's mode before updating and releasing buf_old,
> if the mode is CS_MODE_SYSFS, then skip updating and releasing it.
Given that we now have a couple of reported issues related to ETR mode,
I'd like to refactor the ETR mode handling and its reference counting
thoroughly. I've drafted a large change (it's quite big, but we can
split it into small patches if we agree to proceed).
Thanks for reporting the issue!
Leo
---8<---
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index b07fcdb3fe1a..d0fac958c614 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -1241,6 +1241,8 @@ static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
struct etr_buf *sysfs_buf = NULL, *new_buf = NULL, *free_buf = NULL;
+ WARN_ON(coresight_get_mode(csdev) != CS_MODE_SYSFS);
+
/*
* If we are enabling the ETR from disabled state, we need to make
* sure we have a buffer with the right size. The etr_buf is not reset
@@ -1263,7 +1265,7 @@ static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
raw_spin_lock_irqsave(&drvdata->spinlock, flags);
}
- if (drvdata->reading || coresight_get_mode(csdev) == CS_MODE_PERF) {
+ if (drvdata->reading) {
ret = -EBUSY;
goto out;
}
@@ -1292,30 +1294,14 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
int ret = 0;
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- struct etr_buf *sysfs_buf = tmc_etr_get_sysfs_buffer(csdev);
+ struct etr_buf *sysfs_buf;
+ sysfs_buf = tmc_etr_get_sysfs_buffer(csdev);
if (IS_ERR(sysfs_buf))
return PTR_ERR(sysfs_buf);
raw_spin_lock_irqsave(&drvdata->spinlock, flags);
-
- /*
- * In sysFS mode we can have multiple writers per sink. Since this
- * sink is already enabled no memory is needed and the HW need not be
- * touched, even if the buffer size has changed.
- */
- if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
- csdev->refcnt++;
- goto out;
- }
-
ret = tmc_etr_enable_hw(drvdata, sysfs_buf);
- if (!ret) {
- coresight_set_mode(csdev, CS_MODE_SYSFS);
- csdev->refcnt++;
- }
-
-out:
raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
if (!ret)
@@ -1735,11 +1721,6 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
struct etr_perf_buffer *etr_perf = etm_perf_sink_config(handle);
raw_spin_lock_irqsave(&drvdata->spinlock, flags);
- /* Don't use this sink if it is already claimed by sysFS */
- if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
- rc = -EBUSY;
- goto unlock_out;
- }
if (WARN_ON(!etr_perf || !etr_perf->etr_buf)) {
rc = -EINVAL;
@@ -1759,18 +1740,14 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
* No HW configuration is needed if the sink is already in
* use for this session.
*/
- if (drvdata->pid == pid) {
- csdev->refcnt++;
+ if (drvdata->pid == pid)
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;
- csdev->refcnt++;
}
unlock_out:
@@ -1778,17 +1755,76 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
return rc;
}
+static int tmc_acquire_mode(struct coresight_device *csdev, enum cs_mode mode)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ if (mode != CS_MODE_SYSFS && mode != CS_MODE_PERF)
+ return -EINVAL;
+
+ scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock);
+
+ if (coresight_get_mode(csdev) == CS_MODE_DISABLED) {
+ if (!csdev->refcnt)
+ coresight_set_mode(csdev, mode);
+ csdev->refcnt++;
+ } else if (coresight_get_mode(csdev) != mode) {
+ ret = -EBUSY;
+ }
+
+ return csdev->refcnt;
+}
+
+static void tmc_release_mode(struct coresight_device *csdev, enum cs_mode mode)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock);
+
+ if (WARN_ON(coresight_get_mode(csdev) != mode))
+ return;
+
+ csdev->refcnt--;
+ if (!csdev->refcnt)
+ coresight_set_mode(csdev, CS_MODE_DISABLED);
+}
+
static int tmc_enable_etr_sink(struct coresight_device *csdev,
enum cs_mode mode, void *data)
{
+ unsigned long flags;
+ struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ int ret;
+
+ ret = tmc_acquire_mode(csdev, mode);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * For sysfs mode, the higher level mutex ensures exclusively
+ * enabling sink, it is safe to bail out if this is not the
+ * first time to enable sink.
+ *
+ * A perf session can enable the same sink simultaneously, fall
+ * through to call tmc_enable_etr_sink_perf() to ensure the sink
+ * has been enabled.
+ */
+ if (mode == CS_MODE_SYSFS && ret > 1)
+ return 0;
+
switch (mode) {
case CS_MODE_SYSFS:
- return tmc_enable_etr_sink_sysfs(csdev);
+ ret = tmc_enable_etr_sink_sysfs(csdev);
case CS_MODE_PERF:
- return tmc_enable_etr_sink_perf(csdev, data);
+ ret = tmc_enable_etr_sink_perf(csdev, data);
default:
- return -EINVAL;
+ ret = -EINVAL;
}
+
+ if (ret)
+ tmc_release_mode(csdev, mode);
+
+ return ret;
}
static int tmc_disable_etr_sink(struct coresight_device *csdev)
@@ -1796,30 +1832,20 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev)
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+ tmc_release_mode(csdev, mode);
- if (drvdata->reading) {
- raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
- return -EBUSY;
- }
+ scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock);
- csdev->refcnt--;
- if (csdev->refcnt) {
- raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ if (csdev->refcnt || drvdata->reading)
return -EBUSY;
- }
- /* Complain if we (somehow) got out of sync */
- WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED);
+ if (drvdata->pid == -1)
+ return 0;
+
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;
- raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
-
dev_dbg(&csdev->dev, "TMC-ETR disabled\n");
return 0;
}
On 20/10/2025 11:18, Jie Gan wrote:
>
>
> On 10/20/2025 5:06 PM, Xiaoqi Zhuang wrote:
>> When ETR is enabled as CS_MODE_SYSFS, if the buffer size is changed
>> and enabled again, currently sysfs_buf will point to the newly
>> allocated memory(buf_new) and free the old memory(buf_old). But the
>> etr_buf that is being used by the ETR remains pointed to buf_old, not
>> updated to buf_new. In this case, it will result in a memory
>> use-after-free issue.
>>
>> Fix this by checking ETR's mode before updating and releasing buf_old,
>> if the mode is CS_MODE_SYSFS, then skip updating and releasing it.
>>
>
> I think we need a fix tag for the fix patch:
> Fixes: de5461970b3e ("coresight: tmc: allocating memory when needed")
>
> minor comment:
> Since ETR is enabled, we can't switch the sysfs buffer, can we exit
> earlier by checking the CS_MODE to avoid allocating memory unnecessarily?
+1
Something like this:
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c
b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index b07fcdb3fe1a..a9ddb05c10d9 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -1252,6 +1252,12 @@ static struct etr_buf
*tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
raw_spin_lock_irqsave(&drvdata->spinlock, flags);
sysfs_buf = READ_ONCE(drvdata->sysfs_buf);
if (!sysfs_buf || (sysfs_buf->size != drvdata->size)) {
+ /*
+ * If the ETR is already enabled, continue with the existing
+ * buffer.
+ */
+ if (coresight_get_mode(csdev) == CS_MODE_SYSFS)
+ goto out;
raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
/* Allocate memory with the locks released */
Suzuki>
> Besides,
> Looks good to me.
>
> Thanks,
> Jie
>
>> Signed-off-by: Xiaoqi Zhuang <xiaoqi.zhuang(a)oss.qualcomm.com>
>> ---
>> drivers/hwtracing/coresight/coresight-tmc-etr.c | 7 +++++++
>> 1 file changed, 7 insertions(+)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/
>> drivers/hwtracing/coresight/coresight-tmc-etr.c
>> index b07fcdb3fe1a..3e73cf2c38a3 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> @@ -1268,6 +1268,13 @@ static struct etr_buf
>> *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
>> goto out;
>> }
>> + /*
>> + * Since this sink is already enabled, the existing buffer should
>> not
>> + * be released even if the buffer size has changed.
>> + */
>> + if (coresight_get_mode(csdev) == CS_MODE_SYSFS)
>> + goto out;
>> +
>> /*
>> * If we don't have a buffer or it doesn't match the requested
>> size,
>> * use the buffer allocated above. Otherwise reuse the existing
>> buffer.
>>
>> ---
>> base-commit: 98ac9cc4b4452ed7e714eddc8c90ac4ae5da1a09
>> change-id: 20251020-fix_etr_issue-02c706dbc899
>>
>> Best regards,
>
This patch series adds support for the Qualcomm CoreSight Interconnect TNOC
(Trace Network On Chip) block, which acts as a CoreSight graph link forwarding
trace data from subsystems to the Aggregator TNOC. Unlike the Aggregator TNOC,
this block does not support aggregation or ATID assignment.
Signed-off-by: Yuanfang Zhang <yuanfang.zhang(a)oss.qualcomm.com>
---
Changes in v5:
- Add the missing review-by tag for patch 3.
- Link to v4: https://lore.kernel.org/r/20250831-itnoc-v4-0-f0fb0ef822a5@oss.qualcomm.com
Changes in v4:
- Fix unintended blank line removals in trace_noc_enable_hw.
- Link to v3: https://lore.kernel.org/r/20250828-itnoc-v3-0-f1b55dea7a27@oss.qualcomm.com
Changes in v3:
- Add detail for changes in V2.
- Remove '#address-cells' and '#size-cells' properties from in-ports field.
- Fix comment indentation for packet description.
- Link to v2: https://lore.kernel.org/r/20250819-itnoc-v2-0-2d0e6be44e2f@oss.qualcomm.com
Changes in v2:
- Removed the trailing '|' after the description in qcom,coresight-itnoc.yaml.
- Dropped the 'select' section from the YAML file.
- Updated node name to use a more generic naming convention.
- Removed the 'items' property from the compatible field.
- Deleted the description for the reg property.
- Dropped clock-names and adjusted the order of clock-names and clocks.
- Moved additionalProperties to follow the $ref of out-ports.
- Change "atid" type from u32 to int, set it as "-EOPNOTSUPP" for non-AMBA device.
- Link to v1: https://lore.kernel.org/r/20250815-itnoc-v1-0-62c8e4f7ad32@oss.qualcomm.com
---
Yuanfang Zhang (3):
dt-bindings: arm: qcom: Add Coresight Interconnect TNOC
coresight-tnoc: add platform driver to support Interconnect TNOC
coresight-tnoc: Add runtime PM support for Interconnect TNOC
.../bindings/arm/qcom,coresight-itnoc.yaml | 90 ++++++++++++++
drivers/hwtracing/coresight/coresight-tnoc.c | 136 +++++++++++++++++++--
2 files changed, 215 insertions(+), 11 deletions(-)
---
base-commit: 2b52cf338d39d684a1c6af298e8204902c026aca
change-id: 20250815-itnoc-460273d1b80c
Best regards,
--
Yuanfang Zhang <yuanfang.zhang(a)oss.qualcomm.com>
Do some cleanups then add a new format attribute to set the timestamp
interval for ETMv4 in Perf mode. The current interval is too high for
most use cases, and particularly on the FVP the number of timestamps
generated is excessive.
Although it would be good to make only SYNC timestamps the default and
have counter timestamps opt-in, this would be a breaking change. We
can always do that later, or disable counter timestamps from Perf.
This is added as an event format attribute, rather than a Coresight
config because it's something that the driver is already configuring
automatically in Perf mode with any unused counter, so it's not possible
to modify this with a config.
Applies to coresight/next
Signed-off-by: James Clark <james.clark(a)linaro.org>
---
James Clark (6):
coresight: Change syncfreq to be a u8
coresight: Fix holes in struct etmv4_config
coresight: Repack struct etmv4_drvdata
coresight: Refactor etm4_config_timestamp_event()
coresight: Add format attribute for setting the timestamp interval
coresight: docs: Document etm4x ts_interval
Documentation/trace/coresight/coresight.rst | 14 +++
drivers/hwtracing/coresight/coresight-etm-perf.c | 6 +-
drivers/hwtracing/coresight/coresight-etm4x-core.c | 110 +++++++++++++--------
drivers/hwtracing/coresight/coresight-etm4x.h | 86 ++++++++++------
4 files changed, 144 insertions(+), 72 deletions(-)
---
base-commit: a80198ba650f50d266d7fc4a6c5262df9970f9f2
change-id: 20250724-james-cs-syncfreq-7c2257a38ed3
Best regards,
--
James Clark <james.clark(a)linaro.org>