Skip to content

Commit e79634b

Browse files
rmurphy-armwilldeacon
authored andcommitted
perf/arm-cmn: Refactor node ID handling. Again.
The scope of the "extra device ports" configuration is not made clear by the CMN documentation - so far we've assumed it applies globally, based on the sole example which suggests as much. However it transpires that this is incorrect, and the format does in fact vary based on each individual XP's port configuration. As a consequence, we're currenly liable to decode the port/device indices from a node ID incorrectly, thus program the wrong event source in the DTM leading to bogus event counts, and also show device topology on the wrong ports in debugfs. To put this right, rework node IDs yet again to carry around the additional data necessary to decode them properly per-XP. At this point the notion of fully decomposing an ID becomes more impractical than it's worth, so unabstracting the XY mesh coordinates (where 2/3 users were just debug anyway) ends up leaving things a bit simpler overall. Fixes: 60d1504 ("perf/arm-cmn: Support new IP features") Acked-by: Mark Rutland <mark.rutland@arm.com> Signed-off-by: Robin Murphy <robin.murphy@arm.com> Link: https://lore.kernel.org/r/5195f990152fc37adba5fbf5929a6b11063d9f09.1725296395.git.robin.murphy@arm.com Signed-off-by: Will Deacon <will@kernel.org>
1 parent d1c93d5 commit e79634b

1 file changed

Lines changed: 40 additions & 54 deletions

File tree

drivers/perf/arm-cmn.c

Lines changed: 40 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,6 @@
2424
#define CMN_NI_NODE_ID GENMASK_ULL(31, 16)
2525
#define CMN_NI_LOGICAL_ID GENMASK_ULL(47, 32)
2626

