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
next prev parent 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