Commit e0c69ca7 authored by Andrew Lunn's avatar Andrew Lunn Committed by David S. Miller

net: dsa: mv88e6xxx: Add ATU occupancy via devlink resources

The ATU can report how many entries it contains. It does this per bin,
there being 4 bins in total. Export the ATU as a devlink resource, and
provide a method the needed callback to get the resource occupancy.
Signed-off-by: default avatarAndrew Lunn <andrew@lunn.ch>
Acked-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c5f299d5
...@@ -2720,9 +2720,179 @@ static void mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds) ...@@ -2720,9 +2720,179 @@ static void mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds)
ARRAY_SIZE(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;
}
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);
}
static 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 void mv88e6xxx_teardown(struct dsa_switch *ds) static void mv88e6xxx_teardown(struct dsa_switch *ds)
{ {
mv88e6xxx_teardown_devlink_params(ds); mv88e6xxx_teardown_devlink_params(ds);
dsa_devlink_resources_unregister(ds);
} }
static int mv88e6xxx_setup(struct dsa_switch *ds) static int mv88e6xxx_setup(struct dsa_switch *ds)
...@@ -2841,11 +3011,23 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) ...@@ -2841,11 +3011,23 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
unlock: unlock:
mv88e6xxx_reg_unlock(chip); mv88e6xxx_reg_unlock(chip);
/* Has to be called without holding the register lock, since if (err)
* it takes the devlink lock, and we later take the locks in return err;
* the reverse order when getting/setting parameters.
/* Have to be called without holding the register lock, since
* they take the devlink lock, and we later take the locks in
* the reverse order when getting/setting parameters or
* resource occupancy.
*/ */
return mv88e6xxx_setup_devlink_params(ds); err = mv88e6xxx_setup_devlink_resources(ds);
if (err)
return err;
err = mv88e6xxx_setup_devlink_params(ds);
if (err)
dsa_devlink_resources_unregister(ds);
return err;
} }
static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg) static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment