Skip to content

Commit 809a241

Browse files
coresight: etm-perf: incorporating sink definition from the cmd line
Now that PMU specific configuration is available as part of the event, lookup the sink identified by users from the perf command line and build a path from source to sink. With this functionality it is no longer required to select a sink in a separate step (from sysFS) before a perf trace session can be started. Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
1 parent 376daf0 commit 809a241

1 file changed

Lines changed: 118 additions & 1 deletion

File tree

drivers/hwtracing/coresight/coresight-etm-perf.c

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/list.h>
2323
#include <linux/mm.h>
2424
#include <linux/init.h>
25+
#include <linux/parser.h>
2526
#include <linux/perf_event.h>
2627
#include <linux/slab.h>
2728
#include <linux/types.h>
@@ -46,6 +47,17 @@ struct etm_event_data {
4647
struct list_head **path;
4748
};
4849

50+
/**
51+
* struct perf_pmu_drv_config - Driver specific configuration needed
52+
* before a session can start.
53+
* @sink: The name of the sink this session should use.
54+
* @entry: Hook to the event->drv_configs list.
55+
*/
56+
struct perf_pmu_drv_config {
57+
char *sink;
58+
struct list_head entry;
59+
};
60+
4961
static DEFINE_PER_CPU(struct perf_output_handle, ctx_handle);
5062
static DEFINE_PER_CPU(struct coresight_device *, csdev_src);
5163

@@ -159,9 +171,22 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
159171
int nr_pages, bool overwrite)
160172
{
161173
int cpu;
174+
char *sink_def = NULL;
162175
cpumask_t *mask;
163176
struct coresight_device *sink;
164177
struct etm_event_data *event_data = NULL;
178+
struct perf_pmu_drv_config *drv_config;
179+
180+
/*
181+
* Search the driver configurables looking for a sink. If more than
182+
* one sink was specified the last one is taken.
183+
*/
184+
list_for_each_entry(drv_config, &event->drv_configs, entry) {
185+
if (drv_config && drv_config->sink) {
186+
sink_def = drv_config->sink;
187+
break;
188+
}
189+
}
165190

166191
event_data = alloc_event_data(event->cpu);
167192
if (!event_data)
@@ -184,7 +209,7 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
184209
* list of devices from source to sink that can be
185210
* referenced later when the path is actually needed.
186211
*/
187-
event_data->path[cpu] = coresight_build_path(csdev, NULL);
212+
event_data->path[cpu] = coresight_build_path(csdev, sink_def);
188213
if (!event_data->path[cpu])
189214
goto err;
190215
}
@@ -342,6 +367,95 @@ static void etm_event_del(struct perf_event *event, int mode)
342367
etm_event_stop(event, PERF_EF_UPDATE);
343368
}
344369

370+
enum {
371+
ETM_TOKEN_SINK_CPU,
372+
ETM_TOKEN_SINK,
373+
ETM_TOKEN_ERR,
374+
};
375+
376+
static const match_table_t drv_cfg_tokens = {
377+
{ETM_TOKEN_SINK_CPU, "sink=cpu%d:%s"},
378+
{ETM_TOKEN_SINK, "sink=%s"},
379+
{ETM_TOKEN_ERR, NULL},
380+
};
381+
382+
static int etm_get_drv_configs(struct perf_event *event, void __user *arg)
383+
{
384+
char *config, *sink = NULL;
385+
int cpu = -1, token, ret = 0;
386+
substring_t args[MAX_OPT_ARGS];
387+
struct perf_pmu_drv_config *drv_config = NULL;
388+
389+
/* Make user supplied input usable */
390+
config = strndup_user(arg, PAGE_SIZE);
391+
if (IS_ERR(config))
392+
return PTR_ERR(config);
393+
394+
/* See above declared @drv_cfg_tokens for the usable formats */
395+
token = match_token(config, drv_cfg_tokens, args);
396+
switch (token) {
397+
case ETM_TOKEN_SINK:
398+
/* Just a sink has been specified */
399+
sink = match_strdup(&args[0]);
400+
if (IS_ERR(sink)) {
401+
ret = PTR_ERR(sink);
402+
goto err;
403+
}
404+
break;
405+
case ETM_TOKEN_SINK_CPU:
406+
/* We have a sink and a CPU */
407+
if (match_int(&args[0], &cpu)) {
408+
ret = -EINVAL;
409+
goto err;
410+
}
411+
sink = match_strdup(&args[1]);
412+
if (IS_ERR(sink)) {
413+
ret = PTR_ERR(sink);
414+
goto err;
415+
}
416+
break;
417+
default:
418+
ret = -EINVAL;
419+
goto err;
420+
}
421+
422+
/* If the CPUs don't match the sink is destined to another path */
423+
if (event->cpu != cpu)
424+
goto err;
425+
426+
/*
427+
* We have a valid configuration, allocate memory and add to the list
428+
* of driver configurables.
429+
*/
430+
drv_config = kzalloc(sizeof(*drv_config), GFP_KERNEL);
431+
if (IS_ERR(drv_config)) {
432+
ret = PTR_ERR(drv_config);
433+
goto err;
434+
}
435+
436+
drv_config->sink = sink;
437+
list_add(&drv_config->entry, &event->drv_configs);
438+
439+
out:
440+
kfree(config);
441+
return ret;
442+
443+
err:
444+
kfree(sink);
445+
goto out;
446+
}
447+
448+
static void etm_free_drv_configs(struct perf_event *event)
449+
{
450+
struct perf_pmu_drv_config *config, *itr;
451+
452+
list_for_each_entry_safe(config, itr, &event->drv_configs, entry) {
453+
list_del(&config->entry);
454+
kfree(config->sink);
455+
kfree(config);
456+
}
457+
}
458+
345459
int etm_perf_symlink(struct coresight_device *csdev, bool link)
346460
{
347461
char entry[sizeof("cpu9999999")];
@@ -383,6 +497,9 @@ static int __init etm_perf_init(void)
383497
etm_pmu.stop = etm_event_stop;
384498
etm_pmu.add = etm_event_add;
385499
etm_pmu.del = etm_event_del;
500+
etm_pmu.get_drv_configs = etm_get_drv_configs;
501+
etm_pmu.free_drv_configs
502+
= etm_free_drv_configs;
386503

387504
ret = perf_pmu_register(&etm_pmu, CORESIGHT_ETM_PMU_NAME, -1);
388505
if (ret == 0)

0 commit comments

Comments
 (0)