Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / drivers / net / dsa / mv88e6xxx / devlink.c
blob795c8df7b6a7430619ba675a6c8155f577b99f5c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 #include <net/dsa.h>
4 #include "chip.h"
5 #include "devlink.h"
6 #include "global1.h"
7 #include "global2.h"
8 #include "port.h"
10 static int mv88e6xxx_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash)
12 if (chip->info->ops->atu_get_hash)
13 return chip->info->ops->atu_get_hash(chip, hash);
15 return -EOPNOTSUPP;
18 static int mv88e6xxx_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash)
20 if (chip->info->ops->atu_set_hash)
21 return chip->info->ops->atu_set_hash(chip, hash);
23 return -EOPNOTSUPP;
26 enum mv88e6xxx_devlink_param_id {
27 MV88E6XXX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
28 MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
31 int mv88e6xxx_devlink_param_get(struct dsa_switch *ds, u32 id,
32 struct devlink_param_gset_ctx *ctx)
34 struct mv88e6xxx_chip *chip = ds->priv;
35 int err;
37 mv88e6xxx_reg_lock(chip);
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;
48 mv88e6xxx_reg_unlock(chip);
50 return err;
53 int mv88e6xxx_devlink_param_set(struct dsa_switch *ds, u32 id,
54 struct devlink_param_gset_ctx *ctx)
56 struct mv88e6xxx_chip *chip = ds->priv;
57 int err;
59 mv88e6xxx_reg_lock(chip);
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;
70 mv88e6xxx_reg_unlock(chip);
72 return err;
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)),
81 int mv88e6xxx_setup_devlink_params(struct dsa_switch *ds)
83 return dsa_devlink_params_register(ds, mv88e6xxx_devlink_params,
84 ARRAY_SIZE(mv88e6xxx_devlink_params));
87 void mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds)
89 dsa_devlink_params_unregister(ds, mv88e6xxx_devlink_params,
90 ARRAY_SIZE(mv88e6xxx_devlink_params));
93 enum mv88e6xxx_devlink_resource_id {
94 MV88E6XXX_RESOURCE_ID_ATU,
95 MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
96 MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
97 MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
98 MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
101 static u64 mv88e6xxx_devlink_atu_bin_get(struct mv88e6xxx_chip *chip,
102 u16 bin)
104 u16 occupancy = 0;
105 int err;
107 mv88e6xxx_reg_lock(chip);
109 err = mv88e6xxx_g2_atu_stats_set(chip, MV88E6XXX_G2_ATU_STATS_MODE_ALL,
110 bin);
111 if (err) {
112 dev_err(chip->dev, "failed to set ATU stats kind/bin\n");
113 goto unlock;
116 err = mv88e6xxx_g1_atu_get_next(chip, 0);
117 if (err) {
118 dev_err(chip->dev, "failed to perform ATU get next\n");
119 goto unlock;
122 err = mv88e6xxx_g2_atu_stats_get(chip, &occupancy);
123 if (err) {
124 dev_err(chip->dev, "failed to get ATU stats\n");
125 goto unlock;
128 occupancy &= MV88E6XXX_G2_ATU_STATS_MASK;
130 unlock:
131 mv88e6xxx_reg_unlock(chip);
133 return occupancy;
136 static u64 mv88e6xxx_devlink_atu_bin_0_get(void *priv)
138 struct mv88e6xxx_chip *chip = priv;
140 return mv88e6xxx_devlink_atu_bin_get(chip,
141 MV88E6XXX_G2_ATU_STATS_BIN_0);
144 static u64 mv88e6xxx_devlink_atu_bin_1_get(void *priv)
146 struct mv88e6xxx_chip *chip = priv;
148 return mv88e6xxx_devlink_atu_bin_get(chip,
149 MV88E6XXX_G2_ATU_STATS_BIN_1);
152 static u64 mv88e6xxx_devlink_atu_bin_2_get(void *priv)
154 struct mv88e6xxx_chip *chip = priv;
156 return mv88e6xxx_devlink_atu_bin_get(chip,
157 MV88E6XXX_G2_ATU_STATS_BIN_2);
160 static u64 mv88e6xxx_devlink_atu_bin_3_get(void *priv)
162 struct mv88e6xxx_chip *chip = priv;
164 return mv88e6xxx_devlink_atu_bin_get(chip,
165 MV88E6XXX_G2_ATU_STATS_BIN_3);
168 static u64 mv88e6xxx_devlink_atu_get(void *priv)
170 return mv88e6xxx_devlink_atu_bin_0_get(priv) +
171 mv88e6xxx_devlink_atu_bin_1_get(priv) +
172 mv88e6xxx_devlink_atu_bin_2_get(priv) +
173 mv88e6xxx_devlink_atu_bin_3_get(priv);
176 int mv88e6xxx_setup_devlink_resources(struct dsa_switch *ds)
178 struct devlink_resource_size_params size_params;
179 struct mv88e6xxx_chip *chip = ds->priv;
180 int err;
182 devlink_resource_size_params_init(&size_params,
183 mv88e6xxx_num_macs(chip),
184 mv88e6xxx_num_macs(chip),
185 1, DEVLINK_RESOURCE_UNIT_ENTRY);
187 err = dsa_devlink_resource_register(ds, "ATU",
188 mv88e6xxx_num_macs(chip),
189 MV88E6XXX_RESOURCE_ID_ATU,
190 DEVLINK_RESOURCE_ID_PARENT_TOP,
191 &size_params);
192 if (err)
193 goto out;
195 devlink_resource_size_params_init(&size_params,
196 mv88e6xxx_num_macs(chip) / 4,
197 mv88e6xxx_num_macs(chip) / 4,
198 1, DEVLINK_RESOURCE_UNIT_ENTRY);
200 err = dsa_devlink_resource_register(ds, "ATU_bin_0",
201 mv88e6xxx_num_macs(chip) / 4,
202 MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
203 MV88E6XXX_RESOURCE_ID_ATU,
204 &size_params);
205 if (err)
206 goto out;
208 err = dsa_devlink_resource_register(ds, "ATU_bin_1",
209 mv88e6xxx_num_macs(chip) / 4,
210 MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
211 MV88E6XXX_RESOURCE_ID_ATU,
212 &size_params);
213 if (err)
214 goto out;
216 err = dsa_devlink_resource_register(ds, "ATU_bin_2",
217 mv88e6xxx_num_macs(chip) / 4,
218 MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
219 MV88E6XXX_RESOURCE_ID_ATU,
220 &size_params);
221 if (err)
222 goto out;
224 err = dsa_devlink_resource_register(ds, "ATU_bin_3",
225 mv88e6xxx_num_macs(chip) / 4,
226 MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
227 MV88E6XXX_RESOURCE_ID_ATU,
228 &size_params);
229 if (err)
230 goto out;
232 dsa_devlink_resource_occ_get_register(ds,
233 MV88E6XXX_RESOURCE_ID_ATU,
234 mv88e6xxx_devlink_atu_get,
235 chip);
237 dsa_devlink_resource_occ_get_register(ds,
238 MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
239 mv88e6xxx_devlink_atu_bin_0_get,
240 chip);
242 dsa_devlink_resource_occ_get_register(ds,
243 MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
244 mv88e6xxx_devlink_atu_bin_1_get,
245 chip);
247 dsa_devlink_resource_occ_get_register(ds,
248 MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
249 mv88e6xxx_devlink_atu_bin_2_get,
250 chip);
252 dsa_devlink_resource_occ_get_register(ds,
253 MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
254 mv88e6xxx_devlink_atu_bin_3_get,
255 chip);
257 return 0;
259 out:
260 dsa_devlink_resources_unregister(ds);
261 return err;
264 static int mv88e6xxx_region_global_snapshot(struct devlink *dl,
265 const struct devlink_region_ops *ops,
266 struct netlink_ext_ack *extack,
267 u8 **data)
269 struct mv88e6xxx_region_priv *region_priv = ops->priv;
270 struct dsa_switch *ds = dsa_devlink_to_ds(dl);
271 struct mv88e6xxx_chip *chip = ds->priv;
272 u16 *registers;
273 int i, err;
275 registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);
276 if (!registers)
277 return -ENOMEM;
279 mv88e6xxx_reg_lock(chip);
280 for (i = 0; i < 32; i++) {
281 switch (region_priv->id) {
282 case MV88E6XXX_REGION_GLOBAL1:
283 err = mv88e6xxx_g1_read(chip, i, &registers[i]);
284 break;
285 case MV88E6XXX_REGION_GLOBAL2:
286 err = mv88e6xxx_g2_read(chip, i, &registers[i]);
287 break;
288 default:
289 err = -EOPNOTSUPP;
292 if (err) {
293 kfree(registers);
294 goto out;
297 *data = (u8 *)registers;
298 out:
299 mv88e6xxx_reg_unlock(chip);
301 return err;
304 /* The ATU entry varies between mv88e6xxx chipset generations. Define
305 * a generic format which covers all the current and hopefully future
306 * mv88e6xxx generations
309 struct mv88e6xxx_devlink_atu_entry {
310 /* The FID is scattered over multiple registers. */
311 u16 fid;
312 u16 atu_op;
313 u16 atu_data;
314 u16 atu_01;
315 u16 atu_23;
316 u16 atu_45;
319 static int mv88e6xxx_region_atu_snapshot_fid(struct mv88e6xxx_chip *chip,
320 int fid,
321 struct mv88e6xxx_devlink_atu_entry *table,
322 int *count)
324 u16 atu_op, atu_data, atu_01, atu_23, atu_45;
325 struct mv88e6xxx_atu_entry addr;
326 int err;
328 addr.state = 0;
329 eth_broadcast_addr(addr.mac);
331 do {
332 err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
333 if (err)
334 return err;
336 if (!addr.state)
337 break;
339 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &atu_op);
340 if (err)
341 return err;
343 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_DATA, &atu_data);
344 if (err)
345 return err;
347 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC01, &atu_01);
348 if (err)
349 return err;
351 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC23, &atu_23);
352 if (err)
353 return err;
355 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC45, &atu_45);
356 if (err)
357 return err;
359 table[*count].fid = fid;
360 table[*count].atu_op = atu_op;
361 table[*count].atu_data = atu_data;
362 table[*count].atu_01 = atu_01;
363 table[*count].atu_23 = atu_23;
364 table[*count].atu_45 = atu_45;
365 (*count)++;
366 } while (!is_broadcast_ether_addr(addr.mac));
368 return 0;
371 static int mv88e6xxx_region_atu_snapshot(struct devlink *dl,
372 const struct devlink_region_ops *ops,
373 struct netlink_ext_ack *extack,
374 u8 **data)
376 struct dsa_switch *ds = dsa_devlink_to_ds(dl);
377 struct mv88e6xxx_devlink_atu_entry *table;
378 struct mv88e6xxx_chip *chip = ds->priv;
379 int fid = -1, err = 0, count;
381 table = kmalloc_array(mv88e6xxx_num_databases(chip),
382 sizeof(struct mv88e6xxx_devlink_atu_entry),
383 GFP_KERNEL);
384 if (!table)
385 return -ENOMEM;
387 memset(table, 0, mv88e6xxx_num_databases(chip) *
388 sizeof(struct mv88e6xxx_devlink_atu_entry));
390 count = 0;
392 mv88e6xxx_reg_lock(chip);
394 while (1) {
395 fid = find_next_bit(chip->fid_bitmap, MV88E6XXX_N_FID, fid + 1);
396 if (fid == MV88E6XXX_N_FID)
397 break;
399 err = mv88e6xxx_region_atu_snapshot_fid(chip, fid, table,
400 &count);
401 if (err) {
402 kfree(table);
403 goto out;
406 *data = (u8 *)table;
407 out:
408 mv88e6xxx_reg_unlock(chip);
410 return err;
414 * struct mv88e6xxx_devlink_vtu_entry - Devlink VTU entry
415 * @fid: Global1/2: FID and VLAN policy.
416 * @sid: Global1/3: SID, unknown filters and learning.
417 * @op: Global1/5: FID (old chipsets).
418 * @vid: Global1/6: VID, valid, and page.
419 * @data: Global1/7-9: Membership data and priority override.
420 * @resvd: Reserved. Also happens to align the size to 16B.
422 * The VTU entry format varies between chipset generations, the
423 * descriptions above represent the superset of all possible
424 * information, not all fields are valid on all devices. Since this is
425 * a low-level debug interface, copy all data verbatim and defer
426 * parsing to the consumer.
428 struct mv88e6xxx_devlink_vtu_entry {
429 u16 fid;
430 u16 sid;
431 u16 op;
432 u16 vid;
433 u16 data[3];
434 u16 resvd;
437 static int mv88e6xxx_region_vtu_snapshot(struct devlink *dl,
438 const struct devlink_region_ops *ops,
439 struct netlink_ext_ack *extack,
440 u8 **data)
442 struct mv88e6xxx_devlink_vtu_entry *table, *entry;
443 struct dsa_switch *ds = dsa_devlink_to_ds(dl);
444 struct mv88e6xxx_chip *chip = ds->priv;
445 struct mv88e6xxx_vtu_entry vlan;
446 int err;
448 table = kcalloc(mv88e6xxx_max_vid(chip) + 1,
449 sizeof(struct mv88e6xxx_devlink_vtu_entry),
450 GFP_KERNEL);
451 if (!table)
452 return -ENOMEM;
454 entry = table;
455 vlan.vid = mv88e6xxx_max_vid(chip);
456 vlan.valid = false;
458 mv88e6xxx_reg_lock(chip);
460 do {
461 err = mv88e6xxx_g1_vtu_getnext(chip, &vlan);
462 if (err)
463 break;
465 if (!vlan.valid)
466 break;
468 err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_FID,
469 &entry->fid);
470 err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,
471 &entry->sid);
472 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP,
473 &entry->op);
474 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,
475 &entry->vid);
476 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,
477 &entry->data[0]);
478 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,
479 &entry->data[1]);
480 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,
481 &entry->data[2]);
482 if (err)
483 break;
485 entry++;
486 } while (vlan.vid < mv88e6xxx_max_vid(chip));
488 mv88e6xxx_reg_unlock(chip);
490 if (err) {
491 kfree(table);
492 return err;
495 *data = (u8 *)table;
496 return 0;
500 * struct mv88e6xxx_devlink_stu_entry - Devlink STU entry
501 * @sid: Global1/3: SID, unknown filters and learning.
502 * @vid: Global1/6: Valid bit.
503 * @data: Global1/7-9: Membership data and priority override.
504 * @resvd: Reserved. In case we forgot something.
506 * The STU entry format varies between chipset generations. Peridot
507 * and Amethyst packs the STU data into Global1/7-8. Older silicon
508 * spreads the information across all three VTU data registers -
509 * inheriting the layout of even older hardware that had no STU at
510 * all. Since this is a low-level debug interface, copy all data
511 * verbatim and defer parsing to the consumer.
513 struct mv88e6xxx_devlink_stu_entry {
514 u16 sid;
515 u16 vid;
516 u16 data[3];
517 u16 resvd;
520 static int mv88e6xxx_region_stu_snapshot(struct devlink *dl,
521 const struct devlink_region_ops *ops,
522 struct netlink_ext_ack *extack,
523 u8 **data)
525 struct mv88e6xxx_devlink_stu_entry *table, *entry;
526 struct dsa_switch *ds = dsa_devlink_to_ds(dl);
527 struct mv88e6xxx_chip *chip = ds->priv;
528 struct mv88e6xxx_stu_entry stu;
529 int err;
531 table = kcalloc(mv88e6xxx_max_sid(chip) + 1,
532 sizeof(struct mv88e6xxx_devlink_stu_entry),
533 GFP_KERNEL);
534 if (!table)
535 return -ENOMEM;
537 entry = table;
538 stu.sid = mv88e6xxx_max_sid(chip);
539 stu.valid = false;
541 mv88e6xxx_reg_lock(chip);
543 do {
544 err = mv88e6xxx_g1_stu_getnext(chip, &stu);
545 if (err)
546 break;
548 if (!stu.valid)
549 break;
551 err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,
552 &entry->sid);
553 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,
554 &entry->vid);
555 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,
556 &entry->data[0]);
557 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,
558 &entry->data[1]);
559 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,
560 &entry->data[2]);
561 if (err)
562 break;
564 entry++;
565 } while (stu.sid < mv88e6xxx_max_sid(chip));
567 mv88e6xxx_reg_unlock(chip);
569 if (err) {
570 kfree(table);
571 return err;
574 *data = (u8 *)table;
575 return 0;
578 static int mv88e6xxx_region_pvt_snapshot(struct devlink *dl,
579 const struct devlink_region_ops *ops,
580 struct netlink_ext_ack *extack,
581 u8 **data)
583 struct dsa_switch *ds = dsa_devlink_to_ds(dl);
584 struct mv88e6xxx_chip *chip = ds->priv;
585 int dev, port, err;
586 u16 *pvt, *cur;
588 pvt = kcalloc(MV88E6XXX_MAX_PVT_ENTRIES, sizeof(*pvt), GFP_KERNEL);
589 if (!pvt)
590 return -ENOMEM;
592 mv88e6xxx_reg_lock(chip);
594 cur = pvt;
595 for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; dev++) {
596 for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; port++) {
597 err = mv88e6xxx_g2_pvt_read(chip, dev, port, cur);
598 if (err)
599 break;
601 cur++;
605 mv88e6xxx_reg_unlock(chip);
607 if (err) {
608 kfree(pvt);
609 return err;
612 *data = (u8 *)pvt;
613 return 0;
616 static int mv88e6xxx_region_port_snapshot(struct devlink_port *devlink_port,
617 const struct devlink_port_region_ops *ops,
618 struct netlink_ext_ack *extack,
619 u8 **data)
621 struct dsa_switch *ds = dsa_devlink_port_to_ds(devlink_port);
622 int port = dsa_devlink_port_to_port(devlink_port);
623 struct mv88e6xxx_chip *chip = ds->priv;
624 u16 *registers;
625 int i, err;
627 registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);
628 if (!registers)
629 return -ENOMEM;
631 mv88e6xxx_reg_lock(chip);
632 for (i = 0; i < 32; i++) {
633 err = mv88e6xxx_port_read(chip, port, i, &registers[i]);
634 if (err) {
635 kfree(registers);
636 goto out;
639 *data = (u8 *)registers;
640 out:
641 mv88e6xxx_reg_unlock(chip);
643 return err;
646 static struct mv88e6xxx_region_priv mv88e6xxx_region_global1_priv = {
647 .id = MV88E6XXX_REGION_GLOBAL1,
650 static struct devlink_region_ops mv88e6xxx_region_global1_ops = {
651 .name = "global1",
652 .snapshot = mv88e6xxx_region_global_snapshot,
653 .destructor = kfree,
654 .priv = &mv88e6xxx_region_global1_priv,
657 static struct mv88e6xxx_region_priv mv88e6xxx_region_global2_priv = {
658 .id = MV88E6XXX_REGION_GLOBAL2,
661 static struct devlink_region_ops mv88e6xxx_region_global2_ops = {
662 .name = "global2",
663 .snapshot = mv88e6xxx_region_global_snapshot,
664 .destructor = kfree,
665 .priv = &mv88e6xxx_region_global2_priv,
668 static struct devlink_region_ops mv88e6xxx_region_atu_ops = {
669 .name = "atu",
670 .snapshot = mv88e6xxx_region_atu_snapshot,
671 .destructor = kfree,
674 static struct devlink_region_ops mv88e6xxx_region_vtu_ops = {
675 .name = "vtu",
676 .snapshot = mv88e6xxx_region_vtu_snapshot,
677 .destructor = kfree,
680 static struct devlink_region_ops mv88e6xxx_region_stu_ops = {
681 .name = "stu",
682 .snapshot = mv88e6xxx_region_stu_snapshot,
683 .destructor = kfree,
686 static struct devlink_region_ops mv88e6xxx_region_pvt_ops = {
687 .name = "pvt",
688 .snapshot = mv88e6xxx_region_pvt_snapshot,
689 .destructor = kfree,
692 static const struct devlink_port_region_ops mv88e6xxx_region_port_ops = {
693 .name = "port",
694 .snapshot = mv88e6xxx_region_port_snapshot,
695 .destructor = kfree,
698 struct mv88e6xxx_region {
699 struct devlink_region_ops *ops;
700 u64 size;
702 bool (*cond)(struct mv88e6xxx_chip *chip);
705 static struct mv88e6xxx_region mv88e6xxx_regions[] = {
706 [MV88E6XXX_REGION_GLOBAL1] = {
707 .ops = &mv88e6xxx_region_global1_ops,
708 .size = 32 * sizeof(u16)
710 [MV88E6XXX_REGION_GLOBAL2] = {
711 .ops = &mv88e6xxx_region_global2_ops,
712 .size = 32 * sizeof(u16) },
713 [MV88E6XXX_REGION_ATU] = {
714 .ops = &mv88e6xxx_region_atu_ops
715 /* calculated at runtime */
717 [MV88E6XXX_REGION_VTU] = {
718 .ops = &mv88e6xxx_region_vtu_ops
719 /* calculated at runtime */
721 [MV88E6XXX_REGION_STU] = {
722 .ops = &mv88e6xxx_region_stu_ops,
723 .cond = mv88e6xxx_has_stu,
724 /* calculated at runtime */
726 [MV88E6XXX_REGION_PVT] = {
727 .ops = &mv88e6xxx_region_pvt_ops,
728 .size = MV88E6XXX_MAX_PVT_ENTRIES * sizeof(u16),
729 .cond = mv88e6xxx_has_pvt,
733 void mv88e6xxx_teardown_devlink_regions_global(struct dsa_switch *ds)
735 struct mv88e6xxx_chip *chip = ds->priv;
736 int i;
738 for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++)
739 dsa_devlink_region_destroy(chip->regions[i]);
742 void mv88e6xxx_teardown_devlink_regions_port(struct dsa_switch *ds, int port)
744 struct mv88e6xxx_chip *chip = ds->priv;
746 dsa_devlink_region_destroy(chip->ports[port].region);
749 int mv88e6xxx_setup_devlink_regions_port(struct dsa_switch *ds, int port)
751 struct mv88e6xxx_chip *chip = ds->priv;
752 struct devlink_region *region;
754 region = dsa_devlink_port_region_create(ds,
755 port,
756 &mv88e6xxx_region_port_ops, 1,
757 32 * sizeof(u16));
758 if (IS_ERR(region))
759 return PTR_ERR(region);
761 chip->ports[port].region = region;
763 return 0;
766 int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds)
768 bool (*cond)(struct mv88e6xxx_chip *chip);
769 struct mv88e6xxx_chip *chip = ds->priv;
770 struct devlink_region_ops *ops;
771 struct devlink_region *region;
772 u64 size;
773 int i, j;
775 for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++) {
776 ops = mv88e6xxx_regions[i].ops;
777 size = mv88e6xxx_regions[i].size;
778 cond = mv88e6xxx_regions[i].cond;
780 if (cond && !cond(chip))
781 continue;
783 switch (i) {
784 case MV88E6XXX_REGION_ATU:
785 size = mv88e6xxx_num_databases(chip) *
786 sizeof(struct mv88e6xxx_devlink_atu_entry);
787 break;
788 case MV88E6XXX_REGION_VTU:
789 size = (mv88e6xxx_max_vid(chip) + 1) *
790 sizeof(struct mv88e6xxx_devlink_vtu_entry);
791 break;
792 case MV88E6XXX_REGION_STU:
793 size = (mv88e6xxx_max_sid(chip) + 1) *
794 sizeof(struct mv88e6xxx_devlink_stu_entry);
795 break;
798 region = dsa_devlink_region_create(ds, ops, 1, size);
799 if (IS_ERR(region))
800 goto out;
801 chip->regions[i] = region;
803 return 0;
805 out:
806 for (j = 0; j < i; j++)
807 dsa_devlink_region_destroy(chip->regions[j]);
809 return PTR_ERR(region);
812 int mv88e6xxx_devlink_info_get(struct dsa_switch *ds,
813 struct devlink_info_req *req,
814 struct netlink_ext_ack *extack)
816 struct mv88e6xxx_chip *chip = ds->priv;
818 return devlink_info_version_fixed_put(req,
819 DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
820 chip->info->name);