All of lore.kernel.org
 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: 12+ 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-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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.