[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