[openwrt/openwrt] kernel: Backport mv88e6xxx patch to keep pvid at 0 if VLAN-unaware and remove hack

LEDE Commits lede-commits at lists.infradead.org
Sun Mar 27 09:39:17 PDT 2022


dangole pushed a commit to openwrt/openwrt.git, branch master:
https://git.openwrt.org/9caa6f0aa742253901c72f43eebecd2c8da5f127

commit 9caa6f0aa742253901c72f43eebecd2c8da5f127
Author: Marek Behún <kabel at kernel.org>
AuthorDate: Mon Mar 21 17:53:10 2022 +0100

    kernel: Backport mv88e6xxx patch to keep pvid at 0 if VLAN-unaware and remove hack
    
    Backport patch
      8b6836d82470 ("net: dsa: mv88e6xxx: keep the pvid at 0 when VLAN-unaware")
    from 5.15.
    
    Keeping the pvid at 0 when VLAN-unaware makes it possible to drop the
    hack introduced in commit 920eaab1d817 ("kernel: DSA roaming fix for
    Marvell mv88e6xxx"). Dropping the hack makes it possible to use VLAN
    interfaces with VID 1 on DSA ports without problems with FDB.
    
    Signed-off-by: Marek Behún <kabel at kernel.org>
---
 ...8e6xxx-keep-the-pvid-at-0-when-VLAN-unawa.patch | 236 +++++++++++++++++++++
 .../710-net-dsa-mv88e6xxx-default-VID-1.patch      |  18 --
 2 files changed, 236 insertions(+), 18 deletions(-)

diff --git a/target/linux/generic/backport-5.10/774-v5.15-net-dsa-mv88e6xxx-keep-the-pvid-at-0-when-VLAN-unawa.patch b/target/linux/generic/backport-5.10/774-v5.15-net-dsa-mv88e6xxx-keep-the-pvid-at-0-when-VLAN-unawa.patch
new file mode 100644
index 0000000000..c5b006493c
--- /dev/null
+++ b/target/linux/generic/backport-5.10/774-v5.15-net-dsa-mv88e6xxx-keep-the-pvid-at-0-when-VLAN-unawa.patch
@@ -0,0 +1,236 @@
+From 675992be6f7b603b8cfda4678f173e1021fc1ab6 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean at nxp.com>
+Date: Thu, 7 Oct 2021 19:47:10 +0300
+Subject: [PATCH] net: dsa: mv88e6xxx: keep the pvid at 0 when VLAN-unaware
+
+The VLAN support in mv88e6xxx has a loaded history. Commit 2ea7a679ca2a
+("net: dsa: Don't add vlans when vlan filtering is disabled") noticed
+some issues with VLAN and decided the best way to deal with them was to
+make the DSA core ignore VLANs added by the bridge while VLAN awareness
+is turned off. Those issues were never explained, just presented as
+"at least one corner case".
+
+That approach had problems of its own, presented by
+commit 54a0ed0df496 ("net: dsa: provide an option for drivers to always
+receive bridge VLANs") for the DSA core, followed by
+commit 1fb74191988f ("net: dsa: mv88e6xxx: fix vlan setup") which
+applied ds->configure_vlan_while_not_filtering = true for mv88e6xxx in
+particular.
+
+We still don't know what corner case Andrew saw when he wrote
+commit 2ea7a679ca2a ("net: dsa: Don't add vlans when vlan filtering is
+disabled"), but Tobias now reports that when we use TX forwarding
+offload, pinging an external station from the bridge device is broken if
+the front-facing DSA user port has flooding turned off. The full
+description is in the link below, but for short, when a mv88e6xxx port
+is under a VLAN-unaware bridge, it inherits that bridge's pvid.
+So packets ingressing a user port will be classified to e.g. VID 1
+(assuming that value for the bridge_default_pvid), whereas when
+tag_dsa.c xmits towards a user port, it always sends packets using a VID
+of 0 if that port is standalone or under a VLAN-unaware bridge - or at
+least it did so prior to commit d82f8ab0d874 ("net: dsa: tag_dsa:
+offload the bridge forwarding process").
+
+In any case, when there is a conversation between the CPU and a station
+connected to a user port, the station's MAC address is learned in VID 1
+but the CPU tries to transmit through VID 0. The packets reach the
+intended station, but via flooding and not by virtue of matching the
+existing ATU entry.
+
+DSA has established (and enforced in other drivers: sja1105, felix,
+mt7530) that a VLAN-unaware port should use a private pvid, and not
+inherit the one from the bridge. The bridge's pvid should only be
+inherited when that bridge is VLAN-aware, so all state transitions need
+to be handled. On the other hand, all bridge VLANs should sit in the VTU
+starting with the moment when the bridge offloads them via switchdev,
+they are just not used.
+
+This solves the problem that Tobias sees because packets ingressing on
+VLAN-unaware user ports now get classified to VID 0, which is also the
+VID used by tag_dsa.c on xmit.
+
+Fixes: d82f8ab0d874 ("net: dsa: tag_dsa: offload the bridge forwarding process")
+Link: https://patchwork.kernel.org/project/netdevbpf/patch/20211003222312.284175-2-vladimir.oltean@nxp.com/#24491503
+Reported-by: Tobias Waldekranz <tobias at waldekranz.com>
+Signed-off-by: Vladimir Oltean <vladimir.oltean at nxp.com>
+Signed-off-by: Jakub Kicinski <kuba at kernel.org>
+---
+ drivers/net/dsa/mv88e6xxx/chip.c | 56 +++++++++++++++++++++++++++++---
+ drivers/net/dsa/mv88e6xxx/chip.h |  6 ++++
+ drivers/net/dsa/mv88e6xxx/port.c | 21 ++++++++++++
+ drivers/net/dsa/mv88e6xxx/port.h |  2 ++
+ 4 files changed, 81 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
+index 1992be77522a..a77c86e0321d 100644
+--- a/drivers/net/dsa/mv88e6xxx/chip.c
++++ b/drivers/net/dsa/mv88e6xxx/chip.c
+@@ -1586,6 +1586,26 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
+ 	return 0;
+ }
+ 
++static int mv88e6xxx_port_commit_pvid(struct mv88e6xxx_chip *chip, int port)
++{
++	struct dsa_port *dp = dsa_to_port(chip->ds, port);
++	struct mv88e6xxx_port *p = &chip->ports[port];
++	bool drop_untagged = false;
++	u16 pvid = 0;
++	int err;
++
++	if (dp->bridge_dev && br_vlan_enabled(dp->bridge_dev)) {
++		pvid = p->bridge_pvid.vid;
++		drop_untagged = !p->bridge_pvid.valid;
++	}
++
++	err = mv88e6xxx_port_set_pvid(chip, port, pvid);
++	if (err)
++		return err;
++
++	return mv88e6xxx_port_drop_untagged(chip, port, drop_untagged);
++}
++
+ static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
+ 					 bool vlan_filtering,
+ 					 struct switchdev_trans *trans)
+@@ -1599,7 +1619,16 @@ static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
+ 		return chip->info->max_vid ? 0 : -EOPNOTSUPP;
+ 
+ 	mv88e6xxx_reg_lock(chip);
++
+ 	err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
++	if (err)
++		goto unlock;
++
++	err = mv88e6xxx_port_commit_pvid(chip, port);
++	if (err)
++		goto unlock;
++
++unlock:
+ 	mv88e6xxx_reg_unlock(chip);
+ 
+ 	return err;
+@@ -1982,8 +2011,10 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
+ 	struct mv88e6xxx_chip *chip = ds->priv;
+ 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
+ 	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
++	struct mv88e6xxx_port *p = &chip->ports[port];
+ 	bool warn;
+ 	u8 member;
++	int err;
+ 	u16 vid;
+ 
+ 	if (!chip->info->max_vid)
+@@ -2008,9 +2039,23 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
+ 			dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port,
+ 				vid, untagged ? 'u' : 't');
+ 
+-	if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end))
+-		dev_err(ds->dev, "p%d: failed to set PVID %d\n", port,
+-			vlan->vid_end);
++	if (pvid) {
++		p->bridge_pvid.vid = vlan->vid_end;
++		p->bridge_pvid.valid = true;
++
++		err = mv88e6xxx_port_commit_pvid(chip, port);
++		if (err)
++			dev_err(ds->dev, "p%d: failed to set PVID %d", port,
++				vlan->vid_end);
++	} else if (vlan->vid_end && p->bridge_pvid.vid == vlan->vid_end) {
++		/* The old pvid was reinstalled as a non-pvid VLAN */
++		p->bridge_pvid.valid = false;
++
++		err = mv88e6xxx_port_commit_pvid(chip, port);
++		if (err)
++			dev_err(ds->dev, "p%d: failed to unset PVID %d", port,
++				vlan->vid_end);
++	}
+ 
+ 	mv88e6xxx_reg_unlock(chip);
+ }
+@@ -2061,6 +2106,7 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
+ 				   const struct switchdev_obj_port_vlan *vlan)
+ {
+ 	struct mv88e6xxx_chip *chip = ds->priv;
++	struct mv88e6xxx_port *p = &chip->ports[port];
+ 	u16 pvid, vid;
+ 	int err = 0;
+ 
+@@ -2079,7 +2125,9 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
+ 			goto unlock;
+ 
+ 		if (vid == pvid) {
+-			err = mv88e6xxx_port_set_pvid(chip, port, 0);
++			p->bridge_pvid.valid = false;
++
++			err = mv88e6xxx_port_commit_pvid(chip, port);
+ 			if (err)
+ 				goto unlock;
+ 		}
+diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
+index 51a7ff44478e..843803c3adf2 100644
+--- a/drivers/net/dsa/mv88e6xxx/chip.h
++++ b/drivers/net/dsa/mv88e6xxx/chip.h
+@@ -224,9 +224,15 @@ struct mv88e6xxx_policy {
+ 	u16 vid;
+ };
+ 
++struct mv88e6xxx_vlan {
++	u16	vid;
++	bool	valid;
++};
++
+ struct mv88e6xxx_port {
+ 	struct mv88e6xxx_chip *chip;
+ 	int port;
++	struct mv88e6xxx_vlan bridge_pvid;
+ 	u64 serdes_stats[2];
+ 	u64 atu_member_violation;
+ 	u64 atu_miss_violation;
+diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
+index dfd9e8292e9a..a7177aa254a8 100644
+--- a/drivers/net/dsa/mv88e6xxx/port.c
++++ b/drivers/net/dsa/mv88e6xxx/port.c
+@@ -1062,6 +1062,27 @@ int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,
+ 	return 0;
+ }
+ 
++int mv88e6xxx_port_drop_untagged(struct mv88e6xxx_chip *chip, int port,
++				 bool drop_untagged)
++{
++	u16 old, new;
++	int err;
++
++	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &old);
++	if (err)
++		return err;
++
++	if (drop_untagged)
++		new = old | MV88E6XXX_PORT_CTL2_DISCARD_UNTAGGED;
++	else
++		new = old & ~MV88E6XXX_PORT_CTL2_DISCARD_UNTAGGED;
++
++	if (new == old)
++		return 0;
++
++	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, new);
++}
++
+ int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port)
+ {
+ 	u16 reg;
+diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
+index 44d76ac973f6..3390517df42e 100644
+--- a/drivers/net/dsa/mv88e6xxx/port.h
++++ b/drivers/net/dsa/mv88e6xxx/port.h
+@@ -364,6 +364,8 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
+ 			      phy_interface_t mode);
+ int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
+ int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
++int mv88e6xxx_port_drop_untagged(struct mv88e6xxx_chip *chip, int port,
++				 bool drop_untagged);
+ int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port);
+ int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,
+ 				     int upstream_port);
+-- 
+2.34.1
+
diff --git a/target/linux/generic/hack-5.10/710-net-dsa-mv88e6xxx-default-VID-1.patch b/target/linux/generic/hack-5.10/710-net-dsa-mv88e6xxx-default-VID-1.patch
deleted file mode 100644
index 03725653f9..0000000000
--- a/target/linux/generic/hack-5.10/710-net-dsa-mv88e6xxx-default-VID-1.patch
+++ /dev/null
@@ -1,18 +0,0 @@
---- a/drivers/net/dsa/mv88e6xxx/chip.c
-+++ b/drivers/net/dsa/mv88e6xxx/chip.c
-@@ -2097,6 +2097,7 @@ static int mv88e6xxx_port_fdb_add(struct
- 	struct mv88e6xxx_chip *chip = ds->priv;
- 	int err;
- 
-+	vid = vid ? : 1;
- 	mv88e6xxx_reg_lock(chip);
- 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
- 					   MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
-@@ -2111,6 +2112,7 @@ static int mv88e6xxx_port_fdb_del(struct
- 	struct mv88e6xxx_chip *chip = ds->priv;
- 	int err;
- 
-+	vid = vid ? : 1;
- 	mv88e6xxx_reg_lock(chip);
- 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0);
- 	mv88e6xxx_reg_unlock(chip);




More information about the lede-commits mailing list