[openwrt/openwrt] realtek: 5.15: backport VLAN fix

LEDE Commits lede-commits at lists.infradead.org
Mon Sep 16 01:33:32 PDT 2024


robimarko pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/35e13244aab36958831195a1d2e152aa3ad0ab6c

commit 35e13244aab36958831195a1d2e152aa3ad0ab6c
Author: Markus Stockhausen <markus.stockhausen at gmx.de>
AuthorDate: Sat Sep 14 16:26:34 2024 -0400

    realtek: 5.15: backport VLAN fix
    
    With commit a22d359fa56fe0 VLAN handling was fixed for kernel 6.6.
    This restored network connectivity of the devices. For easy testing
    backport the fix for 5.15 too.
    
    Signed-off-by: Markus Stockhausen <markus.stockhausen at gmx.de>
    Link: https://github.com/openwrt/openwrt/pull/16391
    Signed-off-by: Robert Marko <robimarko at gmail.com>
---
 .../files-5.15/drivers/net/dsa/rtl83xx/dsa.c       | 71 ++++++++++++++--------
 1 file changed, 45 insertions(+), 26 deletions(-)

diff --git a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c
index 9eb444515f..ee87de8e07 100644
--- a/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c
+++ b/target/linux/realtek/files-5.15/drivers/net/dsa/rtl83xx/dsa.c
@@ -109,6 +109,20 @@ static enum dsa_tag_protocol rtl83xx_get_tag_protocol(struct dsa_switch *ds,
 	return DSA_TAG_PROTO_TRAILER;
 }
 
+static void rtl83xx_vlan_set_pvid(struct rtl838x_switch_priv *priv,
+				  int port, int pvid)
+{
+	/* Set both inner and outer PVID of the port */
+	priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_INNER, pvid);
+	priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_OUTER, pvid);
+	priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_INNER,
+					PBVLAN_MODE_UNTAG_AND_PRITAG);
+	priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_OUTER,
+					PBVLAN_MODE_UNTAG_AND_PRITAG);
+
+	priv->ports[port].pvid = pvid;
+}
+
 /* Initialize all VLANS */
 static void rtl83xx_vlan_setup(struct rtl838x_switch_priv *priv)
 {
@@ -132,17 +146,22 @@ static void rtl83xx_vlan_setup(struct rtl838x_switch_priv *priv)
 		info.l2_tunnel_list_id = -1;
 	}
 
-	/* Initialize all vlans 0-4095 */
-	for (int i = 0; i < MAX_VLANS; i ++)
+	/* Initialize normal VLANs 1-4095 */
+	for (int i = 1; i < MAX_VLANS; i ++)
 		priv->r->vlan_set_tagged(i, &info);
 
-	/* reset PVIDs; defaults to 1 on reset */
+	/*
+	 * Initialize the special VLAN 0 and reset PVIDs. The CPU port PVID
+	 * is applied to packets from the CPU for untagged destinations,
+	 * regardless if the actual ingress VID. Any port with untagged
+	 * egress VLAN(s) must therefore be a member of VLAN 0 to support
+	 * CPU port as ingress when VLAN filtering is enabled.
+	 */
 	for (int i = 0; i <= priv->cpu_port; i++) {
-		priv->r->vlan_port_pvid_set(i, PBVLAN_TYPE_INNER, 1);
-		priv->r->vlan_port_pvid_set(i, PBVLAN_TYPE_OUTER, 1);
-		priv->r->vlan_port_pvidmode_set(i, PBVLAN_TYPE_INNER, PBVLAN_MODE_UNTAG_AND_PRITAG);
-		priv->r->vlan_port_pvidmode_set(i, PBVLAN_TYPE_OUTER, PBVLAN_MODE_UNTAG_AND_PRITAG);
+		rtl83xx_vlan_set_pvid(priv, i, 0);
+		info.tagged_ports |= BIT_ULL(i);
 	}
+	priv->r->vlan_set_tagged(0, &info);
 
 	/* Set forwarding action based on inner VLAN tag */
 	for (int i = 0; i < priv->cpu_port; i++)
@@ -1392,20 +1411,6 @@ static int rtl83xx_vlan_prepare(struct dsa_switch *ds, int port,
 	return 0;
 }
 
-static void rtl83xx_vlan_set_pvid(struct rtl838x_switch_priv *priv,
-				  int port, int pvid)
-{
-	/* Set both inner and outer PVID of the port */
-	priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_INNER, pvid);
-	priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_OUTER, pvid);
-	priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_INNER,
-					PBVLAN_MODE_UNTAG_AND_PRITAG);
-	priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_OUTER,
-					PBVLAN_MODE_UNTAG_AND_PRITAG);
-
-	priv->ports[port].pvid = pvid;
-}
-
 static int rtl83xx_vlan_add(struct dsa_switch *ds, int port,
 			    const struct switchdev_obj_port_vlan *vlan,
 			    struct netlink_ext_ack *extack)
@@ -1417,7 +1422,8 @@ static int rtl83xx_vlan_add(struct dsa_switch *ds, int port,
 	pr_debug("%s port %d, vid %d, flags %x\n",
 		__func__, port, vlan->vid, vlan->flags);
 
-	if(!vlan->vid) return 0;
+	/* Let no one mess with our special VLAN 0 */
+	if (!vlan->vid) return 0;
 
 	if (vlan->vid > 4095) {
 		dev_err(priv->dev, "VLAN out of range: %d", vlan->vid);
@@ -1430,10 +1436,20 @@ static int rtl83xx_vlan_add(struct dsa_switch *ds, int port,
 
 	mutex_lock(&priv->reg_mutex);
 
-	if (vlan->flags & BRIDGE_VLAN_INFO_PVID)
-		rtl83xx_vlan_set_pvid(priv, port, vlan->vid);
-	else if (priv->ports[port].pvid == vlan->vid)
-		rtl83xx_vlan_set_pvid(priv, port, 0);
+	/*
+	 * Realtek switches copy frames as-is to/from the CPU. For a proper
+	 * VLAN handling the 12 bit RVID field (= VLAN id) for incoming traffic
+	 * and the 1 bit RVID_SEL field (0 = use inner tag, 1 = use outer tag)
+	 * for outgoing traffic of the CPU tag structure need to be handled. As
+	 * of now no such logic is in place. So for the CPU port keep the fixed
+	 * PVID=0 from initial setup in place and ignore all subsequent settings.
+	 */
+	if (port != priv->cpu_port) {
+		if (vlan->flags & BRIDGE_VLAN_INFO_PVID)
+			rtl83xx_vlan_set_pvid(priv, port, vlan->vid);
+		else if (priv->ports[port].pvid == vlan->vid)
+			rtl83xx_vlan_set_pvid(priv, port, 0);
+	}
 
 	/* Get port memberships of this vlan */
 	priv->r->vlan_tables_read(vlan->vid, &info);
@@ -1477,6 +1493,9 @@ static int rtl83xx_vlan_del(struct dsa_switch *ds, int port,
 	pr_debug("%s: port %d, vid %d, flags %x\n",
 		__func__, port, vlan->vid, vlan->flags);
 
+	/* Let no one mess with our special VLAN 0 */
+	if (!vlan->vid) return 0;
+
 	if (vlan->vid > 4095) {
 		dev_err(priv->dev, "VLAN out of range: %d", vlan->vid);
 		return -ENOTSUPP;




More information about the lede-commits mailing list