Commit 041bd545 authored by Tobias Waldekranz's avatar Tobias Waldekranz Committed by David S. Miller
Browse files

net: dsa: mv88e6xxx: Offload bridge learning flag



Allow a user to control automatic learning per port.

Many chips have an explicit "LearningDisable"-bit that can be used for
this, but we opt for setting/clearing the PAV instead, as it works on
all devices at least as far back as 6083.

Signed-off-by: default avatarTobias Waldekranz <tobias@waldekranz.com>
Reviewed-by: default avatarVladimir Oltean <olteanv@gmail.com>
Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7b9f16fe
Loading
Loading
Loading
Loading
+29 −8
Original line number Diff line number Diff line
@@ -2740,15 +2740,20 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
			return err;
	}

	/* Port Association Vector: when learning source addresses
	 * of packets, add the address to the address database using
	 * a port bitmap that has only the bit for this port set and
	 * the other bits clear.
	/* Port Association Vector: disable automatic address learning
	 * on all user ports since they start out in standalone
	 * mode. When joining a bridge, learning will be configured to
	 * match the bridge port settings. Enable learning on all
	 * DSA/CPU ports. NOTE: FROM_CPU frames always bypass the
	 * learning process.
	 *
	 * Disable HoldAt1, IntOnAgeOut, LockedPort, IgnoreWrongData,
	 * and RefreshLocked. I.e. setup standard automatic learning.
	 */
	reg = 1 << port;
	/* Disable learning for CPU port */
	if (dsa_is_cpu_port(ds, port))
	if (dsa_is_user_port(ds, port))
		reg = 0;
	else
		reg = 1 << port;

	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
				   reg);
@@ -5604,7 +5609,7 @@ static int mv88e6xxx_port_pre_bridge_flags(struct dsa_switch *ds, int port,
	struct mv88e6xxx_chip *chip = ds->priv;
	const struct mv88e6xxx_ops *ops;

	if (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD))
	if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD))
		return -EINVAL;

	ops = chip->info->ops;
@@ -5623,10 +5628,23 @@ 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);

	if (flags.mask & BR_LEARNING) {
		bool learning = !!(flags.val & BR_LEARNING);
		u16 pav = learning ? (1 << port) : 0;

		err = mv88e6xxx_port_set_assoc_vector(chip, port, pav);
		if (err)
			goto out;

		if (!learning)
			do_fast_age = true;
	}

	if (flags.mask & BR_FLOOD) {
		bool unicast = !!(flags.val & BR_FLOOD);

@@ -5648,6 +5666,9 @@ 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;
}

+21 −0
Original line number Diff line number Diff line
@@ -1309,6 +1309,27 @@ int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)
				    0x0001);
}

/* Offset 0x0B: Port Association Vector */

int mv88e6xxx_port_set_assoc_vector(struct mv88e6xxx_chip *chip, int port,
				    u16 pav)
{
	u16 reg, mask;
	int err;

	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
				  &reg);
	if (err)
		return err;

	mask = mv88e6xxx_port_mask(chip);
	reg &= ~mask;
	reg |= pav & mask;

	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
				    reg);
}

/* Offset 0x0C: Port ATU Control */

int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port)
+2 −0
Original line number Diff line number Diff line
@@ -407,6 +407,8 @@ int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port,
				  size_t size);
int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port);
int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port);
int mv88e6xxx_port_set_assoc_vector(struct mv88e6xxx_chip *chip, int port,
				    u16 pav);
int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
			       u8 out);
int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,