linux/drivers/net/dsa/mv88e6xxx/devlink.c
<<
>>
Prefs
   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, &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;
 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
 506static int mv88e6xxx_region_pvt_snapshot(struct devlink *dl,
 507                                         const struct devlink_region_ops *ops,
 508                                         struct netlink_ext_ack *extack,
 509                                         u8 **data)
 510{
 511        struct dsa_switch *ds = dsa_devlink_to_ds(dl);
 512        struct mv88e6xxx_chip *chip = ds->priv;
 513        int dev, port, err;
 514        u16 *pvt, *cur;
 515
 516        pvt = kcalloc(MV88E6XXX_MAX_PVT_ENTRIES, sizeof(*pvt), GFP_KERNEL);
 517        if (!pvt)
 518                return -ENOMEM;
 519
 520        mv88e6xxx_reg_lock(chip);
 521
 522        cur = pvt;
 523        for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; dev++) {
 524                for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; port++) {
 525                        err = mv88e6xxx_g2_pvt_read(chip, dev, port, cur);
 526                        if (err)
 527                                break;
 528
 529                        cur++;
 530                }
 531        }
 532
 533        mv88e6xxx_reg_unlock(chip);
 534
 535        if (err) {
 536                kfree(pvt);
 537                return err;
 538        }
 539
 540        *data = (u8 *)pvt;
 541        return 0;
 542}
 543
 544static int mv88e6xxx_region_port_snapshot(struct devlink_port *devlink_port,
 545                                          const struct devlink_port_region_ops *ops,
 546                                          struct netlink_ext_ack *extack,
 547                                          u8 **data)
 548{
 549        struct dsa_switch *ds = dsa_devlink_port_to_ds(devlink_port);
 550        int port = dsa_devlink_port_to_port(devlink_port);
 551        struct mv88e6xxx_chip *chip = ds->priv;
 552        u16 *registers;
 553        int i, err;
 554
 555        registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);
 556        if (!registers)
 557                return -ENOMEM;
 558
 559        mv88e6xxx_reg_lock(chip);
 560        for (i = 0; i < 32; i++) {
 561                err = mv88e6xxx_port_read(chip, port, i, &registers[i]);
 562                if (err) {
 563                        kfree(registers);
 564                        goto out;
 565                }
 566        }
 567        *data = (u8 *)registers;
 568out:
 569        mv88e6xxx_reg_unlock(chip);
 570
 571        return err;
 572}
 573
 574static struct mv88e6xxx_region_priv mv88e6xxx_region_global1_priv = {
 575        .id = MV88E6XXX_REGION_GLOBAL1,
 576};
 577
 578static struct devlink_region_ops mv88e6xxx_region_global1_ops = {
 579        .name = "global1",
 580        .snapshot = mv88e6xxx_region_global_snapshot,
 581        .destructor = kfree,
 582        .priv = &mv88e6xxx_region_global1_priv,
 583};
 584
 585static struct mv88e6xxx_region_priv mv88e6xxx_region_global2_priv = {
 586        .id = MV88E6XXX_REGION_GLOBAL2,
 587};
 588
 589static struct devlink_region_ops mv88e6xxx_region_global2_ops = {
 590        .name = "global2",
 591        .snapshot = mv88e6xxx_region_global_snapshot,
 592        .destructor = kfree,
 593        .priv = &mv88e6xxx_region_global2_priv,
 594};
 595
 596static struct devlink_region_ops mv88e6xxx_region_atu_ops = {
 597        .name = "atu",
 598        .snapshot = mv88e6xxx_region_atu_snapshot,
 599        .destructor = kfree,
 600};
 601
 602static struct devlink_region_ops mv88e6xxx_region_vtu_ops = {
 603        .name = "vtu",
 604        .snapshot = mv88e6xxx_region_vtu_snapshot,
 605        .destructor = kfree,
 606};
 607
 608static struct devlink_region_ops mv88e6xxx_region_pvt_ops = {
 609        .name = "pvt",
 610        .snapshot = mv88e6xxx_region_pvt_snapshot,
 611        .destructor = kfree,
 612};
 613
 614static const struct devlink_port_region_ops mv88e6xxx_region_port_ops = {
 615        .name = "port",
 616        .snapshot = mv88e6xxx_region_port_snapshot,
 617        .destructor = kfree,
 618};
 619
 620struct mv88e6xxx_region {
 621        struct devlink_region_ops *ops;
 622        u64 size;
 623
 624        bool (*cond)(struct mv88e6xxx_chip *chip);
 625};
 626
 627static struct mv88e6xxx_region mv88e6xxx_regions[] = {
 628        [MV88E6XXX_REGION_GLOBAL1] = {
 629                .ops = &mv88e6xxx_region_global1_ops,
 630                .size = 32 * sizeof(u16)
 631        },
 632        [MV88E6XXX_REGION_GLOBAL2] = {
 633                .ops = &mv88e6xxx_region_global2_ops,
 634                .size = 32 * sizeof(u16) },
 635        [MV88E6XXX_REGION_ATU] = {
 636                .ops = &mv88e6xxx_region_atu_ops
 637          /* calculated at runtime */
 638        },
 639        [MV88E6XXX_REGION_VTU] = {
 640                .ops = &mv88e6xxx_region_vtu_ops
 641          /* calculated at runtime */
 642        },
 643        [MV88E6XXX_REGION_PVT] = {
 644                .ops = &mv88e6xxx_region_pvt_ops,
 645                .size = MV88E6XXX_MAX_PVT_ENTRIES * sizeof(u16),
 646                .cond = mv88e6xxx_has_pvt,
 647        },
 648};
 649
 650void mv88e6xxx_teardown_devlink_regions_global(struct dsa_switch *ds)
 651{
 652        struct mv88e6xxx_chip *chip = ds->priv;
 653        int i;
 654
 655        for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++)
 656                dsa_devlink_region_destroy(chip->regions[i]);
 657}
 658
 659void mv88e6xxx_teardown_devlink_regions_port(struct dsa_switch *ds, int port)
 660{
 661        struct mv88e6xxx_chip *chip = ds->priv;
 662
 663        dsa_devlink_region_destroy(chip->ports[port].region);
 664}
 665
 666int mv88e6xxx_setup_devlink_regions_port(struct dsa_switch *ds, int port)
 667{
 668        struct mv88e6xxx_chip *chip = ds->priv;
 669        struct devlink_region *region;
 670
 671        region = dsa_devlink_port_region_create(ds,
 672                                                port,
 673                                                &mv88e6xxx_region_port_ops, 1,
 674                                                32 * sizeof(u16));
 675        if (IS_ERR(region))
 676                return PTR_ERR(region);
 677
 678        chip->ports[port].region = region;
 679
 680        return 0;
 681}
 682
 683int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds)
 684{
 685        bool (*cond)(struct mv88e6xxx_chip *chip);
 686        struct mv88e6xxx_chip *chip = ds->priv;
 687        struct devlink_region_ops *ops;
 688        struct devlink_region *region;
 689        u64 size;
 690        int i, j;
 691
 692        for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++) {
 693                ops = mv88e6xxx_regions[i].ops;
 694                size = mv88e6xxx_regions[i].size;
 695                cond = mv88e6xxx_regions[i].cond;
 696
 697                if (cond && !cond(chip))
 698                        continue;
 699
 700                switch (i) {
 701                case MV88E6XXX_REGION_ATU:
 702                        size = mv88e6xxx_num_databases(chip) *
 703                                sizeof(struct mv88e6xxx_devlink_atu_entry);
 704                        break;
 705                case MV88E6XXX_REGION_VTU:
 706                        size = (mv88e6xxx_max_vid(chip) + 1) *
 707                                sizeof(struct mv88e6xxx_devlink_vtu_entry);
 708                        break;
 709                }
 710
 711                region = dsa_devlink_region_create(ds, ops, 1, size);
 712                if (IS_ERR(region))
 713                        goto out;
 714                chip->regions[i] = region;
 715        }
 716        return 0;
 717
 718out:
 719        for (j = 0; j < i; j++)
 720                dsa_devlink_region_destroy(chip->regions[j]);
 721
 722        return PTR_ERR(region);
 723}
 724
 725int mv88e6xxx_devlink_info_get(struct dsa_switch *ds,
 726                               struct devlink_info_req *req,
 727                               struct netlink_ext_ack *extack)
 728{
 729        struct mv88e6xxx_chip *chip = ds->priv;
 730        int err;
 731
 732        err = devlink_info_driver_name_put(req, "mv88e6xxx");
 733        if (err)
 734                return err;
 735
 736        return devlink_info_version_fixed_put(req,
 737                                              DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
 738                                              chip->info->name);
 739}
 740