* [PATCH 1/5] perf/arm-cmn: Rename filter variables for clarity
2026-06-30 15:19 [PATCH 0/5] perf/arm-cmn: Support CMN S3 r2 Robin Murphy
@ 2026-06-30 15:19 ` Robin Murphy
2026-06-30 15:19 ` [PATCH 2/5] perf/arm-cmn: Refactor event filter programming Robin Murphy
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Robin Murphy @ 2026-06-30 15:19 UTC (permalink / raw)
To: will, mark.rutland; +Cc: linux-arm-kernel, linux-perf-users, ilkka
CMN has already grown many more event-specific filters than the original
Occupancy ID, but since they are all independent of each other we've
just overloaded them onto the same name. Before we add yet more, and
they begin to overlap, rename all our "occupid" variables to "filter" so
that things can be a bit clearer and more consistent (but leaving the
format attribute itself, to avoid UAPI concerns).
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
drivers/perf/arm-cmn.c | 53 ++++++++++++++++++++++--------------------
1 file changed, 28 insertions(+), 25 deletions(-)
diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
index 50402bc4a21d..2a8a67da72c3 100644
--- a/drivers/perf/arm-cmn.c
+++ b/drivers/perf/arm-cmn.c
@@ -163,13 +163,13 @@
/* Event attributes */
#define CMN_CONFIG_TYPE GENMASK_ULL(15, 0)
#define CMN_CONFIG_EVENTID GENMASK_ULL(26, 16)
-#define CMN_CONFIG_OCCUPID GENMASK_ULL(30, 27)
+#define CMN_CONFIG_FILTER GENMASK_ULL(30, 27)
#define CMN_CONFIG_BYNODEID BIT_ULL(31)
#define CMN_CONFIG_NODEID GENMASK_ULL(47, 32)
#define CMN_EVENT_TYPE(event) FIELD_GET(CMN_CONFIG_TYPE, (event)->attr.config)
#define CMN_EVENT_EVENTID(event) FIELD_GET(CMN_CONFIG_EVENTID, (event)->attr.config)
-#define CMN_EVENT_OCCUPID(event) FIELD_GET(CMN_CONFIG_OCCUPID, (event)->attr.config)
+#define CMN_EVENT_FILTER(event) FIELD_GET(CMN_CONFIG_FILTER, (event)->attr.config)
#define CMN_EVENT_BYNODEID(event) FIELD_GET(CMN_CONFIG_BYNODEID, (event)->attr.config)
#define CMN_EVENT_NODEID(event) FIELD_GET(CMN_CONFIG_NODEID, (event)->attr.config)
@@ -301,7 +301,7 @@ struct arm_cmn_node {
struct {
u8 val : 4;
u8 count : 4;
- } occupid[SEL_MAX];
+ } filter[SEL_MAX];
union {
u8 event[4];
__le32 event_sel;
@@ -672,7 +672,7 @@ struct arm_cmn_event_attr {
enum cmn_node_type type;
enum cmn_filter_select fsel;
u16 eventid;
- u8 occupid;
+ u8 filter;
};
struct arm_cmn_format_attr {
@@ -681,13 +681,13 @@ struct arm_cmn_format_attr {
int config;
};
-#define _CMN_EVENT_ATTR(_model, _name, _type, _eventid, _occupid, _fsel)\
+#define _CMN_EVENT_ATTR(_model, _name, _type, _eventid, _filter, _fsel)\
(&((struct arm_cmn_event_attr[]) {{ \
.attr = __ATTR(_name, 0444, arm_cmn_event_show, NULL), \
.model = _model, \
.type = _type, \
.eventid = _eventid, \
- .occupid = _occupid, \
+ .filter = _filter, \
.fsel = _fsel, \
}})[0].attr.attr)
#define CMN_EVENT_ATTR(_model, _name, _type, _eventid) \
@@ -709,8 +709,8 @@ static ssize_t arm_cmn_event_show(struct device *dev,
eattr->type, eattr->eventid);
if (eattr->fsel > SEL_NONE)
- return sysfs_emit(buf, "type=0x%x,eventid=0x%x,occupid=0x%x\n",
- eattr->type, eattr->eventid, eattr->occupid);
+ return sysfs_emit(buf, "type=0x%x,eventid=0x%x,filter=0x%x\n",
+ eattr->type, eattr->eventid, eattr->filter);
return sysfs_emit(buf, "type=0x%x,eventid=0x%x\n", eattr->type,
eattr->eventid);
@@ -1320,7 +1320,7 @@ static ssize_t arm_cmn_format_show(struct device *dev,
static struct attribute *arm_cmn_format_attrs[] = {
CMN_FORMAT_ATTR(type, CMN_CONFIG_TYPE),
CMN_FORMAT_ATTR(eventid, CMN_CONFIG_EVENTID),
- CMN_FORMAT_ATTR(occupid, CMN_CONFIG_OCCUPID),
+ CMN_FORMAT_ATTR(filter, CMN_CONFIG_FILTER),
CMN_FORMAT_ATTR(bynodeid, CMN_CONFIG_BYNODEID),
CMN_FORMAT_ATTR(nodeid, CMN_CONFIG_NODEID),
@@ -1333,6 +1333,9 @@ static struct attribute *arm_cmn_format_attrs[] = {
_CMN_FORMAT_ATTR(wp_val, 1, CMN_CONFIG1_WP_VAL),
_CMN_FORMAT_ATTR(wp_mask, 2, CMN_CONFIG2_WP_MASK),
+ /* Old name for UAPI compatibility */
+ CMN_FORMAT_ATTR(occupid, CMN_CONFIG_FILTER),
+
NULL
};
@@ -1544,30 +1547,30 @@ static void arm_cmn_event_read(struct perf_event *event)
}
static int arm_cmn_set_event_sel_hi(struct arm_cmn_node *dn,
- enum cmn_filter_select fsel, u8 occupid)
+ enum cmn_filter_select fsel, u8 filter)
{
u64 reg;
if (fsel == SEL_NONE)
return 0;
- if (!dn->occupid[fsel].count) {
- dn->occupid[fsel].val = occupid;
+ if (!dn->filter[fsel].count) {
+ dn->filter[fsel].val = filter;
reg = FIELD_PREP(CMN__PMU_CBUSY_SNTHROTTLE_SEL,
- dn->occupid[SEL_CBUSY_SNTHROTTLE_SEL].val) |
+ dn->filter[SEL_CBUSY_SNTHROTTLE_SEL].val) |
FIELD_PREP(CMN__PMU_SN_HOME_SEL,
- dn->occupid[SEL_SN_HOME_SEL].val) |
+ dn->filter[SEL_SN_HOME_SEL].val) |
FIELD_PREP(CMN__PMU_HBT_LBT_SEL,
- dn->occupid[SEL_HBT_LBT_SEL].val) |
+ dn->filter[SEL_HBT_LBT_SEL].val) |
FIELD_PREP(CMN__PMU_CLASS_OCCUP_ID,
- dn->occupid[SEL_CLASS_OCCUP_ID].val) |
+ dn->filter[SEL_CLASS_OCCUP_ID].val) |
FIELD_PREP(CMN__PMU_OCCUP1_ID,
- dn->occupid[SEL_OCCUP1ID].val);
+ dn->filter[SEL_OCCUP1ID].val);
writel_relaxed(reg >> 32, dn->pmu_base + CMN_PMU_EVENT_SEL + 4);
- } else if (dn->occupid[fsel].val != occupid) {
+ } else if (dn->filter[fsel].val != filter) {
return -EBUSY;
}
- dn->occupid[fsel].count++;
+ dn->filter[fsel].count++;
return 0;
}
@@ -1649,7 +1652,7 @@ static void arm_cmn_event_stop(struct perf_event *event, int flags)
struct arm_cmn_val {
u8 dtm_count[CMN_MAX_DTMS];
- u8 occupid[CMN_MAX_DTMS][SEL_MAX];
+ u8 filter[CMN_MAX_DTMS][SEL_MAX];
u8 wp[CMN_MAX_DTMS][4];
u8 wp_combine[CMN_MAX_DTMS][2];
int dtc_count[CMN_MAX_DTCS];
@@ -1694,7 +1697,7 @@ static void arm_cmn_val_add_event(struct arm_cmn *cmn, struct arm_cmn_val *val,
val->dtm_count[dtm]++;
if (sel > SEL_NONE)
- val->occupid[dtm][sel] = CMN_EVENT_OCCUPID(event) + 1;
+ val->filter[dtm][sel] = CMN_EVENT_FILTER(event) + 1;
if (type != CMN_TYPE_WP)
continue;
@@ -1745,8 +1748,8 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
if (val->dtm_count[dtm] == CMN_DTM_NUM_COUNTERS)
goto done;
- if (sel > SEL_NONE && val->occupid[dtm][sel] &&
- val->occupid[dtm][sel] != CMN_EVENT_OCCUPID(event) + 1)
+ if (sel > SEL_NONE && val->filter[dtm][sel] &&
+ val->filter[dtm][sel] != CMN_EVENT_FILTER(event) + 1)
goto done;
if (type != CMN_TYPE_WP)
@@ -1892,7 +1895,7 @@ static void arm_cmn_event_clear(struct arm_cmn *cmn, struct perf_event *event,
}
if (hw->filter_sel > SEL_NONE)
- hw->dn[i].occupid[hw->filter_sel].count--;
+ hw->dn[i].filter[hw->filter_sel].count--;
dtm->pmu_config_low &= ~CMN__PMEVCNT_PAIRED(dtm_idx);
writel_relaxed(dtm->pmu_config_low, dtm->base + CMN_DTM_PMU_CONFIG);
@@ -1978,7 +1981,7 @@ static int arm_cmn_event_add(struct perf_event *event, int flags)
input_sel = CMN__PMEVCNT0_INPUT_SEL_DEV + dtm_idx +
(nid.port << 4) + (nid.dev << 2);
- if (arm_cmn_set_event_sel_hi(dn, hw->filter_sel, CMN_EVENT_OCCUPID(event)))
+ if (arm_cmn_set_event_sel_hi(dn, hw->filter_sel, CMN_EVENT_FILTER(event)))
goto free_dtms;
}
--
2.54.0.dirty
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 2/5] perf/arm-cmn: Refactor event filter programming
2026-06-30 15:19 [PATCH 0/5] perf/arm-cmn: Support CMN S3 r2 Robin Murphy
2026-06-30 15:19 ` [PATCH 1/5] perf/arm-cmn: Rename filter variables for clarity Robin Murphy
@ 2026-06-30 15:19 ` Robin Murphy
2026-06-30 15:19 ` [PATCH 3/5] perf/arm-cmn: Refactor event filter data Robin Murphy
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Robin Murphy @ 2026-06-30 15:19 UTC (permalink / raw)
To: will, mark.rutland; +Cc: linux-arm-kernel, linux-perf-users, ilkka
We're soon going to need to cope with events having multiple filters,
plus the filter fields themselves moving around, wherein any more inline
if/else logic will struggle to scale. Add a more general abstraction for
the node-specific filter controls, and rejig the pmu_event_sel filter
programming around it in a more extensible manner.
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
drivers/perf/arm-cmn.c | 139 ++++++++++++++++++++++++++++++-----------
1 file changed, 101 insertions(+), 38 deletions(-)
diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
index 2a8a67da72c3..14c267d2e2f9 100644
--- a/drivers/perf/arm-cmn.c
+++ b/drivers/perf/arm-cmn.c
@@ -278,8 +278,8 @@ enum cmn_node_type {
};
enum cmn_filter_select {
- SEL_NONE = -1,
- SEL_OCCUP1ID,
+ SEL_NONE,
+ SEL_OCCUP1_ID,
SEL_CLASS_OCCUP_ID,
SEL_CBUSY_SNTHROTTLE_SEL,
SEL_HBT_LBT_SEL,
@@ -599,6 +599,57 @@ static void arm_cmn_debugfs_init(struct arm_cmn *cmn, int id)
static void arm_cmn_debugfs_init(struct arm_cmn *cmn, int id) {}
#endif
+enum cmn_filter_type {
+ FILT_NONE,
+ FILT_OCCUP1_ID,
+ FILT_HNF_700,
+ FILT_HNS,
+};
+#define CMN_FILTER(_sel) [SEL_##_sel] = CMN__PMU_##_sel
+
+static const u64 arm_cmn_filters[][SEL_MAX] = {
+ [FILT_NONE] = {},
+ /* DVM etc. */
+ [FILT_OCCUP1_ID] = {
+ CMN_FILTER(OCCUP1_ID)
+ },
+ /* Newer HN-F */
+ [FILT_HNF_700] = {
+ CMN_FILTER(OCCUP1_ID),
+ CMN_FILTER(CLASS_OCCUP_ID),
+ CMN_FILTER(CBUSY_SNTHROTTLE_SEL)
+ },
+ /* HN-S */
+ [FILT_HNS] = {
+ CMN_FILTER(OCCUP1_ID),
+ CMN_FILTER(CLASS_OCCUP_ID),
+ CMN_FILTER(CBUSY_SNTHROTTLE_SEL),
+ CMN_FILTER(HBT_LBT_SEL),
+ CMN_FILTER(SN_HOME_SEL)
+ },
+};
+
+static enum cmn_filter_type arm_cmn_filter(enum cmn_node_type node,
+ enum cmn_model model)
+{
+ switch (node) {
+ default:
+ return FILT_NONE;
+ case CMN_TYPE_DVM:
+ case CMN_TYPE_CXRA:
+ case CMN_TYPE_CXHA:
+ case CMN_TYPE_CCRA:
+ case CMN_TYPE_CCHA:
+ return FILT_OCCUP1_ID;
+ case CMN_TYPE_HNF:
+ if (model < CMN700)
+ return FILT_OCCUP1_ID;
+ return FILT_HNF_700;
+ case CMN_TYPE_HNS:
+ return FILT_HNS;
+ };
+}
+
struct arm_cmn_hw_event {
struct arm_cmn_node *dn;
union {
@@ -708,7 +759,7 @@ static ssize_t arm_cmn_event_show(struct device *dev,
"type=0x%x,eventid=0x%x,wp_dev_sel=?,wp_chn_sel=?,wp_grp=?,wp_val=?,wp_mask=?\n",
eattr->type, eattr->eventid);
- if (eattr->fsel > SEL_NONE)
+ if (eattr->fsel)
return sysfs_emit(buf, "type=0x%x,eventid=0x%x,filter=0x%x\n",
eattr->type, eattr->eventid, eattr->filter);
@@ -832,16 +883,16 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
#define CMN_EVENT_DVM(_model, _name, _event) \
_CMN_EVENT_DVM(_model, _name, _event, 0, SEL_NONE)
#define CMN_EVENT_DVM_OCC(_model, _name, _event) \
- _CMN_EVENT_DVM(_model, _name##_all, _event, 0, SEL_OCCUP1ID), \
- _CMN_EVENT_DVM(_model, _name##_dvmop, _event, 1, SEL_OCCUP1ID), \
- _CMN_EVENT_DVM(_model, _name##_dvmsync, _event, 2, SEL_OCCUP1ID)
+ _CMN_EVENT_DVM(_model, _name##_all, _event, 0, SEL_OCCUP1_ID), \
+ _CMN_EVENT_DVM(_model, _name##_dvmop, _event, 1, SEL_OCCUP1_ID), \
+ _CMN_EVENT_DVM(_model, _name##_dvmsync, _event, 2, SEL_OCCUP1_ID)
#define CMN_EVENT_HN_OCC(_model, _name, _type, _event) \
- _CMN_EVENT_ATTR(_model, _name##_all, _type, _event, 0, SEL_OCCUP1ID), \
- _CMN_EVENT_ATTR(_model, _name##_read, _type, _event, 1, SEL_OCCUP1ID), \
- _CMN_EVENT_ATTR(_model, _name##_write, _type, _event, 2, SEL_OCCUP1ID), \
- _CMN_EVENT_ATTR(_model, _name##_atomic, _type, _event, 3, SEL_OCCUP1ID), \
- _CMN_EVENT_ATTR(_model, _name##_stash, _type, _event, 4, SEL_OCCUP1ID)
+ _CMN_EVENT_ATTR(_model, _name##_all, _type, _event, 0, SEL_OCCUP1_ID), \
+ _CMN_EVENT_ATTR(_model, _name##_read, _type, _event, 1, SEL_OCCUP1_ID), \
+ _CMN_EVENT_ATTR(_model, _name##_write, _type, _event, 2, SEL_OCCUP1_ID), \
+ _CMN_EVENT_ATTR(_model, _name##_atomic, _type, _event, 3, SEL_OCCUP1_ID), \
+ _CMN_EVENT_ATTR(_model, _name##_stash, _type, _event, 4, SEL_OCCUP1_ID)
#define CMN_EVENT_HN_CLS(_model, _name, _type, _event) \
_CMN_EVENT_ATTR(_model, _name##_class0, _type, _event, 0, SEL_CLASS_OCCUP_ID), \
_CMN_EVENT_ATTR(_model, _name##_class1, _type, _event, 1, SEL_CLASS_OCCUP_ID), \
@@ -865,9 +916,9 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
#define CMN_EVENT_HNS_OCC(_name, _event) \
CMN_EVENT_HN_OCC(CMN_ANY, hns_##_name, CMN_TYPE_HNS, _event), \
- _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_rxsnp, CMN_TYPE_HNS, _event, 5, SEL_OCCUP1ID), \
- _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_lbt, CMN_TYPE_HNS, _event, 6, SEL_OCCUP1ID), \
- _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_hbt, CMN_TYPE_HNS, _event, 7, SEL_OCCUP1ID)
+ _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_rxsnp, CMN_TYPE_HNS, _event, 5, SEL_OCCUP1_ID), \
+ _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_lbt, CMN_TYPE_HNS, _event, 6, SEL_OCCUP1_ID), \
+ _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_hbt, CMN_TYPE_HNS, _event, 7, SEL_OCCUP1_ID)
#define CMN_EVENT_HNS_CLS( _name, _event) \
CMN_EVENT_HN_CLS(CMN_ANY, hns_##_name, CMN_TYPE_HNS, _event)
#define CMN_EVENT_HNS_SNT(_name, _event) \
@@ -1547,27 +1598,20 @@ static void arm_cmn_event_read(struct perf_event *event)
}
static int arm_cmn_set_event_sel_hi(struct arm_cmn_node *dn,
- enum cmn_filter_select fsel, u8 filter)
+ enum cmn_filter_select fsel, u8 val)
{
- u64 reg;
-
- if (fsel == SEL_NONE)
- return 0;
-
if (!dn->filter[fsel].count) {
- dn->filter[fsel].val = filter;
- reg = FIELD_PREP(CMN__PMU_CBUSY_SNTHROTTLE_SEL,
- dn->filter[SEL_CBUSY_SNTHROTTLE_SEL].val) |
- FIELD_PREP(CMN__PMU_SN_HOME_SEL,
- dn->filter[SEL_SN_HOME_SEL].val) |
- FIELD_PREP(CMN__PMU_HBT_LBT_SEL,
- dn->filter[SEL_HBT_LBT_SEL].val) |
- FIELD_PREP(CMN__PMU_CLASS_OCCUP_ID,
- dn->filter[SEL_CLASS_OCCUP_ID].val) |
- FIELD_PREP(CMN__PMU_OCCUP1_ID,
- dn->filter[SEL_OCCUP1ID].val);
+ const u64 *filter = arm_cmn_filters[dn->filter[SEL_NONE].val];
+ u64 reg = 0;
+
+ dn->filter[fsel].val = val;
+ for (int i = SEL_OCCUP1_ID; i < SEL_MAX; i++) {
+ if (filter[i])
+ reg |= field_prep(filter[i], dn->filter[i].val);
+ }
+
writel_relaxed(reg >> 32, dn->pmu_base + CMN_PMU_EVENT_SEL + 4);
- } else if (dn->filter[fsel].val != filter) {
+ } else if (dn->filter[fsel].val != val) {
return -EBUSY;
}
dn->filter[fsel].count++;
@@ -1696,7 +1740,7 @@ static void arm_cmn_val_add_event(struct arm_cmn *cmn, struct arm_cmn_val *val,
val->dtm_count[dtm]++;
- if (sel > SEL_NONE)
+ if (sel)
val->filter[dtm][sel] = CMN_EVENT_FILTER(event) + 1;
if (type != CMN_TYPE_WP)
@@ -1748,7 +1792,7 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
if (val->dtm_count[dtm] == CMN_DTM_NUM_COUNTERS)
goto done;
- if (sel > SEL_NONE && val->filter[dtm][sel] &&
+ if (sel && val->filter[dtm][sel] &&
val->filter[dtm][sel] != CMN_EVENT_FILTER(event) + 1)
goto done;
@@ -1894,7 +1938,7 @@ static void arm_cmn_event_clear(struct arm_cmn *cmn, struct perf_event *event,
dtm->wp_event[wp_idx] = -1;
}
- if (hw->filter_sel > SEL_NONE)
+ if (hw->filter_sel)
hw->dn[i].filter[hw->filter_sel].count--;
dtm->pmu_config_low &= ~CMN__PMEVCNT_PAIRED(dtm_idx);
@@ -1906,6 +1950,17 @@ static void arm_cmn_event_clear(struct arm_cmn *cmn, struct perf_event *event,
cmn->dtc[j].counters[idx] = NULL;
}
+static int arm_cmn_set_event_filter(struct arm_cmn_node *dn, struct perf_event *event)
+{
+ enum cmn_filter_select fsel = to_cmn_hw(event)->filter_sel;
+ int ret = 0;
+
+ if (fsel)
+ ret = arm_cmn_set_event_sel_hi(dn, fsel, CMN_EVENT_FILTER(event));
+
+ return ret;
+}
+
static int arm_cmn_event_add(struct perf_event *event, int flags)
{
struct arm_cmn *cmn = to_cmn(event->pmu);
@@ -1981,7 +2036,7 @@ static int arm_cmn_event_add(struct perf_event *event, int flags)
input_sel = CMN__PMEVCNT0_INPUT_SEL_DEV + dtm_idx +
(nid.port << 4) + (nid.dev << 2);
- if (arm_cmn_set_event_sel_hi(dn, hw->filter_sel, CMN_EVENT_FILTER(event)))
+ if (arm_cmn_set_event_filter(dn, event))
goto free_dtms;
}
@@ -2311,6 +2366,7 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
void __iomem *cfg_region, __iomem *xp_region;
struct arm_cmn_node cfg, *dn;
struct arm_cmn_dtm *dtm;
+ enum cmn_model model;
enum cmn_part part;
u16 child_count, child_poff;
u64 reg;
@@ -2342,12 +2398,14 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
"Firmware binding mismatch: expected part number 0x%x, found 0x%x\n",
cmn->part, part);
cmn->part = part;
- if (!arm_cmn_model(cmn))
- dev_warn(cmn->dev, "Unknown part number: 0x%x\n", part);
reg = readl_relaxed(cfg_region + CMN_CFGM_PERIPH_ID_23);
cmn->rev = FIELD_GET(CMN_CFGM_PID2_REVISION, reg);
+ model = arm_cmn_model(cmn);
+ if (!model)
+ dev_warn(cmn->dev, "Unknown part number: 0x%x\n", part);
+
/*
* With the device isolation feature, if firmware has neglected to enable
* an XP port then we risk locking up if we try to access anything behind
@@ -2500,6 +2558,11 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
dev_err(cmn->dev, "Node ID invalid for supported CMN versions: %d\n", dn->logid);
return -ENODEV;
}
+ /*
+ * We can utilise the "wasted" filter array slot to store
+ * the index for referencing the filter encodings later.
+ */
+ dn->filter[SEL_NONE].val = arm_cmn_filter(dn->type, model);
switch (dn->type) {
case CMN_TYPE_DTC:
--
2.54.0.dirty
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 3/5] perf/arm-cmn: Refactor event filter data
2026-06-30 15:19 [PATCH 0/5] perf/arm-cmn: Support CMN S3 r2 Robin Murphy
2026-06-30 15:19 ` [PATCH 1/5] perf/arm-cmn: Rename filter variables for clarity Robin Murphy
2026-06-30 15:19 ` [PATCH 2/5] perf/arm-cmn: Refactor event filter programming Robin Murphy
@ 2026-06-30 15:19 ` Robin Murphy
2026-06-30 15:19 ` [PATCH 4/5] perf/arm-cmn: Add new filters Robin Murphy
2026-06-30 15:19 ` [PATCH 5/5] perf/arm-cmn: Support CMN S3 r2 Robin Murphy
4 siblings, 0 replies; 6+ messages in thread
From: Robin Murphy @ 2026-06-30 15:19 UTC (permalink / raw)
To: will, mark.rutland; +Cc: linux-arm-kernel, linux-perf-users, ilkka
The ABI hole I have dug myself into requires the driver to know which
event encodings are associated with which particular filter control.
Since we will soon have a notion of multiple filters per event, refactor
the event data to encapsulate filters in an explicit structure, which
can then more easily scale as an array in future.
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
drivers/perf/arm-cmn.c | 95 ++++++++++++++++++++++--------------------
1 file changed, 49 insertions(+), 46 deletions(-)
diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
index 14c267d2e2f9..4ba78df87045 100644
--- a/drivers/perf/arm-cmn.c
+++ b/drivers/perf/arm-cmn.c
@@ -717,13 +717,17 @@ static void arm_cmn_clear_idx(struct arm_cmn_hw_event *hw)
bitmap_zero(hw->wp_idx, CMN_MAX_XPS);
}
+struct arm_cmn_filter_attr {
+ enum cmn_filter_select sel;
+ u8 val;
+};
+
struct arm_cmn_event_attr {
struct device_attribute attr;
enum cmn_model model;
enum cmn_node_type type;
- enum cmn_filter_select fsel;
u16 eventid;
- u8 filter;
+ struct arm_cmn_filter_attr filter[1];
};
struct arm_cmn_format_attr {
@@ -732,24 +736,25 @@ struct arm_cmn_format_attr {
int config;
};
-#define _CMN_EVENT_ATTR(_model, _name, _type, _eventid, _filter, _fsel)\
+#define _CMN_EVENT_ATTR(_model, _name, _type, _eventid, _filter, ...) \
(&((struct arm_cmn_event_attr[]) {{ \
.attr = __ATTR(_name, 0444, arm_cmn_event_show, NULL), \
.model = _model, \
.type = _type, \
.eventid = _eventid, \
- .filter = _filter, \
- .fsel = _fsel, \
+ .filter = {{_filter}}, \
}})[0].attr.attr)
-#define CMN_EVENT_ATTR(_model, _name, _type, _eventid) \
- _CMN_EVENT_ATTR(_model, _name, _type, _eventid, 0, SEL_NONE)
+#define CMN_EVENT_ATTR(_model, _name, _type, _eventid, _filter...) \
+ _CMN_EVENT_ATTR(_model, _name, _type, _eventid, ##_filter, 0, 0)
static ssize_t arm_cmn_event_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct arm_cmn_event_attr *eattr;
+ struct arm_cmn_filter_attr *filter;
eattr = container_of(attr, typeof(*eattr), attr);
+ filter = eattr->filter;
if (eattr->type == CMN_TYPE_DTC)
return sysfs_emit(buf, "type=0x%x\n", eattr->type);
@@ -759,9 +764,9 @@ static ssize_t arm_cmn_event_show(struct device *dev,
"type=0x%x,eventid=0x%x,wp_dev_sel=?,wp_chn_sel=?,wp_grp=?,wp_val=?,wp_mask=?\n",
eattr->type, eattr->eventid);
- if (eattr->fsel)
+ if (filter[0].sel)
return sysfs_emit(buf, "type=0x%x,eventid=0x%x,filter=0x%x\n",
- eattr->type, eattr->eventid, eattr->filter);
+ eattr->type, eattr->eventid, filter[0].val);
return sysfs_emit(buf, "type=0x%x,eventid=0x%x\n", eattr->type,
eattr->eventid);
@@ -849,8 +854,8 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
return attr->mode;
}
-#define _CMN_EVENT_DVM(_model, _name, _event, _occup, _fsel) \
- _CMN_EVENT_ATTR(_model, dn_##_name, CMN_TYPE_DVM, _event, _occup, _fsel)
+#define CMN_EVENT_DVM(_model, _name, _event, _filter...) \
+ CMN_EVENT_ATTR(_model, dn_##_name, CMN_TYPE_DVM, _event, ##_filter)
#define CMN_EVENT_DTC(_name) \
CMN_EVENT_ATTR(CMN_ANY, dtc_##_name, CMN_TYPE_DTC, 0)
#define CMN_EVENT_HNF(_model, _name, _event) \
@@ -880,32 +885,30 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
#define CMN_EVENT_HNS(_name, _event) \
CMN_EVENT_ATTR(CMN_ANY, hns_##_name, CMN_TYPE_HNS, _event)
-#define CMN_EVENT_DVM(_model, _name, _event) \
- _CMN_EVENT_DVM(_model, _name, _event, 0, SEL_NONE)
#define CMN_EVENT_DVM_OCC(_model, _name, _event) \
- _CMN_EVENT_DVM(_model, _name##_all, _event, 0, SEL_OCCUP1_ID), \
- _CMN_EVENT_DVM(_model, _name##_dvmop, _event, 1, SEL_OCCUP1_ID), \
- _CMN_EVENT_DVM(_model, _name##_dvmsync, _event, 2, SEL_OCCUP1_ID)
+ CMN_EVENT_DVM(_model, _name##_all, _event, SEL_OCCUP1_ID, 0), \
+ CMN_EVENT_DVM(_model, _name##_dvmop, _event, SEL_OCCUP1_ID, 1), \
+ CMN_EVENT_DVM(_model, _name##_dvmsync, _event, SEL_OCCUP1_ID, 2)
#define CMN_EVENT_HN_OCC(_model, _name, _type, _event) \
- _CMN_EVENT_ATTR(_model, _name##_all, _type, _event, 0, SEL_OCCUP1_ID), \
- _CMN_EVENT_ATTR(_model, _name##_read, _type, _event, 1, SEL_OCCUP1_ID), \
- _CMN_EVENT_ATTR(_model, _name##_write, _type, _event, 2, SEL_OCCUP1_ID), \
- _CMN_EVENT_ATTR(_model, _name##_atomic, _type, _event, 3, SEL_OCCUP1_ID), \
- _CMN_EVENT_ATTR(_model, _name##_stash, _type, _event, 4, SEL_OCCUP1_ID)
+ CMN_EVENT_ATTR(_model, _name##_all, _type, _event, SEL_OCCUP1_ID, 0), \
+ CMN_EVENT_ATTR(_model, _name##_read, _type, _event, SEL_OCCUP1_ID, 1), \
+ CMN_EVENT_ATTR(_model, _name##_write, _type, _event, SEL_OCCUP1_ID, 2), \
+ CMN_EVENT_ATTR(_model, _name##_atomic, _type, _event, SEL_OCCUP1_ID, 3), \
+ CMN_EVENT_ATTR(_model, _name##_stash, _type, _event, SEL_OCCUP1_ID, 4)
#define CMN_EVENT_HN_CLS(_model, _name, _type, _event) \
- _CMN_EVENT_ATTR(_model, _name##_class0, _type, _event, 0, SEL_CLASS_OCCUP_ID), \
- _CMN_EVENT_ATTR(_model, _name##_class1, _type, _event, 1, SEL_CLASS_OCCUP_ID), \
- _CMN_EVENT_ATTR(_model, _name##_class2, _type, _event, 2, SEL_CLASS_OCCUP_ID), \
- _CMN_EVENT_ATTR(_model, _name##_class3, _type, _event, 3, SEL_CLASS_OCCUP_ID)
+ CMN_EVENT_ATTR(_model, _name##_class0, _type, _event, SEL_CLASS_OCCUP_ID, 0), \
+ CMN_EVENT_ATTR(_model, _name##_class1, _type, _event, SEL_CLASS_OCCUP_ID, 1), \
+ CMN_EVENT_ATTR(_model, _name##_class2, _type, _event, SEL_CLASS_OCCUP_ID, 2), \
+ CMN_EVENT_ATTR(_model, _name##_class3, _type, _event, SEL_CLASS_OCCUP_ID, 3)
#define CMN_EVENT_HN_SNT(_model, _name, _type, _event) \
- _CMN_EVENT_ATTR(_model, _name##_all, _type, _event, 0, SEL_CBUSY_SNTHROTTLE_SEL), \
- _CMN_EVENT_ATTR(_model, _name##_group0_read, _type, _event, 1, SEL_CBUSY_SNTHROTTLE_SEL), \
- _CMN_EVENT_ATTR(_model, _name##_group0_write, _type, _event, 2, SEL_CBUSY_SNTHROTTLE_SEL), \
- _CMN_EVENT_ATTR(_model, _name##_group1_read, _type, _event, 3, SEL_CBUSY_SNTHROTTLE_SEL), \
- _CMN_EVENT_ATTR(_model, _name##_group1_write, _type, _event, 4, SEL_CBUSY_SNTHROTTLE_SEL), \
- _CMN_EVENT_ATTR(_model, _name##_read, _type, _event, 5, SEL_CBUSY_SNTHROTTLE_SEL), \
- _CMN_EVENT_ATTR(_model, _name##_write, _type, _event, 6, SEL_CBUSY_SNTHROTTLE_SEL)
+ CMN_EVENT_ATTR(_model, _name##_all, _type, _event, SEL_CBUSY_SNTHROTTLE_SEL, 0), \
+ CMN_EVENT_ATTR(_model, _name##_group0_read, _type, _event, SEL_CBUSY_SNTHROTTLE_SEL, 1), \
+ CMN_EVENT_ATTR(_model, _name##_group0_write, _type, _event, SEL_CBUSY_SNTHROTTLE_SEL, 2), \
+ CMN_EVENT_ATTR(_model, _name##_group1_read, _type, _event, SEL_CBUSY_SNTHROTTLE_SEL, 3), \
+ CMN_EVENT_ATTR(_model, _name##_group1_write, _type, _event, SEL_CBUSY_SNTHROTTLE_SEL, 4), \
+ CMN_EVENT_ATTR(_model, _name##_read, _type, _event, SEL_CBUSY_SNTHROTTLE_SEL, 5), \
+ CMN_EVENT_ATTR(_model, _name##_write, _type, _event, SEL_CBUSY_SNTHROTTLE_SEL, 6)
#define CMN_EVENT_HNF_OCC(_model, _name, _event) \
CMN_EVENT_HN_OCC(_model, hnf_##_name, CMN_TYPE_HNF, _event)
@@ -916,21 +919,21 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
#define CMN_EVENT_HNS_OCC(_name, _event) \
CMN_EVENT_HN_OCC(CMN_ANY, hns_##_name, CMN_TYPE_HNS, _event), \
- _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_rxsnp, CMN_TYPE_HNS, _event, 5, SEL_OCCUP1_ID), \
- _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_lbt, CMN_TYPE_HNS, _event, 6, SEL_OCCUP1_ID), \
- _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_hbt, CMN_TYPE_HNS, _event, 7, SEL_OCCUP1_ID)
+ CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_rxsnp, CMN_TYPE_HNS, _event, SEL_OCCUP1_ID, 5), \
+ CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_lbt, CMN_TYPE_HNS, _event, SEL_OCCUP1_ID, 6), \
+ CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_hbt, CMN_TYPE_HNS, _event, SEL_OCCUP1_ID, 7)
#define CMN_EVENT_HNS_CLS( _name, _event) \
CMN_EVENT_HN_CLS(CMN_ANY, hns_##_name, CMN_TYPE_HNS, _event)
#define CMN_EVENT_HNS_SNT(_name, _event) \
CMN_EVENT_HN_SNT(CMN_ANY, hns_##_name, CMN_TYPE_HNS, _event)
#define CMN_EVENT_HNS_HBT(_name, _event) \
- _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_all, CMN_TYPE_HNS, _event, 0, SEL_HBT_LBT_SEL), \
- _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_hbt, CMN_TYPE_HNS, _event, 1, SEL_HBT_LBT_SEL), \
- _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_lbt, CMN_TYPE_HNS, _event, 2, SEL_HBT_LBT_SEL)
+ CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_all, CMN_TYPE_HNS, _event, SEL_HBT_LBT_SEL, 0), \
+ CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_hbt, CMN_TYPE_HNS, _event, SEL_HBT_LBT_SEL, 1), \
+ CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_lbt, CMN_TYPE_HNS, _event, SEL_HBT_LBT_SEL, 2)
#define CMN_EVENT_HNS_SNH(_name, _event) \
- _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_all, CMN_TYPE_HNS, _event, 0, SEL_SN_HOME_SEL), \
- _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_sn, CMN_TYPE_HNS, _event, 1, SEL_SN_HOME_SEL), \
- _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_home, CMN_TYPE_HNS, _event, 2, SEL_SN_HOME_SEL)
+ CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_all, CMN_TYPE_HNS, _event, SEL_SN_HOME_SEL, 0), \
+ CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_sn, CMN_TYPE_HNS, _event, SEL_SN_HOME_SEL, 1), \
+ CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_home, CMN_TYPE_HNS, _event, SEL_SN_HOME_SEL, 2)
#define _CMN_EVENT_XP_MESH(_name, _event) \
__CMN_EVENT_XP(e_##_name, (_event) | (0 << 2)), \
@@ -1814,9 +1817,9 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
return ret;
}
-static enum cmn_filter_select arm_cmn_filter_sel(const struct arm_cmn *cmn,
- enum cmn_node_type type,
- unsigned int eventid)
+static enum cmn_filter_select arm_cmn_event_filter(const struct arm_cmn *cmn,
+ enum cmn_node_type type,
+ unsigned int eventid)
{
struct arm_cmn_event_attr *e;
enum cmn_model model = arm_cmn_model(cmn);
@@ -1824,7 +1827,7 @@ static enum cmn_filter_select arm_cmn_filter_sel(const struct arm_cmn *cmn,
for (int i = 0; i < ARRAY_SIZE(arm_cmn_event_attrs) - 1; i++) {
e = container_of(arm_cmn_event_attrs[i], typeof(*e), attr.attr);
if (e->model & model && e->type == type && e->eventid == eventid)
- return e->fsel;
+ return e->filter[0].sel;
}
return SEL_NONE;
}
@@ -1889,7 +1892,7 @@ static int arm_cmn_event_init(struct perf_event *event)
}
/* This is sufficiently annoying to recalculate, so cache it */
- hw->filter_sel = arm_cmn_filter_sel(cmn, type, eventid);
+ hw->filter_sel = arm_cmn_event_filter(cmn, type, eventid);
bynodeid = CMN_EVENT_BYNODEID(event);
nodeid = CMN_EVENT_NODEID(event);
--
2.54.0.dirty
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 4/5] perf/arm-cmn: Add new filters
2026-06-30 15:19 [PATCH 0/5] perf/arm-cmn: Support CMN S3 r2 Robin Murphy
` (2 preceding siblings ...)
2026-06-30 15:19 ` [PATCH 3/5] perf/arm-cmn: Refactor event filter data Robin Murphy
@ 2026-06-30 15:19 ` Robin Murphy
2026-06-30 15:19 ` [PATCH 5/5] perf/arm-cmn: Support CMN S3 r2 Robin Murphy
4 siblings, 0 replies; 6+ messages in thread
From: Robin Murphy @ 2026-06-30 15:19 UTC (permalink / raw)
To: will, mark.rutland; +Cc: linux-arm-kernel, linux-perf-users, ilkka
Add the logic to handle events with the upcoming new filter controls.
Since for now we will have the sole invariant of all EVICT_STATE_SEL
events having HBT_LBT_SEL as a secondary filter, for the sake of
simplicity we can just special-case that, and save the complication
of a full abstraction until unavoidably necessary.
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
drivers/perf/arm-cmn.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
index 4ba78df87045..c935ddcf462a 100644
--- a/drivers/perf/arm-cmn.c
+++ b/drivers/perf/arm-cmn.c
@@ -166,12 +166,14 @@
#define CMN_CONFIG_FILTER GENMASK_ULL(30, 27)
#define CMN_CONFIG_BYNODEID BIT_ULL(31)
#define CMN_CONFIG_NODEID GENMASK_ULL(47, 32)
+#define CMN_CONFIG_FILTER2 GENMASK_ULL(51, 48)
#define CMN_EVENT_TYPE(event) FIELD_GET(CMN_CONFIG_TYPE, (event)->attr.config)
#define CMN_EVENT_EVENTID(event) FIELD_GET(CMN_CONFIG_EVENTID, (event)->attr.config)
#define CMN_EVENT_FILTER(event) FIELD_GET(CMN_CONFIG_FILTER, (event)->attr.config)
#define CMN_EVENT_BYNODEID(event) FIELD_GET(CMN_CONFIG_BYNODEID, (event)->attr.config)
#define CMN_EVENT_NODEID(event) FIELD_GET(CMN_CONFIG_NODEID, (event)->attr.config)
+#define CMN_EVENT_FILTER2(event) FIELD_GET(CMN_CONFIG_FILTER2, (event)->attr.config)
#define CMN_CONFIG_WP_COMBINE GENMASK_ULL(30, 27)
#define CMN_CONFIG_WP_DEV_SEL GENMASK_ULL(50, 48)
@@ -284,6 +286,9 @@ enum cmn_filter_select {
SEL_CBUSY_SNTHROTTLE_SEL,
SEL_HBT_LBT_SEL,
SEL_SN_HOME_SEL,
+ SEL_SNP_VC_SEL,
+ SEL_ENHANCED_HBT_LBT_SEL,
+ SEL_EVICT_STATE_SEL,
SEL_MAX
};
@@ -1377,6 +1382,7 @@ static struct attribute *arm_cmn_format_attrs[] = {
CMN_FORMAT_ATTR(filter, CMN_CONFIG_FILTER),
CMN_FORMAT_ATTR(bynodeid, CMN_CONFIG_BYNODEID),
CMN_FORMAT_ATTR(nodeid, CMN_CONFIG_NODEID),
+ CMN_FORMAT_ATTR(filter2, CMN_CONFIG_FILTER2),
CMN_FORMAT_ATTR(wp_dev_sel, CMN_CONFIG_WP_DEV_SEL),
CMN_FORMAT_ATTR(wp_chn_sel, CMN_CONFIG_WP_CHN_SEL),
@@ -1745,6 +1751,8 @@ static void arm_cmn_val_add_event(struct arm_cmn *cmn, struct arm_cmn_val *val,
if (sel)
val->filter[dtm][sel] = CMN_EVENT_FILTER(event) + 1;
+ if (sel == SEL_EVICT_STATE_SEL)
+ val->filter[dtm][SEL_HBT_LBT_SEL] = CMN_EVENT_FILTER2(event) + 1;
if (type != CMN_TYPE_WP)
continue;
@@ -1799,6 +1807,10 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
val->filter[dtm][sel] != CMN_EVENT_FILTER(event) + 1)
goto done;
+ if (sel == SEL_EVICT_STATE_SEL && val->filter[dtm][SEL_HBT_LBT_SEL] &&
+ val->filter[dtm][SEL_HBT_LBT_SEL] != CMN_EVENT_FILTER2(event) + 1)
+ goto done;
+
if (type != CMN_TYPE_WP)
continue;
@@ -1943,6 +1955,8 @@ static void arm_cmn_event_clear(struct arm_cmn *cmn, struct perf_event *event,
if (hw->filter_sel)
hw->dn[i].filter[hw->filter_sel].count--;
+ if (hw->filter_sel == SEL_EVICT_STATE_SEL)
+ hw->dn[i].filter[SEL_HBT_LBT_SEL].count--;
dtm->pmu_config_low &= ~CMN__PMEVCNT_PAIRED(dtm_idx);
writel_relaxed(dtm->pmu_config_low, dtm->base + CMN_DTM_PMU_CONFIG);
@@ -1961,6 +1975,11 @@ static int arm_cmn_set_event_filter(struct arm_cmn_node *dn, struct perf_event *
if (fsel)
ret = arm_cmn_set_event_sel_hi(dn, fsel, CMN_EVENT_FILTER(event));
+ if (fsel == SEL_EVICT_STATE_SEL && !ret) {
+ ret = arm_cmn_set_event_sel_hi(dn, SEL_HBT_LBT_SEL, CMN_EVENT_FILTER2(event));
+ if (ret)
+ dn->filter[fsel].count--;
+ }
return ret;
}
--
2.54.0.dirty
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 5/5] perf/arm-cmn: Support CMN S3 r2
2026-06-30 15:19 [PATCH 0/5] perf/arm-cmn: Support CMN S3 r2 Robin Murphy
` (3 preceding siblings ...)
2026-06-30 15:19 ` [PATCH 4/5] perf/arm-cmn: Add new filters Robin Murphy
@ 2026-06-30 15:19 ` Robin Murphy
4 siblings, 0 replies; 6+ messages in thread
From: Robin Murphy @ 2026-06-30 15:19 UTC (permalink / raw)
To: will, mark.rutland; +Cc: linux-arm-kernel, linux-perf-users, ilkka
If you were disappointed at how minimal the initial CMN S3 support
looked compared to previous versions, then oh boy is it time to put your
party hats on... The biggest batch of incompatible changes yet comes not
with a new CMN product, but a point release of an existing one. We've
got new filters, loads of changes to existing events, register fields
moved around for no good reason, and much, much more! On the upside, we
do at least gain a means of working around the isolation feature.
As such, for the sake of sanity in the driver it is easiest to split it
into a distict "model" for our internal abstractions despite it bearing
the same part number as r0/r1.
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
drivers/perf/arm-cmn.c | 270 +++++++++++++++++++++++++++++------------
1 file changed, 193 insertions(+), 77 deletions(-)
diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
index c935ddcf462a..a03e2a8ca41e 100644
--- a/drivers/perf/arm-cmn.c
+++ b/drivers/perf/arm-cmn.c
@@ -29,6 +29,7 @@
#define CMN_CI_CHILD_PTR_OFFSET GENMASK_ULL(31, 16)
#define CMN_CHILD_NODE_ADDR GENMASK(29, 0)
+#define CMN_CHILD_NODE_ISOLATED BIT(30)
#define CMN_CHILD_NODE_EXTERNAL BIT(31)
/* Some implementations use a mesh larger than the architectural max of 12 */
@@ -48,11 +49,16 @@
#define CMN_CFGM_INFO_GLOBAL 0x0900
#define CMN_INFO_MULTIPLE_DTM_EN BIT_ULL(63)
+#define CMN_S3_R2_MULTIPLE_DTM_EN BIT_ULL(59)
#define CMN_INFO_RSP_VC_NUM GENMASK_ULL(53, 52)
#define CMN_INFO_DAT_VC_NUM GENMASK_ULL(51, 50)
#define CMN_INFO_DEVICE_ISO_ENABLE BIT_ULL(44)
#define CMN_CFGM_INFO_GLOBAL_1 0x0908
+#define CMN_S3_R2_RSP_VC_NUM GENMASK_ULL(11, 9)
+#define CMN_S3_R2_DAT_VC_NUM GENMASK_ULL(8, 6)
+#define CMN_S3_R2_SNP_VC_NUM GENMASK_ULL(5, 3)
+#define CMN_S3_R2_REQ_VC_NUM GENMASK_ULL(2, 0)
#define CMN_INFO_SNP_VC_NUM GENMASK_ULL(3, 2)
#define CMN_INFO_REQ_VC_NUM GENMASK_ULL(1, 0)
@@ -78,6 +84,16 @@
/* Technically this is 4 bits wide on DNs, but we only use 2 there anyway */
#define CMN__PMU_OCCUP1_ID GENMASK_ULL(34, 32)
+/* But then... */
+#define CMN__PMU_EVICT_STATE_SEL GENMASK_ULL(54, 52)
+#define CMN__PMU_ENHANCED_HBT_LBT_SEL GENMASK_ULL(51, 48)
+#define CMN__PMU_SNP_VC_SEL GENMASK_ULL(47, 46)
+#define CMN__S3_R2_CBUSY_SNTHROTTLE_SEL GENMASK_ULL(45, 42)
+#define CMN__S3_R2_SN_HOME_SEL GENMASK_ULL(41, 40)
+#define CMN__S3_R2_HBT_LBT_SEL GENMASK_ULL(39, 38)
+#define CMN__S3_R2_CLASS_OCCUP_ID GENMASK_ULL(37, 36)
+#define CMN__S3_R2_OCCUP1_ID GENMASK_ULL(35, 32)
+
/* Some types are designed to coexist with another device in the same node */
#define CMN_CCLA_PMU_EVENT_SEL 0x008
#define CMN_HNP_PMU_EVENT_SEL 0x008
@@ -202,12 +218,14 @@ enum cmn_model {
CMN650 = 2,
CI700 = 4,
CMN700 = 8,
- CMNS3 = 16,
+ CMNS3R01 = 16,
+ CMNS3R2 = 32,
/* ...and then we can use bitmap tricks for commonality */
CMN_ANY = -1,
NOT_CMN600 = -2,
CMN_700ON = ~(CMN700 - 1),
CMN_650ON = CMN_700ON | CMN650,
+ CMNS3 = CMNS3R01 | CMNS3R2,
};
/* Actual part numbers and revision IDs defined by the hardware */
@@ -243,6 +261,10 @@ enum cmn_revision {
REV_CMNS3_R0P0 = 0,
REV_CMNS3_R0P1,
REV_CMNS3_R1P0,
+ REV_CMNS3_R2P0,
+ REV_CMNS3_R2P1,
+ REV_CMNS3_R2P2,
+ REV_CMNS3_R2P5,
REV_CI700_R0P0 = 0,
REV_CI700_R1P0,
REV_CI700_R2P0,
@@ -429,7 +451,9 @@ static enum cmn_model arm_cmn_model(const struct arm_cmn *cmn)
case PART_CI700:
return CI700;
case PART_CMN_S3:
- return CMNS3;
+ if (cmn->rev >= REV_CMNS3_R2P0)
+ return CMNS3R2;
+ return CMNS3R01;
default:
return 0;
};
@@ -609,8 +633,10 @@ enum cmn_filter_type {
FILT_OCCUP1_ID,
FILT_HNF_700,
FILT_HNS,
+ FILT_HNS_S3R2,
};
#define CMN_FILTER(_sel) [SEL_##_sel] = CMN__PMU_##_sel
+#define CMN_FILTER_V2(_sel) [SEL_##_sel] = CMN__S3_R2_##_sel
static const u64 arm_cmn_filters[][SEL_MAX] = {
[FILT_NONE] = {},
@@ -632,6 +658,17 @@ static const u64 arm_cmn_filters[][SEL_MAX] = {
CMN_FILTER(HBT_LBT_SEL),
CMN_FILTER(SN_HOME_SEL)
},
+ /* Newer HN-S */
+ [FILT_HNS_S3R2] = {
+ CMN_FILTER_V2(OCCUP1_ID),
+ CMN_FILTER_V2(CLASS_OCCUP_ID),
+ CMN_FILTER_V2(CBUSY_SNTHROTTLE_SEL),
+ CMN_FILTER_V2(HBT_LBT_SEL),
+ CMN_FILTER_V2(SN_HOME_SEL),
+ CMN_FILTER(SNP_VC_SEL),
+ CMN_FILTER(ENHANCED_HBT_LBT_SEL),
+ CMN_FILTER(EVICT_STATE_SEL)
+ }
};
static enum cmn_filter_type arm_cmn_filter(enum cmn_node_type node,
@@ -651,7 +688,9 @@ static enum cmn_filter_type arm_cmn_filter(enum cmn_node_type node,
return FILT_OCCUP1_ID;
return FILT_HNF_700;
case CMN_TYPE_HNS:
- return FILT_HNS;
+ if (model < CMNS3R2)
+ return FILT_HNS;
+ return FILT_HNS_S3R2;
};
}
@@ -732,7 +771,7 @@ struct arm_cmn_event_attr {
enum cmn_model model;
enum cmn_node_type type;
u16 eventid;
- struct arm_cmn_filter_attr filter[1];
+ struct arm_cmn_filter_attr filter[2];
};
struct arm_cmn_format_attr {
@@ -741,16 +780,16 @@ struct arm_cmn_format_attr {
int config;
};
-#define _CMN_EVENT_ATTR(_model, _name, _type, _eventid, _filter, ...) \
+#define _CMN_EVENT_ATTR(_model, _name, _type, _eventid, _fa, _fb, _fc, _fd, ...) \
(&((struct arm_cmn_event_attr[]) {{ \
.attr = __ATTR(_name, 0444, arm_cmn_event_show, NULL), \
.model = _model, \
.type = _type, \
.eventid = _eventid, \
- .filter = {{_filter}}, \
+ .filter = {{_fa, _fb}, {_fc, _fd}}, \
}})[0].attr.attr)
#define CMN_EVENT_ATTR(_model, _name, _type, _eventid, _filter...) \
- _CMN_EVENT_ATTR(_model, _name, _type, _eventid, ##_filter, 0, 0)
+ _CMN_EVENT_ATTR(_model, _name, _type, _eventid, ##_filter, 0, 0, 0, 0)
static ssize_t arm_cmn_event_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -769,6 +808,10 @@ static ssize_t arm_cmn_event_show(struct device *dev,
"type=0x%x,eventid=0x%x,wp_dev_sel=?,wp_chn_sel=?,wp_grp=?,wp_val=?,wp_mask=?\n",
eattr->type, eattr->eventid);
+ if (filter[1].sel)
+ return sysfs_emit(buf, "type=0x%x,eventid=0x%x,filter=0x%x,filter2=0x%x\n",
+ eattr->type, eattr->eventid, filter[0].val, filter[1].val);
+
if (filter[0].sel)
return sysfs_emit(buf, "type=0x%x,eventid=0x%x,filter=0x%x\n",
eattr->type, eattr->eventid, filter[0].val);
@@ -887,8 +930,8 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
CMN_EVENT_ATTR(_model, ccha_##_name, CMN_TYPE_CCHA, _event)
#define CMN_EVENT_CCLA(_name, _event) \
CMN_EVENT_ATTR(CMN_ANY, ccla_##_name, CMN_TYPE_CCLA, _event)
-#define CMN_EVENT_HNS(_name, _event) \
- CMN_EVENT_ATTR(CMN_ANY, hns_##_name, CMN_TYPE_HNS, _event)
+#define _CMN_EVENT_HNS(_model, _name, _event, _filter...) \
+ CMN_EVENT_ATTR(_model, hns_##_name, CMN_TYPE_HNS, _event, ##_filter)
#define CMN_EVENT_DVM_OCC(_model, _name, _event) \
CMN_EVENT_DVM(_model, _name##_all, _event, SEL_OCCUP1_ID, 0), \
@@ -913,7 +956,12 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
CMN_EVENT_ATTR(_model, _name##_group1_read, _type, _event, SEL_CBUSY_SNTHROTTLE_SEL, 3), \
CMN_EVENT_ATTR(_model, _name##_group1_write, _type, _event, SEL_CBUSY_SNTHROTTLE_SEL, 4), \
CMN_EVENT_ATTR(_model, _name##_read, _type, _event, SEL_CBUSY_SNTHROTTLE_SEL, 5), \
- CMN_EVENT_ATTR(_model, _name##_write, _type, _event, SEL_CBUSY_SNTHROTTLE_SEL, 6)
+ CMN_EVENT_ATTR(_model, _name##_write, _type, _event, SEL_CBUSY_SNTHROTTLE_SEL, 6), \
+ CMN_EVENT_ATTR(CMNS3R2, _name##_ccg_read, _type, _event, SEL_CBUSY_SNTHROTTLE_SEL, 9), \
+ CMN_EVENT_ATTR(CMNS3R2, _name##_ccg_write, _type, _event, SEL_CBUSY_SNTHROTTLE_SEL, 10), \
+ CMN_EVENT_ATTR(CMNS3R2, _name##_lbt_read, _type, _event, SEL_CBUSY_SNTHROTTLE_SEL, 11), \
+ CMN_EVENT_ATTR(CMNS3R2, _name##_lbt_write, _type, _event, SEL_CBUSY_SNTHROTTLE_SEL, 12), \
+ CMN_EVENT_ATTR(CMNS3R2, _name##_lbt, _type, _event, SEL_CBUSY_SNTHROTTLE_SEL, 13)
#define CMN_EVENT_HNF_OCC(_model, _name, _event) \
CMN_EVENT_HN_OCC(_model, hnf_##_name, CMN_TYPE_HNF, _event)
@@ -922,23 +970,75 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
#define CMN_EVENT_HNF_SNT(_model, _name, _event) \
CMN_EVENT_HN_SNT(_model, hnf_##_name, CMN_TYPE_HNF, _event)
-#define CMN_EVENT_HNS_OCC(_name, _event) \
- CMN_EVENT_HN_OCC(CMN_ANY, hns_##_name, CMN_TYPE_HNS, _event), \
- CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_rxsnp, CMN_TYPE_HNS, _event, SEL_OCCUP1_ID, 5), \
- CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_lbt, CMN_TYPE_HNS, _event, SEL_OCCUP1_ID, 6), \
- CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_hbt, CMN_TYPE_HNS, _event, SEL_OCCUP1_ID, 7)
+#define CMN_EVENT_HNS(_name, _event) \
+ _CMN_EVENT_HNS(CMN_ANY, _name, _event)
+#define CMN_EVENT_HNSR0(_name, _event) \
+ _CMN_EVENT_HNS(CMN700 | CMNS3R01, _name, _event)
+#define _CMN_EVENT_HNS_HBT(_model, _name, _event, _sel) \
+ _CMN_EVENT_HNS(_model, _name##_all, _event, _sel, 0), \
+ _CMN_EVENT_HNS(_model, _name##_hbt, _event, _sel, 1), \
+ _CMN_EVENT_HNS(_model, _name##_lbt, _event, _sel, 2)
+#define _CMN_EVENT_HNS_HBT2(_model, _name, _event, _fsel1, f1) \
+ _CMN_EVENT_HNS(_model, _name##_all, _event, _fsel1, f1, SEL_HBT_LBT_SEL, 0), \
+ _CMN_EVENT_HNS(_model, _name##_hbt, _event, _fsel1, f1, SEL_HBT_LBT_SEL, 1), \
+ _CMN_EVENT_HNS(_model, _name##_lbt, _event, _fsel1, f1, SEL_HBT_LBT_SEL, 2)
+
+#define CMN_EVENT_HNS_OCC(_model, _name, _event) \
+ CMN_EVENT_HN_OCC(_model, hns_##_name, CMN_TYPE_HNS, _event), \
+ _CMN_EVENT_HNS(_model, _name##_rxsnp, _event, SEL_OCCUP1_ID, 5), \
+ _CMN_EVENT_HNS(_model, _name##_lbt, _event, SEL_OCCUP1_ID, 6), \
+ _CMN_EVENT_HNS(_model, _name##_hbt, _event, SEL_OCCUP1_ID, 7), \
+ _CMN_EVENT_HNS(CMNS3R2, _name##_rnf, _event, SEL_OCCUP1_ID, 8), \
+ _CMN_EVENT_HNS(CMNS3R2, _name##_rni, _event, SEL_OCCUP1_ID, 9), \
+ _CMN_EVENT_HNS(CMNS3R2, _name##_ccglcn, _event, SEL_OCCUP1_ID, 10), \
+ _CMN_EVENT_HNS(CMNS3R2, _name##_ccgrn, _event, SEL_OCCUP1_ID, 11)
#define CMN_EVENT_HNS_CLS( _name, _event) \
CMN_EVENT_HN_CLS(CMN_ANY, hns_##_name, CMN_TYPE_HNS, _event)
-#define CMN_EVENT_HNS_SNT(_name, _event) \
- CMN_EVENT_HN_SNT(CMN_ANY, hns_##_name, CMN_TYPE_HNS, _event)
-#define CMN_EVENT_HNS_HBT(_name, _event) \
- CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_all, CMN_TYPE_HNS, _event, SEL_HBT_LBT_SEL, 0), \
- CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_hbt, CMN_TYPE_HNS, _event, SEL_HBT_LBT_SEL, 1), \
- CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_lbt, CMN_TYPE_HNS, _event, SEL_HBT_LBT_SEL, 2)
-#define CMN_EVENT_HNS_SNH(_name, _event) \
- CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_all, CMN_TYPE_HNS, _event, SEL_SN_HOME_SEL, 0), \
- CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_sn, CMN_TYPE_HNS, _event, SEL_SN_HOME_SEL, 1), \
- CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_home, CMN_TYPE_HNS, _event, SEL_SN_HOME_SEL, 2)
+#define CMN_EVENT_HNSR0_CLS( _name, _event) \
+ CMN_EVENT_HN_CLS(CMN700 | CMNS3R01, hns_##_name, CMN_TYPE_HNS, _event)
+#define CMN_EVENT_HNS_SNT(_model, _name, _event) \
+ CMN_EVENT_HN_SNT(_model, hns_##_name, CMN_TYPE_HNS, _event)
+#define CMN_EVENT_HNS_SNH(_model, _name, _event) \
+ _CMN_EVENT_HNS(_model, _name##_all, _event, SEL_SN_HOME_SEL, 0), \
+ _CMN_EVENT_HNS(_model, _name##_sn, _event, SEL_SN_HOME_SEL, 1), \
+ _CMN_EVENT_HNS(_model, _name##_home, _event, SEL_SN_HOME_SEL, 2)
+#define CMN_EVENT_HNS_VC(_name, _event) \
+ CMN_EVENT_HNSR0(_name, _event), \
+ _CMN_EVENT_HNS(CMNS3R2, _name##_vc0, _event, SEL_SNP_VC_SEL, 0), \
+ _CMN_EVENT_HNS(CMNS3R2, _name##_vc1, _event, SEL_SNP_VC_SEL, 1), \
+ _CMN_EVENT_HNS(CMNS3R2, _name##_vc2, _event, SEL_SNP_VC_SEL, 2)
+#define CMN_EVENT_HNS_ENHBT(_name, _event) \
+ _CMN_EVENT_HNS_HBT(CMNS3R2, _name, _event, SEL_ENHANCED_HBT_LBT_SEL), \
+ _CMN_EVENT_HNS(CMNS3R2, _name##_rnf, _event, SEL_ENHANCED_HBT_LBT_SEL, 3), \
+ _CMN_EVENT_HNS(CMNS3R2, _name##_rni, _event, SEL_ENHANCED_HBT_LBT_SEL, 4), \
+ _CMN_EVENT_HNS(CMNS3R2, _name##_ccglcn, _event, SEL_ENHANCED_HBT_LBT_SEL, 5), \
+ _CMN_EVENT_HNS(CMNS3R2, _name##_ccgrn, _event, SEL_ENHANCED_HBT_LBT_SEL, 6)
+#define CMN_EVENT_HNS_EVICT(_model, _name, _event) \
+ _CMN_EVENT_HNS_HBT2(_model, _name##_all, _event, SEL_EVICT_STATE_SEL, 0), \
+ _CMN_EVENT_HNS_HBT2(_model, _name##_eu, _event, SEL_EVICT_STATE_SEL, 1), \
+ _CMN_EVENT_HNS_HBT2(_model, _name##_en, _event, SEL_EVICT_STATE_SEL, 2), \
+ _CMN_EVENT_HNS_HBT2(_model, _name##_su, _event, SEL_EVICT_STATE_SEL, 3), \
+ _CMN_EVENT_HNS_HBT2(_model, _name##_sn, _event, SEL_EVICT_STATE_SEL, 4), \
+ _CMN_EVENT_HNS_HBT2(_model, _name##_mu, _event, SEL_EVICT_STATE_SEL, 5), \
+ _CMN_EVENT_HNS_HBT2(_model, _name##_mn, _event, SEL_EVICT_STATE_SEL, 6)
+
+#define CMN_EVENT_HNSR0_HBT(_name, _event) \
+ _CMN_EVENT_HNS_HBT(CMN700 | CMNS3R01, _name, _event, SEL_HBT_LBT_SEL)
+#define CMN_EVENT_HNS_R2SNH(_name, _event) \
+ CMN_EVENT_HNSR0(_name, _event), \
+ CMN_EVENT_HNS_SNH(CMNS3R2, _name, _event)
+#define CMN_EVENT_HNS_R2HBT(_name, _event) \
+ CMN_EVENT_HNSR0(_name, _event), \
+ _CMN_EVENT_HNS_HBT(CMNS3R2, _name, _event, SEL_HBT_LBT_SEL)
+#define CMN_EVENT_HNS_HBT_ENHBT(_name, _event) \
+ CMN_EVENT_HNSR0_HBT(_name, _event), \
+ CMN_EVENT_HNS_ENHBT(_name, _event)
+#define CMN_EVENT_HNS_HBT_OCC(_name, _event) \
+ CMN_EVENT_HNSR0_HBT(_name, _event), \
+ CMN_EVENT_HNS_OCC(CMNS3R2, _name, _event)
+#define CMN_EVENT_HNS_HBT_EVICT(_name, _event) \
+ CMN_EVENT_HNSR0_HBT(_name, _event), \
+ CMN_EVENT_HNS_EVICT(CMNS3R2, _name, _event)
#define _CMN_EVENT_XP_MESH(_name, _event) \
__CMN_EVENT_XP(e_##_name, (_event) | (0 << 2)), \
@@ -1288,65 +1388,72 @@ static struct attribute *arm_cmn_event_attrs[] = {
CMN_EVENT_CCLA(pfwd_sndr_stalls_static_crd, 0x2a),
CMN_EVENT_CCLA(pfwd_sndr_stalls_dynmaic_crd, 0x2b),
- CMN_EVENT_HNS_HBT(cache_miss, 0x01),
- CMN_EVENT_HNS_HBT(slc_sf_cache_access, 0x02),
- CMN_EVENT_HNS_HBT(cache_fill, 0x03),
- CMN_EVENT_HNS_HBT(pocq_retry, 0x04),
- CMN_EVENT_HNS_HBT(pocq_reqs_recvd, 0x05),
- CMN_EVENT_HNS_HBT(sf_hit, 0x06),
- CMN_EVENT_HNS_HBT(sf_evictions, 0x07),
- CMN_EVENT_HNS(dir_snoops_sent, 0x08),
- CMN_EVENT_HNS(brd_snoops_sent, 0x09),
- CMN_EVENT_HNS_HBT(slc_eviction, 0x0a),
- CMN_EVENT_HNS_HBT(slc_fill_invalid_way, 0x0b),
- CMN_EVENT_HNS(mc_retries_local, 0x0c),
- CMN_EVENT_HNS_SNH(mc_reqs_local, 0x0d),
+ CMN_EVENT_HNS_HBT_ENHBT(cache_miss, 0x01),
+ CMN_EVENT_HNS_HBT_ENHBT(slc_sf_cache_access, 0x02),
+ CMN_EVENT_HNS_HBT_ENHBT(cache_fill, 0x03),
+ CMN_EVENT_HNS_HBT_OCC(pocq_retry, 0x04),
+ CMN_EVENT_HNS_HBT_OCC(pocq_reqs_recvd, 0x05),
+ CMN_EVENT_HNS_HBT_ENHBT(sf_hit, 0x06),
+ CMN_EVENT_HNS_HBT_EVICT(sf_evictions, 0x07),
+ CMN_EVENT_HNS_VC(dir_snoops_sent, 0x08),
+ CMN_EVENT_HNS_VC(brd_snoops_sent, 0x09),
+ CMN_EVENT_HNS_HBT_EVICT(slc_eviction, 0x0a),
+ CMN_EVENT_HNS_HBT_ENHBT(slc_fill_invalid_way, 0x0b),
+ CMN_EVENT_HNS_R2SNH(mc_retries_local, 0x0c),
+ CMN_EVENT_HNS_SNH(CMN_ANY, mc_reqs_local, 0x0d),
CMN_EVENT_HNS(qos_hh_retry, 0x0e),
- CMN_EVENT_HNS_OCC(qos_pocq_occupancy, 0x0f),
- CMN_EVENT_HNS(pocq_addrhaz, 0x10),
- CMN_EVENT_HNS(pocq_atomic_addrhaz, 0x11),
- CMN_EVENT_HNS(ld_st_swp_adq_full, 0x12),
- CMN_EVENT_HNS(cmp_adq_full, 0x13),
+ CMN_EVENT_HNS_OCC(CMN_ANY, qos_pocq_occupancy, 0x0f),
+ CMN_EVENT_HNS_HBT_ENHBT(pocq_addrhaz, 0x10),
+ CMN_EVENT_HNS_HBT_ENHBT(pocq_atomic_addrhaz, 0x11),
+ CMN_EVENT_HNSR0(ld_st_swp_adq_full, 0x12),
+ CMN_EVENT_HNSR0(cmp_adq_full, 0x13),
CMN_EVENT_HNS(txdat_stall, 0x14),
CMN_EVENT_HNS(txrsp_stall, 0x15),
- CMN_EVENT_HNS(seq_full, 0x16),
+ CMN_EVENT_HNSR0(seq_full, 0x16),
CMN_EVENT_HNS(seq_hit, 0x17),
- CMN_EVENT_HNS(snp_sent, 0x18),
- CMN_EVENT_HNS(sfbi_dir_snp_sent, 0x19),
- CMN_EVENT_HNS(sfbi_brd_snp_sent, 0x1a),
+ CMN_EVENT_HNS_VC(snp_sent, 0x18),
+ CMN_EVENT_HNS_VC(sfbi_dir_snp_sent, 0x19),
+ CMN_EVENT_HNS_VC(sfbi_brd_snp_sent, 0x1a),
CMN_EVENT_HNS(intv_dirty, 0x1c),
- CMN_EVENT_HNS(stash_snp_sent, 0x1d),
- CMN_EVENT_HNS(stash_data_pull, 0x1e),
- CMN_EVENT_HNS(snp_fwded, 0x1f),
- CMN_EVENT_HNS(atomic_fwd, 0x20),
+ CMN_EVENT_HNSR0(stash_snp_sent, 0x1d),
+ CMN_EVENT_HNSR0(stash_data_pull, 0x1e),
+ CMN_EVENT_HNS_VC(snp_fwded, 0x1f),
+ CMN_EVENT_HNSR0(atomic_fwd, 0x20),
CMN_EVENT_HNS(mpam_hardlim, 0x21),
CMN_EVENT_HNS(mpam_softlim, 0x22),
- CMN_EVENT_HNS(snp_sent_cluster, 0x23),
- CMN_EVENT_HNS(sf_imprecise_evict, 0x24),
+ CMN_EVENT_HNS_VC(snp_sent_cluster, 0x23),
+ CMN_EVENT_HNS_R2HBT(sf_imprecise_evict, 0x24),
CMN_EVENT_HNS(sf_evict_shared_line, 0x25),
CMN_EVENT_HNS_CLS(pocq_class_occup, 0x26),
CMN_EVENT_HNS_CLS(pocq_class_retry, 0x27),
CMN_EVENT_HNS_CLS(class_mc_reqs_local, 0x28),
- CMN_EVENT_HNS_CLS(class_cgnt_cmin, 0x29),
- CMN_EVENT_HNS_SNT(sn_throttle, 0x2a),
- CMN_EVENT_HNS_SNT(sn_throttle_min, 0x2b),
+ CMN_EVENT_HNSR0_CLS(class_cgnt_cmin, 0x29),
+ CMN_EVENT_HNS_SNT(CMN_ANY, sn_throttle, 0x2a),
+ CMN_EVENT_HNS_SNT(CMN_ANY, sn_throttle_min, 0x2b),
CMN_EVENT_HNS(sf_precise_to_imprecise, 0x2c),
CMN_EVENT_HNS(snp_intv_cln, 0x2d),
CMN_EVENT_HNS(nc_excl, 0x2e),
- CMN_EVENT_HNS(excl_mon_ovfl, 0x2f),
+ CMN_EVENT_HNSR0(excl_mon_ovfl, 0x2f),
CMN_EVENT_HNS(snp_req_recvd, 0x30),
CMN_EVENT_HNS(snp_req_byp_pocq, 0x31),
CMN_EVENT_HNS(dir_ccgha_snp_sent, 0x32),
CMN_EVENT_HNS(brd_ccgha_snp_sent, 0x33),
- CMN_EVENT_HNS(ccgha_snp_stall, 0x34),
+ CMN_EVENT_HNSR0(ccgha_snp_stall, 0x34),
CMN_EVENT_HNS(lbt_req_hardlim, 0x35),
CMN_EVENT_HNS(hbt_req_hardlim, 0x36),
CMN_EVENT_HNS(sf_reupdate, 0x37),
- CMN_EVENT_HNS(excl_sf_imprecise, 0x38),
+ CMN_EVENT_HNS_R2HBT(excl_sf_imprecise, 0x38),
CMN_EVENT_HNS(snp_pocq_addrhaz, 0x39),
- CMN_EVENT_HNS(mc_retries_remote, 0x3a),
- CMN_EVENT_HNS_SNH(mc_reqs_remote, 0x3b),
+ CMN_EVENT_HNS_R2SNH(mc_retries_remote, 0x3a),
+ CMN_EVENT_HNS_SNH(CMN_ANY, mc_reqs_remote, 0x3b),
CMN_EVENT_HNS_CLS(class_mc_reqs_remote, 0x3c),
+ CMN_EVENT_HNS_ENHBT(readonce_hazard_detected, 0x3d),
+ CMN_EVENT_HNS_ENHBT(readonce_fwd_data_completed, 0x3e),
+ CMN_EVENT_HNS_SNT(CMNS3R2, cbusy00, 0x40),
+ CMN_EVENT_HNS_SNT(CMNS3R2, cbusy01, 0x41),
+ CMN_EVENT_HNS_SNT(CMNS3R2, cbusy10, 0x42),
+ CMN_EVENT_HNS_SNT(CMNS3R2, cbusy11, 0x43),
+ CMN_EVENT_HNS_ENHBT(ro_rnsd_new_alloc_hint, 0x44),
NULL
};
@@ -2431,21 +2538,33 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
/*
* With the device isolation feature, if firmware has neglected to enable
* an XP port then we risk locking up if we try to access anything behind
- * it; however we also have no way to tell from Non-Secure whether any
- * given port is disabled or not, so the only way to win is not to play...
+ * it; however prior to CMN S3 r2p0 we also have no way to tell from
+ * Non-Secure whether any given port is disabled or not, so in that case
+ * the only way to win is not to play...
*/
reg = readq_relaxed(cfg_region + CMN_CFGM_INFO_GLOBAL);
- if (reg & CMN_INFO_DEVICE_ISO_ENABLE) {
+ if (reg & CMN_INFO_DEVICE_ISO_ENABLE && model == CMNS3R01) {
dev_err(cmn->dev, "Device isolation enabled, not continuing due to risk of lockup\n");
return -ENODEV;
}
- cmn->multi_dtm = reg & CMN_INFO_MULTIPLE_DTM_EN;
- cmn->rsp_vc_num = FIELD_GET(CMN_INFO_RSP_VC_NUM, reg);
- cmn->dat_vc_num = FIELD_GET(CMN_INFO_DAT_VC_NUM, reg);
+ if (model < CMNS3R2) {
+ cmn->multi_dtm = reg & CMN_INFO_MULTIPLE_DTM_EN;
+ cmn->rsp_vc_num = FIELD_GET(CMN_INFO_RSP_VC_NUM, reg);
+ cmn->dat_vc_num = FIELD_GET(CMN_INFO_DAT_VC_NUM, reg);
+ } else {
+ cmn->multi_dtm = reg & CMN_S3_R2_MULTIPLE_DTM_EN;
+ }
reg = readq_relaxed(cfg_region + CMN_CFGM_INFO_GLOBAL_1);
- cmn->snp_vc_num = FIELD_GET(CMN_INFO_SNP_VC_NUM, reg);
- cmn->req_vc_num = FIELD_GET(CMN_INFO_REQ_VC_NUM, reg);
+ if (model < CMNS3R2) {
+ cmn->snp_vc_num = FIELD_GET(CMN_INFO_SNP_VC_NUM, reg);
+ cmn->req_vc_num = FIELD_GET(CMN_INFO_REQ_VC_NUM, reg);
+ } else {
+ cmn->rsp_vc_num = FIELD_GET(CMN_S3_R2_RSP_VC_NUM, reg);
+ cmn->dat_vc_num = FIELD_GET(CMN_S3_R2_DAT_VC_NUM, reg);
+ cmn->snp_vc_num = FIELD_GET(CMN_S3_R2_SNP_VC_NUM, reg);
+ cmn->req_vc_num = FIELD_GET(CMN_S3_R2_REQ_VC_NUM, reg);
+ }
reg = readq_relaxed(cfg_region + CMN_CHILD_INFO);
child_count = FIELD_GET(CMN_CI_CHILD_COUNT, reg);
@@ -2545,15 +2664,12 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
reg = readq_relaxed(xp_region + child_poff + j * 8);
/*
* Don't even try to touch anything external, since in general
- * we haven't a clue how to power up arbitrary CHI requesters.
- * As of CMN-600r1 these could only be RN-SAMs or CXLAs,
- * neither of which have any PMU events anyway.
- * (Actually, CXLAs do seem to have grown some events in r1p2,
- * but they don't go to regular XP DTMs, and they depend on
- * secure configuration which we can't easily deal with)
+ * we haven't a clue how to power up arbitrary CHI requesters,
+ * and none of them have standard PMU events anyway. Isolated
+ * nodes effectively just do not exist at all from our PoV.
*/
- if (reg & CMN_CHILD_NODE_EXTERNAL) {
- dev_dbg(cmn->dev, "ignoring external node %llx\n", reg);
+ if (reg & (CMN_CHILD_NODE_EXTERNAL | CMN_CHILD_NODE_ISOLATED)) {
+ dev_dbg(cmn->dev, "ignoring external/isolated node %llx\n", reg);
continue;
}
/*
--
2.54.0.dirty
^ permalink raw reply related [flat|nested] 6+ messages in thread