Commit 8d1d8298 authored by Tobias Waldekranz's avatar Tobias Waldekranz Committed by David S. Miller

net: dsa: mv88e6xxx: Offload bridge broadcast flooding flag

These switches have two modes of classifying broadcast:

1. Broadcast is multicast.
2. Broadcast is its own unique thing that is always flooded
   everywhere.

This driver uses the first option, making sure to load the broadcast
address into all active databases. Because of this, we can support
per-port broadcast flooding by (1) making sure to only set the subset
of ports that have it enabled whenever joining a new bridge or VLAN,
and (2) by updating all active databases whenever the setting is
changed on a port.
Signed-off-by: default avatarTobias Waldekranz <tobias@waldekranz.com>
Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 041bd545
......@@ -1982,6 +1982,19 @@ static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
int err;
for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
struct dsa_port *dp = dsa_to_port(chip->ds, port);
struct net_device *brport;
if (dsa_is_unused_port(chip->ds, port))
continue;
brport = dsa_port_to_bridge_port(dp);
if (brport && !br_port_flag_is_set(brport, BR_BCAST_FLOOD))
/* Skip bridged user ports where broadcast
* flooding is disabled.
*/
continue;
err = mv88e6xxx_port_add_broadcast(chip, port, vid);
if (err)
return err;
......@@ -1990,6 +2003,53 @@ static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
return 0;
}
struct mv88e6xxx_port_broadcast_sync_ctx {
int port;
bool flood;
};
static int
mv88e6xxx_port_broadcast_sync_vlan(struct mv88e6xxx_chip *chip,
const struct mv88e6xxx_vtu_entry *vlan,
void *_ctx)
{
struct mv88e6xxx_port_broadcast_sync_ctx *ctx = _ctx;
u8 broadcast[ETH_ALEN];
u8 state;
if (ctx->flood)
state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC;
else
state = MV88E6XXX_G1_ATU_DATA_STATE_MC_UNUSED;
eth_broadcast_addr(broadcast);
return mv88e6xxx_port_db_load_purge(chip, ctx->port, broadcast,
vlan->vid, state);
}
static int mv88e6xxx_port_broadcast_sync(struct mv88e6xxx_chip *chip, int port,
bool flood)
{
struct mv88e6xxx_port_broadcast_sync_ctx ctx = {
.port = port,
.flood = flood,
};
struct mv88e6xxx_vtu_entry vid0 = {
.vid = 0,
};
int err;
/* Update the port's private database... */
err = mv88e6xxx_port_broadcast_sync_vlan(chip, &vid0, &ctx);
if (err)
return err;
/* ...and the database for all VLANs. */
return mv88e6xxx_vtu_walk(chip, mv88e6xxx_port_broadcast_sync_vlan,
&ctx);
}
static int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port,
u16 vid, u8 member, bool warn)
{
......@@ -5609,7 +5669,8 @@ 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_LEARNING | BR_FLOOD | BR_MCAST_FLOOD))
if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
BR_BCAST_FLOOD))
return -EINVAL;
ops = chip->info->ops;
......@@ -5663,6 +5724,14 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
goto out;
}
if (flags.mask & BR_BCAST_FLOOD) {
bool broadcast = !!(flags.val & BR_BCAST_FLOOD);
err = mv88e6xxx_port_broadcast_sync(chip, port, broadcast);
if (err)
goto out;
}
out:
mv88e6xxx_reg_unlock(chip);
......
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