Netdev List
 help / color / mirror / Atom feed
From: Joris Vaisvila <joey@tinyisr.com>
To: netdev@vger.kernel.org
Cc: horms@kernel.org, pabeni@redhat.com, kuba@kernel.org,
	edumazet@google.com, davem@davemloft.net, olteanv@gmail.com,
	Andrew Lunn <andrew@lunn.ch>, Joris Vaisvila <joey@tinyisr.com>
Subject: [PATCH net-next v1 1/6] net: dsa: mt7628: rework vlan block allocator
Date: Sun,  6 Sep 2026 20:16:20 +0300	[thread overview]
Message-ID: <20260906171625.533915-2-joey@tinyisr.com> (raw)
In-Reply-To: <20260906171625.533915-1-joey@tinyisr.com>

Rework the VLAN hardware entry allocator to allow reserving entries for
tag_8021q bridge/isolation use. This is prerequisite work for VLAN
filtering support.

6 VLAN table entries are reserved for tag_8021q use and the rest are
left for the upcoming VLAN filtering support. No functional change
intended.

The active property is removed from VLAN entries in favor of vid == 0,
since tag_8021q VIDs cannot be 0.

Signed-off-by: Joris Vaisvila <joey@tinyisr.com>
---
 drivers/net/dsa/mt7628.c | 160 +++++++++++++++++++++++++--------------
 1 file changed, 104 insertions(+), 56 deletions(-)

diff --git a/drivers/net/dsa/mt7628.c b/drivers/net/dsa/mt7628.c
index fb63f6f644b9..990556cc2f65 100644
--- a/drivers/net/dsa/mt7628.c
+++ b/drivers/net/dsa/mt7628.c
@@ -138,6 +138,7 @@
 #define MT7628_ESW_PORTS_CPU BIT(6)
 #define MT7628_ESW_PORTS_ALL GENMASK(6, 0)
 
+#define MT7628_ESW_NUM_USER_PORTS 5
 #define MT7628_ESW_NUM_PORTS 7
 #define MT7628_NUM_VLANS 16
 
