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

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
......@@ -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;
}
......
......@@ -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)
......
......@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment