Commit c9d1b0b5 authored by Daniel Machon's avatar Daniel Machon Committed by Paolo Abeni
Browse files

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: d6fce514 ("net: sparx5: add switching support")
Signed-off-by: default avatarDaniel Machon <daniel.machon@microchip.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20251003-fix-flood-fwd-v1-1-48eb478b2904@microchip.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 4dc8b26a
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -708,6 +708,11 @@ static int sparx5_start(struct sparx5 *sparx5)
	/* Init masks */
	sparx5_update_fwd(sparx5);

	/* Init flood masks */
	for (int pgid = sparx5_get_pgid(sparx5, PGID_UC_FLOOD);
	     pgid <= sparx5_get_pgid(sparx5, PGID_BCAST); pgid++)
		sparx5_pgid_clear(sparx5, pgid);

	/* CPU copy CPU pgids */
	spx5_wr(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(1), sparx5,
		ANA_AC_PGID_MISC_CFG(sparx5_get_pgid(sparx5, PGID_CPU)));
+12 −0
Original line number Diff line number Diff line
@@ -176,6 +176,7 @@ static int sparx5_port_bridge_join(struct sparx5_port *port,
				   struct net_device *bridge,
				   struct netlink_ext_ack *extack)
{
	struct switchdev_brport_flags flags = {0};
	struct sparx5 *sparx5 = port->sparx5;
	struct net_device *ndev = port->ndev;
	int err;
@@ -205,6 +206,11 @@ static int sparx5_port_bridge_join(struct sparx5_port *port,
	 */
	__dev_mc_unsync(ndev, sparx5_mc_unsync);

	/* Enable uc/mc/bc flooding */
	flags.mask = BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
	flags.val = flags.mask;
	sparx5_port_attr_bridge_flags(port, flags);

	return 0;

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

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

	/* Port enters in host more therefore restore mc list */
	__dev_mc_sync(port->ndev, sparx5_mc_sync, sparx5_mc_unsync);

	/* Disable uc/mc/bc flooding */
	flags.mask = BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
	flags.val = 0;
	sparx5_port_attr_bridge_flags(port, flags);
}

static int sparx5_port_changeupper(struct net_device *dev,
+0 −10
Original line number Diff line number Diff line
@@ -167,16 +167,6 @@ void sparx5_update_fwd(struct sparx5 *sparx5)
	/* Divide up fwd mask in 32 bit words */
	bitmap_to_arr32(mask, sparx5->bridge_fwd_mask, SPX5_PORTS);

	/* Update flood masks */
	for (port = sparx5_get_pgid(sparx5, PGID_UC_FLOOD);
	     port <= sparx5_get_pgid(sparx5, PGID_BCAST); port++) {
		spx5_wr(mask[0], sparx5, ANA_AC_PGID_CFG(port));
		if (is_sparx5(sparx5)) {
			spx5_wr(mask[1], sparx5, ANA_AC_PGID_CFG1(port));
			spx5_wr(mask[2], sparx5, ANA_AC_PGID_CFG2(port));
		}
	}

	/* Update SRC masks */
	for (port = 0; port < sparx5->data->consts->n_ports; port++) {
		if (test_bit(port, sparx5->bridge_fwd_mask)) {