Skip to content

Commit 7819e05

Browse files
rmurphy-armwilldeacon
authored andcommitted
perf/arm-cmn: Revamp model detection
CMN implements a set of CoreSight-format peripheral ID registers which in principle we should be able to use to identify the hardware. However so far we have avoided trying to use the part number field since the TRMs have all described it as "configuration dependent". It turns out, though, that this is a quirk of the documentation generation process, and in fact the part number should always be a stable well-defined field which we can trust. To that end, revamp our model detection to rely less on ACPI/DT, and pave the way towards further using the hardware information as an identifier for userspace jevent metrics. This includes renaming the revision constants to maximise readability. Signed-off-by: Robin Murphy <[email protected]> Reviewed-and-tested-by: Ilkka Koskinen <[email protected]> Link: https://lore.kernel.org/r/3c791eaae814b0126f9adbd5419bfb4a600dade7.1686588640.git.robin.murphy@arm.com Signed-off-by: Will Deacon <[email protected]>
1 parent 95f5819 commit 7819e05

File tree

1 file changed

+93
-52
lines changed

1 file changed

+93
-52
lines changed

drivers/perf/arm-cmn.c

Lines changed: 93 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,11 @@
4444
#define CMN_MAX_DTMS (CMN_MAX_XPS + (CMN_MAX_DIMENSION - 1) * 4)
4545

4646
/* The CFG node has various info besides the discovery tree */
47-
#define CMN_CFGM_PERIPH_ID_2 0x0010
48-
#define CMN_CFGM_PID2_REVISION GENMASK(7, 4)
47+
#define CMN_CFGM_PERIPH_ID_01 0x0008
48+
#define CMN_CFGM_PID0_PART_0 GENMASK_ULL(7, 0)
49+
#define CMN_CFGM_PID1_PART_1 GENMASK_ULL(35, 32)
50+
#define CMN_CFGM_PERIPH_ID_23 0x0010
51+
#define CMN_CFGM_PID2_REVISION GENMASK_ULL(7, 4)
4952

5053
#define CMN_CFGM_INFO_GLOBAL 0x900
5154
#define CMN_INFO_MULTIPLE_DTM_EN BIT_ULL(63)
@@ -186,6 +189,7 @@
186189
#define CMN_WP_DOWN 2
187190

188191

