From: Anup Patel <apatel@ventanamicro.com>
To: Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Paul Walmsley <paul.walmsley@sifive.com>,
Palmer Dabbelt <palmer@dabbelt.com>,
Greg KH <gregkh@linuxfoundation.org>,
Alexander Shishkin <alexander.shishkin@linux.intel.com>,
Ian Rogers <irogers@google.com>
Cc: Alexandre Ghiti <alex@ghiti.fr>,
Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@redhat.com>,
Namhyung Kim <namhyung@kernel.org>,
Mark Rutland <mark.rutland@arm.com>, Jiri Olsa <jolsa@kernel.org>,
Adrian Hunter <adrian.hunter@intel.com>,
Liang Kan <kan.liang@linux.intel.com>,
Mayuresh Chitale <mchitale@gmail.com>,
Anup Patel <anup@brainfault.org>,
Atish Patra <atish.patra@linux.dev>,
Andrew Jones <ajones@ventanamicro.com>,
Sunil V L <sunilvl@ventanamicro.com>,
linux-riscv@lists.infradead.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
Anup Patel <apatel@ventanamicro.com>,
Mayuresh Chitale <mchitale@ventanamicro.com>
Subject: [PATCH v2 03/12] rvtrace: Add functions to create/destroy a trace component path
Date: Sat, 1 Nov 2025 21:12:36 +0530 [thread overview]
Message-ID: <20251101154245.162492-4-apatel@ventanamicro.com> (raw)
In-Reply-To: <20251101154245.162492-1-apatel@ventanamicro.com>
Trace needs to be configured on a chain of trace components which are
connected to each other. These chain of components is also referred
to as trace component path. Add functions to create/destroy a trace
component path which will be later used by RISC-V trace perf support.
Co-developed-by: Mayuresh Chitale <mchitale@ventanamicro.com>
Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
drivers/hwtracing/rvtrace/rvtrace-core.c | 223 +++++++++++++++++++++++
include/linux/rvtrace.h | 43 ++++-
2 files changed, 264 insertions(+), 2 deletions(-)
diff --git a/drivers/hwtracing/rvtrace/rvtrace-core.c b/drivers/hwtracing/rvtrace/rvtrace-core.c
index 32fda1647b39..7006a4469d62 100644
--- a/drivers/hwtracing/rvtrace/rvtrace-core.c
+++ b/drivers/hwtracing/rvtrace/rvtrace-core.c
@@ -211,6 +211,53 @@ int rvtrace_disable_component(struct rvtrace_component *comp)
}
EXPORT_SYMBOL_GPL(rvtrace_disable_component);
+static int __rvtrace_walk_output_components(struct rvtrace_component *comp,
+ bool *stop, void *priv,
+ int (*fn)(struct rvtrace_component *comp, bool *stop,
+ struct rvtrace_connection *stop_conn,
+ void *priv))
+{
+ struct rvtrace_connection *conn, *stop_conn = NULL;
+ struct rvtrace_platform_data *pdata = comp->pdata;
+ int i, ret;
+
+ for (i = 0; i < pdata->nr_outconns; i++) {
+ conn = pdata->outconns[i];
+ ret = __rvtrace_walk_output_components(conn->dest_comp, stop, priv, fn);
+ if (ret)
+ return ret;
+ if (*stop) {
+ stop_conn = conn;
+ break;
+ }
+ }
+
+ ret = fn(comp, stop, stop_conn, priv);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int rvtrace_walk_output_components(struct rvtrace_component *comp, void *priv,
+ int (*fn)(struct rvtrace_component *comp, bool *stop,
+ struct rvtrace_connection *stop_conn,
+ void *priv))
+{
+ bool stop = false;
+ int ret;
+
+ if (!comp || !fn)
+ return -EINVAL;
+
+ mutex_lock(&rvtrace_mutex);
+ ret = __rvtrace_walk_output_components(comp, &stop, priv, fn);
+ mutex_unlock(&rvtrace_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rvtrace_walk_output_components);
+
struct rvtrace_component *rvtrace_cpu_source(unsigned int cpu)
{
if (!cpu_present(cpu))
@@ -463,6 +510,182 @@ void rvtrace_unregister_component(struct rvtrace_component *comp)
}
EXPORT_SYMBOL_GPL(rvtrace_unregister_component);
+struct rvtrace_path_node {
+ struct list_head head;
+ struct rvtrace_component *comp;
+ struct rvtrace_connection *conn;
+};
+
+struct rvtrace_component *rvtrace_path_source(struct rvtrace_path *path)
+{
+ struct rvtrace_path_node *node;
+
+ node = list_first_entry(&path->comp_list, struct rvtrace_path_node, head);
+ return node->comp;
+}
+EXPORT_SYMBOL_GPL(rvtrace_path_source);
+
+struct rvtrace_component *rvtrace_path_sink(struct rvtrace_path *path)
+{
+ struct rvtrace_path_node *node;
+
+ node = list_last_entry(&path->comp_list, struct rvtrace_path_node, head);
+ return node->comp;
+}
+EXPORT_SYMBOL_GPL(rvtrace_path_sink);
+
+static int rvtrace_assign_trace_id(struct rvtrace_path *path)
+{
+ const struct rvtrace_driver *rtdrv;
+ struct rvtrace_component *comp;
+ struct rvtrace_path_node *node;
+ int trace_id;
+
+ list_for_each_entry(node, &path->comp_list, head) {
+ comp = node->comp;
+ rtdrv = to_rvtrace_driver(comp->dev.driver);
+
+ if (!rtdrv->get_trace_id)
+ continue;
+
+ trace_id = rtdrv->get_trace_id(comp, path->mode);
+ if (trace_id > 0) {
+ path->trace_id = trace_id;
+ return 0;
+ } else if (trace_id < 0) {
+ return trace_id;
+ }
+ }
+
+ return 0;
+}
+
+static void rvtrace_unassign_trace_id(struct rvtrace_path *path)
+{
+ const struct rvtrace_driver *rtdrv;
+ struct rvtrace_component *comp;
+ struct rvtrace_path_node *node;
+
+ list_for_each_entry(node, &path->comp_list, head) {
+ comp = node->comp;
+ rtdrv = to_rvtrace_driver(comp->dev.driver);
+
+ if (!rtdrv->put_trace_id)
+ continue;
+
+ rtdrv->put_trace_id(comp, path->mode, path->trace_id);
+ }
+}
+
+static bool rvtrace_path_ready(struct rvtrace_path *path)
+{
+ struct rvtrace_path_node *node;
+
+ list_for_each_entry(node, &path->comp_list, head) {
+ if (!node->comp->ready)
+ return false;
+ }
+
+ return true;
+}
+
+struct build_path_walk_priv {
+ struct rvtrace_path *path;
+ struct rvtrace_component *sink;
+};
+
+static int build_path_walk_fn(struct rvtrace_component *comp, bool *stop,
+ struct rvtrace_connection *stop_conn,
+ void *priv)
+{
+ struct build_path_walk_priv *ppriv = priv;
+ struct rvtrace_path *path = ppriv->path;
+ struct rvtrace_path_node *node;
+
+ if ((!ppriv->sink && rvtrace_is_sink(comp->pdata)) ||
+ (ppriv->sink && ppriv->sink == comp))
+ *stop = true;
+
+ if (*stop) {
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!path)
+ return -ENOMEM;
+ INIT_LIST_HEAD(&node->head);
+ rvtrace_get_component(comp);
+ node->comp = comp;
+ node->conn = stop_conn;
+ list_add(&node->head, &path->comp_list);
+ }
+
+ return 0;
+}
+
+static void rvtrace_release_path_nodes(struct rvtrace_path *path)
+{
+ struct rvtrace_path_node *node, *node1;
+
+ list_for_each_entry_safe(node, node1, &path->comp_list, head) {
+ list_del(&node->head);
+ rvtrace_put_component(node->comp);
+ kfree(node);
+ }
+}
+
+struct rvtrace_path *rvtrace_create_path(struct rvtrace_component *source,
+ struct rvtrace_component *sink,
+ enum rvtrace_component_mode mode)
+{
+ struct build_path_walk_priv priv;
+ struct rvtrace_path *path;
+ int ret = 0;
+
+ if (!source || mode >= RVTRACE_COMPONENT_MODE_MAX) {
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ path = kzalloc(sizeof(*path), GFP_KERNEL);
+ if (!path) {
+ ret = -ENOMEM;
+ goto err_out;
+ }
+ INIT_LIST_HEAD(&path->comp_list);
+ path->mode = mode;
+ path->trace_id = RVTRACE_INVALID_TRACE_ID;
+
+ priv.path = path;
+ priv.sink = sink;
+ ret = rvtrace_walk_output_components(source, &priv, build_path_walk_fn);
+ if (ret < 0)
+ goto err_release_path_nodes;
+
+ if (!rvtrace_path_ready(path)) {
+ ret = -EOPNOTSUPP;
+ goto err_release_path_nodes;
+ }
+
+ ret = rvtrace_assign_trace_id(path);
+ if (ret < 0)
+ goto err_release_path_nodes;
+
+ return path;
+
+err_release_path_nodes:
+ rvtrace_release_path_nodes(path);
+ kfree(path);
+err_out:
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(rvtrace_create_path);
+
+void rvtrace_destroy_path(struct rvtrace_path *path)
+{
+ rvtrace_unassign_trace_id(path);
+ rvtrace_release_path_nodes(path);
+ kfree(path);
+}
+EXPORT_SYMBOL_GPL(rvtrace_destroy_path);
+
int __rvtrace_register_driver(struct module *owner, struct rvtrace_driver *rtdrv)
{
rtdrv->driver.owner = owner;
diff --git a/include/linux/rvtrace.h b/include/linux/rvtrace.h
index e8e055ad6583..4b31ab96e721 100644
--- a/include/linux/rvtrace.h
+++ b/include/linux/rvtrace.h
@@ -8,6 +8,8 @@
#include <linux/device.h>
#include <linux/io.h>
+#include <linux/limits.h>
+#include <linux/list.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/types.h>
@@ -72,6 +74,12 @@ enum rvtrace_component_impid {
RVTRACE_COMPONENT_IMPID_MAX
};
+/* Supported usage modes for RISC-V trace components */
+enum rvtrace_component_mode {
+ RVTRACE_COMPONENT_MODE_PERF,
+ RVTRACE_COMPONENT_MODE_MAX
+};
+
/**
* struct rvtrace_connection - Representation of a physical connection between
* two RISC-V trace components.
@@ -238,22 +246,53 @@ int rvtrace_poll_bit(struct rvtrace_platform_data *pdata, int offset,
int rvtrace_enable_component(struct rvtrace_component *comp);
int rvtrace_disable_component(struct rvtrace_component *comp);
+int rvtrace_walk_output_components(struct rvtrace_component *comp, void *priv,
+ int (*fn)(struct rvtrace_component *comp, bool *stop,
+ struct rvtrace_connection *stop_conn,
+ void *priv));
struct rvtrace_component *rvtrace_cpu_source(unsigned int cpu);
struct rvtrace_component *rvtrace_register_component(struct rvtrace_platform_data *pdata);
void rvtrace_unregister_component(struct rvtrace_component *comp);
+/**
+ * struct rvtrace_path - Representation of a RISC-V trace path from source to sink
+ * @comp_list: List of RISC-V trace components in the path
+ * @mode: Usage mode for RISC-V trace components
+ * @trace_id: ID of the trace source (typically hart id)
+ */
+struct rvtrace_path {
+ struct list_head comp_list;
+ enum rvtrace_component_mode mode;
+ u32 trace_id;
+#define RVTRACE_INVALID_TRACE_ID 0
+};
+
+struct rvtrace_component *rvtrace_path_source(struct rvtrace_path *path);
+struct rvtrace_component *rvtrace_path_sink(struct rvtrace_path *path);
+struct rvtrace_path *rvtrace_create_path(struct rvtrace_component *source,
+ struct rvtrace_component *sink,
+ enum rvtrace_component_mode mode);
+void rvtrace_destroy_path(struct rvtrace_path *path);
+
/**
* struct rvtrace_driver - Representation of a RISC-V trace driver
* id_table: Table to match components handled by the driver
- * probe: Driver probe() function
- * remove: Driver remove() function
+ * probe: Driver probe() function
+ * remove: Driver remove() function
+ * get_trace_id: Get/allocate a trace ID
+ * put_trace_id: Put/free a trace ID
* driver: Device driver instance
*/
struct rvtrace_driver {
const struct rvtrace_component_id *id_table;
int (*probe)(struct rvtrace_component *comp);
void (*remove)(struct rvtrace_component *comp);
+ int (*get_trace_id)(struct rvtrace_component *comp,
+ enum rvtrace_component_mode mode);
+ void (*put_trace_id)(struct rvtrace_component *comp,
+ enum rvtrace_component_mode mode,
+ u32 trace_id);
struct device_driver driver;
};
--
2.43.0
next prev parent reply other threads:[~2025-11-01 15:43 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-01 15:42 [PATCH v2 00/12] Linux RISC-V trace framework and drivers Anup Patel
2025-11-01 15:42 ` [PATCH v2 01/12] dt-bindings: Add RISC-V trace component bindings Anup Patel
2025-11-20 16:39 ` Rob Herring
2026-01-02 3:38 ` Anup Patel
2025-11-01 15:42 ` [PATCH v2 02/12] rvtrace: Initial implementation of driver framework Anup Patel
2025-11-21 7:49 ` Nutty.Liu
2025-12-02 10:41 ` Bo Gan
2025-11-01 15:42 ` Anup Patel [this message]
2025-11-01 15:42 ` [PATCH v2 04/12] rvtrace: Add functions to start/stop tracing on a component path Anup Patel
2025-11-01 15:42 ` [PATCH v2 05/12] rvtrace: Add trace encoder driver Anup Patel
2025-11-01 15:42 ` [PATCH v2 06/12] rvtrace: Add function to copy into perf AUX buffer Anup Patel
2025-11-01 15:42 ` [PATCH v2 07/12] rvtrace: Add trace ramsink driver Anup Patel
2025-11-30 7:45 ` Bo Gan
2025-12-02 11:47 ` Mayuresh Chitale
2025-12-03 1:10 ` Bo Gan
2025-12-06 17:59 ` Mayuresh Chitale
2025-11-01 15:42 ` [PATCH v2 08/12] riscv: Enable DMA_RESTRICTED_POOL in defconfig Anup Patel
2025-11-01 15:42 ` [PATCH v2 09/12] rvtrace: Add perf driver for tracing using perf tool Anup Patel
2025-11-01 15:42 ` [PATCH v2 10/12] perf tools: Add RISC-V trace PMU record capabilities Anup Patel
2025-11-21 8:09 ` Nutty.Liu
2026-01-02 3:52 ` Anup Patel
2025-11-01 15:42 ` [PATCH v2 11/12] perf tools: Initial support for RISC-V trace decoder Anup Patel
2025-11-01 15:42 ` [PATCH v2 12/12] MAINTAINERS: Add entry for RISC-V trace framework and drivers Anup Patel
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=20251101154245.162492-4-apatel@ventanamicro.com \
--to=apatel@ventanamicro.com \
--cc=adrian.hunter@intel.com \
--cc=ajones@ventanamicro.com \
--cc=alex@ghiti.fr \
--cc=alexander.shishkin@linux.intel.com \
--cc=anup@brainfault.org \
--cc=atish.patra@linux.dev \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=gregkh@linuxfoundation.org \
--cc=irogers@google.com \
--cc=jolsa@kernel.org \
--cc=kan.liang@linux.intel.com \
--cc=krzk+dt@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=mark.rutland@arm.com \
--cc=mchitale@gmail.com \
--cc=mchitale@ventanamicro.com \
--cc=mingo@redhat.com \
--cc=namhyung@kernel.org \
--cc=palmer@dabbelt.com \
--cc=paul.walmsley@sifive.com \
--cc=peterz@infradead.org \
--cc=robh@kernel.org \
--cc=sunilvl@ventanamicro.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).