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