OSDN Git Service

net: dsa: bcm_sf2: Add support for CFP statistics
authorFlorian Fainelli <f.fainelli@gmail.com>
Wed, 6 Feb 2019 20:45:59 +0000 (12:45 -0800)
committerDavid S. Miller <davem@davemloft.net>
Sat, 9 Feb 2019 06:11:07 +0000 (22:11 -0800)
Return CFP policer statistics (Green, Yellow or Red) as part of the
standard ethtool statistics. This helps debug when CFP rules may not be
hit (0 counter).

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/bcm_sf2.c
drivers/net/dsa/bcm_sf2.h
drivers/net/dsa/bcm_sf2_cfp.c
drivers/net/dsa/bcm_sf2_regs.h

index ce5f426..5193da6 100644 (file)
@@ -897,19 +897,33 @@ static const struct b53_io_ops bcm_sf2_io_ops = {
 static void bcm_sf2_sw_get_strings(struct dsa_switch *ds, int port,
                                   u32 stringset, uint8_t *data)
 {
+       int cnt = b53_get_sset_count(ds, port, stringset);
+
        b53_get_strings(ds, port, stringset, data);
+       bcm_sf2_cfp_get_strings(ds, port, stringset,
+                               data + cnt * ETH_GSTRING_LEN);
 }
 
 static void bcm_sf2_sw_get_ethtool_stats(struct dsa_switch *ds, int port,
                                         uint64_t *data)
 {
+       int cnt = b53_get_sset_count(ds, port, ETH_SS_STATS);
+
        b53_get_ethtool_stats(ds, port, data);
+       bcm_sf2_cfp_get_ethtool_stats(ds, port, data + cnt);
 }
 
 static int bcm_sf2_sw_get_sset_count(struct dsa_switch *ds, int port,
                                     int sset)
 {
-       return b53_get_sset_count(ds, port, sset);
+       int cnt = b53_get_sset_count(ds, port, sset);
+
+       if (cnt < 0)
+               return cnt;
+
+       cnt += bcm_sf2_cfp_get_sset_count(ds, port, sset);
+
+       return cnt;
 }
 
 static const struct dsa_switch_ops bcm_sf2_ops = {
index 83e1d80..eb3655b 100644 (file)
@@ -213,5 +213,10 @@ int bcm_sf2_set_rxnfc(struct dsa_switch *ds, int port,
 int bcm_sf2_cfp_rst(struct bcm_sf2_priv *priv);
 void bcm_sf2_cfp_exit(struct dsa_switch *ds);
 int bcm_sf2_cfp_resume(struct dsa_switch *ds);
+void bcm_sf2_cfp_get_strings(struct dsa_switch *ds, int port,
+                            u32 stringset, uint8_t *data);
+void bcm_sf2_cfp_get_ethtool_stats(struct dsa_switch *ds, int port,
+                                  uint64_t *data);
+int bcm_sf2_cfp_get_sset_count(struct dsa_switch *ds, int port, int sset);
 
 #endif /* __BCM_SF2_H */
index 6d8059d..8747d18 100644 (file)
@@ -1201,3 +1201,91 @@ int bcm_sf2_cfp_resume(struct dsa_switch *ds)
 
        return ret;
 }
+
+static const struct bcm_sf2_cfp_stat {
+       unsigned int offset;
+       unsigned int ram_loc;
+       const char *name;
+} bcm_sf2_cfp_stats[] = {
+       {
+               .offset = CORE_STAT_GREEN_CNTR,
+               .ram_loc = GREEN_STAT_RAM,
+               .name = "Green"
+       },
+       {
+               .offset = CORE_STAT_YELLOW_CNTR,
+               .ram_loc = YELLOW_STAT_RAM,
+               .name = "Yellow"
+       },
+       {
+               .offset = CORE_STAT_RED_CNTR,
+               .ram_loc = RED_STAT_RAM,
+               .name = "Red"
+       },
+};
+
+void bcm_sf2_cfp_get_strings(struct dsa_switch *ds, int port,
+                            u32 stringset, uint8_t *data)
+{
+       struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
+       unsigned int s = ARRAY_SIZE(bcm_sf2_cfp_stats);
+       char buf[ETH_GSTRING_LEN];
+       unsigned int i, j, iter;
+
+       if (stringset != ETH_SS_STATS)
+               return;
+
+       for (i = 1; i < priv->num_cfp_rules; i++) {
+               for (j = 0; j < s; j++) {
+                       snprintf(buf, sizeof(buf),
+                                "CFP%03d_%sCntr",
+                                i, bcm_sf2_cfp_stats[j].name);
+                       iter = (i - 1) * s + j;
+                       strlcpy(data + iter * ETH_GSTRING_LEN,
+                               buf, ETH_GSTRING_LEN);
+               }
+       }
+}
+
+void bcm_sf2_cfp_get_ethtool_stats(struct dsa_switch *ds, int port,
+                                  uint64_t *data)
+{
+       struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
+       unsigned int s = ARRAY_SIZE(bcm_sf2_cfp_stats);
+       const struct bcm_sf2_cfp_stat *stat;
+       unsigned int i, j, iter;
+       struct cfp_rule *rule;
+       int ret;
+
+       mutex_lock(&priv->cfp.lock);
+       for (i = 1; i < priv->num_cfp_rules; i++) {
+               rule = bcm_sf2_cfp_rule_find(priv, port, i);
+               if (!rule)
+                       continue;
+
+               for (j = 0; j < s; j++) {
+                       stat = &bcm_sf2_cfp_stats[j];
+
+                       bcm_sf2_cfp_rule_addr_set(priv, i);
+                       ret = bcm_sf2_cfp_op(priv, stat->ram_loc | OP_SEL_READ);
+                       if (ret)
+                               continue;
+
+                       iter = (i - 1) * s + j;
+                       data[iter] = core_readl(priv, stat->offset);
+               }
+
+       }
+       mutex_unlock(&priv->cfp.lock);
+}
+
+int bcm_sf2_cfp_get_sset_count(struct dsa_switch *ds, int port, int sset)
+{
+       struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
+
+       if (sset != ETH_SS_STATS)
+               return 0;
+
+       /* 3 counters per CFP rules */
+       return (priv->num_cfp_rules - 1) * ARRAY_SIZE(bcm_sf2_cfp_stats);
+}
index 0a1e530..67f0562 100644 (file)
@@ -400,6 +400,10 @@ enum bcm_sf2_reg_offs {
 #define CORE_RATE_METER6               0x281e0
 #define  CIR_REF_CNT_MASK              0x7ffff
 
+#define CORE_STAT_GREEN_CNTR           0x28200
+#define CORE_STAT_YELLOW_CNTR          0x28210
+#define CORE_STAT_RED_CNTR             0x28220
+
 #define CORE_CFP_CTL_REG               0x28400
 #define  CFP_EN_MAP_MASK               0x1ff