Skip to content

Commit c9d1b0b

Browse files
DanielmachonPaolo Abeni
authored andcommitted
net: sparx5/lan969x: fix flooding configuration on bridge join/leave
The sparx5 driver programs UC/MC/BC flooding in sparx5_update_fwd() by unconditionally applying bridge_fwd_mask to all flood PGIDs. Any bridge topology change that triggers sparx5_update_fwd() (for example enslaving another port) therefore reinstalls flooding in hardware for already bridged ports, regardless of their per-port flood flags. This results in clobbering of the flood masks, and desynchronization between software and hardware: the bridge still reports “flood off” for the port, but hardware has flooding enabled due to unconditional PGID reprogramming. Steps to reproduce: $ ip link add br0 type bridge $ ip link set br0 up $ ip link set eth0 master br0 $ ip link set eth0 up $ bridge link set dev eth0 flood off $ ip link set eth1 master br0 $ ip link set eth1 up At this point, flooding is silently re-enabled for eth0. Software still shows “flood off” for eth0, but hardware has flooding enabled. To fix this, flooding is now set explicitly during bridge join/leave, through sparx5_port_attr_bridge_flags(): On bridge join, UC/MC/BC flooding is enabled by default. On bridge leave, UC/MC/BC flooding is disabled. sparx5_update_fwd() no longer touches the flood PGIDs, clobbering the flood masks, and desynchronizing software and hardware. Initialization of the flooding PGIDs have been moved to sparx5_start(). This is required as flooding PGIDs defaults to 0x3fffffff in hardware and the initialization was previously handled in sparx5_update_fwd(), which was removed. With this change, user-configured flooding flags persist across bridge updates and are no longer overridden by sparx5_update_fwd(). Fixes: d6fce51 ("net: sparx5: add switching support") Signed-off-by: Daniel Machon <[email protected]> Reviewed-by: Simon Horman <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
1 parent 4dc8b26 commit c9d1b0b

File tree

3 files changed

+17
-10
lines changed

3 files changed

+17
-10
lines changed

drivers/net/ethernet/microchip/sparx5/sparx5_main.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,11 @@ static int sparx5_start(struct sparx5 *sparx5)
708708
/* Init masks */
709709
sparx5_update_fwd(sparx5);
710710

711+
/* Init flood masks */
712+
for (int pgid = sparx5_get_pgid(sparx5, PGID_UC_FLOOD);
713+
pgid <= sparx5_get_pgid(sparx5, PGID_BCAST); pgid++)
714+
sparx5_pgid_clear(sparx5, pgid);
715+
711716
/* CPU copy CPU pgids */
712717
spx5_wr(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(1), sparx5,
713718
ANA_AC_PGID_MISC_CFG(sparx5_get_pgid(sparx5, PGID_CPU)));

drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ static int sparx5_port_bridge_join(struct sparx5_port *port,
176176
struct net_device *bridge,
177177
struct netlink_ext_ack *extack)
178178
{
179+
struct switchdev_brport_flags flags = {0};
179180
struct sparx5 *sparx5 = port->sparx5;
180181
struct net_device *ndev = port->ndev;
181182
int err;
@@ -205,6 +206,11 @@ static int sparx5_port_bridge_join(struct sparx5_port *port,
205206
*/
206207
__dev_mc_unsync(ndev, sparx5_mc_unsync);
207208

209+
/* Enable uc/mc/bc flooding */
210+
flags.mask = BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
211+
flags.val = flags.mask;
212+
sparx5_port_attr_bridge_flags(port, flags);
213+
208214
return 0;
209215

210216
err_switchdev_offload:
@@ -215,6 +221,7 @@ static int sparx5_port_bridge_join(struct sparx5_port *port,
215221
static void sparx5_port_bridge_leave(struct sparx5_port *port,
216222
struct net_device *bridge)
217223
{
224+
struct switchdev_brport_flags flags = {0};
218225
struct sparx5 *sparx5 = port->sparx5;
219226

220227
switchdev_bridge_port_unoffload(port->ndev, NULL, NULL, NULL);
@@ -234,6 +241,11 @@ static void sparx5_port_bridge_leave(struct sparx5_port *port,
234241

235242
/* Port enters in host more therefore restore mc list */
236243
__dev_mc_sync(port->ndev, sparx5_mc_sync, sparx5_mc_unsync);
244+
245+
/* Disable uc/mc/bc flooding */
246+
flags.mask = BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
247+
flags.val = 0;
248+
sparx5_port_attr_bridge_flags(port, flags);
237249
}
238250

239251
static int sparx5_port_changeupper(struct net_device *dev,

drivers/net/ethernet/microchip/sparx5/sparx5_vlan.c

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -167,16 +167,6 @@ void sparx5_update_fwd(struct sparx5 *sparx5)
167167
/* Divide up fwd mask in 32 bit words */
168168
bitmap_to_arr32(mask, sparx5->bridge_fwd_mask, SPX5_PORTS);
169169

170-
/* Update flood masks */
171-
for (port = sparx5_get_pgid(sparx5, PGID_UC_FLOOD);
172-
port <= sparx5_get_pgid(sparx5, PGID_BCAST); port++) {
173-
spx5_wr(mask[0], sparx5, ANA_AC_PGID_CFG(port));
174-
if (is_sparx5(sparx5)) {
175-
spx5_wr(mask[1], sparx5, ANA_AC_PGID_CFG1(port));
176-
spx5_wr(mask[2], sparx5, ANA_AC_PGID_CFG2(port));
177-
}
178-
}
179-
180170
/* Update SRC masks */
181171
for (port = 0; port < sparx5->data->consts->n_ports; port++) {
182172
if (test_bit(port, sparx5->bridge_fwd_mask)) {

0 commit comments

Comments
 (0)