[PATCH v5 04/14] gtrace: Add functions to create/destroy a trace component path
Mayuresh Chitale <[email protected]>
| Newsgroups | org.infradead.lists.linux-riscv,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
From: Anup Patel <[email protected]> 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 gtrace perf support. Co-developed-by: Mayuresh Chitale <[email protected]> Signed-off-by: Mayuresh Chitale <[email protected]> Signed-off-by: Anup Patel <[email protected]> --- drivers/hwtracing/gtrace/gtrace-core.c | 223 +++++++++++++++++++++++++ include/linux/gtrace.h | 24 +++ 2 files changed, 247 insertions(+) diff --git a/drivers/hwtracing/gtrace/gtrace-core.c b/drivers/hwtracing/gtrace/gtrace-core.c index 97398f2b7cbb..a89d195ab5b8 100644 --- a/drivers/hwtracing/gtrace/gtrace-core.c +++ b/drivers/hwtracing/gtrace/gtrace-core.c @@ -210,6 +210,53 @@ int gtrace_reset_component(struct gtrace_component *comp) } EXPORT_SYMBOL_GPL(gtrace_reset_component); +static int __gtrace_walk_output_components(struct gtrace_component *comp, + bool *stop, void *priv, + int (*fn)(struct gtrace_component *comp, bool *stop, + struct gtrace_connection *stop_conn, + void *priv)) +{ + struct gtrace_connection *conn, *stop_conn = NULL; + struct gtrace_platform_data *pdata = comp->pdata; + int i, ret; + + for (i = 0; i < pdata->nr_outconns; i++) { + conn = pdata->outconns[i]; + ret = __gtrace_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 gtrace_walk_output_components(struct gtrace_component *comp, void *priv, + int (*fn)(struct gtrace_component *comp, bool *stop, + struct gtrace_connection *stop_conn, + void *priv)) +{ + bool stop = false; + int ret; + + if (!comp || !fn) + return -EINVAL; + + mutex_lock(>race_mutex); + ret = __gtrace_walk_output_components(comp, &stop, priv, fn); + mutex_unlock(>race_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(gtrace_walk_output_components); + struct gtrace_component *gtrace_cpu_source(unsigned int cpu) { if (!cpu_present(cpu)) @@ -414,6 +461,182 @@ void gtrace_unregister_component(struct gtrace_component *comp) } EXPORT_SYMBOL_GPL(gtrace_unregister_component); +struct gtrace_path_node { + struct list_head head; + struct gtrace_component *comp; + struct gtrace_connection *conn; +}; + +struct gtrace_component *gtrace_path_source(struct gtrace_path *path) +{ + struct gtrace_path_node *node; + + node = list_first_entry(&path->comp_list, struct gtrace_path_node, head); + return node->comp; +} +EXPORT_SYMBOL_GPL(gtrace_path_source); + +struct gtrace_component *gtrace_path_sink(struct gtrace_path *path) +{ + struct gtrace_path_node *node; + + node = list_last_entry(&path->comp_list, struct gtrace_path_node, head); + return node->comp; +} +EXPORT_SYMBOL_GPL(gtrace_path_sink); + +static int gtrace_assign_trace_id(struct gtrace_path *path) +{ + const struct gtrace_driver *gtdrv; + struct gtrace_component *comp; + struct gtrace_path_node *node; + int trace_id; + + list_for_each_entry(node, &path->comp_list, head) { + comp = node->comp; + gtdrv = to_gtrace_driver(comp->dev.driver); + + if (!gtdrv->get_trace_id) + continue; + + trace_id = gtdrv->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 gtrace_unassign_trace_id(struct gtrace_path *path) +{ + const struct gtrace_driver *gtdrv; + struct gtrace_component *comp; + struct gtrace_path_node *node; + + list_for_each_entry(node, &path->comp_list, head) { + comp = node->comp; + gtdrv = to_gtrace_driver(comp->dev.driver); + + if (!gtdrv->put_trace_id) + continue; + + gtdrv->put_trace_id(comp, path->mode, path->trace_id); + } +} + +static bool gtrace_path_ready(struct gtrace_path *path) +{ + struct gtrace_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 gtrace_path *path; + struct gtrace_component *sink; +}; + +static int build_path_walk_fn(struct gtrace_component *comp, bool *stop, + struct gtrace_connection *stop_conn, + void *priv) +{ + struct build_path_walk_priv *ppriv = priv; + struct gtrace_path *path = ppriv->path; + struct gtrace_path_node *node; + + if ((!ppriv->sink && gtrace_is_sink(comp->pdata)) || + (ppriv->sink && ppriv->sink == comp)) + *stop = true; + + if (*stop) { + node = kzalloc_obj(*node); + if (!node) + return -ENOMEM; + INIT_LIST_HEAD(&node->head); + gtrace_get_component(comp); + node->comp = comp; + node->conn = stop_conn; + list_add(&node->head, &path->comp_list); + } + + return 0; +} + +static void gtrace_release_path_nodes(struct gtrace_path *path) +{ + struct gtrace_path_node *node, *node1; + + list_for_each_entry_safe(node, node1, &path->comp_list, head) { + list_del(&node->head); + gtrace_put_component(node->comp); + kfree(node); + } +} + +struct gtrace_path *gtrace_create_path(struct gtrace_component *source, + struct gtrace_component *sink, + enum gtrace_component_mode mode) +{ + struct build_path_walk_priv priv; + struct gtrace_path *path; + int ret = 0; + + if (!source || mode >= GTRACE_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 = GTRACE_INVALID_TRACE_ID; + + priv.path = path; + priv.sink = sink; + ret = gtrace_walk_output_components(source, &priv, build_path_walk_fn); + if (ret < 0) + goto err_release_path_nodes; + + if (!gtrace_path_ready(path)) { + ret = -EOPNOTSUPP; + goto err_release_path_nodes; + } + + ret = gtrace_assign_trace_id(path); + if (ret < 0) + goto err_release_path_nodes; + + return path; + +err_release_path_nodes: + gtrace_release_path_nodes(path); + kfree(path); +err_out: + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(gtrace_create_path); + +void gtrace_destroy_path(struct gtrace_path *path) +{ + gtrace_unassign_trace_id(path); + gtrace_release_path_nodes(path); + kfree(path); +} +EXPORT_SYMBOL_GPL(gtrace_destroy_path); + int __gtrace_register_driver(struct module *owner, struct gtrace_driver *gtdrv) { gtdrv->driver.owner = owner; diff --git a/include/linux/gtrace.h b/include/linux/gtrace.h index e8ca2bd46e67..b74d4b83b141 100644 --- a/include/linux/gtrace.h +++ b/include/linux/gtrace.h @@ -224,6 +224,10 @@ int gtrace_enable_component(struct gtrace_component *comp); int gtrace_disable_component(struct gtrace_component *comp); int gtrace_reset_component(struct gtrace_component *comp); +int gtrace_walk_output_components(struct gtrace_component *comp, void *priv, + int (*fn)(struct gtrace_component *comp, bool *stop, + struct gtrace_connection *stop_conn, + void *priv)); struct gtrace_component *gtrace_cpu_source(unsigned int cpu); struct gtrace_component *gtrace_register_component(struct gtrace_component_id *id, @@ -231,6 +235,26 @@ struct gtrace_component *gtrace_register_component(struct gtrace_component_id *i struct gtrace_platform_data *pdata); void gtrace_unregister_component(struct gtrace_component *comp); +/** + * struct gtrace_path - Representation of a trace path from source to sink. + * @comp_list: List of trace components in the path. + * @mode: Usage mode for trace components. + * @trace_id: ID of the trace source (typically hart/CPU id). + */ +struct gtrace_path { + struct list_head comp_list; + enum gtrace_component_mode mode; + u32 trace_id; +#define GTRACE_INVALID_TRACE_ID 0 +}; + +struct gtrace_component *gtrace_path_source(struct gtrace_path *path); +struct gtrace_component *gtrace_path_sink(struct gtrace_path *path); +struct gtrace_path *gtrace_create_path(struct gtrace_component *source, + struct gtrace_component *sink, + enum gtrace_component_mode mode); +void gtrace_destroy_path(struct gtrace_path *path); + /** * struct gtrace_driver - Representation of a trace driver. * @id_table: Table to match components handled by the driver. -- 2.43.0 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv