Add start_port() and stop_port() callbacks to gtrace_driver so multi-port link components like funnel and replicator can enable a specific input/output port the first time a path uses it, tracked by the per-connection src_refcnt/dest_refcnt fields.
Signed-off-by: Zane Leung liangzhen@linux.spacemit.com --- drivers/hwtracing/gtrace/gtrace-core.c | 66 ++++++++++++++++++++------ include/linux/gtrace.h | 12 +++++ 2 files changed, 64 insertions(+), 14 deletions(-)
diff --git a/drivers/hwtracing/gtrace/gtrace-core.c b/drivers/hwtracing/gtrace/gtrace-core.c index 3f55d8b7302d..231d06218d8e 100644 --- a/drivers/hwtracing/gtrace/gtrace-core.c +++ b/drivers/hwtracing/gtrace/gtrace-core.c @@ -654,7 +654,9 @@ static void gtrace_release_path_nodes(struct gtrace_path *path) }
static int __gtrace_comp_start(struct gtrace_component *comp, - struct gtrace_path *path) + struct gtrace_path *path, + struct gtrace_connection *inconn, + struct gtrace_connection *outconn) { struct gtrace_comp_priv *cpriv = to_gtrace_comp_priv(comp); const struct gtrace_driver *gtdrv = to_gtrace_driver(comp->dev.driver); @@ -690,6 +692,12 @@ static int __gtrace_comp_start(struct gtrace_component *comp, cpriv->owner = task_pid_nr(path->event->owner); }
+ if (gtdrv->start_port) { + ret = gtdrv->start_port(comp, inconn, outconn); + if (ret) + goto out; + } + cpriv->start_count++; out: raw_spin_unlock_irqrestore(&cpriv->lock, flags); @@ -697,7 +705,9 @@ static int __gtrace_comp_start(struct gtrace_component *comp, }
static int __gtrace_comp_stop(struct gtrace_component *comp, - struct gtrace_path *path) + struct gtrace_path *path, + struct gtrace_connection *inconn, + struct gtrace_connection *outconn) { struct gtrace_comp_priv *cpriv = to_gtrace_comp_priv(comp); const struct gtrace_driver *gtdrv = to_gtrace_driver(comp->dev.driver); @@ -715,13 +725,16 @@ static int __gtrace_comp_stop(struct gtrace_component *comp, goto out; }
+ if (!gtdrv) { + ret = -ENODEV; + goto out; + } + + if (gtdrv->stop_port) + gtdrv->stop_port(comp, inconn, outconn); + cpriv->start_count--; if (!cpriv->start_count) { - if (!gtdrv) { - ret = -ENODEV; - goto out; - } - if (gtdrv->stop) ret = gtdrv->stop(comp); comp->path = NULL; @@ -734,19 +747,36 @@ static int __gtrace_comp_stop(struct gtrace_component *comp,
int gtrace_path_start(struct gtrace_path *path) { - struct gtrace_path_node *node; + struct gtrace_path_node *node, *prev; + struct gtrace_connection *inconn; int ret = 0;
list_for_each_entry_reverse(node, &path->comp_list, head) { - ret = __gtrace_comp_start(node->comp, path); + if (node->comp == gtrace_path_source(path)) { + inconn = NULL; + } else { + prev = list_prev_entry(node, head); + inconn = prev->conn; + } + + ret = __gtrace_comp_start(node->comp, path, inconn, node->conn); if (ret) break; }
/* If a component failed to start, stop all the components that were started before it */ - if (ret) - list_for_each_entry_continue(node, &path->comp_list, head) - __gtrace_comp_stop(node->comp, path); + if (ret) { + list_for_each_entry_continue(node, &path->comp_list, head) { + if (node->comp == gtrace_path_source(path)) { + inconn = NULL; + } else { + prev = list_prev_entry(node, head); + inconn = prev->conn; + } + + __gtrace_comp_stop(node->comp, path, inconn, node->conn); + } + }
return ret; } @@ -754,11 +784,19 @@ EXPORT_SYMBOL_GPL(gtrace_path_start);
int gtrace_path_stop(struct gtrace_path *path) { - struct gtrace_path_node *node; + struct gtrace_path_node *node, *prev; + struct gtrace_connection *inconn; int ret = 0, err;
list_for_each_entry(node, &path->comp_list, head) { - err = __gtrace_comp_stop(node->comp, path); + if (node->comp == gtrace_path_source(path)) { + inconn = NULL; + } else { + prev = list_prev_entry(node, head); + inconn = prev->conn; + } + + err = __gtrace_comp_stop(node->comp, path, inconn, node->conn); if (err && !ret) ret = err; } diff --git a/include/linux/gtrace.h b/include/linux/gtrace.h index 4bbe5ac835ec..ee60585ef65c 100644 --- a/include/linux/gtrace.h +++ b/include/linux/gtrace.h @@ -55,9 +55,11 @@ enum gtrace_format { * @src_port: A connection's source port number. * @src_fwnode: Source component's fwnode handle. * @src_comp: Source component's pointer. + * @src_refcnt: Number of paths currently using this connection's source port. * @dest_port: A connection's destination port number. * @dest_fwnode: Destination component's fwnode handle. * @dest_comp: Destination component's pointer. + * @dest_refcnt: Number of paths currently routing data into the destination port. */ struct gtrace_connection { int src_port; @@ -66,6 +68,8 @@ struct gtrace_connection { struct fwnode_handle *dest_fwnode; struct gtrace_component *src_comp; struct gtrace_component *dest_comp; + u32 src_refcnt; + u32 dest_refcnt; };
struct gtrace_platform_data; @@ -363,6 +367,8 @@ int gtrace_path_copyto_auxbuf(struct gtrace_path *path, * via @format (see PERF_AUX_FLAG_PMU_FORMAT_TYPE_MASK). * @start: Callback to start tracing. * @stop: Callback to stop tracing. + * @start_port: Callback to start a specific component port. + * @stop_port: Callback to stop a specific component port. * @probe: Driver probe() function. * @remove: Driver remove() function. * @get_trace_id: Get/allocate a trace ID. @@ -376,6 +382,12 @@ struct gtrace_driver { u64 *format); int (*start)(struct gtrace_component *comp); int (*stop)(struct gtrace_component *comp); + int (*start_port)(struct gtrace_component *comp, + struct gtrace_connection *inconn, + struct gtrace_connection *outconn); + void (*stop_port)(struct gtrace_component *comp, + struct gtrace_connection *inconn, + struct gtrace_connection *outconn); int (*probe)(struct gtrace_component *comp); void (*remove)(struct gtrace_component *comp); int (*get_trace_id)(struct gtrace_component *comp,