Skip to contentSkip to conversation

net: dsa: mt7530: assorted fixes

PATCH Superseded Daniel Golle 3 participants 10 messages May 5 – May 7

Subsystems (5)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore

Daniel Golle

author maintainer
#0 lore raw

cover net: dsa: mt7530: assorted fixes

A batch of small, independent fixes for the MediaTek MT7530 family DSA driver, addressing long-standing correctness issues that surface on hardware with bridge VLAN filtering enabled, on link-local frame reception, and during bridge join/leave transitions.

Daniel Golle (4):
net: dsa: mt7530: fix FDB entries not aging out with short timeout
net: dsa: mt7530: preserve VLAN tags on trapped link-local frames
net: dsa: mt7530: fix CPU port VLAN not being reset to unaware
net: dsa: mt7530: clear flood flags on bridge leave

Edward Parker (1):
net: dsa: mt7530: untag VLAN-aware bridge PVID

 drivers/net/dsa/mt7530.c | 153 +++++++++++++++++++++++----------------
 1 file changed, 90 insertions(+), 63 deletions(-)
Signature · 1 line
2.54.0
author maintainer
#1 lore raw

PATCH 1/5 net: dsa: mt7530: fix FDB entries not aging out with short timeout

When setting a low ageing time such as 10 seconds, the algorithm in mt7530_set_ageing_time() finds AGE_CNT=0 and AGE_UNIT=9 as the first exact match (starting the search from tmp_age_count=0).

On the MT7530/MT7531 hardware, the per-entry aging counter is initialized to AGE_CNT when a MAC address is learned. With AGE_CNT=0, new entries start with a counter value of 0, which the hardware treats as "already aged" and never removes, effectively disabling aging.

Fix this by starting the search from tmp_age_count=1 to ensure entries always have a non-zero initial aging counter. For a 10-second ageing time this yields AGE_CNT=1 and AGE_UNIT=4 instead: the timer ticks every 5 seconds and entries are removed after 2 ticks.

Fixes ea6d5c924e39 ("net: dsa: mt7530: support setting ageing time")
---
 drivers/net/dsa/mt7530.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/net/dsa/mt7530.c +6 -2
index 44d670904ad8..b1903da7d500 100644
@@ -1027,8 +1027,12 @@ mt7530_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
 	if (secs < 1 || secs > (AGE_CNT_MAX + 1) * (AGE_UNIT_MAX + 1))
 		return -ERANGE;
 
