linux-perf-users.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Leo Yan <leo.yan@arm.com>
To: Suzuki K Poulose <suzuki.poulose@arm.com>,
	 Mike Leach <mike.leach@linaro.org>,
	James Clark <james.clark@linaro.org>,
	 Anshuman Khandual <anshuman.khandual@arm.com>,
	 Yeoreum Yun <yeoreum.yun@arm.com>, Will Deacon <will@kernel.org>,
	 Mark Rutland <mark.rutland@arm.com>,
	Tamas Petz <tamas.petz@arm.com>,
	 Tamas Zsoldos <tamas.zsoldos@arm.com>,
	 Arnaldo Carvalho de Melo <acme@kernel.org>,
	 Namhyung Kim <namhyung@kernel.org>, Jiri Olsa <jolsa@kernel.org>,
	 Ian Rogers <irogers@google.com>,
	Adrian Hunter <adrian.hunter@intel.com>
Cc: coresight@lists.linaro.org, linux-arm-kernel@lists.infradead.org,
	 linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org,
	 Leo Yan <leo.yan@arm.com>
Subject: [PATCH 16/19] coresight: trbe: Support trigger mode
Date: Mon, 01 Dec 2025 11:22:06 +0000	[thread overview]
Message-ID: <20251201-trbe_buffer_refactor_v1-1-v1-16-7da32b076b28@arm.com> (raw)
In-Reply-To: <20251201-trbe_buffer_refactor_v1-1-v1-0-7da32b076b28@arm.com>

The buffer currently operates in fill mode, where tracing stops when it
reaches the end of the buffer and a maintenance interrupt is raised.
However, due to IRQ latency, trace data may be lost during the window in
which tracing is halted but the program continues to run.

To mitigate the issue, this commit enables the trigger count to support
buffer maintenance without disabling tracing.  This is fulfilled with
two modes:

1) Set a trigger count as a watermark and use fill mode to prevent the
   buffer from being overwritten.  Once the count is decremented to
   zero, an interrupt is raised for buffer maintenance, but the hardware
   continues collecting trace data until limit.

          head            watermark tail
     +----+---------------+---------+-------+
     |$$$$|               |         |$$$$$$$|
     +----+---------------+---------+-------+
     base `---- count ----'         limit   base + nr_pages

     $$$ : Filled trace data

2) Use wrap mode so that tracing continues when reach the top of the
   buffer.  The trigger count is configured as "Stop on trigger" to
   guard the trace data not to be overwritten.

              watermark   tail      head
     +--------+-----------+---------+-------+
     |        |           |$$$$$$$$$|       |
     +--------+-----------+---------+-------+
     base                                   base + nr_pages
                                            limit

                                    `------->
     >-- counter ---------'

     $$$ : Filled trace data

The modes are selected by comparing the limit with the trigger position.

