829 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2#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 10static 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 18static 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 26enum mv88e6xxx_devlink_param_id {27 MV88E6XXX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,28 MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,29};30 31int 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 53int 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 75static 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 81int 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 87void 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 93enum 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,99};100 101static u64 mv88e6xxx_devlink_atu_bin_get(struct mv88e6xxx_chip *chip,102 u16 bin)103{104 u16 occupancy = 0;105 int err;106 107 mv88e6xxx_reg_lock(chip);108 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;114 }115 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;120 }121 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;126 }127 128 occupancy &= MV88E6XXX_G2_ATU_STATS_MASK;129 130unlock:131 mv88e6xxx_reg_unlock(chip);132 133 return occupancy;134}135 136static u64 mv88e6xxx_devlink_atu_bin_0_get(void *priv)137{138 struct mv88e6xxx_chip *chip = priv;139 140 return mv88e6xxx_devlink_atu_bin_get(chip,141 MV88E6XXX_G2_ATU_STATS_BIN_0);142}143 144static u64 mv88e6xxx_devlink_atu_bin_1_get(void *priv)145{146 struct mv88e6xxx_chip *chip = priv;147 148 return mv88e6xxx_devlink_atu_bin_get(chip,149 MV88E6XXX_G2_ATU_STATS_BIN_1);150}151 152static u64 mv88e6xxx_devlink_atu_bin_2_get(void *priv)153{154 struct mv88e6xxx_chip *chip = priv;155 156 return mv88e6xxx_devlink_atu_bin_get(chip,157 MV88E6XXX_G2_ATU_STATS_BIN_2);158}159 160static u64 mv88e6xxx_devlink_atu_bin_3_get(void *priv)161{162 struct mv88e6xxx_chip *chip = priv;163 164 return mv88e6xxx_devlink_atu_bin_get(chip,165 MV88E6XXX_G2_ATU_STATS_BIN_3);166}167 168static u64 mv88e6xxx_devlink_atu_get(void *priv)169{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);174}175 176int mv88e6xxx_setup_devlink_resources(struct dsa_switch *ds)177{178 struct devlink_resource_size_params size_params;179 struct mv88e6xxx_chip *chip = ds->priv;180 int err;181 182 devlink_resource_size_params_init(&size_params,183 mv88e6xxx_num_macs(chip),184 mv88e6xxx_num_macs(chip),185 1, DEVLINK_RESOURCE_UNIT_ENTRY);186 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;194 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);199 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;207 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;215 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;223 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;231 232 dsa_devlink_resource_occ_get_register(ds,233 MV88E6XXX_RESOURCE_ID_ATU,234 mv88e6xxx_devlink_atu_get,235 chip);236 237 dsa_devlink_resource_occ_get_register(ds,238 MV88E6XXX_RESOURCE_ID_ATU_BIN_0,239 mv88e6xxx_devlink_atu_bin_0_get,240 chip);241 242 dsa_devlink_resource_occ_get_register(ds,243 MV88E6XXX_RESOURCE_ID_ATU_BIN_1,244 mv88e6xxx_devlink_atu_bin_1_get,245 chip);246 247 dsa_devlink_resource_occ_get_register(ds,248 MV88E6XXX_RESOURCE_ID_ATU_BIN_2,249 mv88e6xxx_devlink_atu_bin_2_get,250 chip);251 252 dsa_devlink_resource_occ_get_register(ds,253 MV88E6XXX_RESOURCE_ID_ATU_BIN_3,254 mv88e6xxx_devlink_atu_bin_3_get,255 chip);256 257 return 0;258 259out:260 dsa_devlink_resources_unregister(ds);261 return err;262}263 264static int mv88e6xxx_region_global_snapshot(struct devlink *dl,265 const struct devlink_region_ops *ops,266 struct netlink_ext_ack *extack,267 u8 **data)268{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;274 275 registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);276 if (!registers)277 return -ENOMEM;278 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]);284 break;285 case MV88E6XXX_REGION_GLOBAL2:286 err = mv88e6xxx_g2_read(chip, i, ®isters[i]);287 break;288 default:289 err = -EOPNOTSUPP;290 }291 292 if (err) {293 kfree(registers);294 goto out;295 }296 }297 *data = (u8 *)registers;298out:299 mv88e6xxx_reg_unlock(chip);300 301 return err;302}303 304/* The ATU entry varies between mv88e6xxx chipset generations. Define305 * a generic format which covers all the current and hopefully future306 * mv88e6xxx generations307 */308 309struct 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;317};318 319static int mv88e6xxx_region_atu_snapshot_fid(struct mv88e6xxx_chip *chip,320 int fid,321 struct mv88e6xxx_devlink_atu_entry *table,322 int *count)323{324 u16 atu_op, atu_data, atu_01, atu_23, atu_45;325 struct mv88e6xxx_atu_entry addr;326 int err;327 328 addr.state = 0;329 eth_broadcast_addr(addr.mac);330 331 do {332 err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);333 if (err)334 return err;335 336 if (!addr.state)337 break;338 339 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &atu_op);340 if (err)341 return err;342 343 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_DATA, &atu_data);344 if (err)345 return err;346 347 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC01, &atu_01);348 if (err)349 return err;350 351 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC23, &atu_23);352 if (err)353 return err;354 355 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC45, &atu_45);356 if (err)357 return err;358 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));367 368 return 0;369}370 371static int mv88e6xxx_region_atu_snapshot(struct devlink *dl,372 const struct devlink_region_ops *ops,373 struct netlink_ext_ack *extack,374 u8 **data)375{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;381 382 table = kmalloc_array(mv88e6xxx_num_databases(chip),383 sizeof(struct mv88e6xxx_devlink_atu_entry),384 GFP_KERNEL);385 if (!table)386 return -ENOMEM;387 388 memset(table, 0, mv88e6xxx_num_databases(chip) *389 sizeof(struct mv88e6xxx_devlink_atu_entry));390 391 count = 0;392 393 mv88e6xxx_reg_lock(chip);394 395 err = mv88e6xxx_fid_map(chip, fid_bitmap);396 if (err) {397 kfree(table);398 goto out;399 }400 401 while (1) {402 fid = find_next_bit(fid_bitmap, MV88E6XXX_N_FID, fid + 1);403 if (fid == MV88E6XXX_N_FID)404 break;405 406 err = mv88e6xxx_region_atu_snapshot_fid(chip, fid, table,407 &count);408 if (err) {409 kfree(table);410 goto out;411 }412 }413 *data = (u8 *)table;414out:415 mv88e6xxx_reg_unlock(chip);416 417 return err;418}419 420/**421 * struct mv88e6xxx_devlink_vtu_entry - Devlink VTU entry422 * @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.428 *429 * The VTU entry format varies between chipset generations, the430 * descriptions above represent the superset of all possible431 * information, not all fields are valid on all devices. Since this is432 * a low-level debug interface, copy all data verbatim and defer433 * parsing to the consumer.434 */435struct mv88e6xxx_devlink_vtu_entry {436 u16 fid;437 u16 sid;438 u16 op;439 u16 vid;440 u16 data[3];441 u16 resvd;442};443 444static int mv88e6xxx_region_vtu_snapshot(struct devlink *dl,445 const struct devlink_region_ops *ops,446 struct netlink_ext_ack *extack,447 u8 **data)448{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;453 int err;454 455 table = kcalloc(mv88e6xxx_max_vid(chip) + 1,456 sizeof(struct mv88e6xxx_devlink_vtu_entry),457 GFP_KERNEL);458 if (!table)459 return -ENOMEM;460 461 entry = table;462 vlan.vid = mv88e6xxx_max_vid(chip);463 vlan.valid = false;464 465 mv88e6xxx_reg_lock(chip);466 467 do {468 err = mv88e6xxx_g1_vtu_getnext(chip, &vlan);469 if (err)470 break;471 472 if (!vlan.valid)473 break;474 475 err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_FID,476 &entry->fid);477 err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,478 &entry->sid);479 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP,480 &entry->op);481 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,482 &entry->vid);483 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,484 &entry->data[0]);485 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,486 &entry->data[1]);487 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,488 &entry->data[2]);489 if (err)490 break;491 492 entry++;493 } while (vlan.vid < mv88e6xxx_max_vid(chip));494 495 mv88e6xxx_reg_unlock(chip);496 497 if (err) {498 kfree(table);499 return err;500 }501 502 *data = (u8 *)table;503 return 0;504}505 506/**507 * struct mv88e6xxx_devlink_stu_entry - Devlink STU entry508 * @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.512 *513 * The STU entry format varies between chipset generations. Peridot514 * and Amethyst packs the STU data into Global1/7-8. Older silicon515 * spreads the information across all three VTU data registers -516 * inheriting the layout of even older hardware that had no STU at517 * all. Since this is a low-level debug interface, copy all data518 * verbatim and defer parsing to the consumer.519 */520struct mv88e6xxx_devlink_stu_entry {521 u16 sid;522 u16 vid;523 u16 data[3];524 u16 resvd;525};526 527static int mv88e6xxx_region_stu_snapshot(struct devlink *dl,528 const struct devlink_region_ops *ops,529 struct netlink_ext_ack *extack,530 u8 **data)531{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;536 int err;537 538 table = kcalloc(mv88e6xxx_max_sid(chip) + 1,539 sizeof(struct mv88e6xxx_devlink_stu_entry),540 GFP_KERNEL);541 if (!table)542 return -ENOMEM;543 544 entry = table;545 stu.sid = mv88e6xxx_max_sid(chip);546 stu.valid = false;547 548 mv88e6xxx_reg_lock(chip);549 550 do {551 err = mv88e6xxx_g1_stu_getnext(chip, &stu);552 if (err)553 break;554 555 if (!stu.valid)556 break;557 558 err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,559 &entry->sid);560 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,561 &entry->vid);562 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,563 &entry->data[0]);564 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,565 &entry->data[1]);566 err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,567 &entry->data[2]);568 if (err)569 break;570 571 entry++;572 } while (stu.sid < mv88e6xxx_max_sid(chip));573 574 mv88e6xxx_reg_unlock(chip);575 576 if (err) {577 kfree(table);578 return err;579 }580 581 *data = (u8 *)table;582 return 0;583}584 585static int mv88e6xxx_region_pvt_snapshot(struct devlink *dl,586 const struct devlink_region_ops *ops,587 struct netlink_ext_ack *extack,588 u8 **data)589{590 struct dsa_switch *ds = dsa_devlink_to_ds(dl);591 struct mv88e6xxx_chip *chip = ds->priv;592 int dev, port, err;593 u16 *pvt, *cur;594 595 pvt = kcalloc(MV88E6XXX_MAX_PVT_ENTRIES, sizeof(*pvt), GFP_KERNEL);596 if (!pvt)597 return -ENOMEM;598 599 mv88e6xxx_reg_lock(chip);600 601 cur = pvt;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);605 if (err)606 break;607 608 cur++;609 }610 }611 612 mv88e6xxx_reg_unlock(chip);613 614 if (err) {615 kfree(pvt);616 return err;617 }618 619 *data = (u8 *)pvt;620 return 0;621}622 623static int mv88e6xxx_region_port_snapshot(struct devlink_port *devlink_port,624 const struct devlink_port_region_ops *ops,625 struct netlink_ext_ack *extack,626 u8 **data)627{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;631 u16 *registers;632 int i, err;633 634 registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);635 if (!registers)636 return -ENOMEM;637 638 mv88e6xxx_reg_lock(chip);639 for (i = 0; i < 32; i++) {640 err = mv88e6xxx_port_read(chip, port, i, ®isters[i]);641 if (err) {642 kfree(registers);643 goto out;644 }645 }646 *data = (u8 *)registers;647out:648 mv88e6xxx_reg_unlock(chip);649 650 return err;651}652 653static struct mv88e6xxx_region_priv mv88e6xxx_region_global1_priv = {654 .id = MV88E6XXX_REGION_GLOBAL1,655};656 657static struct devlink_region_ops mv88e6xxx_region_global1_ops = {658 .name = "global1",659 .snapshot = mv88e6xxx_region_global_snapshot,660 .destructor = kfree,661 .priv = &mv88e6xxx_region_global1_priv,662};663 664static struct mv88e6xxx_region_priv mv88e6xxx_region_global2_priv = {665 .id = MV88E6XXX_REGION_GLOBAL2,666};667 668static struct devlink_region_ops mv88e6xxx_region_global2_ops = {669 .name = "global2",670 .snapshot = mv88e6xxx_region_global_snapshot,671 .destructor = kfree,672 .priv = &mv88e6xxx_region_global2_priv,673};674 675static struct devlink_region_ops mv88e6xxx_region_atu_ops = {676 .name = "atu",677 .snapshot = mv88e6xxx_region_atu_snapshot,678 .destructor = kfree,679};680 681static struct devlink_region_ops mv88e6xxx_region_vtu_ops = {682 .name = "vtu",683 .snapshot = mv88e6xxx_region_vtu_snapshot,684 .destructor = kfree,685};686 687static struct devlink_region_ops mv88e6xxx_region_stu_ops = {688 .name = "stu",689 .snapshot = mv88e6xxx_region_stu_snapshot,690 .destructor = kfree,691};692 693static struct devlink_region_ops mv88e6xxx_region_pvt_ops = {694 .name = "pvt",695 .snapshot = mv88e6xxx_region_pvt_snapshot,696 .destructor = kfree,697};698 699static const struct devlink_port_region_ops mv88e6xxx_region_port_ops = {700 .name = "port",701 .snapshot = mv88e6xxx_region_port_snapshot,702 .destructor = kfree,703};704 705struct mv88e6xxx_region {706 struct devlink_region_ops *ops;707 u64 size;708 709 bool (*cond)(struct mv88e6xxx_chip *chip);710};711 712static struct mv88e6xxx_region mv88e6xxx_regions[] = {713 [MV88E6XXX_REGION_GLOBAL1] = {714 .ops = &mv88e6xxx_region_global1_ops,715 .size = 32 * sizeof(u16)716 },717 [MV88E6XXX_REGION_GLOBAL2] = {718 .ops = &mv88e6xxx_region_global2_ops,719 .size = 32 * sizeof(u16) },720 [MV88E6XXX_REGION_ATU] = {721 .ops = &mv88e6xxx_region_atu_ops722 /* calculated at runtime */723 },724 [MV88E6XXX_REGION_VTU] = {725 .ops = &mv88e6xxx_region_vtu_ops726 /* calculated at runtime */727 },728 [MV88E6XXX_REGION_STU] = {729 .ops = &mv88e6xxx_region_stu_ops,730 .cond = mv88e6xxx_has_stu,731 /* calculated at runtime */732 },733 [MV88E6XXX_REGION_PVT] = {734 .ops = &mv88e6xxx_region_pvt_ops,735 .size = MV88E6XXX_MAX_PVT_ENTRIES * sizeof(u16),736 .cond = mv88e6xxx_has_pvt,737 },738};739 740void mv88e6xxx_teardown_devlink_regions_global(struct dsa_switch *ds)741{742 struct mv88e6xxx_chip *chip = ds->priv;743 int i;744 745 for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++)746 dsa_devlink_region_destroy(chip->regions[i]);747}748 749void mv88e6xxx_teardown_devlink_regions_port(struct dsa_switch *ds, int port)750{751 struct mv88e6xxx_chip *chip = ds->priv;752 753 dsa_devlink_region_destroy(chip->ports[port].region);754}755 756int mv88e6xxx_setup_devlink_regions_port(struct dsa_switch *ds, int port)757{758 struct mv88e6xxx_chip *chip = ds->priv;759 struct devlink_region *region;760 761 region = dsa_devlink_port_region_create(ds,762 port,763 &mv88e6xxx_region_port_ops, 1,764 32 * sizeof(u16));765 if (IS_ERR(region))766 return PTR_ERR(region);767 768 chip->ports[port].region = region;769 770 return 0;771}772 773int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds)774{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;779 u64 size;780 int i, j;781 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;786 787 if (cond && !cond(chip))788 continue;789 790 switch (i) {791 case MV88E6XXX_REGION_ATU:792 size = mv88e6xxx_num_databases(chip) *793 sizeof(struct mv88e6xxx_devlink_atu_entry);794 break;795 case MV88E6XXX_REGION_VTU:796 size = (mv88e6xxx_max_vid(chip) + 1) *797 sizeof(struct mv88e6xxx_devlink_vtu_entry);798 break;799 case MV88E6XXX_REGION_STU:800 size = (mv88e6xxx_max_sid(chip) + 1) *801 sizeof(struct mv88e6xxx_devlink_stu_entry);802 break;803 }804 805 region = dsa_devlink_region_create(ds, ops, 1, size);806 if (IS_ERR(region))807 goto out;808 chip->regions[i] = region;809 }810 return 0;811 812out:813 for (j = 0; j < i; j++)814 dsa_devlink_region_destroy(chip->regions[j]);815 816 return PTR_ERR(region);817}818 819int mv88e6xxx_devlink_info_get(struct dsa_switch *ds,820 struct devlink_info_req *req,821 struct netlink_ext_ack *extack)822{823 struct mv88e6xxx_chip *chip = ds->priv;824 825 return devlink_info_version_fixed_put(req,826 DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,827 chip->info->name);828}829