65
65
66
66
/* For most nodes, this is all there is */
67
67
#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)
68
70
69
71
/* HN-Ps are weird... */
70
72
#define CMN_HNP_PMU_EVENT_SEL 0x008
@@ -229,6 +231,12 @@ enum cmn_node_type {
229
231
CMN_TYPE_WP = 0x7770
230
232
};
231
233
234
+ enum cmn_filter_select {
235
+ SEL_NONE = -1 ,
236
+ SEL_OCCUP1ID ,
237
+ SEL_MAX
238
+ };
239
+
232
240
struct arm_cmn_node {
233
241
void __iomem * pmu_base ;
234
242
u16 id , logid ;
@@ -238,9 +246,9 @@ struct arm_cmn_node {
238
246
union {
239
247
/* DN/HN-F/CXHA */
240
248
struct {
241
- u8 occupid_val ;
242
- u8 occupid_count ;
243
- };
249
+ u8 val : 4 ;
250
+ u8 count : 4 ;
251
+ } occupid [ SEL_MAX ] ;
244
252
/* XP */
245
253
u8 dtc ;
246
254
};
@@ -510,6 +518,7 @@ struct arm_cmn_hw_event {
510
518
u8 dtcs_used ;
511
519
u8 num_dns ;
512
520
u8 dtm_offset ;
521
+ enum cmn_filter_select filter_sel ;
513
522
};
514
523
515
524
#define for_each_hw_dn (hw , dn , i ) \
@@ -535,6 +544,7 @@ struct arm_cmn_event_attr {
535
544
struct device_attribute attr ;
536
545
enum cmn_model model ;
537
546
enum cmn_node_type type ;
547
+ enum cmn_filter_select fsel ;
538
548
u8 eventid ;
539
549
u8 occupid ;
540
550
};
@@ -545,22 +555,17 @@ struct arm_cmn_format_attr {
545
555
int config ;
546
556
};
547
557
548
- #define CMN_EVENT_ATTR (_model , _name , _type , _eventid , _occupid ) \
558
+ #define _CMN_EVENT_ATTR (_model , _name , _type , _eventid , _occupid , _fsel ) \
549
559
(&((struct arm_cmn_event_attr[]) {{ \
550
560
.attr = __ATTR(_name, 0444, arm_cmn_event_show, NULL), \
551
561
.model = _model, \
552
562
.type = _type, \
553
563
.eventid = _eventid, \
554
564
.occupid = _occupid, \
565
+ .fsel = _fsel, \
555
566
}})[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)
564
569
565
570
static ssize_t arm_cmn_event_show (struct device * dev ,
566
571
struct device_attribute * attr , char * buf )
@@ -577,7 +582,7 @@ static ssize_t arm_cmn_event_show(struct device *dev,
577
582
"type=0x%x,eventid=0x%x,wp_dev_sel=?,wp_chn_sel=?,wp_grp=?,wp_val=?,wp_mask=?\n" ,
578
583
eattr -> type , eattr -> eventid );
579
584
580
- if (arm_cmn_is_occup_event ( eattr -> model , eattr -> type , eattr -> eventid ) )
585
+ if (eattr -> fsel > SEL_NONE )
581
586
return sysfs_emit (buf , "type=0x%x,eventid=0x%x,occupid=0x%x\n" ,
582
587
eattr -> type , eattr -> eventid , eattr -> occupid );
583
588
@@ -652,33 +657,37 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
652
657
return attr -> mode ;
653
658
}
654
659
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 )
657
662
#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 )
661
666
#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)
663
668
#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)
665
670
#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)
667
672
#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)
669
674
#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)
671
676
#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)
673
678
#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)
675
680
#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)
677
682
678
683
#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)
680
689
#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 )
682
691
#define _CMN_EVENT_XP (_name , _event ) \
683
692
__CMN_EVENT_XP(e_##_name, (_event) | (0 << 2)), \
684
693
__CMN_EVENT_XP(w_##_name, (_event) | (1 << 2)), \
@@ -712,9 +721,7 @@ static struct attribute *arm_cmn_event_attrs[] = {
712
721
CMN_EVENT_DVM (CMN600 , rxreq_dvmsync , 0x02 ),
713
722
CMN_EVENT_DVM (CMN600 , rxreq_dvmop_vmid_filtered , 0x03 ),
714
723
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 ),
718
725
CMN_EVENT_DVM (NOT_CMN600 , dvmop_tlbi , 0x01 ),
719
726
CMN_EVENT_DVM (NOT_CMN600 , dvmop_bpi , 0x02 ),
720
727
CMN_EVENT_DVM (NOT_CMN600 , dvmop_pici , 0x03 ),
@@ -726,9 +733,7 @@ static struct attribute *arm_cmn_event_attrs[] = {
726
733
CMN_EVENT_DVM (NOT_CMN600 , txsnp_flitv , 0x09 ),
727
734
CMN_EVENT_DVM (NOT_CMN600 , txsnp_stall , 0x0a ),
728
735
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 ),
732
737
733
738
CMN_EVENT_HNF (CMN_ANY , cache_miss , 0x01 ),
734
739
CMN_EVENT_HNF (CMN_ANY , slc_sf_cache_access , 0x02 ),
@@ -744,11 +749,11 @@ static struct attribute *arm_cmn_event_attrs[] = {
744
749
CMN_EVENT_HNF (CMN_ANY , mc_retries , 0x0c ),
745
750
CMN_EVENT_HNF (CMN_ANY , mc_reqs , 0x0d ),
746
751
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 ),
752
757
CMN_EVENT_HNF (CMN_ANY , pocq_addrhaz , 0x10 ),
753
758
CMN_EVENT_HNF (CMN_ANY , pocq_atomic_addrhaz , 0x11 ),
754
759
CMN_EVENT_HNF (CMN_ANY , ld_st_swp_adq_full , 0x12 ),
@@ -817,8 +822,8 @@ static struct attribute *arm_cmn_event_attrs[] = {
817
822
CMN_EVENT_XP (txflit_stall , 0x02 ),
818
823
CMN_EVENT_XP (partial_dat_flit , 0x03 ),
819
824
/* 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 ),
822
827
823
828
CMN_EVENT_SBSX (CMN_ANY , rd_req , 0x01 ),
824
829
CMN_EVENT_SBSX (CMN_ANY , wr_req , 0x02 ),
@@ -1132,6 +1137,26 @@ static void arm_cmn_event_read(struct perf_event *event)
1132
1137
local64_add (delta , & event -> count );
1133
1138
}
1134
1139
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
+
1135
1160
static void arm_cmn_event_start (struct perf_event * event , int flags )
1136
1161
{
1137
1162
struct arm_cmn * cmn = to_cmn (event -> pmu );
@@ -1195,7 +1220,7 @@ static void arm_cmn_event_stop(struct perf_event *event, int flags)
1195
1220
1196
1221
struct arm_cmn_val {
1197
1222
u8 dtm_count [CMN_MAX_DTMS ];
1198
- u8 occupid [CMN_MAX_DTMS ];
1223
+ u8 occupid [CMN_MAX_DTMS ][ SEL_MAX ] ;
1199
1224
u8 wp [CMN_MAX_DTMS ][4 ];
1200
1225
int dtc_count ;
1201
1226
bool cycles ;
@@ -1208,7 +1233,6 @@ static void arm_cmn_val_add_event(struct arm_cmn *cmn, struct arm_cmn_val *val,
1208
1233
struct arm_cmn_node * dn ;
1209
1234
enum cmn_node_type type ;
1210
1235
int i ;
1211
- u8 occupid ;
1212
1236
1213
1237
if (is_software_event (event ))
1214
1238
return ;
@@ -1220,16 +1244,14 @@ static void arm_cmn_val_add_event(struct arm_cmn *cmn, struct arm_cmn_val *val,
1220
1244
}
1221
1245
1222
1246
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 ;
1227
1247
1228
1248
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 ;
1230
1250
1231
1251
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 ;
1233
1255
1234
1256
if (type != CMN_TYPE_WP )
1235
1257
continue ;
@@ -1247,7 +1269,6 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
1247
1269
enum cmn_node_type type ;
1248
1270
struct arm_cmn_val * val ;
1249
1271
int i , ret = - EINVAL ;
1250
- u8 occupid ;
1251
1272
1252
1273
if (leader == event )
1253
1274
return 0 ;
@@ -1272,18 +1293,14 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
1272
1293
if (val -> dtc_count == CMN_DT_NUM_COUNTERS )
1273
1294
goto done ;
1274
1295
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
-
1280
1296
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 ;
1282
1298
1283
1299
if (val -> dtm_count [dtm ] == CMN_DTM_NUM_COUNTERS )
1284
1300
goto done ;
1285
1301
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 )
1287
1304
goto done ;
1288
1305
1289
1306
if (type != CMN_TYPE_WP )
@@ -1304,6 +1321,22 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
1304
1321
return ret ;
1305
1322
}
1306
1323
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
+
1307
1340
static int arm_cmn_event_init (struct perf_event * event )
1308
1341
{
1309
1342
struct arm_cmn * cmn = to_cmn (event -> pmu );
@@ -1328,18 +1361,21 @@ static int arm_cmn_event_init(struct perf_event *event)
1328
1361
if (type == CMN_TYPE_DTC )
1329
1362
return 0 ;
1330
1363
1364
+ eventid = CMN_EVENT_EVENTID (event );
1331
1365
/* For watchpoints we need the actual XP node here */
1332
1366
if (type == CMN_TYPE_WP ) {
1333
1367
type = CMN_TYPE_XP ;
1334
1368
/* ...and we need a "real" direction */
1335
- eventid = CMN_EVENT_EVENTID (event );
1336
1369
if (eventid != CMN_WP_UP && eventid != CMN_WP_DOWN )
1337
1370
return - EINVAL ;
1338
1371
/* ...but the DTM may depend on which port we're watching */
1339
1372
if (cmn -> multi_dtm )
1340
1373
hw -> dtm_offset = CMN_EVENT_WP_DEV_SEL (event ) / 2 ;
1341
1374
}
1342
1375
1376
+ /* This is sufficiently annoying to recalculate, so cache it */
1377
+ hw -> filter_sel = arm_cmn_filter_sel (cmn -> model , type , eventid );
1378
+
1343
1379
bynodeid = CMN_EVENT_BYNODEID (event );
1344
1380
nodeid = CMN_EVENT_NODEID (event );
1345
1381
@@ -1381,8 +1417,8 @@ static void arm_cmn_event_clear(struct arm_cmn *cmn, struct perf_event *event,
1381
1417
if (type == CMN_TYPE_WP )
1382
1418
dtm -> wp_event [arm_cmn_wp_idx (event )] = -1 ;
1383
1419
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 -- ;
1386
1422
1387
1423
dtm -> pmu_config_low &= ~CMN__PMEVCNT_PAIRED (dtm_idx );
1388
1424
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)
1462
1498
input_sel = CMN__PMEVCNT0_INPUT_SEL_DEV + dtm_idx +
1463
1499
(nid .port << 4 ) + (nid .dev << 2 );
1464
1500
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 ;
1477
1503
}
1478
1504
1479
1505
arm_cmn_set_index (hw -> dtm_idx , i , dtm_idx );
0 commit comments