Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 #include <net/dsa.h>
0003 
0004 #include "chip.h"
0005 #include "devlink.h"
0006 #include "global1.h"
0007 #include "global2.h"
0008 #include "port.h"
0009 
0010 static int mv88e6xxx_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash)
0011 {
0012     if (chip->info->ops->atu_get_hash)
0013         return chip->info->ops->atu_get_hash(chip, hash);
0014 
0015     return -EOPNOTSUPP;
0016 }
0017 
0018 static int mv88e6xxx_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash)
0019 {
0020     if (chip->info->ops->atu_set_hash)
0021         return chip->info->ops->atu_set_hash(chip, hash);
0022 
0023     return -EOPNOTSUPP;
0024 }
0025 
0026 enum mv88e6xxx_devlink_param_id {
0027     MV88E6XXX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
0028     MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
0029 };
0030 
0031 int mv88e6xxx_devlink_param_get(struct dsa_switch *ds, u32 id,
0032                 struct devlink_param_gset_ctx *ctx)
0033 {
0034     struct mv88e6xxx_chip *chip = ds->priv;
0035     int err;
0036 
0037     mv88e6xxx_reg_lock(chip);
0038 
0039     switch (id) {
0040     case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
0041         err = mv88e6xxx_atu_get_hash(chip, &ctx->val.vu8);
0042         break;
0043     default:
0044         err = -EOPNOTSUPP;
0045         break;
0046     }
0047 
0048     mv88e6xxx_reg_unlock(chip);
0049 
0050     return err;
0051 }
0052 
0053 int mv88e6xxx_devlink_param_set(struct dsa_switch *ds, u32 id,
0054                 struct devlink_param_gset_ctx *ctx)
0055 {
0056     struct mv88e6xxx_chip *chip = ds->priv;
0057     int err;
0058 
0059     mv88e6xxx_reg_lock(chip);
0060 
0061     switch (id) {
0062     case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
0063         err = mv88e6xxx_atu_set_hash(chip, ctx->val.vu8);
0064         break;
0065     default:
0066         err = -EOPNOTSUPP;
0067         break;
0068     }
0069 
0070     mv88e6xxx_reg_unlock(chip);
0071 
0072     return err;
0073 }
0074 
0075 static const struct devlink_param mv88e6xxx_devlink_params[] = {
0076     DSA_DEVLINK_PARAM_DRIVER(MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
0077                  "ATU_hash", DEVLINK_PARAM_TYPE_U8,
0078                  BIT(DEVLINK_PARAM_CMODE_RUNTIME)),
0079 };
0080 
0081 int mv88e6xxx_setup_devlink_params(struct dsa_switch *ds)
0082 {
0083     return dsa_devlink_params_register(ds, mv88e6xxx_devlink_params,
0084                        ARRAY_SIZE(mv88e6xxx_devlink_params));
0085 }
0086 
0087 void mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds)
0088 {
0089     dsa_devlink_params_unregister(ds, mv88e6xxx_devlink_params,
0090                       ARRAY_SIZE(mv88e6xxx_devlink_params));
0091 }
0092 
0093 enum mv88e6xxx_devlink_resource_id {
0094     MV88E6XXX_RESOURCE_ID_ATU,
0095     MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
0096     MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
0097     MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
0098     MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
0099 };
0100 
0101 static u64 mv88e6xxx_devlink_atu_bin_get(struct mv88e6xxx_chip *chip,
0102                      u16 bin)
0103 {
0104     u16 occupancy = 0;
0105     int err;
0106 
0107     mv88e6xxx_reg_lock(chip);
0108 
0109     err = mv88e6xxx_g2_atu_stats_set(chip, MV88E6XXX_G2_ATU_STATS_MODE_ALL,
0110                      bin);
0111     if (err) {
0112         dev_err(chip->dev, "failed to set ATU stats kind/bin\n");
0113         goto unlock;
0114     }
0115 
0116     err = mv88e6xxx_g1_atu_get_next(chip, 0);
0117     if (err) {
0118         dev_err(chip->dev, "failed to perform ATU get next\n");
0119         goto unlock;
0120     }
0121 
0122     err = mv88e6xxx_g2_atu_stats_get(chip, &occupancy);
0123     if (err) {
0124         dev_err(chip->dev, "failed to get ATU stats\n");
0125         goto unlock;
0126     }
0127 
0128     occupancy &= MV88E6XXX_G2_ATU_STATS_MASK;
0129 
0130 unlock:
0131     mv88e6xxx_reg_unlock(chip);
0132 
0133     return occupancy;
0134 }
0135 
0136 static u64 mv88e6xxx_devlink_atu_bin_0_get(void *priv)
0137 {
0138     struct mv88e6xxx_chip *chip = priv;
0139 
0140     return mv88e6xxx_devlink_atu_bin_get(chip,
0141                          MV88E6XXX_G2_ATU_STATS_BIN_0);
0142 }
0143 
0144 static u64 mv88e6xxx_devlink_atu_bin_1_get(void *priv)
0145 {
0146     struct mv88e6xxx_chip *chip = priv;
0147 
0148     return mv88e6xxx_devlink_atu_bin_get(chip,
0149                          MV88E6XXX_G2_ATU_STATS_BIN_1);
0150 }
0151 
0152 static u64 mv88e6xxx_devlink_atu_bin_2_get(void *priv)
0153 {
0154     struct mv88e6xxx_chip *chip = priv;
0155 
0156     return mv88e6xxx_devlink_atu_bin_get(chip,
0157                          MV88E6XXX_G2_ATU_STATS_BIN_2);
0158 }
0159 
0160 static u64 mv88e6xxx_devlink_atu_bin_3_get(void *priv)
0161 {
0162     struct mv88e6xxx_chip *chip = priv;
0163 
0164     return mv88e6xxx_devlink_atu_bin_get(chip,
0165                          MV88E6XXX_G2_ATU_STATS_BIN_3);
0166 }
0167 
0168 static u64 mv88e6xxx_devlink_atu_get(void *priv)
0169 {
0170     return mv88e6xxx_devlink_atu_bin_0_get(priv) +
0171         mv88e6xxx_devlink_atu_bin_1_get(priv) +
0172         mv88e6xxx_devlink_atu_bin_2_get(priv) +
0173         mv88e6xxx_devlink_atu_bin_3_get(priv);
0174 }
0175 
0176 int mv88e6xxx_setup_devlink_resources(struct dsa_switch *ds)
0177 {
0178     struct devlink_resource_size_params size_params;
0179     struct mv88e6xxx_chip *chip = ds->priv;
0180     int err;
0181 
0182     devlink_resource_size_params_init(&size_params,
0183                       mv88e6xxx_num_macs(chip),
0184                       mv88e6xxx_num_macs(chip),
0185                       1, DEVLINK_RESOURCE_UNIT_ENTRY);
0186 
0187     err = dsa_devlink_resource_register(ds, "ATU",
0188                         mv88e6xxx_num_macs(chip),
0189                         MV88E6XXX_RESOURCE_ID_ATU,
0190                         DEVLINK_RESOURCE_ID_PARENT_TOP,
0191                         &size_params);
0192     if (err)
0193         goto out;
0194 
0195     devlink_resource_size_params_init(&size_params,
0196                       mv88e6xxx_num_macs(chip) / 4,
0197                       mv88e6xxx_num_macs(chip) / 4,
0198                       1, DEVLINK_RESOURCE_UNIT_ENTRY);
0199 
0200     err = dsa_devlink_resource_register(ds, "ATU_bin_0",
0201                         mv88e6xxx_num_macs(chip) / 4,
0202                         MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
0203                         MV88E6XXX_RESOURCE_ID_ATU,
0204                         &size_params);
0205     if (err)
0206         goto out;
0207 
0208     err = dsa_devlink_resource_register(ds, "ATU_bin_1",
0209                         mv88e6xxx_num_macs(chip) / 4,
0210                         MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
0211                         MV88E6XXX_RESOURCE_ID_ATU,
0212                         &size_params);
0213     if (err)
0214         goto out;
0215 
0216     err = dsa_devlink_resource_register(ds, "ATU_bin_2",
0217                         mv88e6xxx_num_macs(chip) / 4,
0218                         MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
0219                         MV88E6XXX_RESOURCE_ID_ATU,
0220                         &size_params);
0221     if (err)
0222         goto out;
0223 
0224     err = dsa_devlink_resource_register(ds, "ATU_bin_3",
0225                         mv88e6xxx_num_macs(chip) / 4,
0226                         MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
0227                         MV88E6XXX_RESOURCE_ID_ATU,
0228                         &size_params);
0229     if (err)
0230         goto out;
0231 
0232     dsa_devlink_resource_occ_get_register(ds,
0233                           MV88E6XXX_RESOURCE_ID_ATU,
0234                           mv88e6xxx_devlink_atu_get,
0235                           chip);
0236 
0237     dsa_devlink_resource_occ_get_register(ds,
0238                           MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
0239                           mv88e6xxx_devlink_atu_bin_0_get,
0240                           chip);
0241 
0242     dsa_devlink_resource_occ_get_register(ds,
0243                           MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
0244                           mv88e6xxx_devlink_atu_bin_1_get,
0245                           chip);
0246 
0247     dsa_devlink_resource_occ_get_register(ds,
0248                           MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
0249                           mv88e6xxx_devlink_atu_bin_2_get,
0250                           chip);
0251 
0252     dsa_devlink_resource_occ_get_register(ds,
0253                           MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
0254                           mv88e6xxx_devlink_atu_bin_3_get,
0255                           chip);
0256 
0257     return 0;
0258 
0259 out:
0260     dsa_devlink_resources_unregister(ds);
0261     return err;
0262 }
0263 
0264 static int mv88e6xxx_region_global_snapshot(struct devlink *dl,
0265                         const struct devlink_region_ops *ops,
0266                         struct netlink_ext_ack *extack,
0267                         u8 **data)
0268 {
0269     struct mv88e6xxx_region_priv *region_priv = ops->priv;
0270     struct dsa_switch *ds = dsa_devlink_to_ds(dl);
0271     struct mv88e6xxx_chip *chip = ds->priv;
0272     u16 *registers;
0273     int i, err;
0274 
0275     registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);
0276     if (!registers)
0277         return -ENOMEM;
0278 
0279     mv88e6xxx_reg_lock(chip);
0280     for (i = 0; i < 32; i++) {
0281         switch (region_priv->id) {
0282         case MV88E6XXX_REGION_GLOBAL1:
0283             err = mv88e6xxx_g1_read(chip, i, &registers[i]);
0284             break;
0285         case MV88E6XXX_REGION_GLOBAL2:
0286             err = mv88e6xxx_g2_read(chip, i, &registers[i]);
0287             break;
0288         default:
0289             err = -EOPNOTSUPP;
0290         }
0291 
0292         if (err) {
0293             kfree(registers);
0294             goto out;
0295         }
0296     }
0297     *data = (u8 *)registers;
0298 out:
0299     mv88e6xxx_reg_unlock(chip);
0300 
0301     return err;
0302 }
0303 
0304 /* The ATU entry varies between mv88e6xxx chipset generations. Define
0305  * a generic format which covers all the current and hopefully future
0306  * mv88e6xxx generations
0307  */
0308 
0309 struct mv88e6xxx_devlink_atu_entry {
0310     /* The FID is scattered over multiple registers. */
0311     u16 fid;
0312     u16 atu_op;
0313     u16 atu_data;
0314     u16 atu_01;
0315     u16 atu_23;
0316     u16 atu_45;
0317 };
0318 
0319 static int mv88e6xxx_region_atu_snapshot_fid(struct mv88e6xxx_chip *chip,
0320                          int fid,
0321                          struct mv88e6xxx_devlink_atu_entry *table,
0322                          int *count)
0323 {
0324     u16 atu_op, atu_data, atu_01, atu_23, atu_45;
0325     struct mv88e6xxx_atu_entry addr;
0326     int err;
0327 
0328     addr.state = 0;
0329     eth_broadcast_addr(addr.mac);
0330 
0331     do {
0332         err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
0333         if (err)
0334             return err;
0335 
0336         if (!addr.state)
0337             break;
0338 
0339         err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &atu_op);
0340         if (err)
0341             return err;
0342 
0343         err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_DATA, &atu_data);
0344         if (err)
0345             return err;
0346 
0347         err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC01, &atu_01);
0348         if (err)
0349             return err;
0350 
0351         err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC23, &atu_23);
0352         if (err)
0353             return err;
0354 
0355         err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC45, &atu_45);
0356         if (err)
0357             return err;
0358 
0359         table[*count].fid = fid;
0360         table[*count].atu_op = atu_op;
0361         table[*count].atu_data = atu_data;
0362         table[*count].atu_01 = atu_01;
0363         table[*count].atu_23 = atu_23;
0364         table[*count].atu_45 = atu_45;
0365         (*count)++;
0366     } while (!is_broadcast_ether_addr(addr.mac));
0367 
0368     return 0;
0369 }
0370 
0371 static int mv88e6xxx_region_atu_snapshot(struct devlink *dl,
0372                      const struct devlink_region_ops *ops,
0373                      struct netlink_ext_ack *extack,
0374                      u8 **data)
0375 {
0376     struct dsa_switch *ds = dsa_devlink_to_ds(dl);
0377     DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
0378     struct mv88e6xxx_devlink_atu_entry *table;
0379     struct mv88e6xxx_chip *chip = ds->priv;
0380     int fid = -1, count, err;
0381 
0382     table = kmalloc_array(mv88e6xxx_num_databases(chip),
0383                   sizeof(struct mv88e6xxx_devlink_atu_entry),
0384                   GFP_KERNEL);
0385     if (!table)
0386         return -ENOMEM;
0387 
0388     memset(table, 0, mv88e6xxx_num_databases(chip) *
0389            sizeof(struct mv88e6xxx_devlink_atu_entry));
0390 
0391     count = 0;
0392 
0393     mv88e6xxx_reg_lock(chip);
0394 
0395     err = mv88e6xxx_fid_map(chip, fid_bitmap);
0396     if (err) {
0397         kfree(table);
0398         goto out;
0399     }
0400 
0401     while (1) {
0402         fid = find_next_bit(fid_bitmap, MV88E6XXX_N_FID, fid + 1);
0403         if (fid == MV88E6XXX_N_FID)
0404             break;
0405 
0406         err =  mv88e6xxx_region_atu_snapshot_fid(chip, fid, table,
0407                              &count);
0408         if (err) {
0409             kfree(table);
0410             goto out;
0411         }
0412     }
0413     *data = (u8 *)table;
0414 out:
0415     mv88e6xxx_reg_unlock(chip);
0416 
0417     return err;
0418 }
0419 
0420 /**
0421  * struct mv88e6xxx_devlink_vtu_entry - Devlink VTU entry
0422  * @fid:   Global1/2:   FID and VLAN policy.
0423  * @sid:   Global1/3:   SID, unknown filters and learning.
0424  * @op:    Global1/5:   FID (old chipsets).
0425  * @vid:   Global1/6:   VID, valid, and page.
0426  * @data:  Global1/7-9: Membership data and priority override.
0427  * @resvd: Reserved. Also happens to align the size to 16B.
0428  *
0429  * The VTU entry format varies between chipset generations, the
0430  * descriptions above represent the superset of all possible
0431  * information, not all fields are valid on all devices. Since this is
0432  * a low-level debug interface, copy all data verbatim and defer
0433  * parsing to the consumer.
0434  */
0435 struct mv88e6xxx_devlink_vtu_entry {
0436     u16 fid;
0437     u16 sid;
0438     u16 op;
0439     u16 vid;
0440     u16 data[3];
0441     u16 resvd;
0442 };
0443 
0444 static int mv88e6xxx_region_vtu_snapshot(struct devlink *dl,
0445                      const struct devlink_region_ops *ops,
0446                      struct netlink_ext_ack *extack,
0447                      u8 **data)
0448 {
0449     struct mv88e6xxx_devlink_vtu_entry *table, *entry;
0450     struct dsa_switch *ds = dsa_devlink_to_ds(dl);
0451     struct mv88e6xxx_chip *chip = ds->priv;
0452     struct mv88e6xxx_vtu_entry vlan;
0453     int err;
0454 
0455     table = kcalloc(mv88e6xxx_max_vid(chip) + 1,
0456             sizeof(struct mv88e6xxx_devlink_vtu_entry),
0457             GFP_KERNEL);
0458     if (!table)
0459         return -ENOMEM;
0460 
0461     entry = table;
0462     vlan.vid = mv88e6xxx_max_vid(chip);
0463     vlan.valid = false;
0464 
0465     mv88e6xxx_reg_lock(chip);
0466 
0467     do {
0468         err = mv88e6xxx_g1_vtu_getnext(chip, &vlan);
0469         if (err)
0470             break;
0471 
0472         if (!vlan.valid)
0473             break;
0474 
0475         err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_FID,
0476                         &entry->fid);
0477         err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,
0478                         &entry->sid);
0479         err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP,
0480                         &entry->op);
0481         err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,
0482                         &entry->vid);
0483         err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,
0484                         &entry->data[0]);
0485         err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,
0486                         &entry->data[1]);
0487         err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,
0488                         &entry->data[2]);
0489         if (err)
0490             break;
0491 
0492         entry++;
0493     } while (vlan.vid < mv88e6xxx_max_vid(chip));
0494 
0495     mv88e6xxx_reg_unlock(chip);
0496 
0497     if (err) {
0498         kfree(table);
0499         return err;
0500     }
0501 
0502     *data = (u8 *)table;
0503     return 0;
0504 }
0505 
0506 /**
0507  * struct mv88e6xxx_devlink_stu_entry - Devlink STU entry
0508  * @sid:   Global1/3:   SID, unknown filters and learning.
0509  * @vid:   Global1/6:   Valid bit.
0510  * @data:  Global1/7-9: Membership data and priority override.
0511  * @resvd: Reserved. In case we forgot something.
0512  *
0513  * The STU entry format varies between chipset generations. Peridot
0514  * and Amethyst packs the STU data into Global1/7-8. Older silicon
0515  * spreads the information across all three VTU data registers -
0516  * inheriting the layout of even older hardware that had no STU at
0517  * all. Since this is a low-level debug interface, copy all data
0518  * verbatim and defer parsing to the consumer.
0519  */
0520 struct mv88e6xxx_devlink_stu_entry {
0521     u16 sid;
0522     u16 vid;
0523     u16 data[3];
0524     u16 resvd;
0525 };
0526 
0527 static int mv88e6xxx_region_stu_snapshot(struct devlink *dl,
0528                      const struct devlink_region_ops *ops,
0529                      struct netlink_ext_ack *extack,
0530                      u8 **data)
0531 {
0532     struct mv88e6xxx_devlink_stu_entry *table, *entry;
0533     struct dsa_switch *ds = dsa_devlink_to_ds(dl);
0534     struct mv88e6xxx_chip *chip = ds->priv;
0535     struct mv88e6xxx_stu_entry stu;
0536     int err;
0537 
0538     table = kcalloc(mv88e6xxx_max_sid(chip) + 1,
0539             sizeof(struct mv88e6xxx_devlink_stu_entry),
0540             GFP_KERNEL);
0541     if (!table)
0542         return -ENOMEM;
0543 
0544     entry = table;
0545     stu.sid = mv88e6xxx_max_sid(chip);
0546     stu.valid = false;
0547 
0548     mv88e6xxx_reg_lock(chip);
0549 
0550     do {
0551         err = mv88e6xxx_g1_stu_getnext(chip, &stu);
0552         if (err)
0553             break;
0554 
0555         if (!stu.valid)
0556             break;
0557 
0558         err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,
0559                         &entry->sid);
0560         err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,
0561                         &entry->vid);
0562         err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,
0563                         &entry->data[0]);
0564         err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,
0565                         &entry->data[1]);
0566         err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,
0567                         &entry->data[2]);
0568         if (err)
0569             break;
0570 
0571         entry++;
0572     } while (stu.sid < mv88e6xxx_max_sid(chip));
0573 
0574     mv88e6xxx_reg_unlock(chip);
0575 
0576     if (err) {
0577         kfree(table);
0578         return err;
0579     }
0580 
0581     *data = (u8 *)table;
0582     return 0;
0583 }
0584 
0585 static int mv88e6xxx_region_pvt_snapshot(struct devlink *dl,
0586                      const struct devlink_region_ops *ops,
0587                      struct netlink_ext_ack *extack,
0588                      u8 **data)
0589 {
0590     struct dsa_switch *ds = dsa_devlink_to_ds(dl);
0591     struct mv88e6xxx_chip *chip = ds->priv;
0592     int dev, port, err;
0593     u16 *pvt, *cur;
0594 
0595     pvt = kcalloc(MV88E6XXX_MAX_PVT_ENTRIES, sizeof(*pvt), GFP_KERNEL);
0596     if (!pvt)
0597         return -ENOMEM;
0598 
0599     mv88e6xxx_reg_lock(chip);
0600 
0601     cur = pvt;
0602     for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; dev++) {
0603         for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; port++) {
0604             err = mv88e6xxx_g2_pvt_read(chip, dev, port, cur);
0605             if (err)
0606                 break;
0607 
0608             cur++;
0609         }
0610     }
0611 
0612     mv88e6xxx_reg_unlock(chip);
0613 
0614     if (err) {
0615         kfree(pvt);
0616         return err;
0617     }
0618 
0619     *data = (u8 *)pvt;
0620     return 0;
0621 }
0622 
0623 static int mv88e6xxx_region_port_snapshot(struct devlink_port *devlink_port,
0624                       const struct devlink_port_region_ops *ops,
0625                       struct netlink_ext_ack *extack,
0626                       u8 **data)
0627 {
0628     struct dsa_switch *ds = dsa_devlink_port_to_ds(devlink_port);
0629     int port = dsa_devlink_port_to_port(devlink_port);
0630     struct mv88e6xxx_chip *chip = ds->priv;
0631     u16 *registers;
0632     int i, err;
0633 
0634     registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);
0635     if (!registers)
0636         return -ENOMEM;
0637 
0638     mv88e6xxx_reg_lock(chip);
0639     for (i = 0; i < 32; i++) {
0640         err = mv88e6xxx_port_read(chip, port, i, &registers[i]);
0641         if (err) {
0642             kfree(registers);
0643             goto out;
0644         }
0645     }
0646     *data = (u8 *)registers;
0647 out:
0648     mv88e6xxx_reg_unlock(chip);
0649 
0650     return err;
0651 }
0652 
0653 static struct mv88e6xxx_region_priv mv88e6xxx_region_global1_priv = {
0654     .id = MV88E6XXX_REGION_GLOBAL1,
0655 };
0656 
0657 static struct devlink_region_ops mv88e6xxx_region_global1_ops = {
0658     .name = "global1",
0659     .snapshot = mv88e6xxx_region_global_snapshot,
0660     .destructor = kfree,
0661     .priv = &mv88e6xxx_region_global1_priv,
0662 };
0663 
0664 static struct mv88e6xxx_region_priv mv88e6xxx_region_global2_priv = {
0665     .id = MV88E6XXX_REGION_GLOBAL2,
0666 };
0667 
0668 static struct devlink_region_ops mv88e6xxx_region_global2_ops = {
0669     .name = "global2",
0670     .snapshot = mv88e6xxx_region_global_snapshot,
0671     .destructor = kfree,
0672     .priv = &mv88e6xxx_region_global2_priv,
0673 };
0674 
0675 static struct devlink_region_ops mv88e6xxx_region_atu_ops = {
0676     .name = "atu",
0677     .snapshot = mv88e6xxx_region_atu_snapshot,
0678     .destructor = kfree,
0679 };
0680 
0681 static struct devlink_region_ops mv88e6xxx_region_vtu_ops = {
0682     .name = "vtu",
0683     .snapshot = mv88e6xxx_region_vtu_snapshot,
0684     .destructor = kfree,
0685 };
0686 
0687 static struct devlink_region_ops mv88e6xxx_region_stu_ops = {
0688     .name = "stu",
0689     .snapshot = mv88e6xxx_region_stu_snapshot,
0690     .destructor = kfree,
0691 };
0692 
0693 static struct devlink_region_ops mv88e6xxx_region_pvt_ops = {
0694     .name = "pvt",
0695     .snapshot = mv88e6xxx_region_pvt_snapshot,
0696     .destructor = kfree,
0697 };
0698 
0699 static const struct devlink_port_region_ops mv88e6xxx_region_port_ops = {
0700     .name = "port",
0701     .snapshot = mv88e6xxx_region_port_snapshot,
0702     .destructor = kfree,
0703 };
0704 
0705 struct mv88e6xxx_region {
0706     struct devlink_region_ops *ops;
0707     u64 size;
0708 
0709     bool (*cond)(struct mv88e6xxx_chip *chip);
0710 };
0711 
0712 static struct mv88e6xxx_region mv88e6xxx_regions[] = {
0713     [MV88E6XXX_REGION_GLOBAL1] = {
0714         .ops = &mv88e6xxx_region_global1_ops,
0715         .size = 32 * sizeof(u16)
0716     },
0717     [MV88E6XXX_REGION_GLOBAL2] = {
0718         .ops = &mv88e6xxx_region_global2_ops,
0719         .size = 32 * sizeof(u16) },
0720     [MV88E6XXX_REGION_ATU] = {
0721         .ops = &mv88e6xxx_region_atu_ops
0722       /* calculated at runtime */
0723     },
0724     [MV88E6XXX_REGION_VTU] = {
0725         .ops = &mv88e6xxx_region_vtu_ops
0726       /* calculated at runtime */
0727     },
0728     [MV88E6XXX_REGION_STU] = {
0729         .ops = &mv88e6xxx_region_stu_ops,
0730         .cond = mv88e6xxx_has_stu,
0731       /* calculated at runtime */
0732     },
0733     [MV88E6XXX_REGION_PVT] = {
0734         .ops = &mv88e6xxx_region_pvt_ops,
0735         .size = MV88E6XXX_MAX_PVT_ENTRIES * sizeof(u16),
0736         .cond = mv88e6xxx_has_pvt,
0737     },
0738 };
0739 
0740 void mv88e6xxx_teardown_devlink_regions_global(struct dsa_switch *ds)
0741 {
0742     struct mv88e6xxx_chip *chip = ds->priv;
0743     int i;
0744 
0745     for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++)
0746         dsa_devlink_region_destroy(chip->regions[i]);
0747 }
0748 
0749 void mv88e6xxx_teardown_devlink_regions_port(struct dsa_switch *ds, int port)
0750 {
0751     struct mv88e6xxx_chip *chip = ds->priv;
0752 
0753     dsa_devlink_region_destroy(chip->ports[port].region);
0754 }
0755 
0756 int mv88e6xxx_setup_devlink_regions_port(struct dsa_switch *ds, int port)
0757 {
0758     struct mv88e6xxx_chip *chip = ds->priv;
0759     struct devlink_region *region;
0760 
0761     region = dsa_devlink_port_region_create(ds,
0762                         port,
0763                         &mv88e6xxx_region_port_ops, 1,
0764                         32 * sizeof(u16));
0765     if (IS_ERR(region))
0766         return PTR_ERR(region);
0767 
0768     chip->ports[port].region = region;
0769 
0770     return 0;
0771 }
0772 
0773 int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds)
0774 {
0775     bool (*cond)(struct mv88e6xxx_chip *chip);
0776     struct mv88e6xxx_chip *chip = ds->priv;
0777     struct devlink_region_ops *ops;
0778     struct devlink_region *region;
0779     u64 size;
0780     int i, j;
0781 
0782     for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++) {
0783         ops = mv88e6xxx_regions[i].ops;
0784         size = mv88e6xxx_regions[i].size;
0785         cond = mv88e6xxx_regions[i].cond;
0786 
0787         if (cond && !cond(chip))
0788             continue;
0789 
0790         switch (i) {
0791         case MV88E6XXX_REGION_ATU:
0792             size = mv88e6xxx_num_databases(chip) *
0793                 sizeof(struct mv88e6xxx_devlink_atu_entry);
0794             break;
0795         case MV88E6XXX_REGION_VTU:
0796             size = (mv88e6xxx_max_vid(chip) + 1) *
0797                 sizeof(struct mv88e6xxx_devlink_vtu_entry);
0798             break;
0799         case MV88E6XXX_REGION_STU:
0800             size = (mv88e6xxx_max_sid(chip) + 1) *
0801                 sizeof(struct mv88e6xxx_devlink_stu_entry);
0802             break;
0803         }
0804 
0805         region = dsa_devlink_region_create(ds, ops, 1, size);
0806         if (IS_ERR(region))
0807             goto out;
0808         chip->regions[i] = region;
0809     }
0810     return 0;
0811 
0812 out:
0813     for (j = 0; j < i; j++)
0814         dsa_devlink_region_destroy(chip->regions[j]);
0815 
0816     return PTR_ERR(region);
0817 }
0818 
0819 int mv88e6xxx_devlink_info_get(struct dsa_switch *ds,
0820                    struct devlink_info_req *req,
0821                    struct netlink_ext_ack *extack)
0822 {
0823     struct mv88e6xxx_chip *chip = ds->priv;
0824     int err;
0825 
0826     err = devlink_info_driver_name_put(req, "mv88e6xxx");
0827     if (err)
0828         return err;
0829 
0830     return devlink_info_version_fixed_put(req,
0831                           DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
0832                           chip->info->name);
0833 }