CPU PM notifiers need to control only part of a path instead of always operating on the full path.
Add internal enable and disable helpers that take an inclusive node range [from, to], validate that the requested nodes are ordered before using them.
Update the existed coresight_{enable|disable}_path() interfaces as full-path wrappers by passing the first and last path nodes. The helpers coresight_path_{first|last}_node() are provided for conveniently fetching the first and last nodes on the path.
In coresight_enable_path_from_to(), if a failure occurs at the last node in the range, no device is actually enabled in this case, bail out directly.
Tested-by: Jie Gan jie.gan@oss.qualcomm.com Reviewed-by: Yeoreum Yun yeoreum.yun@arm.com Reviewed-by: James Clark james.clark@linaro.org Tested-by: James Clark james.clark@linaro.org Signed-off-by: Leo Yan leo.yan@arm.com --- drivers/hwtracing/coresight/coresight-core.c | 95 ++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 14 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 856036ad838b3508bf39a2ef40e68673925bca5b..0c82869b21cb734ab3ae96123c53c78071281cd6 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -62,6 +62,24 @@ static LIST_HEAD(coresight_dev_idx_list);
static const struct cti_assoc_op *cti_assoc_ops;
+static struct coresight_node * +coresight_path_first_node(struct coresight_path *path) +{ + if (list_empty(&path->path_list)) + return NULL; + + return list_first_entry(&path->path_list, struct coresight_node, link); +} + +static struct coresight_node * +coresight_path_last_node(struct coresight_path *path) +{ + if (list_empty(&path->path_list)) + return NULL; + + return list_last_entry(&path->path_list, struct coresight_node, link); +} + void coresight_set_cti_ops(const struct cti_assoc_op *cti_op) { cti_assoc_ops = cti_op; @@ -488,19 +506,41 @@ int coresight_resume_source(struct coresight_device *csdev) EXPORT_SYMBOL_GPL(coresight_resume_source);
/* - * coresight_disable_path_from : Disable components in the given path starting - * from @nd in the list. If @nd is NULL, all the components, except the SOURCE - * are disabled. + * Callers must fetch nodes from the path and pass @from and @to to the path + * enable/disable functions. Walk the path from @from to locate @to. If @to + * is found, it indicates @from and @to are in order. Otherwise, they are out + * of order. */ -static void coresight_disable_path_from(struct coresight_path *path, - struct coresight_node *nd) +static bool coresight_path_nodes_in_order(struct coresight_path *path, + struct coresight_node *from, + struct coresight_node *to) +{ + struct coresight_node *nd; + + if (WARN_ON_ONCE(!from || !to)) + return false; + + nd = from; + list_for_each_entry_from(nd, &path->path_list, link) { + if (nd == to) + return true; + } + + return false; +} + +static void coresight_disable_path_from_to(struct coresight_path *path, + struct coresight_node *from, + struct coresight_node *to) { u32 type; struct coresight_device *csdev, *parent, *child; + struct coresight_node *nd;
- if (!nd) - nd = list_first_entry(&path->path_list, struct coresight_node, link); + if (!coresight_path_nodes_in_order(path, from, to)) + return;
+ nd = from; list_for_each_entry_from(nd, &path->path_list, link) { csdev = nd->csdev; type = csdev->type; @@ -534,12 +574,18 @@ static void coresight_disable_path_from(struct coresight_path *path,
/* Disable all helpers adjacent along the path last */ coresight_disable_helpers(csdev, path); + + /* Iterate up to and including @to */ + if (nd == to) + break; } }
void coresight_disable_path(struct coresight_path *path) { - coresight_disable_path_from(path, NULL); + coresight_disable_path_from_to(path, + coresight_path_first_node(path), + coresight_path_last_node(path)); } EXPORT_SYMBOL_GPL(coresight_disable_path);
@@ -572,16 +618,21 @@ static int coresight_enable_helpers(struct coresight_device *csdev, return ret; }
-int coresight_enable_path(struct coresight_path *path, enum cs_mode mode) +static int coresight_enable_path_from_to(struct coresight_path *path, + enum cs_mode mode, + struct coresight_node *from, + struct coresight_node *to) { int ret = 0; u32 type; struct coresight_node *nd; struct coresight_device *csdev, *parent, *child; - struct coresight_device *source;
- source = coresight_get_source(path); - list_for_each_entry_reverse(nd, &path->path_list, link) { + if (!coresight_path_nodes_in_order(path, from, to)) + return -EINVAL; + + nd = to; + list_for_each_entry_from_reverse(nd, &path->path_list, link) { csdev = nd->csdev; type = csdev->type;
@@ -620,7 +671,8 @@ int coresight_enable_path(struct coresight_path *path, enum cs_mode mode) case CORESIGHT_DEV_TYPE_LINK: parent = list_prev_entry(nd, link)->csdev; child = list_next_entry(nd, link)->csdev; - ret = coresight_enable_link(csdev, parent, child, source); + ret = coresight_enable_link(csdev, parent, child, + coresight_get_source(path)); if (ret) goto err_disable_helpers; break; @@ -628,6 +680,10 @@ int coresight_enable_path(struct coresight_path *path, enum cs_mode mode) ret = -EINVAL; goto err_disable_helpers; } + + /* Iterate down to and including @from */ + if (nd == from) + break; }
out: @@ -635,12 +691,23 @@ int coresight_enable_path(struct coresight_path *path, enum cs_mode mode) err_disable_helpers: coresight_disable_helpers(csdev, path); err_disable_path: + /* No device is actually enabled */ + if (nd == to) + goto out; + /* Fetch the previous node, the last successfully enabled one */ nd = list_next_entry(nd, link); - coresight_disable_path_from(path, nd); + coresight_disable_path_from_to(path, nd, to); goto out; }
+int coresight_enable_path(struct coresight_path *path, enum cs_mode mode) +{ + return coresight_enable_path_from_to(path, mode, + coresight_path_first_node(path), + coresight_path_last_node(path)); +} + struct coresight_device *coresight_get_sink(struct coresight_path *path) { struct coresight_device *csdev;