From: Leo Yan Date: Fri, 15 May 2026 20:08:23 +0000 (+0100) Subject: coresight: Control path with range X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=3d3289c0d850b186e07351b77e89e0ee755d1f62;p=thirdparty%2Fkernel%2Flinux.git coresight: Control path with range 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 Reviewed-by: Yeoreum Yun Reviewed-by: James Clark Tested-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260515-arm_coresight_path_power_management_improvement-v14-16-f88c4a3ecfe9@arm.com --- diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index d65cdce1dfef..62a12a909889 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 @@ err: 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 @@ out: 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;