0001
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, ®isters[i]);
0284 break;
0285 case MV88E6XXX_REGION_GLOBAL2:
0286 err = mv88e6xxx_g2_read(chip, i, ®isters[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
0305
0306
0307
0308
0309 struct mv88e6xxx_devlink_atu_entry {
0310
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
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
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
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
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, ®isters[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
0723 },
0724 [MV88E6XXX_REGION_VTU] = {
0725 .ops = &mv88e6xxx_region_vtu_ops
0726
0727 },
0728 [MV88E6XXX_REGION_STU] = {
0729 .ops = &mv88e6xxx_region_stu_ops,
0730 .cond = mv88e6xxx_has_stu,
0731
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 }