@@ -151,8 +152,14 @@ static const struct regmap_config mt7628_esw_regmap_cfg = {
 	.val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
+enum {
+	MT7628_VLAN_TYPE_AWARE,
+	MT7628_VLAN_TYPE_UNAWARE,
+	MT7628_VLAN_TYPE_NUM,
+};
+
 struct mt7628_vlan {
-	bool active;
+	unsigned int type;
 	u8 members;
 	u8 untag;
 	u16 vid;
@@ -383,6 +390,82 @@ static void mt7628_esw_set_vub(struct mt7628_esw *esw, unsigned int vlan,
 			   MT7628_ESW_VUB_PREP(vlan, vub));
 }
 
+static struct mt7628_vlan *mt7628_find_vlan_block(struct dsa_switch *ds,
+						  u16 vid, unsigned int type)
+{
+	struct mt7628_esw *esw = ds->priv;
+	struct mt7628_vlan *vlan;
+	int i;
+
+	for (i = 0; i < MT7628_NUM_VLANS; i++) {
+		vlan = &esw->vlans[i];
+		if (vlan->vid == vid && vlan->type == type)
+			return vlan;
+	}
+	return NULL;
+}
+
+static struct mt7628_vlan *mt7628_alloc_vlan_block(struct dsa_switch *ds,
+						   u16 vid, unsigned int type)
+{
+	struct mt7628_esw *esw = ds->priv;
+	struct mt7628_vlan *vlan;
+	int i;
+
+	for (i = 0; i < MT7628_NUM_VLANS; i++) {
+		vlan = &esw->vlans[i];
+		if (vlan->vid)
+			continue;
+		if (vlan->type != type)
+			continue;
+		vlan->vid = vid;
+		return vlan;
+	}
+
+	return NULL;
+}
+
+static int mt7628_port_join_vlan_block(struct dsa_switch *ds, int port, u16 vid,
+				       unsigned int type, u16 flags)
+{
+	struct mt7628_vlan *vlan = mt7628_find_vlan_block(ds, vid, type);
+	struct mt7628_esw *esw = ds->priv;
+
+	if (!vlan)
+		vlan = mt7628_alloc_vlan_block(ds, vid, type);
+
+	if (!vlan)
+		return -ENOSPC;
+
+	vlan->members |= BIT(port);
+	if (flags & BRIDGE_VLAN_INFO_PVID)
+		esw->tag_8021q_pvid[port] = vid;
+	if (flags & BRIDGE_VLAN_INFO_UNTAGGED)
+		vlan->untag |= BIT(port);
+	return 0;
+}
+
+static int mt7628_port_leave_vlan_block(struct dsa_switch *ds, int port,
+					u16 vid, unsigned int type)
+{
+	struct mt7628_vlan *vlan = mt7628_find_vlan_block(ds, vid, type);
+	struct mt7628_esw *esw = ds->priv;
+
+	if (!vlan)
+		return -ENOENT;
+
+	if (esw->tag_8021q_pvid[port] == vid)
+		esw->tag_8021q_pvid[port] = 0;
+	vlan->members &= ~BIT(port);
+	vlan->untag &= ~BIT(port);
+	/*
+	 * Free the vlan if we're the last member of it.
+	 */
+	if (!vlan->members)
+		vlan->vid = 0;
+	return 0;
+}
+
 static void mt7628_vlan_sync(struct dsa_switch *ds)
 {
 	struct mt7628_esw *esw = ds->priv;
@@ -425,6 +508,17 @@ static int mt7628_setup(struct dsa_switch *ds)
 	if (ret)
 		return ret;
 
+	/*
+	 * Dedicate the first num_user_ports + 1 VLAN slots for tag_8021q.
+	 * Since bridges are only offloaded when they have at least one member
+	 * port, the worst case entry requirement is 1 per port. The extra slot
+	 * is needed because when changing the configuration, tag_8021q adds a
+	 * new VLAN before removing the old one. The rest of the VLAN slots can
+	 * be used for filtering.
+	 */
+	for (int i = 0; i < MT7628_ESW_NUM_USER_PORTS + 1; i++)
+		esw->vlans[i].type = MT7628_VLAN_TYPE_UNAWARE;
+
 	rtnl_lock();
 	ret = dsa_tag_8021q_register(ds, htons(ETH_P_8021Q));
 	rtnl_unlock();
@@ -479,67 +573,21 @@ static void mt7628_phylink_get_caps(struct dsa_switch *ds, int port,
 static int mt7628_dsa_8021q_vlan_add(struct dsa_switch *ds, int port,
 				     u16 vid, u16 flags)
 {
-	struct mt7628_esw *esw = ds->priv;
-	struct mt7628_vlan *vlan = NULL;
-	int i;
-
-	for (i = 0; i < MT7628_NUM_VLANS; i++) {
-		struct mt7628_vlan *check_vlan = &esw->vlans[i];
-
-		if (!check_vlan->active && !vlan)
-			vlan = check_vlan;
-
-		if (check_vlan->active && check_vlan->vid == vid) {
-			vlan = check_vlan;
-			break;
-		}
-	}
-
-	if (!vlan)
-		return -ENOSPC;
-
-	vlan->vid = vid;
-	vlan->active = true;
-	vlan->members |= BIT(port);
-
-	if (flags & BRIDGE_VLAN_INFO_PVID)
-		esw->tag_8021q_pvid[port] = vid;
-
-	if (flags & BRIDGE_VLAN_INFO_UNTAGGED)
-		vlan->untag |= BIT(port);
-
+	int ret =
+	    mt7628_port_join_vlan_block(ds, port, vid, MT7628_VLAN_TYPE_UNAWARE,
+					flags);
+	if (ret)
+		return ret;
 	mt7628_vlan_sync(ds);
 	return 0;
 }
 
 static int mt7628_dsa_8021q_vlan_del(struct dsa_switch *ds, int port, u16 vid)
 {
-	struct mt7628_esw *esw = ds->priv;
-	struct mt7628_vlan *vlan = NULL;
-	int i;
-
-	for (i = 0; i < MT7628_NUM_VLANS; i++) {
-		struct mt7628_vlan *check_vlan = &esw->vlans[i];
-
-		if (!check_vlan->active || check_vlan->vid != vid)
-			continue;
-		vlan = check_vlan;
-		break;
-	}
-	if (!vlan)
-		return -ENOENT;
-
-	if (esw->tag_8021q_pvid[port] == vid)
-		esw->tag_8021q_pvid[port] = 0;
-
-	vlan->members &= ~BIT(port);
-	vlan->untag &= ~BIT(port);
-
-	if (!vlan->members) {
-		vlan->active = false;
-		vlan->vid = 0;
-	}
-
+	int ret = mt7628_port_leave_vlan_block(ds, port, vid,
+					       MT7628_VLAN_TYPE_UNAWARE);
+	if (ret)
+		return ret;
 	mt7628_vlan_sync(ds);
 	return 0;
 }
-- 
2.55.0


  reply	other threads:[~2026-09-06 17:20 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-06 17:16 [PATCH net-next v1 0/6] net: dsa: mt7628: add VLAN filtering support Joris Vaisvila
2026-09-06 17:16 ` Joris Vaisvila [this message]
2026-09-10  0:17   ` [PATCH net-next v1 1/6] net: dsa: mt7628: rework vlan block allocator netdev-bot+sashiko
2026-09-06 17:16 ` [PATCH net-next v1 2/6] net: dsa: mt7628: add port bridge offload support Joris Vaisvila
2026-09-10  0:17   ` netdev-bot+sashiko
2026-09-06 17:16 ` [PATCH net-next v1 3/6] net: dsa: tag: mt7628: add bridge support Joris Vaisvila
2026-09-10  0:17   ` netdev-bot+sashiko
2026-09-06 17:16 ` [PATCH net-next v1 4/6] net: dsa: mt7628: add VLAN filtering support Joris Vaisvila
2026-09-10  0:17   ` netdev-bot+sashiko
2026-09-06 17:16 ` [PATCH net-next v1 5/6] net: dsa: tag: mt7628: add VLAN awareness support Joris Vaisvila
2026-09-10  0:17   ` netdev-bot+sashiko
2026-09-13 16:59     ` Joris Vaisvila
2026-09-06 17:16 ` [PATCH net-next v1 6/6] MAINTAINERS: add myself as MT7628 embedded switch maintainer Joris Vaisvila

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260906171625.533915-2-joey@tinyisr.com \
    --to=joey@tinyisr.com \
    --cc=andrew@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=olteanv@gmail.com \
    --cc=pabeni@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox