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: Tobias Waldekranz <tobias@waldekranz.com> Reviewed-by: Vladimir Oltean <olteanv@gmail.com> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
7b9f16fe40
commit
041bd545e1
@@ -2740,15 +2740,20 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Port Association Vector: when learning source addresses
|
/* Port Association Vector: disable automatic address learning
|
||||||
* of packets, add the address to the address database using
|
* on all user ports since they start out in standalone
|
||||||
* a port bitmap that has only the bit for this port set and
|
* mode. When joining a bridge, learning will be configured to
|
||||||
* the other bits clear.
|
* 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;
|
if (dsa_is_user_port(ds, port))
|
||||||
/* Disable learning for CPU port */
|
|
||||||
if (dsa_is_cpu_port(ds, port))
|
|
||||||
reg = 0;
|
reg = 0;
|
||||||
|
else
|
||||||
|
reg = 1 << port;
|
||||||
|
|
||||||
err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
|
err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
|
||||||
reg);
|
reg);
|
||||||
@@ -5604,7 +5609,7 @@ static int mv88e6xxx_port_pre_bridge_flags(struct dsa_switch *ds, int port,
|
|||||||
struct mv88e6xxx_chip *chip = ds->priv;
|
struct mv88e6xxx_chip *chip = ds->priv;
|
||||||
const struct mv88e6xxx_ops *ops;
|
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;
|
return -EINVAL;
|
||||||
|
|
||||||
ops = chip->info->ops;
|
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 netlink_ext_ack *extack)
|
||||||
{
|
{
|
||||||
struct mv88e6xxx_chip *chip = ds->priv;
|
struct mv88e6xxx_chip *chip = ds->priv;
|
||||||
|
bool do_fast_age = false;
|
||||||
int err = -EOPNOTSUPP;
|
int err = -EOPNOTSUPP;
|
||||||
|
|
||||||
mv88e6xxx_reg_lock(chip);
|
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) {
|
if (flags.mask & BR_FLOOD) {
|
||||||
bool unicast = !!(flags.val & 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:
|
out:
|
||||||
mv88e6xxx_reg_unlock(chip);
|
mv88e6xxx_reg_unlock(chip);
|
||||||
|
|
||||||
|
if (do_fast_age)
|
||||||
|
mv88e6xxx_port_fast_age(ds, port);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1309,6 +1309,27 @@ int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)
|
|||||||
0x0001);
|
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,
|
||||||
|
®);
|
||||||
|
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 */
|
/* Offset 0x0C: Port ATU Control */
|
||||||
|
|
||||||
int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port)
|
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);
|
size_t size);
|
||||||
int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port);
|
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 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,
|
int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
|
||||||
u8 out);
|
u8 out);
|
||||||
int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
|
int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
|
||||||
|
|||||||
Reference in New Issue
Block a user