diff options
Diffstat (limited to 'drivers/net/dsa/mv88e6xxx/devlink.c')
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/devlink.c | 58 |
1 files changed, 57 insertions, 1 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/devlink.c b/drivers/net/dsa/mv88e6xxx/devlink.c index 21953d6d484c..0c0f5ea6680c 100644 --- a/drivers/net/dsa/mv88e6xxx/devlink.c +++ b/drivers/net/dsa/mv88e6xxx/devlink.c @@ -503,6 +503,44 @@ static int mv88e6xxx_region_vtu_snapshot(struct devlink *dl, 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, @@ -567,6 +605,12 @@ static struct devlink_region_ops mv88e6xxx_region_vtu_ops = { .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, @@ -576,6 +620,8 @@ static const struct devlink_port_region_ops mv88e6xxx_region_port_ops = { struct mv88e6xxx_region { struct devlink_region_ops *ops; u64 size; + + bool (*cond)(struct mv88e6xxx_chip *chip); }; static struct mv88e6xxx_region mv88e6xxx_regions[] = { @@ -594,6 +640,11 @@ static struct mv88e6xxx_region mv88e6xxx_regions[] = { .ops = &mv88e6xxx_region_vtu_ops /* calculated at runtime */ }, + [MV88E6XXX_REGION_PVT] = { + .ops = &mv88e6xxx_region_pvt_ops, + .size = MV88E6XXX_MAX_PVT_ENTRIES * sizeof(u16), + .cond = mv88e6xxx_has_pvt, + }, }; static void @@ -663,6 +714,7 @@ out: static int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds, struct mv88e6xxx_chip *chip) { + bool (*cond)(struct mv88e6xxx_chip *chip); struct devlink_region_ops *ops; struct devlink_region *region; u64 size; @@ -671,6 +723,10 @@ static int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds, 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: @@ -678,7 +734,7 @@ static int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds, sizeof(struct mv88e6xxx_devlink_atu_entry); break; case MV88E6XXX_REGION_VTU: - size = mv88e6xxx_max_vid(chip) * + size = (mv88e6xxx_max_vid(chip) + 1) * sizeof(struct mv88e6xxx_devlink_vtu_entry); break; } |