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

Merge branch 'sja1105-fast-ageing'



Vladimir Oltean says:

====================
Fast ageing support for SJA1105 DSA driver

While adding support for flushing dynamically learned FDB entries in the
sja1105 driver, I noticed a few things that could be improved in DSA.
Most notably, drivers could omit a fast age when address learning is
turned off, which might mean that ports leaving a bridge and becoming
standalone could still have FDB entries pointing towards them. Secondly,
when DSA fast ages a port after the 'learning' flag has been turned off,
the software bridge still has the dynamically learned 'master' FDB
entries installed, and those should be deleted too.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 64ec13ec 5126ec72
Loading
Loading
Loading
Loading
+0 −7
Original line number Diff line number Diff line
@@ -5797,7 +5797,6 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
				       struct netlink_ext_ack *extack)
{
	struct mv88e6xxx_chip *chip = ds->priv;
	bool do_fast_age = false;
	int err = -EOPNOTSUPP;

	mv88e6xxx_reg_lock(chip);
@@ -5809,9 +5808,6 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
		err = mv88e6xxx_port_set_assoc_vector(chip, port, pav);
		if (err)
			goto out;

		if (!learning)
			do_fast_age = true;
	}

	if (flags.mask & BR_FLOOD) {
@@ -5843,9 +5839,6 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
out:
	mv88e6xxx_reg_unlock(chip);

	if (do_fast_age)
		mv88e6xxx_port_fast_age(ds, port);

	return err;
}

+0 −1
Original line number Diff line number Diff line
@@ -233,7 +233,6 @@ struct sja1105_private {
	phy_interface_t phy_mode[SJA1105_MAX_NUM_PORTS];
	bool fixed_link[SJA1105_MAX_NUM_PORTS];
	bool vlan_aware;
	unsigned long learn_ena;
	unsigned long ucast_egress_floods;
	unsigned long bcast_egress_floods;
	const struct sja1105_info *info;
+54 −19
Original line number Diff line number Diff line
@@ -176,7 +176,7 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
	struct sja1105_mac_config_entry *mac;
	struct dsa_switch *ds = priv->ds;
	struct sja1105_table *table;
	int i;
	struct dsa_port *dp;

	table = &priv->static_config.tables[BLK_IDX_MAC_CONFIG];

@@ -195,8 +195,11 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)

	mac = table->entries;

	for (i = 0; i < ds->num_ports; i++) {
		mac[i] = default_mac;
	list_for_each_entry(dp, &ds->dst->ports, list) {
		if (dp->ds != ds)
			continue;

		mac[dp->index] = default_mac;

		/* Let sja1105_bridge_stp_state_set() keep address learning
		 * enabled for the DSA ports. CPU ports use software-assisted
@@ -205,8 +208,8 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
		 * CPU ports in a cross-chip topology if multiple CPU ports
		 * exist.
		 */
		if (dsa_is_dsa_port(ds, i))
			priv->learn_ena |= BIT(i);
		if (dsa_port_is_dsa(dp))
			dp->learning = true;
	}

	return 0;
@@ -1791,6 +1794,46 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
	return 0;
}

static void sja1105_fast_age(struct dsa_switch *ds, int port)
{
	struct sja1105_private *priv = ds->priv;
	int i;

	for (i = 0; i < SJA1105_MAX_L2_LOOKUP_COUNT; i++) {
		struct sja1105_l2_lookup_entry l2_lookup = {0};
		u8 macaddr[ETH_ALEN];
		int rc;

		rc = sja1105_dynamic_config_read(priv, BLK_IDX_L2_LOOKUP,
						 i, &l2_lookup);
		/* No fdb entry at i, not an issue */
		if (rc == -ENOENT)
			continue;
		if (rc) {
			dev_err(ds->dev, "Failed to read FDB: %pe\n",
				ERR_PTR(rc));
			return;
		}

		if (!(l2_lookup.destports & BIT(port)))
			continue;

		/* Don't delete static FDB entries */
		if (l2_lookup.lockeds)
			continue;

		u64_to_ether_addr(l2_lookup.macaddr, macaddr);

		rc = sja1105_fdb_del(ds, port, macaddr, l2_lookup.vlanid);
		if (rc) {
			dev_err(ds->dev,
				"Failed to delete FDB entry %pM vid %lld: %pe\n",
				macaddr, l2_lookup.vlanid, ERR_PTR(rc));
			return;
		}
	}
}

