mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling
@ 2026-10-16 16:54 Leo Yan
  2026-10-16 16:54 ` [PATCH v2 01/23] arm64/sysreg: Define TRBSR_EL1.EC event classes Leo Yan
                   ` (22 more replies)
  0 siblings, 23 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:54 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

This series follows the earlier TRBE buffer refactoring posting [1].
The work is now split into two parts. This first part contains fixes
and refactoring in preparation for wrap and trigger mode support.
Support for those modes will be sent separately.

The patches are grouped as follows for easier review:

  Patches 1-5: Minor fixes
    Add register definitions, fix the watermark range check, and
    improve erratum checks and perf handle validation.

  Patches 6-11: Enable/disable lifecycle fixes
    Clean up session setup, status clearing and IRQ handle ownership.

  Patches 12-17: Refine status classification
    Decode stop reasons, report truncation on errors and improve
    trace-size accounting.

  Patches 18-23: Improve IRQ and overflow handling
    Keep the handle in per-CPU data, stabilize status reads, and
    improve AUX restarts and trace-gap reporting.

A race also remains between TRBE interrupt handling and AUX pause/resume
from a sampling NMI. This should be resolved as part of the state
machine refactoring in the CoreSight AUX sampling series [2].

[1] https://lore.kernel.org/linux-arm-kernel/20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com/
[2] https://lore.kernel.org/linux-arm-kernel/20260915-arm_cs_support_aux_sample-v1-0-35cf6f297d20@arm.com/T/#t

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
Leo Yan (23):
      arm64/sysreg: Define TRBSR_EL1.EC event classes
      coresight: trbe: Make watermark range check overflow safe in __trbe_normal_offset()
      coresight: trbe: Use helpers for checking errata
      coresight: trbe: Check the buffer association before IRQ validation
      coresight: trbe: Validate perf handle before using sink data
      coresight: trbe: Drop redundant disable from enable path
      coresight: trbe: Publish the session after successful enable
      coresight: trbe: Clear stale external abort status
      coresight: trbe: Clear TRBSR status at stop sites
      coresight: trbe: Drop redundant disables
      coresight: trbe: Assign the perf handle in enable and disable
      coresight: trbe: Decode TRBSR status codes
      coresight: trbe: Simplify wrap status handling
      coresight: trbe: Treat access not allowed stops as fatal
      coresight: trbe: Report truncated trace on buffer update errors
      coresight: trbe: Always classify TRBSR when updating buffer
      coresight: trbe: Calculate trace size across buffer wrap
      coresight: trbe: Keep the perf handle in per-CPU data
      coresight: trbe: Reload the AUX buffer on overflow restart
      coresight: trbe: Add fault action argument to trbe_handle_overflow()
      coresight: trbe: Read TRBSR after prohibiting and flushing trace
      coresight: trbe: Restart trace source for stopped buffers
      coresight: trbe: Report trace gaps with PARTIAL instead of COLLISION

 arch/arm64/include/asm/sysreg.h              |   6 +
 arch/arm64/tools/sysreg                      |   8 +-
 drivers/hwtracing/coresight/coresight-trbe.c | 481 ++++++++++++++++++---------
 drivers/hwtracing/coresight/coresight-trbe.h |   8 -
 4 files changed, 345 insertions(+), 158 deletions(-)
---
base-commit: 343cfcbb3ecfdb80aa576a428cfa3b65ad783842
change-id: 20261016-trbe_enable_disable_irq_handle_refactor-0a3450f03473

