18
18
#include <linux/types.h>
19
19
#include <linux/workqueue.h>
20
20
21
+ #include "coresight-config.h"
21
22
#include "coresight-etm-perf.h"
22
23
#include "coresight-priv.h"
24
+ #include "coresight-syscfg.h"
23
25
24
26
static struct pmu etm_pmu ;
25
27
static bool etm_perf_up ;
@@ -57,8 +59,13 @@ PMU_FORMAT_ATTR(contextid1, "config:" __stringify(ETM_OPT_CTXTID));
57
59
PMU_FORMAT_ATTR (contextid2 , "config:" __stringify (ETM_OPT_CTXTID2 ));
58
60
PMU_FORMAT_ATTR (timestamp , "config:" __stringify (ETM_OPT_TS ));
59
61
PMU_FORMAT_ATTR (retstack , "config:" __stringify (ETM_OPT_RETSTK ));
62
+ /* preset - if sink ID is used as a configuration selector */
63
+ PMU_FORMAT_ATTR (preset , "config:0-3" );
60
64
/* Sink ID - same for all ETMs */
61
65
PMU_FORMAT_ATTR (sinkid , "config2:0-31" );
66
+ /* config ID - set if a system configuration is selected */
67
+ PMU_FORMAT_ATTR (configid , "config2:32-63" );
68
+
62
69
63
70
/*
64
71
* contextid always traces the "PID". The PID is in CONTEXTIDR_EL1
@@ -88,6 +95,8 @@ static struct attribute *etm_config_formats_attr[] = {
88
95
& format_attr_timestamp .attr ,
89
96
& format_attr_retstack .attr ,
90
97
& format_attr_sinkid .attr ,
98
+ & format_attr_preset .attr ,
99
+ & format_attr_configid .attr ,
91
100
NULL ,
92
101
};
93
102
@@ -105,9 +114,19 @@ static const struct attribute_group etm_pmu_sinks_group = {
105
114
.attrs = etm_config_sinks_attr ,
106
115
};
107
116
117
+ static struct attribute * etm_config_events_attr [] = {
118
+ NULL ,
119
+ };
120
+
121
+ static const struct attribute_group etm_pmu_events_group = {
122
+ .name = "events" ,
123
+ .attrs = etm_config_events_attr ,
124
+ };
125
+
108
126
static const struct attribute_group * etm_pmu_attr_groups [] = {
109
127
& etm_pmu_format_group ,
110
128
& etm_pmu_sinks_group ,
129
+ & etm_pmu_events_group ,
111
130
NULL ,
112
131
};
113
132
@@ -286,7 +305,7 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
286
305
INIT_WORK (& event_data -> work , free_event_data );
287
306
288
307
/* First get the selected sink from user space. */
289
- if (event -> attr .config2 ) {
308
+ if (event -> attr .config2 & GENMASK_ULL ( 31 , 0 ) ) {
290
309
id = (u32 )event -> attr .config2 ;
291
310
sink = user_sink = coresight_get_sink_by_id (id );
292
311
}
@@ -658,68 +677,127 @@ static ssize_t etm_perf_sink_name_show(struct device *dev,
658
677
return scnprintf (buf , PAGE_SIZE , "0x%lx\n" , (unsigned long )(ea -> var ));
659
678
}
660
679
661
- int etm_perf_add_symlink_sink (struct coresight_device * csdev )
680
+ static struct dev_ext_attribute *
681
+ etm_perf_add_symlink_group (struct device * dev , const char * name , const char * group_name )
662
682
{
663
- int ret ;
683
+ struct dev_ext_attribute * ea ;
664
684
unsigned long hash ;
665
- const char * name ;
685
+ int ret ;
666
686
struct device * pmu_dev = etm_pmu .dev ;
667
- struct device * dev = & csdev -> dev ;
668
- struct dev_ext_attribute * ea ;
669
-
670
- if (csdev -> type != CORESIGHT_DEV_TYPE_SINK &&
671
- csdev -> type != CORESIGHT_DEV_TYPE_LINKSINK )
672
- return - EINVAL ;
673
-
674
- if (csdev -> ea != NULL )
675
- return - EINVAL ;
676
687
677
688
if (!etm_perf_up )
678
- return - EPROBE_DEFER ;
689
+ return ERR_PTR ( - EPROBE_DEFER ) ;
679
690
680
691
ea = devm_kzalloc (dev , sizeof (* ea ), GFP_KERNEL );
681
692
if (!ea )
682
- return - ENOMEM ;
693
+ return ERR_PTR ( - ENOMEM ) ;
683
694
684
- name = dev_name (dev );
685
- /* See function coresight_get_sink_by_id() to know where this is used */
695
+ /*
696
+ * If this function is called adding a sink then the hash is used for
697
+ * sink selection - see function coresight_get_sink_by_id().
698
+ * If adding a configuration then the hash is used for selection in
699
+ * cscfg_activate_config()
700
+ */
686
701
hash = hashlen_hash (hashlen_string (NULL , name ));
687
702
688
703
sysfs_attr_init (& ea -> attr .attr );
689
704
ea -> attr .attr .name = devm_kstrdup (dev , name , GFP_KERNEL );
690
705
if (!ea -> attr .attr .name )
691
- return - ENOMEM ;
706
+ return ERR_PTR ( - ENOMEM ) ;
692
707
693
708
ea -> attr .attr .mode = 0444 ;
694
- ea -> attr .show = etm_perf_sink_name_show ;
695
709
ea -> var = (unsigned long * )hash ;
696
710
697
711
ret = sysfs_add_file_to_group (& pmu_dev -> kobj ,
698
- & ea -> attr .attr , "sinks" );
712
+ & ea -> attr .attr , group_name );
699
713
700
- if (! ret )
701
- csdev -> ea = ea ;
714
+ return ret ? ERR_PTR ( ret ) : ea ;
715
+ }
702
716
703
- return ret ;
717
+ int etm_perf_add_symlink_sink (struct coresight_device * csdev )
718
+ {
719
+ const char * name ;
720
+ struct device * dev = & csdev -> dev ;
721
+ int err = 0 ;
722
+
723
+ if (csdev -> type != CORESIGHT_DEV_TYPE_SINK &&
724
+ csdev -> type != CORESIGHT_DEV_TYPE_LINKSINK )
725
+ return - EINVAL ;
726
+
727
+ if (csdev -> ea != NULL )
728
+ return - EINVAL ;
729
+
730
+ name = dev_name (dev );
731
+ csdev -> ea = etm_perf_add_symlink_group (dev , name , "sinks" );
732
+ if (IS_ERR (csdev -> ea )) {
733
+ err = PTR_ERR (csdev -> ea );
734
+ csdev -> ea = NULL ;
735
+ } else
736
+ csdev -> ea -> attr .show = etm_perf_sink_name_show ;
737
+
738
+ return err ;
704
739
}
705
740
706
- void etm_perf_del_symlink_sink (struct coresight_device * csdev )
741
+ static void etm_perf_del_symlink_group (struct dev_ext_attribute * ea , const char * group_name )
707
742
{
708
743
struct device * pmu_dev = etm_pmu .dev ;
709
- struct dev_ext_attribute * ea = csdev -> ea ;
710
744
745
+ sysfs_remove_file_from_group (& pmu_dev -> kobj ,
746
+ & ea -> attr .attr , group_name );
747
+ }
748
+
749
+ void etm_perf_del_symlink_sink (struct coresight_device * csdev )
750
+ {
711
751
if (csdev -> type != CORESIGHT_DEV_TYPE_SINK &&
712
752
csdev -> type != CORESIGHT_DEV_TYPE_LINKSINK )
713
753
return ;
714
754
715
- if (!ea )
755
+ if (!csdev -> ea )
716
756
return ;
717
757
718
- sysfs_remove_file_from_group (& pmu_dev -> kobj ,
719
- & ea -> attr .attr , "sinks" );
758
+ etm_perf_del_symlink_group (csdev -> ea , "sinks" );
720
759
csdev -> ea = NULL ;
721
760
}
722
761
762
+ static ssize_t etm_perf_cscfg_event_show (struct device * dev ,
763
+ struct device_attribute * dattr ,
764
+ char * buf )
765
+ {
766
+ struct dev_ext_attribute * ea ;
767
+
768
+ ea = container_of (dattr , struct dev_ext_attribute , attr );
769
+ return scnprintf (buf , PAGE_SIZE , "configid=0x%lx\n" , (unsigned long )(ea -> var ));
770
+ }
771
+
772
+ int etm_perf_add_symlink_cscfg (struct device * dev , struct cscfg_config_desc * config_desc )
773
+ {
774
+ int err = 0 ;
775
+
776
+ if (config_desc -> event_ea != NULL )
777
+ return 0 ;
778
+
779
+ config_desc -> event_ea = etm_perf_add_symlink_group (dev , config_desc -> name , "events" );
780
+
781
+ /* set the show function to the custom cscfg event */
782
+ if (!IS_ERR (config_desc -> event_ea ))
783
+ config_desc -> event_ea -> attr .show = etm_perf_cscfg_event_show ;
784
+ else {
785
+ err = PTR_ERR (config_desc -> event_ea );
786
+ config_desc -> event_ea = NULL ;
787
+ }
788
+
789
+ return err ;
790
+ }
791
+
792
+ void etm_perf_del_symlink_cscfg (struct cscfg_config_desc * config_desc )
793
+ {
794
+ if (!config_desc -> event_ea )
795
+ return ;
796
+
797
+ etm_perf_del_symlink_group (config_desc -> event_ea , "events" );
798
+ config_desc -> event_ea = NULL ;
799
+ }
800
+
723
801
int __init etm_perf_init (void )
724
802
{
725
803
int ret ;
0 commit comments