blob: fc9e5839b3696e8d01e4eb7b19bc5ff0ada87f90 [file] [log] [blame]
Patrick Williams2194f502022-10-16 14:26:09 -05001From 821c1c36ba8883a8709bbbcdf4ebc716e69da991 Mon Sep 17 00:00:00 2001
Brad Bishopbec4ebc2022-08-03 09:55:16 -04002From: Robin Murphy <robin.murphy@arm.com>
3Date: Fri, 3 Dec 2021 11:45:00 +0000
Patrick Williams2194f502022-10-16 14:26:09 -05004Subject: [PATCH 25/40] perf/arm-cmn: Support new IP features
Brad Bishopbec4ebc2022-08-03 09:55:16 -04005
6The second generation of CMN IPs add new node types and significantly
7expand the configuration space with options for extra device ports on
8edge XPs, either plumbed into the regular DTM or with extra dedicated
9DTMs to monitor them, plus larger (and smaller) mesh sizes. Add basic
10support for pulling this new information out of the hardware, piping
11it around as necessary, and handling (most of) the new choices.
12
13Signed-off-by: Robin Murphy <robin.murphy@arm.com>
14Link: https://lore.kernel.org/r/e58b495bcc7deec3882be4bac910ed0bf6979674.1638530442.git.robin.murphy@arm.com
15Signed-off-by: Will Deacon <will@kernel.org>
Patrick Williams2194f502022-10-16 14:26:09 -050016Upstream-Status = Backport [https://lore.kernel.org/r/e58b495bcc7deec3882be4bac910ed0bf6979674.1638530442.git.robin.murphy@arm.com]
Brad Bishopbec4ebc2022-08-03 09:55:16 -040017Signed-off-by: Rupinderjit Singh <rupinderjit.singh@arm.com>
Patrick Williams2194f502022-10-16 14:26:09 -050018Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Brad Bishopbec4ebc2022-08-03 09:55:16 -040019---
Patrick Williams2194f502022-10-16 14:26:09 -050020 drivers/perf/arm-cmn.c | 218 ++++++++++++++++++++++++++++++++---------
21 1 file changed, 171 insertions(+), 47 deletions(-)
Brad Bishopbec4ebc2022-08-03 09:55:16 -040022
23diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
Patrick Williams2194f502022-10-16 14:26:09 -050024index ce94f923a607..0a3f33a83c01 100644
Brad Bishopbec4ebc2022-08-03 09:55:16 -040025--- a/drivers/perf/arm-cmn.c
26+++ b/drivers/perf/arm-cmn.c
27@@ -24,7 +24,10 @@
28 #define CMN_NI_LOGICAL_ID GENMASK_ULL(47, 32)
29
30 #define CMN_NODEID_DEVID(reg) ((reg) & 3)
31+#define CMN_NODEID_EXT_DEVID(reg) ((reg) & 1)
32 #define CMN_NODEID_PID(reg) (((reg) >> 2) & 1)
33+#define CMN_NODEID_EXT_PID(reg) (((reg) >> 1) & 3)
34+#define CMN_NODEID_1x1_PID(reg) (((reg) >> 2) & 7)
35 #define CMN_NODEID_X(reg, bits) ((reg) >> (3 + (bits)))
36 #define CMN_NODEID_Y(reg, bits) (((reg) >> 3) & ((1U << (bits)) - 1))
37
38@@ -37,13 +40,26 @@
39
40 #define CMN_MAX_DIMENSION 8
41 #define CMN_MAX_XPS (CMN_MAX_DIMENSION * CMN_MAX_DIMENSION)
42-#define CMN_MAX_DTMS CMN_MAX_XPS
43+#define CMN_MAX_DTMS (CMN_MAX_XPS + (CMN_MAX_DIMENSION - 1) * 4)
44
45-/* The CFG node has one other useful purpose */
46+/* 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)
49
50-/* PMU registers occupy the 3rd 4KB page of each node's 16KB space */
51+#define CMN_CFGM_INFO_GLOBAL 0x900
52+#define CMN_INFO_MULTIPLE_DTM_EN BIT_ULL(63)
53+#define CMN_INFO_RSP_VC_NUM GENMASK_ULL(53, 52)
54+#define CMN_INFO_DAT_VC_NUM GENMASK_ULL(51, 50)
55+
56+/* XPs also have some local topology info which has uses too */
57+#define CMN_MXP__CONNECT_INFO_P0 0x0008
58+#define CMN_MXP__CONNECT_INFO_P1 0x0010
59+#define CMN_MXP__CONNECT_INFO_P2 0x0028
60+#define CMN_MXP__CONNECT_INFO_P3 0x0030
61+#define CMN_MXP__CONNECT_INFO_P4 0x0038
62+#define CMN_MXP__CONNECT_INFO_P5 0x0040
63+
64+/* PMU registers occupy the 3rd 4KB page of each node's region */
65 #define CMN_PMU_OFFSET 0x2000
66
67 /* For most nodes, this is all there is */
68@@ -53,6 +69,7 @@
69 /* DTMs live in the PMU space of XP registers */
70 #define CMN_DTM_WPn(n) (0x1A0 + (n) * 0x18)
71 #define CMN_DTM_WPn_CONFIG(n) (CMN_DTM_WPn(n) + 0x00)
72+#define CMN_DTM_WPn_CONFIG_WP_DEV_SEL2 GENMASK_ULL(18,17)
73 #define CMN_DTM_WPn_CONFIG_WP_COMBINE BIT(6)
74 #define CMN_DTM_WPn_CONFIG_WP_EXCLUSIVE BIT(5)
75 #define CMN_DTM_WPn_CONFIG_WP_GRP BIT(4)
76@@ -77,7 +94,11 @@
77
78 #define CMN_DTM_PMEVCNTSR 0x240
79
80+#define CMN_DTM_UNIT_INFO 0x0910
81+
82 #define CMN_DTM_NUM_COUNTERS 4
83+/* Want more local counters? Why not replicate the whole DTM! Ugh... */
84+#define CMN_DTM_OFFSET(n) ((n) * 0x200)
85
86 /* The DTC node is where the magic happens */
87 #define CMN_DT_DTC_CTL 0x0a00
88@@ -131,10 +152,10 @@
89 #define CMN_EVENT_NODEID(event) FIELD_GET(CMN_CONFIG_NODEID, (event)->attr.config)
90
91 #define CMN_CONFIG_WP_COMBINE GENMASK_ULL(27, 24)
92-#define CMN_CONFIG_WP_DEV_SEL BIT_ULL(48)
93-#define CMN_CONFIG_WP_CHN_SEL GENMASK_ULL(50, 49)
94-#define CMN_CONFIG_WP_GRP BIT_ULL(52)
95-#define CMN_CONFIG_WP_EXCLUSIVE BIT_ULL(53)
96+#define CMN_CONFIG_WP_DEV_SEL GENMASK_ULL(50, 48)
97+#define CMN_CONFIG_WP_CHN_SEL GENMASK_ULL(55, 51)
98+#define CMN_CONFIG_WP_GRP BIT_ULL(56)
99+#define CMN_CONFIG_WP_EXCLUSIVE BIT_ULL(57)
100 #define CMN_CONFIG1_WP_VAL GENMASK_ULL(63, 0)
101 #define CMN_CONFIG2_WP_MASK GENMASK_ULL(63, 0)
102
103@@ -176,9 +197,12 @@ enum cmn_node_type {
104 CMN_TYPE_HNF,
105 CMN_TYPE_XP,
106 CMN_TYPE_SBSX,
107- CMN_TYPE_RNI = 0xa,
108+ CMN_TYPE_MPAM_S,
109+ CMN_TYPE_MPAM_NS,
110+ CMN_TYPE_RNI,
111 CMN_TYPE_RND = 0xd,
112 CMN_TYPE_RNSAM = 0xf,
113+ CMN_TYPE_MTSX,
114 CMN_TYPE_CXRA = 0x100,
115 CMN_TYPE_CXHA = 0x101,
116 CMN_TYPE_CXLA = 0x102,
117@@ -233,6 +257,7 @@ struct arm_cmn_dtc {
118 struct arm_cmn {
119 struct device *dev;
120 void __iomem *base;
121+ unsigned int state;
122
123 enum cmn_revision rev;
124 enum cmn_model model;
125@@ -240,6 +265,13 @@ struct arm_cmn {
126 u8 mesh_y;
127 u16 num_xps;
128 u16 num_dns;
129+ bool multi_dtm;
130+ u8 ports_used;
131+ struct {
132+ unsigned int rsp_vc_num : 2;
133+ unsigned int dat_vc_num : 2;
134+ };
135+
136 struct arm_cmn_node *xps;
137 struct arm_cmn_node *dns;
138
139@@ -250,7 +282,6 @@ struct arm_cmn {
140 int cpu;
141 struct hlist_node cpuhp_node;
142
143- unsigned int state;
144 struct pmu pmu;
145 };
146
147@@ -275,13 +306,25 @@ static int arm_cmn_xyidbits(const struct arm_cmn *cmn)
148 static struct arm_cmn_nodeid arm_cmn_nid(const struct arm_cmn *cmn, u16 id)
149 {
150 struct arm_cmn_nodeid nid;
151- int bits = arm_cmn_xyidbits(cmn);
152
153- nid.x = CMN_NODEID_X(id, bits);
154- nid.y = CMN_NODEID_Y(id, bits);
155- nid.port = CMN_NODEID_PID(id);
156- nid.dev = CMN_NODEID_DEVID(id);
157+ if (cmn->num_xps == 1) {
158+ nid.x = 0;
159+ nid.y = 0;
160+ nid.port = CMN_NODEID_1x1_PID(id);
161+ nid.dev = CMN_NODEID_DEVID(id);
162+ } else {
163+ int bits = arm_cmn_xyidbits(cmn);
164
165+ nid.x = CMN_NODEID_X(id, bits);
166+ nid.y = CMN_NODEID_Y(id, bits);
167+ if (cmn->ports_used & 0xc) {
168+ nid.port = CMN_NODEID_EXT_PID(id);
169+ nid.dev = CMN_NODEID_EXT_DEVID(id);
170+ } else {
171+ nid.port = CMN_NODEID_PID(id);
172+ nid.dev = CMN_NODEID_DEVID(id);
173+ }
174+ }
175 return nid;
176 }
177
178@@ -310,6 +353,7 @@ struct arm_cmn_hw_event {
179 unsigned int dtc_idx;
180 u8 dtcs_used;
181 u8 num_dns;
182+ u8 dtm_offset;
183 };
184
185 #define for_each_hw_dn(hw, dn, i) \
186@@ -354,7 +398,8 @@ struct arm_cmn_format_attr {
187 .occupid = _occupid, \
188 }})[0].attr.attr)
189
190-static bool arm_cmn_is_occup_event(enum cmn_node_type type, unsigned int id)
191+static bool arm_cmn_is_occup_event(enum cmn_model model,
192+ enum cmn_node_type type, unsigned int id)
193 {
194 return (type == CMN_TYPE_DVM && id == 0x05) ||
195 (type == CMN_TYPE_HNF && id == 0x0f);
Patrick Williams2194f502022-10-16 14:26:09 -0500196@@ -375,7 +420,7 @@ static ssize_t arm_cmn_event_show(struct device *dev,
197 "type=0x%x,eventid=0x%x,wp_dev_sel=?,wp_chn_sel=?,wp_grp=?,wp_val=?,wp_mask=?\n",
198 eattr->type, eattr->eventid);
Brad Bishopbec4ebc2022-08-03 09:55:16 -0400199
200- if (arm_cmn_is_occup_event(eattr->type, eattr->eventid))
Brad Bishopbec4ebc2022-08-03 09:55:16 -0400201+ if (arm_cmn_is_occup_event(eattr->model, eattr->type, eattr->eventid))
Patrick Williams2194f502022-10-16 14:26:09 -0500202 return sysfs_emit(buf, "type=0x%x,eventid=0x%x,occupid=0x%x\n",
203 eattr->type, eattr->eventid, eattr->occupid);
Brad Bishopbec4ebc2022-08-03 09:55:16 -0400204
Brad Bishopbec4ebc2022-08-03 09:55:16 -0400205@@ -390,25 +435,36 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
206 struct device *dev = kobj_to_dev(kobj);
207 struct arm_cmn *cmn = to_cmn(dev_get_drvdata(dev));
208 struct arm_cmn_event_attr *eattr;
209- enum cmn_node_type type;
210
211 eattr = container_of(attr, typeof(*eattr), attr.attr);
212- type = eattr->type;
213
214 if (!(eattr->model & cmn->model))
215 return 0;
216
217- /* Watchpoints aren't nodes */
218- if (type == CMN_TYPE_WP)
219- type = CMN_TYPE_XP;
220+ /* Watchpoints aren't nodes, so avoid confusion */
221+ if (eattr->type == CMN_TYPE_WP)
222+ return attr->mode;
223+
224+ /* Hide XP events for unused interfaces/channels */
225+ if (eattr->type == CMN_TYPE_XP) {
226+ unsigned int intf = (eattr->eventid >> 2) & 7;
227+ unsigned int chan = eattr->eventid >> 5;
228+
229+ if ((intf & 4) && !(cmn->ports_used & BIT(intf & 3)))
230+ return 0;
231+
232+ if ((chan == 5 && cmn->rsp_vc_num < 2) ||
233+ (chan == 6 && cmn->dat_vc_num < 2))
234+ return 0;
235+ }
236
237 /* Revision-specific differences */
238 if (cmn->model == CMN600 && cmn->rev < CMN600_R1P2) {
239- if (type == CMN_TYPE_HNF && eattr->eventid == 0x1b)
240+ if (eattr->type == CMN_TYPE_HNF && eattr->eventid == 0x1b)
241 return 0;
242 }
243
244- if (!arm_cmn_node(cmn, type))
245+ if (!arm_cmn_node(cmn, eattr->type))
246 return 0;
247
248 return attr->mode;
249@@ -669,7 +725,8 @@ static u32 arm_cmn_wp_config(struct perf_event *event)
250 config = FIELD_PREP(CMN_DTM_WPn_CONFIG_WP_DEV_SEL, dev) |
251 FIELD_PREP(CMN_DTM_WPn_CONFIG_WP_CHN_SEL, chn) |
252 FIELD_PREP(CMN_DTM_WPn_CONFIG_WP_GRP, grp) |
253- FIELD_PREP(CMN_DTM_WPn_CONFIG_WP_EXCLUSIVE, exc);
254+ FIELD_PREP(CMN_DTM_WPn_CONFIG_WP_EXCLUSIVE, exc) |
255+ FIELD_PREP(CMN_DTM_WPn_CONFIG_WP_DEV_SEL2, dev >> 1);
256 if (combine && !grp)
257 config |= CMN_DTM_WPn_CONFIG_WP_COMBINE;
258
259@@ -712,7 +769,7 @@ static u64 arm_cmn_read_dtm(struct arm_cmn *cmn, struct arm_cmn_hw_event *hw,
260 offset = snapshot ? CMN_DTM_PMEVCNTSR : CMN_DTM_PMEVCNT;
261 for_each_hw_dn(hw, dn, i) {
262 if (dtm != &cmn->dtms[dn->dtm]) {
263- dtm = &cmn->dtms[dn->dtm];
264+ dtm = &cmn->dtms[dn->dtm] + hw->dtm_offset;
265 reg = readq_relaxed(dtm->base + offset);
266 }
267 dtm_idx = arm_cmn_get_index(hw->dtm_idx, i);
268@@ -800,8 +857,10 @@ static void arm_cmn_event_start(struct perf_event *event, int flags)
269 u64 mask = CMN_EVENT_WP_MASK(event);
270
271 for_each_hw_dn(hw, dn, i) {
272- writeq_relaxed(val, dn->pmu_base + CMN_DTM_WPn_VAL(wp_idx));
273- writeq_relaxed(mask, dn->pmu_base + CMN_DTM_WPn_MASK(wp_idx));
274+ void __iomem *base = dn->pmu_base + CMN_DTM_OFFSET(hw->dtm_offset);
275+
276+ writeq_relaxed(val, base + CMN_DTM_WPn_VAL(wp_idx));
277+ writeq_relaxed(mask, base + CMN_DTM_WPn_MASK(wp_idx));
278 }
279 } else for_each_hw_dn(hw, dn, i) {
280 int dtm_idx = arm_cmn_get_index(hw->dtm_idx, i);
281@@ -826,8 +885,10 @@ static void arm_cmn_event_stop(struct perf_event *event, int flags)
282 int wp_idx = arm_cmn_wp_idx(event);
283
284 for_each_hw_dn(hw, dn, i) {
285- writeq_relaxed(0, dn->pmu_base + CMN_DTM_WPn_MASK(wp_idx));
286- writeq_relaxed(~0ULL, dn->pmu_base + CMN_DTM_WPn_VAL(wp_idx));
287+ void __iomem *base = dn->pmu_base + CMN_DTM_OFFSET(hw->dtm_offset);
288+
289+ writeq_relaxed(0, base + CMN_DTM_WPn_MASK(wp_idx));
290+ writeq_relaxed(~0ULL, base + CMN_DTM_WPn_VAL(wp_idx));
291 }
292 } else for_each_hw_dn(hw, dn, i) {
293 int dtm_idx = arm_cmn_get_index(hw->dtm_idx, i);
294@@ -847,7 +908,8 @@ struct arm_cmn_val {
295 bool cycles;
296 };
297
298-static void arm_cmn_val_add_event(struct arm_cmn_val *val, struct perf_event *event)
299+static void arm_cmn_val_add_event(struct arm_cmn *cmn, struct arm_cmn_val *val,
300+ struct perf_event *event)
301 {
302 struct arm_cmn_hw_event *hw = to_cmn_hw(event);
303 struct arm_cmn_node *dn;
304@@ -865,7 +927,7 @@ static void arm_cmn_val_add_event(struct arm_cmn_val *val, struct perf_event *ev
305 }
306
307 val->dtc_count++;
308- if (arm_cmn_is_occup_event(type, CMN_EVENT_EVENTID(event)))
309+ if (arm_cmn_is_occup_event(cmn->model, type, CMN_EVENT_EVENTID(event)))
310 occupid = CMN_EVENT_OCCUPID(event) + 1;
311 else
312 occupid = 0;
313@@ -884,7 +946,7 @@ static void arm_cmn_val_add_event(struct arm_cmn_val *val, struct perf_event *ev
314 }
315 }
316
317-static int arm_cmn_validate_group(struct perf_event *event)
318+static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
319 {
320 struct arm_cmn_hw_event *hw = to_cmn_hw(event);
321 struct arm_cmn_node *dn;
322@@ -904,9 +966,9 @@ static int arm_cmn_validate_group(struct perf_event *event)
323 if (!val)
324 return -ENOMEM;
325
326- arm_cmn_val_add_event(val, leader);
327+ arm_cmn_val_add_event(cmn, val, leader);
328 for_each_sibling_event(sibling, leader)
329- arm_cmn_val_add_event(val, sibling);
330+ arm_cmn_val_add_event(cmn, val, sibling);
331
332 type = CMN_EVENT_TYPE(event);
333 if (type == CMN_TYPE_DTC) {
334@@ -917,7 +979,7 @@ static int arm_cmn_validate_group(struct perf_event *event)
335 if (val->dtc_count == CMN_DT_NUM_COUNTERS)
336 goto done;
337
338- if (arm_cmn_is_occup_event(type, CMN_EVENT_EVENTID(event)))
339+ if (arm_cmn_is_occup_event(cmn->model, type, CMN_EVENT_EVENTID(event)))
340 occupid = CMN_EVENT_OCCUPID(event) + 1;
341 else
342 occupid = 0;
343@@ -980,6 +1042,9 @@ static int arm_cmn_event_init(struct perf_event *event)
344 eventid = CMN_EVENT_EVENTID(event);
345 if (eventid != CMN_WP_UP && eventid != CMN_WP_DOWN)
346 return -EINVAL;
347+ /* ...but the DTM may depend on which port we're watching */
348+ if (cmn->multi_dtm)
349+ hw->dtm_offset = CMN_EVENT_WP_DEV_SEL(event) / 2;
350 }
351
352 bynodeid = CMN_EVENT_BYNODEID(event);
353@@ -1007,7 +1072,7 @@ static int arm_cmn_event_init(struct perf_event *event)
354 return -EINVAL;
355 }
356
357- return arm_cmn_validate_group(event);
358+ return arm_cmn_validate_group(cmn, event);
359 }
360
361 static void arm_cmn_event_clear(struct arm_cmn *cmn, struct perf_event *event,
362@@ -1017,13 +1082,13 @@ static void arm_cmn_event_clear(struct arm_cmn *cmn, struct perf_event *event,
363 enum cmn_node_type type = CMN_EVENT_TYPE(event);
364
365 while (i--) {
366- struct arm_cmn_dtm *dtm = &cmn->dtms[hw->dn[i].dtm];
367+ struct arm_cmn_dtm *dtm = &cmn->dtms[hw->dn[i].dtm] + hw->dtm_offset;
368 unsigned int dtm_idx = arm_cmn_get_index(hw->dtm_idx, i);
369
370 if (type == CMN_TYPE_WP)
371 dtm->wp_event[arm_cmn_wp_idx(event)] = -1;
372
373- if (arm_cmn_is_occup_event(type, CMN_EVENT_EVENTID(event)))
374+ if (arm_cmn_is_occup_event(cmn->model, type, CMN_EVENT_EVENTID(event)))
375 hw->dn[i].occupid_count--;
376
377 dtm->pmu_config_low &= ~CMN__PMEVCNT_PAIRED(dtm_idx);
378@@ -1069,7 +1134,7 @@ static int arm_cmn_event_add(struct perf_event *event, int flags)
379
380 /* ...then the local counters to feed it. */
381 for_each_hw_dn(hw, dn, i) {
382- struct arm_cmn_dtm *dtm = &cmn->dtms[dn->dtm];
383+ struct arm_cmn_dtm *dtm = &cmn->dtms[dn->dtm] + hw->dtm_offset;
384 unsigned int dtm_idx, shift;
385 u64 reg;
386
387@@ -1098,10 +1163,13 @@ static int arm_cmn_event_add(struct perf_event *event, int flags)
388 } else {
389 struct arm_cmn_nodeid nid = arm_cmn_nid(cmn, dn->id);
390
391+ if (cmn->multi_dtm)
392+ nid.port %= 2;
393+
394 input_sel = CMN__PMEVCNT0_INPUT_SEL_DEV + dtm_idx +
395 (nid.port << 4) + (nid.dev << 2);
396
397- if (arm_cmn_is_occup_event(type, CMN_EVENT_EVENTID(event))) {
398+ if (arm_cmn_is_occup_event(cmn->model, type, CMN_EVENT_EVENTID(event))) {
399 u8 occupid = CMN_EVENT_OCCUPID(event);
400
401 if (dn->occupid_count == 0) {
402@@ -1283,11 +1351,11 @@ static int arm_cmn_init_irqs(struct arm_cmn *cmn)
403 return 0;
404 }
405
406-static void arm_cmn_init_dtm(struct arm_cmn_dtm *dtm, struct arm_cmn_node *xp)
407+static void arm_cmn_init_dtm(struct arm_cmn_dtm *dtm, struct arm_cmn_node *xp, int idx)
408 {
409 int i;
410
411- dtm->base = xp->pmu_base;
412+ dtm->base = xp->pmu_base + CMN_DTM_OFFSET(idx);
413 dtm->pmu_config_low = CMN_DTM_PMU_CONFIG_PMU_EN;
414 for (i = 0; i < 4; i++) {
415 dtm->wp_event[i] = -1;
416@@ -1345,6 +1413,8 @@ static int arm_cmn_init_dtcs(struct arm_cmn *cmn)
417
418 xp = arm_cmn_node_to_xp(cmn, dn);
419 dn->dtm = xp->dtm;
420+ if (cmn->multi_dtm)
421+ dn->dtm += arm_cmn_nid(cmn, dn->id).port / 2;
422
423 if (dn->type == CMN_TYPE_DTC) {
424 int err;
425@@ -1408,6 +1478,11 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
426 reg = readl_relaxed(cfg_region + CMN_CFGM_PERIPH_ID_2);
427 cmn->rev = FIELD_GET(CMN_CFGM_PID2_REVISION, reg);
428
429+ reg = readq_relaxed(cfg_region + CMN_CFGM_INFO_GLOBAL);
430+ cmn->multi_dtm = reg & CMN_INFO_MULTIPLE_DTM_EN;
431+ cmn->rsp_vc_num = FIELD_GET(CMN_INFO_RSP_VC_NUM, reg);
432+ cmn->dat_vc_num = FIELD_GET(CMN_INFO_DAT_VC_NUM, reg);
433+
434 reg = readq_relaxed(cfg_region + CMN_CHILD_INFO);
435 child_count = FIELD_GET(CMN_CI_CHILD_COUNT, reg);
436 child_poff = FIELD_GET(CMN_CI_CHILD_PTR_OFFSET, reg);
437@@ -1429,7 +1504,11 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
438 if (!dn)
439 return -ENOMEM;
440
441- dtm = devm_kcalloc(cmn->dev, cmn->num_xps, sizeof(*dtm), GFP_KERNEL);
442+ /* Initial safe upper bound on DTMs for any possible mesh layout */
443+ i = cmn->num_xps;
444+ if (cmn->multi_dtm)
445+ i += cmn->num_xps + 1;
446+ dtm = devm_kcalloc(cmn->dev, i, sizeof(*dtm), GFP_KERNEL);
447 if (!dtm)
448 return -ENOMEM;
449
450@@ -1439,6 +1518,7 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
451 for (i = 0; i < cmn->num_xps; i++) {
452 void __iomem *xp_region = cmn->base + xp_offset[i];
453 struct arm_cmn_node *xp = dn++;
454+ unsigned int xp_ports = 0;
455
456 arm_cmn_init_node_info(cmn, xp_offset[i], xp);
457 /*
458@@ -1450,9 +1530,39 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
459 if (xp->id == (1 << 3))
460 cmn->mesh_x = xp->logid;
461
462- xp->dtc = 0xf;
463+ if (cmn->model == CMN600)
464+ xp->dtc = 0xf;
465+ else
466+ xp->dtc = 1 << readl_relaxed(xp_region + CMN_DTM_UNIT_INFO);
467+
468 xp->dtm = dtm - cmn->dtms;
469- arm_cmn_init_dtm(dtm++, xp);
470+ arm_cmn_init_dtm(dtm++, xp, 0);
471+ /*
472+ * Keeping track of connected ports will let us filter out
473+ * unnecessary XP events easily. We can also reliably infer the
474+ * "extra device ports" configuration for the node ID format
475+ * from this, since in that case we will see at least one XP
476+ * with port 2 connected, for the HN-D.
477+ */
478+ if (readq_relaxed(xp_region + CMN_MXP__CONNECT_INFO_P0))
479+ xp_ports |= BIT(0);
480+ if (readq_relaxed(xp_region + CMN_MXP__CONNECT_INFO_P1))
481+ xp_ports |= BIT(1);
482+ if (readq_relaxed(xp_region + CMN_MXP__CONNECT_INFO_P2))
483+ xp_ports |= BIT(2);
484+ if (readq_relaxed(xp_region + CMN_MXP__CONNECT_INFO_P3))
485+ xp_ports |= BIT(3);
486+ if (readq_relaxed(xp_region + CMN_MXP__CONNECT_INFO_P4))
487+ xp_ports |= BIT(4);
488+ if (readq_relaxed(xp_region + CMN_MXP__CONNECT_INFO_P5))
489+ xp_ports |= BIT(5);
490+
491+ if (cmn->multi_dtm && (xp_ports & 0xc))
492+ arm_cmn_init_dtm(dtm++, xp, 1);
493+ if (cmn->multi_dtm && (xp_ports & 0x30))
494+ arm_cmn_init_dtm(dtm++, xp, 2);
495+
496+ cmn->ports_used |= xp_ports;
497
498 reg = readq_relaxed(xp_region + CMN_CHILD_INFO);
499 child_count = FIELD_GET(CMN_CI_CHILD_COUNT, reg);
500@@ -1488,11 +1598,14 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
501 case CMN_TYPE_SBSX:
502 case CMN_TYPE_RNI:
503 case CMN_TYPE_RND:
504+ case CMN_TYPE_MTSX:
505 case CMN_TYPE_CXRA:
506 case CMN_TYPE_CXHA:
507 dn++;
508 break;
509 /* Nothing to see here */
510+ case CMN_TYPE_MPAM_S:
511+ case CMN_TYPE_MPAM_NS:
512 case CMN_TYPE_RNSAM:
513 case CMN_TYPE_CXLA:
514 break;
515@@ -1512,6 +1625,11 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
516 if (dn)
517 cmn->dns = dn;
518
519+ sz = (void *)dtm - (void *)cmn->dtms;
520+ dtm = devm_krealloc(cmn->dev, cmn->dtms, sz, GFP_KERNEL);
521+ if (dtm)
522+ cmn->dtms = dtm;
523+
524 /*
525 * If mesh_x wasn't set during discovery then we never saw
526 * an XP at (0,1), thus we must have an Nx1 configuration.
527@@ -1520,9 +1638,15 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
528 cmn->mesh_x = cmn->num_xps;
529 cmn->mesh_y = cmn->num_xps / cmn->mesh_x;
530
531+ /* 1x1 config plays havoc with XP event encodings */
532+ if (cmn->num_xps == 1)
533+ dev_warn(cmn->dev, "1x1 config not fully supported, translate XP events manually\n");
534+
535 dev_dbg(cmn->dev, "model %d, periph_id_2 revision %d\n", cmn->model, cmn->rev);
536- dev_dbg(cmn->dev, "mesh %dx%d, ID width %d\n",
537- cmn->mesh_x, cmn->mesh_y, arm_cmn_xyidbits(cmn));
538+ reg = cmn->ports_used;
539+ dev_dbg(cmn->dev, "mesh %dx%d, ID width %d, ports %6pbl%s\n",
540+ cmn->mesh_x, cmn->mesh_y, arm_cmn_xyidbits(cmn), &reg,
541+ cmn->multi_dtm ? ", multi-DTM" : "");
542
543 return 0;
544 }
545--
Patrick Williams2194f502022-10-16 14:26:09 -05005462.34.1
Brad Bishopbec4ebc2022-08-03 09:55:16 -0400547