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+
4961static DEFINE_PER_CPU (struct perf_output_handle , ctx_handle ) ;
5062static 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+
345459int 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