[PATCH RFC 09/12] rvtrace: Add pre-ratified ramsink setup
From: Eric Lin
Date: Tue Jun 30 2026 - 05:54:37 EST
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@xxxxxxxxxx>
Signed-off-by: Nick Hu <nick.hu@xxxxxxxxxx>
Co-developed-by: Vincent Chen <vincent.chen@xxxxxxxxxx>
Signed-off-by: Vincent Chen <vincent.chen@xxxxxxxxxx>
Signed-off-by: Eric Lin <eric.lin@xxxxxxxxxx>
---
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