[PATCH v2 17/23] coresight: trbe: Calculate trace size across buffer wrap

From: Leo Yan

Date: Fri Oct 16 2026 - 13:09:55 EST


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@xxxxxxx>
---
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