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>,
devicetree@vger.kernel.org, Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Joris Vaisvila <joey@tinyisr.com>
Subject: [PATCH net-next 3/4] net: dsa: initial MT7628 tagging driver
Date: Thu, 26 Mar 2026 22:44:12 +0200 [thread overview]
Message-ID: <20260326204413.3317584-4-joey@tinyisr.com> (raw)
In-Reply-To: <20260326204413.3317584-1-joey@tinyisr.com>
Add support for the MT7628 embedded switch's tag.
The MT7628 tag is merged with the VLAN TPID field when a VLAN is
appended by the switch hardware. It is not installed if the VLAN tag is
already there on ingress. Due to this hardware quirk the tag cannot be
trusted for port 0 if we don't know that the VLAN was added by the
hardware. As a workaround for this the switch is configured to always
append the port PVID tag even if the incoming packet is already tagged.
The tagging driver can then trust that the tag is always accurate and
the whole VLAN tag can be removed on ingress as it's only metadata for
the tagger.
On egress the MT7628 tag allows precise TX, but the correct VLAN tag
from tag_8021q is still appended or the switch will not forward the
packet.
Signed-off-by: Joris Vaisvila <joey@tinyisr.com>
---
include/net/dsa.h | 2 +
net/dsa/Kconfig | 6 +++
net/dsa/Makefile | 1 +
net/dsa/tag_mt7628.c | 92 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 101 insertions(+)
create mode 100644 net/dsa/tag_mt7628.c
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 6c17446f3dcc..e93f9356b5c3 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -58,6 +58,7 @@ struct tc_action;
#define DSA_TAG_PROTO_YT921X_VALUE 30
#define DSA_TAG_PROTO_MXL_GSW1XX_VALUE 31
#define DSA_TAG_PROTO_MXL862_VALUE 32
+#define DSA_TAG_PROTO_MT7628_VALUE 33
enum dsa_tag_protocol {
DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE,
@@ -93,6 +94,7 @@ enum dsa_tag_protocol {
DSA_TAG_PROTO_YT921X = DSA_TAG_PROTO_YT921X_VALUE,
DSA_TAG_PROTO_MXL_GSW1XX = DSA_TAG_PROTO_MXL_GSW1XX_VALUE,
DSA_TAG_PROTO_MXL862 = DSA_TAG_PROTO_MXL862_VALUE,
+ DSA_TAG_PROTO_MT7628 = DSA_TAG_PROTO_MT7628_VALUE,
};
struct dsa_switch;
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index 5ed8c704636d..4aa73bd1aa9b 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -211,4 +211,10 @@ config NET_DSA_TAG_YT921X
Say Y or M if you want to enable support for tagging frames for
Motorcomm YT921x switches.
+config NET_DSA_TAG_MT7628
+ tristate "Tag driver for the MT7628 embedded switch"
+ help
+ Say Y or M if you want to enable support for tagging frames for the
+ switch embedded in the MT7628 SoC.
+
endif
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index bf7247759a64..d25ec0ab7d67 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
obj-$(CONFIG_NET_DSA_TAG_VSC73XX_8021Q) += tag_vsc73xx_8021q.o
obj-$(CONFIG_NET_DSA_TAG_XRS700X) += tag_xrs700x.o
obj-$(CONFIG_NET_DSA_TAG_YT921X) += tag_yt921x.o
+obj-$(CONFIG_NET_DSA_TAG_MT7628) += tag_mt7628.o
# for tracing framework to find trace.h
CFLAGS_trace.o := -I$(src)
diff --git a/net/dsa/tag_mt7628.c b/net/dsa/tag_mt7628.c
new file mode 100644
index 000000000000..ef119c37b26a
--- /dev/null
+++ b/net/dsa/tag_mt7628.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2026, Joris Vaisvila <joey@tinyisr.com>
+ * MT7628 switch tag support
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/dsa/8021q.h>
+#include <net/dsa.h>
+
+#include "tag.h"
+
+/*
+ * The MT7628 tag is encoded in the VLAN TPID field.
+ * On TX the lower 6 bits encode the destination port bitmask.
+ * On RX the lower 3 bits encode the source port number.
+ *
+ * The switch hardware will not modify the TPID of an incoming packet if it is
+ * already VLAN tagged. To work around this the switch is configured to always
+ * append a tag_8021q standalone VLAN tag for each port. That means we can
+ * safely strip the outer VLAN tag after parsing it.
+ *
+ * A VLAN tag is constructed on egress to target the standalone VLAN and
+ * destination port.
+ */
+
+#define MT7628_TAG_NAME "mt7628"
+
+#define MT7628_TAG_TX_PORT_BIT_MASK GENMASK(5, 0)
+#define MT7628_TAG_RX_PORT_MASK GENMASK(2, 0)
+#define MT7628_TAG_LEN 4
+
+static struct sk_buff *mt7628_tag_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct dsa_port *dp;
+ u16 xmit_vlan;
+ __be16 *tag;
+
+ dp = dsa_user_to_port(dev);
+ xmit_vlan = dsa_tag_8021q_standalone_vid(dp);
+
+ skb_push(skb, MT7628_TAG_LEN);
+ dsa_alloc_etype_header(skb, MT7628_TAG_LEN);
+
+ tag = dsa_etype_header_pos_tx(skb);
+
+ tag[0] = htons(ETH_P_8021Q |
+ FIELD_PREP(MT7628_TAG_TX_PORT_BIT_MASK,
+ dsa_xmit_port_mask(skb, dev)));
+ tag[1] = htons(xmit_vlan);
+
+ return skb;
+}
+
+static struct sk_buff *mt7628_tag_rcv(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ int src_port;
+ __be16 *phdr;
+ u16 tpid;
+
+ if (unlikely(!pskb_may_pull(skb, MT7628_TAG_LEN)))
+ return NULL;
+
+ phdr = dsa_etype_header_pos_rx(skb);
+ tpid = ntohs(*phdr);
+ skb_pull_rcsum(skb, MT7628_TAG_LEN);
+ dsa_strip_etype_header(skb, MT7628_TAG_LEN);
+
+ src_port = tpid & MT7628_TAG_RX_PORT_MASK;
+
+ skb->dev = dsa_conduit_find_user(dev, 0, src_port);
+ if (!skb->dev)
+ return NULL;
+ dsa_default_offload_fwd_mark(skb);
+ return skb;
+}
+
+static const struct dsa_device_ops mt7628_tag_ops = {
+ .name = MT7628_TAG_NAME,
+ .proto = DSA_TAG_PROTO_MT7628,
+ .xmit = mt7628_tag_xmit,
+ .rcv = mt7628_tag_rcv,
+ .needed_headroom = MT7628_TAG_LEN,
+};
+
+module_dsa_tag_driver(mt7628_tag_ops);
+
+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MT7628, MT7628_TAG_NAME);
+MODULE_DESCRIPTION("DSA tag driver for MT7628 switch");
+MODULE_LICENSE("GPL");
--
2.53.0
next prev parent reply other threads:[~2026-03-26 20:44 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-26 20:44 [PATCH net-next 0/4] net: dsa: mt7628 embedded switch initial support Joris Vaisvila
2026-03-26 20:44 ` [PATCH net-next 1/4] dt-bindings: net: dsa: add MT7628 ESW Joris Vaisvila
2026-03-26 23:11 ` Daniel Golle
2026-03-27 6:00 ` Joris Vaisvila
2026-03-27 11:32 ` Daniel Golle
2026-03-27 15:35 ` Joris Vaisvila
2026-03-26 20:44 ` [PATCH net-next 2/4] net: phy: mediatek: add phy driver for MT7628 built-in Fast Ethernet PHYs Joris Vaisvila
2026-03-27 11:48 ` Andrew Lunn
2026-03-26 20:44 ` Joris Vaisvila [this message]
2026-03-26 23:24 ` [PATCH net-next 3/4] net: dsa: initial MT7628 tagging driver Daniel Golle
2026-03-26 20:44 ` [PATCH net-next 4/4] net: dsa: initial support for MT7628 embedded switch Joris Vaisvila
2026-03-27 12:07 ` Andrew Lunn
2026-03-27 15:39 ` 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=20260326204413.3317584-4-joey@tinyisr.com \
--to=joey@tinyisr.com \
--cc=andrew@lunn.ch \
--cc=conor+dt@kernel.org \
--cc=davem@davemloft.net \
--cc=devicetree@vger.kernel.org \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=krzk+dt@kernel.org \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=olteanv@gmail.com \
--cc=pabeni@redhat.com \
--cc=robh@kernel.org \
/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