3131#include <linux/amba/bus.h>
3232#include <linux/seq_file.h>
3333#include <linux/uaccess.h>
34+ #include <linux/perf_event.h>
3435#include <linux/pm_runtime.h>
3536#include <linux/perf_event.h>
3637#include <asm/sections.h>
3738#include <asm/local.h>
3839
3940#include "coresight-etm4x.h"
41+ #include "coresight-etm-perf.h"
4042
4143static int boot_enable ;
4244module_param_named (boot_enable , boot_enable , int , S_IRUGO );
4345
4446/* The number of ETMv4 currently registered */
4547static int etm4_count ;
4648static struct etmv4_drvdata * etmdrvdata [NR_CPUS ];
49+ static void etm4_set_default (struct etmv4_config * config );
4750
4851static void etm4_os_unlock (struct etmv4_drvdata * drvdata )
4952{
@@ -189,6 +192,58 @@ static void etm4_enable_hw(void *info)
189192 dev_dbg (drvdata -> dev , "cpu: %d enable smp call done\n" , drvdata -> cpu );
190193}
191194
195+ static int etm4_parse_event_config (struct etmv4_drvdata * drvdata ,
196+ struct perf_event_attr * attr )
197+ {
198+ struct etmv4_config * config = & drvdata -> config ;
199+
200+ if (!attr )
201+ return - EINVAL ;
202+
203+ /* Clear configuration from previous run */
204+ memset (config , 0 , sizeof (struct etmv4_config ));
205+
206+ if (attr -> exclude_kernel )
207+ config -> mode = ETM_MODE_EXCL_KERN ;
208+
209+ if (attr -> exclude_user )
210+ config -> mode = ETM_MODE_EXCL_USER ;
211+
212+ /* Always start from the default config */
213+ etm4_set_default (config );
214+
215+ /*
216+ * By default the tracers are configured to trace the whole address
217+ * range. Narrow the field only if requested by user space.
218+ */
219+ if (config -> mode )
220+ etm4_config_trace_mode (config );
221+
222+ /* Go from generic option to ETMv4 specifics */
223+ if (attr -> config & BIT (ETM_OPT_CYCACC ))
224+ config -> cfg |= ETMv4_MODE_CYCACC ;
225+ if (attr -> config & BIT (ETM_OPT_TS ))
226+ config -> cfg |= ETMv4_MODE_TIMESTAMP ;
227+
228+ return 0 ;
229+ }
230+
231+ static int etm4_enable_perf (struct coresight_device * csdev ,
232+ struct perf_event_attr * attr )
233+ {
234+ struct etmv4_drvdata * drvdata = dev_get_drvdata (csdev -> dev .parent );
235+
236+ if (WARN_ON_ONCE (drvdata -> cpu != smp_processor_id ()))
237+ return - EINVAL ;
238+
239+ /* Configure the tracer based on the session's specifics */
240+ etm4_parse_event_config (drvdata , attr );
241+ /* And enable it */
242+ etm4_enable_hw (drvdata );
243+
244+ return 0 ;
245+ }
246+
192247static int etm4_enable_sysfs (struct coresight_device * csdev )
193248{
194249 struct etmv4_drvdata * drvdata = dev_get_drvdata (csdev -> dev .parent );
@@ -233,6 +288,9 @@ static int etm4_enable(struct coresight_device *csdev,
233288 case CS_MODE_SYSFS :
234289 ret = etm4_enable_sysfs (csdev );
235290 break ;
291+ case CS_MODE_PERF :
292+ ret = etm4_enable_perf (csdev , attr );
293+ break ;
236294 default :
237295 ret = - EINVAL ;
238296 }
@@ -266,6 +324,17 @@ static void etm4_disable_hw(void *info)
266324 dev_dbg (drvdata -> dev , "cpu: %d disable smp call done\n" , drvdata -> cpu );
267325}
268326
327+ static int etm4_disable_perf (struct coresight_device * csdev )
328+ {
329+ struct etmv4_drvdata * drvdata = dev_get_drvdata (csdev -> dev .parent );
330+
331+ if (WARN_ON_ONCE (drvdata -> cpu != smp_processor_id ()))
332+ return - EINVAL ;
333+
334+ etm4_disable_hw (drvdata );
335+ return 0 ;
336+ }
337+
269338static void etm4_disable_sysfs (struct coresight_device * csdev )
270339{
271340 struct etmv4_drvdata * drvdata = dev_get_drvdata (csdev -> dev .parent );
@@ -309,6 +378,9 @@ static void etm4_disable(struct coresight_device *csdev)
309378 case CS_MODE_SYSFS :
310379 etm4_disable_sysfs (csdev );
311380 break ;
381+ case CS_MODE_PERF :
382+ etm4_disable_perf (csdev );
383+ break ;
312384 }
313385
314386 if (mode )
@@ -708,8 +780,6 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
708780 etm4_init_trace_id (drvdata );
709781 etm4_set_default (& drvdata -> config );
710782
711- pm_runtime_put (& adev -> dev );
712-
713783 desc -> type = CORESIGHT_DEV_TYPE_SOURCE ;
714784 desc -> subtype .source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC ;
715785 desc -> ops = & etm4_cs_ops ;
@@ -719,9 +789,16 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
719789 drvdata -> csdev = coresight_register (desc );
720790 if (IS_ERR (drvdata -> csdev )) {
721791 ret = PTR_ERR (drvdata -> csdev );
722- goto err_coresight_register ;
792+ goto err_arch_supported ;
723793 }
724794
795+ ret = etm_perf_symlink (drvdata -> csdev , true);
796+ if (ret ) {
797+ coresight_unregister (drvdata -> csdev );
798+ goto err_arch_supported ;
799+ }
800+
801+ pm_runtime_put (& adev -> dev );
725802 dev_info (dev , "%s initialized\n" , (char * )id -> data );
726803
727804 if (boot_enable ) {
@@ -732,8 +809,6 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
732809 return 0 ;
733810
734811err_arch_supported :
735- pm_runtime_put (& adev -> dev );
736- err_coresight_register :
737812 if (-- etm4_count == 0 )
738813 unregister_hotcpu_notifier (& etm4_cpu_notifier );
739814 return ret ;
0 commit comments