From 622e2d0971b5a5e2e5cb822b4dc6ca3a1c0af8be Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Thu, 9 Oct 2025 14:56:39 +0200 Subject: [PATCH] realtek: dsa: Share port member configuration code The leave and join callbacks for DSA were using their own implementation of the port member handling code. This makes the implementation of additional functionality based on the port member matrix complicated because it needs to be implemented in both places and also in the new code path for the introduced feature. By sharing this code, it is much easier to guarantee that all code paths behave the same. This approach is already implemented by other DSA drivers like qca8k, mt7530 or ksz. Signed-off-by: Sven Eckelmann Link: https://github.com/openwrt/openwrt/pull/20360 Signed-off-by: Robert Marko --- .../files-6.12/drivers/net/dsa/rtl83xx/dsa.c | 96 +++++++++---------- 1 file changed, 46 insertions(+), 50 deletions(-) diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c index 508119ff01..d97283065f 100644 --- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c @@ -1528,15 +1528,56 @@ static int rtl83xx_set_ageing_time(struct dsa_switch *ds, unsigned int msec) return 0; } +static void rtldsa_update_port_member(struct rtl838x_switch_priv *priv, int port, + const struct net_device *bridge_dev, bool join) + __must_hold(&priv->reg_mutex) +{ + struct dsa_port *dp = dsa_to_port(priv->ds, port); + struct rtl838x_port *p = &priv->ports[port]; + struct dsa_port *cpu_dp = dp->cpu_dp; + u64 port_mask = BIT_ULL(cpu_dp->index); + struct rtl838x_port *other_p; + struct dsa_port *other_dp; + int other_port; + + dsa_switch_for_each_user_port(other_dp, priv->ds) { + other_port = other_dp->index; + other_p = &priv->ports[other_port]; + + if (dp == other_dp) + continue; + + if (!dsa_port_offloads_bridge_dev(other_dp, bridge_dev)) + continue; + + if (join && priv->is_lagmember[other_port]) + continue; + + if (join) { + port_mask |= BIT_ULL(other_port); + other_p->pm |= BIT_ULL(port); + } else { + other_p->pm &= ~BIT_ULL(port); + } + + if (other_p->enable) + priv->r->traffic_set(other_port, other_p->pm); + } + + p->pm = port_mask; + + if (p->enable) + priv->r->traffic_set(port, port_mask); +} + static int rtl83xx_port_bridge_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge, bool *tx_fwd_offload, struct netlink_ext_ack *extack) { struct rtl838x_switch_priv *priv = ds->priv; - u64 port_bitmap = BIT_ULL(priv->cpu_port), v; - pr_debug("%s %x: %d %llx", __func__, (u32)priv, port, port_bitmap); + pr_debug("%s %x: %d", __func__, (u32)priv, port); if (priv->is_lagmember[port]) { pr_debug("%s: %d is lag slave. ignore\n", __func__, port); @@ -1544,30 +1585,8 @@ static int rtl83xx_port_bridge_join(struct dsa_switch *ds, int port, } mutex_lock(&priv->reg_mutex); - for (int i = 0; i < ds->num_ports; i++) { - /* Add this port to the port matrix of the other ports in the - * same bridge. If the port is disabled, port matrix is kept - * and not being setup until the port becomes enabled. - */ - if (dsa_is_user_port(ds, i) && !priv->is_lagmember[i] && i != port) { - if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge)) - continue; - if (priv->ports[i].enable) - priv->r->traffic_enable(i, port); - priv->ports[i].pm |= BIT_ULL(port); - port_bitmap |= BIT_ULL(i); - } - } - - /* Add all other ports to this port matrix. */ - if (priv->ports[port].enable) { - priv->r->traffic_enable(priv->cpu_port, port); - v = priv->r->traffic_get(port); - v |= port_bitmap; - priv->r->traffic_set(port, v); - } - priv->ports[port].pm |= port_bitmap; + rtldsa_update_port_member(priv, port, bridge.dev, true); if (priv->r->set_static_move_action) priv->r->set_static_move_action(port, false); @@ -1581,35 +1600,12 @@ static void rtl83xx_port_bridge_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge) { struct rtl838x_switch_priv *priv = ds->priv; - u64 port_bitmap = 0, v; pr_debug("%s %x: %d", __func__, (u32)priv, port); + mutex_lock(&priv->reg_mutex); - for (int i = 0; i < ds->num_ports; i++) { - /* Remove this port from the port matrix of the other ports - * in the same bridge. If the port is disabled, port matrix - * is kept and not being setup until the port becomes enabled. - * And the other port's port matrix cannot be broken when the - * other port is still a VLAN-aware port. - */ - if (dsa_is_user_port(ds, i) && i != port) { - if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge)) - continue; - if (priv->ports[i].enable) - priv->r->traffic_disable(i, port); - priv->ports[i].pm &= ~BIT_ULL(port); - port_bitmap |= BIT_ULL(i); - } - } - - /* Remove all other ports from this port matrix. */ - if (priv->ports[port].enable) { - v = priv->r->traffic_get(port); - v &= ~port_bitmap; - priv->r->traffic_set(port, v); - } - priv->ports[port].pm &= ~port_bitmap; + rtldsa_update_port_member(priv, port, bridge.dev, false); if (priv->r->set_static_move_action) priv->r->set_static_move_action(port, true);