[PATCH v3 03/12] rvtrace: Add functions to create/destroy a trace component path

Vincent Chen vincent.chen at sifive.com
Thu Mar 12 23:25:29 PDT 2026


>
> 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 <mayuresh.chitale at oss.qualcomm.com>
> Signed-off-by: Mayuresh Chitale <mayuresh.chitale at oss.qualcomm.com>
> Signed-off-by: Anup Patel <anup.patel at oss.qualcomm.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 d69c2236493a..5f40bad215e0 100644
> --- a/drivers/hwtracing/rvtrace/rvtrace-core.c
> +++ b/drivers/hwtracing/rvtrace/rvtrace-core.c
> @@ -229,6 +229,53 @@ int rvtrace_reset_component(struct
> rvtrace_platform_data *pdata)
>  }
>  EXPORT_SYMBOL_GPL(rvtrace_reset_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))
> @@ -452,6 +499,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)

Hi Anup,
It looks like there's a typo here. I believe this should be if (!node)
instead of 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 d6be6e3cc10f..00b63fa22da9 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.
> @@ -239,6 +247,10 @@ int rvtrace_enable_component(struct
> rvtrace_platform_data *pdata);
>  int rvtrace_disable_component(struct rvtrace_platform_data *pdata);
>  int rvtrace_reset_component(struct rvtrace_platform_data *pdata);
>
> +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(enum
> rvtrace_component_type type,
> @@ -246,17 +258,44 @@ struct rvtrace_component
> *rvtrace_register_component(enum rvtrace_component_type
>       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;
>  };



More information about the linux-riscv mailing list