diff mbox series

[v2,net-next,09/14] net: mscc: ocelot: reapply bridge forwarding mask on bonding join/leave

Message ID 20210116005943.219479-10-olteanv@gmail.com
State New
Headers show
Series LAG offload for Ocelot DSA switches | expand

Commit Message

Vladimir Oltean Jan. 16, 2021, 12:59 a.m. UTC
From: Vladimir Oltean <vladimir.oltean@nxp.com>

Applying the bridge forwarding mask currently is done only on the STP
state changes for any port. But it depends on both STP state changes,
and bonding interface state changes. Export the bit that recalculates
the forwarding mask so that it could be reused, and call it when a port
starts and stops offloading a bonding interface.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
---
Changes in v2:
Found a better strategic placement for the ocelot_apply_bridge_fwd_mask
function (i.e. just code ordering).

 drivers/net/ethernet/mscc/ocelot.c | 68 +++++++++++++++++-------------
 1 file changed, 38 insertions(+), 30 deletions(-)
diff mbox series

Patch

diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index 915cf81f602a..8ab74325eb78 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -894,40 +894,18 @@  static u32 ocelot_get_bond_mask(struct ocelot *ocelot, struct net_device *bond)
 	return bond_mask;
 }
 
-void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state)
+static void ocelot_apply_bridge_fwd_mask(struct ocelot *ocelot)
 {
-	u32 port_cfg;
-	int p;
-
-	if (!(BIT(port) & ocelot->bridge_mask))
-		return;
-
-	port_cfg = ocelot_read_gix(ocelot, ANA_PORT_PORT_CFG, port);
-
-	switch (state) {
-	case BR_STATE_FORWARDING:
-		ocelot->bridge_fwd_mask |= BIT(port);
-		fallthrough;
-	case BR_STATE_LEARNING:
-		port_cfg |= ANA_PORT_PORT_CFG_LEARN_ENA;
-		break;
-
-	default:
-		port_cfg &= ~ANA_PORT_PORT_CFG_LEARN_ENA;
-		ocelot->bridge_fwd_mask &= ~BIT(port);
-		break;
-	}
-
-	ocelot_write_gix(ocelot, port_cfg, ANA_PORT_PORT_CFG, port);
+	int port;
 
 	/* Apply FWD mask. The loop is needed to add/remove the current port as
 	 * a source for the other ports. If the source port is in a bond, then
 	 * all the other ports from that bond need to be removed from this
 	 * source port's forwarding mask.
 	 */
-	for (p = 0; p < ocelot->num_phys_ports; p++) {
-		if (ocelot->bridge_fwd_mask & BIT(p)) {
-			unsigned long mask = ocelot->bridge_fwd_mask & ~BIT(p);
+	for (port = 0; port < ocelot->num_phys_ports; port++) {
+		if (ocelot->bridge_fwd_mask & BIT(port)) {
+			unsigned long mask = ocelot->bridge_fwd_mask & ~BIT(port);
 			int lag;
 
 			for (lag = 0; lag < ocelot->num_phys_ports; lag++) {
@@ -936,20 +914,48 @@  void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state)
 				if (!bond_mask)
 					continue;
 
-				if (bond_mask & BIT(p)) {
+				if (bond_mask & BIT(port)) {
 					mask &= ~bond_mask;
 					break;
 				}
 			}
 
 			ocelot_write_rix(ocelot, mask,
-					 ANA_PGID_PGID, PGID_SRC + p);
+					 ANA_PGID_PGID, PGID_SRC + port);
 		} else {
 			ocelot_write_rix(ocelot, 0,
-					 ANA_PGID_PGID, PGID_SRC + p);
+					 ANA_PGID_PGID, PGID_SRC + port);
 		}
 	}
 }
+
+void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state)
+{
+	u32 port_cfg;
+
+	if (!(BIT(port) & ocelot->bridge_mask))
+		return;
+
+	port_cfg = ocelot_read_gix(ocelot, ANA_PORT_PORT_CFG, port);
+
+	switch (state) {
+	case BR_STATE_FORWARDING:
+		ocelot->bridge_fwd_mask |= BIT(port);
+		fallthrough;
+	case BR_STATE_LEARNING:
+		port_cfg |= ANA_PORT_PORT_CFG_LEARN_ENA;
+		break;
+
+	default:
+		port_cfg &= ~ANA_PORT_PORT_CFG_LEARN_ENA;
+		ocelot->bridge_fwd_mask &= ~BIT(port);
+		break;
+	}
+
+	ocelot_write_gix(ocelot, port_cfg, ANA_PORT_PORT_CFG, port);
+
+	ocelot_apply_bridge_fwd_mask(ocelot);
+}
 EXPORT_SYMBOL(ocelot_bridge_stp_state_set);
 
 void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs)
@@ -1300,6 +1306,7 @@  int ocelot_port_lag_join(struct ocelot *ocelot, int port,
 	}
 
 	ocelot_setup_lag(ocelot, lag);
+	ocelot_apply_bridge_fwd_mask(ocelot);
 	ocelot_set_aggr_pgids(ocelot);
 
 	return 0;
@@ -1335,6 +1342,7 @@  void ocelot_port_lag_leave(struct ocelot *ocelot, int port,
 	ocelot_write_gix(ocelot, port_cfg | ANA_PORT_PORT_CFG_PORTID_VAL(port),
 			 ANA_PORT_PORT_CFG, port);
 
+	ocelot_apply_bridge_fwd_mask(ocelot);
 	ocelot_set_aggr_pgids(ocelot);
 }
 EXPORT_SYMBOL(ocelot_port_lag_leave);