[PATCH v1 3/3] net: dsa: sja1105: Add support for global forwarding mode

Oleksij Rempel o.rempel at pengutronix.de
Wed Mar 12 04:20:57 PDT 2025


Add support for global forwarding mode in the SJA1105 DSA driver,
allowing dynamic control over whether the switch forwards traffic
between all ports or restricts communication to only CPU-port
connections.

Signed-off-by: Oleksij Rempel <o.rempel at pengutronix.de>
---
 drivers/net/sja1105.c | 77 +++++++++++++++++++++++++++++++++----------
 1 file changed, 59 insertions(+), 18 deletions(-)

diff --git a/drivers/net/sja1105.c b/drivers/net/sja1105.c
index 4ef30b8c81f1..aaf9237dc19d 100644
--- a/drivers/net/sja1105.c
+++ b/drivers/net/sja1105.c
@@ -1230,11 +1230,13 @@ static int sja1105_init_mii_settings(struct sja1105_private *priv)
 	return 0;
 }
 
-static void sja1105_setup_tagging(struct sja1105_private *priv, int port)
+static void sja1105_setup_tagging(struct sja1105_private *priv, int port,
+				  bool forward_all)
 {
 	struct sja1105_vlan_lookup_entry *vlan;
 	struct dsa_switch *ds = &priv->ds;
 	int cpu = ds->cpu_port;
+	u8 vlan_mask;
 
 	/* The CPU port is implicitly configured by
 	 * configuring the front-panel ports
@@ -1246,8 +1248,16 @@ static void sja1105_setup_tagging(struct sja1105_private *priv, int port)
 
 	priv->pvid[port] = DSA_8021Q_DIR_TX | DSA_8021Q_PORT(port);
 
-	vlan[port].vmemb_port	= BIT(port) | BIT(cpu);
-	vlan[port].vlan_bc	= BIT(port) | BIT(cpu);
+	if (forward_all) {
+		/* All ports in the same VLAN */
+		vlan_mask = (1 << ds->num_ports) - 1;
+	} else {
+		/* Only allow port ↔ CPU communication */
+		vlan_mask = BIT(port) | BIT(cpu);
+	}
+
+	vlan[port].vmemb_port	= vlan_mask;
+	vlan[port].vlan_bc	= vlan_mask;
 	vlan[port].tag_port	= BIT(cpu);
 	vlan[port].vlanid	= priv->pvid[port];
 	vlan[port].type_entry	= SJA1110_VLAN_D_TAG;
@@ -1269,7 +1279,7 @@ static int sja1105_init_vlan(struct sja1105_private *priv)
 	table->entry_count = ds->num_ports;
 
 	for (port = 0; port < ds->num_ports; port++)
-		sja1105_setup_tagging(priv, port);
+		sja1105_setup_tagging(priv, port, false);
 
 	return 0;
 }
@@ -1283,33 +1293,47 @@ sja1105_port_allow_traffic(struct sja1105_l2_forwarding_entry *l2_fwd,
 	l2_fwd[from].fl_domain  |= BIT(to);
 }
 
-static int sja1105_init_l2_forwarding(struct sja1105_private *priv)
+static int sja1105_init_l2_forwarding(struct sja1105_private *priv,
+				      bool forward_all)
 {
 	struct sja1105_l2_forwarding_entry *l2fwd;
 	struct dsa_switch *ds = &priv->ds;
 	struct sja1105_table *table;
 	int cpu = ds->cpu_port;
-	int i;
+	int i, j;
 
 	table = &priv->static_config.tables[BLK_IDX_L2_FORWARDING];
 
-	table->entries = calloc(SJA1105_MAX_L2_FORWARDING_COUNT,
-				table->ops->unpacked_entry_size);
-	if (!table->entries)
-		return -ENOMEM;
+	if (!table->entries) {
+		table->entries = calloc(SJA1105_MAX_L2_FORWARDING_COUNT,
+					table->ops->unpacked_entry_size);
+		if (!table->entries)
+			return -ENOMEM;
+	}
 
 	table->entry_count = SJA1105_MAX_L2_FORWARDING_COUNT;
 
 	l2fwd = table->entries;
 
-	/* First 5 entries define the forwarding rules */
-	for (i = 0; i < ds->num_ports; i++) {
-		if (i == cpu)
-			continue;
-
-		sja1105_port_allow_traffic(l2fwd, i, cpu);
-		sja1105_port_allow_traffic(l2fwd, cpu, i);
+	if (forward_all) {
+		/* Forwarding mode: All ports can talk to each other */
+		for (i = 0; i < ds->num_ports; i++) {
+			for (j = 0; j < ds->num_ports; j++) {
+				if (i == j)
+					continue;
+				sja1105_port_allow_traffic(l2fwd, i, j);
+			}
+		}
+	} else {
+		/* Default mode: Each port only forwards to/from the CPU */
+		for (i = 0; i < ds->num_ports; i++) {
+			if (i == cpu)
+				continue;
+			sja1105_port_allow_traffic(l2fwd, i, cpu);
+			sja1105_port_allow_traffic(l2fwd, cpu, i);
+		}
 	}
+
 	/* Next 8 entries define VLAN PCP mapping from ingress to egress.
 	 * Leave them unpopulated (implicitly 0) but present.
 	 */
@@ -1490,7 +1514,7 @@ static int sja1105_static_config_init(struct sja1105_private *priv)
 	rc = sja1105_init_mii_settings(priv);
 	if (rc < 0)
 		return rc;
-	rc = sja1105_init_l2_forwarding(priv);
+	rc = sja1105_init_l2_forwarding(priv, false);
 	if (rc < 0)
 		return rc;
 	rc = sja1105_init_l2_forwarding_params(priv);
@@ -2866,12 +2890,29 @@ static int sja1105_cpu_port_enable(struct dsa_port *dp, int port,
 	return sja1105_static_config_reload(priv);
 }
 
+static int sja1105_set_forwarding(struct dsa_switch *ds, bool enable)
+{
+	struct device *dev = ds->dev;
+	struct sja1105_private *priv = dev_get_priv(dev);
+	int port, ret;
+
+	for (port = 0; port < ds->num_ports; port++)
+		sja1105_setup_tagging(priv, port, enable);
+
+	ret = sja1105_init_l2_forwarding(priv, enable);
+	if (ret)
+		return ret;
+
+	return sja1105_static_config_reload(priv);
+}
+
 static const struct dsa_switch_ops sja1105_dsa_ops = {
 	.port_pre_enable	= sja1105_port_pre_enable,
 	.port_enable		= sja1105_cpu_port_enable,
 	.adjust_link		= sja1105_adjust_link,
 	.xmit			= sja1105_xmit,
 	.rcv			= sja1105_rcv,
+	.set_forwarding		= sja1105_set_forwarding,
 };
 
 static int sja1105_init(struct sja1105_private *priv)
-- 
2.39.5




More information about the barebox mailing list