An extra TRBE_FAULT_ACT_TRIG state is introduced for fault action, it is
used to distinguish the trigger event from the WRAP event.

Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 drivers/hwtracing/coresight/coresight-trbe.c | 101 +++++++++++++++++++++------
 drivers/hwtracing/coresight/coresight-trbe.h |  14 ++++
 2 files changed, 94 insertions(+), 21 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 8390d0a8fe23d35945610df15f21751279ee37ee..0551ea9b4f8286c156e3c9c7ac94e2ecd3b9dc3f 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -48,6 +48,7 @@
 #define TRBE_TRACE_MIN_BUF_SIZE		64
 
 enum trbe_fault_action {
+	TRBE_FAULT_ACT_TRIG,
 	TRBE_FAULT_ACT_WRAP,
 	TRBE_FAULT_ACT_SPURIOUS,
 	TRBE_FAULT_ACT_FATAL,
@@ -67,6 +68,7 @@ struct trbe_buf {
 	unsigned long trbe_hw_base;
 	unsigned long trbe_limit;
 	unsigned long trbe_write;
+	unsigned long trbe_count;
 	int nr_pages;
 	void **pages;
 	bool snapshot;
@@ -478,6 +480,10 @@ static unsigned long __trbe_normal_offset(struct perf_output_handle *handle)
 	if (head < tail)
 		limit = round_down(tail, PAGE_SIZE);
 
+	/* If trigger mode is enabled, no need to use limit for watermark */
+	if (!static_branch_unlikely(&trbe_trigger_mode_bypass))
+		goto out;
+
 	/*
 	 * Wakeup may be arbitrarily far into the future. If it's not in the
 	 * current generation, either we'll wrap before hitting it, or it's
@@ -495,6 +501,7 @@ static unsigned long __trbe_normal_offset(struct perf_output_handle *handle)
 	if (handle->wakeup < (handle->head + handle->size) && head <= wakeup)
 		limit = min(limit, round_up(wakeup, PAGE_SIZE));
 
+out:
 	/*
 	 * There is a situation when this can happen i.e limit is before
 	 * the head and hence TRBE cannot be configured.
@@ -518,6 +525,39 @@ static unsigned long __trbe_normal_offset(struct perf_output_handle *handle)
 	return 0;
 }
 
+static u64 __trbe_normal_trigger_count(struct perf_output_handle *handle)
+{
+	struct trbe_buf *buf = etm_perf_sink_config(handle);
+	struct trbe_cpudata *cpudata = buf->cpudata;
+	u64 limit, head, wakeup;
+	u64 count = 0;
+
+	if (static_branch_unlikely(&trbe_trigger_mode_bypass))
+		return 0;
+
+	limit = buf->trbe_limit - buf->trbe_base;
+	head = PERF_IDX2OFF(handle->head, buf);
+	wakeup = PERF_IDX2OFF(handle->wakeup, buf);
+
+	/* Set the count to guard the end of free buffer after wrap around */
+	if (limit == buf->nr_pages * PAGE_SIZE && (head + handle->size) > limit)
+		count = handle->size;
+
+	/*
+	 * If the watermark is less than the limit, use the trigger count for
+	 * the watermark maintenance.
+	 */
+	if (handle->wakeup < (handle->head + handle->size) && head <= wakeup) {
+		u64 wakeup_count =
+			round_up(wakeup - head, cpudata->trbe_hw_align);
+
+		if (head + wakeup_count < limit)
+			count = wakeup_count;
+	}
+
+	return count;
+}
+
 static int trbe_normal_offset(struct perf_output_handle *handle)
 {
 	struct trbe_buf *buf = etm_perf_sink_config(handle);
@@ -542,6 +582,7 @@ static int trbe_normal_offset(struct perf_output_handle *handle)
 		return -ENOSPC;
 
 	buf->trbe_limit = buf->trbe_base + limit;
+	buf->trbe_count = __trbe_normal_trigger_count(handle);
 	return 0;
 }
 
@@ -594,24 +635,40 @@ static void set_trbe_limit_pointer_enabled(struct trbe_buf *buf)
 	trblimitr &= ~TRBLIMITR_EL1_TM_MASK;
 	trblimitr &= ~TRBLIMITR_EL1_LIMIT_MASK;
 
-	/*
-	 * Fill trace buffer mode is used here while configuring the
-	 * TRBE for trace capture. In this particular mode, the trace
-	 * collection is stopped and a maintenance interrupt is raised
-	 * when the current write pointer wraps. This pause in trace
-	 * collection gives the software an opportunity to capture the
-	 * trace data in the interrupt handler, before reconfiguring
-	 * the TRBE.
-	 */
-	trblimitr |= (TRBLIMITR_EL1_FM_FILL << TRBLIMITR_EL1_FM_SHIFT) &
-		     TRBLIMITR_EL1_FM_MASK;
+	if (!buf->trbe_count ||
+	    buf->trbe_write + buf->trbe_count == buf->trbe_limit) {
+		/*
+		 * Fill trace buffer mode is used here while configuring the
+		 * TRBE for trace capture. In this particular mode, the trace
+		 * collection is stopped and a maintenance interrupt is raised
+		 * when the current write pointer wraps. This pause in trace
+		 * collection gives the software an opportunity to capture the
+		 * trace data in the interrupt handler, before reconfiguring
+		 * the TRBE.
+		 */
+		trblimitr |= FIELD_PREP(TRBLIMITR_EL1_FM_MASK, TRBLIMITR_EL1_FM_FILL) |
+			     FIELD_PREP(TRBLIMITR_EL1_TM_MASK, TRBLIMITR_EL1_TM_IGNR);
+	} else if (buf->trbe_write + buf->trbe_count < buf->trbe_limit) {
+		/*
+		 * Fill mode is used here to stop trace collection and prevent
+		 * the buffer from being overwritten. Trigger mode continues
+		 * trace collection and raises a maintenance interrupt on a
+		 * trigger event, which acts as a watermark for notifying
+		 * userspace.
+		 */
+		trblimitr |= FIELD_PREP(TRBLIMITR_EL1_FM_MASK, TRBLIMITR_EL1_FM_FILL) |
+			     FIELD_PREP(TRBLIMITR_EL1_TM_MASK, TRBLIMITR_EL1_TM_IRQ);
+	} else if (buf->trbe_write + buf->trbe_count > buf->trbe_limit) {
+		/*
+		 * Wrap buffer mode continues trace collection and raises
+		 * maintenance interrupt on buffer wrap. Trigger mode stops
+		 * trace on trigger event to guard the buffer from being
+		 * overwritten.
+		 */
+		trblimitr |= FIELD_PREP(TRBLIMITR_EL1_FM_MASK, TRBLIMITR_EL1_FM_WRAP) |
+			     FIELD_PREP(TRBLIMITR_EL1_TM_MASK, TRBLIMITR_EL1_TM_STOP);
+	}
 
-	/*
-	 * Trigger mode is not used here while configuring the TRBE for
-	 * the trace capture. Hence just keep this in the ignore mode.
-	 */
-	trblimitr |= (TRBLIMITR_EL1_TM_IGNR << TRBLIMITR_EL1_TM_SHIFT) &
-		     TRBLIMITR_EL1_TM_MASK;
 	trblimitr |= (addr & PAGE_MASK);
 	set_trbe_enabled(buf->cpudata, trblimitr);
 }
@@ -623,6 +680,7 @@ static void trbe_enable_hw(struct trbe_buf *buf)
 	WARN_ON(buf->trbe_write >= buf->trbe_limit);
 	set_trbe_base_pointer(buf->trbe_hw_base);
 	set_trbe_write_pointer(buf->trbe_write);
+	set_trbe_trigger_count(buf->trbe_count);
 
 	/*
 	 * Synchronize all the register updates
@@ -639,8 +697,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;
@@ -672,8 +728,7 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
 	case TRBE_BSC_FILLED:
 		break;
 	case TRBE_BSC_TRIGGERED:
-		err_str = "Unexpected trigger status";
-		goto out_fatal;
+		break;
 	default:
 		err_str = "Unexpected buffer status code";
 		goto out_fatal;
@@ -692,6 +747,9 @@ static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *hand
 	if (is_trbe_wrap(trbsr))
 		return TRBE_FAULT_ACT_WRAP;
 
+	if (is_trbe_trg(trbsr))
+		return TRBE_FAULT_ACT_TRIG;
+
 	return TRBE_FAULT_ACT_SPURIOUS;
 
 out_fatal:
@@ -1180,6 +1238,7 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
 		clr_trbe_status();
 
 	switch (act) {
+	case TRBE_FAULT_ACT_TRIG:
 	case TRBE_FAULT_ACT_WRAP:
 		truncated = !!trbe_handle_overflow(handle, act);
 		break;
diff --git a/drivers/hwtracing/coresight/coresight-trbe.h b/drivers/hwtracing/coresight/coresight-trbe.h
index d7f7cd763c0c7139cf322b7336ee563073e3bea0..4c65d164a946ec9860825e7564196745b60d730b 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.h
+++ b/drivers/hwtracing/coresight/coresight-trbe.h
@@ -114,6 +114,20 @@ static inline void set_trbe_write_pointer(unsigned long addr)
 	write_sysreg_s(addr, SYS_TRBPTR_EL1);
 }
 
+static inline void set_trbe_trigger_count(unsigned long count)
+{
+	u64 trbsr;
+
+	write_sysreg_s(count, SYS_TRBTRG_EL1);
+
+	/* TRBSR_EL1.TRG has been cleared in clr_trbe_status() */
+	if (!count)
+		return;
+
+	trbsr = read_sysreg_s(SYS_TRBSR_EL1);
+	write_sysreg_s(trbsr | TRBSR_EL1_TRG, SYS_TRBSR_EL1);
+}
+
 static inline unsigned long get_trbe_limit_pointer(void)
 {
 	u64 trblimitr = read_sysreg_s(SYS_TRBLIMITR_EL1);

-- 
2.34.1


  parent reply	other threads:[~2025-12-01 11:22 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-12-01 11:21 [PATCH 00/19] coresight: trbe: Support trigger and circle buffer modes Leo Yan
2025-12-01 11:21 ` [PATCH 01/19] coresight: trbe: Use helpers for checking errata Leo Yan
2025-12-04 12:08   ` Anshuman Khandual
2025-12-01 11:21 ` [PATCH 02/19] coresight: trbe: Remove redundant disable operation Leo Yan
2025-12-04 12:25   ` Anshuman Khandual
2025-12-01 11:21 ` [PATCH 03/19] coresight: trbe: Remove buffer disabling in trbe_handle_overflow() Leo Yan
2025-12-04 12:31   ` Anshuman Khandual
2025-12-01 11:21 ` [PATCH 04/19] coresight: trbe: Remove set_trbe_disabled() from the enable flow Leo Yan
2025-12-04 12:43   ` Anshuman Khandual
2025-12-04 13:25     ` Leo Yan
2025-12-01 11:21 ` [PATCH 05/19] coresight: trbe: Refactor status clearing Leo Yan
2025-12-04 12:57   ` Anshuman Khandual
2025-12-09 15:29     ` Leo Yan
2025-12-01 11:21 ` [PATCH 06/19] coresight: trbe: Refactor syndrome decoding Leo Yan
2025-12-02 11:06   ` Suzuki K Poulose
2025-12-02 14:24     ` Leo Yan
2025-12-09 13:17     ` James Clark
2025-12-09 16:06       ` Leo Yan
2025-12-05  4:10   ` Anshuman Khandual
2025-12-09 15:57     ` Leo Yan
2025-12-01 11:21 ` [PATCH 07/19] coresight: trbe: Refactor AUX flag setting Leo Yan
2025-12-02 11:15   ` Suzuki K Poulose
2025-12-02 14:21     ` Leo Yan
2025-12-09 13:37   ` James Clark
2025-12-10 15:43     ` Leo Yan
2025-12-12 14:50       ` James Clark
2025-12-12 15:27         ` Leo Yan
2025-12-12 15:52           ` James Clark
2025-12-01 11:21 ` [PATCH 08/19] coresight: trbe: Use PERF_AUX_FLAG_PARTIAL instead of PERF_AUX_FLAG_COLLISION Leo Yan
2025-12-05  4:28   ` Anshuman Khandual
2025-12-09 13:40     ` James Clark
2025-12-10 16:19       ` Leo Yan
2025-12-01 11:21 ` [PATCH 09/19] coresight: trbe: Add fault action argument to trbe_handle_overflow() Leo Yan
2025-12-01 11:22 ` [PATCH 10/19] coresight: trbe: Always check fault action when updating buffer Leo Yan
2025-12-02 12:00   ` Suzuki K Poulose
2025-12-01 11:22 ` [PATCH 11/19] coresight: trbe: Apply overwrite erratum for only wrap event Leo Yan
2025-12-02 12:05   ` Suzuki K Poulose
2025-12-02 16:56     ` Leo Yan
2025-12-02 17:12       ` Leo Yan
2025-12-01 11:22 ` [PATCH 12/19] coresight: trbe: Calculate size for buffer wrapping Leo Yan
2025-12-01 11:22 ` [PATCH 13/19] coresight: trbe: Remove misleading comment Leo Yan
2025-12-01 11:22 ` [PATCH 14/19] coresight: trbe: Refactor compute_trbe_buffer_limit() Leo Yan
2025-12-01 11:22 ` [PATCH 15/19] coresight: trbe: Add static key for bypassing trigger mode Leo Yan
2025-12-02 12:10   ` Suzuki K Poulose
2025-12-01 11:22 ` Leo Yan [this message]
2025-12-01 11:22 ` [PATCH 17/19] coresight: trbe: Enable circle mode for snapshot Leo Yan
2025-12-01 11:22 ` [PATCH 18/19] coresight: trbe: Add kunit tests Leo Yan
2025-12-01 11:22 ` [PATCH 19/19] perf: cs-etm: Set watermark for AUX trace Leo Yan
2025-12-05  4:48   ` Anshuman Khandual
2025-12-09 14:54     ` James Clark
2025-12-10  2:22       ` Anshuman Khandual
2025-12-05  4:53 ` [PATCH 00/19] coresight: trbe: Support trigger and circle buffer modes Anshuman Khandual

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251201-trbe_buffer_refactor_v1-1-v1-16-7da32b076b28@arm.com \
    --to=leo.yan@arm.com \
    --cc=acme@kernel.org \
    --cc=adrian.hunter@intel.com \
    --cc=anshuman.khandual@arm.com \
    --cc=coresight@lists.linaro.org \
    --cc=irogers@google.com \
    --cc=james.clark@linaro.org \
    --cc=jolsa@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=mike.leach@linaro.org \
    --cc=namhyung@kernel.org \
    --cc=suzuki.poulose@arm.com \
    --cc=tamas.petz@arm.com \
    --cc=tamas.zsoldos@arm.com \
    --cc=will@kernel.org \
    --cc=yeoreum.yun@arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).