162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci#include <net/dsa.h> 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include "chip.h" 562306a36Sopenharmony_ci#include "devlink.h" 662306a36Sopenharmony_ci#include "global1.h" 762306a36Sopenharmony_ci#include "global2.h" 862306a36Sopenharmony_ci#include "port.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_cistatic int mv88e6xxx_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash) 1162306a36Sopenharmony_ci{ 1262306a36Sopenharmony_ci if (chip->info->ops->atu_get_hash) 1362306a36Sopenharmony_ci return chip->info->ops->atu_get_hash(chip, hash); 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci return -EOPNOTSUPP; 1662306a36Sopenharmony_ci} 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic int mv88e6xxx_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci if (chip->info->ops->atu_set_hash) 2162306a36Sopenharmony_ci return chip->info->ops->atu_set_hash(chip, hash); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci return -EOPNOTSUPP; 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cienum mv88e6xxx_devlink_param_id { 2762306a36Sopenharmony_ci MV88E6XXX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, 2862306a36Sopenharmony_ci MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH, 2962306a36Sopenharmony_ci}; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciint mv88e6xxx_devlink_param_get(struct dsa_switch *ds, u32 id, 3262306a36Sopenharmony_ci struct devlink_param_gset_ctx *ctx) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 3562306a36Sopenharmony_ci int err; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci switch (id) { 4062306a36Sopenharmony_ci case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH: 4162306a36Sopenharmony_ci err = mv88e6xxx_atu_get_hash(chip, &ctx->val.vu8); 4262306a36Sopenharmony_ci break; 4362306a36Sopenharmony_ci default: 4462306a36Sopenharmony_ci err = -EOPNOTSUPP; 4562306a36Sopenharmony_ci break; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci return err; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ciint mv88e6xxx_devlink_param_set(struct dsa_switch *ds, u32 id, 5462306a36Sopenharmony_ci struct devlink_param_gset_ctx *ctx) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 5762306a36Sopenharmony_ci int err; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci switch (id) { 6262306a36Sopenharmony_ci case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH: 6362306a36Sopenharmony_ci err = mv88e6xxx_atu_set_hash(chip, ctx->val.vu8); 6462306a36Sopenharmony_ci break; 6562306a36Sopenharmony_ci default: 6662306a36Sopenharmony_ci err = -EOPNOTSUPP; 6762306a36Sopenharmony_ci break; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return err; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic const struct devlink_param mv88e6xxx_devlink_params[] = { 7662306a36Sopenharmony_ci DSA_DEVLINK_PARAM_DRIVER(MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH, 7762306a36Sopenharmony_ci "ATU_hash", DEVLINK_PARAM_TYPE_U8, 7862306a36Sopenharmony_ci BIT(DEVLINK_PARAM_CMODE_RUNTIME)), 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ciint mv88e6xxx_setup_devlink_params(struct dsa_switch *ds) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci return dsa_devlink_params_register(ds, mv88e6xxx_devlink_params, 8462306a36Sopenharmony_ci ARRAY_SIZE(mv88e6xxx_devlink_params)); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_civoid mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci dsa_devlink_params_unregister(ds, mv88e6xxx_devlink_params, 9062306a36Sopenharmony_ci ARRAY_SIZE(mv88e6xxx_devlink_params)); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cienum mv88e6xxx_devlink_resource_id { 9462306a36Sopenharmony_ci MV88E6XXX_RESOURCE_ID_ATU, 9562306a36Sopenharmony_ci MV88E6XXX_RESOURCE_ID_ATU_BIN_0, 9662306a36Sopenharmony_ci MV88E6XXX_RESOURCE_ID_ATU_BIN_1, 9762306a36Sopenharmony_ci MV88E6XXX_RESOURCE_ID_ATU_BIN_2, 9862306a36Sopenharmony_ci MV88E6XXX_RESOURCE_ID_ATU_BIN_3, 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic u64 mv88e6xxx_devlink_atu_bin_get(struct mv88e6xxx_chip *chip, 10262306a36Sopenharmony_ci u16 bin) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci u16 occupancy = 0; 10562306a36Sopenharmony_ci int err; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci err = mv88e6xxx_g2_atu_stats_set(chip, MV88E6XXX_G2_ATU_STATS_MODE_ALL, 11062306a36Sopenharmony_ci bin); 11162306a36Sopenharmony_ci if (err) { 11262306a36Sopenharmony_ci dev_err(chip->dev, "failed to set ATU stats kind/bin\n"); 11362306a36Sopenharmony_ci goto unlock; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci err = mv88e6xxx_g1_atu_get_next(chip, 0); 11762306a36Sopenharmony_ci if (err) { 11862306a36Sopenharmony_ci dev_err(chip->dev, "failed to perform ATU get next\n"); 11962306a36Sopenharmony_ci goto unlock; 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci err = mv88e6xxx_g2_atu_stats_get(chip, &occupancy); 12362306a36Sopenharmony_ci if (err) { 12462306a36Sopenharmony_ci dev_err(chip->dev, "failed to get ATU stats\n"); 12562306a36Sopenharmony_ci goto unlock; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci occupancy &= MV88E6XXX_G2_ATU_STATS_MASK; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ciunlock: 13162306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci return occupancy; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic u64 mv88e6xxx_devlink_atu_bin_0_get(void *priv) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = priv; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci return mv88e6xxx_devlink_atu_bin_get(chip, 14162306a36Sopenharmony_ci MV88E6XXX_G2_ATU_STATS_BIN_0); 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic u64 mv88e6xxx_devlink_atu_bin_1_get(void *priv) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = priv; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci return mv88e6xxx_devlink_atu_bin_get(chip, 14962306a36Sopenharmony_ci MV88E6XXX_G2_ATU_STATS_BIN_1); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic u64 mv88e6xxx_devlink_atu_bin_2_get(void *priv) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = priv; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci return mv88e6xxx_devlink_atu_bin_get(chip, 15762306a36Sopenharmony_ci MV88E6XXX_G2_ATU_STATS_BIN_2); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic u64 mv88e6xxx_devlink_atu_bin_3_get(void *priv) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = priv; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci return mv88e6xxx_devlink_atu_bin_get(chip, 16562306a36Sopenharmony_ci MV88E6XXX_G2_ATU_STATS_BIN_3); 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic u64 mv88e6xxx_devlink_atu_get(void *priv) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci return mv88e6xxx_devlink_atu_bin_0_get(priv) + 17162306a36Sopenharmony_ci mv88e6xxx_devlink_atu_bin_1_get(priv) + 17262306a36Sopenharmony_ci mv88e6xxx_devlink_atu_bin_2_get(priv) + 17362306a36Sopenharmony_ci mv88e6xxx_devlink_atu_bin_3_get(priv); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ciint mv88e6xxx_setup_devlink_resources(struct dsa_switch *ds) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct devlink_resource_size_params size_params; 17962306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 18062306a36Sopenharmony_ci int err; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci devlink_resource_size_params_init(&size_params, 18362306a36Sopenharmony_ci mv88e6xxx_num_macs(chip), 18462306a36Sopenharmony_ci mv88e6xxx_num_macs(chip), 18562306a36Sopenharmony_ci 1, DEVLINK_RESOURCE_UNIT_ENTRY); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci err = dsa_devlink_resource_register(ds, "ATU", 18862306a36Sopenharmony_ci mv88e6xxx_num_macs(chip), 18962306a36Sopenharmony_ci MV88E6XXX_RESOURCE_ID_ATU, 19062306a36Sopenharmony_ci DEVLINK_RESOURCE_ID_PARENT_TOP, 19162306a36Sopenharmony_ci &size_params); 19262306a36Sopenharmony_ci if (err) 19362306a36Sopenharmony_ci goto out; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci devlink_resource_size_params_init(&size_params, 19662306a36Sopenharmony_ci mv88e6xxx_num_macs(chip) / 4, 19762306a36Sopenharmony_ci mv88e6xxx_num_macs(chip) / 4, 19862306a36Sopenharmony_ci 1, DEVLINK_RESOURCE_UNIT_ENTRY); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci err = dsa_devlink_resource_register(ds, "ATU_bin_0", 20162306a36Sopenharmony_ci mv88e6xxx_num_macs(chip) / 4, 20262306a36Sopenharmony_ci MV88E6XXX_RESOURCE_ID_ATU_BIN_0, 20362306a36Sopenharmony_ci MV88E6XXX_RESOURCE_ID_ATU, 20462306a36Sopenharmony_ci &size_params); 20562306a36Sopenharmony_ci if (err) 20662306a36Sopenharmony_ci goto out; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci err = dsa_devlink_resource_register(ds, "ATU_bin_1", 20962306a36Sopenharmony_ci mv88e6xxx_num_macs(chip) / 4, 21062306a36Sopenharmony_ci MV88E6XXX_RESOURCE_ID_ATU_BIN_1, 21162306a36Sopenharmony_ci MV88E6XXX_RESOURCE_ID_ATU, 21262306a36Sopenharmony_ci &size_params); 21362306a36Sopenharmony_ci if (err) 21462306a36Sopenharmony_ci goto out; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci err = dsa_devlink_resource_register(ds, "ATU_bin_2", 21762306a36Sopenharmony_ci mv88e6xxx_num_macs(chip) / 4, 21862306a36Sopenharmony_ci MV88E6XXX_RESOURCE_ID_ATU_BIN_2, 21962306a36Sopenharmony_ci MV88E6XXX_RESOURCE_ID_ATU, 22062306a36Sopenharmony_ci &size_params); 22162306a36Sopenharmony_ci if (err) 22262306a36Sopenharmony_ci goto out; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci err = dsa_devlink_resource_register(ds, "ATU_bin_3", 22562306a36Sopenharmony_ci mv88e6xxx_num_macs(chip) / 4, 22662306a36Sopenharmony_ci MV88E6XXX_RESOURCE_ID_ATU_BIN_3, 22762306a36Sopenharmony_ci MV88E6XXX_RESOURCE_ID_ATU, 22862306a36Sopenharmony_ci &size_params); 22962306a36Sopenharmony_ci if (err) 23062306a36Sopenharmony_ci goto out; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci dsa_devlink_resource_occ_get_register(ds, 23362306a36Sopenharmony_ci MV88E6XXX_RESOURCE_ID_ATU, 23462306a36Sopenharmony_ci mv88e6xxx_devlink_atu_get, 23562306a36Sopenharmony_ci chip); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci dsa_devlink_resource_occ_get_register(ds, 23862306a36Sopenharmony_ci MV88E6XXX_RESOURCE_ID_ATU_BIN_0, 23962306a36Sopenharmony_ci mv88e6xxx_devlink_atu_bin_0_get, 24062306a36Sopenharmony_ci chip); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci dsa_devlink_resource_occ_get_register(ds, 24362306a36Sopenharmony_ci MV88E6XXX_RESOURCE_ID_ATU_BIN_1, 24462306a36Sopenharmony_ci mv88e6xxx_devlink_atu_bin_1_get, 24562306a36Sopenharmony_ci chip); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci dsa_devlink_resource_occ_get_register(ds, 24862306a36Sopenharmony_ci MV88E6XXX_RESOURCE_ID_ATU_BIN_2, 24962306a36Sopenharmony_ci mv88e6xxx_devlink_atu_bin_2_get, 25062306a36Sopenharmony_ci chip); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci dsa_devlink_resource_occ_get_register(ds, 25362306a36Sopenharmony_ci MV88E6XXX_RESOURCE_ID_ATU_BIN_3, 25462306a36Sopenharmony_ci mv88e6xxx_devlink_atu_bin_3_get, 25562306a36Sopenharmony_ci chip); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci return 0; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ciout: 26062306a36Sopenharmony_ci dsa_devlink_resources_unregister(ds); 26162306a36Sopenharmony_ci return err; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic int mv88e6xxx_region_global_snapshot(struct devlink *dl, 26562306a36Sopenharmony_ci const struct devlink_region_ops *ops, 26662306a36Sopenharmony_ci struct netlink_ext_ack *extack, 26762306a36Sopenharmony_ci u8 **data) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci struct mv88e6xxx_region_priv *region_priv = ops->priv; 27062306a36Sopenharmony_ci struct dsa_switch *ds = dsa_devlink_to_ds(dl); 27162306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 27262306a36Sopenharmony_ci u16 *registers; 27362306a36Sopenharmony_ci int i, err; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL); 27662306a36Sopenharmony_ci if (!registers) 27762306a36Sopenharmony_ci return -ENOMEM; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 28062306a36Sopenharmony_ci for (i = 0; i < 32; i++) { 28162306a36Sopenharmony_ci switch (region_priv->id) { 28262306a36Sopenharmony_ci case MV88E6XXX_REGION_GLOBAL1: 28362306a36Sopenharmony_ci err = mv88e6xxx_g1_read(chip, i, ®isters[i]); 28462306a36Sopenharmony_ci break; 28562306a36Sopenharmony_ci case MV88E6XXX_REGION_GLOBAL2: 28662306a36Sopenharmony_ci err = mv88e6xxx_g2_read(chip, i, ®isters[i]); 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci default: 28962306a36Sopenharmony_ci err = -EOPNOTSUPP; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (err) { 29362306a36Sopenharmony_ci kfree(registers); 29462306a36Sopenharmony_ci goto out; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci *data = (u8 *)registers; 29862306a36Sopenharmony_ciout: 29962306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci return err; 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci/* The ATU entry varies between mv88e6xxx chipset generations. Define 30562306a36Sopenharmony_ci * a generic format which covers all the current and hopefully future 30662306a36Sopenharmony_ci * mv88e6xxx generations 30762306a36Sopenharmony_ci */ 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistruct mv88e6xxx_devlink_atu_entry { 31062306a36Sopenharmony_ci /* The FID is scattered over multiple registers. */ 31162306a36Sopenharmony_ci u16 fid; 31262306a36Sopenharmony_ci u16 atu_op; 31362306a36Sopenharmony_ci u16 atu_data; 31462306a36Sopenharmony_ci u16 atu_01; 31562306a36Sopenharmony_ci u16 atu_23; 31662306a36Sopenharmony_ci u16 atu_45; 31762306a36Sopenharmony_ci}; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic int mv88e6xxx_region_atu_snapshot_fid(struct mv88e6xxx_chip *chip, 32062306a36Sopenharmony_ci int fid, 32162306a36Sopenharmony_ci struct mv88e6xxx_devlink_atu_entry *table, 32262306a36Sopenharmony_ci int *count) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci u16 atu_op, atu_data, atu_01, atu_23, atu_45; 32562306a36Sopenharmony_ci struct mv88e6xxx_atu_entry addr; 32662306a36Sopenharmony_ci int err; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci addr.state = 0; 32962306a36Sopenharmony_ci eth_broadcast_addr(addr.mac); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci do { 33262306a36Sopenharmony_ci err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr); 33362306a36Sopenharmony_ci if (err) 33462306a36Sopenharmony_ci return err; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (!addr.state) 33762306a36Sopenharmony_ci break; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &atu_op); 34062306a36Sopenharmony_ci if (err) 34162306a36Sopenharmony_ci return err; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_DATA, &atu_data); 34462306a36Sopenharmony_ci if (err) 34562306a36Sopenharmony_ci return err; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC01, &atu_01); 34862306a36Sopenharmony_ci if (err) 34962306a36Sopenharmony_ci return err; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC23, &atu_23); 35262306a36Sopenharmony_ci if (err) 35362306a36Sopenharmony_ci return err; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC45, &atu_45); 35662306a36Sopenharmony_ci if (err) 35762306a36Sopenharmony_ci return err; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci table[*count].fid = fid; 36062306a36Sopenharmony_ci table[*count].atu_op = atu_op; 36162306a36Sopenharmony_ci table[*count].atu_data = atu_data; 36262306a36Sopenharmony_ci table[*count].atu_01 = atu_01; 36362306a36Sopenharmony_ci table[*count].atu_23 = atu_23; 36462306a36Sopenharmony_ci table[*count].atu_45 = atu_45; 36562306a36Sopenharmony_ci (*count)++; 36662306a36Sopenharmony_ci } while (!is_broadcast_ether_addr(addr.mac)); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return 0; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic int mv88e6xxx_region_atu_snapshot(struct devlink *dl, 37262306a36Sopenharmony_ci const struct devlink_region_ops *ops, 37362306a36Sopenharmony_ci struct netlink_ext_ack *extack, 37462306a36Sopenharmony_ci u8 **data) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci struct dsa_switch *ds = dsa_devlink_to_ds(dl); 37762306a36Sopenharmony_ci DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); 37862306a36Sopenharmony_ci struct mv88e6xxx_devlink_atu_entry *table; 37962306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 38062306a36Sopenharmony_ci int fid = -1, count, err; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci table = kmalloc_array(mv88e6xxx_num_databases(chip), 38362306a36Sopenharmony_ci sizeof(struct mv88e6xxx_devlink_atu_entry), 38462306a36Sopenharmony_ci GFP_KERNEL); 38562306a36Sopenharmony_ci if (!table) 38662306a36Sopenharmony_ci return -ENOMEM; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci memset(table, 0, mv88e6xxx_num_databases(chip) * 38962306a36Sopenharmony_ci sizeof(struct mv88e6xxx_devlink_atu_entry)); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci count = 0; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci err = mv88e6xxx_fid_map(chip, fid_bitmap); 39662306a36Sopenharmony_ci if (err) { 39762306a36Sopenharmony_ci kfree(table); 39862306a36Sopenharmony_ci goto out; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci while (1) { 40262306a36Sopenharmony_ci fid = find_next_bit(fid_bitmap, MV88E6XXX_N_FID, fid + 1); 40362306a36Sopenharmony_ci if (fid == MV88E6XXX_N_FID) 40462306a36Sopenharmony_ci break; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci err = mv88e6xxx_region_atu_snapshot_fid(chip, fid, table, 40762306a36Sopenharmony_ci &count); 40862306a36Sopenharmony_ci if (err) { 40962306a36Sopenharmony_ci kfree(table); 41062306a36Sopenharmony_ci goto out; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci *data = (u8 *)table; 41462306a36Sopenharmony_ciout: 41562306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci return err; 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci/** 42162306a36Sopenharmony_ci * struct mv88e6xxx_devlink_vtu_entry - Devlink VTU entry 42262306a36Sopenharmony_ci * @fid: Global1/2: FID and VLAN policy. 42362306a36Sopenharmony_ci * @sid: Global1/3: SID, unknown filters and learning. 42462306a36Sopenharmony_ci * @op: Global1/5: FID (old chipsets). 42562306a36Sopenharmony_ci * @vid: Global1/6: VID, valid, and page. 42662306a36Sopenharmony_ci * @data: Global1/7-9: Membership data and priority override. 42762306a36Sopenharmony_ci * @resvd: Reserved. Also happens to align the size to 16B. 42862306a36Sopenharmony_ci * 42962306a36Sopenharmony_ci * The VTU entry format varies between chipset generations, the 43062306a36Sopenharmony_ci * descriptions above represent the superset of all possible 43162306a36Sopenharmony_ci * information, not all fields are valid on all devices. Since this is 43262306a36Sopenharmony_ci * a low-level debug interface, copy all data verbatim and defer 43362306a36Sopenharmony_ci * parsing to the consumer. 43462306a36Sopenharmony_ci */ 43562306a36Sopenharmony_cistruct mv88e6xxx_devlink_vtu_entry { 43662306a36Sopenharmony_ci u16 fid; 43762306a36Sopenharmony_ci u16 sid; 43862306a36Sopenharmony_ci u16 op; 43962306a36Sopenharmony_ci u16 vid; 44062306a36Sopenharmony_ci u16 data[3]; 44162306a36Sopenharmony_ci u16 resvd; 44262306a36Sopenharmony_ci}; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic int mv88e6xxx_region_vtu_snapshot(struct devlink *dl, 44562306a36Sopenharmony_ci const struct devlink_region_ops *ops, 44662306a36Sopenharmony_ci struct netlink_ext_ack *extack, 44762306a36Sopenharmony_ci u8 **data) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci struct mv88e6xxx_devlink_vtu_entry *table, *entry; 45062306a36Sopenharmony_ci struct dsa_switch *ds = dsa_devlink_to_ds(dl); 45162306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 45262306a36Sopenharmony_ci struct mv88e6xxx_vtu_entry vlan; 45362306a36Sopenharmony_ci int err; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci table = kcalloc(mv88e6xxx_max_vid(chip) + 1, 45662306a36Sopenharmony_ci sizeof(struct mv88e6xxx_devlink_vtu_entry), 45762306a36Sopenharmony_ci GFP_KERNEL); 45862306a36Sopenharmony_ci if (!table) 45962306a36Sopenharmony_ci return -ENOMEM; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci entry = table; 46262306a36Sopenharmony_ci vlan.vid = mv88e6xxx_max_vid(chip); 46362306a36Sopenharmony_ci vlan.valid = false; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci do { 46862306a36Sopenharmony_ci err = mv88e6xxx_g1_vtu_getnext(chip, &vlan); 46962306a36Sopenharmony_ci if (err) 47062306a36Sopenharmony_ci break; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if (!vlan.valid) 47362306a36Sopenharmony_ci break; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_FID, 47662306a36Sopenharmony_ci &entry->fid); 47762306a36Sopenharmony_ci err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID, 47862306a36Sopenharmony_ci &entry->sid); 47962306a36Sopenharmony_ci err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP, 48062306a36Sopenharmony_ci &entry->op); 48162306a36Sopenharmony_ci err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID, 48262306a36Sopenharmony_ci &entry->vid); 48362306a36Sopenharmony_ci err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1, 48462306a36Sopenharmony_ci &entry->data[0]); 48562306a36Sopenharmony_ci err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2, 48662306a36Sopenharmony_ci &entry->data[1]); 48762306a36Sopenharmony_ci err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3, 48862306a36Sopenharmony_ci &entry->data[2]); 48962306a36Sopenharmony_ci if (err) 49062306a36Sopenharmony_ci break; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci entry++; 49362306a36Sopenharmony_ci } while (vlan.vid < mv88e6xxx_max_vid(chip)); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (err) { 49862306a36Sopenharmony_ci kfree(table); 49962306a36Sopenharmony_ci return err; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci *data = (u8 *)table; 50362306a36Sopenharmony_ci return 0; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci/** 50762306a36Sopenharmony_ci * struct mv88e6xxx_devlink_stu_entry - Devlink STU entry 50862306a36Sopenharmony_ci * @sid: Global1/3: SID, unknown filters and learning. 50962306a36Sopenharmony_ci * @vid: Global1/6: Valid bit. 51062306a36Sopenharmony_ci * @data: Global1/7-9: Membership data and priority override. 51162306a36Sopenharmony_ci * @resvd: Reserved. In case we forgot something. 51262306a36Sopenharmony_ci * 51362306a36Sopenharmony_ci * The STU entry format varies between chipset generations. Peridot 51462306a36Sopenharmony_ci * and Amethyst packs the STU data into Global1/7-8. Older silicon 51562306a36Sopenharmony_ci * spreads the information across all three VTU data registers - 51662306a36Sopenharmony_ci * inheriting the layout of even older hardware that had no STU at 51762306a36Sopenharmony_ci * all. Since this is a low-level debug interface, copy all data 51862306a36Sopenharmony_ci * verbatim and defer parsing to the consumer. 51962306a36Sopenharmony_ci */ 52062306a36Sopenharmony_cistruct mv88e6xxx_devlink_stu_entry { 52162306a36Sopenharmony_ci u16 sid; 52262306a36Sopenharmony_ci u16 vid; 52362306a36Sopenharmony_ci u16 data[3]; 52462306a36Sopenharmony_ci u16 resvd; 52562306a36Sopenharmony_ci}; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic int mv88e6xxx_region_stu_snapshot(struct devlink *dl, 52862306a36Sopenharmony_ci const struct devlink_region_ops *ops, 52962306a36Sopenharmony_ci struct netlink_ext_ack *extack, 53062306a36Sopenharmony_ci u8 **data) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci struct mv88e6xxx_devlink_stu_entry *table, *entry; 53362306a36Sopenharmony_ci struct dsa_switch *ds = dsa_devlink_to_ds(dl); 53462306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 53562306a36Sopenharmony_ci struct mv88e6xxx_stu_entry stu; 53662306a36Sopenharmony_ci int err; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci table = kcalloc(mv88e6xxx_max_sid(chip) + 1, 53962306a36Sopenharmony_ci sizeof(struct mv88e6xxx_devlink_stu_entry), 54062306a36Sopenharmony_ci GFP_KERNEL); 54162306a36Sopenharmony_ci if (!table) 54262306a36Sopenharmony_ci return -ENOMEM; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci entry = table; 54562306a36Sopenharmony_ci stu.sid = mv88e6xxx_max_sid(chip); 54662306a36Sopenharmony_ci stu.valid = false; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci do { 55162306a36Sopenharmony_ci err = mv88e6xxx_g1_stu_getnext(chip, &stu); 55262306a36Sopenharmony_ci if (err) 55362306a36Sopenharmony_ci break; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (!stu.valid) 55662306a36Sopenharmony_ci break; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID, 55962306a36Sopenharmony_ci &entry->sid); 56062306a36Sopenharmony_ci err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID, 56162306a36Sopenharmony_ci &entry->vid); 56262306a36Sopenharmony_ci err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1, 56362306a36Sopenharmony_ci &entry->data[0]); 56462306a36Sopenharmony_ci err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2, 56562306a36Sopenharmony_ci &entry->data[1]); 56662306a36Sopenharmony_ci err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3, 56762306a36Sopenharmony_ci &entry->data[2]); 56862306a36Sopenharmony_ci if (err) 56962306a36Sopenharmony_ci break; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci entry++; 57262306a36Sopenharmony_ci } while (stu.sid < mv88e6xxx_max_sid(chip)); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (err) { 57762306a36Sopenharmony_ci kfree(table); 57862306a36Sopenharmony_ci return err; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci *data = (u8 *)table; 58262306a36Sopenharmony_ci return 0; 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistatic int mv88e6xxx_region_pvt_snapshot(struct devlink *dl, 58662306a36Sopenharmony_ci const struct devlink_region_ops *ops, 58762306a36Sopenharmony_ci struct netlink_ext_ack *extack, 58862306a36Sopenharmony_ci u8 **data) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci struct dsa_switch *ds = dsa_devlink_to_ds(dl); 59162306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 59262306a36Sopenharmony_ci int dev, port, err; 59362306a36Sopenharmony_ci u16 *pvt, *cur; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci pvt = kcalloc(MV88E6XXX_MAX_PVT_ENTRIES, sizeof(*pvt), GFP_KERNEL); 59662306a36Sopenharmony_ci if (!pvt) 59762306a36Sopenharmony_ci return -ENOMEM; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci cur = pvt; 60262306a36Sopenharmony_ci for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; dev++) { 60362306a36Sopenharmony_ci for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; port++) { 60462306a36Sopenharmony_ci err = mv88e6xxx_g2_pvt_read(chip, dev, port, cur); 60562306a36Sopenharmony_ci if (err) 60662306a36Sopenharmony_ci break; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci cur++; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci if (err) { 61562306a36Sopenharmony_ci kfree(pvt); 61662306a36Sopenharmony_ci return err; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci *data = (u8 *)pvt; 62062306a36Sopenharmony_ci return 0; 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic int mv88e6xxx_region_port_snapshot(struct devlink_port *devlink_port, 62462306a36Sopenharmony_ci const struct devlink_port_region_ops *ops, 62562306a36Sopenharmony_ci struct netlink_ext_ack *extack, 62662306a36Sopenharmony_ci u8 **data) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci struct dsa_switch *ds = dsa_devlink_port_to_ds(devlink_port); 62962306a36Sopenharmony_ci int port = dsa_devlink_port_to_port(devlink_port); 63062306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 63162306a36Sopenharmony_ci u16 *registers; 63262306a36Sopenharmony_ci int i, err; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL); 63562306a36Sopenharmony_ci if (!registers) 63662306a36Sopenharmony_ci return -ENOMEM; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci mv88e6xxx_reg_lock(chip); 63962306a36Sopenharmony_ci for (i = 0; i < 32; i++) { 64062306a36Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, i, ®isters[i]); 64162306a36Sopenharmony_ci if (err) { 64262306a36Sopenharmony_ci kfree(registers); 64362306a36Sopenharmony_ci goto out; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci *data = (u8 *)registers; 64762306a36Sopenharmony_ciout: 64862306a36Sopenharmony_ci mv88e6xxx_reg_unlock(chip); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci return err; 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic struct mv88e6xxx_region_priv mv88e6xxx_region_global1_priv = { 65462306a36Sopenharmony_ci .id = MV88E6XXX_REGION_GLOBAL1, 65562306a36Sopenharmony_ci}; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic struct devlink_region_ops mv88e6xxx_region_global1_ops = { 65862306a36Sopenharmony_ci .name = "global1", 65962306a36Sopenharmony_ci .snapshot = mv88e6xxx_region_global_snapshot, 66062306a36Sopenharmony_ci .destructor = kfree, 66162306a36Sopenharmony_ci .priv = &mv88e6xxx_region_global1_priv, 66262306a36Sopenharmony_ci}; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_cistatic struct mv88e6xxx_region_priv mv88e6xxx_region_global2_priv = { 66562306a36Sopenharmony_ci .id = MV88E6XXX_REGION_GLOBAL2, 66662306a36Sopenharmony_ci}; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic struct devlink_region_ops mv88e6xxx_region_global2_ops = { 66962306a36Sopenharmony_ci .name = "global2", 67062306a36Sopenharmony_ci .snapshot = mv88e6xxx_region_global_snapshot, 67162306a36Sopenharmony_ci .destructor = kfree, 67262306a36Sopenharmony_ci .priv = &mv88e6xxx_region_global2_priv, 67362306a36Sopenharmony_ci}; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_cistatic struct devlink_region_ops mv88e6xxx_region_atu_ops = { 67662306a36Sopenharmony_ci .name = "atu", 67762306a36Sopenharmony_ci .snapshot = mv88e6xxx_region_atu_snapshot, 67862306a36Sopenharmony_ci .destructor = kfree, 67962306a36Sopenharmony_ci}; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic struct devlink_region_ops mv88e6xxx_region_vtu_ops = { 68262306a36Sopenharmony_ci .name = "vtu", 68362306a36Sopenharmony_ci .snapshot = mv88e6xxx_region_vtu_snapshot, 68462306a36Sopenharmony_ci .destructor = kfree, 68562306a36Sopenharmony_ci}; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistatic struct devlink_region_ops mv88e6xxx_region_stu_ops = { 68862306a36Sopenharmony_ci .name = "stu", 68962306a36Sopenharmony_ci .snapshot = mv88e6xxx_region_stu_snapshot, 69062306a36Sopenharmony_ci .destructor = kfree, 69162306a36Sopenharmony_ci}; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_cistatic struct devlink_region_ops mv88e6xxx_region_pvt_ops = { 69462306a36Sopenharmony_ci .name = "pvt", 69562306a36Sopenharmony_ci .snapshot = mv88e6xxx_region_pvt_snapshot, 69662306a36Sopenharmony_ci .destructor = kfree, 69762306a36Sopenharmony_ci}; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic const struct devlink_port_region_ops mv88e6xxx_region_port_ops = { 70062306a36Sopenharmony_ci .name = "port", 70162306a36Sopenharmony_ci .snapshot = mv88e6xxx_region_port_snapshot, 70262306a36Sopenharmony_ci .destructor = kfree, 70362306a36Sopenharmony_ci}; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_cistruct mv88e6xxx_region { 70662306a36Sopenharmony_ci struct devlink_region_ops *ops; 70762306a36Sopenharmony_ci u64 size; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci bool (*cond)(struct mv88e6xxx_chip *chip); 71062306a36Sopenharmony_ci}; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_cistatic struct mv88e6xxx_region mv88e6xxx_regions[] = { 71362306a36Sopenharmony_ci [MV88E6XXX_REGION_GLOBAL1] = { 71462306a36Sopenharmony_ci .ops = &mv88e6xxx_region_global1_ops, 71562306a36Sopenharmony_ci .size = 32 * sizeof(u16) 71662306a36Sopenharmony_ci }, 71762306a36Sopenharmony_ci [MV88E6XXX_REGION_GLOBAL2] = { 71862306a36Sopenharmony_ci .ops = &mv88e6xxx_region_global2_ops, 71962306a36Sopenharmony_ci .size = 32 * sizeof(u16) }, 72062306a36Sopenharmony_ci [MV88E6XXX_REGION_ATU] = { 72162306a36Sopenharmony_ci .ops = &mv88e6xxx_region_atu_ops 72262306a36Sopenharmony_ci /* calculated at runtime */ 72362306a36Sopenharmony_ci }, 72462306a36Sopenharmony_ci [MV88E6XXX_REGION_VTU] = { 72562306a36Sopenharmony_ci .ops = &mv88e6xxx_region_vtu_ops 72662306a36Sopenharmony_ci /* calculated at runtime */ 72762306a36Sopenharmony_ci }, 72862306a36Sopenharmony_ci [MV88E6XXX_REGION_STU] = { 72962306a36Sopenharmony_ci .ops = &mv88e6xxx_region_stu_ops, 73062306a36Sopenharmony_ci .cond = mv88e6xxx_has_stu, 73162306a36Sopenharmony_ci /* calculated at runtime */ 73262306a36Sopenharmony_ci }, 73362306a36Sopenharmony_ci [MV88E6XXX_REGION_PVT] = { 73462306a36Sopenharmony_ci .ops = &mv88e6xxx_region_pvt_ops, 73562306a36Sopenharmony_ci .size = MV88E6XXX_MAX_PVT_ENTRIES * sizeof(u16), 73662306a36Sopenharmony_ci .cond = mv88e6xxx_has_pvt, 73762306a36Sopenharmony_ci }, 73862306a36Sopenharmony_ci}; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_civoid mv88e6xxx_teardown_devlink_regions_global(struct dsa_switch *ds) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 74362306a36Sopenharmony_ci int i; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++) 74662306a36Sopenharmony_ci dsa_devlink_region_destroy(chip->regions[i]); 74762306a36Sopenharmony_ci} 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_civoid mv88e6xxx_teardown_devlink_regions_port(struct dsa_switch *ds, int port) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci dsa_devlink_region_destroy(chip->ports[port].region); 75462306a36Sopenharmony_ci} 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ciint mv88e6xxx_setup_devlink_regions_port(struct dsa_switch *ds, int port) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 75962306a36Sopenharmony_ci struct devlink_region *region; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci region = dsa_devlink_port_region_create(ds, 76262306a36Sopenharmony_ci port, 76362306a36Sopenharmony_ci &mv88e6xxx_region_port_ops, 1, 76462306a36Sopenharmony_ci 32 * sizeof(u16)); 76562306a36Sopenharmony_ci if (IS_ERR(region)) 76662306a36Sopenharmony_ci return PTR_ERR(region); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci chip->ports[port].region = region; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci return 0; 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ciint mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds) 77462306a36Sopenharmony_ci{ 77562306a36Sopenharmony_ci bool (*cond)(struct mv88e6xxx_chip *chip); 77662306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 77762306a36Sopenharmony_ci struct devlink_region_ops *ops; 77862306a36Sopenharmony_ci struct devlink_region *region; 77962306a36Sopenharmony_ci u64 size; 78062306a36Sopenharmony_ci int i, j; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++) { 78362306a36Sopenharmony_ci ops = mv88e6xxx_regions[i].ops; 78462306a36Sopenharmony_ci size = mv88e6xxx_regions[i].size; 78562306a36Sopenharmony_ci cond = mv88e6xxx_regions[i].cond; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if (cond && !cond(chip)) 78862306a36Sopenharmony_ci continue; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci switch (i) { 79162306a36Sopenharmony_ci case MV88E6XXX_REGION_ATU: 79262306a36Sopenharmony_ci size = mv88e6xxx_num_databases(chip) * 79362306a36Sopenharmony_ci sizeof(struct mv88e6xxx_devlink_atu_entry); 79462306a36Sopenharmony_ci break; 79562306a36Sopenharmony_ci case MV88E6XXX_REGION_VTU: 79662306a36Sopenharmony_ci size = (mv88e6xxx_max_vid(chip) + 1) * 79762306a36Sopenharmony_ci sizeof(struct mv88e6xxx_devlink_vtu_entry); 79862306a36Sopenharmony_ci break; 79962306a36Sopenharmony_ci case MV88E6XXX_REGION_STU: 80062306a36Sopenharmony_ci size = (mv88e6xxx_max_sid(chip) + 1) * 80162306a36Sopenharmony_ci sizeof(struct mv88e6xxx_devlink_stu_entry); 80262306a36Sopenharmony_ci break; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci region = dsa_devlink_region_create(ds, ops, 1, size); 80662306a36Sopenharmony_ci if (IS_ERR(region)) 80762306a36Sopenharmony_ci goto out; 80862306a36Sopenharmony_ci chip->regions[i] = region; 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci return 0; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ciout: 81362306a36Sopenharmony_ci for (j = 0; j < i; j++) 81462306a36Sopenharmony_ci dsa_devlink_region_destroy(chip->regions[j]); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci return PTR_ERR(region); 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ciint mv88e6xxx_devlink_info_get(struct dsa_switch *ds, 82062306a36Sopenharmony_ci struct devlink_info_req *req, 82162306a36Sopenharmony_ci struct netlink_ext_ack *extack) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci struct mv88e6xxx_chip *chip = ds->priv; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci return devlink_info_version_fixed_put(req, 82662306a36Sopenharmony_ci DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, 82762306a36Sopenharmony_ci chip->info->name); 82862306a36Sopenharmony_ci} 829