6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladimir Oltean vladimir.oltean@nxp.com
[ Upstream commit c0054b25e2f1045f47b4954cf13a539e5e6047df ]
A port added to a "single port bridge" operates as standalone, and this is mutually exclusive to being part of a Linux bridge. In fact, gswip_port_bridge_join() calls gswip_add_single_port_br() with add=false, i.e. removes the port from the "single port bridge" to enable autonomous forwarding.
The blamed commit seems to have incorrectly thought that ds->ops->port_enable() is called one time per port, during the setup phase of the switch.
However, it is actually called during the ndo_open() implementation of DSA user ports, which is to say that this sequence of events:
1. ip link set swp0 down 2. ip link add br0 type bridge 3. ip link set swp0 master br0 4. ip link set swp0 up
would cause swp0 to join back the "single port bridge" which step 3 had just removed it from.
The correct DSA hook for one-time actions per port at switch init time is ds->ops->port_setup(). This is what seems to match the coder's intention; also see the comment at the beginning of the file:
* At the initialization the driver allocates one bridge table entry for ~~~~~~~~~~~~~~~~~~~~~ * each switch port which is used when the port is used without an * explicit bridge.
Fixes: 8206e0ce96b3 ("net: dsa: lantiq: Add VLAN unaware bridge offloading") Signed-off-by: Vladimir Oltean vladimir.oltean@nxp.com Link: https://patch.msgid.link/20250918072142.894692-2-vladimir.oltean@nxp.com Tested-by: Daniel Golle daniel@makrotopia.org Reviewed-by: Daniel Golle daniel@makrotopia.org Signed-off-by: Paolo Abeni pabeni@redhat.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/net/dsa/lantiq_gswip.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c index a2b10b28c11fa..054548294f039 100644 --- a/drivers/net/dsa/lantiq_gswip.c +++ b/drivers/net/dsa/lantiq_gswip.c @@ -682,18 +682,27 @@ static int gswip_add_single_port_br(struct gswip_priv *priv, int port, bool add) return 0; }
-static int gswip_port_enable(struct dsa_switch *ds, int port, - struct phy_device *phydev) +static int gswip_port_setup(struct dsa_switch *ds, int port) { struct gswip_priv *priv = ds->priv; int err;
if (!dsa_is_cpu_port(ds, port)) { - u32 mdio_phy = 0; - err = gswip_add_single_port_br(priv, port, true); if (err) return err; + } + + return 0; +} + +static int gswip_port_enable(struct dsa_switch *ds, int port, + struct phy_device *phydev) +{ + struct gswip_priv *priv = ds->priv; + + if (!dsa_is_cpu_port(ds, port)) { + u32 mdio_phy = 0;
if (phydev) mdio_phy = phydev->mdio.addr & GSWIP_MDIO_PHY_ADDR_MASK; @@ -1813,6 +1822,7 @@ static int gswip_get_sset_count(struct dsa_switch *ds, int port, int sset) static const struct dsa_switch_ops gswip_xrx200_switch_ops = { .get_tag_protocol = gswip_get_tag_protocol, .setup = gswip_setup, + .port_setup = gswip_port_setup, .port_enable = gswip_port_enable, .port_disable = gswip_port_disable, .port_bridge_join = gswip_port_bridge_join,