-	/* iterate through all possible age_count to find the closest pair */
-	for (tmp_age_count = 0; tmp_age_count <= AGE_CNT_MAX; ++tmp_age_count) {
+	/* Iterate through all possible age_count values to find the closest
+	 * pair. Start from 1 because the per-entry aging counter is
+	 * initialized to AGE_CNT and a value of 0 means the entry will
+	 * never be aged out.
+	 */
+	for (tmp_age_count = 1; tmp_age_count <= AGE_CNT_MAX; ++tmp_age_count) {
 		unsigned int tmp_age_unit = secs / (tmp_age_count + 1) - 1;
 
 		if (tmp_age_unit <= AGE_UNIT_MAX) {
Signature · 1 line
2.54.0
maintainer
#2 lore raw

Re: [PATCH net 1/5] net: dsa: mt7530: fix FDB entries not aging out with short timeout

Quoted 29 lines · Daniel Golle

When setting a low ageing time such as 10 seconds, the algorithm in mt7530_set_ageing_time() finds AGE_CNT=0 and AGE_UNIT=9 as the first exact match (starting the search from tmp_age_count=0).

On the MT7530/MT7531 hardware, the per-entry aging counter is initialized to AGE_CNT when a MAC address is learned. With AGE_CNT=0, new entries start with a counter value of 0, which the hardware treats as "already aged" and never removes, effectively disabling aging.

Fix this by starting the search from tmp_age_count=1 to ensure entries always have a non-zero initial aging counter. For a 10-second ageing time this yields AGE_CNT=1 and AGE_UNIT=4 instead: the timer ticks every 5 seconds and entries are removed after 2 ticks.

Fixes ea6d5c924e39 ("net: dsa: mt7530: support setting ageing time")
---
 drivers/net/dsa/mt7530.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/net/dsa/mt7530.c +0 -1
index 44d670904ad8..b1903da7d500 100644
@@ -1027,8 +1027,12 @@ mt7530_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
 	if (secs < 1 || secs > (AGE_CNT_MAX + 1) * (AGE_UNIT_MAX + 1))
 		return -ERANGE;
 
-	/* iterate through all possible age_count to find the closest pair */

drivers/net/dsa/mt7530.c mt7530_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) · line 1038

Quoted 10 lines
drivers/net/dsa/mt7530.c +6 -1
-	for (tmp_age_count = 0; tmp_age_count <= AGE_CNT_MAX; ++tmp_age_count) {
+	/* Iterate through all possible age_count values to find the closest
+	 * pair. Start from 1 because the per-entry aging counter is
+	 * initialized to AGE_CNT and a value of 0 means the entry will
+	 * never be aged out.
+	 */
+	for (tmp_age_count = 1; tmp_age_count <= AGE_CNT_MAX; ++tmp_age_count) {
 		unsigned int tmp_age_unit = secs / (tmp_age_count + 1) - 1;
 
 		if (tmp_age_unit <= AGE_UNIT_MAX) {

Sashiko noted that the above will have problem with secs == 1:

What happens here if secs is 1?
Since the bounds check at the start of the function allows secs == 1, tmp_age_unit would be calculated as 1 / (1 + 1) - 1, which evaluates to 0 - 1, resulting in an unsigned underflow to UINT_MAX.

Quoted 1 line

if (tmp_age_unit <= AGE_UNIT_MAX) {

Because UINT_MAX is greater than AGE_UNIT_MAX, this condition will fail for all iterations of the loop.
[ ... ]

Quoted 1 line

mt7530_write(priv, MT7530_AAC, AGE_CNT(age_count) | AGE_UNIT(age_unit));

If the loop exits without ever finding a match and entering the if block, age_count and age_unit will remain uninitialized. Could this result in uninitialized stack variables being written to the MT7530_AAC hardware register?

/P

author maintainer
#3 lore raw

PATCH 2/5 net: dsa: mt7530: preserve VLAN tags on trapped link-local frames

In reply to Daniel Golle

The BPC, RGAC1 and RGAC2 registers control the handling of link-local frames with reserved MAC DAs (01:80:C2:00:00:0x). These frames are correctly trapped to the CPU port, but the egress VLAN tag attribute was set to MT7530_VLAN_EG_UNTAGGED which causes the switch to strip any VLAN tags from trapped frames before they reach the CPU.

This causes VLAN-tagged link-local frames (STP BPDUs, LLDP, PTP Peer Delay Requests) to arrive at the CPU without their VLAN tag, so they are delivered to the base network interface instead of the VLAN sub-interface. The DSA local_termination selftest confirms this: all link-local protocol tests on VLAN upper interfaces fail.

Set the EG_TAG attribute to MT7530_VLAN_EG_DISABLED (system default) so that the switch does not modify VLAN tags in trapped frames. This way VLAN-tagged frames retain their original tag and are delivered to the correct VLAN sub-interface, matching the behavior of non-trapped frames which pass through without VLAN tag modification.

Fixes 69ddba9d170b ("net: dsa: mt7530: fix handling of all link-local frames")
---
 drivers/net/dsa/mt7530.c | 27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)
drivers/net/dsa/mt7530.c +15 -12
index b1903da7d500..a696c8736982 100644
@@ -1300,37 +1300,40 @@ static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface)
 static void
 mt753x_trap_frames(struct mt7530_priv *priv)
 {
-	/* Trap 802.1X PAE frames and BPDUs to the CPU port(s) and egress them
-	 * VLAN-untagged.
+	/* Trap 802.1X PAE frames and BPDUs to the CPU port(s) and egress
+	 * them with the EG_TAG attribute set to disabled (system default)
+	 * so that any VLAN tags in the frame are not modified by the
+	 * switch egress VLAN tag processing. This preserves VLAN tags
+	 * for reception on VLAN sub-interfaces.
 	 */
 	mt7530_rmw(priv, MT753X_BPC,
 		   PAE_BPDU_FR | PAE_EG_TAG_MASK | PAE_PORT_FW_MASK |
 			   BPDU_EG_TAG_MASK | BPDU_PORT_FW_MASK,
-		   PAE_BPDU_FR | PAE_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
+		   PAE_BPDU_FR | PAE_EG_TAG(MT7530_VLAN_EG_DISABLED) |
 			   PAE_PORT_FW(TO_CPU_FW_CPU_ONLY) |
-			   BPDU_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
+			   BPDU_EG_TAG(MT7530_VLAN_EG_DISABLED) |
 			   TO_CPU_FW_CPU_ONLY);
 
-	/* Trap frames with :01 and :02 MAC DAs to the CPU port(s) and egress
-	 * them VLAN-untagged.
+	/* Trap frames with :01 and :02 MAC DAs to the CPU port(s) and
+	 * egress them with EG_TAG disabled.
 	 */
 	mt7530_rmw(priv, MT753X_RGAC1,
 		   R02_BPDU_FR | R02_EG_TAG_MASK | R02_PORT_FW_MASK |
 			   R01_BPDU_FR | R01_EG_TAG_MASK | R01_PORT_FW_MASK,
-		   R02_BPDU_FR | R02_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
+		   R02_BPDU_FR | R02_EG_TAG(MT7530_VLAN_EG_DISABLED) |
 			   R02_PORT_FW(TO_CPU_FW_CPU_ONLY) | R01_BPDU_FR |
-			   R01_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
+			   R01_EG_TAG(MT7530_VLAN_EG_DISABLED) |
 			   TO_CPU_FW_CPU_ONLY);
 
-	/* Trap frames with :03 and :0E MAC DAs to the CPU port(s) and egress
-	 * them VLAN-untagged.
+	/* Trap frames with :03 and :0E MAC DAs to the CPU port(s) and
+	 * egress them with EG_TAG disabled.
 	 */
 	mt7530_rmw(priv, MT753X_RGAC2,
 		   R0E_BPDU_FR | R0E_EG_TAG_MASK | R0E_PORT_FW_MASK |
 			   R03_BPDU_FR | R03_EG_TAG_MASK | R03_PORT_FW_MASK,
-		   R0E_BPDU_FR | R0E_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
+		   R0E_BPDU_FR | R0E_EG_TAG(MT7530_VLAN_EG_DISABLED) |
 			   R0E_PORT_FW(TO_CPU_FW_CPU_ONLY) | R03_BPDU_FR |
-			   R03_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
+			   R03_EG_TAG(MT7530_VLAN_EG_DISABLED) |
 			   TO_CPU_FW_CPU_ONLY);
 }
 
Signature · 1 line
2.54.0
maintainer
#4 lore raw

Re: [PATCH net 2/5] net: dsa: mt7530: preserve VLAN tags on trapped link-local frames

Hey Daniel.

Quoted 12 lines · Daniel Golle

The BPC, RGAC1 and RGAC2 registers control the handling of link-local frames with reserved MAC DAs (01:80:C2:00:00:0x). These frames are correctly trapped to the CPU port, but the egress VLAN tag attribute was set to MT7530_VLAN_EG_UNTAGGED which causes the switch to strip any VLAN tags from trapped frames before they reach the CPU.

This causes VLAN-tagged link-local frames (STP BPDUs, LLDP, PTP Peer Delay Requests) to arrive at the CPU without their VLAN tag, so they are delivered to the base network interface instead of the VLAN sub-interface. The DSA local_termination selftest confirms this: all link-local protocol tests on VLAN upper interfaces fail.

Quoted 8 lines

Set the EG_TAG attribute to MT7530_VLAN_EG_DISABLED (system default) so that the switch does not modify VLAN tags in trapped frames. This way VLAN-tagged frames retain their original tag and are delivered to the correct VLAN sub-interface, matching the behavior of non-trapped frames which pass through without VLAN tag modification.

Fixes 69ddba9d170b ("net: dsa: mt7530: fix handling of all link-local frames")

Thank you for this patch. Could you please confirm that it conforms to the findings documented on this patch log?

https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=e8bf353577f382c7066c661fed41b2adc0fc7c40

Cheers.
Chester A.

author maintainer
#5 lore raw

Re: [PATCH net 2/5] net: dsa: mt7530: preserve VLAN tags on trapped link-local frames

Quoted 21 lines · Chester A. Unal

Hey Daniel.

Quoted 18 lines · Daniel Golle

The BPC, RGAC1 and RGAC2 registers control the handling of link-local frames with reserved MAC DAs (01:80:C2:00:00:0x). These frames are correctly trapped to the CPU port, but the egress VLAN tag attribute was set to MT7530_VLAN_EG_UNTAGGED which causes the switch to strip any VLAN tags from trapped frames before they reach the CPU.

This causes VLAN-tagged link-local frames (STP BPDUs, LLDP, PTP Peer Delay Requests) to arrive at the CPU without their VLAN tag, so they are delivered to the base network interface instead of the VLAN sub-interface. The DSA local_termination selftest confirms this: all link-local protocol tests on VLAN upper interfaces fail.

Set the EG_TAG attribute to MT7530_VLAN_EG_DISABLED (system default) so that the switch does not modify VLAN tags in trapped frames. This way VLAN-tagged frames retain their original tag and are delivered to the correct VLAN sub-interface, matching the behavior of non-trapped frames which pass through without VLAN tag modification.

Quoted 7 lines
Quoted 2 lines
Fixes 69ddba9d170b ("net: dsa: mt7530: fix handling of all link-local frames")

Thank you for this patch. Could you please confirm that it conforms to the findings documented on this patch log?

https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=e8bf353577f382c7066c661fed41b2adc0fc7c40

Yes. Combining VLAN CTAG and DSA tag into single "mess" tag is what the MT7530 hardware does, and also what tag_mtk.c expects, and mtk_eth_soc "special tag" feature handles well.

I've found, addressed and verified all the issues in the series using the DSA selftests in tools/testing/selftest/drivers/net/dsa, ie. running bridge_vlan_aware.sh, bridge_vlan_unaware.sh and local_termination.sh in a loop, and random order, on BPi-R3 (MT7531) and BPi-R4 (MT7988).

With the series applied many of the previously failing tests are now passing.

maintainer Acked-by
#6 lore raw

Re: [PATCH net 2/5] net: dsa: mt7530: preserve VLAN tags on trapped link-local frames

Quoted 34 lines · Daniel Golle
Quoted 21 lines · Chester A. Unal

Hey Daniel.

Quoted 18 lines · Daniel Golle

The BPC, RGAC1 and RGAC2 registers control the handling of link-local frames with reserved MAC DAs (01:80:C2:00:00:0x). These frames are correctly trapped to the CPU port, but the egress VLAN tag attribute was set to MT7530_VLAN_EG_UNTAGGED which causes the switch to strip any VLAN tags from trapped frames before they reach the CPU.

This causes VLAN-tagged link-local frames (STP BPDUs, LLDP, PTP Peer Delay Requests) to arrive at the CPU without their VLAN tag, so they are delivered to the base network interface instead of the VLAN sub-interface. The DSA local_termination selftest confirms this: all link-local protocol tests on VLAN upper interfaces fail.

Set the EG_TAG attribute to MT7530_VLAN_EG_DISABLED (system default) so that the switch does not modify VLAN tags in trapped frames. This way VLAN-tagged frames retain their original tag and are delivered to the correct VLAN sub-interface, matching the behavior of non-trapped frames which pass through without VLAN tag modification.

Quoted 7 lines
Quoted 2 lines
Fixes 69ddba9d170b ("net: dsa: mt7530: fix handling of all link-local frames")

Thank you for this patch. Could you please confirm that it conforms to the findings documented on this patch log?

https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=e8bf353577f382c7066c661fed41b2adc0fc7c40

Yes. Combining VLAN CTAG and DSA tag into single "mess" tag is what the MT7530 hardware does, and also what tag_mtk.c expects, and mtk_eth_soc "special tag" feature handles well.

Quoted 7 lines

I've found, addressed and verified all the issues in the series using the DSA selftests in tools/testing/selftest/drivers/net/dsa, ie. running bridge_vlan_aware.sh, bridge_vlan_unaware.sh and local_termination.sh in a loop, and random order, on BPi-R3 (MT7531) and BPi-R4 (MT7988).

With the series applied many of the previously failing tests are now passing.

Great to hear!

Chester A.

author maintainer
#7 lore raw

PATCH 3/5 net: dsa: mt7530: fix CPU port VLAN not being reset to unaware

In reply to Daniel Golle

After a VLAN-aware bridge is destroyed, creating any VLAN-unaware bridge loses all connectivity. The VID 0 VLAN table entry used by VLAN-unaware ports in FALLBACK mode gets corrupted during VLAN-aware
operation: mt7530_hw_vlan_add() overwrites its EG_CON flag with VTAG_EN and bridge teardown removes ports from its PORT_MEM.

The cleanup code that should restore it never runs because the current port's dp->vlan_filtering flag is still true when checked (DSA updates it only after the driver callback returns). Even when restored, the deferred VLAN deletion events from the switchdev workqueue can corrupt VID 0 again after the restoration.

Skip the current port in the all_user_ports_removed check, call mt7530_setup_vlan0() to restore the VID 0 entry, and protect VID 0 from being modified by bridge VLAN operations in port_vlan_add and port_vlan_del since it is managed exclusively by mt7530_setup_vlan0().

Remove the CPU port PCR and PVC register writes which were clobbering PORT_VLAN mode and VLAN_ATTR with wrong values.

Fixes 83163f7dca56 ("net: dsa: mediatek: add VLAN support for MT7530")
---
 drivers/net/dsa/mt7530.c | 111 ++++++++++++++++++++++-----------------
 1 file changed, 62 insertions(+), 49 deletions(-)
drivers/net/dsa/mt7530.c +62 -49
index a696c8736982..7cd8566a31e6 100644
@@ -1623,6 +1623,49 @@ mt7530_port_bridge_join(struct dsa_switch *ds, int port,
 	return 0;
 }
 
+static int
+mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid)
+{
+	struct mt7530_dummy_poll p;
+	u32 val;
+	int ret;
+
+	val = VTCR_BUSY | VTCR_FUNC(cmd) | vid;
+	mt7530_write(priv, MT7530_VTCR, val);
+
+	INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_VTCR);
+	ret = readx_poll_timeout(_mt7530_read, &p, val,
+				 !(val & VTCR_BUSY), 20, 20000);
+	if (ret < 0) {
+		dev_err(priv->dev, "poll timeout\n");
+		return ret;
+	}
+
+	val = mt7530_read(priv, MT7530_VTCR);
+	if (val & VTCR_INVALID) {
+		dev_err(priv->dev, "read VTCR invalid\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+mt7530_setup_vlan0(struct mt7530_priv *priv)
+{
+	u32 val;
+
+	/* Validate the entry with independent learning, keep the original
+	 * ingress tag attribute.
+	 */
+	val = IVL_MAC | EG_CON | PORT_MEM(MT7530_ALL_MEMBERS) | FID(FID_BRIDGED) |
+	      VLAN_VALID;
+	mt7530_write(priv, MT7530_VAWD1, val);
+	mt7530_write(priv, MT7530_VAWD2, 0);
+
+	return mt7530_vlan_cmd(priv, MT7530_VTCR_WR_VID, 0);
+}
+
 static void
 mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port)
 {
@@ -1648,6 +1691,8 @@ mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port)
 		   G0_PORT_VID_DEF);
 
 	for (i = 0; i < priv->ds->num_ports; i++) {
+		if (i == port)
+			continue;
 		if (dsa_is_user_port(ds, i) &&
 		    dsa_port_is_vlan_filtering(dsa_to_port(ds, i))) {
 			all_user_ports_removed = false;
@@ -1659,13 +1704,9 @@ mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port)
 	 * the CPU port get out of VLAN filtering mode.
 	 */
 	if (all_user_ports_removed) {
-		struct dsa_port *dp = dsa_to_port(ds, port);
-		struct dsa_port *cpu_dp = dp->cpu_dp;
-
-		mt7530_write(priv, MT7530_PCR_P(cpu_dp->index),
-			     PCR_MATRIX(dsa_user_ports(priv->ds)));
-		mt7530_write(priv, MT7530_PVC_P(cpu_dp->index), PORT_SPEC_TAG
-			     | PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
+		mutex_lock(&priv->reg_mutex);
+		mt7530_setup_vlan0(priv);
+		mutex_unlock(&priv->reg_mutex);
 	}
 }
 
@@ -1853,33 +1894,6 @@ mt7530_port_mdb_del(struct dsa_switch *ds, int port,
 	return ret;
 }
 
-static int
-mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid)
-{
-	struct mt7530_dummy_poll p;
-	u32 val;
-	int ret;
-
-	val = VTCR_BUSY | VTCR_FUNC(cmd) | vid;
-	mt7530_write(priv, MT7530_VTCR, val);
-
-	INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_VTCR);
-	ret = readx_poll_timeout(_mt7530_read, &p, val,
-				 !(val & VTCR_BUSY), 20, 20000);
-	if (ret < 0) {
-		dev_err(priv->dev, "poll timeout\n");
-		return ret;
-	}
-
-	val = mt7530_read(priv, MT7530_VTCR);
-	if (val & VTCR_INVALID) {
-		dev_err(priv->dev, "read VTCR invalid\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
 static int
 mt7530_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
 			   struct netlink_ext_ack *extack)
@@ -1984,21 +1998,6 @@ mt7530_hw_vlan_update(struct mt7530_priv *priv, u16 vid,
 	mt7530_vlan_cmd(priv, MT7530_VTCR_WR_VID, vid);
 }
 
-static int
-mt7530_setup_vlan0(struct mt7530_priv *priv)
-{
-	u32 val;
-
-	/* Validate the entry with independent learning, keep the original
-	 * ingress tag attribute.
-	 */
-	val = IVL_MAC | EG_CON | PORT_MEM(MT7530_ALL_MEMBERS) | FID(FID_BRIDGED) |
-	      VLAN_VALID;
-	mt7530_write(priv, MT7530_VAWD1, val);
-
-	return mt7530_vlan_cmd(priv, MT7530_VTCR_WR_VID, 0);
-}
-
 static int
 mt7530_port_vlan_add(struct dsa_switch *ds, int port,
 		     const struct switchdev_obj_port_vlan *vlan,
@@ -2011,9 +2010,18 @@ mt7530_port_vlan_add(struct dsa_switch *ds, int port,
 
 	mutex_lock(&priv->reg_mutex);
 
+	/* VID 0 is managed exclusively by mt7530_setup_vlan0() for
+	 * VLAN-unaware bridge operation. Don't let the bridge overwrite
+	 * its EG_CON flag with VTAG_EN and corrupt PORT_MEM.
+	 */
+	if (vlan->vid == 0)
+		goto skip_vlan_table;
+
 	mt7530_hw_vlan_entry_init(&new_entry, port, untagged);
 	mt7530_hw_vlan_update(priv, vlan->vid, &new_entry, mt7530_hw_vlan_add);
 
+skip_vlan_table:
+
 	if (pvid) {
 		priv->ports[port].pvid = vlan->vid;
 
@@ -2053,10 +2061,15 @@ mt7530_port_vlan_del(struct dsa_switch *ds, int port,
 
 	mutex_lock(&priv->reg_mutex);
 
+	/* VID 0 is managed exclusively by mt7530_setup_vlan0(). */
+	if (vlan->vid == 0)
+		goto skip_vlan_table;
+
 	mt7530_hw_vlan_entry_init(&target_entry, port, 0);
 	mt7530_hw_vlan_update(priv, vlan->vid, &target_entry,
 			      mt7530_hw_vlan_del);
 
+skip_vlan_table:
 	/* PVID is being restored to the default whenever the PVID port
 	 * is being removed from the VLAN.
 	 */
Signature · 1 line
2.54.0
author maintainer
#8 lore raw

PATCH 4/5 net: dsa: mt7530: clear flood flags on bridge leave

In reply to Daniel Golle

Flood flags set by port_bridge_flags persist after a port leaves the bridge, causing unknown unicast to be forwarded to standalone ports.

Clear UNU_FFP, UNM_FFP and BC_FFP in port_bridge_leave so that the port returns to its initial state without flooding.

Fixes 5a30833b9a16 ("net: dsa: mt7530: support MDB and bridge flag operations")
---
 drivers/net/dsa/mt7530.c | 5 +++++
 1 file changed, 5 insertions(+)
drivers/net/dsa/mt7530.c +5 -0
index 7cd8566a31e6..2e5337186800 100644
@@ -1767,6 +1767,11 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
 	mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
 		   MT7530_PORT_MATRIX_MODE);
 
+	/* Clear flood flags so they don't persist across bridge leave */
+	mt7530_clear(priv, MT753X_MFC,
+		     UNU_FFP(BIT(port)) | UNM_FFP(BIT(port)) |
+		     BC_FFP(BIT(port)));
+
 	mutex_unlock(&priv->reg_mutex);
 }
 
Signature · 1 line
2.54.0
author maintainer
#9 lore raw

PATCH 5/5 net: dsa: mt7530: untag VLAN-aware bridge PVID

In reply to Daniel Golle

From: Edward Parker <[email protected]>

With bridge VLAN filtering enabled on a port configured as untagged member of the bridge PVID, ingress untagged frames do not reach the corresponding bridge VLAN upper interface (br-lan.<vid>). ARP and similar traffic is visible on the physical port but not delivered to the VLAN sub-interface.

The MT7530/MT7531 forwards frames to the CPU port with the user port's PVID tag applied even when the frame ingressed untagged on the wire, because the CPU port is set to MT7530_VLAN_EG_CONSISTENT and is a tagged member of the VLAN entry created for the bridge VLAN. The DSA core then sees a hwaccel-tagged frame whose VID matches the port's PVID, which the bridge does not treat as the untagged-on-the-wire frame that the user expects.

Set ds->untag_vlan_aware_bridge_pvid in the mt7530 and mt7531 setup paths so the DSA core strips that hwaccel tag in software when the parsed VID matches the bridge port's PVID, restoring the on-the-wire frame as the bridge expects to see it.

Fixes 83163f7dca56 ("net: dsa: mediatek: add VLAN support for MT7530")
[[email protected]: improve commit message]
---
 drivers/net/dsa/mt7530.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/net/dsa/mt7530.c +2 -0
index 2e5337186800..4b7e5398b211 100644
@@ -2452,6 +2452,7 @@ mt7530_setup(struct dsa_switch *ds)
 	}
 
 	ds->assisted_learning_on_cpu_port = true;
+	ds->untag_vlan_aware_bridge_pvid = true;
 	ds->mtu_enforcement_ingress = true;
 
 	if (priv->id == ID_MT7530) {
@@ -2641,6 +2642,7 @@ mt7531_setup_common(struct dsa_switch *ds)
 	int ret, i;
 
 	ds->assisted_learning_on_cpu_port = true;
+	ds->untag_vlan_aware_bridge_pvid = true;
 	ds->mtu_enforcement_ingress = true;
 
 	mt753x_trap_frames(priv);
Signature · 1 line
2.54.0