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, ®isters[i]); 285 break; 286 case MV88E6XXX_REGION_GLOBAL2: 287 err = mv88e6xxx_g2_read(chip, i, ®isters[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, ®isters[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