[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251002060732.100213-4-apatel@ventanamicro.com>
Date: Thu, 2 Oct 2025 11:37:24 +0530
From: Anup Patel <apatel@...tanamicro.com>
To: Rob Herring <robh@...nel.org>,
Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>,
Paul Walmsley <paul.walmsley@...ive.com>,
Palmer Dabbelt <palmer@...belt.com>,
Greg KH <gregkh@...uxfoundation.org>,
Alexander Shishkin <alexander.shishkin@...ux.intel.com>,
Ian Rogers <irogers@...gle.com>
Cc: Alexandre Ghiti <alex@...ti.fr>,
Peter Zijlstra <peterz@...radead.org>,
Ingo Molnar <mingo@...hat.com>,
Namhyung Kim <namhyung@...nel.org>,
Mark Rutland <mark.rutland@....com>,
Jiri Olsa <jolsa@...nel.org>,
Adrian Hunter <adrian.hunter@...el.com>,
Liang Kan <kan.liang@...ux.intel.com>,
Mayuresh Chitale <mchitale@...il.com>,
Anup Patel <anup@...infault.org>,
Atish Patra <atish.patra@...ux.dev>,
Andrew Jones <ajones@...tanamicro.com>,
Sunil V L <sunilvl@...tanamicro.com>,
linux-riscv@...ts.infradead.org,
devicetree@...r.kernel.org,
linux-kernel@...r.kernel.org,
Anup Patel <apatel@...tanamicro.com>,
Mayuresh Chitale <mchitale@...tanamicro.com>
Subject: [PATCH 03/11] rvtrace: Add functions to create/destroy a trace component path
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@...tanamicro.com>
Signed-off-by: Mayuresh Chitale <mchitale@...tanamicro.com>
Signed-off-by: Anup Patel <apatel@...tanamicro.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 52ea931745fc..7013d50ca569 100644
--- a/drivers/hwtracing/rvtrace/rvtrace-core.c
+++ b/drivers/hwtracing/rvtrace/rvtrace-core.c
@@ -194,6 +194,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))
@@ -446,6 +493,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 04eb03e62601..f2174f463a69 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>
@@ -71,6 +73,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.
@@ -237,22 +245,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
Powered by blists - more mailing lists