192+
/* Internal values for encoding event support */
189193
enum cmn_model {
190194
CMN600 = 1,
191195
CMN650 = 2,
@@ -197,26 +201,34 @@ enum cmn_model {
197201
CMN_650ON = CMN650 | CMN700,
198202
};
199203

204+
/* Actual part numbers and revision IDs defined by the hardware */
205+
enum cmn_part {
206+
PART_CMN600 = 0x434,
207+
PART_CMN650 = 0x436,
208+
PART_CMN700 = 0x43c,
209+
PART_CI700 = 0x43a,
210+
};
211+
200212
/* CMN-600 r0px shouldn't exist in silicon, thankfully */
201213
enum cmn_revision {
202-
CMN600_R1P0,
203-
CMN600_R1P1,
204-
CMN600_R1P2,
205-
CMN600_R1P3,
206-
CMN600_R2P0,
207-
CMN600_R3P0,
208-
CMN600_R3P1,
209-
CMN650_R0P0 = 0,
210-
CMN650_R1P0,
211-
CMN650_R1P1,
212-
CMN650_R2P0,
213-
CMN650_R1P2,
214-
CMN700_R0P0 = 0,
215-
CMN700_R1P0,
216-
CMN700_R2P0,
217-
CI700_R0P0 = 0,
218-
CI700_R1P0,
219-
CI700_R2P0,
214+
REV_CMN600_R1P0,
215+
REV_CMN600_R1P1,
216+
REV_CMN600_R1P2,
217+
REV_CMN600_R1P3,
218+
REV_CMN600_R2P0,
219+
REV_CMN600_R3P0,
220+
REV_CMN600_R3P1,
221+
REV_CMN650_R0P0 = 0,
222+
REV_CMN650_R1P0,
223+
REV_CMN650_R1P1,
224+
REV_CMN650_R2P0,
225+
REV_CMN650_R1P2,
226+
REV_CMN700_R0P0 = 0,
227+
REV_CMN700_R1P0,
228+
REV_CMN700_R2P0,
229+
REV_CI700_R0P0 = 0,
230+
REV_CI700_R1P0,
231+
REV_CI700_R2P0,
220232
};
221233

222234
enum cmn_node_type {
@@ -306,7 +318,7 @@ struct arm_cmn {
306318
unsigned int state;
307319

308320
enum cmn_revision rev;
309-
enum cmn_model model;
321+
enum cmn_part part;
310322
u8 mesh_x;
311323
u8 mesh_y;
312324
u16 num_xps;
@@ -394,19 +406,35 @@ static struct arm_cmn_node *arm_cmn_node(const struct arm_cmn *cmn,
394406
return NULL;
395407
}
396408

409+
static enum cmn_model arm_cmn_model(const struct arm_cmn *cmn)
410+
{
411+
switch (cmn->part) {
412+
case PART_CMN600:
413+
return CMN600;
414+
case PART_CMN650:
415+
return CMN650;
416+
case PART_CMN700:
417+
return CMN700;
418+
case PART_CI700:
419+
return CI700;
420+
default:
421+
return 0;
422+
};
423+
}
424+
397425
static u32 arm_cmn_device_connect_info(const struct arm_cmn *cmn,
398426
const struct arm_cmn_node *xp, int port)
399427
{
400428
int offset = CMN_MXP__CONNECT_INFO(port);
401429

402430
if (port >= 2) {
403-
if (cmn->model & (CMN600 | CMN650))
431+
if (cmn->part == PART_CMN600 || cmn->part == PART_CMN650)
404432
return 0;
405433
/*
406434
* CI-700 may have extra ports, but still has the
407435
* mesh_port_connect_info registers in the way.
408436
*/
409-
if (cmn->model == CI700)
437+
if (cmn->part == PART_CI700)
410438
offset += CI700_CONNECT_INFO_P2_5_OFFSET;
411439
}
412440

@@ -640,7 +668,7 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
640668

641669
eattr = container_of(attr, typeof(*eattr), attr.attr);
642670

643-
if (!(eattr->model & cmn->model))
671+
if (!(eattr->model & arm_cmn_model(cmn)))
644672
return 0;
645673

646674
type = eattr->type;
@@ -658,7 +686,7 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
658686
if ((intf & 4) && !(cmn->ports_used & BIT(intf & 3)))
659687
return 0;
660688

661-
if (chan == 4 && cmn->model == CMN600)
689+
if (chan == 4 && cmn->part == PART_CMN600)
662690
return 0;
663691

664692
if ((chan == 5 && cmn->rsp_vc_num < 2) ||
@@ -669,36 +697,36 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
669697
}
670698

671699
/* Revision-specific differences */
672-
if (cmn->model == CMN600) {
673-
if (cmn->rev < CMN600_R1P3) {
700+
if (cmn->part == PART_CMN600) {
701+
if (cmn->rev < REV_CMN600_R1P3) {
674702
if (type == CMN_TYPE_CXRA && eventid > 0x10)
675703
return 0;
676704
}
677-
if (cmn->rev < CMN600_R1P2) {
705+
if (cmn->rev < REV_CMN600_R1P2) {
678706
if (type == CMN_TYPE_HNF && eventid == 0x1b)
679707
return 0;
680708
if (type == CMN_TYPE_CXRA || type == CMN_TYPE_CXHA)
681709
return 0;
682710
}
683-
} else if (cmn->model == CMN650) {
684-
if (cmn->rev < CMN650_R2P0 || cmn->rev == CMN650_R1P2) {
711+
} else if (cmn->part == PART_CMN650) {
712+
if (cmn->rev < REV_CMN650_R2P0 || cmn->rev == REV_CMN650_R1P2) {
685713
if (type == CMN_TYPE_HNF && eventid > 0x22)
686714
return 0;
687715
if (type == CMN_TYPE_SBSX && eventid == 0x17)
688716
return 0;
689717
if (type == CMN_TYPE_RNI && eventid > 0x10)
690718
return 0;
691719
}
692-
} else if (cmn->model == CMN700) {
693-
if (cmn->rev < CMN700_R2P0) {
720+
} else if (cmn->part == PART_CMN700) {
721+
if (cmn->rev < REV_CMN700_R2P0) {
694722
if (type == CMN_TYPE_HNF && eventid > 0x2c)
695723
return 0;
696724
if (type == CMN_TYPE_CCHA && eventid > 0x74)
697725
return 0;
698726
if (type == CMN_TYPE_CCLA && eventid > 0x27)
699727
return 0;
700728
}
701-
if (cmn->rev < CMN700_R1P0) {
729+
if (cmn->rev < REV_CMN700_R1P0) {
702730
if (type == CMN_TYPE_HNF && eventid > 0x2b)
703731
return 0;
704732
}
@@ -1200,7 +1228,7 @@ static u32 arm_cmn_wp_config(struct perf_event *event)
12001228
u32 grp = CMN_EVENT_WP_GRP(event);
12011229
u32 exc = CMN_EVENT_WP_EXCLUSIVE(event);
12021230
u32 combine = CMN_EVENT_WP_COMBINE(event);
1203-
bool is_cmn600 = to_cmn(event->pmu)->model == CMN600;
1231+
bool is_cmn600 = to_cmn(event->pmu)->part == PART_CMN600;
12041232

12051233
config = FIELD_PREP(CMN_DTM_WPn_CONFIG_WP_DEV_SEL, dev) |
12061234
FIELD_PREP(CMN_DTM_WPn_CONFIG_WP_CHN_SEL, chn) |
@@ -1520,14 +1548,14 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
15201548
return ret;
15211549
}
15221550

1523-
static enum cmn_filter_select arm_cmn_filter_sel(enum cmn_model model,
1551+
static enum cmn_filter_select arm_cmn_filter_sel(const struct arm_cmn *cmn,
15241552
enum cmn_node_type type,
15251553
unsigned int eventid)
15261554
{
15271555
struct arm_cmn_event_attr *e;
1528-
int i;
1556+
enum cmn_model model = arm_cmn_model(cmn);
15291557

1530-
for (i = 0; i < ARRAY_SIZE(arm_cmn_event_attrs) - 1; i++) {
1558+
for (int i = 0; i < ARRAY_SIZE(arm_cmn_event_attrs) - 1; i++) {
15311559
e = container_of(arm_cmn_event_attrs[i], typeof(*e), attr.attr);
15321560
if (e->model & model && e->type == type && e->eventid == eventid)
15331561
return e->fsel;
@@ -1570,12 +1598,12 @@ static int arm_cmn_event_init(struct perf_event *event)
15701598
/* ...but the DTM may depend on which port we're watching */
15711599
if (cmn->multi_dtm)
15721600
hw->dtm_offset = CMN_EVENT_WP_DEV_SEL(event) / 2;
1573-
} else if (type == CMN_TYPE_XP && cmn->model == CMN700) {
1601+
} else if (type == CMN_TYPE_XP && cmn->part == PART_CMN700) {
15741602
hw->wide_sel = true;
15751603
}
15761604

15771605
/* This is sufficiently annoying to recalculate, so cache it */
1578-
hw->filter_sel = arm_cmn_filter_sel(cmn->model, type, eventid);
1606+
hw->filter_sel = arm_cmn_filter_sel(cmn, type, eventid);
15791607

15801608
bynodeid = CMN_EVENT_BYNODEID(event);
15811609
nodeid = CMN_EVENT_NODEID(event);
@@ -2007,6 +2035,7 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
20072035
void __iomem *cfg_region;
20082036
struct arm_cmn_node cfg, *dn;
20092037
struct arm_cmn_dtm *dtm;
2038+
enum cmn_part part;
20102039
u16 child_count, child_poff;
20112040
u32 xp_offset[CMN_MAX_XPS];
20122041
u64 reg;
@@ -2018,7 +2047,19 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
20182047
return -ENODEV;
20192048

20202049
cfg_region = cmn->base + rgn_offset;
2021-
reg = readl_relaxed(cfg_region + CMN_CFGM_PERIPH_ID_2);
2050+
2051+
reg = readq_relaxed(cfg_region + CMN_CFGM_PERIPH_ID_01);
2052+
part = FIELD_GET(CMN_CFGM_PID0_PART_0, reg);
2053+
part |= FIELD_GET(CMN_CFGM_PID1_PART_1, reg) << 8;
2054+
if (cmn->part && cmn->part != part)
2055+
dev_warn(cmn->dev,
2056+
"Firmware binding mismatch: expected part number 0x%x, found 0x%x\n",
2057+
cmn->part, part);
2058+
cmn->part = part;
2059+
if (!arm_cmn_model(cmn))
2060+
dev_warn(cmn->dev, "Unknown part number: 0x%x\n", part);
2061+
2062+
reg = readl_relaxed(cfg_region + CMN_CFGM_PERIPH_ID_23);
20222063
cmn->rev = FIELD_GET(CMN_CFGM_PID2_REVISION, reg);
20232064

20242065
reg = readq_relaxed(cfg_region + CMN_CFGM_INFO_GLOBAL);
@@ -2082,7 +2123,7 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
20822123
if (xp->id == (1 << 3))
20832124
cmn->mesh_x = xp->logid;
20842125

2085-
if (cmn->model == CMN600)
2126+
if (cmn->part == PART_CMN600)
20862127
xp->dtc = 0xf;
20872128
else
20882129
xp->dtc = 1 << readl_relaxed(xp_region + CMN_DTM_UNIT_INFO);
@@ -2202,7 +2243,7 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
22022243
if (cmn->num_xps == 1)
22032244
dev_warn(cmn->dev, "1x1 config not fully supported, translate XP events manually\n");
22042245

2205-
dev_dbg(cmn->dev, "model %d, periph_id_2 revision %d\n", cmn->model, cmn->rev);
2246+
dev_dbg(cmn->dev, "periph_id part 0x%03x revision %d\n", cmn->part, cmn->rev);
22062247
reg = cmn->ports_used;
22072248
dev_dbg(cmn->dev, "mesh %dx%d, ID width %d, ports %6pbl%s\n",
22082249
cmn->mesh_x, cmn->mesh_y, arm_cmn_xyidbits(cmn), &reg,
@@ -2257,17 +2298,17 @@ static int arm_cmn_probe(struct platform_device *pdev)
22572298
return -ENOMEM;
22582299

22592300
cmn->dev = &pdev->dev;
2260-
cmn->model = (unsigned long)device_get_match_data(cmn->dev);
2301+
cmn->part = (unsigned long)device_get_match_data(cmn->dev);
22612302
platform_set_drvdata(pdev, cmn);
22622303

2263-
if (cmn->model == CMN600 && has_acpi_companion(cmn->dev)) {
2304+
if (cmn->part == PART_CMN600 && has_acpi_companion(cmn->dev)) {
22642305
rootnode = arm_cmn600_acpi_probe(pdev, cmn);
22652306
} else {
22662307
rootnode = 0;
22672308
cmn->base = devm_platform_ioremap_resource(pdev, 0);
22682309
if (IS_ERR(cmn->base))
22692310
return PTR_ERR(cmn->base);
2270-
if (cmn->model == CMN600)
2311+
if (cmn->part == PART_CMN600)
22712312
rootnode = arm_cmn600_of_probe(pdev->dev.of_node);
22722313
}
22732314
if (rootnode < 0)
@@ -2336,20 +2377,20 @@ static int arm_cmn_remove(struct platform_device *pdev)
23362377

23372378
#ifdef CONFIG_OF
23382379
static const struct of_device_id arm_cmn_of_match[] = {
2339-
{ .compatible = "arm,cmn-600", .data = (void *)CMN600 },
2340-
{ .compatible = "arm,cmn-650", .data = (void *)CMN650 },
2341-
{ .compatible = "arm,cmn-700", .data = (void *)CMN700 },
2342-
{ .compatible = "arm,ci-700", .data = (void *)CI700 },
2380+
{ .compatible = "arm,cmn-600", .data = (void *)PART_CMN600 },
2381+
{ .compatible = "arm,cmn-650" },
2382+
{ .compatible = "arm,cmn-700" },
2383+
{ .compatible = "arm,ci-700" },
23432384
{}
23442385
};
23452386
MODULE_DEVICE_TABLE(of, arm_cmn_of_match);
23462387
#endif
23472388

23482389
#ifdef CONFIG_ACPI
23492390
static const struct acpi_device_id arm_cmn_acpi_match[] = {
2350-
{ "ARMHC600", CMN600 },
2351-
{ "ARMHC650", CMN650 },
2352-
{ "ARMHC700", CMN700 },
2391+
{ "ARMHC600", PART_CMN600 },
2392+
{ "ARMHC650" },
2393+
{ "ARMHC700" },
23532394
{}
23542395
};
23552396
MODULE_DEVICE_TABLE(acpi, arm_cmn_acpi_match);

0 commit comments

Comments
 (0)