Skip to content

Commit 65adf71

Browse files
rmurphy-armwilldeacon
authored andcommitted
perf/arm-cmn: Refactor occupancy filter selector
So far, DNs and HN-Fs have each had one event ralated to occupancy trackers which are filtered by a separate field. CMN-700 raises the stakes by introducing two more sets of HN-F events with corresponding additional filter fields. Prepare for this by refactoring our filter selection and tracking logic to account for multiple filter types coexisting on the same node. This need not affect the uAPI, which can just continue to encode any per-event filter setting in the "occupid" config field, even if it's technically not the most accurate name for some of them. Signed-off-by: Robin Murphy <[email protected]> Tested-by: Ilkka Koskinen <[email protected]> Link: https://lore.kernel.org/r/1aa47ba0455b144c416537f6b0e58dc93b467a00.1650320598.git.robin.murphy@arm.com Signed-off-by: Will Deacon <[email protected]>
1 parent 8e504d9 commit 65adf71

File tree

1 file changed

+98
-72
lines changed

1 file changed

+98
-72
lines changed

drivers/perf/arm-cmn.c

Lines changed: 98 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@
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+
232240
struct 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

565570
static 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+
11351160
static 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

11961221
struct 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+
13071340
static 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

Comments
 (0)