]> www.infradead.org Git - users/hch/misc.git/commitdiff
net: sparx5/lan969x: fix flooding configuration on bridge join/leave
authorDaniel Machon <daniel.machon@microchip.com>
Fri, 3 Oct 2025 12:35:59 +0000 (14:35 +0200)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 7 Oct 2025 09:53:45 +0000 (11:53 +0200)
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: d6fce5141929 ("net: sparx5: add switching support")
Signed-off-by: Daniel Machon <daniel.machon@microchip.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20251003-fix-flood-fwd-v1-1-48eb478b2904@microchip.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/microchip/sparx5/sparx5_main.c
drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c
drivers/net/ethernet/microchip/sparx5/sparx5_vlan.c

index 74ad1d73b4652e9cc5185e0f7ad751f195914930..40b1bfc600a791d61f70086150e1de74c0f94679 100644 (file)
@@ -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)));
index bc9ecb9392cd35d178f9e20f0352dbeebc29a282..0a71abbd3da58c63208c55d405fcf7a0fee51b82 100644 (file)
@@ -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 @@ err_switchdev_offload:
 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,
index d42097aa60a0e4c31c9294b3ec34759ad9313f93..4947828719038b9a84ec7c8fb5caa2c439d2b2b8 100644 (file)
@@ -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)) {