[openwrt/openwrt] generic: qca8k: backport bridge port isolation support

LEDE Commits lede-commits at lists.infradead.org
Tue Apr 8 10:12:12 PDT 2025


neocturne pushed a commit to openwrt/openwrt.git, branch openwrt-24.10:
https://git.openwrt.org/eb1f411036ff239cc998c9dd872a9ba9d85add7a

commit eb1f411036ff239cc998c9dd872a9ba9d85add7a
Author: Matthias Schiffer <mschiffer at universe-factory.net>
AuthorDate: Sat Mar 29 21:31:49 2025 +0100

    generic: qca8k: backport bridge port isolation support
    
    Bridge port isolation offload support has been added to the bridge core
    and many DSA drivers. mt7530 support was backported in OpenWrt commit
    c4e6a147a6c0 ("generic: 6.6: mt7530: add support for bridge port
    isolation").
    
    Backport qca8k support as well.
    
    Signed-off-by: Matthias Schiffer <mschiffer at universe-factory.net>
    Link: https://github.com/openwrt/openwrt/pull/18375
    Signed-off-by: Christian Marangi <ansuelsmth at gmail.com>
    (cherry picked from commit 5d1dedd9f7fc7a7c893e14ec6c1548e2be7a1a13)
---
 ...8k-do-not-write-port-mask-twice-in-bridge.patch |  58 ++++++++
 ...-qca8k-factor-out-bridge-join-leave-logic.patch | 153 +++++++++++++++++++++
 ...a8k-add-support-for-bridge-port-isolation.patch |  91 ++++++++++++
 ...t-dsa-qca8k-implement-lag_fdb_add-del-ops.patch |   4 +-
 ...qca8k-add-IPQ4019-built-in-switch-support.patch |  23 +---
 5 files changed, 311 insertions(+), 18 deletions(-)

diff --git a/target/linux/generic/backport-6.6/793-01-v6.11-net-dsa-qca8k-do-not-write-port-mask-twice-in-bridge.patch b/target/linux/generic/backport-6.6/793-01-v6.11-net-dsa-qca8k-do-not-write-port-mask-twice-in-bridge.patch
new file mode 100644
index 0000000000..22b544c433
--- /dev/null
+++ b/target/linux/generic/backport-6.6/793-01-v6.11-net-dsa-qca8k-do-not-write-port-mask-twice-in-bridge.patch
@@ -0,0 +1,58 @@
+From e85d3e6fea05c8ae21a40809a3c6b7adc97411c7 Mon Sep 17 00:00:00 2001
+Message-ID: <e85d3e6fea05c8ae21a40809a3c6b7adc97411c7.1728674648.git.mschiffer at universe-factory.net>
+From: Matthias Schiffer <mschiffer at universe-factory.net>
+Date: Thu, 20 Jun 2024 19:25:48 +0200
+Subject: [PATCH] net: dsa: qca8k: do not write port mask twice in bridge
+ join/leave
+
+qca8k_port_bridge_join() set QCA8K_PORT_LOOKUP_CTRL() for i == port twice,
+once in the loop handling all other port's masks, and finally at the end
+with the accumulated port_mask.
+
+The first time it would incorrectly set the port's own bit in the mask,
+only to correct the mistake a moment later. qca8k_port_bridge_leave() had
+the same issue, but here the regmap_clear_bits() was a no-op rather than
+setting an unintended value.
+
+Remove the duplicate assignment by skipping the whole loop iteration for
+i == port. The unintended bit setting doesn't seem to have any negative
+effects (even when not reverted right away), so the change is submitted
+as a simple cleanup rather than a fix.
+
+Signed-off-by: Matthias Schiffer <mschiffer at universe-factory.net>
+Reviewed-by: Wojciech Drewek <wojciech.drewek at intel.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/dsa/qca/qca8k-common.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/dsa/qca/qca8k-common.c
++++ b/drivers/net/dsa/qca/qca8k-common.c
+@@ -654,6 +654,8 @@ int qca8k_port_bridge_join(struct dsa_sw
+ 	port_mask = BIT(cpu_port);
+ 
+ 	for (i = 0; i < QCA8K_NUM_PORTS; i++) {
++		if (i == port)
++			continue;
+ 		if (dsa_is_cpu_port(ds, i))
+ 			continue;
+ 		if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
+@@ -666,8 +668,7 @@ int qca8k_port_bridge_join(struct dsa_sw
+ 				      BIT(port));
+ 		if (ret)
+ 			return ret;
+-		if (i != port)
+-			port_mask |= BIT(i);
++		port_mask |= BIT(i);
+ 	}
+ 
+ 	/* Add all other ports to this ports portvlan mask */
+@@ -686,6 +687,8 @@ void qca8k_port_bridge_leave(struct dsa_
+ 	cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
+ 
+ 	for (i = 0; i < QCA8K_NUM_PORTS; i++) {
++		if (i == port)
++			continue;
+ 		if (dsa_is_cpu_port(ds, i))
+ 			continue;
+ 		if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
diff --git a/target/linux/generic/backport-6.6/793-02-v6.11-net-dsa-qca8k-factor-out-bridge-join-leave-logic.patch b/target/linux/generic/backport-6.6/793-02-v6.11-net-dsa-qca8k-factor-out-bridge-join-leave-logic.patch
new file mode 100644
index 0000000000..fdb7e7b8b6
--- /dev/null
+++ b/target/linux/generic/backport-6.6/793-02-v6.11-net-dsa-qca8k-factor-out-bridge-join-leave-logic.patch
@@ -0,0 +1,153 @@
+From 412e1775f413c944b8c51bdadb675be957d83dc8 Mon Sep 17 00:00:00 2001
+Message-ID: <412e1775f413c944b8c51bdadb675be957d83dc8.1728674648.git.mschiffer at universe-factory.net>
+In-Reply-To: <e85d3e6fea05c8ae21a40809a3c6b7adc97411c7.1728674648.git.mschiffer at universe-factory.net>
+References: <e85d3e6fea05c8ae21a40809a3c6b7adc97411c7.1728674648.git.mschiffer at universe-factory.net>
+From: Matthias Schiffer <mschiffer at universe-factory.net>
+Date: Thu, 20 Jun 2024 19:25:49 +0200
+Subject: [PATCH] net: dsa: qca8k: factor out bridge join/leave logic
+
+Most of the logic in qca8k_port_bridge_join() and qca8k_port_bridge_leave()
+is the same. Refactor to reduce duplication and prepare for reusing the
+code for implementing bridge port isolation.
+
+dsa_port_offloads_bridge_dev() is used instead of
+dsa_port_offloads_bridge(), passing the bridge in as a struct netdevice *,
+as we won't have a struct dsa_bridge in qca8k_port_bridge_flags().
+
+The error handling is changed slightly in the bridge leave case,
+returning early and emitting an error message when a regmap access fails.
+This shouldn't matter in practice, as there isn't much we can do if
+communication with the switch breaks down in the middle of reconfiguration.
+
+Signed-off-by: Matthias Schiffer <mschiffer at universe-factory.net>
+Reviewed-by: Wojciech Drewek <wojciech.drewek at intel.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/dsa/qca/qca8k-common.c | 101 ++++++++++++++---------------
+ 1 file changed, 50 insertions(+), 51 deletions(-)
+
+--- a/drivers/net/dsa/qca/qca8k-common.c
++++ b/drivers/net/dsa/qca/qca8k-common.c
+@@ -615,6 +615,49 @@ void qca8k_port_stp_state_set(struct dsa
+ 	qca8k_port_configure_learning(ds, port, learning);
+ }
+ 
++static int qca8k_update_port_member(struct qca8k_priv *priv, int port,
++				    const struct net_device *bridge_dev,
++				    bool join)
++{
++	struct dsa_port *dp = dsa_to_port(priv->ds, port), *other_dp;
++	u32 port_mask = BIT(dp->cpu_dp->index);
++	int i, ret;
++
++	for (i = 0; i < QCA8K_NUM_PORTS; i++) {
++		if (i == port)
++			continue;
++		if (dsa_is_cpu_port(priv->ds, i))
++			continue;
++
++		other_dp = dsa_to_port(priv->ds, i);
++		if (!dsa_port_offloads_bridge_dev(other_dp, bridge_dev))
++			continue;
++
++		/* Add/remove this port to/from the portvlan mask of the other
++		 * ports in the bridge
++		 */
++		if (join) {
++			port_mask |= BIT(i);
++			ret = regmap_set_bits(priv->regmap,
++					      QCA8K_PORT_LOOKUP_CTRL(i),
++					      BIT(port));
++		} else {
++			ret = regmap_clear_bits(priv->regmap,
++						QCA8K_PORT_LOOKUP_CTRL(i),
++						BIT(port));
++		}
++
++		if (ret)
++			return ret;
++	}
++
++	/* Add/remove all other ports to/from this port's portvlan mask */
++	ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
++			QCA8K_PORT_LOOKUP_MEMBER, port_mask);
++
++	return ret;
++}
++
+ int qca8k_port_pre_bridge_flags(struct dsa_switch *ds, int port,
+ 				struct switchdev_brport_flags flags,
+ 				struct netlink_ext_ack *extack)
+@@ -647,65 +690,21 @@ int qca8k_port_bridge_join(struct dsa_sw
+ 			   struct netlink_ext_ack *extack)
+ {
+ 	struct qca8k_priv *priv = ds->priv;
+-	int port_mask, cpu_port;
+-	int i, ret;
+-
+-	cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
+-	port_mask = BIT(cpu_port);
+ 
+-	for (i = 0; i < QCA8K_NUM_PORTS; i++) {
+-		if (i == port)
+-			continue;
+-		if (dsa_is_cpu_port(ds, i))
+-			continue;
+-		if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
+-			continue;
+-		/* Add this port to the portvlan mask of the other ports
+-		 * in the bridge
+-		 */
+-		ret = regmap_set_bits(priv->regmap,
+-				      QCA8K_PORT_LOOKUP_CTRL(i),
+-				      BIT(port));
+-		if (ret)
+-			return ret;
+-		port_mask |= BIT(i);
+-	}
+-
+-	/* Add all other ports to this ports portvlan mask */
+-	ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
+-			QCA8K_PORT_LOOKUP_MEMBER, port_mask);
+-
+-	return ret;
++	return qca8k_update_port_member(priv, port, bridge.dev, true);
+ }
+ 
+ void qca8k_port_bridge_leave(struct dsa_switch *ds, int port,
+ 			     struct dsa_bridge bridge)
+ {
+ 	struct qca8k_priv *priv = ds->priv;
+-	int cpu_port, i;
+-
+-	cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
+-
+-	for (i = 0; i < QCA8K_NUM_PORTS; i++) {
+-		if (i == port)
+-			continue;
+-		if (dsa_is_cpu_port(ds, i))
+-			continue;
+-		if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
+-			continue;
+-		/* Remove this port to the portvlan mask of the other ports
+-		 * in the bridge
+-		 */
+-		regmap_clear_bits(priv->regmap,
+-				  QCA8K_PORT_LOOKUP_CTRL(i),
+-				  BIT(port));
+-	}
++	int err;
+ 
+-	/* Set the cpu port to be the only one in the portvlan mask of
+-	 * this port
+-	 */
+-	qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
+-		  QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port));
++	err = qca8k_update_port_member(priv, port, bridge.dev, false);
++	if (err)
++		dev_err(priv->dev,
++			"Failed to update switch config for bridge leave: %d\n",
++			err);
+ }
+ 
+ void qca8k_port_fast_age(struct dsa_switch *ds, int port)
diff --git a/target/linux/generic/backport-6.6/793-03-v6.11-net-dsa-qca8k-add-support-for-bridge-port-isolation.patch b/target/linux/generic/backport-6.6/793-03-v6.11-net-dsa-qca8k-add-support-for-bridge-port-isolation.patch
new file mode 100644
index 0000000000..263fe10d4b
--- /dev/null
+++ b/target/linux/generic/backport-6.6/793-03-v6.11-net-dsa-qca8k-add-support-for-bridge-port-isolation.patch
@@ -0,0 +1,91 @@
+From 422b64025ec10981c48f9367311846bf4bd38042 Mon Sep 17 00:00:00 2001
+Message-ID: <422b64025ec10981c48f9367311846bf4bd38042.1728674648.git.mschiffer at universe-factory.net>
+In-Reply-To: <e85d3e6fea05c8ae21a40809a3c6b7adc97411c7.1728674648.git.mschiffer at universe-factory.net>
+References: <e85d3e6fea05c8ae21a40809a3c6b7adc97411c7.1728674648.git.mschiffer at universe-factory.net>
+From: Matthias Schiffer <mschiffer at universe-factory.net>
+Date: Thu, 20 Jun 2024 19:25:50 +0200
+Subject: [PATCH] net: dsa: qca8k: add support for bridge port isolation
+
+Remove a pair of ports from the port matrix when both ports have the
+isolated flag set.
+
+Signed-off-by: Matthias Schiffer <mschiffer at universe-factory.net>
+Reviewed-by: Wojciech Drewek <wojciech.drewek at intel.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/dsa/qca/qca8k-common.c | 22 ++++++++++++++++++++--
+ drivers/net/dsa/qca/qca8k.h        |  1 +
+ 2 files changed, 21 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/dsa/qca/qca8k-common.c
++++ b/drivers/net/dsa/qca/qca8k-common.c
+@@ -619,6 +619,7 @@ static int qca8k_update_port_member(stru
+ 				    const struct net_device *bridge_dev,
+ 				    bool join)
+ {
++	bool isolated = !!(priv->port_isolated_map & BIT(port)), other_isolated;
+ 	struct dsa_port *dp = dsa_to_port(priv->ds, port), *other_dp;
+ 	u32 port_mask = BIT(dp->cpu_dp->index);
+ 	int i, ret;
+@@ -633,10 +634,12 @@ static int qca8k_update_port_member(stru
+ 		if (!dsa_port_offloads_bridge_dev(other_dp, bridge_dev))
+ 			continue;
+ 
++		other_isolated = !!(priv->port_isolated_map & BIT(i));
++
+ 		/* Add/remove this port to/from the portvlan mask of the other
+ 		 * ports in the bridge
+ 		 */
+-		if (join) {
++		if (join && !(isolated && other_isolated)) {
+ 			port_mask |= BIT(i);
+ 			ret = regmap_set_bits(priv->regmap,
+ 					      QCA8K_PORT_LOOKUP_CTRL(i),
+@@ -662,7 +665,7 @@ int qca8k_port_pre_bridge_flags(struct d
+ 				struct switchdev_brport_flags flags,
+ 				struct netlink_ext_ack *extack)
+ {
+-	if (flags.mask & ~BR_LEARNING)
++	if (flags.mask & ~(BR_LEARNING | BR_ISOLATED))
+ 		return -EINVAL;
+ 
+ 	return 0;
+@@ -672,6 +675,7 @@ int qca8k_port_bridge_flags(struct dsa_s
+ 			    struct switchdev_brport_flags flags,
+ 			    struct netlink_ext_ack *extack)
+ {
++	struct qca8k_priv *priv = ds->priv;
+ 	int ret;
+ 
+ 	if (flags.mask & BR_LEARNING) {
+@@ -680,6 +684,20 @@ int qca8k_port_bridge_flags(struct dsa_s
+ 		if (ret)
+ 			return ret;
+ 	}
++
++	if (flags.mask & BR_ISOLATED) {
++		struct dsa_port *dp = dsa_to_port(ds, port);
++		struct net_device *bridge_dev = dsa_port_bridge_dev_get(dp);
++
++		if (flags.val & BR_ISOLATED)
++			priv->port_isolated_map |= BIT(port);
++		else
++			priv->port_isolated_map &= ~BIT(port);
++
++		ret = qca8k_update_port_member(priv, port, bridge_dev, true);
++		if (ret)
++			return ret;
++	}
+ 
+ 	return 0;
+ }
+--- a/drivers/net/dsa/qca/qca8k.h
++++ b/drivers/net/dsa/qca/qca8k.h
+@@ -451,6 +451,7 @@ struct qca8k_priv {
+ 	 * Bit 1: port enabled. Bit 0: port disabled.
+ 	 */
+ 	u8 port_enabled_map;
++	u8 port_isolated_map;
+ 	struct qca8k_ports_config ports_config;
+ 	struct regmap *regmap;
+ 	struct mii_bus *bus;
diff --git a/target/linux/generic/pending-6.6/711-01-net-dsa-qca8k-implement-lag_fdb_add-del-ops.patch b/target/linux/generic/pending-6.6/711-01-net-dsa-qca8k-implement-lag_fdb_add-del-ops.patch
index 3197aea091..8d815dd2f2 100644
--- a/target/linux/generic/pending-6.6/711-01-net-dsa-qca8k-implement-lag_fdb_add-del-ops.patch
+++ b/target/linux/generic/pending-6.6/711-01-net-dsa-qca8k-implement-lag_fdb_add-del-ops.patch
@@ -27,7 +27,7 @@ Signed-off-by: Christian Marangi <ansuelsmth at gmail.com>
  	.port_mirror_add	= qca8k_port_mirror_add,
 --- a/drivers/net/dsa/qca/qca8k-common.c
 +++ b/drivers/net/dsa/qca/qca8k-common.c
-@@ -1215,6 +1215,42 @@ int qca8k_port_lag_leave(struct dsa_swit
+@@ -1235,6 +1235,42 @@ int qca8k_port_lag_leave(struct dsa_swit
  	return qca8k_lag_refresh_portmap(ds, port, lag, true);
  }
  
@@ -72,7 +72,7 @@ Signed-off-by: Christian Marangi <ansuelsmth at gmail.com>
  	u32 val;
 --- a/drivers/net/dsa/qca/qca8k.h
 +++ b/drivers/net/dsa/qca/qca8k.h
-@@ -590,5 +590,11 @@ int qca8k_port_lag_join(struct dsa_switc
+@@ -591,5 +591,11 @@ int qca8k_port_lag_join(struct dsa_switc
  			struct netlink_ext_ack *extack);
  int qca8k_port_lag_leave(struct dsa_switch *ds, int port,
  			 struct dsa_lag lag);
diff --git a/target/linux/ipq40xx/patches-6.6/706-net-dsa-qca8k-add-IPQ4019-built-in-switch-support.patch b/target/linux/ipq40xx/patches-6.6/706-net-dsa-qca8k-add-IPQ4019-built-in-switch-support.patch
index 9bd5ca515e..76539cea88 100644
--- a/target/linux/ipq40xx/patches-6.6/706-net-dsa-qca8k-add-IPQ4019-built-in-switch-support.patch
+++ b/target/linux/ipq40xx/patches-6.6/706-net-dsa-qca8k-add-IPQ4019-built-in-switch-support.patch
@@ -67,24 +67,15 @@ Signed-off-by: Robert Marko <robert.marko at sartura.hr>
  		mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i);
  
  		if ((reg & mask) != mask) {
-@@ -653,7 +653,7 @@ int qca8k_port_bridge_join(struct dsa_sw
- 	cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
- 	port_mask = BIT(cpu_port);
+@@ -624,7 +624,7 @@ static int qca8k_update_port_member(stru
+ 	u32 port_mask = BIT(dp->cpu_dp->index);
+ 	int i, ret;
  
 -	for (i = 0; i < QCA8K_NUM_PORTS; i++) {
-+	for (i = 0; i < ds->num_ports; i++) {
- 		if (dsa_is_cpu_port(ds, i))
- 			continue;
- 		if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
-@@ -685,7 +685,7 @@ void qca8k_port_bridge_leave(struct dsa_
- 
- 	cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
- 
--	for (i = 0; i < QCA8K_NUM_PORTS; i++) {
-+	for (i = 0; i < ds->num_ports; i++) {
- 		if (dsa_is_cpu_port(ds, i))
++	for (i = 0; i < priv->ds->num_ports; i++) {
+ 		if (i == port)
  			continue;
- 		if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
+ 		if (dsa_is_cpu_port(priv->ds, i))
 --- /dev/null
 +++ b/drivers/net/dsa/qca/qca8k-ipq4019.c
 @@ -0,0 +1,948 @@
@@ -1119,7 +1110,7 @@ Signed-off-by: Robert Marko <robert.marko at sartura.hr>
  enum {
  	QCA8K_PORT_SPEED_10M = 0,
  	QCA8K_PORT_SPEED_100M = 1,
-@@ -466,6 +518,10 @@ struct qca8k_priv {
+@@ -467,6 +519,10 @@ struct qca8k_priv {
  	struct qca8k_pcs pcs_port_6;
  	const struct qca8k_match_data *info;
  	struct qca8k_led ports_led[QCA8K_LED_COUNT];




More information about the lede-commits mailing list