@@ -619,6 +619,26 @@ static FILE *cs_device__open_file(const char *name)
}
+static int cs_etm_check_drv_config_term(const char *name)
+{
+ struct stat st;
+ char path[PATH_MAX];
+ const char *sysfs;
+
+ /* CS devices are all found under sysFS */
+ sysfs = sysfs__mountpoint();
+ if (!sysfs)
+ return -EINVAL;
+
+ snprintf(path, PATH_MAX,
+ "%s" CS_BUS_DEVICE_PATH "%s", sysfs, name);
+
+ if (stat(path, &st) < 0)
+ return -EINVAL;
+
+ return 0;
+}
+
static int __printf(2, 3) cs_device__print_file(const char *name, const char *fmt, ...)
{
va_list args;
@@ -635,7 +655,7 @@ static int __printf(2, 3) cs_device__print_file(const char *name, const char *fm
return ret;
}
-static int cs_etm_set_drv_config_term(struct perf_evsel_config_term *term)
+static int cs_etm_set_drv_config_term_sysfs(struct perf_evsel_config_term *term)
{
int ret;
char enable_sink[ENABLE_SINK_MAX];
@@ -650,6 +670,21 @@ static int cs_etm_set_drv_config_term(struct perf_evsel_config_term *term)
return 0;
}
+static int cs_etm_set_drv_config_term_ioctl(struct perf_evsel *evsel,
+ struct perf_evsel_config_term *term)
+{
+ int ret;
+ const char *drv_cfg = term->val.drv_cfg;
+
+ /* First check the input */
+ ret = cs_etm_check_drv_config_term(drv_cfg);
+ if (ret)
+ return ret;
+
+ /* All good, apply configuration */
+ return perf_evsel__apply_drv_config(evsel, drv_cfg);
+}
+
int cs_etm_set_drv_config(struct perf_evsel *evsel,
struct perf_evsel_config_term **err_term)
{
@@ -660,7 +695,17 @@ int cs_etm_set_drv_config(struct perf_evsel *evsel,
if (term->type != PERF_EVSEL__CONFIG_TERM_DRV_CFG)
continue;
- err = cs_etm_set_drv_config_term(term);
+ /* First try the new interface, i.e ioctl() */
+ err = cs_etm_set_drv_config_term_ioctl(evsel, term);
+ if (!err)
+ continue;
+
+ /*
+ * Something went wrong, we are probably working with an older
+ * kernel. As such use the sysFS interface, which will only
+ * work for per-thread scenarios.
+ */
+ err = cs_etm_set_drv_config_term_sysfs(term);
if (err) {
*err_term = term;
break;
@@ -1195,6 +1195,13 @@ static int perf_evsel__append_filter(struct perf_evsel *evsel,
return -1;
}
+int perf_evsel__apply_drv_config(struct perf_evsel *evsel, const char *config)
+{
+ return perf_evsel__run_ioctl(evsel,
+ PERF_EVENT_IOC_SET_DRV_CONFIG,
+ (void *)config);
+}
+
int perf_evsel__append_tp_filter(struct perf_evsel *evsel, const char *filter)
{
return perf_evsel__append_filter(evsel, "(%s) && (%s)", filter);
@@ -276,6 +276,7 @@ int perf_evsel__append_tp_filter(struct perf_evsel *evsel, const char *filter);
int perf_evsel__append_addr_filter(struct perf_evsel *evsel,
const char *filter);
int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter);
+int perf_evsel__apply_drv_config(struct perf_evsel *evsel, const char *config);
int perf_evsel__enable(struct perf_evsel *evsel);
int perf_evsel__disable(struct perf_evsel *evsel);
The communication of sink information for a trace session doesn't work when more than one CPU is involved in the scenario due to the static nature of sysFS. As such communicate the sink information to each event by using the driver's sink configuration information and an ioctl command. Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org> --- tools/perf/arch/arm/util/cs-etm.c | 49 +++++++++++++++++++++++++++++++++++++-- tools/perf/util/evsel.c | 7 ++++++ tools/perf/util/evsel.h | 1 + 3 files changed, 55 insertions(+), 2 deletions(-)