From 65f60e4582bd321f4df1433a22f717f18e60f721 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 28 Mar 2018 23:50:28 +0200 Subject: [PATCH] net: dsa: mv88e6xxx: Keep ATU/VTU violation statistics Count the numbers of various ATU and VTU violation statistics and return them as part of the ethtool -S statistics. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 50 +++++++++++++++++++++---- drivers/net/dsa/mv88e6xxx/chip.h | 13 +++++-- drivers/net/dsa/mv88e6xxx/global1_atu.c | 12 ++++-- drivers/net/dsa/mv88e6xxx/global1_vtu.c | 8 ++-- drivers/net/dsa/mv88e6xxx/serdes.c | 15 +++++--- drivers/net/dsa/mv88e6xxx/serdes.h | 8 ++-- 6 files changed, 78 insertions(+), 28 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 9a5d786b4885..3d2091099f7f 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -723,6 +723,24 @@ static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip, STATS_TYPE_BANK0 | STATS_TYPE_BANK1); } +static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = { + "atu_member_violation", + "atu_miss_violation", + "atu_full_violation", + "vtu_member_violation", + "vtu_miss_violation", +}; + +static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++) + strlcpy(data + i * ETH_GSTRING_LEN, + mv88e6xxx_atu_vtu_stats_strings[i], + ETH_GSTRING_LEN); +} + static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, uint8_t *data) { @@ -736,9 +754,12 @@ static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, if (chip->info->ops->serdes_get_strings) { data += count * ETH_GSTRING_LEN; - chip->info->ops->serdes_get_strings(chip, port, data); + count = chip->info->ops->serdes_get_strings(chip, port, data); } + data += count * ETH_GSTRING_LEN; + mv88e6xxx_atu_vtu_get_strings(data); + mutex_unlock(&chip->reg_lock); } @@ -783,10 +804,13 @@ static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port) if (chip->info->ops->serdes_get_sset_count) serdes_count = chip->info->ops->serdes_get_sset_count(chip, port); - if (serdes_count < 0) + if (serdes_count < 0) { count = serdes_count; - else - count += serdes_count; + goto out; + } + count += serdes_count; + count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); + out: mutex_unlock(&chip->reg_lock); @@ -841,6 +865,16 @@ static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port, 0); } +static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port, + uint64_t *data) +{ + *data++ = chip->ports[port].atu_member_violation; + *data++ = chip->ports[port].atu_miss_violation; + *data++ = chip->ports[port].atu_full_violation; + *data++ = chip->ports[port].vtu_member_violation; + *data++ = chip->ports[port].vtu_miss_violation; +} + static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port, uint64_t *data) { @@ -849,12 +883,14 @@ static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port, if (chip->info->ops->stats_get_stats) count = chip->info->ops->stats_get_stats(chip, port, data); + mutex_lock(&chip->reg_lock); if (chip->info->ops->serdes_get_stats) { data += count; - mutex_lock(&chip->reg_lock); - chip->info->ops->serdes_get_stats(chip, port, data); - mutex_unlock(&chip->reg_lock); + count = chip->info->ops->serdes_get_stats(chip, port, data); } + data += count; + mv88e6xxx_atu_vtu_get_stats(chip, port, data); + mutex_unlock(&chip->reg_lock); } static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index bad211014e91..80490f66bc06 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -194,6 +194,11 @@ struct mv88e6xxx_port_hwtstamp { struct mv88e6xxx_port { u64 serdes_stats[2]; + u64 atu_member_violation; + u64 atu_miss_violation; + u64 atu_full_violation; + u64 vtu_member_violation; + u64 vtu_miss_violation; }; struct mv88e6xxx_chip { @@ -409,10 +414,10 @@ struct mv88e6xxx_ops { /* Statistics from the SERDES interface */ int (*serdes_get_sset_count)(struct mv88e6xxx_chip *chip, int port); - void (*serdes_get_strings)(struct mv88e6xxx_chip *chip, int port, - uint8_t *data); - void (*serdes_get_stats)(struct mv88e6xxx_chip *chip, int port, - uint64_t *data); + int (*serdes_get_strings)(struct mv88e6xxx_chip *chip, int port, + uint8_t *data); + int (*serdes_get_stats)(struct mv88e6xxx_chip *chip, int port, + uint64_t *data); /* VLAN Translation Unit operations */ int (*vtu_getnext)(struct mv88e6xxx_chip *chip, diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c index 20d941f4273b..307410898fc9 100644 --- a/drivers/net/dsa/mv88e6xxx/global1_atu.c +++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c @@ -336,8 +336,6 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id) if (err) goto out; - mutex_unlock(&chip->reg_lock); - if (val & MV88E6XXX_G1_ATU_OP_AGE_OUT_VIOLATION) { dev_err_ratelimited(chip->dev, "ATU age out violation for %pM\n", @@ -348,17 +346,23 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id) dev_err_ratelimited(chip->dev, "ATU member violation for %pM portvec %x\n", entry.mac, entry.portvec); + chip->ports[entry.portvec].atu_member_violation++; } - if (val & MV88E6XXX_G1_ATU_OP_MEMBER_VIOLATION) + if (val & MV88E6XXX_G1_ATU_OP_MEMBER_VIOLATION) { dev_err_ratelimited(chip->dev, "ATU miss violation for %pM portvec %x\n", entry.mac, entry.portvec); + chip->ports[entry.portvec].atu_miss_violation++; + } - if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION) + if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION) { dev_err_ratelimited(chip->dev, "ATU full violation for %pM portvec %x\n", entry.mac, entry.portvec); + chip->ports[entry.portvec].atu_full_violation++; + } + mutex_unlock(&chip->reg_lock); return IRQ_HANDLED; diff --git a/drivers/net/dsa/mv88e6xxx/global1_vtu.c b/drivers/net/dsa/mv88e6xxx/global1_vtu.c index 7997961647de..2cbaf946e7ed 100644 --- a/drivers/net/dsa/mv88e6xxx/global1_vtu.c +++ b/drivers/net/dsa/mv88e6xxx/global1_vtu.c @@ -539,18 +539,20 @@ static irqreturn_t mv88e6xxx_g1_vtu_prob_irq_thread_fn(int irq, void *dev_id) if (err) goto out; - mutex_unlock(&chip->reg_lock); - spid = val & MV88E6XXX_G1_VTU_OP_SPID_MASK; if (val & MV88E6XXX_G1_VTU_OP_MEMBER_VIOLATION) { dev_err_ratelimited(chip->dev, "VTU member violation for vid %d, source port %d\n", entry.vid, spid); + chip->ports[spid].vtu_member_violation++; } - if (val & MV88E6XXX_G1_VTU_OP_MISS_VIOLATION) + if (val & MV88E6XXX_G1_VTU_OP_MISS_VIOLATION) { dev_err_ratelimited(chip->dev, "VTU miss violation for vid %d, source port %d\n", entry.vid, spid); + chip->ports[spid].vtu_miss_violation++; + } + mutex_unlock(&chip->reg_lock); return IRQ_HANDLED; diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index b6166424216a..fb058fd35c0d 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -106,20 +106,21 @@ int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port) return 0; } -void mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, - int port, uint8_t *data) +int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, + int port, uint8_t *data) { struct mv88e6352_serdes_hw_stat *stat; int i; if (!mv88e6352_port_has_serdes(chip, port)) - return; + return 0; for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) { stat = &mv88e6352_serdes_hw_stats[i]; memcpy(data + i * ETH_GSTRING_LEN, stat->string, ETH_GSTRING_LEN); } + return ARRAY_SIZE(mv88e6352_serdes_hw_stats); } static uint64_t mv88e6352_serdes_get_stat(struct mv88e6xxx_chip *chip, @@ -149,8 +150,8 @@ static uint64_t mv88e6352_serdes_get_stat(struct mv88e6xxx_chip *chip, return val; } -void mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, - uint64_t *data) +int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, + uint64_t *data) { struct mv88e6xxx_port *mv88e6xxx_port = &chip->ports[port]; struct mv88e6352_serdes_hw_stat *stat; @@ -158,7 +159,7 @@ void mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, int i; if (!mv88e6352_port_has_serdes(chip, port)) - return; + return 0; BUILD_BUG_ON(ARRAY_SIZE(mv88e6352_serdes_hw_stats) > ARRAY_SIZE(mv88e6xxx_port->serdes_stats)); @@ -169,6 +170,8 @@ void mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, mv88e6xxx_port->serdes_stats[i] += value; data[i] = mv88e6xxx_port->serdes_stats[i]; } + + return ARRAY_SIZE(mv88e6352_serdes_hw_stats); } /* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */ diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h index 641baa75f910..1897c01c6e19 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.h +++ b/drivers/net/dsa/mv88e6xxx/serdes.h @@ -45,8 +45,8 @@ int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on); int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on); int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port); -void mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, - int port, uint8_t *data); -void mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, - uint64_t *data); +int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, + int port, uint8_t *data); +int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, + uint64_t *data); #endif -- 2.30.2