[PATCH RFC 09/12] rvtrace: Add pre-ratified ramsink setup

Eric Lin eric.lin at sifive.com
Tue Jun 30 02:46:32 PDT 2026


Unlike the standard RISC-V trace ramsink, which is an independent
device, the pre-ratified ramsink are embedded within the trace encoder
or funnel MMIO registers and utilize a different register layout.

Define the pre-ratified ramsink register layout using 'struct
rvtrace_ramsink_regs' and hook the pre-ratified initialization into the
encoder and funnel driver probe sequences. Depending on the component's
major version, rvtrace_ramsink_setup() dynamically selects between the
standard and pre-ratified register maps.

Additionally, handle a hardware constraint where the pre-ratified
ramsink's sink limit and write pointer registers share their upper
32 bits with the sink base address register. This restricts the trace
buffer from crossing a 4GB memory boundary. To satisfy this, invoke
of_reserved_mem_device_init() during setup to allow the device to utilize
a suitably aligned reserved memory region defined in the Device Tree.

Co-developed-by: Nick Hu <nick.hu at sifive.com>
Signed-off-by: Nick Hu <nick.hu at sifive.com>
Co-developed-by: Vincent Chen <vincent.chen at sifive.com>
Signed-off-by: Vincent Chen <vincent.chen at sifive.com>
Signed-off-by: Eric Lin <eric.lin at sifive.com>
---
 drivers/hwtracing/rvtrace/rvtrace-encoder.c |  9 ++++++
 drivers/hwtracing/rvtrace/rvtrace-funnel.c  |  9 ++++++
 drivers/hwtracing/rvtrace/rvtrace-ramsink.c | 44 +++++++++++++++++++++++------
 drivers/hwtracing/rvtrace/rvtrace-ramsink.h | 11 ++++++++
 drivers/hwtracing/rvtrace/rvtrace-v0.c      | 43 ++++++++++++++++++++++++++++
 drivers/hwtracing/rvtrace/rvtrace-v0.h      | 13 +++++++++
 6 files changed, 120 insertions(+), 9 deletions(-)

