OSDN Git Service

Merge branch 'net-dsa-bcm_sf2-Add-support-for-CFP-statistics'
authorDavid S. Miller <davem@davemloft.net>
Sat, 9 Feb 2019 06:11:07 +0000 (22:11 -0800)
committerDavid S. Miller <davem@davemloft.net>
Sat, 9 Feb 2019 06:11:07 +0000 (22:11 -0800)
Florian Fainelli says:

====================
net: dsa: bcm_sf2: Add support for CFP statistics

The Broadcom SF2 switch has a Compact Field Processor (CFP) which not
only can perform matching + action, but also counts the number of times
a rule has been hit. This is invaluable while debugging when/if rules
are not matched.
====================

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 361fbde..5193da6 100644 (file)
@@ -894,12 +894,44 @@ static const struct b53_io_ops bcm_sf2_io_ops = {
        .write64 = bcm_sf2_core_write64,
 };
 
+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)
+{
+       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 = {
        .get_tag_protocol       = b53_get_tag_protocol,
        .setup                  = bcm_sf2_sw_setup,
-       .get_strings            = b53_get_strings,
-       .get_ethtool_stats      = b53_get_ethtool_stats,
-       .get_sset_count         = b53_get_sset_count,
+       .get_strings            = bcm_sf2_sw_get_strings,
+       .get_ethtool_stats      = bcm_sf2_sw_get_ethtool_stats,
+       .get_sset_count         = bcm_sf2_sw_get_sset_count,
        .get_ethtool_phy_stats  = b53_get_ethtool_phy_stats,
        .get_phy_flags          = bcm_sf2_sw_get_phy_flags,
        .phylink_validate       = bcm_sf2_sw_validate,
@@ -1062,7 +1094,6 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev)
        dev_set_drvdata(&pdev->dev, priv);
 
        spin_lock_init(&priv->indir_lock);
-       mutex_init(&priv->stats_mutex);
        mutex_init(&priv->cfp.lock);
        INIT_LIST_HEAD(&priv->cfp.rules_list);
 
index faaef32..eb3655b 100644 (file)
@@ -87,9 +87,6 @@ struct bcm_sf2_priv {
        /* Backing b53_device */
        struct b53_device               *dev;
 
-       /* Mutex protecting access to the MIB counters */
-       struct mutex                    stats_mutex;
-
        struct bcm_sf2_hw_params        hw_params;
 
        struct bcm_sf2_port_status      port_sts[DSA_MAX_PORTS];
@@ -216,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..0b9ca4b 100644 (file)
@@ -213,6 +213,7 @@ static inline unsigned int bcm_sf2_cfp_rule_size(struct bcm_sf2_priv *priv)
 
 static int bcm_sf2_cfp_act_pol_set(struct bcm_sf2_priv *priv,
                                   unsigned int rule_index,
+                                  int src_port,
                                   unsigned int port_num,
                                   unsigned int queue_num,
                                   bool fwd_map_change)
@@ -230,6 +231,10 @@ static int bcm_sf2_cfp_act_pol_set(struct bcm_sf2_priv *priv,
        else
                reg = 0;
 
+       /* Enable looping back to the original port */
+       if (src_port == port_num)
+               reg |= LOOP_BK_EN;
+
        core_writel(priv, reg, CORE_ACT_POL_DATA0);
 
        /* Set classification ID that needs to be put in Broadcom tag */
@@ -443,7 +448,7 @@ static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port,
        }
 
        /* Insert into Action and policer RAMs now */
-       ret = bcm_sf2_cfp_act_pol_set(priv, rule_index, port_num,
+       ret = bcm_sf2_cfp_act_pol_set(priv, rule_index, port, port_num,
                                      queue_num, true);
        if (ret)
                goto out_err_flow_rule;
@@ -733,7 +738,7 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port,
        }
 
        /* Insert into Action and policer RAMs now */
-       ret = bcm_sf2_cfp_act_pol_set(priv, rule_index[0], port_num,
+       ret = bcm_sf2_cfp_act_pol_set(priv, rule_index[0], port, port_num,
                                      queue_num, false);
        if (ret)
                goto out_err_flow_rule;
@@ -795,7 +800,7 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port,
        /* Insert into Action and policer RAMs now, set chain ID to
         * the one we are chained to
         */
-       ret = bcm_sf2_cfp_act_pol_set(priv, rule_index[1], port_num,
+       ret = bcm_sf2_cfp_act_pol_set(priv, rule_index[1], port, port_num,
                                      queue_num, true);
        if (ret)
                goto out_err_flow_rule;
@@ -1201,3 +1206,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