Skip to content

Commit a687d9d

Browse files
rmurphy-armgregkh
authored andcommitted
perf/arm-cmn: Refactor node ID handling. Again.
[ Upstream commit e79634b ] 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 <[email protected]> Signed-off-by: Robin Murphy <[email protected]> Link: https://lore.kernel.org/r/5195f990152fc37adba5fbf5929a6b11063d9f09.1725296395.git.robin.murphy@arm.com Signed-off-by: Will Deacon <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent a1b2566 commit a687d9d

File tree

1 file changed

+40
-54
lines changed

1 file changed

+40
-54
lines changed

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)
@@ -281,8 +273,11 @@ struct arm_cmn_node {
281273
u16 id, logid;
282274
enum cmn_node_type type;
283275

276+
/* XP properties really, but replicated to children for convenience */
284277
u8 dtm;
285278
s8 dtc;
279+
u8 portid_bits:4;
280+
u8 deviceid_bits:4;
286281
/* DN/HN-F/CXHA */
287282
struct {
288283
u8 val : 4;
@@ -358,49 +353,33 @@ struct arm_cmn {
358353
static int arm_cmn_hp_state;
359354

360355
struct arm_cmn_nodeid {
361-
u8 x;
362-
u8 y;
363356
u8 port;
364357
u8 dev;
365358
};
366359

367360
static int arm_cmn_xyidbits(const struct arm_cmn *cmn)
368361
{
369-
return fls((cmn->mesh_x - 1) | (cmn->mesh_y - 1) | 2);
362+
return fls((cmn->mesh_x - 1) | (cmn->mesh_y - 1));
370363
}
371364

372-
static struct arm_cmn_nodeid arm_cmn_nid(const struct arm_cmn *cmn, u16 id)
365+
static struct arm_cmn_nodeid arm_cmn_nid(const struct arm_cmn_node *dn)
373366
{
374367
struct arm_cmn_nodeid nid;
375368

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

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

403-
return cmn->xps + xp_idx;
382+
return cmn->xps + cmn->mesh_x * y + x;
404383
}
405384
static struct arm_cmn_node *arm_cmn_node(const struct arm_cmn *cmn,
406385
enum cmn_node_type type)
@@ -486,13 +465,13 @@ static const char *arm_cmn_device_type(u8 type)
486465
}
487466
}
488467

489-
static void arm_cmn_show_logid(struct seq_file *s, int x, int y, int p, int d)
468+
static void arm_cmn_show_logid(struct seq_file *s, const struct arm_cmn_node *xp, int p, int d)
490469
{
491470
struct arm_cmn *cmn = s->private;
492471
struct arm_cmn_node *dn;
472+
u16 id = xp->id | d | (p << xp->deviceid_bits);
493473

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

498477
if (dn->type == CMN_TYPE_XP)
@@ -501,7 +480,7 @@ static void arm_cmn_show_logid(struct seq_file *s, int x, int y, int p, int d)
501480
if (dn->type < CMN_TYPE_HNI)
502481
continue;
503482

504-
if (nid.x != x || nid.y != y || nid.port != p || nid.dev != d)
483+
if (dn->id != id)
505484
continue;
506485

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

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

530510
seq_printf(s, "\n%-2d |", y);
531511
for (x = 0; x < cmn->mesh_x; x++) {
532-
struct arm_cmn_node *xp = cmn->xps + xp_base + x;
533-
534512
for (p = 0; p < CMN_MAX_PORTS; p++)
535-
port[p][x] = arm_cmn_device_connect_info(cmn, xp, p);
513+
port[p][x] = arm_cmn_device_connect_info(cmn, xp + x, p);
536514
seq_printf(s, " XP #%-3d|", xp_base + x);
537515
}
538516

539517
seq_puts(s, "\n |");
540518
for (x = 0; x < cmn->mesh_x; x++) {
541-
s8 dtc = cmn->xps[xp_base + x].dtc;
519+
s8 dtc = xp[x].dtc;
542520

543521
if (dtc < 0)
544522
seq_puts(s, " DTC ?? |");
@@ -555,10 +533,10 @@ static int arm_cmn_map_show(struct seq_file *s, void *data)
555533
seq_puts(s, arm_cmn_device_type(port[p][x]));
556534
seq_puts(s, "\n 0|");
557535
for (x = 0; x < cmn->mesh_x; x++)
558-
arm_cmn_show_logid(s, x, y, p, 0);
536+
arm_cmn_show_logid(s, xp + x, p, 0);
559537
seq_puts(s, "\n 1|");
560538
for (x = 0; x < cmn->mesh_x; x++)
561-
arm_cmn_show_logid(s, x, y, p, 1);
539+
arm_cmn_show_logid(s, xp + x, p, 1);
562540
}
563541
seq_puts(s, "\n-----+");
564542
}
@@ -1751,10 +1729,7 @@ static int arm_cmn_event_init(struct perf_event *event)
17511729
}
17521730

