etm_event_build_path() silently skips error cases to support opening cpu=-1 events on all CPUs when a system might not have reachable sinks or ETMs for every CPU. In the next commit we want to reject the event if invalid sharing on any sink is detected, so propagate errors.
This means that things like failed memory allocations when building the path and invalid aux pause options now reject the event which is probably an improvement.
Keep the silent skips for things that make sense like missing ETMs and sinks.
Previously, _coresight_build_path() used -ENODEV both when no route to the sink existed and when coresight_grab_device() could not acquire a device or helper on a found route. Return -ENOENT exclusively for the unreachable case, and retain -ENODEV for device acquisition failures, such as a missing driver or failure to take a module reference.
Signed-off-by: James Clark james.clark@linaro.org --- drivers/hwtracing/coresight/coresight-core.c | 22 ++++++--- drivers/hwtracing/coresight/coresight-etm-perf.c | 61 +++++++++++++----------- 2 files changed, 47 insertions(+), 36 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index c05d657cde73..a635c51c25ac 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -980,6 +980,9 @@ int coresight_path_assign_trace_id(struct coresight_path *path, * From there the sink is added to the list along with all the devices that led * to that point - the end result is a list from source to sink. In that list * the source is the first device and the sink the last one. + * + * Return: 0 on success, -ENOENT if the sink is unreachable, or another error + * if path construction fails. */ static int _coresight_build_path(struct coresight_device *csdev, struct coresight_device *source, @@ -996,10 +999,10 @@ static int _coresight_build_path(struct coresight_device *csdev,
if (coresight_is_percpu_source(csdev) && coresight_is_percpu_sink(sink) && sink == per_cpu(csdev_sink, csdev->cpu)) { - if (_coresight_build_path(sink, source, sink, path) == 0) { - found = true; - goto out; - } + ret = _coresight_build_path(sink, source, sink, path); + if (ret) + return ret; + goto out; }
/* Not a sink - recursively explore each port found on this element */ @@ -1011,15 +1014,20 @@ static int _coresight_build_path(struct coresight_device *csdev, if (coresight_blocks_source(source, csdev->pdata->out_conns[i])) continue;
- if (child_dev && - _coresight_build_path(child_dev, source, sink, path) == 0) { + if (!child_dev) + continue; + + ret = _coresight_build_path(child_dev, source, sink, path); + if (!ret) { found = true; break; } + if (ret != -ENOENT) + return ret; }
if (!found) - return -ENODEV; + return -ENOENT;
out: /* diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index faec4c7bb83d..a9adf1cca7a8 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -334,32 +334,30 @@ static struct coresight_path *etm_event_get_ctxt_path(struct etm_ctxt *ctxt) return path; }
-static struct coresight_path * -etm_event_build_path(struct perf_event *event, int cpu, - struct coresight_device *user_sink, - struct coresight_device *match_sink) +static int etm_event_build_path(struct perf_event *event, int cpu, + struct coresight_device *user_sink, + struct coresight_device *match_sink, + struct coresight_path **path) { - struct coresight_path *path = NULL; struct coresight_device *source, *sink; - int ret; + int ret = 0;
+ *path = NULL; source = coresight_get_percpu_source_ref(cpu);
- /* - * If there is no ETM associated with this CPU or ever we try to trace - * on this CPU, we handle it accordingly. - */ + /* Silently skip CPUs without a loaded ETM. */ if (!source) - return NULL; + return 0;
/* * If AUX pause feature is enabled but the ETM driver does not - * support the operations, skip for this source. + * support the operations, reject the whole event. */ if (event->attr.aux_start_paused && (!source_ops(source)->pause_perf || !source_ops(source)->resume_perf)) { dev_err_once(&source->dev, "AUX pause is not supported.\n"); + ret = -EINVAL; goto out; }
@@ -380,30 +378,34 @@ etm_event_build_path(struct perf_event *event, int cpu, * trace on a CPU if the sink is not compatible. */
- /* Find the default sink for this ETM */ + /* Silently skip ETMs with no reachable sink loaded */ sink = coresight_find_default_sink(source); if (!sink) goto out;
- /* Check if this sink compatible with the last sink */ + /* Silently skip sinks incompatible with the last sink. */ if (match_sink && !sinks_compatible(match_sink, sink)) goto out; }
/* - * Building a path doesn't enable it, it simply builds a - * list of devices from source to sink that can be - * referenced later when the path is actually needed. + * Build path, but don't enable. Skip CPUs that cannot reach the sink. + * Reject the whole event on other path construction errors. */ - path = coresight_build_path(source, sink); - if (IS_ERR(path)) + *path = coresight_build_path(source, sink); + if (IS_ERR(*path)) { + ret = PTR_ERR(*path); + if (ret == -ENOENT) + ret = 0; + *path = NULL; goto out; + }
- /* ensure we can allocate a trace ID for this CPU */ - ret = coresight_path_assign_trace_id(path, CS_MODE_PERF); + /* Reject whole event if we can't allocate a trace ID for this CPU */ + ret = coresight_path_assign_trace_id(*path, CS_MODE_PERF); if (ret) { - coresight_release_path_locked(path); - path = NULL; + coresight_release_path_locked(*path); + *path = NULL; goto out; }
@@ -411,7 +413,7 @@ etm_event_build_path(struct perf_event *event, int cpu,
out: coresight_put_percpu_source_ref(source); - return IS_ERR_OR_NULL(path) ? NULL : path; + return ret; }
static void *etm_setup_aux(struct perf_event *event, void **pages, @@ -448,15 +450,16 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
/* * Setup the path for each CPU in a trace session. We try to build - * trace path for each CPU in the mask. If we don't find an ETM - * for the CPU or fail to build a path, we clear the CPU from the - * mask and continue with the rest. If ever we try to trace on those - * CPUs, we can handle it and fail the session. + * trace path for each CPU in the mask. Skip CPUs without an ETM, without + * a compatible default sink, or unable to reach the selected sink by + * clearing them from the mask. Other errors reject the whole event. */ for_each_cpu(cpu, mask) { struct coresight_path *path;
- path = etm_event_build_path(event, cpu, user_sink, sink); + if (etm_event_build_path(event, cpu, user_sink, sink, &path)) + goto err; + if (!path) { /* * Failed to create a path for the CPU, clear it from