Commit bc794e6e authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'net-dsa-bcm_sf2-Add-support-for-CFP-statistics'



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: default avatarDavid S. Miller <davem@davemloft.net>
parents 93c09704 db78ed27
Loading
Loading
Loading
Loading
+35 −4
Original line number Diff line number Diff line
@@ -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);

+5 −3
Original line number Diff line number Diff line
@@ -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 */
+96 −3
Original line number Diff line number Diff line
@@ -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);
}
+4 −0
Original line number Diff line number Diff line
@@ -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