static int sja1105_mdb_add(struct dsa_switch *ds, int port,
			   const struct switchdev_obj_port_mdb *mdb)
{
@@ -1899,6 +1942,7 @@ static int sja1105_bridge_member(struct dsa_switch *ds, int port,
static void sja1105_bridge_stp_state_set(struct dsa_switch *ds, int port,
					 u8 state)
{
	struct dsa_port *dp = dsa_to_port(ds, port);
	struct sja1105_private *priv = ds->priv;
	struct sja1105_mac_config_entry *mac;

@@ -1924,12 +1968,12 @@ static void sja1105_bridge_stp_state_set(struct dsa_switch *ds, int port,
	case BR_STATE_LEARNING:
		mac[port].ingress   = true;
		mac[port].egress    = false;
		mac[port].dyn_learn = !!(priv->learn_ena & BIT(port));
		mac[port].dyn_learn = dp->learning;
		break;
	case BR_STATE_FORWARDING:
		mac[port].ingress   = true;
		mac[port].egress    = true;
		mac[port].dyn_learn = !!(priv->learn_ena & BIT(port));
		mac[port].dyn_learn = dp->learning;
		break;
	default:
		dev_err(ds->dev, "invalid STP state: %d\n", state);
@@ -2891,23 +2935,13 @@ static int sja1105_port_set_learning(struct sja1105_private *priv, int port,
				     bool enabled)
{
	struct sja1105_mac_config_entry *mac;
	int rc;

	mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;

	mac[port].dyn_learn = enabled;

	rc = sja1105_dynamic_config_write(priv, BLK_IDX_MAC_CONFIG, port,
	return sja1105_dynamic_config_write(priv, BLK_IDX_MAC_CONFIG, port,
					    &mac[port], true);
	if (rc)
		return rc;

	if (enabled)
		priv->learn_ena |= BIT(port);
	else
		priv->learn_ena &= ~BIT(port);

	return 0;
}

static int sja1105_port_ucast_bcast_flood(struct sja1105_private *priv, int to,
@@ -3042,6 +3076,7 @@ static const struct dsa_switch_ops sja1105_switch_ops = {
	.port_fdb_dump		= sja1105_fdb_dump,
	.port_fdb_add		= sja1105_fdb_add,
	.port_fdb_del		= sja1105_fdb_del,
	.port_fast_age		= sja1105_fast_age,
	.port_bridge_join	= sja1105_bridge_join,
	.port_bridge_leave	= sja1105_bridge_leave,
	.port_pre_bridge_flags	= sja1105_port_pre_bridge_flags,
+2 −0
Original line number Diff line number Diff line
@@ -254,6 +254,8 @@ struct dsa_port {
	struct device_node	*dn;
	unsigned int		ageing_time;
	bool			vlan_filtering;
	/* Managed by DSA on user ports and by drivers on CPU and DSA ports */
	bool			learning;
	u8			stp_state;
	struct net_device	*bridge_dev;
	int			bridge_num;
+1 −1
Original line number Diff line number Diff line
@@ -241,7 +241,7 @@ int dsa_port_host_mdb_del(const struct dsa_port *dp,
int dsa_port_pre_bridge_flags(const struct dsa_port *dp,
			      struct switchdev_brport_flags flags,
			      struct netlink_ext_ack *extack);
int dsa_port_bridge_flags(const struct dsa_port *dp,
int dsa_port_bridge_flags(struct dsa_port *dp,
			  struct switchdev_brport_flags flags,
			  struct netlink_ext_ack *extack);
int dsa_port_vlan_add(struct dsa_port *dp,
Loading