xref: /linux/drivers/net/dsa/mv88e6xxx/devlink.c (revision 18f65355e112dfc87d5e2e8a299119afd2e65e7e)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 #include <net/dsa.h>
3 
4 #include "chip.h"
5 #include "devlink.h"
6 #include "global1.h"
7 #include "global2.h"
8 #include "port.h"
9 
10 static int mv88e6xxx_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash)
11 {
12 	if (chip->info->ops->atu_get_hash)
13 		return chip->info->ops->atu_get_hash(chip, hash);
14 
15 	return -EOPNOTSUPP;
16 }
17 
18 static int mv88e6xxx_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash)
19 {
20 	if (chip->info->ops->atu_set_hash)
21 		return chip->info->ops->atu_set_hash(chip, hash);
22 
23 	return -EOPNOTSUPP;
24 }
25 
26 enum mv88e6xxx_devlink_param_id {
27 	MV88E6XXX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
28 	MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
29 };
30 
31 int mv88e6xxx_devlink_param_get(struct dsa_switch *ds, u32 id,
32 				struct devlink_param_gset_ctx *ctx)
33 {
34 	struct mv88e6xxx_chip *chip = ds->priv;
35 	int err;
36 
37 	mv88e6xxx_reg_lock(chip);
38 
39 	switch (id) {
40 	case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
41 		err = mv88e6xxx_atu_get_hash(chip, &ctx->val.vu8);
42 		break;
43 	default:
44 		err = -EOPNOTSUPP;
45 		break;
46 	}
47 
48 	mv88e6xxx_reg_unlock(chip);
49 
50 	return err;
51 }
52 
53 int mv88e6xxx_devlink_param_set(struct dsa_switch *ds, u32 id,
54 				struct devlink_param_gset_ctx *ctx)
55 {
56 	struct mv88e6xxx_chip *chip = ds->priv;
57 	int err;
58 
59 	mv88e6xxx_reg_lock(chip);
60 
61 	switch (id) {
62 	case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
63 		err = mv88e6xxx_atu_set_hash(chip, ctx->val.vu8);
64 		break;
65 	default:
66 		err = -EOPNOTSUPP;
67 		break;
68 	}
69 
70 	mv88e6xxx_reg_unlock(chip);
71 
72 	return err;
73 }
74 
75 static const struct devlink_param mv88e6xxx_devlink_params[] = {
76 	DSA_DEVLINK_PARAM_DRIVER(MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
77 				 "ATU_hash", DEVLINK_PARAM_TYPE_U8,
78 				 BIT(DEVLINK_PARAM_CMODE_RUNTIME)),
79 };
80 
81 int mv88e6xxx_setup_devlink_params(struct dsa_switch *ds)
82 {
83 	return dsa_devlink_params_register(ds, mv88e6xxx_devlink_params,
84 					   ARRAY_SIZE(mv88e6xxx_devlink_params));
85 }
86 
87 void mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds)
88 {
89 	dsa_devlink_params_unregister(ds, mv88e6xxx_devlink_params,
90 				      ARRAY_SIZE(mv88e6xxx_devlink_params));
91 }
92 
93 enum mv88e6xxx_devlink_resource_id {
94 	MV88E6XXX_RESOURCE_ID_NONE,  /* DEVLINK_RESOURCE_ID_PARENT_TOP */
95 	MV88E6XXX_RESOURCE_ID_ATU,
96 	MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
97 	MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
98 	MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
99 	MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
100 };
101 
102 static u64 mv88e6xxx_devlink_atu_bin_get(struct mv88e6xxx_chip *chip,
103 					 u16 bin)
104 {
105 	u16 occupancy = 0;
106 	int err;
107 
108 	mv88e6xxx_reg_lock(chip);
109 
110 	err = mv88e6xxx_g2_atu_stats_set(chip, MV88E6XXX_G2_ATU_STATS_MODE_ALL,
111 					 bin);
112 	if (err) {
113 		dev_err(chip->dev, "failed to set ATU stats kind/bin\n");
114 		goto unlock;
115 	}
116 
117 	err = mv88e6xxx_g1_atu_get_next(chip, 0);
118 	if (err) {
119 		dev_err(chip->dev, "failed to perform ATU get next\n");
120 		goto unlock;
121 	}
122 
123 	err = mv88e6xxx_g2_atu_stats_get(chip, &occupancy);
124 	if (err) {
125 		dev_err(chip->dev, "failed to get ATU stats\n");
126 		goto unlock;
127 	}
128 
129 	occupancy &= MV88E6XXX_G2_ATU_STATS_MASK;
130 
131 unlock:
132 	mv88e6xxx_reg_unlock(chip);
133 
134 	return occupancy;
135 }
136 
137 static u64 mv88e6xxx_devlink_atu_bin_0_get(void *priv)
138 {
139 	struct mv88e6xxx_chip *chip = priv;
140 
141 	return mv88e6xxx_devlink_atu_bin_get(chip,
142 					     MV88E6XXX_G2_ATU_STATS_BIN_0);
143 }
144 
145 static u64 mv88e6xxx_devlink_atu_bin_1_get(void *priv)
146 {
147 	struct mv88e6xxx_chip *chip = priv;
148 
149 	return mv88e6xxx_devlink_atu_bin_get(chip,
150 					     MV88E6XXX_G2_ATU_STATS_BIN_1);
151 }
152 
153 static u64 mv88e6xxx_devlink_atu_bin_2_get(void *priv)
154 {
155 	struct mv88e6xxx_chip *chip = priv;
156 
157 	return mv88e6xxx_devlink_atu_bin_get(chip,
158 					     MV88E6XXX_G2_ATU_STATS_BIN_2);
159 }
160 
161 static u64 mv88e6xxx_devlink_atu_bin_3_get(void *priv)
162 {
163 	struct mv88e6xxx_chip *chip = priv;
164 
165 	return mv88e6xxx_devlink_atu_bin_get(chip,
166 					     MV88E6XXX_G2_ATU_STATS_BIN_3);
167 }
168 
169 static u64 mv88e6xxx_devlink_atu_get(void *priv)
170 {
171 	return mv88e6xxx_devlink_atu_bin_0_get(priv) +
172 		mv88e6xxx_devlink_atu_bin_1_get(priv) +
173 		mv88e6xxx_devlink_atu_bin_2_get(priv) +
174 		mv88e6xxx_devlink_atu_bin_3_get(priv);
175 }
176 
177 int mv88e6xxx_setup_devlink_resources(struct dsa_switch *ds)
178 {
179 	struct devlink_resource_size_params size_params;
180 	struct mv88e6xxx_chip *chip = ds->priv;
181 	int err;
182 
183 	devlink_resource_size_params_init(&size_params,
184 					  mv88e6xxx_num_macs(chip),
185 					  mv88e6xxx_num_macs(chip),
186 					  1, DEVLINK_RESOURCE_UNIT_ENTRY);
187 
188 	err = dsa_devlink_resource_register(ds, "ATU",
189 					    mv88e6xxx_num_macs(chip),
190 					    MV88E6XXX_RESOURCE_ID_ATU,
191 					    DEVLINK_RESOURCE_ID_PARENT_TOP,
192 					    &size_params);
193 	if (err)
194 		goto out;
195 
196 	devlink_resource_size_params_init(&size_params,
197 					  mv88e6xxx_num_macs(chip) / 4,
198 					  mv88e6xxx_num_macs(chip) / 4,
199 					  1, DEVLINK_RESOURCE_UNIT_ENTRY);
200 
201 	err = dsa_devlink_resource_register(ds, "ATU_bin_0",
202 					    mv88e6xxx_num_macs(chip) / 4,
203 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
204 					    DEVLINK_RESOURCE_ID_PARENT_TOP,
205 					    &size_params);
206 	if (err)
207 		goto out;
208 
209 	err = dsa_devlink_resource_register(ds, "ATU_bin_1",
210 					    mv88e6xxx_num_macs(chip) / 4,
211 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
212 					    DEVLINK_RESOURCE_ID_PARENT_TOP,
213 					    &size_params);
214 	if (err)
215 		goto out;
216 
217 	err = dsa_devlink_resource_register(ds, "ATU_bin_2",
218 					    mv88e6xxx_num_macs(chip) / 4,
219 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
220 					    DEVLINK_RESOURCE_ID_PARENT_TOP,
221 					    &size_params);
222 	if (err)
223 		goto out;
224 
225 	err = dsa_devlink_resource_register(ds, "ATU_bin_3",
226 					    mv88e6xxx_num_macs(chip) / 4,
227 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
228 					    DEVLINK_RESOURCE_ID_PARENT_TOP,
229 					    &size_params);
230 	if (err)
231 		goto out;
232 
233 	dsa_devlink_resource_occ_get_register(ds,
234 					      MV88E6XXX_RESOURCE_ID_ATU,
235 					      mv88e6xxx_devlink_atu_get,
236 					      chip);
237 
238 	dsa_devlink_resource_occ_get_register(ds,
239 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
240 					      mv88e6xxx_devlink_atu_bin_0_get,
241 					      chip);
242 
243 	dsa_devlink_resource_occ_get_register(ds,
244 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
245 					      mv88e6xxx_devlink_atu_bin_1_get,
246 					      chip);
247 
248 	dsa_devlink_resource_occ_get_register(ds,
249 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
250 					      mv88e6xxx_devlink_atu_bin_2_get,
251 					      chip);
252 
253 	dsa_devlink_resource_occ_get_register(ds,
254 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
255 					      mv88e6xxx_devlink_atu_bin_3_get,
256 					      chip);
257 
258 	return 0;
259 
260 out:
261 	dsa_devlink_resources_unregister(ds);
262 	return err;
263 }
264 
265 static int mv88e6xxx_region_global_snapshot(struct devlink *dl,
266 					    const struct devlink_region_ops *ops,
267 					    struct netlink_ext_ack *extack,
268 					    u8 **data)
269 {
270 	struct mv88e6xxx_region_priv *region_priv = ops->priv;
271 	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
272 	struct mv88e6xxx_chip *chip = ds->priv;
273 	u16 *registers;
274 	int i, err;
275 
276 	registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);
277 	if (!registers)
278 		return -ENOMEM;
279 
280 	mv88e6xxx_reg_lock(chip);
281 	for (i = 0; i < 32; i++) {
282 		switch (region_priv->id) {
283 		case MV88E6XXX_REGION_GLOBAL1:
284 			err = mv88e6xxx_g1_read(chip, i, &registers[i]);
285 			break;
286 		case MV88E6XXX_REGION_GLOBAL2:
287 			err = mv88e6xxx_g2_read(chip, i, &registers[i]);
288 			break;
289 		default:
290 			err = -EOPNOTSUPP;
291 		}
292 
293 		if (err) {
294 			kfree(registers);
295 			goto out;
296 		}
297 	}
298 	*data = (u8 *)registers;
299 out:
300 	mv88e6xxx_reg_unlock(chip);
301 
302 	return err;
303 }
304 
305 /* The ATU entry varies between mv88e6xxx chipset generations. Define
306  * a generic format which covers all the current and hopefully future
307  * mv88e6xxx generations
308  */
309 
310 struct mv88e6xxx_devlink_atu_entry {
311 	/* The FID is scattered over multiple registers. */
312 	u16 fid;
313 	u16 atu_op;
314 	u16 atu_data;
315 	u16 atu_01;
316 	u16 atu_23;
317 	u16 atu_45;
318 };
319 
320 static int mv88e6xxx_region_atu_snapshot_fid(struct mv88e6xxx_chip *chip,
321 					     int fid,
322 					     struct mv88e6xxx_devlink_atu_entry *table,
323 					     int *count)
324 {
325 	u16 atu_op, atu_data, atu_01, atu_23, atu_45;
326 	struct mv88e6xxx_atu_entry addr;
327 	int err;
328 
329 	addr.state = 0;
330 	eth_broadcast_addr(addr.mac);
331 
332 	do {
333 		err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
334 		if (err)
335 			return err;
336 
337 		if (!addr.state)
338 			break;
339 
340 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &atu_op);
341 		if (err)
342 			return err;
343 
344 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_DATA, &atu_data);
345 		if (err)
346 			return err;
347 
348 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC01, &atu_01);
349 		if (err)
350 			return err;
351 
352 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC23, &atu_23);
353 		if (err)
354 			return err;
355 
356 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC45, &atu_45);
357 		if (err)
358 			return err;
359 
360 		table[*count].fid = fid;
361 		table[*count].atu_op = atu_op;
362 		table[*count].atu_data = atu_data;
363 		table[*count].atu_01 = atu_01;
364 		table[*count].atu_23 = atu_23;
365 		table[*count].atu_45 = atu_45;
366 		(*count)++;
367 	} while (!is_broadcast_ether_addr(addr.mac));
368 
369 	return 0;
370 }
371 
372 static int mv88e6xxx_region_atu_snapshot(struct devlink *dl,
373 					 const struct devlink_region_ops *ops,
374 					 struct netlink_ext_ack *extack,
375 					 u8 **data)
376 {
377 	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
378 	struct mv88e6xxx_devlink_atu_entry *table;
379 	struct mv88e6xxx_chip *chip = ds->priv;
380 	int fid = -1, err = 0, count = 0;
381 
382 	table = kzalloc_objs(struct mv88e6xxx_devlink_atu_entry,
383 			     mv88e6xxx_num_databases(chip));
384 	if (!table)
385 		return -ENOMEM;
386 
387 	mv88e6xxx_reg_lock(chip);
388 
389 	while (1) {
390 		fid = find_next_bit(chip->fid_bitmap, MV88E6XXX_N_FID, fid + 1);
391 		if (fid == MV88E6XXX_N_FID)
392 			break;
393 
394 		err =  mv88e6xxx_region_atu_snapshot_fid(chip, fid, table,
395 							 &count);
396 		if (err) {
397 			kfree(table);
398 			goto out;
399 		}
400 	}
401 	*data = (u8 *)table;
402 out:
403 	mv88e6xxx_reg_unlock(chip);
404 
405 	return err;
406 }
407 
408 /**
409  * struct mv88e6xxx_devlink_vtu_entry - Devlink VTU entry
410  * @fid:   Global1/2:   FID and VLAN policy.
411  * @sid:   Global1/3:   SID, unknown filters and learning.
412  * @op:    Global1/5:   FID (old chipsets).
413  * @vid:   Global1/6:   VID, valid, and page.
414  * @data:  Global1/7-9: Membership data and priority override.
415  * @resvd: Reserved. Also happens to align the size to 16B.
416  *
417  * The VTU entry format varies between chipset generations, the
418  * descriptions above represent the superset of all possible
419  * information, not all fields are valid on all devices. Since this is
420  * a low-level debug interface, copy all data verbatim and defer
421  * parsing to the consumer.
422  */
423 struct mv88e6xxx_devlink_vtu_entry {
424 	u16 fid;
425 	u16 sid;
426 	u16 op;
427 	u16 vid;
428 	u16 data[3];
429 	u16 resvd;
430 };
431 
432 static int mv88e6xxx_region_vtu_snapshot(struct devlink *dl,
433 					 const struct devlink_region_ops *ops,
434 					 struct netlink_ext_ack *extack,
435 					 u8 **data)
436 {
437 	struct mv88e6xxx_devlink_vtu_entry *table, *entry;
438 	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
439 	struct mv88e6xxx_chip *chip = ds->priv;
440 	struct mv88e6xxx_vtu_entry vlan;
441 	int err;
442 
443 	table = kzalloc_objs(struct mv88e6xxx_devlink_vtu_entry,
444 			     mv88e6xxx_max_vid(chip) + 1);
445 	if (!table)
446 		return -ENOMEM;
447 
448 	entry = table;
449 	vlan.vid = mv88e6xxx_max_vid(chip);
450 	vlan.valid = false;
451 
452 	mv88e6xxx_reg_lock(chip);
453 
454 	do {
455 		err = mv88e6xxx_g1_vtu_getnext(chip, &vlan);
456 		if (err)
457 			break;
458 
459 		if (!vlan.valid)
460 			break;
461 
462 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_FID,
463 						&entry->fid);
464 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,
465 						&entry->sid);
466 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP,
467 						&entry->op);
468 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,
469 						&entry->vid);
470 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,
471 						&entry->data[0]);
472 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,
473 						&entry->data[1]);
474 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,
475 						&entry->data[2]);
476 		if (err)
477 			break;
478 
479 		entry++;
480 	} while (vlan.vid < mv88e6xxx_max_vid(chip));
481 
482 	mv88e6xxx_reg_unlock(chip);
483 
484 	if (err) {
485 		kfree(table);
486 		return err;
487 	}
488 
489 	*data = (u8 *)table;
490 	return 0;
491 }
492 
493 /**
494  * struct mv88e6xxx_devlink_stu_entry - Devlink STU entry
495  * @sid:   Global1/3:   SID, unknown filters and learning.
496  * @vid:   Global1/6:   Valid bit.
497  * @data:  Global1/7-9: Membership data and priority override.
498  * @resvd: Reserved. In case we forgot something.
499  *
500  * The STU entry format varies between chipset generations. Peridot
501  * and Amethyst packs the STU data into Global1/7-8. Older silicon
502  * spreads the information across all three VTU data registers -
503  * inheriting the layout of even older hardware that had no STU at
504  * all. Since this is a low-level debug interface, copy all data
505  * verbatim and defer parsing to the consumer.
506  */
507 struct mv88e6xxx_devlink_stu_entry {
508 	u16 sid;
509 	u16 vid;
510 	u16 data[3];
511 	u16 resvd;
512 };
513 
514 static int mv88e6xxx_region_stu_snapshot(struct devlink *dl,
515 					 const struct devlink_region_ops *ops,
516 					 struct netlink_ext_ack *extack,
517 					 u8 **data)
518 {
519 	struct mv88e6xxx_devlink_stu_entry *table, *entry;
520 	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
521 	struct mv88e6xxx_chip *chip = ds->priv;
522 	struct mv88e6xxx_stu_entry stu;
523 	int err;
524 
525 	table = kzalloc_objs(struct mv88e6xxx_devlink_stu_entry,
526 			     mv88e6xxx_max_sid(chip) + 1);
527 	if (!table)
528 		return -ENOMEM;
529 
530 	entry = table;
531 	stu.sid = mv88e6xxx_max_sid(chip);
532 	stu.valid = false;
533 
534 	mv88e6xxx_reg_lock(chip);
535 
536 	do {
537 		err = mv88e6xxx_g1_stu_getnext(chip, &stu);
538 		if (err)
539 			break;
540 
541 		if (!stu.valid)
542 			break;
543 
544 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,
545 						&entry->sid);
546 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,
547 						&entry->vid);
548 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,
549 						&entry->data[0]);
550 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,
551 						&entry->data[1]);
552 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,
553 						&entry->data[2]);
554 		if (err)
555 			break;
556 
557 		entry++;
558 	} while (stu.sid < mv88e6xxx_max_sid(chip));
559 
560 	mv88e6xxx_reg_unlock(chip);
561 
562 	if (err) {
563 		kfree(table);
564 		return err;
565 	}
566 
567 	*data = (u8 *)table;
568 	return 0;
569 }
570 
571 static int mv88e6xxx_region_pvt_snapshot(struct devlink *dl,
572 					 const struct devlink_region_ops *ops,
573 					 struct netlink_ext_ack *extack,
574 					 u8 **data)
575 {
576 	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
577 	struct mv88e6xxx_chip *chip = ds->priv;
578 	int dev, port, err;
579 	u16 *pvt, *cur;
580 
581 	pvt = kcalloc(MV88E6XXX_MAX_PVT_ENTRIES, sizeof(*pvt), GFP_KERNEL);
582 	if (!pvt)
583 		return -ENOMEM;
584 
585 	mv88e6xxx_reg_lock(chip);
586 
587 	cur = pvt;
588 	for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; dev++) {
589 		for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; port++) {
590 			err = mv88e6xxx_g2_pvt_read(chip, dev, port, cur);
591 			if (err)
592 				break;
593 
594 			cur++;
595 		}
596 	}
597 
598 	mv88e6xxx_reg_unlock(chip);
599 
600 	if (err) {
601 		kfree(pvt);
602 		return err;
603 	}
604 
605 	*data = (u8 *)pvt;
606 	return 0;
607 }
608 
609 static int mv88e6xxx_region_port_snapshot(struct devlink_port *devlink_port,
610 					  const struct devlink_port_region_ops *ops,
611 					  struct netlink_ext_ack *extack,
612 					  u8 **data)
613 {
614 	struct dsa_switch *ds = dsa_devlink_port_to_ds(devlink_port);
615 	int port = dsa_devlink_port_to_port(devlink_port);
616 	struct mv88e6xxx_chip *chip = ds->priv;
617 	u16 *registers;
618 	int i, err;
619 
620 	registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);
621 	if (!registers)
622 		return -ENOMEM;
623 
624 	mv88e6xxx_reg_lock(chip);
625 	for (i = 0; i < 32; i++) {
626 		err = mv88e6xxx_port_read(chip, port, i, &registers[i]);
627 		if (err) {
628 			kfree(registers);
629 			goto out;
630 		}
631 	}
632 	*data = (u8 *)registers;
633 out:
634 	mv88e6xxx_reg_unlock(chip);
635 
636 	return err;
637 }
638 
639 static struct mv88e6xxx_region_priv mv88e6xxx_region_global1_priv = {
640 	.id = MV88E6XXX_REGION_GLOBAL1,
641 };
642 
643 static const struct devlink_region_ops mv88e6xxx_region_global1_ops = {
644 	.name = "global1",
645 	.snapshot = mv88e6xxx_region_global_snapshot,
646 	.destructor = kfree,
647 	.priv = &mv88e6xxx_region_global1_priv,
648 };
649 
650 static struct mv88e6xxx_region_priv mv88e6xxx_region_global2_priv = {
651 	.id = MV88E6XXX_REGION_GLOBAL2,
652 };
653 
654 static const struct devlink_region_ops mv88e6xxx_region_global2_ops = {
655 	.name = "global2",
656 	.snapshot = mv88e6xxx_region_global_snapshot,
657 	.destructor = kfree,
658 	.priv = &mv88e6xxx_region_global2_priv,
659 };
660 
661 static const struct devlink_region_ops mv88e6xxx_region_atu_ops = {
662 	.name = "atu",
663 	.snapshot = mv88e6xxx_region_atu_snapshot,
664 	.destructor = kfree,
665 };
666 
667 static const struct devlink_region_ops mv88e6xxx_region_vtu_ops = {
668 	.name = "vtu",
669 	.snapshot = mv88e6xxx_region_vtu_snapshot,
670 	.destructor = kfree,
671 };
672 
673 static const struct devlink_region_ops mv88e6xxx_region_stu_ops = {
674 	.name = "stu",
675 	.snapshot = mv88e6xxx_region_stu_snapshot,
676 	.destructor = kfree,
677 };
678 
679 static const struct devlink_region_ops mv88e6xxx_region_pvt_ops = {
680 	.name = "pvt",
681 	.snapshot = mv88e6xxx_region_pvt_snapshot,
682 	.destructor = kfree,
683 };
684 
685 static const struct devlink_port_region_ops mv88e6xxx_region_port_ops = {
686 	.name = "port",
687 	.snapshot = mv88e6xxx_region_port_snapshot,
688 	.destructor = kfree,
689 };
690 
691 struct mv88e6xxx_region {
692 	const struct devlink_region_ops *ops;
693 	u64 size;
694 
695 	bool (*cond)(struct mv88e6xxx_chip *chip);
696 };
697 
698 static const struct mv88e6xxx_region mv88e6xxx_regions[] = {
699 	[MV88E6XXX_REGION_GLOBAL1] = {
700 		.ops = &mv88e6xxx_region_global1_ops,
701 		.size = 32 * sizeof(u16)
702 	},
703 	[MV88E6XXX_REGION_GLOBAL2] = {
704 		.ops = &mv88e6xxx_region_global2_ops,
705 		.size = 32 * sizeof(u16) },
706 	[MV88E6XXX_REGION_ATU] = {
707 		.ops = &mv88e6xxx_region_atu_ops
708 	  /* calculated at runtime */
709 	},
710 	[MV88E6XXX_REGION_VTU] = {
711 		.ops = &mv88e6xxx_region_vtu_ops
712 	  /* calculated at runtime */
713 	},
714 	[MV88E6XXX_REGION_STU] = {
715 		.ops = &mv88e6xxx_region_stu_ops,
716 		.cond = mv88e6xxx_has_stu,
717 	  /* calculated at runtime */
718 	},
719 	[MV88E6XXX_REGION_PVT] = {
720 		.ops = &mv88e6xxx_region_pvt_ops,
721 		.size = MV88E6XXX_MAX_PVT_ENTRIES * sizeof(u16),
722 		.cond = mv88e6xxx_has_pvt,
723 	},
724 };
725 
726 void mv88e6xxx_teardown_devlink_regions_global(struct dsa_switch *ds)
727 {
728 	struct mv88e6xxx_chip *chip = ds->priv;
729 	int i;
730 
731 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++)
732 		if (chip->regions[i])
733 			dsa_devlink_region_destroy(chip->regions[i]);
734 }
735 
736 void mv88e6xxx_teardown_devlink_regions_port(struct dsa_switch *ds, int port)
737 {
738 	struct mv88e6xxx_chip *chip = ds->priv;
739 
740 	dsa_devlink_region_destroy(chip->ports[port].region);
741 }
742 
743 int mv88e6xxx_setup_devlink_regions_port(struct dsa_switch *ds, int port)
744 {
745 	struct mv88e6xxx_chip *chip = ds->priv;
746 	struct devlink_region *region;
747 
748 	region = dsa_devlink_port_region_create(ds,
749 						port,
750 						&mv88e6xxx_region_port_ops, 1,
751 						32 * sizeof(u16));
752 	if (IS_ERR(region))
753 		return PTR_ERR(region);
754 
755 	chip->ports[port].region = region;
756 
757 	return 0;
758 }
759 
760 int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds)
761 {
762 	bool (*cond)(struct mv88e6xxx_chip *chip);
763 	struct mv88e6xxx_chip *chip = ds->priv;
764 	const struct devlink_region_ops *ops;
765 	struct devlink_region *region;
766 	u64 size;
767 	int i, j;
768 
769 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++) {
770 		ops = mv88e6xxx_regions[i].ops;
771 		size = mv88e6xxx_regions[i].size;
772 		cond = mv88e6xxx_regions[i].cond;
773 
774 		if (cond && !cond(chip))
775 			continue;
776 
777 		switch (i) {
778 		case MV88E6XXX_REGION_ATU:
779 			size = mv88e6xxx_num_databases(chip) *
780 				sizeof(struct mv88e6xxx_devlink_atu_entry);
781 			break;
782 		case MV88E6XXX_REGION_VTU:
783 			size = (mv88e6xxx_max_vid(chip) + 1) *
784 				sizeof(struct mv88e6xxx_devlink_vtu_entry);
785 			break;
786 		case MV88E6XXX_REGION_STU:
787 			size = (mv88e6xxx_max_sid(chip) + 1) *
788 				sizeof(struct mv88e6xxx_devlink_stu_entry);
789 			break;
790 		}
791 
792 		region = dsa_devlink_region_create(ds, ops, 1, size);
793 		if (IS_ERR(region))
794 			goto out;
795 		chip->regions[i] = region;
796 	}
797 	return 0;
798 
799 out:
800 	for (j = 0; j < i; j++)
801 		dsa_devlink_region_destroy(chip->regions[j]);
802 
803 	return PTR_ERR(region);
804 }
805 
806 int mv88e6xxx_devlink_info_get(struct dsa_switch *ds,
807 			       struct devlink_info_req *req,
808 			       struct netlink_ext_ack *extack)
809 {
810 	struct mv88e6xxx_chip *chip = ds->priv;
811 
812 	return devlink_info_version_fixed_put(req,
813 					      DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
814 					      chip->info->name);
815 }
816