Best regards,
-- 
Leo Yan <leo.yan@arm.com>


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 01/23] arm64/sysreg: Define TRBSR_EL1.EC event classes
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
@ 2026-10-16 16:54 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 02/23] coresight: trbe: Make watermark range check overflow safe in __trbe_normal_offset() Leo Yan
                   ` (21 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:54 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

TRBSR_EL1.EC identifies the cause of a trace buffer management event,
but the sysreg description does not name its architected values. Define
the five encodings as an unsigned enum so TRBE status handling can
refer to each cause by name.

The values cover other events, Granule Protection Check faults,
implementation-defined events, and stage 1 and stage 2 Data Aborts on
writes to the trace buffer, as specified by Arm ARM (ARM DDI 0487 M.c).

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 arch/arm64/tools/sysreg | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index 94bf065c8ac71f20f482c91a5147cb6e001dfba2..f68c23dd4e83ee4d00610e097d9188d3a2c9ed15 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -5834,7 +5834,13 @@ EndSysreg
 Sysreg	TRBSR_EL1	3	0	9	11	3
 Res0	63:56
 Field	55:32	MSS2
-Field	31:26	EC
+UnsignedEnum	31:26	EC
+	0b000000	OTHER
+	0b011110	FAULT_GPC
+	0b011111	IMP_DEF
+	0b100100	FAULT_WRITE_S1
+	0b100101	FAULT_WRITE_S2
+EndEnum
 Res0	25:24
 Field	23	DAT
 Field	22	IRQ

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 02/23] coresight: trbe: Make watermark range check overflow safe in __trbe_normal_offset()
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
  2026-10-16 16:54 ` [PATCH v2 01/23] arm64/sysreg: Define TRBSR_EL1.EC event classes Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 03/23] coresight: trbe: Use helpers for checking errata Leo Yan
                   ` (20 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

The current code checks whether the wakeup point lies before the current
tail by comparing against handle->head + handle->size. That addition can
overflow when the monotonically increasing perf AUX head is close to
ULONG_MAX, causing a valid wakeup point in the current writable range to
be missed.

Use unsigned subtraction to compare the distance from head to wakeup
against the buffer size instead. This keeps the check correct across
potential wrap.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index eca8e13a97447b46a4b383049aacb3fa7ad3c329..02d12445763a86d58c79bdf5143f761827456bc3 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -526,7 +526,7 @@ static unsigned long __trbe_normal_offset(struct perf_output_handle *handle)
 	 * +----|---------------|-------|-------+
 	 * trbe_base		limit		trbe_base + nr_pages
 	 */
-	if (handle->wakeup < (handle->head + handle->size) && head <= wakeup)
+	if ((handle->wakeup - handle->head) < handle->size && head <= wakeup)
 		limit = min(limit, round_up(wakeup, PAGE_SIZE));
 
 	/*

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 03/23] coresight: trbe: Use helpers for checking errata
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
  2026-10-16 16:54 ` [PATCH v2 01/23] arm64/sysreg: Define TRBSR_EL1.EC event classes Leo Yan
  2026-10-16 16:55 ` [PATCH v2 02/23] coresight: trbe: Make watermark range check overflow safe in __trbe_normal_offset() Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 04/23] coresight: trbe: Check the buffer association before IRQ validation Leo Yan
                   ` (19 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

Use the existing helpers for checking errata instead of open coded
equivalent.

Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 02d12445763a86d58c79bdf5143f761827456bc3..8ec0b4c4987f25d10ee0b2f80c27e10f76357387 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -738,7 +738,7 @@ static unsigned long trbe_get_trace_size(struct perf_output_handle *handle,
 	 * the space we skipped with IGNORE packets. And we are always
 	 * guaranteed to have at least a PAGE_SIZE space in the buffer.
 	 */
-	if (trbe_has_erratum(buf->cpudata, TRBE_WORKAROUND_OVERWRITE_FILL_MODE) &&
+	if (trbe_may_overwrite_in_fill_mode(buf->cpudata) &&
 	    !WARN_ON(size < overwrite_skip))
 		__trbe_pad_buf(buf, start_off, overwrite_skip);
 
@@ -961,7 +961,7 @@ static int trbe_apply_work_around_before_enable(struct trbe_buf *buf)
 	 *  - At trace collection:
 	 *     - Pad the 256bytes skipped above again with IGNORE packets.
 	 */
-	if (trbe_has_erratum(buf->cpudata, TRBE_WORKAROUND_OVERWRITE_FILL_MODE)) {
+	if (trbe_may_overwrite_in_fill_mode(buf->cpudata)) {
 		if (WARN_ON(!IS_ALIGNED(buf->trbe_write, PAGE_SIZE)))
 			return -EINVAL;
 		buf->trbe_hw_base = buf->trbe_write;
@@ -985,7 +985,7 @@ static int trbe_apply_work_around_before_enable(struct trbe_buf *buf)
 	 *     - Adjust the TRBLIMITR.LIMIT to leave the extra PAGE outside
 	 *       the TRBE's range (i.e [TRBBASER, TRBLIMITR.LIMI] ).
 	 */
-	if (trbe_has_erratum(buf->cpudata, TRBE_WORKAROUND_WRITE_OUT_OF_RANGE)) {
+	if (trbe_may_write_out_of_range(buf->cpudata)) {
 		s64 space = buf->trbe_limit - buf->trbe_write;
 		/*
 		 * We must have more than a PAGE_SIZE worth space in the proposed

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 04/23] coresight: trbe: Check the buffer association before IRQ validation
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (2 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 03/23] coresight: trbe: Use helpers for checking errata Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 05/23] coresight: trbe: Validate perf handle before using sink data Leo Yan
                   ` (18 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

is_perf_trbe() obtains the sink buffer from the output handle and
dereferences buf->cpudata before validating either pointer. A live AUX
transaction does not guarantee that the selected buffer has a CPU
association.

Reject a missing buffer or CPU association before reading CPU driver
data or checking the hardware buffer addresses. Treat these configurations
as an invalid perf TRBE session.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 8ec0b4c4987f25d10ee0b2f80c27e10f76357387..91fbdbad3676ffae399df0b4d4ddcd603a40e86c 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -1111,10 +1111,16 @@ static int trbe_handle_overflow(struct perf_output_handle *handle)
 static bool is_perf_trbe(struct perf_output_handle *handle)
 {
 	struct trbe_buf *buf = etm_perf_sink_config(handle);
-	struct trbe_cpudata *cpudata = buf->cpudata;
-	struct trbe_drvdata *drvdata = cpudata->drvdata;
+	struct trbe_cpudata *cpudata;
+	struct trbe_drvdata *drvdata;
 	int cpu = smp_processor_id();
 
+	if (!buf || !buf->cpudata)
+		return false;
+
+	cpudata = buf->cpudata;
+	drvdata = cpudata->drvdata;
+
 	WARN_ON(buf->trbe_hw_base != get_trbe_base_pointer());
 	WARN_ON(buf->trbe_limit != get_trbe_limit_pointer());
 

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 05/23] coresight: trbe: Validate perf handle before using sink data
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (3 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 04/23] coresight: trbe: Check the buffer association before IRQ validation Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 06/23] coresight: trbe: Drop redundant disable from enable path Leo Yan
                   ` (17 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

The TRBE IRQ handler calls etm_perf_sink_config(handle) before
validating the per-CPU perf handle and its AUX transaction. This may
dereference a NULL handle after disabling TRBE or access stale sink
data after perf_aux_output_end().

Validate the handle and AUX transaction before accessing the sink
configuration. Move the local buffer lookup closer to its use.
Remove the warning for a NULL handle, which is expected after
disabling TRBE.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 91fbdbad3676ffae399df0b4d4ddcd603a40e86c..a7c1037a048f5236598f8f3a7cc4f47bff9d329c 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -1150,12 +1150,18 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
 {
 	struct perf_output_handle **handle_ptr = dev;
 	struct perf_output_handle *handle = *handle_ptr;
-	struct trbe_buf *buf = etm_perf_sink_config(handle);
+	struct trbe_buf *buf;
 	enum trbe_fault_action act;
 	u64 status;
 	bool truncated = false;
 	u64 trfcr;
 
+	if (!handle || !perf_get_aux(handle))
+		return IRQ_NONE;
+
+	if (!is_perf_trbe(handle))
+		return IRQ_NONE;
+
 	/* Reads to TRBSR_EL1 is fine when TRBE is active */
 	status = read_sysreg_s(SYS_TRBSR_EL1);
 	/*
@@ -1171,16 +1177,11 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
 	 * Ensure the trace is visible to the CPUs and
 	 * any external aborts have been resolved.
 	 */
+	buf = etm_perf_sink_config(handle);
 	trbe_drain_and_disable_local(buf->cpudata);
 	clr_trbe_irq();
 	isb();
 
-	if (WARN_ON_ONCE(!handle) || !perf_get_aux(handle))
-		return IRQ_NONE;
-
-	if (!is_perf_trbe(handle))
-		return IRQ_NONE;
-
 	act = trbe_get_fault_act(handle, status);
 	switch (act) {
 	case TRBE_FAULT_ACT_WRAP:

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 06/23] coresight: trbe: Drop redundant disable from enable path
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (4 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 05/23] coresight: trbe: Validate perf handle before using sink data Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 07/23] coresight: trbe: Publish the session after successful enable Leo Yan
                   ` (16 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

The Arm ARM (ARM DDI 0487 M.c) rule RDJMDD says:

 | When the following conditions apply, the PE might ignore a direct or
 | external write to any of certain Trace Buffer Unit registers, other
 | than a direct write or external write to TRBLIMITR_EL1 that clears
 | the conditions:
 | • TRBLIMITR_EL1.E is 1, and either FEAT_TRBE_EXT is not implemented
 |   or the Trace Buffer Unit is using Self-hosted mode.

trbe_enable_hw() calls set_trbe_disabled() first to ensure TRBE has
already been disabled before programming any other TRBE registers.

However, TRBE is already expected to be disabled before trbe_enable_hw()
runs:

 1. CPU probe resets TRBLIMITR_EL1 via trbe_reset_local();
 2. Interrupt handling disables the buffer before re-enabling it;
 3. The normal disable path clears TRBLIMITR_EL1.E.

Calling set_trbe_disabled() from the enable path is therefore redundant.
Drop the call from trbe_enable_hw(), which only needs to program a
known-disabled TRBE.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index a7c1037a048f5236598f8f3a7cc4f47bff9d329c..979d0fa84c1c7b448c1ce5cd7a37dff8845795ef 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -652,7 +652,6 @@ static void trbe_enable_hw(struct trbe_buf *buf)
 	WARN_ON(buf->trbe_hw_base < buf->trbe_base);
 	WARN_ON(buf->trbe_write < buf->trbe_hw_base);
 	WARN_ON(buf->trbe_write >= buf->trbe_limit);
-	set_trbe_disabled(buf->cpudata);
 	clr_trbe_status();
 	set_trbe_base_pointer(buf->trbe_hw_base);
 	set_trbe_write_pointer(buf->trbe_write);

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 07/23] coresight: trbe: Publish the session after successful enable
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (5 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 06/23] coresight: trbe: Drop redundant disable from enable path Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 08/23] coresight: trbe: Clear stale external abort status Leo Yan
                   ` (15 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

arm_trbe_enable() records the session buffer and perf mode before
__arm_trbe_enable() can fail. CoreSight skips the sink disable callback
when sink enable fails, leaving that session state published even though
tracing did not start.

Install buf->cpudata temporarily for the buffer setup helpers, then call
__arm_trbe_enable() before assigning cpudata->buf and cpudata->mode.
Clear the temporary buffer association if setup fails; the inner helper
still truncates and ends the AUX transaction.

After successful enable, retain the buffer association across AUX
transactions and clear it in arm_trbe_disable().

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 979d0fa84c1c7b448c1ce5cd7a37dff8845795ef..9dfc6bb7afb4c42dfdec643ee7e4f2f193e2b70c 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -69,6 +69,7 @@ struct trbe_buf {
 	int nr_pages;
 	void **pages;
 	bool snapshot;
+	/* CPU used to configure this buffer. */
 	struct trbe_cpudata *cpudata;
 };
 
@@ -137,6 +138,7 @@ struct trbe_save_state {
  * @trbe_align		- Software alignment used for the TRBPTR_EL1.
  * @cpu			- CPU this TRBE belongs to.
  * @mode		- Mode of current operation. (perf/disabled)
+ * @buf			- Buffer configuration retained for the enabled session.
  * @drvdata		- TRBE specific drvdata
  * @errata		- Bit map for the errata on this TRBE.
  */
@@ -1033,17 +1035,24 @@ static int arm_trbe_enable(struct coresight_device *csdev, enum cs_mode mode,
 	struct trbe_cpudata *cpudata = dev_get_drvdata(&csdev->dev);
 	struct perf_output_handle *handle = path->handle;
 	struct trbe_buf *buf = etm_perf_sink_config(handle);
+	int ret;
 
 	WARN_ON(cpudata->cpu != smp_processor_id());
 	WARN_ON(cpudata->drvdata != drvdata);
 	if (mode != CS_MODE_PERF)
 		return -EINVAL;
 
-	cpudata->buf = buf;
-	cpudata->mode = mode;
+	/* Buffer helpers need the CPU association while setting up tracing. */
 	buf->cpudata = cpudata;
+	ret = __arm_trbe_enable(buf, handle);
+	if (ret) {
+		buf->cpudata = NULL;
+		return ret;
+	}
 
-	return __arm_trbe_enable(buf, handle);
+	cpudata->buf = buf;
+	cpudata->mode = mode;
+	return 0;
 }
 
 static int arm_trbe_disable(struct coresight_device *csdev)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 08/23] coresight: trbe: Clear stale external abort status
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (6 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 07/23] coresight: trbe: Publish the session after successful enable Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 09/23] coresight: trbe: Clear TRBSR status at stop sites Leo Yan
                   ` (14 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

clr_trbe_status() clears the buffer status and syndrome fields, but
leaves TRBSR_EL1.EA unchanged. After an external abort, this indication
can survive into a later perf session on the same CPU.

Clear EA along with the other status fields while TRBE is disabled.
The status captured for the current fault remains available for
classification, so external aborts are still handled as fatal.

Fixes: 3fbf7f011f24 ("coresight: sink: Add TRBE driver")
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 9dfc6bb7afb4c42dfdec643ee7e4f2f193e2b70c..26e7554d6bdd31f8a55a8bc3a7b6d4c49b984b9b 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -608,6 +608,7 @@ static void clr_trbe_status(void)
 	trbsr &= ~TRBSR_EL1_IRQ;
 	trbsr &= ~TRBSR_EL1_TRG;
 	trbsr &= ~TRBSR_EL1_WRAP;
+	trbsr &= ~TRBSR_EL1_EA;
 	trbsr &= ~TRBSR_EL1_EC_MASK;
 	trbsr &= ~TRBSR_EL1_BSC_MASK;
 	trbsr &= ~TRBSR_EL1_S;

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 09/23] coresight: trbe: Clear TRBSR status at stop sites
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (7 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 08/23] coresight: trbe: Clear stale external abort status Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 10/23] coresight: trbe: Drop redundant disables Leo Yan
                   ` (13 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

TRBSR_EL1 records the status of the buffer that just stopped. Clearing
it in trbe_enable_hw() postpones cleanup until another run starts. If
AUX output cannot restart, for example when AUX space is exhausted,
that clear never executes. Clear the status in arm_trbe_disable()
after disabling TRBE instead.

trbe_handle_overflow() can start the next run without calling
arm_trbe_disable(). Clear the stopped buffer's syndrome and status bits
while TRBE is disabled, before attempting the AUX restart. This also
leaves the status clean when the restart fails.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 26e7554d6bdd31f8a55a8bc3a7b6d4c49b984b9b..dd9c9330bb0c739795f300dafc6ce34e72fbf280 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -655,7 +655,6 @@ static void trbe_enable_hw(struct trbe_buf *buf)
 	WARN_ON(buf->trbe_hw_base < buf->trbe_base);
 	WARN_ON(buf->trbe_write < buf->trbe_hw_base);
 	WARN_ON(buf->trbe_write >= buf->trbe_limit);
-	clr_trbe_status();
 	set_trbe_base_pointer(buf->trbe_hw_base);
 	set_trbe_write_pointer(buf->trbe_write);
 
@@ -1069,6 +1068,8 @@ static int arm_trbe_disable(struct coresight_device *csdev)
 		return -EINVAL;
 
 	trbe_drain_and_disable_local(cpudata);
+	clr_trbe_status();
+
 	buf->cpudata = NULL;
 	cpudata->buf = NULL;
 	cpudata->mode = CS_MODE_DISABLED;
@@ -1095,6 +1096,13 @@ static int trbe_handle_overflow(struct perf_output_handle *handle)
 	unsigned long size;
 	struct etm_event_data *event_data;
 
+	/*
+	 * Clear the status. No context synchronization is required here,
+	 * since context synchronization will be performed before TRBE is
+	 * re-enabled (see trbe_enable_hw()).
+	 */
+	clr_trbe_status();
+
 	size = trbe_get_trace_size(handle, buf, true);
 	if (buf->snapshot)
 		handle->head += size;

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 10/23] coresight: trbe: Drop redundant disables
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (8 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 09/23] coresight: trbe: Clear TRBSR status at stop sites Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 11/23] coresight: trbe: Assign the perf handle in enable and disable Leo Yan
                   ` (12 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

The IRQ handler has a common point that disables TRBE before dispatching
the fault action. Once execution reaches the overflow handling or
truncate path, the trace buffer has already been stopped.

The __arm_trbe_enable() error path does not need a disable there either,
as TRBE is already in disabled state.

Remove TRBE disable from the truncate helper and from the overflow
failure path. The truncate helper only needs to mark and end the AUX
output, so rename it to trbe_truncate_event() to reflect its remaining
purpose.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 15 +++------------
 1 file changed, 3 insertions(+), 12 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index dd9c9330bb0c739795f300dafc6ce34e72fbf280..4a041bbc6e970d72a7d735e15f7221037cb091d6 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -301,18 +301,10 @@ static void trbe_report_wrap_event(struct perf_output_handle *handle)
 	perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);
 }
 
-static void trbe_stop_and_truncate_event(struct perf_output_handle *handle)
+static void trbe_truncate_event(struct perf_output_handle *handle)
 {
 	struct trbe_buf *buf = etm_perf_sink_config(handle);
 
-	/*
-	 * We cannot proceed with the buffer collection and we
-	 * do not have any data for the current session. The
-	 * etm_perf driver expects to close out the aux_buffer
-	 * at event_stop(). So disable the TRBE here and leave
-	 * the update_buffer() to return a 0 size.
-	 */
-	trbe_drain_and_disable_local(buf->cpudata);
 	perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
 	perf_aux_output_end(handle, 0);
 	*this_cpu_ptr(buf->cpudata->drvdata->handle) = NULL;
@@ -1024,7 +1016,7 @@ static int __arm_trbe_enable(struct trbe_buf *buf,
 	trbe_enable_hw(buf);
 	return 0;
 err:
-	trbe_stop_and_truncate_event(handle);
+	trbe_truncate_event(handle);
 	return ret;
 }
 
@@ -1117,7 +1109,6 @@ static int trbe_handle_overflow(struct perf_output_handle *handle)
 		 * is able to detect this with a disconnected handle
 		 * (handle->event = NULL).
 		 */
-		trbe_drain_and_disable_local(buf->cpudata);
 		*this_cpu_ptr(buf->cpudata->drvdata->handle) = NULL;
 		return -EINVAL;
 	}
@@ -1208,7 +1199,7 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
 		trbe_handle_spurious(handle);
 		break;
 	case TRBE_FAULT_ACT_FATAL:
-		trbe_stop_and_truncate_event(handle);
+		trbe_truncate_event(handle);
 		truncated = true;
 		break;
 	}

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 11/23] coresight: trbe: Assign the perf handle in enable and disable
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (9 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 10/23] coresight: trbe: Drop redundant disables Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 12/23] coresight: trbe: Decode TRBSR status codes Leo Yan
                   ` (11 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

etm-perf owns the perf output handle embedded in its per-CPU etm_ctxt and
passes it to TRBE through arm_trbe_enable(). TRBE binds that handle after
successful sink enable and unbinds it in arm_trbe_disable(). The handle
object remains valid throughout this interval, even if the current AUX
transaction ends or a new transaction begins.

The inner enable helper currently publishes the handle, while truncation
and failed rollover clear it. Sink disable leaves the handle installed
after dropping the buffer association. These assignments track the AUX
transaction rather than the enabled sink session.

Publish the handle only in arm_trbe_enable() after successful setup and
clear it in arm_trbe_disable() before dropping the buffer association.
Remove the assignments from the inner enable, overflow and truncation
paths so the handle association follows the enabled sink session.

A valid handle object may have no active AUX transaction, so the IRQ
handler continues to check perf_get_aux() before accessing the
transaction's configuration.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 20 +++++++-------------
 1 file changed, 7 insertions(+), 13 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 4a041bbc6e970d72a7d735e15f7221037cb091d6..1f51c33de83638479436683fd96e31d69c3b860f 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -303,11 +303,8 @@ static void trbe_report_wrap_event(struct perf_output_handle *handle)
 
 static void trbe_truncate_event(struct perf_output_handle *handle)
 {
-	struct trbe_buf *buf = etm_perf_sink_config(handle);
-
 	perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
 	perf_aux_output_end(handle, 0);
-	*this_cpu_ptr(buf->cpudata->drvdata->handle) = NULL;
 }
 
 /*
@@ -1012,7 +1009,6 @@ static int __arm_trbe_enable(struct trbe_buf *buf,
 	if (ret)
 		goto err;
 
-	*this_cpu_ptr(buf->cpudata->drvdata->handle) = handle;
 	trbe_enable_hw(buf);
 	return 0;
 err:
@@ -1042,6 +1038,7 @@ static int arm_trbe_enable(struct coresight_device *csdev, enum cs_mode mode,
 		return ret;
 	}
 
+	*this_cpu_ptr(drvdata->handle) = handle;
 	cpudata->buf = buf;
 	cpudata->mode = mode;
 	return 0;
@@ -1062,6 +1059,7 @@ static int arm_trbe_disable(struct coresight_device *csdev)
 	trbe_drain_and_disable_local(cpudata);
 	clr_trbe_status();
 
+	*this_cpu_ptr(drvdata->handle) = NULL;
 	buf->cpudata = NULL;
 	cpudata->buf = NULL;
 	cpudata->mode = CS_MODE_DISABLED;
@@ -1102,16 +1100,12 @@ static int trbe_handle_overflow(struct perf_output_handle *handle)
 	trbe_report_wrap_event(handle);
 	perf_aux_output_end(handle, size);
 	event_data = perf_aux_output_begin(handle, event);
-	if (!event_data) {
-		/*
-		 * We are unable to restart the trace collection,
-		 * thus leave the TRBE disabled. The etm-perf driver
-		 * is able to detect this with a disconnected handle
-		 * (handle->event = NULL).
-		 */
-		*this_cpu_ptr(buf->cpudata->drvdata->handle) = NULL;
+	/*
+	 * If trace collection cannot be restarted, leave TRBE disabled.
+	 * The etm-perf driver detects this through handle->event == NULL.
+	 */
+	if (!event_data)
 		return -EINVAL;
-	}
 
 	return __arm_trbe_enable(buf, handle);
 }

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 12/23] coresight: trbe: Decode TRBSR status codes
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (10 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 11/23] coresight: trbe: Assign the perf handle in enable and disable Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 13/23] coresight: trbe: Simplify wrap status handling Leo Yan
                   ` (10 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

trbe_get_fault_act() currently handles only a small set of TRBE stop
reasons: external aborts, trigger events and stage 1 and 2 aborts. Other
TRBSR_EL1 EC/BSC values are reported as spurious events, which hides
useful failure information and makes the status handling hard to extend.

Decode the EC and BSC fields explicitly. Keep the normal fill-mode
handling unchanged, but treat unsupported or unexpected status values as
fatal and report them with a ratelimited diagnostic containing TRBSR_EL1,
TRBPTR_EL1 and TRBLIMITR_EL1. Use %p for the buffer pointers so the
printk diagnostic hashes their address values by default.

Stop using is_trbe_trg(), instead, use TRBSR_EL1_BSC_TRIGGER_EVENT as
the unsupported trigger case. This keeps the stop-reason handling in the
EC/BSC decode path, the driver can validate the status fields safely.

Move the TRBSR_EL1 BSC definitions to the arm64 sysreg header, and use
the common TRBSR_EL1 EC/BSC names in the TRBE driver.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 arch/arm64/include/asm/sysreg.h              |  6 +++
 drivers/hwtracing/coresight/coresight-trbe.c | 57 +++++++++++++++++++++++++---
 drivers/hwtracing/coresight/coresight-trbe.h |  8 ----
 3 files changed, 58 insertions(+), 13 deletions(-)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 7aa08d59d49448cfa3bb61f5cb42e0a6f1aa8a89..0e602f07625b3c4fe6cd3fd71a658ebae768d8fd 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -357,6 +357,12 @@
 #define TRBSR_EL1_BSC_MASK		GENMASK(5, 0)
 #define TRBSR_EL1_BSC_SHIFT		0
 
+#define TRBSR_EL1_BSC_NOT_STOPPED	UL(0)
+#define TRBSR_EL1_BSC_FILLED		UL(1)
+#define TRBSR_EL1_BSC_TRIGGER_EVENT	UL(2)
+#define TRBSR_EL1_BSC_MANUAL_STOP	UL(3)
+#define TRBSR_EL1_BSC_BUF_SIZE		UL(4)
+
 #define SYS_PMINTENSET_EL1		sys_reg(3, 0, 9, 14, 1)
 #define SYS_PMINTENCLR_EL1		sys_reg(3, 0, 9, 14, 2)
 
diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 1f51c33de83638479436683fd96e31d69c3b860f..a851f09d806a6b6a6386d6f7547b01a17f61b88e 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -658,29 +658,76 @@ static void trbe_enable_hw(struct trbe_buf *buf)
 static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *handle,
 						 u64 trbsr)
 {
+	const char *err_str;
 	int ec = get_trbe_ec(trbsr);
 	int bsc = get_trbe_bsc(trbsr);
 	struct trbe_buf *buf = etm_perf_sink_config(handle);
 	struct trbe_cpudata *cpudata = buf->cpudata;
 
 	WARN_ON(is_trbe_running(trbsr));
-	if (is_trbe_trg(trbsr) || is_trbe_abort(trbsr))
-		return TRBE_FAULT_ACT_FATAL;
 
-	if ((ec == TRBE_EC_STAGE1_ABORT) || (ec == TRBE_EC_STAGE2_ABORT))
-		return TRBE_FAULT_ACT_FATAL;
+	if (is_trbe_abort(trbsr)) {
+		err_str = "External abort";
+		goto out_fatal;
+	}
+
+	switch (ec) {
+	case TRBSR_EL1_EC_OTHER:
+		break;
+	case TRBSR_EL1_EC_IMP_DEF:
+		err_str = "Unexpected IMPDEF buffer management event";
+		goto out_fatal;
+	case TRBSR_EL1_EC_FAULT_GPC:
+		err_str = "Granule Protection Check fault";
+		goto out_fatal;
+	case TRBSR_EL1_EC_FAULT_WRITE_S1:
+		err_str = "Stage 1 data abort";
+		goto out_fatal;
+	case TRBSR_EL1_EC_FAULT_WRITE_S2:
+		err_str = "Stage 2 data abort";
+		goto out_fatal;
+	default:
+		err_str = "Unknown error code";
+		goto out_fatal;
+	}
+
+	switch (bsc) {
+	case TRBSR_EL1_BSC_NOT_STOPPED:
+		break;
+	case TRBSR_EL1_BSC_FILLED:
+		break;
+	case TRBSR_EL1_BSC_TRIGGER_EVENT:
+		err_str = "Unsupported trigger event";
+		goto out_fatal;
+	case TRBSR_EL1_BSC_MANUAL_STOP:
+		err_str = "Unsupported manual stop";
+		goto out_fatal;
+	case TRBSR_EL1_BSC_BUF_SIZE:
+		err_str = "Buffer size was too large";
+		goto out_fatal;
+	default:
+		err_str = "Unexpected buffer status code";
+		goto out_fatal;
+	}
 
 	/*
 	 * If the trbe is affected by TRBE_WORKAROUND_OVERWRITE_FILL_MODE,
 	 * it might write data after a WRAP event in the fill mode.
 	 * Thus the check TRBPTR == TRBBASER will not be honored.
 	 */
-	if ((is_trbe_wrap(trbsr) && (ec == TRBE_EC_OTHERS) && (bsc == TRBE_BSC_FILLED)) &&
+	if ((is_trbe_wrap(trbsr) && (ec == TRBSR_EL1_EC_OTHER) && (bsc == TRBSR_EL1_BSC_FILLED)) &&
 	    (trbe_may_overwrite_in_fill_mode(cpudata) ||
 	     get_trbe_write_pointer() == get_trbe_base_pointer()))
 		return TRBE_FAULT_ACT_WRAP;
 
 	return TRBE_FAULT_ACT_SPURIOUS;
+
+out_fatal:
+	pr_err_ratelimited("%s on CPU %d [TRBSR=0x%016llx, TRBPTR=%p, TRBLIMITR=%p]\n",
+			   err_str, smp_processor_id(), trbsr,
+			   (void *)read_sysreg_s(SYS_TRBPTR_EL1),
+			   (void *)read_sysreg_s(SYS_TRBLIMITR_EL1));
+	return TRBE_FAULT_ACT_FATAL;
 }
 
 static unsigned long trbe_get_trace_size(struct perf_output_handle *handle,
diff --git a/drivers/hwtracing/coresight/coresight-trbe.h b/drivers/hwtracing/coresight/coresight-trbe.h
index 45202c48accec7c86ba56130e2737bc2d1830fae..8ba9ef4056e4dc3968816c6a7cbf2859f2bbed36 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.h
+++ b/drivers/hwtracing/coresight/coresight-trbe.h
@@ -35,19 +35,11 @@ static inline bool is_trbe_enabled(void)
 	return trblimitr & TRBLIMITR_EL1_E;
 }
 
-#define TRBE_EC_OTHERS		0
-#define TRBE_EC_STAGE1_ABORT	36
-#define TRBE_EC_STAGE2_ABORT	37
-
 static inline int get_trbe_ec(u64 trbsr)
 {
 	return (trbsr & TRBSR_EL1_EC_MASK) >> TRBSR_EL1_EC_SHIFT;
 }
 
-#define TRBE_BSC_NOT_STOPPED 0
-#define TRBE_BSC_FILLED      1
-#define TRBE_BSC_TRIGGERED   2
-
 static inline int get_trbe_bsc(u64 trbsr)
 {
 	return (trbsr & TRBSR_EL1_BSC_MASK) >> TRBSR_EL1_BSC_SHIFT;

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 13/23] coresight: trbe: Simplify wrap status handling
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (11 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 12/23] coresight: trbe: Decode TRBSR status codes Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 14/23] coresight: trbe: Treat access not allowed stops as fatal Leo Yan
                   ` (9 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

After explicitly decoding the TRBSR_EL1 EC/BSC values, unsupported or
unexpected stop reasons are handled before the WRAP check. And the
erratum and pointer checks is no longer relevant when deciding the
buffer wrap.

Remove the redundant checks and treat any remaining TRBSR_EL1.WRAP
status as a wrap event. This also means WRAP with BSC_NOT_STOPPED is
reported as an overflow instead of a spurious event, which prepares for
for TRBE wrap mode where collection continues and a maintenance
interrupt is raised on current write pointer wrap.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 11 +----------
 1 file changed, 1 insertion(+), 10 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index a851f09d806a6b6a6386d6f7547b01a17f61b88e..4aeed1a17c4bf1653fb41731ac15f31feec7ed2e 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -661,8 +661,6 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
 	const char *err_str;
 	int ec = get_trbe_ec(trbsr);
 	int bsc = get_trbe_bsc(trbsr);
-	struct trbe_buf *buf = etm_perf_sink_config(handle);
-	struct trbe_cpudata *cpudata = buf->cpudata;
 
 	WARN_ON(is_trbe_running(trbsr));
 
@@ -710,14 +708,7 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
 		goto out_fatal;
 	}
 
-	/*
-	 * If the trbe is affected by TRBE_WORKAROUND_OVERWRITE_FILL_MODE,
-	 * it might write data after a WRAP event in the fill mode.
-	 * Thus the check TRBPTR == TRBBASER will not be honored.
-	 */
-	if ((is_trbe_wrap(trbsr) && (ec == TRBSR_EL1_EC_OTHER) && (bsc == TRBSR_EL1_BSC_FILLED)) &&
-	    (trbe_may_overwrite_in_fill_mode(cpudata) ||
-	     get_trbe_write_pointer() == get_trbe_base_pointer()))
+	if (is_trbe_wrap(trbsr))
 		return TRBE_FAULT_ACT_WRAP;
 
 	return TRBE_FAULT_ACT_SPURIOUS;

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 14/23] coresight: trbe: Treat access not allowed stops as fatal
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (12 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 13/23] coresight: trbe: Simplify wrap status handling Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 15/23] coresight: trbe: Report truncated trace on buffer update errors Leo Yan
                   ` (8 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

Arm ARM (ARM DDI 0487 M.b), the rule R_RRCNN in "D6.11 UNPREDICTABLE
behavior" permits a buffer management event when the effective SCR_EL3
security state does not match the owning Security state. This can stop
collection with IRQ=1, S=1, EC=0 and BSC=0 while leaving the other
status fields unchanged.

With EA and WRAP clear, trbe_get_fault_act() currently returns SPURIOUS
for this status. The spurious handler re-enables TRBE without clearing
S, so collection can remain stopped. A retained WRAP indication can
instead cause the status to be treated as a normal buffer wrap.

Recognize this architecturally permitted stopped status as an access
not allowed error and return FATAL so the fatal handling reports
truncated trace. Check the syndrome before WRAP and do not exclude
TRG, since both fields are left unchanged by this stop. Check the saved
IRQ bit to preserve updates without a pending interrupt.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 4aeed1a17c4bf1653fb41731ac15f31feec7ed2e..1c585b6123df2f20d08747678d836742ce9564cc 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -708,6 +708,14 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
 		goto out_fatal;
 	}
 
+	/* An access not allowed stop can leave WRAP and TRG unchanged. */
+	if (is_trbe_irq(trbsr) && !is_trbe_running(trbsr) &&
+	    ec == TRBSR_EL1_EC_OTHER &&
+	    bsc == TRBSR_EL1_BSC_NOT_STOPPED) {
+		err_str = "Trace buffer access not allowed";
+		goto out_fatal;
+	}
+
 	if (is_trbe_wrap(trbsr))
 		return TRBE_FAULT_ACT_WRAP;
 

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 15/23] coresight: trbe: Report truncated trace on buffer update errors
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (13 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 14/23] coresight: trbe: Treat access not allowed stops as fatal Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 16/23] coresight: trbe: Always classify TRBSR when updating buffer Leo Yan
                   ` (7 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

When arm_trbe_update_buffer() handles a pending interrupt that is
not a wrap event, it discards the buffer by returning zero. The AUX
output is not marked as truncated, so userspace is not informed of
the lost trace.

Set PERF_AUX_FLAG_TRUNCATED before returning zero so perf reports
the trace loss when closing the AUX output.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 1c585b6123df2f20d08747678d836742ce9564cc..ac49098aa08412a23a20d32f84c2e1977ee4a223 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -903,6 +903,7 @@ static unsigned long arm_trbe_update_buffer(struct coresight_device *csdev,
 		 * errors and as such buffer is empty.
 		 */
 		if (act != TRBE_FAULT_ACT_WRAP) {
+			perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
 			size = 0;
 			goto done;
 		}

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 16/23] coresight: trbe: Always classify TRBSR when updating buffer
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (14 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 15/23] coresight: trbe: Report truncated trace on buffer update errors Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 17/23] coresight: trbe: Calculate trace size across buffer wrap Leo Yan
                   ` (6 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

arm_trbe_update_buffer() must account trace when perf stops a session,
even if no maintenance interrupt has been handled. Prepare it for
trigger and wrap modes by making the trace-size decision from the
drained TRBSR status rather than gating classification on IRQ.
Acknowledge IRQ only when it is set.

In FILL mode, reaching LIMIT sets WRAP and IRQ and returns TRBPTR to
BASE. Interrupt delivery can be delayed, so update_buffer() may run
before the IRQ handler. The existing IRQ-gated path uses WRAP to size
through LIMIT in that case; preserve this while also classifying
updates without a pending IRQ.

With classification on the no-IRQ path, a normal software stop can
have TRBSR.S clear and an ignored detected trigger can set TRBSR.TRG.
Neither should warn or discard valid trace. Mark fatal status as
truncated and return zero. Use LIMIT for a filled WRAP and TRBPTR
otherwise.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 24 +++++++++---------------
 1 file changed, 9 insertions(+), 15 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index ac49098aa08412a23a20d32f84c2e1977ee4a223..661f4a78e67c30652de8c834e4773819fa67b5ac 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -662,8 +662,6 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
 	int ec = get_trbe_ec(trbsr);
 	int bsc = get_trbe_bsc(trbsr);
 
-	WARN_ON(is_trbe_running(trbsr));
-
 	if (is_trbe_abort(trbsr)) {
 		err_str = "External abort";
 		goto out_fatal;
@@ -844,7 +842,6 @@ static unsigned long arm_trbe_update_buffer(struct coresight_device *csdev,
 	enum trbe_fault_action act;
 	unsigned long size, status;
 	unsigned long flags;
-	bool wrap = false;
 
 	WARN_ON(buf->cpudata != cpudata);
 	WARN_ON(cpudata->cpu != smp_processor_id());
@@ -896,23 +893,20 @@ static unsigned long arm_trbe_update_buffer(struct coresight_device *csdev,
 		 */
 		clr_trbe_irq();
 		isb();
+	}
 
-		act = trbe_get_fault_act(handle, status);
-		/*
-		 * If this was not due to a WRAP event, we have some
-		 * errors and as such buffer is empty.
-		 */
-		if (act != TRBE_FAULT_ACT_WRAP) {
-			perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
-			size = 0;
-			goto done;
-		}
+	act = trbe_get_fault_act(handle, status);
 
+	/* If an error occurred, the buffer may be empty */
+	if (act == TRBE_FAULT_ACT_FATAL) {
+		perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
+		size = 0;
+		goto done;
+	} else if (act == TRBE_FAULT_ACT_WRAP) {
 		trbe_report_wrap_event(handle);
-		wrap = true;
 	}
 
-	size = trbe_get_trace_size(handle, buf, wrap);
+	size = trbe_get_trace_size(handle, buf, act == TRBE_FAULT_ACT_WRAP);
 
 done:
 	local_irq_restore(flags);

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 17/23] coresight: trbe: Calculate trace size across buffer wrap
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (15 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 16/23] coresight: trbe: Always classify TRBSR when updating buffer Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 18/23] coresight: trbe: Keep the perf handle in per-CPU data Leo Yan
                   ` (5 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

trbe_get_trace_size() assumes that the TRBE write pointer is always ahead
of the perf AUX head. That is not true after a WRAP event, where the write
pointer can move back to the start of the programmed TRBE span.

Calculate the size in two parts for WRAP: the bytes from the current AUX
head to TRBLIMITR_EL1, plus any bytes from TRBBASER_EL1 to the current
TRBPTR_EL1. Keep the non-WRAP path strict and reject an unexpected write
pointer below the AUX head.

For CPUs affected by the overwrite-fill-mode or write-out-of-range errata,
continue to ignore TRBPTR_EL1 on WRAP and account data only up to
TRBLIMITR_EL1, since bytes beyond the programmed limit are uncertain.

Apply this fallback before validating the write pointer so a WRAP report
with a pointer outside the programmed range still publishes the trace
from the AUX head to the programmed limit.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 62 +++++++++++++++++-----------
 1 file changed, 37 insertions(+), 25 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 661f4a78e67c30652de8c834e4773819fa67b5ac..9a469c8009ce8a8a8b804c2b63a68e741f1dceaa 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -730,43 +730,55 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
 static unsigned long trbe_get_trace_size(struct perf_output_handle *handle,
 					 struct trbe_buf *buf, bool wrap)
 {
-	u64 write;
-	u64 start_off, end_off;
-	u64 size;
 	u64 overwrite_skip = TRBE_WORKAROUND_OVERWRITE_FILL_MODE_SKIP_BYTES;
+	u64 base = buf->trbe_base;
+	u64 start_off = PERF_IDX2OFF(handle->head, buf);
+	u64 write = get_trbe_write_pointer();
+	u64 limit = get_trbe_limit_pointer();
+	u64 limit_off, write_off, size;
 
 	/*
-	 * If the TRBE has wrapped around the write pointer has
-	 * wrapped and should be treated as limit.
-	 *
 	 * When the TRBE is affected by TRBE_WORKAROUND_WRITE_OUT_OF_RANGE,
-	 * it may write upto 64bytes beyond the "LIMIT". The driver already
+	 * it may write up to 64bytes beyond the "LIMIT". The driver already
 	 * keeps a valid page next to the LIMIT and we could potentially
 	 * consume the trace data that may have been collected there. But we
 	 * cannot be really sure it is available, and the TRBPTR may not
-	 * indicate the same. Also, affected cores are also affected by another
-	 * erratum which forces the PAGE_SIZE alignment on the TRBPTR, and thus
-	 * could potentially pad an entire PAGE_SIZE - 64bytes, to get those
-	 * 64bytes. Thus we ignore the potential triggering of the erratum
-	 * on WRAP and limit the data to LIMIT.
+	 * indicate the same.
+	 *
+	 * Also, affected cores are also affected by another erratum
+	 * TRBE_WORKAROUND_OVERWRITE_FILL_MODE, which forces the PAGE_SIZE
+	 * alignment on the TRBPTR, and thus could potentially pad an entire
+	 * PAGE_SIZE - 64bytes, to get those 64bytes. Thus we ignore the
+	 * potential effects of the erratum on WRAP and limit the data to
+	 * LIMIT.
 	 */
-	if (wrap)
-		write = get_trbe_limit_pointer();
-	else
-		write = get_trbe_write_pointer();
+	if (wrap &&
+	    (trbe_may_overwrite_in_fill_mode(buf->cpudata) ||
+	     trbe_may_write_out_of_range(buf->cpudata)))
+		write = limit;
 
-	/*
-	 * TRBE may use a different base address than the base
-	 * of the ring buffer. Thus use the beginning of the ring
-	 * buffer to compute the offsets.
-	 */
-	end_off = write - buf->trbe_base;
-	start_off = PERF_IDX2OFF(handle->head, buf);
+	/* Should never happen ... */
+	if (WARN_ON_ONCE(write < base || write > limit))
+		return 0;
 
-	if (WARN_ON_ONCE(end_off < start_off))
+	limit_off = limit - base;
+	write_off = write - base;
+
+	if (WARN_ON_ONCE(start_off >= limit_off))
 		return 0;
 
-	size = end_off - start_off;
+	if (!wrap) {
+		if (WARN_ON_ONCE(write_off < start_off))
+			return 0;
+
+		size = write_off - start_off;
+	} else {
+		size = limit_off - start_off;
+
+		if (write != limit)
+			size += write_off;
+	}
+
 	/*
 	 * If the TRBE is affected by the following erratum, we must fill
 	 * the space we skipped with IGNORE packets. And we are always

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 18/23] coresight: trbe: Keep the perf handle in per-CPU data
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (16 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 17/23] coresight: trbe: Calculate trace size across buffer wrap Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 19/23] coresight: trbe: Reload the AUX buffer on overflow restart Leo Yan
                   ` (4 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

Arm SPE owns a per-CPU perf output handle for the PMU lifetime. TRBE
instead receives a handle from CoreSight when enabling its sink.

Store that session handle in trbe_cpudata instead of a separate per-CPU
pointer array, and pass the CPU data as the per-CPU IRQ context. Use this
context directly for overflow and spurious interrupt handling so local
hardware control does not depend on the current AUX buffer configuration.

Allocate the CPU data before registering the IRQ and free it after
releasing the IRQ, keeping the IRQ context valid throughout registration.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 44 ++++++++++++----------------
 1 file changed, 19 insertions(+), 25 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 9a469c8009ce8a8a8b804c2b63a68e741f1dceaa..2328aab0a084a0ac123e950f846f404d120ec2c0 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -139,6 +139,7 @@ struct trbe_save_state {
  * @cpu			- CPU this TRBE belongs to.
  * @mode		- Mode of current operation. (perf/disabled)
  * @buf			- Buffer configuration retained for the enabled session.
+ * @handle		- Perf output handle from successful enable until disable.
  * @drvdata		- TRBE specific drvdata
  * @errata		- Bit map for the errata on this TRBE.
  */
@@ -149,6 +150,7 @@ struct trbe_cpudata {
 	int cpu;
 	enum cs_mode mode;
 	struct trbe_buf *buf;
+	struct perf_output_handle *handle;
 	struct trbe_drvdata *drvdata;
 	struct trbe_save_state save_state;
 	DECLARE_BITMAP(errata, TRBE_ERRATA_MAX);
@@ -156,7 +158,6 @@ struct trbe_cpudata {
 
 struct trbe_drvdata {
 	struct trbe_cpudata __percpu *cpudata;
-	struct perf_output_handle * __percpu *handle;
 	struct hlist_node hotplug_node;
 	int irq;
 	cpumask_t supported_cpus;
@@ -1091,7 +1092,7 @@ static int arm_trbe_enable(struct coresight_device *csdev, enum cs_mode mode,
 		return ret;
 	}
 
-	*this_cpu_ptr(drvdata->handle) = handle;
+	cpudata->handle = handle;
 	cpudata->buf = buf;
 	cpudata->mode = mode;
 	return 0;
@@ -1112,16 +1113,15 @@ static int arm_trbe_disable(struct coresight_device *csdev)
 	trbe_drain_and_disable_local(cpudata);
 	clr_trbe_status();
 
-	*this_cpu_ptr(drvdata->handle) = NULL;
 	buf->cpudata = NULL;
+	cpudata->handle = NULL;
 	cpudata->buf = NULL;
 	cpudata->mode = CS_MODE_DISABLED;
 	return 0;
 }
 
-static void trbe_handle_spurious(struct perf_output_handle *handle)
+static void trbe_handle_spurious(struct trbe_cpudata *cpudata)
 {
-	struct trbe_buf *buf = etm_perf_sink_config(handle);
 	u64 trblimitr = read_sysreg_s(SYS_TRBLIMITR_EL1);
 
 	/*
@@ -1129,11 +1129,12 @@ static void trbe_handle_spurious(struct perf_output_handle *handle)
 	 * back without modifying the buffer parameters to
 	 * retain the trace collected so far.
 	 */
-	set_trbe_enabled(buf->cpudata, trblimitr);
+	set_trbe_enabled(cpudata, trblimitr);
 }
 
-static int trbe_handle_overflow(struct perf_output_handle *handle)
+static int trbe_handle_overflow(struct trbe_cpudata *cpudata)
 {
+	struct perf_output_handle *handle = cpudata->handle;
 	struct perf_event *event = handle->event;
 	struct trbe_buf *buf = etm_perf_sink_config(handle);
 	unsigned long size;
@@ -1203,9 +1204,8 @@ static u64 cpu_prohibit_trace(void)
 
 static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
 {
-	struct perf_output_handle **handle_ptr = dev;
-	struct perf_output_handle *handle = *handle_ptr;
-	struct trbe_buf *buf;
+	struct trbe_cpudata *cpudata = dev;
+	struct perf_output_handle *handle = cpudata->handle;
 	enum trbe_fault_action act;
 	u64 status;
 	bool truncated = false;
@@ -1232,18 +1232,17 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
 	 * Ensure the trace is visible to the CPUs and
 	 * any external aborts have been resolved.
 	 */
-	buf = etm_perf_sink_config(handle);
-	trbe_drain_and_disable_local(buf->cpudata);
+	trbe_drain_and_disable_local(cpudata);
 	clr_trbe_irq();
 	isb();
 
 	act = trbe_get_fault_act(handle, status);
 	switch (act) {
 	case TRBE_FAULT_ACT_WRAP:
-		truncated = !!trbe_handle_overflow(handle);
+		truncated = !!trbe_handle_overflow(cpudata);
 		break;
 	case TRBE_FAULT_ACT_SPURIOUS:
-		trbe_handle_spurious(handle);
+		trbe_handle_spurious(cpudata);
 		break;
 	case TRBE_FAULT_ACT_FATAL:
 		trbe_truncate_event(handle);
@@ -1507,10 +1506,6 @@ static int arm_trbe_probe_coresight(struct trbe_drvdata *drvdata)
 {
 	int cpu;
 
-	drvdata->cpudata = alloc_percpu(typeof(*drvdata->cpudata));
-	if (!drvdata->cpudata)
-		return -ENOMEM;
-
 	for_each_cpu(cpu, &drvdata->supported_cpus) {
 		/* If we fail to probe the CPU, let us defer it to hotplug callbacks */
 		if (smp_call_function_single(cpu, arm_trbe_probe_cpu, drvdata, 1))
@@ -1531,7 +1526,6 @@ static int arm_trbe_remove_coresight(struct trbe_drvdata *drvdata)
 		smp_call_function_single(cpu, arm_trbe_disable_cpu, drvdata, 1);
 		arm_trbe_remove_coresight_cpu(drvdata, cpu);
 	}
-	free_percpu(drvdata->cpudata);
 	return 0;
 }
 
@@ -1618,14 +1612,14 @@ static int arm_trbe_probe_irq(struct platform_device *pdev,
 
 	cpumask_copy(&drvdata->supported_cpus, affinity);
 
-	drvdata->handle = alloc_percpu(struct perf_output_handle *);
-	if (!drvdata->handle)
+	drvdata->cpudata = alloc_percpu(typeof(*drvdata->cpudata));
+	if (!drvdata->cpudata)
 		return -ENOMEM;
 
 	ret = request_percpu_irq_affinity(drvdata->irq, arm_trbe_irq_handler, DRVNAME,
-					  affinity, drvdata->handle);
+					  affinity, drvdata->cpudata);
 	if (ret) {
-		free_percpu(drvdata->handle);
+		free_percpu(drvdata->cpudata);
 		return ret;
 	}
 	return 0;
@@ -1633,8 +1627,8 @@ static int arm_trbe_probe_irq(struct platform_device *pdev,
 
 static void arm_trbe_remove_irq(struct trbe_drvdata *drvdata)
 {
-	free_percpu_irq(drvdata->irq, drvdata->handle);
-	free_percpu(drvdata->handle);
+	free_percpu_irq(drvdata->irq, drvdata->cpudata);
+	free_percpu(drvdata->cpudata);
 }
 
 static int arm_trbe_device_probe(struct platform_device *pdev)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 19/23] coresight: trbe: Reload the AUX buffer on overflow restart
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (17 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 18/23] coresight: trbe: Keep the perf handle in per-CPU data Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 20/23] coresight: trbe: Add fault action argument to trbe_handle_overflow() Leo Yan
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

PERF_EVENT_IOC_SET_OUTPUT lets events share another event's mapped output
buffer. For AUX events, this also selects the associated AUX area and
sink configuration. Perf normally establishes this sharing during setup.

Consider the following hypothetical live-redirection sequence, permitted
by the inspected perf-core paths. P is a parent event and C is its
inherited event, with C->parent = P. A and B are mapped AUX destination
buffers owned by separate, disabled cs_etm events in different task
contexts. All three are per-task events restricted to the same CPU, with
compatible output settings. P has no mmap of its own, allowing its output
to be redirected while A and B remain mapped through their owner events.

1. P's output is redirected to A. C inherits from P and begins tracing
   on the selected CPU, so its open AUX transaction and TRBE hardware
   both use A. P can be inactive while C is running because their
   events are scheduled with their respective tasks.
2. A userspace controller calls PERF_EVENT_IOC_SET_OUTPUT on P to select
   B. ring_buffer_attach() calls perf_event_stop(P, 0), which returns for
   inactive P without stopping C. P->rb now selects B, but C's existing
   handle and hardware still use A.
3. C's next buffer overflow invokes trbe_handle_overflow() from the IRQ
   handler. It saves buf for A, ends that AUX transaction, then calls
   perf_aux_output_begin(handle, C). AUX begin follows C->parent and
   reads P's current rb, rebinding the same handle to B.

This is a hypothetical API sequence, not a reproduced TRBE failure or
an observed buffer switch in normal perf record operation.

Without reloading buf, __arm_trbe_enable() calculates the next buffer
using B through the handle, but its workaround and hardware setup still
receive A. If B has never been enabled, its missing CPU association can
cause the normal-offset calculation to dereference NULL. With a snapshot
buffer, hardware may instead keep using A while perf accounts output to B.

Reload the sink configuration after perf_aux_output_begin() so the buffer
and handle refer to the same AUX transaction. If the buffer is missing or
its CPU association does not match the interrupt's CPU data, truncate the
new transaction and leave TRBE disabled. Truncation requests perf to stop
the event; a subsequent normal restart installs the buffer and its CPU
association through the sink enable path.

Stopping inherited writers during output redirection remains a separate
perf-core fix.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 2328aab0a084a0ac123e950f846f404d120ec2c0..f1f102df6c387f53feaa12b89d3df89f734afcdb 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -1161,6 +1161,20 @@ static int trbe_handle_overflow(struct trbe_cpudata *cpudata)
 	if (!event_data)
 		return -EINVAL;
 
+	/*
+	 * Reload the buffer after perf_aux_output_begin() so it matches the
+	 * handle. A race with PERF_EVENT_IOC_SET_OUTPUT may select a buffer
+	 * that has not been installed on this CPU and has no valid cpudata.
+	 * If the buffer is missing or its CPU association does not match,
+	 * truncate the trace to stop the event. A subsequent normal restart
+	 * installs the buffer and its CPU association through sink enable.
+	 */
+	buf = etm_perf_sink_config(handle);
+	if (!buf || buf->cpudata != cpudata) {
+		trbe_truncate_event(handle);
+		return -EINVAL;
+	}
+
 	return __arm_trbe_enable(buf, handle);
 }
 

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 20/23] coresight: trbe: Add fault action argument to trbe_handle_overflow()
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (18 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 19/23] coresight: trbe: Reload the AUX buffer on overflow restart Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 21/23] coresight: trbe: Read TRBSR after prohibiting and flushing trace Leo Yan
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

Add a new argument to trbe_handle_overflow() for the fault action, which
is used to compare the wrap event for trace size calculation.

No functional change intended; this is preparation for a later update.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index f1f102df6c387f53feaa12b89d3df89f734afcdb..c83c440d4ac13c346bc2a7f9093951c186c90157 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -1132,7 +1132,8 @@ static void trbe_handle_spurious(struct trbe_cpudata *cpudata)
 	set_trbe_enabled(cpudata, trblimitr);
 }
 
-static int trbe_handle_overflow(struct trbe_cpudata *cpudata)
+static int trbe_handle_overflow(struct trbe_cpudata *cpudata,
+				enum trbe_fault_action act)
 {
 	struct perf_output_handle *handle = cpudata->handle;
 	struct perf_event *event = handle->event;
@@ -1147,7 +1148,7 @@ static int trbe_handle_overflow(struct trbe_cpudata *cpudata)
 	 */
 	clr_trbe_status();
 
-	size = trbe_get_trace_size(handle, buf, true);
+	size = trbe_get_trace_size(handle, buf, act == TRBE_FAULT_ACT_WRAP);
 	if (buf->snapshot)
 		handle->head += size;
 
@@ -1253,7 +1254,7 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
 	act = trbe_get_fault_act(handle, status);
 	switch (act) {
 	case TRBE_FAULT_ACT_WRAP:
-		truncated = !!trbe_handle_overflow(cpudata);
+		truncated = !!trbe_handle_overflow(cpudata, act);
 		break;
 	case TRBE_FAULT_ACT_SPURIOUS:
 		trbe_handle_spurious(cpudata);

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 21/23] coresight: trbe: Read TRBSR after prohibiting and flushing trace
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (19 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 20/23] coresight: trbe: Add fault action argument to trbe_handle_overflow() Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 22/23] coresight: trbe: Restart trace source for stopped buffers Leo Yan
  2026-10-16 16:55 ` [PATCH v2 23/23] coresight: trbe: Report trace gaps with PARTIAL instead of COLLISION Leo Yan
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

The IRQ handler needs a stable TRBSR_EL1 value before classifying the
interrupt. If the PE can still generate trace, or if pending trace has
not been flushed, TRBSR can still change while the handler is sampling
it. This is especially important for TRBSR.S bit, which is used to
decide whether the TRBE has stopped.

Move the drain buffer into arm_trbe_prohibit_trace(), so the handler
first prohibits trace and flushes trace before reading TRBSR_EL1. Once
this has been done, the IRQ path no longer needs the unconditional
trbe_drain_and_disable_local(); it only needs to disable TRBE before
handling the stopped-buffer status.

Refactor the IRQ exit path accordingly: restore TRFCR on non-truncated
exits, while the truncated path still runs the perf IRQ work to shut
down the event.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 40 +++++++++++++++++++---------
 1 file changed, 28 insertions(+), 12 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index c83c440d4ac13c346bc2a7f9093951c186c90157..36f143a15e680b28aa6ca6a43ad7d3ee134693be 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -1207,24 +1207,34 @@ static bool is_perf_trbe(struct perf_output_handle *handle)
 	return true;
 }
 
-static u64 cpu_prohibit_trace(void)
+static u64 arm_trbe_prohibit_trace(void)
 {
 	u64 trfcr = read_trfcr();
 
 	/* Prohibit tracing at EL0 & the kernel EL */
 	write_trfcr(trfcr & ~(TRFCR_EL1_ExTRE | TRFCR_EL1_E0TRE));
+
+	/* Ensure the program-flow trace is flushed */
+	trbe_drain_buffer();
+
 	/* Return the original value of the TRFCR */
 	return trfcr;
 }
 
+static void arm_trbe_allow_trace(u64 trfcr)
+{
+	/* Allow tracing at EL0 & the kernel EL */
+	write_trfcr(trfcr);
+}
+
 static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
 {
 	struct trbe_cpudata *cpudata = dev;
 	struct perf_output_handle *handle = cpudata->handle;
 	enum trbe_fault_action act;
-	u64 status;
 	bool truncated = false;
-	u64 trfcr;
+	u64 status, trfcr;
+	irqreturn_t ret;
 
 	if (!handle || !perf_get_aux(handle))
 		return IRQ_NONE;
@@ -1232,22 +1242,25 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
 	if (!is_perf_trbe(handle))
 		return IRQ_NONE;
 
+	/* Prohibit the CPU from tracing before we disable the TRBE */
+	trfcr = arm_trbe_prohibit_trace();
+
 	/* Reads to TRBSR_EL1 is fine when TRBE is active */
 	status = read_sysreg_s(SYS_TRBSR_EL1);
 	/*
 	 * If the pending IRQ was handled by update_buffer callback
 	 * we have nothing to do here.
 	 */
-	if (!is_trbe_irq(status))
-		return IRQ_NONE;
+	if (!is_trbe_irq(status)) {
+		ret = IRQ_NONE;
+		goto out;
+	}
 
-	/* Prohibit the CPU from tracing before we disable the TRBE */
-	trfcr = cpu_prohibit_trace();
 	/*
 	 * Ensure the trace is visible to the CPUs and
 	 * any external aborts have been resolved.
 	 */
-	trbe_drain_and_disable_local(cpudata);
+	set_trbe_disabled(cpudata);
 	clr_trbe_irq();
 	isb();
 
@@ -1272,12 +1285,15 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
 	 * Otherwise, restore the trace filter controls to
 	 * allow the tracing.
 	 */
-	if (truncated)
+	if (truncated) {
 		irq_work_run();
-	else
-		write_trfcr(trfcr);
+		return IRQ_HANDLED;
+	}
 
-	return IRQ_HANDLED;
+	ret = IRQ_HANDLED;
+out:
+	arm_trbe_allow_trace(trfcr);
+	return ret;
 }
 
 static int arm_trbe_save(struct coresight_device *csdev)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 22/23] coresight: trbe: Restart trace source for stopped buffers
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (20 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 21/23] coresight: trbe: Read TRBSR after prohibiting and flushing trace Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  2026-10-16 16:55 ` [PATCH v2 23/23] coresight: trbe: Report trace gaps with PARTIAL instead of COLLISION Leo Yan
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

When TRBSR reports a stopped buffer, the IRQ handler closes the current
AUX buffer and programs TRBE for the next run. This creates a trace
discontinuity. User tool has to reset the decoder when moving to the
next AUX data block, which can reduce decoded trace coverage.

Stop and restart the trace source around TRBE reprogramming for stopped
buffers. This emits ASYNC packets, allowing the decoder to recognize
discontinuity without a full reset.

This duplicates part of the trace source enable/disable code in the
ETMv4 driver. Reusing that code would require splitting the ETMv4
callbacks into finer-grained helpers that TRBE can call, which would
make the change much larger. Keep the TRBE change self-contained for
now.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 121 +++++++++++++++++++++++++--
 1 file changed, 116 insertions(+), 5 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 36f143a15e680b28aa6ca6a43ad7d3ee134693be..6bc82d5b55539795059da37039d2929b4ea504e3 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -17,9 +17,11 @@
 
 #include <asm/barrier.h>
 #include <asm/cpufeature.h>
+#include <linux/iopoll.h>
 #include <linux/kvm_host.h>
 #include <linux/vmalloc.h>
 
+#include "coresight-etm4x.h"
 #include "coresight-self-hosted-trace.h"
 #include "coresight-trbe.h"
 
@@ -1132,14 +1134,106 @@ static void trbe_handle_spurious(struct trbe_cpudata *cpudata)
 	set_trbe_enabled(cpudata, trblimitr);
 }
 
+static u64 read_sys_trcstatr(void)
+{
+	/* Context synchronization for each polling */
+	isb();
+	return read_sysreg_s(SYS_TRCSTATR);
+}
+
+static int arm_trbe_start_tracer(u64 trcprgctlr)
+{
+	u64 val;
+
+	/* A pending IRQ after AUX pause? */
+	if (!(trcprgctlr & BIT(0)))
+		return 0;
+
+	/* Restore the saved tracer state */
+	write_sysreg_s(trcprgctlr, SYS_TRCPRGCTLR);
+
+	/*
+	 * Context synchronization between writing to the TRCPRGCTLR and
+	 * reading the TRCSTATR.
+	 */
+	isb();
+
+	/* Wait for TRCSTATR.IDLE to go down to 0 */
+	if (read_poll_timeout_atomic(read_sys_trcstatr, val,
+				     !(val & BIT(TRCSTATR_IDLE_BIT)),
+				     1,		/* delay_us */
+				     TIMEOUT_US, /* timeout_us */
+				     false)) {	/* delay_before_read */
+		pr_err("TRBE: timeout for TRCSTATR IDLE\n");
+		return -ETIME;
+	}
+
+	/* Context synchronization after programming the tracer */
+	isb();
+
+	return 0;
+}
+
+static int arm_trbe_stop_tracer(u64 *trcprgctlr)
+{
+	u64 val;
+
+	/* Disable tracer and save trcprgctlr */
+	*trcprgctlr = read_sysreg_s(SYS_TRCPRGCTLR);
+
+	/* No need to stop tracer again */
+	if (!(*trcprgctlr & BIT(0)))
+		return 0;
+
+	write_sysreg_s(*trcprgctlr & ~BIT(0), SYS_TRCPRGCTLR);
+
+	/*
+	 * Context synchronization between writing to the TRCPRGCTLR and
+	 * reading the TRCSTATR.
+	 */
+	isb();
+
+	/*
+	 * PMSTABLE alone does not permit re-enabling the tracer.
+	 * Wait for TRCSTATR.IDLE to go to 1.
+	 */
+	if (read_poll_timeout_atomic(read_sys_trcstatr, val,
+				     val & BIT(TRCSTATR_IDLE_BIT),
+				     1,
+				     TIMEOUT_US,
+				     false)) {
+		pr_err("TRBE: timeout for TRCSTATR IDLE=1\n");
+		return -ETIME;
+	}
+
+	/* Context synchronization after programming the tracer */
+	isb();
+
+	return 0;
+}
+
 static int trbe_handle_overflow(struct trbe_cpudata *cpudata,
-				enum trbe_fault_action act)
+				enum trbe_fault_action act,
+				bool is_buffer_stopped)
 {
 	struct perf_output_handle *handle = cpudata->handle;
 	struct perf_event *event = handle->event;
 	struct trbe_buf *buf = etm_perf_sink_config(handle);
 	unsigned long size;
 	struct etm_event_data *event_data;
+	u64 trcprgctlr = 0;
+	int ret = 0;
+
+	/*
+	 * Since the trace buffer has stopped, disable and re-enable the
+	 * tracer to generate ASYNC packets. This allows the decoder to
+	 * recognize the discontinuity in the trace stream.
+	 */
+	if (is_buffer_stopped) {
+		ret = arm_trbe_stop_tracer(&trcprgctlr);
+		if (ret)
+			goto truncate_event;
+	}
 
 	/*
 	 * Clear the status. No context synchronization is required here,
@@ -1172,11 +1266,27 @@ static int trbe_handle_overflow(struct trbe_cpudata *cpudata,
 	 */
 	buf = etm_perf_sink_config(handle);
 	if (!buf || buf->cpudata != cpudata) {
-		trbe_truncate_event(handle);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto truncate_event;
+	}
+
+	ret = __arm_trbe_enable(buf, handle);
+	if (ret)
+		return ret;
+
+	if (is_buffer_stopped) {
+		ret = arm_trbe_start_tracer(trcprgctlr);
+		if (ret) {
+			trbe_drain_and_disable_local(cpudata);
+			goto truncate_event;
+		}
 	}
 
-	return __arm_trbe_enable(buf, handle);
+	return 0;
+
+truncate_event:
+	trbe_truncate_event(handle);
+	return ret;
 }
 
 static bool is_perf_trbe(struct perf_output_handle *handle)
