Message ID | 20200526104642.9526-3-mike.leach@linaro.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Update CoreSight infrastructure to select a default sink. | expand |
On 05/26/2020 11:46 AM, Mike Leach wrote: > Adds a method to select a suitable sink connected to a given source. > > In cases where no sink is defined, the coresight_find_default_sink > routine can search from a given source, through the child connections > until a suitable sink is found. > > The suitability is defined in by the sink coresight_dev_subtype on the > CoreSight device, and the distance from the source by counting > connections. > > Higher value subtype is preferred - where these are equal, shorter > distance from source is used as a tie-break. > > This allows for default sink to be discovered were none is specified > (e.g. perf command line) > > Signed-off-by: Mike Leach <mike.leach@linaro.org> Feel free to add: Suggested-by: Suzuki K Poulose <suzuki.poulose@arm.com> > +/** > + * coresight_find_default_sink: Find a sink suitable for use as a > + * default sink. > + * > + * @csdev: starting source to find a connected sink. > + * > + * Walks connections graph looking for a suitable sink to enable for the > + * supplied source. Uses CoreSight device subtypes and distance from source > + * to select the best sink. > + * > + * If a sink is found, then the default sink for this device is set and > + * will be automatically used in future. > + * > + * Used in cases where the CoreSight user (perf / sysfs) has not selected a > + * sink. > + */ > +struct coresight_device * > +coresight_find_default_sink(struct coresight_device *csdev) > +{ > + int depth = 0; > + > + /* look for a default sink if we have not found for this device */ > + if (!csdev->def_sink) > + csdev->def_sink = coresight_find_sink(csdev, &depth); Could we add a helper to clear the cached "def-sink" from all the "sources", when the sink is going away ? You may be able to do this via coresight_remove_match() Rest looks good to me. Suzuki
Hi Suzuki, On Tue, 2 Jun 2020 at 11:20, Suzuki K Poulose <suzuki.poulose@arm.com> wrote: > > On 05/26/2020 11:46 AM, Mike Leach wrote: > > Adds a method to select a suitable sink connected to a given source. > > > > In cases where no sink is defined, the coresight_find_default_sink > > routine can search from a given source, through the child connections > > until a suitable sink is found. > > > > The suitability is defined in by the sink coresight_dev_subtype on the > > CoreSight device, and the distance from the source by counting > > connections. > > > > Higher value subtype is preferred - where these are equal, shorter > > distance from source is used as a tie-break. > > > > This allows for default sink to be discovered were none is specified > > (e.g. perf command line) > > > > Signed-off-by: Mike Leach <mike.leach@linaro.org> > > Feel free to add: > Suggested-by: Suzuki K Poulose <suzuki.poulose@arm.com> > Will do. > > +/** > > + * coresight_find_default_sink: Find a sink suitable for use as a > > + * default sink.Yes - the newer topologies will need some changes - beyond what we are handling here. However - especially for 1:1 - the best way may be to always use the default sink - as specifying multiple sinks on the perf command line may be problematical. > > + * > > + * @csdev: starting source to find a connected sink. > > + * > > + * Walks connections graph looking for a suitable sink to enable for the > > + * supplied source. Uses CoreSight device subtypes and distance from source > > + * to select the best sink. > > + * > > + * If a sink is found, then the default sink for this device is set and > > + * will be automatically used in future. > > + * > > + * Used in cases where the CoreSight user (perf / sysfs) has not selected a > > + * sink. > > + */ > > +struct coresight_device * > > +coresight_find_default_sink(struct coresight_device *csdev) > > +{ > > + int depth = 0; > > + > > + /* look for a default sink if we have not found for this device */ > > + if (!csdev->def_sink) > > + csdev->def_sink = coresight_find_sink(csdev, &depth); > > Could we add a helper to clear the cached "def-sink" from all the > "sources", when the sink is going away ? You may be able to do this via > coresight_remove_match() > Is this needed in the current state of the CoreSight driver infrastructure? The topology is fixed for the lifetime of the device so a sink cannot disappear without the rest of the CoreSight going away - i.e. reboot / shutdown. If there is concern about a race condition then something similar to coresight_remove_match can be developed, but the actual function only works on immediate connections / output ports. Thanks Mike > Rest looks good to me. > Suzuki > > -- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
On Tue, May 26, 2020 at 11:46:39AM +0100, Mike Leach wrote: > Adds a method to select a suitable sink connected to a given source. > > In cases where no sink is defined, the coresight_find_default_sink > routine can search from a given source, through the child connections > until a suitable sink is found. > > The suitability is defined in by the sink coresight_dev_subtype on the > CoreSight device, and the distance from the source by counting > connections. > > Higher value subtype is preferred - where these are equal, shorter > distance from source is used as a tie-break. > > This allows for default sink to be discovered were none is specified > (e.g. perf command line) > > Signed-off-by: Mike Leach <mike.leach@linaro.org> Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org> Leo has also added a RB for this patch, please add it on when you rebase on v5.8-rc1. > --- > drivers/hwtracing/coresight/coresight-priv.h | 2 + > drivers/hwtracing/coresight/coresight.c | 136 +++++++++++++++++++ > include/linux/coresight.h | 3 + > 3 files changed, 141 insertions(+) > > diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h > index 36c943ae94d5..f2dc625ea585 100644 > --- a/drivers/hwtracing/coresight/coresight-priv.h > +++ b/drivers/hwtracing/coresight/coresight-priv.h > @@ -150,6 +150,8 @@ int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data); > struct coresight_device *coresight_get_sink(struct list_head *path); > struct coresight_device *coresight_get_enabled_sink(bool reset); > struct coresight_device *coresight_get_sink_by_id(u32 id); > +struct coresight_device * > +coresight_find_default_sink(struct coresight_device *csdev); > struct list_head *coresight_build_path(struct coresight_device *csdev, > struct coresight_device *sink); > void coresight_release_path(struct list_head *path); > diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c > index f3efbb3b2b4d..7632d060e25d 100644 > --- a/drivers/hwtracing/coresight/coresight.c > +++ b/drivers/hwtracing/coresight/coresight.c > @@ -769,6 +769,142 @@ void coresight_release_path(struct list_head *path) > path = NULL; > } > > +/* return true if the device is a suitable type for a default sink */ > +static inline bool coresight_is_def_sink_type(struct coresight_device *csdev) > +{ > + /* sink & correct subtype */ > + if (((csdev->type == CORESIGHT_DEV_TYPE_SINK) || > + (csdev->type == CORESIGHT_DEV_TYPE_LINKSINK)) && > + (csdev->subtype.sink_subtype >= CORESIGHT_DEV_SUBTYPE_SINK_BUFFER)) > + return true; > + return false; > +} > + > +/** > + * coresight_select_best_sink - return the best sink for use as default from > + * the two provided. > + * > + * @sink: current best sink. > + * @depth: search depth where current sink was found. > + * @new_sink: new sink for comparison with current sink. > + * @new_depth: search depth where new sink was found. > + * > + * Sinks prioritised according to coresight_dev_subtype_sink, with only > + * subtypes CORESIGHT_DEV_SUBTYPE_SINK_BUFFER or higher being used. > + * > + * Where two sinks of equal priority are found, the sink closest to the > + * source is used (smallest search depth). > + * > + * return @new_sink & update @depth if better than @sink, else return @sink. > + */ > +static struct coresight_device * > +coresight_select_best_sink(struct coresight_device *sink, int *depth, > + struct coresight_device *new_sink, int new_depth) > +{ > + bool update = false; > + > + if (!sink) { > + /* first found at this level */ > + update = true; > + } else if (new_sink->subtype.sink_subtype > > + sink->subtype.sink_subtype) { > + /* found better sink */ > + update = true; > + } else if ((new_sink->subtype.sink_subtype == > + sink->subtype.sink_subtype) && > + (*depth > new_depth)) { > + /* found same but closer sink */ > + update = true; > + } > + > + if (update) > + *depth = new_depth; > + return update ? new_sink : sink; > +} > + > +/** > + * coresight_find_sink - recursive function to walk trace connections from > + * source to find a suitable default sink. > + * > + * @csdev: source / current device to check. > + * @depth: [in] search depth of calling dev, [out] depth of found sink. > + * > + * This will walk the connection path from a source (ETM) till a suitable > + * sink is encountered and return that sink to the original caller. > + * > + * If current device is a plain sink return that & depth, otherwise recursively > + * call child connections looking for a sink. Select best possible using > + * coresight_select_best_sink. > + * > + * return best sink found, or NULL if not found at this node or child nodes. > + */ > +static struct coresight_device * > +coresight_find_sink(struct coresight_device *csdev, int *depth) > +{ > + int i, curr_depth = *depth + 1, found_depth = 0; > + struct coresight_device *found_sink = NULL; > + > + if (coresight_is_def_sink_type(csdev)) { > + found_depth = curr_depth; > + found_sink = csdev; > + if (csdev->type == CORESIGHT_DEV_TYPE_SINK) > + goto return_def_sink; > + /* look past LINKSINK for something better */ > + } > + > + /* > + * Not a sink we want - or possible child sink may be better. > + * recursively explore each port found on this element. > + */ > + for (i = 0; i < csdev->pdata->nr_outport; i++) { > + struct coresight_device *child_dev, *sink = NULL; > + int child_depth = curr_depth; > + > + child_dev = csdev->pdata->conns[i].child_dev; > + if (child_dev) > + sink = coresight_find_sink(child_dev, &child_depth); > + > + if (sink) > + found_sink = coresight_select_best_sink(found_sink, > + &found_depth, > + sink, > + child_depth); > + } > + > +return_def_sink: > + /* return found sink and depth */ > + if (found_sink) > + *depth = found_depth; > + return found_sink; > +} > + > +/** > + * coresight_find_default_sink: Find a sink suitable for use as a > + * default sink. > + * > + * @csdev: starting source to find a connected sink. > + * > + * Walks connections graph looking for a suitable sink to enable for the > + * supplied source. Uses CoreSight device subtypes and distance from source > + * to select the best sink. > + * > + * If a sink is found, then the default sink for this device is set and > + * will be automatically used in future. > + * > + * Used in cases where the CoreSight user (perf / sysfs) has not selected a > + * sink. > + */ > +struct coresight_device * > +coresight_find_default_sink(struct coresight_device *csdev) > +{ > + int depth = 0; > + > + /* look for a default sink if we have not found for this device */ > + if (!csdev->def_sink) > + csdev->def_sink = coresight_find_sink(csdev, &depth); > + return csdev->def_sink; > +} > + > /** coresight_validate_source - make sure a source has the right credentials > * @csdev: the device structure for a source. > * @function: the function this was called from. > diff --git a/include/linux/coresight.h b/include/linux/coresight.h > index 84dc695e87d4..58fffdecdbfd 100644 > --- a/include/linux/coresight.h > +++ b/include/linux/coresight.h > @@ -48,6 +48,7 @@ enum coresight_dev_subtype_sink { > CORESIGHT_DEV_SUBTYPE_SINK_NONE, > CORESIGHT_DEV_SUBTYPE_SINK_PORT, > CORESIGHT_DEV_SUBTYPE_SINK_BUFFER, > + CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM, > }; > > enum coresight_dev_subtype_link { > @@ -182,6 +183,7 @@ struct coresight_sysfs_link { > * happens when a source has been selected and a path is enabled > * from source to that sink. > * @ea: Device attribute for sink representation under PMU directory. > + * @def_sink: cached reference to default sink found for this device. > * @ect_dev: Associated cross trigger device. Not part of the trace data > * path or connections. > * @nr_links: number of sysfs links created to other components from this > @@ -200,6 +202,7 @@ struct coresight_device { > /* sink specific fields */ > bool activated; /* true only if a sink is part of a path */ > struct dev_ext_attribute *ea; > + struct coresight_device *def_sink; > /* cross trigger handling */ > struct coresight_device *ect_dev; > /* sysfs links between components */ > -- > 2.17.1 >
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 36c943ae94d5..f2dc625ea585 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -150,6 +150,8 @@ int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data); struct coresight_device *coresight_get_sink(struct list_head *path); struct coresight_device *coresight_get_enabled_sink(bool reset); struct coresight_device *coresight_get_sink_by_id(u32 id); +struct coresight_device * +coresight_find_default_sink(struct coresight_device *csdev); struct list_head *coresight_build_path(struct coresight_device *csdev, struct coresight_device *sink); void coresight_release_path(struct list_head *path); diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index f3efbb3b2b4d..7632d060e25d 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -769,6 +769,142 @@ void coresight_release_path(struct list_head *path) path = NULL; } +/* return true if the device is a suitable type for a default sink */ +static inline bool coresight_is_def_sink_type(struct coresight_device *csdev) +{ + /* sink & correct subtype */ + if (((csdev->type == CORESIGHT_DEV_TYPE_SINK) || + (csdev->type == CORESIGHT_DEV_TYPE_LINKSINK)) && + (csdev->subtype.sink_subtype >= CORESIGHT_DEV_SUBTYPE_SINK_BUFFER)) + return true; + return false; +} + +/** + * coresight_select_best_sink - return the best sink for use as default from + * the two provided. + * + * @sink: current best sink. + * @depth: search depth where current sink was found. + * @new_sink: new sink for comparison with current sink. + * @new_depth: search depth where new sink was found. + * + * Sinks prioritised according to coresight_dev_subtype_sink, with only + * subtypes CORESIGHT_DEV_SUBTYPE_SINK_BUFFER or higher being used. + * + * Where two sinks of equal priority are found, the sink closest to the + * source is used (smallest search depth). + * + * return @new_sink & update @depth if better than @sink, else return @sink. + */ +static struct coresight_device * +coresight_select_best_sink(struct coresight_device *sink, int *depth, + struct coresight_device *new_sink, int new_depth) +{ + bool update = false; + + if (!sink) { + /* first found at this level */ + update = true; + } else if (new_sink->subtype.sink_subtype > + sink->subtype.sink_subtype) { + /* found better sink */ + update = true; + } else if ((new_sink->subtype.sink_subtype == + sink->subtype.sink_subtype) && + (*depth > new_depth)) { + /* found same but closer sink */ + update = true; + } + + if (update) + *depth = new_depth; + return update ? new_sink : sink; +} + +/** + * coresight_find_sink - recursive function to walk trace connections from + * source to find a suitable default sink. + * + * @csdev: source / current device to check. + * @depth: [in] search depth of calling dev, [out] depth of found sink. + * + * This will walk the connection path from a source (ETM) till a suitable + * sink is encountered and return that sink to the original caller. + * + * If current device is a plain sink return that & depth, otherwise recursively + * call child connections looking for a sink. Select best possible using + * coresight_select_best_sink. + * + * return best sink found, or NULL if not found at this node or child nodes. + */ +static struct coresight_device * +coresight_find_sink(struct coresight_device *csdev, int *depth) +{ + int i, curr_depth = *depth + 1, found_depth = 0; + struct coresight_device *found_sink = NULL; + + if (coresight_is_def_sink_type(csdev)) { + found_depth = curr_depth; + found_sink = csdev; + if (csdev->type == CORESIGHT_DEV_TYPE_SINK) + goto return_def_sink; + /* look past LINKSINK for something better */ + } + + /* + * Not a sink we want - or possible child sink may be better. + * recursively explore each port found on this element. + */ + for (i = 0; i < csdev->pdata->nr_outport; i++) { + struct coresight_device *child_dev, *sink = NULL; + int child_depth = curr_depth; + + child_dev = csdev->pdata->conns[i].child_dev; + if (child_dev) + sink = coresight_find_sink(child_dev, &child_depth); + + if (sink) + found_sink = coresight_select_best_sink(found_sink, + &found_depth, + sink, + child_depth); + } + +return_def_sink: + /* return found sink and depth */ + if (found_sink) + *depth = found_depth; + return found_sink; +} + +/** + * coresight_find_default_sink: Find a sink suitable for use as a + * default sink. + * + * @csdev: starting source to find a connected sink. + * + * Walks connections graph looking for a suitable sink to enable for the + * supplied source. Uses CoreSight device subtypes and distance from source + * to select the best sink. + * + * If a sink is found, then the default sink for this device is set and + * will be automatically used in future. + * + * Used in cases where the CoreSight user (perf / sysfs) has not selected a + * sink. + */ +struct coresight_device * +coresight_find_default_sink(struct coresight_device *csdev) +{ + int depth = 0; + + /* look for a default sink if we have not found for this device */ + if (!csdev->def_sink) + csdev->def_sink = coresight_find_sink(csdev, &depth); + return csdev->def_sink; +} + /** coresight_validate_source - make sure a source has the right credentials * @csdev: the device structure for a source. * @function: the function this was called from. diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 84dc695e87d4..58fffdecdbfd 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -48,6 +48,7 @@ enum coresight_dev_subtype_sink { CORESIGHT_DEV_SUBTYPE_SINK_NONE, CORESIGHT_DEV_SUBTYPE_SINK_PORT, CORESIGHT_DEV_SUBTYPE_SINK_BUFFER, + CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM, }; enum coresight_dev_subtype_link { @@ -182,6 +183,7 @@ struct coresight_sysfs_link { * happens when a source has been selected and a path is enabled * from source to that sink. * @ea: Device attribute for sink representation under PMU directory. + * @def_sink: cached reference to default sink found for this device. * @ect_dev: Associated cross trigger device. Not part of the trace data * path or connections. * @nr_links: number of sysfs links created to other components from this @@ -200,6 +202,7 @@ struct coresight_device { /* sink specific fields */ bool activated; /* true only if a sink is part of a path */ struct dev_ext_attribute *ea; + struct coresight_device *def_sink; /* cross trigger handling */ struct coresight_device *ect_dev; /* sysfs links between components */
Adds a method to select a suitable sink connected to a given source. In cases where no sink is defined, the coresight_find_default_sink routine can search from a given source, through the child connections until a suitable sink is found. The suitability is defined in by the sink coresight_dev_subtype on the CoreSight device, and the distance from the source by counting connections. Higher value subtype is preferred - where these are equal, shorter distance from source is used as a tie-break. This allows for default sink to be discovered were none is specified (e.g. perf command line) Signed-off-by: Mike Leach <mike.leach@linaro.org> --- drivers/hwtracing/coresight/coresight-priv.h | 2 + drivers/hwtracing/coresight/coresight.c | 136 +++++++++++++++++++ include/linux/coresight.h | 3 + 3 files changed, 141 insertions(+)