* [PATCH net-next v4 0/8] net: dsa: motorcomm: Add BR_FLOOD and BR_MCAST_FLOOD support
@ 2026-11-07 12:16 David Yang
2026-11-07 12:16 ` [PATCH net-next v4 1/8] net: dsa: motorcomm: Fix VLAN SVL and learn limit definitions David Yang
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: David Yang @ 2026-11-07 12:16 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
Offload BR_FLOOD / BR_MCAST_FLOOD to the hardware for bridges when
feasible.
v4:
- fix VID 0 handling
- reset port flags on bridge leaving
- remove local cpu_ports_mask
- translate FDB VID for VLAN-unaware bridges
- limit offloading to exactly one bridge
v3: https://lore.kernel.org/r/20261103140109.874443-1-mmyangfl@gmail.com
- refactor port isolation and filter action for standalone ports
- recompute flags when a port leaves bridge
- honor BR_HAIRPIN
v2: https://lore.kernel.org/r/20261011030228.2761810-1-mmyangfl@gmail.com
- fix build error
v1: https://lore.kernel.org/r/20261009005542.72860-1-mmyangfl@gmail.com
David Yang (8):
net: dsa: motorcomm: Fix VLAN SVL and learn limit definitions
net: dsa: motorcomm: Drop VID 0 VLAN table programming
net: dsa: motorcomm: Reset port flags on bridge leaving
net: dsa: motorcomm: Remove local cpu_ports_mask
net: dsa: motorcomm: Isolate all ports during chip setup
net: dsa: motorcomm: Rely on port isolation for conduit port
net: dsa: motorcomm: Translate FDB VID for VLAN-unaware bridges
net: dsa: motorcomm: Support BR_FLOOD and BR_MCAST_FLOOD offloading
drivers/net/dsa/motorcomm/chip.c | 293 +++++++++++++++++++++----------
drivers/net/dsa/motorcomm/chip.h | 10 +-
2 files changed, 208 insertions(+), 95 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH net-next v4 1/8] net: dsa: motorcomm: Fix VLAN SVL and learn limit definitions
2026-11-07 12:16 [PATCH net-next v4 0/8] net: dsa: motorcomm: Add BR_FLOOD and BR_MCAST_FLOOD support David Yang
@ 2026-11-07 12:16 ` David Yang
2026-11-07 12:16 ` [PATCH net-next v4 2/8] net: dsa: motorcomm: Drop VID 0 VLAN table programming David Yang
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: David Yang @ 2026-11-07 12:16 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
Bit 3 of the VLAN table control enables shared VLAN learning (IVL/SVL),
it has nothing to do with S-VLAN tagging, so name it SVL_EN rather than
SVLAN_EN.
Widen PORT_LEARN_LIMIT_M to the 13 bits up to LEARN_DROP_ON_EXCEEDED at
bit 2. Nothing uses it, so this is a no-op.
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/motorcomm/chip.c | 4 +---
drivers/net/dsa/motorcomm/chip.h | 4 ++--
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index 33e5fc127244..693564aeaec1 100644
--- a/drivers/net/dsa/motorcomm/chip.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -922,9 +922,7 @@ yt921x_vlan_aware_set(struct yt921x_priv *priv, int port, bool vlan_aware)
{
u32 ctrl;
- /* Abuse SVLAN for PCP parsing without polluting the FDB - it just works
- * despite YT921X_VLAN_CTRL_SVLAN_EN never being set
- */
+ /* Abuse SVLAN for PCP parsing without polluting the FDB */
if (!vlan_aware)
ctrl = YT921X_PORT_IGR_TPIDn_STAG(0);
else
diff --git a/drivers/net/dsa/motorcomm/chip.h b/drivers/net/dsa/motorcomm/chip.h
index fc315f1d8f87..d9425afc7bce 100644
--- a/drivers/net/dsa/motorcomm/chip.h
+++ b/drivers/net/dsa/motorcomm/chip.h
@@ -240,7 +240,7 @@ enum yt921x_app_selector {
#define YT921X_PORT_LEARN_SUSPEND_DROP_EN BIT(18)
#define YT921X_PORT_LEARN_DIS BIT(17)
#define YT921X_PORT_LEARN_LIMIT_EN BIT(16)
-#define YT921X_PORT_LEARN_LIMIT_M GENMASK(15, 8)
+#define YT921X_PORT_LEARN_LIMIT_M GENMASK(15, 3)
#define YT921X_PORT_LEARN_LIMIT(x) FIELD_PREP(YT921X_PORT_LEARN_LIMIT_M, (x))
#define YT921X_PORT_LEARN_DROP_ON_EXCEEDED BIT(2)
#define YT921X_PORT_LEARN_MODE_M GENMASK(1, 0)
@@ -357,7 +357,7 @@ enum yt921x_app_selector {
#define YT921X_VLAN_CTRLb_UNTAG_PORTn(port) BIT((port) + 8)
#define YT921X_VLAN_CTRLb_STP_ID_M GENMASK(7, 4)
#define YT921X_VLAN_CTRLb_STP_ID(x) FIELD_PREP(YT921X_VLAN_CTRLb_STP_ID_M, (x))
-#define YT921X_VLAN_CTRLb_SVLAN_EN BIT(3)
+#define YT921X_VLAN_CTRLb_SVL_EN BIT(3)
#define YT921X_VLAN_CTRLab_FID_M GENMASK_ULL(34, 23)
#define YT921X_VLAN_CTRLab_FID(x) FIELD_PREP(YT921X_VLAN_CTRLab_FID_M, (x))
#define YT921X_VLAN_CTRLa_LEARN_DIS BIT(22)
--
2.53.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH net-next v4 2/8] net: dsa: motorcomm: Drop VID 0 VLAN table programming
2026-11-07 12:16 [PATCH net-next v4 0/8] net: dsa: motorcomm: Add BR_FLOOD and BR_MCAST_FLOOD support David Yang
2026-11-07 12:16 ` [PATCH net-next v4 1/8] net: dsa: motorcomm: Fix VLAN SVL and learn limit definitions David Yang
@ 2026-11-07 12:16 ` David Yang
2026-11-07 12:16 ` [PATCH net-next v4 3/8] net: dsa: motorcomm: Reset port flags on bridge leaving David Yang
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: David Yang @ 2026-11-07 12:16 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
The VID 0 VLAN table entry is unreachable for priority-tagged frames:
the hardware classifies them to the port's PVID before the VLAN table
lookup, just like untagged frames (measured on YT9215S), so the VID 0
entry is never looked up. Drop the dead programming.
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/motorcomm/chip.c | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index 693564aeaec1..47f06945b8c4 100644
--- a/drivers/net/dsa/motorcomm/chip.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -2263,7 +2263,6 @@ static int yt921x_chip_setup_dsa(struct yt921x_priv *priv)
{
struct dsa_switch *ds = &priv->ds;
unsigned long cpu_ports_mask;
- u32 ctrls[2];
u32 ctrl;
int port;
int res;
@@ -2321,15 +2320,6 @@ static int yt921x_chip_setup_dsa(struct yt921x_priv *priv)
if (res)
return res;
- /* Tagged VID 0 should be treated as untagged, which confuses the
- * hardware a lot
- */
- ctrls[0] = YT921X_VLAN_CTRLa_LEARN_DIS | YT921X_VLAN_CTRLa_PORTS_M;
- ctrls[1] = 0;
- res = yt921x_reg64_write(priv, YT921X_VLANn_CTRL(0), ctrls);
- if (res)
- return res;
-
return 0;
}
--
2.53.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH net-next v4 3/8] net: dsa: motorcomm: Reset port flags on bridge leaving
2026-11-07 12:16 [PATCH net-next v4 0/8] net: dsa: motorcomm: Add BR_FLOOD and BR_MCAST_FLOOD support David Yang
2026-11-07 12:16 ` [PATCH net-next v4 1/8] net: dsa: motorcomm: Fix VLAN SVL and learn limit definitions David Yang
2026-11-07 12:16 ` [PATCH net-next v4 2/8] net: dsa: motorcomm: Drop VID 0 VLAN table programming David Yang
@ 2026-11-07 12:16 ` David Yang
2026-11-07 12:16 ` [PATCH net-next v4 4/8] net: dsa: motorcomm: Remove local cpu_ports_mask David Yang
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: David Yang @ 2026-11-07 12:16 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
DSA does not clear BR_HAIRPIN_MODE and BR_ISOLATED when a port leaves
a bridge, so the cached flags survive into the next bridge join and
program stale hairpin and port isolation state.
Reset them when leaving the bridge.
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/motorcomm/chip.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index 47f06945b8c4..c51491ef4dae 100644
--- a/drivers/net/dsa/motorcomm/chip.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -1158,10 +1158,17 @@ yt921x_dsa_port_vlan_add(struct dsa_switch *ds, int port,
static int yt921x_userport_standalone(struct yt921x_priv *priv, int port)
{
+ struct yt921x_port *pp = &priv->ports[port];
u32 mask;
u32 ctrl;
int res;
+ /* The return value got ignored by DSA core, reset flags before touching
+ * the hardware.
+ */
+ pp->hairpin = false;
+ pp->isolated = false;
+
ctrl = ~priv->cpu_ports_mask;
res = yt921x_reg_write(priv, YT921X_PORTn_ISOLATION(port), ctrl);
if (res)
--
2.53.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH net-next v4 4/8] net: dsa: motorcomm: Remove local cpu_ports_mask
2026-11-07 12:16 [PATCH net-next v4 0/8] net: dsa: motorcomm: Add BR_FLOOD and BR_MCAST_FLOOD support David Yang
` (2 preceding siblings ...)
2026-11-07 12:16 ` [PATCH net-next v4 3/8] net: dsa: motorcomm: Reset port flags on bridge leaving David Yang
@ 2026-11-07 12:16 ` David Yang
2026-11-07 12:16 ` [PATCH net-next v4 5/8] net: dsa: motorcomm: Isolate all ports during chip setup David Yang
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: David Yang @ 2026-11-07 12:16 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
Use dsa_cpu_ports() or dsa_is_cpu_port() instead for a clearer view of
code.
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/motorcomm/chip.c | 18 +++++++++---------
drivers/net/dsa/motorcomm/chip.h | 2 --
2 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index c51491ef4dae..8ab499611fbf 100644
--- a/drivers/net/dsa/motorcomm/chip.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -1003,7 +1003,7 @@ yt921x_vlan_add(struct yt921x_priv *priv, int port, u16 vid, bool untagged)
u32 ctrls[2];
masks[0] = YT921X_VLAN_CTRLa_PORTn(port) |
- YT921X_VLAN_CTRLa_PORTS(priv->cpu_ports_mask);
+ YT921X_VLAN_CTRLa_PORTS(dsa_cpu_ports(&priv->ds));
ctrls[0] = masks[0];
masks[1] = YT921X_VLAN_CTRLb_UNTAG_PORTn(port);
@@ -1159,6 +1159,7 @@ yt921x_dsa_port_vlan_add(struct dsa_switch *ds, int port,
static int yt921x_userport_standalone(struct yt921x_priv *priv, int port)
{
struct yt921x_port *pp = &priv->ports[port];
+ struct dsa_switch *ds = &priv->ds;
u32 mask;
u32 ctrl;
int res;
@@ -1169,7 +1170,7 @@ static int yt921x_userport_standalone(struct yt921x_priv *priv, int port)
pp->hairpin = false;
pp->isolated = false;
- ctrl = ~priv->cpu_ports_mask;
+ ctrl = ~dsa_cpu_ports(ds);
res = yt921x_reg_write(priv, YT921X_PORTn_ISOLATION(port), ctrl);
if (res)
return res;
@@ -1215,7 +1216,7 @@ static int yt921x_isolate(struct yt921x_priv *priv, int port)
mask = BIT(port);
for (int i = 0; i < YT921X_PORT_NUM; i++) {
- if ((BIT(i) & priv->cpu_ports_mask) || i == port)
+ if (dsa_is_cpu_port(&priv->ds, port) || i == port)
continue;
res = yt921x_reg_set_bits(priv, YT921X_PORTn_ISOLATION(i),
@@ -1232,7 +1233,7 @@ static int yt921x_isolate(struct yt921x_priv *priv, int port)
*/
static int yt921x_bridge(struct yt921x_priv *priv, u16 ports_mask)
{
- unsigned long targets_mask = ports_mask & ~priv->cpu_ports_mask;
+ unsigned long targets_mask = ports_mask & dsa_cpu_ports(&priv->ds);
u32 isolated_mask;
u32 ctrl;
int port;
@@ -1345,7 +1346,7 @@ yt921x_bridge_flags(struct yt921x_priv *priv, int port,
u32 ports_mask;
ports_mask = dsa_bridge_ports(ds, bdev);
- ports_mask |= priv->cpu_ports_mask;
+ ports_mask |= dsa_cpu_ports(ds);
res = yt921x_bridge(priv, ports_mask);
if (res)
return res;
@@ -1417,7 +1418,7 @@ yt921x_dsa_port_bridge_join(struct dsa_switch *ds, int port,
return 0;
ports_mask = dsa_bridge_ports(ds, bridge.dev);
- ports_mask |= priv->cpu_ports_mask;
+ ports_mask |= dsa_cpu_ports(ds);
mutex_lock(&priv->reg_lock);
res = yt921x_bridge_join(priv, port, ports_mask);
@@ -2275,10 +2276,10 @@ static int yt921x_chip_setup_dsa(struct yt921x_priv *priv)
int res;
/* Enable DSA */
- priv->cpu_ports_mask = dsa_cpu_ports(ds);
+ cpu_ports_mask = dsa_cpu_ports(ds);
ctrl = YT921X_EXT_CPU_PORT_TAG_EN | YT921X_EXT_CPU_PORT_PORT_EN |
- YT921X_EXT_CPU_PORT_PORT(__ffs(priv->cpu_ports_mask));
+ YT921X_EXT_CPU_PORT_PORT(__ffs(cpu_ports_mask));
res = yt921x_reg_write(priv, YT921X_EXT_CPU_PORT, ctrl);
if (res)
return res;
@@ -2315,7 +2316,6 @@ static int yt921x_chip_setup_dsa(struct yt921x_priv *priv)
/* Except for CPU ports, if any packets are sent via CPU ports without
* tag, they should be dropped.
*/
- cpu_ports_mask = priv->cpu_ports_mask;
for_each_set_bit(port, &cpu_ports_mask, YT921X_PORT_NUM) {
ctrl &= ~YT921X_ACT_UNK_ACTn_M(port);
ctrl |= YT921X_ACT_UNK_ACTn_DROP(port);
diff --git a/drivers/net/dsa/motorcomm/chip.h b/drivers/net/dsa/motorcomm/chip.h
index d9425afc7bce..ab6f28d057cb 100644
--- a/drivers/net/dsa/motorcomm/chip.h
+++ b/drivers/net/dsa/motorcomm/chip.h
@@ -509,8 +509,6 @@ struct yt921x_priv {
const struct yt921x_info *info;
unsigned int meter_slot_ns;
unsigned int port_shape_slot_ns;
- /* cache of dsa_cpu_ports(ds) */
- u16 cpu_ports_mask;
unsigned char cycle_ns;
/* protect the access to the switch registers */
--
2.53.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH net-next v4 5/8] net: dsa: motorcomm: Isolate all ports during chip setup
2026-11-07 12:16 [PATCH net-next v4 0/8] net: dsa: motorcomm: Add BR_FLOOD and BR_MCAST_FLOOD support David Yang
` (3 preceding siblings ...)
2026-11-07 12:16 ` [PATCH net-next v4 4/8] net: dsa: motorcomm: Remove local cpu_ports_mask David Yang
@ 2026-11-07 12:16 ` David Yang
2026-11-07 12:16 ` [PATCH net-next v4 6/8] net: dsa: motorcomm: Rely on port isolation for conduit port David Yang
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: David Yang @ 2026-11-07 12:16 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
Chip setup only blocks unknown unicast and unknown multicast frames,
leaving known multicast and broadcast open, though known multicast
cannot appear while the FDB is still empty.
Isolate every port right after the hardware reset, in preparation for
the isolation refactoring. Note that this only minimizes the window: a
reset always brings the hardware back to a dumb switch, so traffic can
leak before and during it.
Signed-off-by: David Yang <mmyangfl@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/motorcomm/chip.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index 8ab499611fbf..32701f9e687f 100644
--- a/drivers/net/dsa/motorcomm/chip.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -2227,6 +2227,7 @@ static int yt921x_chip_reset(struct yt921x_priv *priv)
{
struct device *dev = yt921x_priv_to_device(priv);
u16 eth_p_tag;
+ u32 ctrl;
u32 val;
int res;
@@ -2264,6 +2265,17 @@ static int yt921x_chip_reset(struct yt921x_priv *priv)
return -EINVAL;
}
+ /* Block all traffic as soon as we reset the hardware since it now acts
+ * as a dumb switch.
+ */
+ for (int port = 0; port < YT921X_PORT_NUM; port++) {
+ ctrl = ~(u32)0;
+ res = yt921x_reg_write(priv, YT921X_PORTn_ISOLATION(port),
+ ctrl);
+ if (res)
+ return res;
+ }
+
return 0;
}
--
2.53.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH net-next v4 6/8] net: dsa: motorcomm: Rely on port isolation for conduit port
2026-11-07 12:16 [PATCH net-next v4 0/8] net: dsa: motorcomm: Add BR_FLOOD and BR_MCAST_FLOOD support David Yang
` (4 preceding siblings ...)
2026-11-07 12:16 ` [PATCH net-next v4 5/8] net: dsa: motorcomm: Isolate all ports during chip setup David Yang
@ 2026-11-07 12:16 ` David Yang
2026-11-07 12:16 ` [PATCH net-next v4 7/8] net: dsa: motorcomm: Translate FDB VID for VLAN-unaware bridges David Yang
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: David Yang @ 2026-11-07 12:16 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
With every port fully isolated during chip setup, the conduit port
already gets its one-way isolation (drop all packets without tag)
there. Skip the redundant handling elsewhere.
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/motorcomm/chip.c | 52 +++++++++-----------------------
1 file changed, 14 insertions(+), 38 deletions(-)
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index 32701f9e687f..1b05ac29ecd7 100644
--- a/drivers/net/dsa/motorcomm/chip.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -1125,7 +1125,7 @@ yt921x_dsa_port_vlan_add(struct dsa_switch *ds, int port,
int res;
/* CPU port is supposed to be a member of every VLAN; see
- * yt921x_vlan_add() and yt921x_port_setup()
+ * yt921x_vlan_add()
*/
if (dsa_is_cpu_port(ds, port))
return 0;
@@ -1170,10 +1170,17 @@ static int yt921x_userport_standalone(struct yt921x_priv *priv, int port)
pp->hairpin = false;
pp->isolated = false;
- ctrl = ~dsa_cpu_ports(ds);
- res = yt921x_reg_write(priv, YT921X_PORTn_ISOLATION(port), ctrl);
- if (res)
- return res;
+ /* Conduit ports should by controlled by tagging completely, skip
+ * setting isolation to preserve the one-way isolation installed
+ * by yt921x_chip_reset().
+ */
+ if (dsa_is_cpu_port(ds, port)) {
+ ctrl = ~dsa_cpu_ports(ds);
+ res = yt921x_reg_write(priv, YT921X_PORTn_ISOLATION(port),
+ ctrl);
+ if (res)
+ return res;
+ }
/* Turn off FDB learning to prevent FDB pollution */
mask = YT921X_PORT_LEARN_DIS;
@@ -1948,8 +1955,6 @@ yt921x_dsa_phylink_get_caps(struct dsa_switch *ds, int port,
static int yt921x_port_setup(struct yt921x_priv *priv, int port)
{
- struct dsa_switch *ds = &priv->ds;
- u32 ctrl;
int res;
res = yt921x_userport_standalone(priv, port);
@@ -1963,27 +1968,6 @@ static int yt921x_port_setup(struct yt921x_priv *priv, int port)
if (res)
return res;
- if (dsa_is_cpu_port(ds, port)) {
- /* Egress of CPU port is supposed to be completely controlled
- * via tagging, so set to oneway isolated (drop all packets
- * without tag).
- */
- ctrl = ~(u32)0;
- res = yt921x_reg_write(priv, YT921X_PORTn_ISOLATION(port),
- ctrl);
- if (res)
- return res;
-
- /* To simplify FDB "isolation" simulation, we also disable
- * learning on the CPU port, and let software identify packets
- * towarding CPU (either trapped or a static FDB entry is
- * matched, no matter which bridge that entry is for), which is
- * already done by yt921x_userport_standalone(). As a result,
- * VLAN-awareness becomes unrelated on the CPU port (set to
- * VLAN-unaware by the way).
- */
- }
-
return 0;
}
@@ -2282,9 +2266,8 @@ static int yt921x_chip_reset(struct yt921x_priv *priv)
static int yt921x_chip_setup_dsa(struct yt921x_priv *priv)
{
struct dsa_switch *ds = &priv->ds;
- unsigned long cpu_ports_mask;
+ u32 cpu_ports_mask;
u32 ctrl;
- int port;
int res;
/* Enable DSA */
@@ -2302,7 +2285,7 @@ static int yt921x_chip_setup_dsa(struct yt921x_priv *priv)
if (res)
return res;
- ctrl = GENMASK(10, 0);
+ ctrl = GENMASK(10, 0) & ~cpu_ports_mask;
res = yt921x_reg_write(priv, YT921X_FILTER_UNK_UCAST, ctrl);
if (res)
return res;
@@ -2325,13 +2308,6 @@ static int yt921x_chip_setup_dsa(struct yt921x_priv *priv)
ctrl = 0;
for (int i = 0; i < YT921X_PORT_NUM; i++)
ctrl |= YT921X_ACT_UNK_ACTn_TRAP(i);
- /* Except for CPU ports, if any packets are sent via CPU ports without
- * tag, they should be dropped.
- */
- for_each_set_bit(port, &cpu_ports_mask, YT921X_PORT_NUM) {
- ctrl &= ~YT921X_ACT_UNK_ACTn_M(port);
- ctrl |= YT921X_ACT_UNK_ACTn_DROP(port);
- }
res = yt921x_reg_write(priv, YT921X_ACT_UNK_UCAST, ctrl);
if (res)
return res;
--
2.53.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH net-next v4 7/8] net: dsa: motorcomm: Translate FDB VID for VLAN-unaware bridges
2026-11-07 12:16 [PATCH net-next v4 0/8] net: dsa: motorcomm: Add BR_FLOOD and BR_MCAST_FLOOD support David Yang
` (5 preceding siblings ...)
2026-11-07 12:16 ` [PATCH net-next v4 6/8] net: dsa: motorcomm: Rely on port isolation for conduit port David Yang
@ 2026-11-07 12:16 ` David Yang
2026-11-07 12:16 ` [PATCH net-next v4 8/8] net: dsa: motorcomm: Support BR_FLOOD and BR_MCAST_FLOOD offloading David Yang
2026-11-07 12:21 ` [PATCH net-next v4 0/8] net: dsa: motorcomm: Add BR_FLOOD and BR_MCAST_FLOOD support netdev-bot+sinfo
8 siblings, 0 replies; 10+ messages in thread
From: David Yang @ 2026-11-07 12:16 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
A VLAN-unaware bridge reports VID 0 for its FDB entries, but lookups run
with the unaware FID (VID 4095). Entries added through switchdev were
installed under FID 0 and could never be hit by the hardware lookups.
Translate the unaware FID and VID 0 back and forth, so the software
mapping stays symmetric with the hardware lookups.
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/motorcomm/chip.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index 1b05ac29ecd7..e41fe4859bfe 100644
--- a/drivers/net/dsa/motorcomm/chip.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -590,6 +590,9 @@ yt921x_fdb_dump(struct yt921x_priv *priv, u16 ports_mask,
res = yt921x_fdb_read(priv, addr, &vid, &pmask, &index, &status);
if (res)
return res;
+
+ if (vid == YT921X_VID_UNWARE)
+ vid = 0;
if ((pmask & ports_mask) && !is_multicast_ether_addr(addr)) {
res = cb(addr, vid,
status == YT921X_FDB_ENTRY_STATUS_STATIC, data);
@@ -618,6 +621,8 @@ yt921x_fdb_dump(struct yt921x_priv *priv, u16 ports_mask,
if (!pmask)
break;
+ if (vid == YT921X_VID_UNWARE)
+ vid = 0;
if ((pmask & ports_mask) && !is_multicast_ether_addr(addr)) {
res = cb(addr, vid,
status == YT921X_FDB_ENTRY_STATUS_STATIC,
@@ -740,6 +745,10 @@ yt921x_fdb_leave(struct yt921x_priv *priv, const unsigned char *addr,
u32 val;
int res;
+ /* See yt921x_fdb_join() */
+ if (!vid)
+ vid = YT921X_VID_UNWARE;
+
/* Check for presence */
res = yt921x_fdb_has(priv, addr, vid, &index);
if (res)
@@ -782,6 +791,13 @@ yt921x_fdb_join(struct yt921x_priv *priv, const unsigned char *addr, u16 vid,
u32 val2;
int res;
+ /* A vlan-unaware bridge reports vid 0, but untagged lookups on its
+ * ports run with the unaware FID; map so that static entries match the
+ * hardware lookups.
+ */
+ if (!vid)
+ vid = YT921X_VID_UNWARE;
+
/* Check for presence */
res = yt921x_fdb_has(priv, addr, vid, &index);
if (res)
--
2.53.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH net-next v4 8/8] net: dsa: motorcomm: Support BR_FLOOD and BR_MCAST_FLOOD offloading
2026-11-07 12:16 [PATCH net-next v4 0/8] net: dsa: motorcomm: Add BR_FLOOD and BR_MCAST_FLOOD support David Yang
` (6 preceding siblings ...)
2026-11-07 12:16 ` [PATCH net-next v4 7/8] net: dsa: motorcomm: Translate FDB VID for VLAN-unaware bridges David Yang
@ 2026-11-07 12:16 ` David Yang
2026-11-07 12:21 ` [PATCH net-next v4 0/8] net: dsa: motorcomm: Add BR_FLOOD and BR_MCAST_FLOOD support netdev-bot+sinfo
8 siblings, 0 replies; 10+ messages in thread
From: David Yang @ 2026-11-07 12:16 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
Let the hardware flood the unknown unicast / multicast for the port if:
- the switch carries only one bridge, otherwise frames hitting FDB entry
from another bridge will be dropped;
- all other ports in the bridge have BR_FLOOD / BR_MCAST_FLOOD enabled;
- the port is not hairpined, as the hardware never floods back to its
ingress port.
This should cover most single-bridge usage. Other data paths remain
unchanged in terms of behavior.
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/motorcomm/chip.c | 180 +++++++++++++++++++++++++------
drivers/net/dsa/motorcomm/chip.h | 4 +
2 files changed, 150 insertions(+), 34 deletions(-)
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index e41fe4859bfe..5fed5b5a2feb 100644
--- a/drivers/net/dsa/motorcomm/chip.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -1185,6 +1185,8 @@ static int yt921x_userport_standalone(struct yt921x_priv *priv, int port)
*/
pp->hairpin = false;
pp->isolated = false;
+ pp->flood = true;
+ pp->mcast_flood = true;
/* Conduit ports should by controlled by tagging completely, skip
* setting isolation to preserve the one-way isolation installed
@@ -1209,13 +1211,17 @@ static int yt921x_userport_standalone(struct yt921x_priv *priv, int port)
if (res)
return res;
- /* Unrelated since learning is off and all packets are trapped;
- * set it anyway
+ /* Unrelated since learning is off and there is only one possible
+ * destination; set it anyway
*/
res = yt921x_port_set_pvid(priv, port, YT921X_VID_UNWARE);
if (res)
return res;
+ /* Also unrelated for FILTER_UNK_UCAST / FILTER_UNK_MCAST since all
+ * packets are handled by software
+ */
+
return 0;
}
@@ -1232,6 +1238,96 @@ static int yt921x_userport_bridge(struct yt921x_priv *priv, int port)
return 0;
}
+/* ports_mask is optional */
+static int yt921x_bridge_flood_set(struct yt921x_priv *priv, u16 ports_mask)
+{
+ struct dsa_bridge *bridges[YT921X_PORT_NUM];
+ struct dsa_switch *ds = &priv->ds;
+ struct dsa_port *dp;
+ unsigned int count;
+ u32 ctrl;
+ int res;
+ int ret;
+
+ /* Offloading is only enabled if there is at most 1 bridge - see the
+ * cross-bridge FDB mismatch below. (0 does nothing, of course.)
+ */
+ count = 0;
+ dsa_switch_for_each_user_port(dp, ds) {
+ unsigned int i;
+
+ if (!dp->bridge)
+ continue;
+
+ for (i = 0; i < count; i++)
+ if (bridges[i] == dp->bridge)
+ break;
+ if (i == count) {
+ bridges[count] = dp->bridge;
+ count++;
+ }
+ }
+
+ ret = 0;
+ if (count != 1) {
+ ctrl = ~(u32)0;
+ res = yt921x_reg_write(priv, YT921X_FILTER_UNK_UCAST, ctrl);
+ if (res)
+ ret = res;
+ res = yt921x_reg_write(priv, YT921X_FILTER_UNK_MCAST, ctrl);
+ if (res)
+ ret = res;
+ return ret;
+ }
+
+ ports_mask &= ~dsa_cpu_ports(ds);
+ if (!ports_mask)
+ ports_mask = dsa_bridge_ports(ds, bridges[0]->dev);
+
+ for (int type = 0; type < 2; type++) {
+ unsigned long targets_mask = ports_mask;
+ u16 flood_mask;
+ u32 addr;
+ int port;
+
+ addr = !type ? YT921X_FILTER_UNK_UCAST :
+ YT921X_FILTER_UNK_MCAST;
+
+ flood_mask = 0;
+ for_each_set_bit(port, &targets_mask, YT921X_PORT_NUM) {
+ struct yt921x_port *pp = &priv->ports[port];
+
+ if (!type ? pp->flood : pp->mcast_flood)
+ flood_mask |= BIT(port);
+ }
+
+ ctrl = 0;
+ for_each_set_bit(port, &targets_mask, YT921X_PORT_NUM) {
+ struct yt921x_port *pp = &priv->ports[port];
+
+ /* Hardware never floods back to its own ingress port,
+ * keep hairpin port trapped: the software bridge does
+ * deliver a flood there.
+ */
+ if (!pp->hairpin && !((flood_mask ^ ports_mask) &
+ ~BIT(port)))
+ continue;
+
+ ctrl |= BIT(port);
+ }
+
+ /* ACT_UNK is fixed to TRAP for every port, see
+ * yt921x_chip_setup_dsa().
+ */
+
+ res = yt921x_reg_update_bits(priv, addr, ports_mask, ctrl);
+ if (res)
+ ret = res;
+ }
+
+ return ret;
+}
+
static int yt921x_isolate(struct yt921x_priv *priv, int port)
{
u32 mask;
@@ -1306,6 +1402,10 @@ static int yt921x_bridge_leave(struct yt921x_priv *priv, int port)
if (res)
return res;
+ res = yt921x_bridge_flood_set(priv, 0);
+ if (res)
+ return res;
+
return 0;
}
@@ -1322,6 +1422,10 @@ yt921x_bridge_join(struct yt921x_priv *priv, int port, u16 ports_mask)
if (res)
return res;
+ res = yt921x_bridge_flood_set(priv, ports_mask);
+ if (res)
+ return res;
+
return 0;
}
@@ -1330,7 +1434,12 @@ yt921x_bridge_flags(struct yt921x_priv *priv, int port,
struct switchdev_brport_flags flags)
{
struct yt921x_port *pp = &priv->ports[port];
- bool do_flush;
+ struct dsa_switch *ds = &priv->ds;
+ bool change_isolated = false;
+ bool change_flood = false;
+ struct net_device *bdev;
+ struct dsa_port *dp;
+ u32 ports_mask;
u32 mask;
int res;
@@ -1344,36 +1453,48 @@ yt921x_bridge_flags(struct yt921x_priv *priv, int port,
return res;
}
- /* BR_FLOOD, BR_MCAST_FLOOD: see the comment where ACT_UNK_ACTn_TRAP
- * is set
- */
-
/* BR_BCAST_FLOOD: we can filter bcast, but cannot trap them */
- do_flush = false;
if (flags.mask & BR_HAIRPIN_MODE) {
pp->hairpin = flags.val & BR_HAIRPIN_MODE;
- do_flush = true;
+ change_isolated = true;
+ /* Hairpin also affects flood flags */
+ change_flood = true;
}
if (flags.mask & BR_ISOLATED) {
pp->isolated = flags.val & BR_ISOLATED;
- do_flush = true;
+ change_isolated = true;
}
- if (do_flush) {
- struct dsa_switch *ds = &priv->ds;
- struct dsa_port *dp = dsa_to_port(ds, port);
- struct net_device *bdev;
- bdev = dsa_port_bridge_dev_get(dp);
- if (bdev) {
- u32 ports_mask;
+ if (flags.mask & BR_FLOOD) {
+ pp->flood = flags.val & BR_FLOOD;
+ change_flood = true;
+ }
+ if (flags.mask & BR_MCAST_FLOOD) {
+ pp->mcast_flood = flags.val & BR_MCAST_FLOOD;
+ change_flood = true;
+ }
- ports_mask = dsa_bridge_ports(ds, bdev);
- ports_mask |= dsa_cpu_ports(ds);
- res = yt921x_bridge(priv, ports_mask);
- if (res)
- return res;
- }
+ if (!change_isolated && !change_flood)
+ return 0;
+
+ dp = dsa_to_port(ds, port);
+ bdev = dsa_port_bridge_dev_get(dp);
+ if (!bdev)
+ return 0;
+
+ ports_mask = dsa_bridge_ports(ds, bdev);
+ ports_mask |= dsa_cpu_ports(ds);
+
+ if (change_isolated) {
+ res = yt921x_bridge(priv, ports_mask);
+ if (res)
+ return res;
+ }
+ if (change_flood) {
+ res = yt921x_bridge_flood_set(priv, ports_mask);
+ if (res)
+ return res;
}
return 0;
@@ -2301,14 +2422,6 @@ static int yt921x_chip_setup_dsa(struct yt921x_priv *priv)
if (res)
return res;
- ctrl = GENMASK(10, 0) & ~cpu_ports_mask;
- res = yt921x_reg_write(priv, YT921X_FILTER_UNK_UCAST, ctrl);
- if (res)
- return res;
- res = yt921x_reg_write(priv, YT921X_FILTER_UNK_MCAST, ctrl);
- if (res)
- return res;
-
/* YT921x does not support native DSA port bridging, so we use port
* isolation to emulate it. However, be especially careful that port
* isolation takes _after_ FDB lookups, i.e. if an FDB entry (from
@@ -2317,9 +2430,8 @@ static int yt921x_chip_setup_dsa(struct yt921x_priv *priv)
* the "bridged" ports, thus we need to trap and handle those packets by
* software.
*
- * If there is no more than one bridge, we might be able to drop them
- * directly given some conditions are met, but we trap them in all cases
- * for now.
+ * The flood action is offloaded to the hardware by fixing UNK_ACT to
+ * TRAP and toggling the FILTER_UNK on the appropriate ports.
*/
ctrl = 0;
for (int i = 0; i < YT921X_PORT_NUM; i++)
diff --git a/drivers/net/dsa/motorcomm/chip.h b/drivers/net/dsa/motorcomm/chip.h
index ab6f28d057cb..98fe8250e99a 100644
--- a/drivers/net/dsa/motorcomm/chip.h
+++ b/drivers/net/dsa/motorcomm/chip.h
@@ -461,6 +461,10 @@ struct yt921x_port {
bool hairpin:1;
/* BR_ISOLATED */
bool isolated:1;
+ /* BR_FLOOD */
+ bool flood:1;
+ /* BR_MCAST_FLOOD */
+ bool mcast_flood:1;
unsigned short acl_cnt;
--
2.53.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next v4 0/8] net: dsa: motorcomm: Add BR_FLOOD and BR_MCAST_FLOOD support
2026-11-07 12:16 [PATCH net-next v4 0/8] net: dsa: motorcomm: Add BR_FLOOD and BR_MCAST_FLOOD support David Yang
` (7 preceding siblings ...)
2026-11-07 12:16 ` [PATCH net-next v4 8/8] net: dsa: motorcomm: Support BR_FLOOD and BR_MCAST_FLOOD offloading David Yang
@ 2026-11-07 12:21 ` netdev-bot+sinfo
8 siblings, 0 replies; 10+ messages in thread
From: netdev-bot+sinfo @ 2026-11-07 12:21 UTC (permalink / raw)
To: David Yang
Cc: netdev, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
Hi!
This is an automated message. This series looks like a fix, but its
commit messages seem to be missing some information:
- Whether the issue was actually triggered, or is only theoretical
(e.g. found by code inspection). If it was triggered please include
the symptoms, like the stack trace or error messages.
Please do not repost the series just to address the above. Instead,
reply to this email with the missing information, so that reviewers
can take it into account. If the series needs another revision for
other reasons, please include the information in the commit messages
then.
The evaluation is done by an LLM so it may be wrong, if you think
that is the case please reply and explain.
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-11-07 12:21 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-07 12:16 [PATCH net-next v4 0/8] net: dsa: motorcomm: Add BR_FLOOD and BR_MCAST_FLOOD support David Yang
2026-11-07 12:16 ` [PATCH net-next v4 1/8] net: dsa: motorcomm: Fix VLAN SVL and learn limit definitions David Yang
2026-11-07 12:16 ` [PATCH net-next v4 2/8] net: dsa: motorcomm: Drop VID 0 VLAN table programming David Yang
2026-11-07 12:16 ` [PATCH net-next v4 3/8] net: dsa: motorcomm: Reset port flags on bridge leaving David Yang
2026-11-07 12:16 ` [PATCH net-next v4 4/8] net: dsa: motorcomm: Remove local cpu_ports_mask David Yang
2026-11-07 12:16 ` [PATCH net-next v4 5/8] net: dsa: motorcomm: Isolate all ports during chip setup David Yang
2026-11-07 12:16 ` [PATCH net-next v4 6/8] net: dsa: motorcomm: Rely on port isolation for conduit port David Yang
2026-11-07 12:16 ` [PATCH net-next v4 7/8] net: dsa: motorcomm: Translate FDB VID for VLAN-unaware bridges David Yang
2026-11-07 12:16 ` [PATCH net-next v4 8/8] net: dsa: motorcomm: Support BR_FLOOD and BR_MCAST_FLOOD offloading David Yang
2026-11-07 12:21 ` [PATCH net-next v4 0/8] net: dsa: motorcomm: Add BR_FLOOD and BR_MCAST_FLOOD support netdev-bot+sinfo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®