@@ -1267,7 +1377,8 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
 	act = trbe_get_fault_act(handle, status);
 	switch (act) {
 	case TRBE_FAULT_ACT_WRAP:
-		truncated = !!trbe_handle_overflow(cpudata, act);
+		truncated = !!trbe_handle_overflow(cpudata, act,
+						   !is_trbe_running(status));
 		break;
 	case TRBE_FAULT_ACT_SPURIOUS:
 		trbe_handle_spurious(cpudata);

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 23/23] coresight: trbe: Report trace gaps with PARTIAL instead of COLLISION
  2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
                   ` (21 preceding siblings ...)
  2026-10-16 16:55 ` [PATCH v2 22/23] coresight: trbe: Restart trace source for stopped buffers Leo Yan
@ 2026-10-16 16:55 ` Leo Yan
  22 siblings, 0 replies; 24+ messages in thread
From: Leo Yan @ 2026-10-16 16:55 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
	Anshuman Khandual, Tamas Petz, Tamas Zsoldos, Suyash Mahar,
	Amir Ayupov
  Cc: linux-arm-kernel, linux-kernel, coresight, Leo Yan

When a fill-mode wrap stops TRBE, the trace source can continue running
until software handles the stop. Trace generated during this interval
may be lost.

The overflow path now stops and restarts the trace source around buffer
reprogramming. This emits ASYNC packets so the decoder can synchronize
with the next trace segment. Use PERF_AUX_FLAG_PARTIAL to report the
possible gap instead of PERF_AUX_FLAG_COLLISION.

Set PARTIAL in both the overflow handler and the buffer update callback.
This also preserves the gap indication when event shutdown handles a
pending wrap, even if no further trace segment follows. Limit the flag
to stopped buffers.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 29 +++++++---------------------
 1 file changed, 7 insertions(+), 22 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 6bc82d5b55539795059da37039d2929b4ea504e3..29a1882b1f3c2eb7166f71eeef37badece67039c 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -285,25 +285,6 @@ static void trbe_reset_local(struct trbe_cpudata *cpudata)
 	write_sysreg_s(0, SYS_TRBSR_EL1);
 }
 
-static void trbe_report_wrap_event(struct perf_output_handle *handle)
-{
-	/*
-	 * Mark the buffer to indicate that there was a WRAP event by
-	 * setting the COLLISION flag. This indicates to the user that
-	 * the TRBE trace collection was stopped without stopping the
-	 * ETE and thus there might be some amount of trace that was
-	 * lost between the time the WRAP was detected and the IRQ
-	 * was consumed by the CPU.
-	 *
-	 * Setting the TRUNCATED flag would move the event to STOPPED
-	 * state unnecessarily, even when there is space left in the
-	 * ring buffer. Using the COLLISION flag doesn't have this side
-	 * effect. We only set TRUNCATED flag when there is no space
-	 * left in the ring buffer.
-	 */
-	perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);
-}
-
 static void trbe_truncate_event(struct perf_output_handle *handle)
 {
 	perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
@@ -917,10 +898,12 @@ static unsigned long arm_trbe_update_buffer(struct coresight_device *csdev,
 		perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
 		size = 0;
 		goto done;
-	} else if (act == TRBE_FAULT_ACT_WRAP) {
-		trbe_report_wrap_event(handle);
 	}
 
+	/* Trace may have been lost before the source was stopped. */
+	if (act == TRBE_FAULT_ACT_WRAP && !is_trbe_running(status))
+		perf_aux_output_flag(handle, PERF_AUX_FLAG_PARTIAL);
+
 	size = trbe_get_trace_size(handle, buf, act == TRBE_FAULT_ACT_WRAP);
 
 done:
@@ -1246,7 +1229,9 @@ static int trbe_handle_overflow(struct trbe_cpudata *cpudata,
 	if (buf->snapshot)
 		handle->head += size;
 
-	trbe_report_wrap_event(handle);
+	if (is_buffer_stopped)
+		perf_aux_output_flag(handle, PERF_AUX_FLAG_PARTIAL);
+
 	perf_aux_output_end(handle, size);
 	event_data = perf_aux_output_begin(handle, event);
 	/*

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2026-10-16 16:55 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-16 16:54 [PATCH v2 00/23] coresight: trbe: Refactor buffer and IRQ handling Leo Yan
2026-10-16 16:54 ` [PATCH v2 01/23] arm64/sysreg: Define TRBSR_EL1.EC event classes Leo Yan
2026-10-16 16:55 ` [PATCH v2 02/23] coresight: trbe: Make watermark range check overflow safe in __trbe_normal_offset() Leo Yan
2026-10-16 16:55 ` [PATCH v2 03/23] coresight: trbe: Use helpers for checking errata Leo Yan
2026-10-16 16:55 ` [PATCH v2 04/23] coresight: trbe: Check the buffer association before IRQ validation Leo Yan
2026-10-16 16:55 ` [PATCH v2 05/23] coresight: trbe: Validate perf handle before using sink data Leo Yan
2026-10-16 16:55 ` [PATCH v2 06/23] coresight: trbe: Drop redundant disable from enable path Leo Yan
2026-10-16 16:55 ` [PATCH v2 07/23] coresight: trbe: Publish the session after successful enable Leo Yan
2026-10-16 16:55 ` [PATCH v2 08/23] coresight: trbe: Clear stale external abort status Leo Yan
2026-10-16 16:55 ` [PATCH v2 09/23] coresight: trbe: Clear TRBSR status at stop sites Leo Yan
2026-10-16 16:55 ` [PATCH v2 10/23] coresight: trbe: Drop redundant disables Leo Yan
2026-10-16 16:55 ` [PATCH v2 11/23] coresight: trbe: Assign the perf handle in enable and disable Leo Yan
2026-10-16 16:55 ` [PATCH v2 12/23] coresight: trbe: Decode TRBSR status codes Leo Yan
2026-10-16 16:55 ` [PATCH v2 13/23] coresight: trbe: Simplify wrap status handling Leo Yan
2026-10-16 16:55 ` [PATCH v2 14/23] coresight: trbe: Treat access not allowed stops as fatal Leo Yan
2026-10-16 16:55 ` [PATCH v2 15/23] coresight: trbe: Report truncated trace on buffer update errors Leo Yan
2026-10-16 16:55 ` [PATCH v2 16/23] coresight: trbe: Always classify TRBSR when updating buffer Leo Yan
2026-10-16 16:55 ` [PATCH v2 17/23] coresight: trbe: Calculate trace size across buffer wrap Leo Yan
2026-10-16 16:55 ` [PATCH v2 18/23] coresight: trbe: Keep the perf handle in per-CPU data Leo Yan
2026-10-16 16:55 ` [PATCH v2 19/23] coresight: trbe: Reload the AUX buffer on overflow restart Leo Yan
2026-10-16 16:55 ` [PATCH v2 20/23] coresight: trbe: Add fault action argument to trbe_handle_overflow() Leo Yan
2026-10-16 16:55 ` [PATCH v2 21/23] coresight: trbe: Read TRBSR after prohibiting and flushing trace Leo Yan
2026-10-16 16:55 ` [PATCH v2 22/23] coresight: trbe: Restart trace source for stopped buffers Leo Yan
2026-10-16 16:55 ` [PATCH v2 23/23] coresight: trbe: Report trace gaps with PARTIAL instead of COLLISION Leo Yan

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®