devlink.c (19996B)
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 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. Define 305 * a generic format which covers all the current and hopefully future 306 * mv88e6xxx generations 307 */ 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 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. 428 * 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. 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 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. 512 * 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. 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_ops 722 /* calculated at runtime */ 723 }, 724 [MV88E6XXX_REGION_VTU] = { 725 .ops = &mv88e6xxx_region_vtu_ops 726 /* 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 int err; 825 826 err = devlink_info_driver_name_put(req, "mv88e6xxx"); 827 if (err) 828 return err; 829 830 return devlink_info_version_fixed_put(req, 831 DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, 832 chip->info->name); 833}