123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- #include <net/dsa.h>
- #include "chip.h"
- #include "devlink.h"
- #include "global1.h"
- #include "global2.h"
- #include "port.h"
- static int mv88e6xxx_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash)
- {
- if (chip->info->ops->atu_get_hash)
- return chip->info->ops->atu_get_hash(chip, hash);
- return -EOPNOTSUPP;
- }
- static int mv88e6xxx_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash)
- {
- if (chip->info->ops->atu_set_hash)
- return chip->info->ops->atu_set_hash(chip, hash);
- return -EOPNOTSUPP;
- }
- enum mv88e6xxx_devlink_param_id {
- MV88E6XXX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
- MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
- };
- int mv88e6xxx_devlink_param_get(struct dsa_switch *ds, u32 id,
- struct devlink_param_gset_ctx *ctx)
- {
- struct mv88e6xxx_chip *chip = ds->priv;
- int err;
- mv88e6xxx_reg_lock(chip);
- switch (id) {
- case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
- err = mv88e6xxx_atu_get_hash(chip, &ctx->val.vu8);
- break;
- default:
- err = -EOPNOTSUPP;
- break;
- }
- mv88e6xxx_reg_unlock(chip);
- return err;
- }
- int mv88e6xxx_devlink_param_set(struct dsa_switch *ds, u32 id,
- struct devlink_param_gset_ctx *ctx)
- {
- struct mv88e6xxx_chip *chip = ds->priv;
- int err;
- mv88e6xxx_reg_lock(chip);
- switch (id) {
- case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
- err = mv88e6xxx_atu_set_hash(chip, ctx->val.vu8);
- break;
- default:
- err = -EOPNOTSUPP;
- break;
- }
- mv88e6xxx_reg_unlock(chip);
- return err;
- }
- static const struct devlink_param mv88e6xxx_devlink_params[] = {
- DSA_DEVLINK_PARAM_DRIVER(MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
- "ATU_hash", DEVLINK_PARAM_TYPE_U8,
- BIT(DEVLINK_PARAM_CMODE_RUNTIME)),
- };
- int mv88e6xxx_setup_devlink_params(struct dsa_switch *ds)
- {
- return dsa_devlink_params_register(ds, mv88e6xxx_devlink_params,
- ARRAY_SIZE(mv88e6xxx_devlink_params));
- }
- void mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds)
- {
- dsa_devlink_params_unregister(ds, mv88e6xxx_devlink_params,
- ARRAY_SIZE(mv88e6xxx_devlink_params));
- }
- enum mv88e6xxx_devlink_resource_id {
- MV88E6XXX_RESOURCE_ID_ATU,
- MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
- MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
- MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
- MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
- };
- static u64 mv88e6xxx_devlink_atu_bin_get(struct mv88e6xxx_chip *chip,
- u16 bin)
- {
- u16 occupancy = 0;
- int err;
- mv88e6xxx_reg_lock(chip);
- err = mv88e6xxx_g2_atu_stats_set(chip, MV88E6XXX_G2_ATU_STATS_MODE_ALL,
- bin);
- if (err) {
- dev_err(chip->dev, "failed to set ATU stats kind/bin\n");
- goto unlock;
- }
- err = mv88e6xxx_g1_atu_get_next(chip, 0);
- if (err) {
- dev_err(chip->dev, "failed to perform ATU get next\n");
- goto unlock;
- }
- err = mv88e6xxx_g2_atu_stats_get(chip, &occupancy);
- if (err) {
- dev_err(chip->dev, "failed to get ATU stats\n");
- goto unlock;
- }
- occupancy &= MV88E6XXX_G2_ATU_STATS_MASK;
- unlock:
- mv88e6xxx_reg_unlock(chip);
- return occupancy;
- }
- static u64 mv88e6xxx_devlink_atu_bin_0_get(void *priv)
- {
- struct mv88e6xxx_chip *chip = priv;
- return mv88e6xxx_devlink_atu_bin_get(chip,
- MV88E6XXX_G2_ATU_STATS_BIN_0);
- }
- static u64 mv88e6xxx_devlink_atu_bin_1_get(void *priv)
- {
- struct mv88e6xxx_chip *chip = priv;
- return mv88e6xxx_devlink_atu_bin_get(chip,
- MV88E6XXX_G2_ATU_STATS_BIN_1);
- }
- static u64 mv88e6xxx_devlink_atu_bin_2_get(void *priv)
- {
- struct mv88e6xxx_chip *chip = priv;
- return mv88e6xxx_devlink_atu_bin_get(chip,
- MV88E6XXX_G2_ATU_STATS_BIN_2);
- }
- static u64 mv88e6xxx_devlink_atu_bin_3_get(void *priv)
- {
- struct mv88e6xxx_chip *chip = priv;
- return mv88e6xxx_devlink_atu_bin_get(chip,
- MV88E6XXX_G2_ATU_STATS_BIN_3);
- }
- static u64 mv88e6xxx_devlink_atu_get(void *priv)
- {
- return mv88e6xxx_devlink_atu_bin_0_get(priv) +
- mv88e6xxx_devlink_atu_bin_1_get(priv) +
- mv88e6xxx_devlink_atu_bin_2_get(priv) +
- mv88e6xxx_devlink_atu_bin_3_get(priv);
- }
- int mv88e6xxx_setup_devlink_resources(struct dsa_switch *ds)
- {
- struct devlink_resource_size_params size_params;
- struct mv88e6xxx_chip *chip = ds->priv;
- int err;
- devlink_resource_size_params_init(&size_params,
- mv88e6xxx_num_macs(chip),
- mv88e6xxx_num_macs(chip),
- 1, DEVLINK_RESOURCE_UNIT_ENTRY);
- err = dsa_devlink_resource_register(ds, "ATU",
- mv88e6xxx_num_macs(chip),
- MV88E6XXX_RESOURCE_ID_ATU,
- DEVLINK_RESOURCE_ID_PARENT_TOP,
- &size_params);
- if (err)
- goto out;
- devlink_resource_size_params_init(&size_params,
- mv88e6xxx_num_macs(chip) / 4,
- mv88e6xxx_num_macs(chip) / 4,
- 1, DEVLINK_RESOURCE_UNIT_ENTRY);
- err = dsa_devlink_resource_register(ds, "ATU_bin_0",
- mv88e6xxx_num_macs(chip) / 4,
- MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
- MV88E6XXX_RESOURCE_ID_ATU,
- &size_params);
- if (err)
- goto out;
- err = dsa_devlink_resource_register(ds, "ATU_bin_1",
- mv88e6xxx_num_macs(chip) / 4,
- MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
- MV88E6XXX_RESOURCE_ID_ATU,
- &size_params);
- if (err)
- goto out;
- err = dsa_devlink_resource_register(ds, "ATU_bin_2",
- mv88e6xxx_num_macs(chip) / 4,
- MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
- MV88E6XXX_RESOURCE_ID_ATU,
- &size_params);
- if (err)
- goto out;
- err = dsa_devlink_resource_register(ds, "ATU_bin_3",
- mv88e6xxx_num_macs(chip) / 4,
- MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
- MV88E6XXX_RESOURCE_ID_ATU,
- &size_params);
- if (err)
- goto out;
- dsa_devlink_resource_occ_get_register(ds,
- MV88E6XXX_RESOURCE_ID_ATU,
- mv88e6xxx_devlink_atu_get,
- chip);
- dsa_devlink_resource_occ_get_register(ds,
- MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
- mv88e6xxx_devlink_atu_bin_0_get,
- chip);
- dsa_devlink_resource_occ_get_register(ds,
- MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
- mv88e6xxx_devlink_atu_bin_1_get,
- chip);
- dsa_devlink_resource_occ_get_register(ds,
- MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
- mv88e6xxx_devlink_atu_bin_2_get,
- chip);
- dsa_devlink_resource_occ_get_register(ds,
- MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
- mv88e6xxx_devlink_atu_bin_3_get,
- chip);
- return 0;
- out:
- dsa_devlink_resources_unregister(ds);
- return err;
- }
- static int mv88e6xxx_region_global_snapshot(struct devlink *dl,
- const struct devlink_region_ops *ops,
- struct netlink_ext_ack *extack,
- u8 **data)
- {
- struct mv88e6xxx_region_priv *region_priv = ops->priv;
- struct dsa_switch *ds = dsa_devlink_to_ds(dl);
- struct mv88e6xxx_chip *chip = ds->priv;
- u16 *registers;
- int i, err;
- registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);
- if (!registers)
- return -ENOMEM;
- mv88e6xxx_reg_lock(chip);
- for (i = 0; i < 32; i++) {
- switch (region_priv->id) {
- case MV88E6XXX_REGION_GLOBAL1:
- err = mv88e6xxx_g1_read(chip, i, ®isters[i]);
- break;
- case MV88E6XXX_REGION_GLOBAL2:
- err = mv88e6xxx_g2_read(chip, i, ®isters[i]);
- break;
- default:
- err = -EOPNOTSUPP;
- }
- if (err) {
- kfree(registers);
- goto out;
- }
- }
- *data = (u8 *)registers;
- out:
- mv88e6xxx_reg_unlock(chip);
- return err;
- }
- /* The ATU entry varies between mv88e6xxx chipset generations. Define
- * a generic format which covers all the current and hopefully future
- * mv88e6xxx generations
- */
- struct mv88e6xxx_devlink_atu_entry {
- /* The FID is scattered over multiple registers. */
- u16 fid;
- u16 atu_op;
- u16 atu_data;
- u16 atu_01;
- u16 atu_23;
- u16 atu_45;
- };
- static int mv88e6xxx_region_atu_snapshot_fid(struct mv88e6xxx_chip *chip,
- int fid,
- struct mv88e6xxx_devlink_atu_entry *table,
- int *count)
- {
- u16 atu_op, atu_data, atu_01, atu_23, atu_45;
- struct mv88e6xxx_atu_entry addr;
- int err;
- addr.state = 0;
- eth_broadcast_addr(addr.mac);
- do {
- err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
- if (err)
- return err;
- if (!addr.state)
- break;
- err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &atu_op);
- if (err)
- return err;
- err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_DATA, &atu_data);
- if (err)
- return err;
- err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC01, &atu_01);
- if (err)
- return err;
- err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC23, &atu_23);
- if (err)
- return err;
- err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC45, &atu_45);
- if (err)
- return err;
- table[*count].fid = fid;
- table[*count].atu_op = atu_op;
- table[*count].atu_data = atu_data;
- table[*count].atu_01 = atu_01;
- table[*count].atu_23 = atu_23;
- table[*count].atu_45 = atu_45;
- (*count)++;
- } while (!is_broadcast_ether_addr(addr.mac));
- return 0;
- }
- static int mv88e6xxx_region_atu_snapshot(struct devlink *dl,
- const struct devlink_region_ops *ops,
- struct netlink_ext_ack *extack,
- u8 **data)
- {
- struct dsa_switch *ds = dsa_devlink_to_ds(dl);
- DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
- struct mv88e6xxx_devlink_atu_entry *table;
- struct mv88e6xxx_chip *chip = ds->priv;
- int fid = -1, count, err;
- table = kmalloc_array(mv88e6xxx_num_databases(chip),
- sizeof(struct mv88e6xxx_devlink_atu_entry),
- GFP_KERNEL);
- if (!table)
- return -ENOMEM;
- memset(table, 0, mv88e6xxx_num_databases(chip) *
- sizeof(struct mv88e6xxx_devlink_atu_entry));
- count = 0;
- mv88e6xxx_reg_lock(chip);
- err = mv88e6xxx_fid_map(chip, fid_bitmap);
- if (err) {
- kfree(table);
- goto out;
- }
- while (1) {
- fid = find_next_bit(fid_bitmap, MV88E6XXX_N_FID, fid + 1);
- if (fid == MV88E6XXX_N_FID)
- break;
- err = mv88e6xxx_region_atu_snapshot_fid(chip, fid, table,
- &count);
- if (err) {
- kfree(table);
- goto out;
- }
- }
- *data = (u8 *)table;
- out:
- mv88e6xxx_reg_unlock(chip);
- return err;
- }
- /**
- * struct mv88e6xxx_devlink_vtu_entry - Devlink VTU entry
- * @fid: Global1/2: FID and VLAN policy.
- * @sid: Global1/3: SID, unknown filters and learning.
- * @op: Global1/5: FID (old chipsets).
- * @vid: Global1/6: VID, valid, and page.
- * @data: Global1/7-9: Membership data and priority override.
- * @resvd: Reserved. Also happens to align the size to 16B.
- *
- * The VTU entry format varies between chipset generations, the
- * descriptions above represent the superset of all possible
- * information, not all fields are valid on all devices. Since this is
- * a low-level debug interface, copy all data verbatim and defer
- * parsing to the consumer.
- */
- struct mv88e6xxx_devlink_vtu_entry {
- u16 fid;
- u16 sid;
- u16 op;
- u16 vid;
- u16 data[3];
- u16 resvd;
- };
- static int mv88e6xxx_region_vtu_snapshot(struct devlink *dl,
- const struct devlink_region_ops *ops,
- struct netlink_ext_ack *extack,
- u8 **data)
- {
- struct mv88e6xxx_devlink_vtu_entry *table, *entry;
- struct dsa_switch *ds = dsa_devlink_to_ds(dl);
- struct mv88e6xxx_chip *chip = ds->priv;
- struct mv88e6xxx_vtu_entry vlan;
- int err;
- table = kcalloc(mv88e6xxx_max_vid(chip) + 1,
- sizeof(struct mv88e6xxx_devlink_vtu_entry),
- GFP_KERNEL);
- if (!table)
- return -ENOMEM;
- entry = table;
- vlan.vid = mv88e6xxx_max_vid(chip);
- vlan.valid = false;
- mv88e6xxx_reg_lock(chip);
- do {
- err = mv88e6xxx_g1_vtu_getnext(chip, &vlan);
- if (err)
- break;
- if (!vlan.valid)
- break;
- err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_FID,
- &entry->fid);
- err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,
- &entry->sid);
- err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP,
- &entry->op);
- err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,
- &entry->vid);
- err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,
- &entry->data[0]);
- err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,
- &entry->data[1]);
- err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,
- &entry->data[2]);
- if (err)
- break;
- entry++;
- } while (vlan.vid < mv88e6xxx_max_vid(chip));
- mv88e6xxx_reg_unlock(chip);
- if (err) {
- kfree(table);
- return err;
- }
- *data = (u8 *)table;
- return 0;
- }
- /**
- * struct mv88e6xxx_devlink_stu_entry - Devlink STU entry
- * @sid: Global1/3: SID, unknown filters and learning.
- * @vid: Global1/6: Valid bit.
- * @data: Global1/7-9: Membership data and priority override.
- * @resvd: Reserved. In case we forgot something.
- *
- * The STU entry format varies between chipset generations. Peridot
- * and Amethyst packs the STU data into Global1/7-8. Older silicon
- * spreads the information across all three VTU data registers -
- * inheriting the layout of even older hardware that had no STU at
- * all. Since this is a low-level debug interface, copy all data
- * verbatim and defer parsing to the consumer.
- */
- struct mv88e6xxx_devlink_stu_entry {
- u16 sid;
- u16 vid;
- u16 data[3];
- u16 resvd;
- };
- static int mv88e6xxx_region_stu_snapshot(struct devlink *dl,
- const struct devlink_region_ops *ops,
- struct netlink_ext_ack *extack,
- u8 **data)
- {
- struct mv88e6xxx_devlink_stu_entry *table, *entry;
- struct dsa_switch *ds = dsa_devlink_to_ds(dl);
- struct mv88e6xxx_chip *chip = ds->priv;
- struct mv88e6xxx_stu_entry stu;
- int err;
- table = kcalloc(mv88e6xxx_max_sid(chip) + 1,
- sizeof(struct mv88e6xxx_devlink_stu_entry),
- GFP_KERNEL);
- if (!table)
- return -ENOMEM;
- entry = table;
- stu.sid = mv88e6xxx_max_sid(chip);
- stu.valid = false;
- mv88e6xxx_reg_lock(chip);
- do {
- err = mv88e6xxx_g1_stu_getnext(chip, &stu);
- if (err)
- break;
- if (!stu.valid)
- break;
- err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,
- &entry->sid);
- err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,
- &entry->vid);
- err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,
- &entry->data[0]);
- err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,
- &entry->data[1]);
- err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,
- &entry->data[2]);
- if (err)
- break;
- entry++;
- } while (stu.sid < mv88e6xxx_max_sid(chip));
- mv88e6xxx_reg_unlock(chip);
- if (err) {
- kfree(table);
- return err;
- }
- *data = (u8 *)table;
- return 0;
- }
- static int mv88e6xxx_region_pvt_snapshot(struct devlink *dl,
- const struct devlink_region_ops *ops,
- struct netlink_ext_ack *extack,
- u8 **data)
- {
- struct dsa_switch *ds = dsa_devlink_to_ds(dl);
- struct mv88e6xxx_chip *chip = ds->priv;
- int dev, port, err;
- u16 *pvt, *cur;
- pvt = kcalloc(MV88E6XXX_MAX_PVT_ENTRIES, sizeof(*pvt), GFP_KERNEL);
- if (!pvt)
- return -ENOMEM;
- mv88e6xxx_reg_lock(chip);
- cur = pvt;
- for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; dev++) {
- for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; port++) {
- err = mv88e6xxx_g2_pvt_read(chip, dev, port, cur);
- if (err)
- break;
- cur++;
- }
- }
- mv88e6xxx_reg_unlock(chip);
- if (err) {
- kfree(pvt);
- return err;
- }
- *data = (u8 *)pvt;
- return 0;
- }
- static int mv88e6xxx_region_port_snapshot(struct devlink_port *devlink_port,
- const struct devlink_port_region_ops *ops,
- struct netlink_ext_ack *extack,
- u8 **data)
- {
- struct dsa_switch *ds = dsa_devlink_port_to_ds(devlink_port);
- int port = dsa_devlink_port_to_port(devlink_port);
- struct mv88e6xxx_chip *chip = ds->priv;
- u16 *registers;
- int i, err;
- registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);
- if (!registers)
- return -ENOMEM;
- mv88e6xxx_reg_lock(chip);
- for (i = 0; i < 32; i++) {
- err = mv88e6xxx_port_read(chip, port, i, ®isters[i]);
- if (err) {
- kfree(registers);
- goto out;
- }
- }
- *data = (u8 *)registers;
- out:
- mv88e6xxx_reg_unlock(chip);
- return err;
- }
- static struct mv88e6xxx_region_priv mv88e6xxx_region_global1_priv = {
- .id = MV88E6XXX_REGION_GLOBAL1,
- };
- static struct devlink_region_ops mv88e6xxx_region_global1_ops = {
- .name = "global1",
- .snapshot = mv88e6xxx_region_global_snapshot,
- .destructor = kfree,
- .priv = &mv88e6xxx_region_global1_priv,
- };
- static struct mv88e6xxx_region_priv mv88e6xxx_region_global2_priv = {
- .id = MV88E6XXX_REGION_GLOBAL2,
- };
- static struct devlink_region_ops mv88e6xxx_region_global2_ops = {
- .name = "global2",
- .snapshot = mv88e6xxx_region_global_snapshot,
- .destructor = kfree,
- .priv = &mv88e6xxx_region_global2_priv,
- };
- static struct devlink_region_ops mv88e6xxx_region_atu_ops = {
- .name = "atu",
- .snapshot = mv88e6xxx_region_atu_snapshot,
- .destructor = kfree,
- };
- static struct devlink_region_ops mv88e6xxx_region_vtu_ops = {
- .name = "vtu",
- .snapshot = mv88e6xxx_region_vtu_snapshot,
- .destructor = kfree,
- };
- static struct devlink_region_ops mv88e6xxx_region_stu_ops = {
- .name = "stu",
- .snapshot = mv88e6xxx_region_stu_snapshot,
- .destructor = kfree,
- };
- static struct devlink_region_ops mv88e6xxx_region_pvt_ops = {
- .name = "pvt",
- .snapshot = mv88e6xxx_region_pvt_snapshot,
- .destructor = kfree,
- };
- static const struct devlink_port_region_ops mv88e6xxx_region_port_ops = {
- .name = "port",
- .snapshot = mv88e6xxx_region_port_snapshot,
- .destructor = kfree,
- };
- struct mv88e6xxx_region {
- struct devlink_region_ops *ops;
- u64 size;
- bool (*cond)(struct mv88e6xxx_chip *chip);
- };
- static struct mv88e6xxx_region mv88e6xxx_regions[] = {
- [MV88E6XXX_REGION_GLOBAL1] = {
- .ops = &mv88e6xxx_region_global1_ops,
- .size = 32 * sizeof(u16)
- },
- [MV88E6XXX_REGION_GLOBAL2] = {
- .ops = &mv88e6xxx_region_global2_ops,
- .size = 32 * sizeof(u16) },
- [MV88E6XXX_REGION_ATU] = {
- .ops = &mv88e6xxx_region_atu_ops
- /* calculated at runtime */
- },
- [MV88E6XXX_REGION_VTU] = {
- .ops = &mv88e6xxx_region_vtu_ops
- /* calculated at runtime */
- },
- [MV88E6XXX_REGION_STU] = {
- .ops = &mv88e6xxx_region_stu_ops,
- .cond = mv88e6xxx_has_stu,
- /* calculated at runtime */
- },
- [MV88E6XXX_REGION_PVT] = {
- .ops = &mv88e6xxx_region_pvt_ops,
- .size = MV88E6XXX_MAX_PVT_ENTRIES * sizeof(u16),
- .cond = mv88e6xxx_has_pvt,
- },
- };
- void mv88e6xxx_teardown_devlink_regions_global(struct dsa_switch *ds)
- {
- struct mv88e6xxx_chip *chip = ds->priv;
- int i;
- for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++)
- dsa_devlink_region_destroy(chip->regions[i]);
- }
- void mv88e6xxx_teardown_devlink_regions_port(struct dsa_switch *ds, int port)
- {
- struct mv88e6xxx_chip *chip = ds->priv;
- dsa_devlink_region_destroy(chip->ports[port].region);
- }
- int mv88e6xxx_setup_devlink_regions_port(struct dsa_switch *ds, int port)
- {
- struct mv88e6xxx_chip *chip = ds->priv;
- struct devlink_region *region;
- region = dsa_devlink_port_region_create(ds,
- port,
- &mv88e6xxx_region_port_ops, 1,
- 32 * sizeof(u16));
- if (IS_ERR(region))
- return PTR_ERR(region);
- chip->ports[port].region = region;
- return 0;
- }
- int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds)
- {
- bool (*cond)(struct mv88e6xxx_chip *chip);
- struct mv88e6xxx_chip *chip = ds->priv;
- struct devlink_region_ops *ops;
- struct devlink_region *region;
- u64 size;
- int i, j;
- for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++) {
- ops = mv88e6xxx_regions[i].ops;
- size = mv88e6xxx_regions[i].size;
- cond = mv88e6xxx_regions[i].cond;
- if (cond && !cond(chip))
- continue;
- switch (i) {
- case MV88E6XXX_REGION_ATU:
- size = mv88e6xxx_num_databases(chip) *
- sizeof(struct mv88e6xxx_devlink_atu_entry);
- break;
- case MV88E6XXX_REGION_VTU:
- size = (mv88e6xxx_max_vid(chip) + 1) *
- sizeof(struct mv88e6xxx_devlink_vtu_entry);
- break;
- case MV88E6XXX_REGION_STU:
- size = (mv88e6xxx_max_sid(chip) + 1) *
- sizeof(struct mv88e6xxx_devlink_stu_entry);
- break;
- }
- region = dsa_devlink_region_create(ds, ops, 1, size);
- if (IS_ERR(region))
- goto out;
- chip->regions[i] = region;
- }
- return 0;
- out:
- for (j = 0; j < i; j++)
- dsa_devlink_region_destroy(chip->regions[j]);
- return PTR_ERR(region);
- }
- int mv88e6xxx_devlink_info_get(struct dsa_switch *ds,
- struct devlink_info_req *req,
- struct netlink_ext_ack *extack)
- {
- struct mv88e6xxx_chip *chip = ds->priv;
- int err;
- err = devlink_info_driver_name_put(req, "mv88e6xxx");
- if (err)
- return err;
- return devlink_info_version_fixed_put(req,
- DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
- chip->info->name);
- }
|