diff --git a/drivers/hwtracing/rvtrace/rvtrace-encoder.c b/drivers/hwtracing/rvtrace/rvtrace-encoder.c
index 47740bbdc206..b187731ff855 100644
--- a/drivers/hwtracing/rvtrace/rvtrace-encoder.c
+++ b/drivers/hwtracing/rvtrace/rvtrace-encoder.c
@@ -79,6 +79,15 @@ static int rvtrace_encoder_stop(struct rvtrace_component *comp)
 static int rvtrace_encoder_probe(struct rvtrace_component *comp)
 {
 	int ret;
+	u32 comp_maj;
+
+	/* Pre-ratified ramsink setup */
+	comp_maj = rvtrace_component_version_major(comp->id.version);
+	if (comp_maj == 0) {
+		ret = rvtrace_v0_ramsink_setup(comp);
+		if (ret)
+			return dev_err_probe(&comp->dev, ret, "failed to setup ramsink.\n");
+	}
 
 	ret = rvtrace_enable_component(comp->pdata);
 	if (ret)
diff --git a/drivers/hwtracing/rvtrace/rvtrace-funnel.c b/drivers/hwtracing/rvtrace/rvtrace-funnel.c
index 2bf553a88d98..21f58001d569 100644
--- a/drivers/hwtracing/rvtrace/rvtrace-funnel.c
+++ b/drivers/hwtracing/rvtrace/rvtrace-funnel.c
@@ -54,6 +54,15 @@ static int rvtrace_funnel_probe(struct rvtrace_component *comp)
 {
 	struct fwnode_handle *fwnode = dev_fwnode(comp->pdata->dev);
 	int ret;
+	u32 comp_maj;
+
+	/* Pre-ratified ramsink setup */
+	comp_maj = rvtrace_component_version_major(comp->id.version);
+	if (comp_maj == 0) {
+		ret = rvtrace_v0_ramsink_setup(comp);
+		if (ret)
+			return dev_err_probe(&comp->dev, ret, "failed to setup ramsink.\n");
+	}
 
 	ret = rvtrace_enable_component(comp->pdata);
 	if (ret)
diff --git a/drivers/hwtracing/rvtrace/rvtrace-ramsink.c b/drivers/hwtracing/rvtrace/rvtrace-ramsink.c
index e569e875568b..e794b01e19d0 100644
--- a/drivers/hwtracing/rvtrace/rvtrace-ramsink.c
+++ b/drivers/hwtracing/rvtrace/rvtrace-ramsink.c
@@ -10,6 +10,8 @@
 #include <linux/rvtrace.h>
 #include <linux/types.h>
 #include <linux/sizes.h>
+#include "rvtrace-ramsink.h"
+#include "rvtrace-v0.h"
 
 #define RVTRACE_RAMSINK_STARTLOW_OFF		0x010
 #define RVTRACE_RAMSINK_STARTHIGH_OFF		0x014
@@ -83,6 +85,20 @@ struct trace_buf {
 	size_t len;
 };
 
+/*
+ * Register offset for SiFive trace encoder/funnel system memory sink.
+ * Note: SiFive uses RVTRACE_V0_SINK_BASE_HIGH_OFF for start_high, limit_high,
+ * and wp_high (shared register).
+ */
+static const struct rvtrace_ramsink_regs rvtrace_v0_sink_regs = {
+	.start_low    = RVTRACE_V0_SINK_BASE_OFF,
+	.start_high   = RVTRACE_V0_SINK_BASE_HIGH_OFF,
+	.limit_low    = RVTRACE_V0_SINK_LIMIT_OFF,
+	.limit_high   = RVTRACE_V0_SINK_BASE_HIGH_OFF,  /* Shared with start_high */
+	.wp_low       = RVTRACE_V0_SINK_WP_OFF,
+	.wp_high      = RVTRACE_V0_SINK_BASE_HIGH_OFF,  /* Shared with start_high */
+};
+
 /* Register offsets for the standard RISC-V trace ramsink */
 static const struct rvtrace_ramsink_regs rvtrace_std_ramsink_regs = {
 	.start_low    = RVTRACE_RAMSINK_STARTLOW_OFF,
@@ -285,10 +301,10 @@ static int rvtrace_ramsink_setup_buf(struct rvtrace_component *comp,
 	return 0;
 }
 
-static int rvtrace_ramsink_setup(struct rvtrace_component *comp)
+int rvtrace_ramsink_setup(struct rvtrace_component *comp)
 {
 	struct rvtrace_ramsink_priv *priv;
-	u32 trram_ctrl;
+	u32 trram_ctrl, comp_maj;
 	int ret;
 
 	priv = devm_kzalloc(&comp->dev, sizeof(*priv), GFP_KERNEL);
@@ -305,16 +321,26 @@ static int rvtrace_ramsink_setup(struct rvtrace_component *comp)
 		break;
 	}
 
-	priv->regs = &rvtrace_std_ramsink_regs;
+	comp_maj = rvtrace_component_version_major(comp->id.version);
+	/* Pre-ratified ramsink regs */
+	if (comp_maj == 0)
+		priv->regs = &rvtrace_v0_sink_regs;
+	else
+		priv->regs = &rvtrace_std_ramsink_regs;
 
 	trram_ctrl = rvtrace_read32(comp->pdata, RVTRACE_COMPONENT_CTRL_OFFSET);
-	trram_ctrl |= priv->mode << RVTRACE_RAMSINK_CTRL_MODE_SHIFT;
-	rvtrace_write32(comp->pdata, trram_ctrl, RVTRACE_COMPONENT_CTRL_OFFSET);
-	trram_ctrl = rvtrace_read32(comp->pdata, RVTRACE_COMPONENT_CTRL_OFFSET);
-	dev_dbg(&comp->dev, "mode: %s\n", (trram_ctrl >> RVTRACE_RAMSINK_CTRL_MODE_SHIFT) & 0x1 ?
-		 "SMEM" : "SRAM");
 
-	trram_ctrl |= priv->stop_on_wrap << RVTRACE_RAMSINK_CTRL_STP_WRAP_SHIFT;
+	if (comp_maj == 0) {
+		trram_ctrl |= priv->stop_on_wrap << RVTRACE_V0_CTRL_STOP_ON_WRAP_SHIFT;
+	} else {
+		trram_ctrl |= priv->mode << RVTRACE_RAMSINK_CTRL_MODE_SHIFT;
+		rvtrace_write32(comp->pdata, trram_ctrl, RVTRACE_COMPONENT_CTRL_OFFSET);
+		trram_ctrl = rvtrace_read32(comp->pdata, RVTRACE_COMPONENT_CTRL_OFFSET);
+		dev_dbg(&comp->dev, "mode: %s\n",
+			(trram_ctrl >> RVTRACE_RAMSINK_CTRL_MODE_SHIFT) & 0x1 ? "SMEM" : "SRAM");
+		trram_ctrl |= priv->stop_on_wrap << RVTRACE_RAMSINK_CTRL_STP_WRAP_SHIFT;
+	}
+
 	rvtrace_write32(comp->pdata, trram_ctrl, RVTRACE_COMPONENT_CTRL_OFFSET);
 
 	ret = rvtrace_ramsink_setup_buf(comp, priv);
diff --git a/drivers/hwtracing/rvtrace/rvtrace-ramsink.h b/drivers/hwtracing/rvtrace/rvtrace-ramsink.h
new file mode 100644
index 000000000000..7e0391aeffd5
--- /dev/null
+++ b/drivers/hwtracing/rvtrace/rvtrace-ramsink.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2026 SiFive, Inc.
+ */
+
+#ifndef __RVTRACE_RAMSINK_H__
+#define __RVTRACE_RAMSINK_H__
+
+int rvtrace_ramsink_setup(struct rvtrace_component *comp);
+
+#endif /* __RVTRACE_RAMSINK_H__ */
diff --git a/drivers/hwtracing/rvtrace/rvtrace-v0.c b/drivers/hwtracing/rvtrace/rvtrace-v0.c
index ba87e1f7a839..9451d96024bc 100644
--- a/drivers/hwtracing/rvtrace/rvtrace-v0.c
+++ b/drivers/hwtracing/rvtrace/rvtrace-v0.c
@@ -3,8 +3,51 @@
  * Copyright (c) 2026 SiFive Inc.
  */
 
+#include <linux/of_reserved_mem.h>
 #include <linux/rvtrace.h>
 #include "rvtrace-v0.h"
+#include "rvtrace-ramsink.h"
+
+int rvtrace_v0_ramsink_setup(struct rvtrace_component *comp)
+{
+	struct rvtrace_v0_comp_features	*data = NULL;
+	int ret;
+	u32 val;
+
+	data = (struct rvtrace_v0_comp_features *)comp->id.data;
+	if (!data)
+		return -EINVAL;
+
+	if (comp->id.type > RVTRACE_COMPONENT_TYPE_FUNNEL)
+		return -EOPNOTSUPP;
+
+	if (data->has_sba_sink) {
+		/*
+		 * The pre-ratified ramsink's sink limit and write pointer registers share
+		 * their upper 32 bits with the sink base address register. This hardware
+		 * constraint prevents the trace buffer from crossing a 4GB memory boundary.
+		 *
+		 * Use of_reserved_mem_device_init() to associate the device with a
+		 * reserved memory region defined in the Device Tree. This ensures the
+		 * buffer allocation adheres to the necessary alignment and size constraints.
+		 */
+		ret = of_reserved_mem_device_init(comp->pdata->dev);
+		if (ret) {
+			dev_err(comp->pdata->dev, "Failed to get reserved memory region\n");
+			return ret;
+		}
+
+		/* Set comp sink to SBA (system memory) */
+		val = rvtrace_read32(comp->pdata, RVTRACE_COMPONENT_CTRL_OFFSET);
+		val &= ~RVTRACE_V0_CTRL_SINK_MASK;
+		val |= TE_SINK_SBA << RVTRACE_V0_CTRL_SINK_SHIFT;
+		rvtrace_write32(comp->pdata, val, RVTRACE_COMPONENT_CTRL_OFFSET);
+
+		return rvtrace_ramsink_setup(comp);
+	}
+
+	return 0;
+}
 
 int rvtrace_v0_sink_config(struct rvtrace_path_node *node)
 {
diff --git a/drivers/hwtracing/rvtrace/rvtrace-v0.h b/drivers/hwtracing/rvtrace/rvtrace-v0.h
index 48728fef24c0..2b4e63e3ead0 100644
--- a/drivers/hwtracing/rvtrace/rvtrace-v0.h
+++ b/drivers/hwtracing/rvtrace/rvtrace-v0.h
@@ -9,6 +9,19 @@
 
 #include <linux/rvtrace.h>
 
+/* Register offsets */
+#define RVTRACE_V0_CTRL_OFF			0x000
+#define RVTRACE_V0_IMPL_OFF			0x004
+#define RVTRACE_V0_IMPL_EXTRA_OFF		0x008
+#define RVTRACE_V0_EV_CTRL_OFF			0x00c
+#define RVTRACE_V0_SINK_BASE_OFF		0x010
+#define RVTRACE_V0_SINK_BASE_HIGH_OFF		0x014
+#define RVTRACE_V0_SINK_LIMIT_OFF		0x018
+#define RVTRACE_V0_SINK_WP_OFF			0x01c
+#define RVTRACE_V0_SINK_RP_OFF			0x020
+#define RVTRACE_V0_SINK_DATA_OFF		0x024
+
+#define RVTRACE_V0_CTRL_STOP_ON_WRAP_SHIFT	14
 #define RVTRACE_V0_CTRL_SINK_SHIFT		28
 #define RVTRACE_V0_CTRL_SINK_MASK		GENMASK(31, RVTRACE_V0_CTRL_SINK_SHIFT)
 

-- 
2.34.1




More information about the linux-riscv mailing list