27-
#define CMN_NODEID_DEVID(reg) ((reg) & 3)
28-
#define CMN_NODEID_EXT_DEVID(reg) ((reg) & 1)
29-
#define CMN_NODEID_PID(reg) (((reg) >> 2) & 1)
30-
#define CMN_NODEID_EXT_PID(reg) (((reg) >> 1) & 3)
31-
#define CMN_NODEID_1x1_PID(reg) (((reg) >> 2) & 7)
32-
#define CMN_NODEID_X(reg, bits) ((reg) >> (3 + (bits)))
33-
#define CMN_NODEID_Y(reg, bits) (((reg) >> 3) & ((1U << (bits)) - 1))
34-
3527
#define CMN_CHILD_INFO 0x0080
3628
#define CMN_CI_CHILD_COUNT GENMASK_ULL(15, 0)
3729
#define CMN_CI_CHILD_PTR_OFFSET GENMASK_ULL(31, 16)
@@ -280,8 +272,11 @@ struct arm_cmn_node {
280272
u16 id, logid;
281273
enum cmn_node_type type;
282274

275+
/* XP properties really, but replicated to children for convenience */
283276
u8 dtm;
284277
s8 dtc;
278+
u8 portid_bits:4;
279+
u8 deviceid_bits:4;
285280
/* DN/HN-F/CXHA */
286281
struct {
287282
u8 val : 4;
@@ -357,49 +352,33 @@ struct arm_cmn {
357352
static int arm_cmn_hp_state;
358353

359354
struct arm_cmn_nodeid {
360-
u8 x;
361-
u8 y;
362355
u8 port;
363356
u8 dev;
364357
};
365358

366359
static int arm_cmn_xyidbits(const struct arm_cmn *cmn)
367360
{
368-
return fls((cmn->mesh_x - 1) | (cmn->mesh_y - 1) | 2);
361+
return fls((cmn->mesh_x - 1) | (cmn->mesh_y - 1));
369362
}
370363

371-
static struct arm_cmn_nodeid arm_cmn_nid(const struct arm_cmn *cmn, u16 id)
364+
static struct arm_cmn_nodeid arm_cmn_nid(const struct arm_cmn_node *dn)
372365
{
373366
struct arm_cmn_nodeid nid;
374367

375-
if (cmn->num_xps == 1) {
376-
nid.x = 0;
377-
nid.y = 0;
378-
nid.port = CMN_NODEID_1x1_PID(id);
379-
nid.dev = CMN_NODEID_DEVID(id);
380-
} else {
381-
int bits = arm_cmn_xyidbits(cmn);
382-
383-
nid.x = CMN_NODEID_X(id, bits);
384-
nid.y = CMN_NODEID_Y(id, bits);
385-
if (cmn->ports_used & 0xc) {
386-
nid.port = CMN_NODEID_EXT_PID(id);
387-
nid.dev = CMN_NODEID_EXT_DEVID(id);
388-
} else {
389-
nid.port = CMN_NODEID_PID(id);
390-
nid.dev = CMN_NODEID_DEVID(id);
391-
}
392-
}
368+
nid.dev = dn->id & ((1U << dn->deviceid_bits) - 1);
369+
nid.port = (dn->id >> dn->deviceid_bits) & ((1U << dn->portid_bits) - 1);
393370
return nid;
394371
}
395372

396373
static struct arm_cmn_node *arm_cmn_node_to_xp(const struct arm_cmn *cmn,
397374
const struct arm_cmn_node *dn)
398375
{
399-
struct arm_cmn_nodeid nid = arm_cmn_nid(cmn, dn->id);
400-
int xp_idx = cmn->mesh_x * nid.y + nid.x;
376+
int id = dn->id >> (dn->portid_bits + dn->deviceid_bits);
377+
int bits = arm_cmn_xyidbits(cmn);
378+
int x = id >> bits;
379+
int y = id & ((1U << bits) - 1);
401380

402-
return cmn->xps + xp_idx;
381+
return cmn->xps + cmn->mesh_x * y + x;
403382
}
404383
static struct arm_cmn_node *arm_cmn_node(const struct arm_cmn *cmn,
405384
enum cmn_node_type type)
@@ -485,13 +464,13 @@ static const char *arm_cmn_device_type(u8 type)
485464
}
486465
}
487466

488-
static void arm_cmn_show_logid(struct seq_file *s, int x, int y, int p, int d)
467+
static void arm_cmn_show_logid(struct seq_file *s, const struct arm_cmn_node *xp, int p, int d)
489468
{
490469
struct arm_cmn *cmn = s->private;
491470
struct arm_cmn_node *dn;
471+
u16 id = xp->id | d | (p << xp->deviceid_bits);
492472

493473
for (dn = cmn->dns; dn->type; dn++) {
494-
struct arm_cmn_nodeid nid = arm_cmn_nid(cmn, dn->id);
495474
int pad = dn->logid < 10;
496475

497476
if (dn->type == CMN_TYPE_XP)
@@ -500,7 +479,7 @@ static void arm_cmn_show_logid(struct seq_file *s, int x, int y, int p, int d)
500479
if (dn->type < CMN_TYPE_HNI)
501480
continue;
502481

503-
if (nid.x != x || nid.y != y || nid.port != p || nid.dev != d)
482+
if (dn->id != id)
504483
continue;
505484

506485
seq_printf(s, " %*c#%-*d |", pad + 1, ' ', 3 - pad, dn->logid);
@@ -521,23 +500,22 @@ static int arm_cmn_map_show(struct seq_file *s, void *data)
521500
y = cmn->mesh_y;
522501
while (y--) {
523502
int xp_base = cmn->mesh_x * y;
503+
struct arm_cmn_node *xp = cmn->xps + xp_base;
524504
u8 port[CMN_MAX_PORTS][CMN_MAX_DIMENSION];
525505

526506
for (x = 0; x < cmn->mesh_x; x++)
527507
seq_puts(s, "--------+");
528508

529509
seq_printf(s, "\n%-2d |", y);
530510
for (x = 0; x < cmn->mesh_x; x++) {
531-
struct arm_cmn_node *xp = cmn->xps + xp_base + x;
532-
533511
for (p = 0; p < CMN_MAX_PORTS; p++)
534-
port[p][x] = arm_cmn_device_connect_info(cmn, xp, p);
512+
port[p][x] = arm_cmn_device_connect_info(cmn, xp + x, p);
535513
seq_printf(s, " XP #%-3d|", xp_base + x);
536514
}
537515

538516
seq_puts(s, "\n |");
539517
for (x = 0; x < cmn->mesh_x; x++) {
540-
s8 dtc = cmn->xps[xp_base + x].dtc;
518+
s8 dtc = xp[x].dtc;
541519

542520
if (dtc < 0)
543521
seq_puts(s, " DTC ?? |");
@@ -554,10 +532,10 @@ static int arm_cmn_map_show(struct seq_file *s, void *data)
554532
seq_puts(s, arm_cmn_device_type(port[p][x]));
555533
seq_puts(s, "\n 0|");
556534
for (x = 0; x < cmn->mesh_x; x++)
557-
arm_cmn_show_logid(s, x, y, p, 0);
535+
arm_cmn_show_logid(s, xp + x, p, 0);
558536
seq_puts(s, "\n 1|");
559537
for (x = 0; x < cmn->mesh_x; x++)
560-
arm_cmn_show_logid(s, x, y, p, 1);
538+
arm_cmn_show_logid(s, xp + x, p, 1);
561539
}
562540
seq_puts(s, "\n-----+");
563541
}
@@ -1815,10 +1793,7 @@ static int arm_cmn_event_init(struct perf_event *event)
18151793
}
18161794

18171795
if (!hw->num_dns) {
1818-
struct arm_cmn_nodeid nid = arm_cmn_nid(cmn, nodeid);
1819-
1820-
dev_dbg(cmn->dev, "invalid node 0x%x (%d,%d,%d,%d) type 0x%x\n",
1821-
nodeid, nid.x, nid.y, nid.port, nid.dev, type);
1796+
dev_dbg(cmn->dev, "invalid node 0x%x type 0x%x\n", nodeid, type);
18221797
return -EINVAL;
18231798
}
18241799

@@ -1921,7 +1896,7 @@ static int arm_cmn_event_add(struct perf_event *event, int flags)
19211896
arm_cmn_claim_wp_idx(dtm, event, d, wp_idx, i);
19221897
writel_relaxed(cfg, dtm->base + CMN_DTM_WPn_CONFIG(wp_idx));
19231898
} else {
1924-
struct arm_cmn_nodeid nid = arm_cmn_nid(cmn, dn->id);
1899+
struct arm_cmn_nodeid nid = arm_cmn_nid(dn);
19251900

19261901
if (cmn->multi_dtm)
19271902
nid.port %= 2;
@@ -2168,10 +2143,12 @@ static int arm_cmn_init_dtcs(struct arm_cmn *cmn)
21682143
continue;
21692144

21702145
xp = arm_cmn_node_to_xp(cmn, dn);
2146+
dn->portid_bits = xp->portid_bits;
2147+
dn->deviceid_bits = xp->deviceid_bits;
21712148
dn->dtc = xp->dtc;
21722149
dn->dtm = xp->dtm;
21732150
if (cmn->multi_dtm)
2174-
dn->dtm += arm_cmn_nid(cmn, dn->id).port / 2;
2151+
dn->dtm += arm_cmn_nid(dn).port / 2;
21752152

21762153
if (dn->type == CMN_TYPE_DTC) {
21772154
int err = arm_cmn_init_dtc(cmn, dn, dtc_idx++);
@@ -2341,18 +2318,27 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
23412318
arm_cmn_init_dtm(dtm++, xp, 0);
23422319
/*
23432320
* Keeping track of connected ports will let us filter out
2344-
* unnecessary XP events easily. We can also reliably infer the
2345-
* "extra device ports" configuration for the node ID format
2346-
* from this, since in that case we will see at least one XP
2347-
* with port 2 connected, for the HN-D.
2321+
* unnecessary XP events easily, and also infer the per-XP
2322+
* part of the node ID format.
23482323
*/
23492324
for (int p = 0; p < CMN_MAX_PORTS; p++)
23502325
if (arm_cmn_device_connect_info(cmn, xp, p))
23512326
xp_ports |= BIT(p);
23522327

2353-
if (cmn->multi_dtm && (xp_ports & 0xc))
2328+
if (cmn->num_xps == 1) {
2329+
xp->portid_bits = 3;
2330+
xp->deviceid_bits = 2;
2331+
} else if (xp_ports > 0x3) {
2332+
xp->portid_bits = 2;
2333+
xp->deviceid_bits = 1;
2334+
} else {
2335+
xp->portid_bits = 1;
2336+
xp->deviceid_bits = 2;
2337+
}
2338+
2339+
if (cmn->multi_dtm && (xp_ports > 0x3))
23542340
arm_cmn_init_dtm(dtm++, xp, 1);
2355-
if (cmn->multi_dtm && (xp_ports & 0x30))
2341+
if (cmn->multi_dtm && (xp_ports > 0xf))
23562342
arm_cmn_init_dtm(dtm++, xp, 2);
23572343

23582344
cmn->ports_used |= xp_ports;

0 commit comments

Comments
 (0)