1 // SPDX-License-Identifier: GPL-2.0-or-later
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);
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);
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;
37 mv88e6xxx_reg_lock(chip);
40 case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
41 err = mv88e6xxx_atu_get_hash(chip, &ctx->val.vu8);
48 mv88e6xxx_reg_unlock(chip);
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;
59 mv88e6xxx_reg_lock(chip);
62 case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
63 err = mv88e6xxx_atu_set_hash(chip, ctx->val.vu8);
70 mv88e6xxx_reg_unlock(chip);
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,
107 mv88e6xxx_reg_lock(chip);
109 err = mv88e6xxx_g2_atu_stats_set(chip, MV88E6XXX_G2_ATU_STATS_MODE_ALL,
112 dev_err(chip->dev, "failed to set ATU stats kind/bin\n");
116 err = mv88e6xxx_g1_atu_get_next(chip, 0);
118 dev_err(chip->dev, "failed to perform ATU get next\n");
122 err = mv88e6xxx_g2_atu_stats_get(chip, &occupancy);
124 dev_err(chip->dev, "failed to get ATU stats\n");
128 occupancy &= MV88E6XXX_G2_ATU_STATS_MASK;
131 mv88e6xxx_reg_unlock(chip);
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;
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,
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,
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,
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,
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,
232 dsa_devlink_resource_occ_get_register(ds,
233 MV88E6XXX_RESOURCE_ID_ATU,
234 mv88e6xxx_devlink_atu_get,
237 dsa_devlink_resource_occ_get_register(ds,
238 MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
239 mv88e6xxx_devlink_atu_bin_0_get,
242 dsa_devlink_resource_occ_get_register(ds,
243 MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
244 mv88e6xxx_devlink_atu_bin_1_get,
247 dsa_devlink_resource_occ_get_register(ds,
248 MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
249 mv88e6xxx_devlink_atu_bin_2_get,
252 dsa_devlink_resource_occ_get_register(ds,
253 MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
254 mv88e6xxx_devlink_atu_bin_3_get,
260 dsa_devlink_resources_unregister(ds);
264 static int mv88e6xxx_region_global_snapshot(struct devlink *dl,
265 const struct devlink_region_ops *ops,
266 struct netlink_ext_ack *extack,
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;
275 registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);
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, ®isters[i]);
285 case MV88E6XXX_REGION_GLOBAL2:
286 err = mv88e6xxx_g2_read(chip, i, ®isters[i]);
297 *data = (u8 *)registers;
299 mv88e6xxx_reg_unlock(chip);
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. */
319 static int mv88e6xxx_region_atu_snapshot_fid(struct mv88e6xxx_chip *chip,
321 struct mv88e6xxx_devlink_atu_entry *table,
324 u16 atu_op, atu_data, atu_01, atu_23, atu_45;
325 struct mv88e6xxx_atu_entry addr;
329 eth_broadcast_addr(addr.mac);
332 err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
339 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &atu_op);
343 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_DATA, &atu_data);
347 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC01, &atu_01);
351 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC23, &atu_23);
355 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC45, &atu_45);
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;
366 } while (!is_broadcast_ether_addr(addr.mac));
371 static int mv88e6xxx_region_atu_snapshot(struct devlink *dl,
372 const struct devlink_region_ops *ops,
373 struct netlink_ext_ack *extack,
376 struct dsa_switch *ds = dsa_devlink_to_ds(dl);
377 DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
378 struct mv88e6xxx_devlink_atu_entry *table;
379 struct mv88e6xxx_chip *chip = ds->priv;
380 int fid = -1, count, err;
382 table = kmalloc_array(mv88e6xxx_num_databases(chip),
383 sizeof(struct mv88e6xxx_devlink_atu_entry),
388 memset(table, 0, mv88e6xxx_num_databases(chip) *
389 sizeof(struct mv88e6xxx_devlink_atu_entry));
393 mv88e6xxx_reg_lock(chip);
395 err = mv88e6xxx_fid_map(chip, fid_bitmap);
402 fid = find_next_bit(fid_bitmap, MV88E6XXX_N_FID, fid + 1);
403 if (fid == MV88E6XXX_N_FID)
406 err = mv88e6xxx_region_atu_snapshot_fid(chip, fid, table,
415 mv88e6xxx_reg_unlock(chip);
421 * struct mv88e6xxx_devlink_vtu_entry - Devlink VTU entry
422 * @fid: Global1/2: FID and VLAN policy.
423 * @sid: Global1/3: SID, unknown filters and learning.
424 * @op: Global1/5: FID (old chipsets).
425 * @vid: Global1/6: VID, valid, and page.
426 * @data: Global1/7-9: Membership data and priority override.
427 * @resvd: Reserved. Also happens to align the size to 16B.
429 * The VTU entry format varies between chipset generations, the
430 * descriptions above represent the superset of all possible
431 * information, not all fields are valid on all devices. Since this is
432 * a low-level debug interface, copy all data verbatim and defer
433 * parsing to the consumer.
435 struct mv88e6xxx_devlink_vtu_entry {
444 static int mv88e6xxx_region_vtu_snapshot(struct devlink *dl,
445 const struct devlink_region_ops *ops,
446 struct netlink_ext_ack *extack,
449 struct mv88e6xxx_devlink_vtu_entry *table, *entry;
450 struct dsa_switch *ds = dsa_devlink_to_ds(dl);
451 struct mv88e6xxx_chip *chip = ds->priv;
452 struct mv88e6xxx_vtu_entry vlan;
455 table = kcalloc(mv88e6xxx_max_vid(chip) + 1,
456 sizeof(struct mv88e6xxx_devlink_vtu_entry),
462 vlan.vid = mv88e6xxx_max_vid(chip);
465 mv88e6xxx_reg_lock(chip);
468 err = mv88e6xxx_g1_vtu_getnext(chip, &vlan);
475 err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_FID,
477 err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,
479 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP,
481 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,
483 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,
485 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,
487 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,
493 } while (vlan.vid < mv88e6xxx_max_vid(chip));
495 mv88e6xxx_reg_unlock(chip);
507 * struct mv88e6xxx_devlink_stu_entry - Devlink STU entry
508 * @sid: Global1/3: SID, unknown filters and learning.
509 * @vid: Global1/6: Valid bit.
510 * @data: Global1/7-9: Membership data and priority override.
511 * @resvd: Reserved. In case we forgot something.
513 * The STU entry format varies between chipset generations. Peridot
514 * and Amethyst packs the STU data into Global1/7-8. Older silicon
515 * spreads the information across all three VTU data registers -
516 * inheriting the layout of even older hardware that had no STU at
517 * all. Since this is a low-level debug interface, copy all data
518 * verbatim and defer parsing to the consumer.
520 struct mv88e6xxx_devlink_stu_entry {
527 static int mv88e6xxx_region_stu_snapshot(struct devlink *dl,
528 const struct devlink_region_ops *ops,
529 struct netlink_ext_ack *extack,
532 struct mv88e6xxx_devlink_stu_entry *table, *entry;
533 struct dsa_switch *ds = dsa_devlink_to_ds(dl);
534 struct mv88e6xxx_chip *chip = ds->priv;
535 struct mv88e6xxx_stu_entry stu;
538 table = kcalloc(mv88e6xxx_max_sid(chip) + 1,
539 sizeof(struct mv88e6xxx_devlink_stu_entry),
545 stu.sid = mv88e6xxx_max_sid(chip);
548 mv88e6xxx_reg_lock(chip);
551 err = mv88e6xxx_g1_stu_getnext(chip, &stu);
558 err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,
560 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,
562 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,
564 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,
566 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,
572 } while (stu.sid < mv88e6xxx_max_sid(chip));
574 mv88e6xxx_reg_unlock(chip);
585 static int mv88e6xxx_region_pvt_snapshot(struct devlink *dl,
586 const struct devlink_region_ops *ops,
587 struct netlink_ext_ack *extack,
590 struct dsa_switch *ds = dsa_devlink_to_ds(dl);
591 struct mv88e6xxx_chip *chip = ds->priv;
595 pvt = kcalloc(MV88E6XXX_MAX_PVT_ENTRIES, sizeof(*pvt), GFP_KERNEL);
599 mv88e6xxx_reg_lock(chip);
602 for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; dev++) {
603 for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; port++) {
604 err = mv88e6xxx_g2_pvt_read(chip, dev, port, cur);
612 mv88e6xxx_reg_unlock(chip);
623 static int mv88e6xxx_region_port_snapshot(struct devlink_port *devlink_port,
624 const struct devlink_port_region_ops *ops,
625 struct netlink_ext_ack *extack,
628 struct dsa_switch *ds = dsa_devlink_port_to_ds(devlink_port);
629 int port = dsa_devlink_port_to_port(devlink_port);
630 struct mv88e6xxx_chip *chip = ds->priv;
634 registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);
638 mv88e6xxx_reg_lock(chip);
639 for (i = 0; i < 32; i++) {
640 err = mv88e6xxx_port_read(chip, port, i, ®isters[i]);
646 *data = (u8 *)registers;
648 mv88e6xxx_reg_unlock(chip);
653 static struct mv88e6xxx_region_priv mv88e6xxx_region_global1_priv = {
654 .id = MV88E6XXX_REGION_GLOBAL1,
657 static struct devlink_region_ops mv88e6xxx_region_global1_ops = {
659 .snapshot = mv88e6xxx_region_global_snapshot,
661 .priv = &mv88e6xxx_region_global1_priv,
664 static struct mv88e6xxx_region_priv mv88e6xxx_region_global2_priv = {
665 .id = MV88E6XXX_REGION_GLOBAL2,
668 static struct devlink_region_ops mv88e6xxx_region_global2_ops = {
670 .snapshot = mv88e6xxx_region_global_snapshot,
672 .priv = &mv88e6xxx_region_global2_priv,
675 static struct devlink_region_ops mv88e6xxx_region_atu_ops = {
677 .snapshot = mv88e6xxx_region_atu_snapshot,
681 static struct devlink_region_ops mv88e6xxx_region_vtu_ops = {
683 .snapshot = mv88e6xxx_region_vtu_snapshot,
687 static struct devlink_region_ops mv88e6xxx_region_stu_ops = {
689 .snapshot = mv88e6xxx_region_stu_snapshot,
693 static struct devlink_region_ops mv88e6xxx_region_pvt_ops = {
695 .snapshot = mv88e6xxx_region_pvt_snapshot,
699 static const struct devlink_port_region_ops mv88e6xxx_region_port_ops = {
701 .snapshot = mv88e6xxx_region_port_snapshot,
705 struct mv88e6xxx_region {
706 struct devlink_region_ops *ops;
709 bool (*cond)(struct mv88e6xxx_chip *chip);
712 static struct mv88e6xxx_region mv88e6xxx_regions[] = {
713 [MV88E6XXX_REGION_GLOBAL1] = {
714 .ops = &mv88e6xxx_region_global1_ops,
715 .size = 32 * sizeof(u16)
717 [MV88E6XXX_REGION_GLOBAL2] = {
718 .ops = &mv88e6xxx_region_global2_ops,
719 .size = 32 * sizeof(u16) },
720 [MV88E6XXX_REGION_ATU] = {
721 .ops = &mv88e6xxx_region_atu_ops
722 /* calculated at runtime */
724 [MV88E6XXX_REGION_VTU] = {
725 .ops = &mv88e6xxx_region_vtu_ops
726 /* calculated at runtime */
728 [MV88E6XXX_REGION_STU] = {
729 .ops = &mv88e6xxx_region_stu_ops,
730 .cond = mv88e6xxx_has_stu,
731 /* calculated at runtime */
733 [MV88E6XXX_REGION_PVT] = {
734 .ops = &mv88e6xxx_region_pvt_ops,
735 .size = MV88E6XXX_MAX_PVT_ENTRIES * sizeof(u16),
736 .cond = mv88e6xxx_has_pvt,
740 void mv88e6xxx_teardown_devlink_regions_global(struct dsa_switch *ds)
742 struct mv88e6xxx_chip *chip = ds->priv;
745 for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++)
746 dsa_devlink_region_destroy(chip->regions[i]);
749 void mv88e6xxx_teardown_devlink_regions_port(struct dsa_switch *ds, int port)
751 struct mv88e6xxx_chip *chip = ds->priv;
753 dsa_devlink_region_destroy(chip->ports[port].region);
756 int mv88e6xxx_setup_devlink_regions_port(struct dsa_switch *ds, int port)
758 struct mv88e6xxx_chip *chip = ds->priv;
759 struct devlink_region *region;
761 region = dsa_devlink_port_region_create(ds,
763 &mv88e6xxx_region_port_ops, 1,
766 return PTR_ERR(region);
768 chip->ports[port].region = region;
773 int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds)
775 bool (*cond)(struct mv88e6xxx_chip *chip);
776 struct mv88e6xxx_chip *chip = ds->priv;
777 struct devlink_region_ops *ops;
778 struct devlink_region *region;
782 for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++) {
783 ops = mv88e6xxx_regions[i].ops;
784 size = mv88e6xxx_regions[i].size;
785 cond = mv88e6xxx_regions[i].cond;
787 if (cond && !cond(chip))
791 case MV88E6XXX_REGION_ATU:
792 size = mv88e6xxx_num_databases(chip) *
793 sizeof(struct mv88e6xxx_devlink_atu_entry);
795 case MV88E6XXX_REGION_VTU:
796 size = (mv88e6xxx_max_vid(chip) + 1) *
797 sizeof(struct mv88e6xxx_devlink_vtu_entry);
799 case MV88E6XXX_REGION_STU:
800 size = (mv88e6xxx_max_sid(chip) + 1) *
801 sizeof(struct mv88e6xxx_devlink_stu_entry);
805 region = dsa_devlink_region_create(ds, ops, 1, size);
808 chip->regions[i] = region;
813 for (j = 0; j < i; j++)
814 dsa_devlink_region_destroy(chip->regions[j]);
816 return PTR_ERR(region);
819 int mv88e6xxx_devlink_info_get(struct dsa_switch *ds,
820 struct devlink_info_req *req,
821 struct netlink_ext_ack *extack)
823 struct mv88e6xxx_chip *chip = ds->priv;
825 return devlink_info_version_fixed_put(req,
826 DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,