6565
6666/* For most nodes, this is all there is */
6767#define CMN_PMU_EVENT_SEL 0x000
68+ /* Technically this is 4 bits wide on DNs, but we only use 2 there anyway */
69+ #define CMN__PMU_OCCUP1_ID GENMASK_ULL(34, 32)
6870
6971/* HN-Ps are weird... */
7072#define CMN_HNP_PMU_EVENT_SEL 0x008
@@ -229,6 +231,12 @@ enum cmn_node_type {
229231 CMN_TYPE_WP = 0x7770
230232};
231233
234+ enum cmn_filter_select {
235+ SEL_NONE = -1 ,
236+ SEL_OCCUP1ID ,
237+ SEL_MAX
238+ };
239+
232240struct arm_cmn_node {
233241 void __iomem * pmu_base ;
234242 u16 id , logid ;
@@ -238,9 +246,9 @@ struct arm_cmn_node {
238246 union {
239247 /* DN/HN-F/CXHA */
240248 struct {
241- u8 occupid_val ;
242- u8 occupid_count ;
243- };
249+ u8 val : 4 ;
250+ u8 count : 4 ;
251+ } occupid [ SEL_MAX ] ;
244252 /* XP */
245253 u8 dtc ;
246254 };
@@ -510,6 +518,7 @@ struct arm_cmn_hw_event {
510518 u8 dtcs_used ;
511519 u8 num_dns ;
512520 u8 dtm_offset ;
521+ enum cmn_filter_select filter_sel ;
513522};
514523
515524#define for_each_hw_dn (hw , dn , i ) \
@@ -535,6 +544,7 @@ struct arm_cmn_event_attr {
535544 struct device_attribute attr ;
536545 enum cmn_model model ;
537546 enum cmn_node_type type ;
547+ enum cmn_filter_select fsel ;
538548 u8 eventid ;
539549 u8 occupid ;
540550};
@@ -545,22 +555,17 @@ struct arm_cmn_format_attr {
545555 int config ;
546556};
547557
548- #define CMN_EVENT_ATTR (_model , _name , _type , _eventid , _occupid ) \
558+ #define _CMN_EVENT_ATTR (_model , _name , _type , _eventid , _occupid , _fsel ) \
549559 (&((struct arm_cmn_event_attr[]) {{ \
550560 .attr = __ATTR(_name, 0444, arm_cmn_event_show, NULL), \
551561 .model = _model, \
552562 .type = _type, \
553563 .eventid = _eventid, \
554564 .occupid = _occupid, \
565+ .fsel = _fsel, \
555566 }})[0].attr.attr)
556-
557- static bool arm_cmn_is_occup_event (enum cmn_model model ,
558- enum cmn_node_type type , unsigned int id )
559- {
560- if (type == CMN_TYPE_DVM )
561- return model == CMN600 ? id == 0x05 : id == 0x0c ;
562- return type == CMN_TYPE_HNF && id == 0x0f ;
563- }
567+ #define CMN_EVENT_ATTR (_model , _name , _type , _eventid ) \
568+ _CMN_EVENT_ATTR(_model, _name, _type, _eventid, 0, SEL_NONE)
564569
565570static ssize_t arm_cmn_event_show (struct device * dev ,
566571 struct device_attribute * attr , char * buf )
@@ -577,7 +582,7 @@ static ssize_t arm_cmn_event_show(struct device *dev,
577582 "type=0x%x,eventid=0x%x,wp_dev_sel=?,wp_chn_sel=?,wp_grp=?,wp_val=?,wp_mask=?\n" ,
578583 eattr -> type , eattr -> eventid );
579584
580- if (arm_cmn_is_occup_event ( eattr -> model , eattr -> type , eattr -> eventid ) )
585+ if (eattr -> fsel > SEL_NONE )
581586 return sysfs_emit (buf , "type=0x%x,eventid=0x%x,occupid=0x%x\n" ,
582587 eattr -> type , eattr -> eventid , eattr -> occupid );
583588
@@ -652,33 +657,37 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
652657 return attr -> mode ;
653658}
654659
655- #define _CMN_EVENT_DVM (_model , _name , _event , _occup ) \
656- CMN_EVENT_ATTR (_model, dn_##_name, CMN_TYPE_DVM, _event, _occup)
660+ #define _CMN_EVENT_DVM (_model , _name , _event , _occup , _fsel ) \
661+ _CMN_EVENT_ATTR (_model, dn_##_name, CMN_TYPE_DVM, _event, _occup, _fsel )
657662#define CMN_EVENT_DTC (_name ) \
658- CMN_EVENT_ATTR(CMN_ANY, dtc_##_name, CMN_TYPE_DTC, 0, 0 )
659- #define _CMN_EVENT_HNF (_model , _name , _event , _occup ) \
660- CMN_EVENT_ATTR (_model, hnf_##_name, CMN_TYPE_HNF, _event, _occup)
663+ CMN_EVENT_ATTR(CMN_ANY, dtc_##_name, CMN_TYPE_DTC, 0)
664+ #define _CMN_EVENT_HNF (_model , _name , _event , _occup , _fsel ) \
665+ _CMN_EVENT_ATTR (_model, hnf_##_name, CMN_TYPE_HNF, _event, _occup, _fsel )
661666#define CMN_EVENT_HNI (_name , _event ) \
662- CMN_EVENT_ATTR(CMN_ANY, hni_##_name, CMN_TYPE_HNI, _event, 0 )
667+ CMN_EVENT_ATTR(CMN_ANY, hni_##_name, CMN_TYPE_HNI, _event)
663668#define CMN_EVENT_HNP (_name , _event ) \
664- CMN_EVENT_ATTR(CMN_ANY, hnp_##_name, CMN_TYPE_HNP, _event, 0 )
669+ CMN_EVENT_ATTR(CMN_ANY, hnp_##_name, CMN_TYPE_HNP, _event)
665670#define __CMN_EVENT_XP (_name , _event ) \
666- CMN_EVENT_ATTR(CMN_ANY, mxp_##_name, CMN_TYPE_XP, _event, 0 )
671+ CMN_EVENT_ATTR(CMN_ANY, mxp_##_name, CMN_TYPE_XP, _event)
667672#define CMN_EVENT_SBSX (_model , _name , _event ) \
668- CMN_EVENT_ATTR(_model, sbsx_##_name, CMN_TYPE_SBSX, _event, 0 )
673+ CMN_EVENT_ATTR(_model, sbsx_##_name, CMN_TYPE_SBSX, _event)
669674#define CMN_EVENT_RNID (_model , _name , _event ) \
670- CMN_EVENT_ATTR(_model, rnid_##_name, CMN_TYPE_RNI, _event, 0 )
675+ CMN_EVENT_ATTR(_model, rnid_##_name, CMN_TYPE_RNI, _event)
671676#define CMN_EVENT_MTSX (_name , _event ) \
672- CMN_EVENT_ATTR(CMN_ANY, mtsx_##_name, CMN_TYPE_MTSX, _event, 0 )
677+ CMN_EVENT_ATTR(CMN_ANY, mtsx_##_name, CMN_TYPE_MTSX, _event)
673678#define CMN_EVENT_CXRA (_model , _name , _event ) \
674- CMN_EVENT_ATTR(_model, cxra_##_name, CMN_TYPE_CXRA, _event, 0 )
679+ CMN_EVENT_ATTR(_model, cxra_##_name, CMN_TYPE_CXRA, _event)
675680#define CMN_EVENT_CXHA (_name , _event ) \
676- CMN_EVENT_ATTR(CMN_ANY, cxha_##_name, CMN_TYPE_CXHA, _event, 0 )
681+ CMN_EVENT_ATTR(CMN_ANY, cxha_##_name, CMN_TYPE_CXHA, _event)
677682
678683#define CMN_EVENT_DVM (_model , _name , _event ) \
679- _CMN_EVENT_DVM(_model, _name, _event, 0)
684+ _CMN_EVENT_DVM(_model, _name, _event, 0, SEL_NONE)
685+ #define CMN_EVENT_DVM_OCC (_model , _name , _event ) \
686+ _CMN_EVENT_DVM(_model, _name##_all, _event, 0, SEL_OCCUP1ID), \
687+ _CMN_EVENT_DVM(_model, _name##_dvmop, _event, 1, SEL_OCCUP1ID), \
688+ _CMN_EVENT_DVM(_model, _name##_dvmsync, _event, 2, SEL_OCCUP1ID)
680689#define CMN_EVENT_HNF (_model , _name , _event ) \
681- _CMN_EVENT_HNF(_model, _name, _event, 0)
690+ _CMN_EVENT_HNF(_model, _name, _event, 0, SEL_NONE )
682691#define _CMN_EVENT_XP (_name , _event ) \
683692 __CMN_EVENT_XP(e_##_name, (_event) | (0 << 2)), \
684693 __CMN_EVENT_XP(w_##_name, (_event) | (1 << 2)), \
@@ -712,9 +721,7 @@ static struct attribute *arm_cmn_event_attrs[] = {
712721 CMN_EVENT_DVM (CMN600 , rxreq_dvmsync , 0x02 ),
713722 CMN_EVENT_DVM (CMN600 , rxreq_dvmop_vmid_filtered , 0x03 ),
714723 CMN_EVENT_DVM (CMN600 , rxreq_retried , 0x04 ),
715- _CMN_EVENT_DVM (CMN600 , rxreq_trk_occupancy_all , 0x05 , 0 ),
716- _CMN_EVENT_DVM (CMN600 , rxreq_trk_occupancy_dvmop , 0x05 , 1 ),
717- _CMN_EVENT_DVM (CMN600 , rxreq_trk_occupancy_dvmsync , 0x05 , 2 ),
724+ CMN_EVENT_DVM_OCC (CMN600 , rxreq_trk_occupancy , 0x05 ),
718725 CMN_EVENT_DVM (NOT_CMN600 , dvmop_tlbi , 0x01 ),
719726 CMN_EVENT_DVM (NOT_CMN600 , dvmop_bpi , 0x02 ),
720727 CMN_EVENT_DVM (NOT_CMN600 , dvmop_pici , 0x03 ),
@@ -726,9 +733,7 @@ static struct attribute *arm_cmn_event_attrs[] = {
726733 CMN_EVENT_DVM (NOT_CMN600 , txsnp_flitv , 0x09 ),
727734 CMN_EVENT_DVM (NOT_CMN600 , txsnp_stall , 0x0a ),
728735 CMN_EVENT_DVM (NOT_CMN600 , trkfull , 0x0b ),
729- _CMN_EVENT_DVM (NOT_CMN600 , trk_occupancy_all , 0x0c , 0 ),
730- _CMN_EVENT_DVM (NOT_CMN600 , trk_occupancy_dvmop , 0x0c , 1 ),
731- _CMN_EVENT_DVM (NOT_CMN600 , trk_occupancy_dvmsync , 0x0c , 2 ),
736+ CMN_EVENT_DVM_OCC (NOT_CMN600 , trk_occupancy , 0x0c ),
732737
733738 CMN_EVENT_HNF (CMN_ANY , cache_miss , 0x01 ),
734739 CMN_EVENT_HNF (CMN_ANY , slc_sf_cache_access , 0x02 ),
@@ -744,11 +749,11 @@ static struct attribute *arm_cmn_event_attrs[] = {
744749 CMN_EVENT_HNF (CMN_ANY , mc_retries , 0x0c ),
745750 CMN_EVENT_HNF (CMN_ANY , mc_reqs , 0x0d ),
746751 CMN_EVENT_HNF (CMN_ANY , qos_hh_retry , 0x0e ),
747- _CMN_EVENT_HNF (CMN_ANY , qos_pocq_occupancy_all , 0x0f , 0 ),
748- _CMN_EVENT_HNF (CMN_ANY , qos_pocq_occupancy_read , 0x0f , 1 ),
749- _CMN_EVENT_HNF (CMN_ANY , qos_pocq_occupancy_write , 0x0f , 2 ),
750- _CMN_EVENT_HNF (CMN_ANY , qos_pocq_occupancy_atomic , 0x0f , 3 ),
751- _CMN_EVENT_HNF (CMN_ANY , qos_pocq_occupancy_stash , 0x0f , 4 ),
752+ _CMN_EVENT_HNF (CMN_ANY , qos_pocq_occupancy_all , 0x0f , 0 , SEL_OCCUP1ID ),
753+ _CMN_EVENT_HNF (CMN_ANY , qos_pocq_occupancy_read , 0x0f , 1 , SEL_OCCUP1ID ),
754+ _CMN_EVENT_HNF (CMN_ANY , qos_pocq_occupancy_write , 0x0f , 2 , SEL_OCCUP1ID ),
755+ _CMN_EVENT_HNF (CMN_ANY , qos_pocq_occupancy_atomic , 0x0f , 3 , SEL_OCCUP1ID ),
756+ _CMN_EVENT_HNF (CMN_ANY , qos_pocq_occupancy_stash , 0x0f , 4 , SEL_OCCUP1ID ),
752757 CMN_EVENT_HNF (CMN_ANY , pocq_addrhaz , 0x10 ),
753758 CMN_EVENT_HNF (CMN_ANY , pocq_atomic_addrhaz , 0x11 ),
754759 CMN_EVENT_HNF (CMN_ANY , ld_st_swp_adq_full , 0x12 ),
@@ -817,8 +822,8 @@ static struct attribute *arm_cmn_event_attrs[] = {
817822 CMN_EVENT_XP (txflit_stall , 0x02 ),
818823 CMN_EVENT_XP (partial_dat_flit , 0x03 ),
819824 /* We treat watchpoints as a special made-up class of XP events */
820- CMN_EVENT_ATTR (CMN_ANY , watchpoint_up , CMN_TYPE_WP , CMN_WP_UP , 0 ),
821- CMN_EVENT_ATTR (CMN_ANY , watchpoint_down , CMN_TYPE_WP , CMN_WP_DOWN , 0 ),
825+ CMN_EVENT_ATTR (CMN_ANY , watchpoint_up , CMN_TYPE_WP , CMN_WP_UP ),
826+ CMN_EVENT_ATTR (CMN_ANY , watchpoint_down , CMN_TYPE_WP , CMN_WP_DOWN ),
822827
823828 CMN_EVENT_SBSX (CMN_ANY , rd_req , 0x01 ),
824829 CMN_EVENT_SBSX (CMN_ANY , wr_req , 0x02 ),
@@ -1132,6 +1137,26 @@ static void arm_cmn_event_read(struct perf_event *event)
11321137 local64_add (delta , & event -> count );
11331138}
11341139
1140+ static int arm_cmn_set_event_sel_hi (struct arm_cmn_node * dn ,
1141+ enum cmn_filter_select fsel , u8 occupid )
1142+ {
1143+ u64 reg ;
1144+
1145+ if (fsel == SEL_NONE )
1146+ return 0 ;
1147+
1148+ if (!dn -> occupid [fsel ].count ) {
1149+ dn -> occupid [fsel ].val = occupid ;
1150+ reg = FIELD_PREP (CMN__PMU_OCCUP1_ID ,
1151+ dn -> occupid [SEL_OCCUP1ID ].val );
1152+ writel_relaxed (reg >> 32 , dn -> pmu_base + CMN_PMU_EVENT_SEL + 4 );
1153+ } else if (dn -> occupid [fsel ].val != occupid ) {
1154+ return - EBUSY ;
1155+ }
1156+ dn -> occupid [fsel ].count ++ ;
1157+ return 0 ;
1158+ }
1159+
11351160static void arm_cmn_event_start (struct perf_event * event , int flags )
11361161{
11371162 struct arm_cmn * cmn = to_cmn (event -> pmu );
@@ -1195,7 +1220,7 @@ static void arm_cmn_event_stop(struct perf_event *event, int flags)
11951220
11961221struct arm_cmn_val {
11971222 u8 dtm_count [CMN_MAX_DTMS ];
1198- u8 occupid [CMN_MAX_DTMS ];
1223+ u8 occupid [CMN_MAX_DTMS ][ SEL_MAX ] ;
11991224 u8 wp [CMN_MAX_DTMS ][4 ];
12001225 int dtc_count ;
12011226 bool cycles ;
@@ -1208,7 +1233,6 @@ static void arm_cmn_val_add_event(struct arm_cmn *cmn, struct arm_cmn_val *val,
12081233 struct arm_cmn_node * dn ;
12091234 enum cmn_node_type type ;
12101235 int i ;
1211- u8 occupid ;
12121236
12131237 if (is_software_event (event ))
12141238 return ;
@@ -1220,16 +1244,14 @@ static void arm_cmn_val_add_event(struct arm_cmn *cmn, struct arm_cmn_val *val,
12201244 }
12211245
12221246 val -> dtc_count ++ ;
1223- if (arm_cmn_is_occup_event (cmn -> model , type , CMN_EVENT_EVENTID (event )))
1224- occupid = CMN_EVENT_OCCUPID (event ) + 1 ;
1225- else
1226- occupid = 0 ;
12271247
12281248 for_each_hw_dn (hw , dn , i ) {
1229- int wp_idx , dtm = dn -> dtm ;
1249+ int wp_idx , dtm = dn -> dtm , sel = hw -> filter_sel ;
12301250
12311251 val -> dtm_count [dtm ]++ ;
1232- val -> occupid [dtm ] = occupid ;
1252+
1253+ if (sel > SEL_NONE )
1254+ val -> occupid [dtm ][sel ] = CMN_EVENT_OCCUPID (event ) + 1 ;
12331255
12341256 if (type != CMN_TYPE_WP )
12351257 continue ;
@@ -1247,7 +1269,6 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
12471269 enum cmn_node_type type ;
12481270 struct arm_cmn_val * val ;
12491271 int i , ret = - EINVAL ;
1250- u8 occupid ;
12511272
12521273 if (leader == event )
12531274 return 0 ;
@@ -1272,18 +1293,14 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
12721293 if (val -> dtc_count == CMN_DT_NUM_COUNTERS )
12731294 goto done ;
12741295
1275- if (arm_cmn_is_occup_event (cmn -> model , type , CMN_EVENT_EVENTID (event )))
1276- occupid = CMN_EVENT_OCCUPID (event ) + 1 ;
1277- else
1278- occupid = 0 ;
1279-
12801296 for_each_hw_dn (hw , dn , i ) {
1281- int wp_idx , wp_cmb , dtm = dn -> dtm ;
1297+ int wp_idx , wp_cmb , dtm = dn -> dtm , sel = hw -> filter_sel ;
12821298
12831299 if (val -> dtm_count [dtm ] == CMN_DTM_NUM_COUNTERS )
12841300 goto done ;
12851301
1286- if (occupid && val -> occupid [dtm ] && occupid != val -> occupid [dtm ])
1302+ if (sel > SEL_NONE && val -> occupid [dtm ][sel ] &&
1303+ val -> occupid [dtm ][sel ] != CMN_EVENT_OCCUPID (event ) + 1 )
12871304 goto done ;
12881305
12891306 if (type != CMN_TYPE_WP )
@@ -1304,6 +1321,22 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
13041321 return ret ;
13051322}
13061323
1324+ static enum cmn_filter_select arm_cmn_filter_sel (enum cmn_model model ,
1325+ enum cmn_node_type type ,
1326+ unsigned int eventid )
1327+ {
1328+ struct arm_cmn_event_attr * e ;
1329+ int i ;
1330+
1331+ for (i = 0 ; i < ARRAY_SIZE (arm_cmn_event_attrs ); i ++ ) {
1332+ e = container_of (arm_cmn_event_attrs [i ], typeof (* e ), attr .attr );
1333+ if (e -> model & model && e -> type == type && e -> eventid == eventid )
1334+ return e -> fsel ;
1335+ }
1336+ return SEL_NONE ;
1337+ }
1338+
1339+
13071340static int arm_cmn_event_init (struct perf_event * event )
13081341{
13091342 struct arm_cmn * cmn = to_cmn (event -> pmu );
@@ -1328,18 +1361,21 @@ static int arm_cmn_event_init(struct perf_event *event)
13281361 if (type == CMN_TYPE_DTC )
13291362 return 0 ;
13301363
1364+ eventid = CMN_EVENT_EVENTID (event );
13311365 /* For watchpoints we need the actual XP node here */
13321366 if (type == CMN_TYPE_WP ) {
13331367 type = CMN_TYPE_XP ;
13341368 /* ...and we need a "real" direction */
1335- eventid = CMN_EVENT_EVENTID (event );
13361369 if (eventid != CMN_WP_UP && eventid != CMN_WP_DOWN )
13371370 return - EINVAL ;
13381371 /* ...but the DTM may depend on which port we're watching */
13391372 if (cmn -> multi_dtm )
13401373 hw -> dtm_offset = CMN_EVENT_WP_DEV_SEL (event ) / 2 ;
13411374 }
13421375
1376+ /* This is sufficiently annoying to recalculate, so cache it */
1377+ hw -> filter_sel = arm_cmn_filter_sel (cmn -> model , type , eventid );
1378+
13431379 bynodeid = CMN_EVENT_BYNODEID (event );
13441380 nodeid = CMN_EVENT_NODEID (event );
13451381
@@ -1381,8 +1417,8 @@ static void arm_cmn_event_clear(struct arm_cmn *cmn, struct perf_event *event,
13811417 if (type == CMN_TYPE_WP )
13821418 dtm -> wp_event [arm_cmn_wp_idx (event )] = -1 ;
13831419
1384- if (arm_cmn_is_occup_event ( cmn -> model , type , CMN_EVENT_EVENTID ( event )) )
1385- hw -> dn [i ].occupid_count -- ;
1420+ if (hw -> filter_sel > SEL_NONE )
1421+ hw -> dn [i ].occupid [ hw -> filter_sel ]. count -- ;
13861422
13871423 dtm -> pmu_config_low &= ~CMN__PMEVCNT_PAIRED (dtm_idx );
13881424 writel_relaxed (dtm -> pmu_config_low , dtm -> base + CMN_DTM_PMU_CONFIG );
@@ -1462,18 +1498,8 @@ static int arm_cmn_event_add(struct perf_event *event, int flags)
14621498 input_sel = CMN__PMEVCNT0_INPUT_SEL_DEV + dtm_idx +
14631499 (nid .port << 4 ) + (nid .dev << 2 );
14641500
1465- if (arm_cmn_is_occup_event (cmn -> model , type , CMN_EVENT_EVENTID (event ))) {
1466- u8 occupid = CMN_EVENT_OCCUPID (event );
1467-
1468- if (dn -> occupid_count == 0 ) {
1469- dn -> occupid_val = occupid ;
1470- writel_relaxed (occupid ,
1471- dn -> pmu_base + CMN_PMU_EVENT_SEL + 4 );
1472- } else if (dn -> occupid_val != occupid ) {
1473- goto free_dtms ;
1474- }
1475- dn -> occupid_count ++ ;
1476- }
1501+ if (arm_cmn_set_event_sel_hi (dn , hw -> filter_sel , CMN_EVENT_OCCUPID (event )))
1502+ goto free_dtms ;
14771503 }
14781504
14791505 arm_cmn_set_index (hw -> dtm_idx , i , dtm_idx );
0 commit comments