17531731
if (!hw->num_dns) {
1754-
struct arm_cmn_nodeid nid = arm_cmn_nid(cmn, nodeid);
1755-
1756-
dev_dbg(cmn->dev, "invalid node 0x%x (%d,%d,%d,%d) type 0x%x\n",
1757-
nodeid, nid.x, nid.y, nid.port, nid.dev, type);
1732+
dev_dbg(cmn->dev, "invalid node 0x%x type 0x%x\n", nodeid, type);
17581733
return -EINVAL;
17591734
}
17601735

@@ -1849,7 +1824,7 @@ static int arm_cmn_event_add(struct perf_event *event, int flags)
18491824
dtm->wp_event[wp_idx] = hw->dtc_idx[d];
18501825
writel_relaxed(cfg, dtm->base + CMN_DTM_WPn_CONFIG(wp_idx));
18511826
} else {
1852-
struct arm_cmn_nodeid nid = arm_cmn_nid(cmn, dn->id);
1827+
struct arm_cmn_nodeid nid = arm_cmn_nid(dn);
18531828

18541829
if (cmn->multi_dtm)
18551830
nid.port %= 2;
@@ -2096,10 +2071,12 @@ static int arm_cmn_init_dtcs(struct arm_cmn *cmn)
20962071
continue;
20972072

20982073
xp = arm_cmn_node_to_xp(cmn, dn);
2074+
dn->portid_bits = xp->portid_bits;
2075+
dn->deviceid_bits = xp->deviceid_bits;
20992076
dn->dtc = xp->dtc;
21002077
dn->dtm = xp->dtm;
21012078
if (cmn->multi_dtm)
2102-
dn->dtm += arm_cmn_nid(cmn, dn->id).port / 2;
2079+
dn->dtm += arm_cmn_nid(dn).port / 2;
21032080

21042081
if (dn->type == CMN_TYPE_DTC) {
21052082
int err = arm_cmn_init_dtc(cmn, dn, dtc_idx++);
@@ -2269,18 +2246,27 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
22692246
arm_cmn_init_dtm(dtm++, xp, 0);
22702247
/*
22712248
* Keeping track of connected ports will let us filter out
2272-
* unnecessary XP events easily. We can also reliably infer the
2273-
* "extra device ports" configuration for the node ID format
2274-
* from this, since in that case we will see at least one XP
2275-
* with port 2 connected, for the HN-D.
2249+
* unnecessary XP events easily, and also infer the per-XP
2250+
* part of the node ID format.
22762251
*/
22772252
for (int p = 0; p < CMN_MAX_PORTS; p++)
22782253
if (arm_cmn_device_connect_info(cmn, xp, p))
22792254
xp_ports |= BIT(p);
22802255

2281-
if (cmn->multi_dtm && (xp_ports & 0xc))
2256+
if (cmn->num_xps == 1) {
2257+
xp->portid_bits = 3;
2258+
xp->deviceid_bits = 2;
2259+
} else if (xp_ports > 0x3) {
2260+
xp->portid_bits = 2;
2261+
xp->deviceid_bits = 1;
2262+
} else {
2263+
xp->portid_bits = 1;
2264+
xp->deviceid_bits = 2;
2265+
}
2266+
2267+
if (cmn->multi_dtm && (xp_ports > 0x3))
22822268
arm_cmn_init_dtm(dtm++, xp, 1);
2283-
if (cmn->multi_dtm && (xp_ports & 0x30))
2269+
if (cmn->multi_dtm && (xp_ports > 0xf))
22842270
arm_cmn_init_dtm(dtm++, xp, 2);
22852271

22862272
cmn->ports_used |= xp_ports;

0 commit comments

Comments
 (0)