net: dsa: tag_yt921x: add support for Motorcomm YT921x tags

Add support for Motorcomm YT921x tags, which includes a proper
configurable ethertype field (default to 0x9988).

Signed-off-by: David Yang <mmyangfl@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20251017060859.326450-3-mmyangfl@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
David Yang
2025-10-17 14:08:54 +08:00
committed by Jakub Kicinski
parent a9dff2b5f7
commit ca4709843b
5 changed files with 151 additions and 0 deletions

View File

@@ -55,6 +55,7 @@ struct tc_action;
#define DSA_TAG_PROTO_LAN937X_VALUE 27
#define DSA_TAG_PROTO_VSC73XX_8021Q_VALUE 28
#define DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE 29
#define DSA_TAG_PROTO_YT921X_VALUE 30
enum dsa_tag_protocol {
DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE,
@@ -87,6 +88,7 @@ enum dsa_tag_protocol {
DSA_TAG_PROTO_RZN1_A5PSW = DSA_TAG_PROTO_RZN1_A5PSW_VALUE,
DSA_TAG_PROTO_LAN937X = DSA_TAG_PROTO_LAN937X_VALUE,
DSA_TAG_PROTO_VSC73XX_8021Q = DSA_TAG_PROTO_VSC73XX_8021Q_VALUE,
DSA_TAG_PROTO_YT921X = DSA_TAG_PROTO_YT921X_VALUE,
};
struct dsa_switch;

View File

@@ -114,6 +114,7 @@
#define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_YT921X 0x9988 /* Motorcomm YT921x DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_EDSA 0xDADA /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_DSA_8021Q 0xDADB /* Fake VLAN Header for DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_DSA_A5PSW 0xE001 /* A5PSW Tag Value [ NOT AN OFFICIALLY REGISTERED ID ] */

View File

@@ -190,4 +190,10 @@ config NET_DSA_TAG_XRS700X
Say Y or M if you want to enable support for tagging frames for
Arrow SpeedChips XRS700x switches that use a single byte tag trailer.
config NET_DSA_TAG_YT921X
tristate "Tag driver for Motorcomm YT921x switches"
help
Say Y or M if you want to enable support for tagging frames for
Motorcomm YT921x switches.
endif

View File

@@ -39,6 +39,7 @@ obj-$(CONFIG_NET_DSA_TAG_SJA1105) += tag_sja1105.o
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
# for tracing framework to find trace.h
CFLAGS_trace.o := -I$(src)

141
net/dsa/tag_yt921x.c Normal file
View File

@@ -0,0 +1,141 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Motorcomm YT921x Switch Extended CPU Port Tagging
*
* Copyright (c) 2025 David Yang <mmyangfl@gmail.com>
*
* +----+----+-------+-----+----+---------
* | DA | SA | TagET | Tag | ET | Payload ...
* +----+----+-------+-----+----+---------
* 6 6 2 6 2 N
*
* Tag Ethertype: CPU_TAG_TPID_TPID (default: ETH_P_YT921X = 0x9988)
* * Hardcoded for the moment, but still configurable. Discuss it if there
* are conflicts somewhere and/or you want to change it for some reason.
* Tag:
* 2: VLAN Tag
* 2: Rx Port
* 15b: Rx Port Valid
* 14b-11b: Rx Port
* 10b-0b: Cmd?
* 2: Tx Port(s)
* 15b: Tx Port(s) Valid
* 10b-0b: Tx Port(s) Mask
*/
#include <linux/etherdevice.h>
#include "tag.h"
#define YT921X_TAG_NAME "yt921x"
#define YT921X_TAG_LEN 8
#define YT921X_TAG_PORT_EN BIT(15)
#define YT921X_TAG_RX_PORT_M GENMASK(14, 11)
#define YT921X_TAG_RX_CMD_M GENMASK(10, 0)
#define YT921X_TAG_RX_CMD(x) FIELD_PREP(YT921X_TAG_RX_CMD_M, (x))
#define YT921X_TAG_RX_CMD_FORWARDED 0x80
#define YT921X_TAG_RX_CMD_UNK_UCAST 0xb2
#define YT921X_TAG_RX_CMD_UNK_MCAST 0xb4
#define YT921X_TAG_TX_PORTS_M GENMASK(10, 0)
#define YT921X_TAG_TX_PORTn(port) BIT(port)
static struct sk_buff *
yt921x_tag_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct dsa_port *dp = dsa_user_to_port(netdev);
unsigned int port = dp->index;
__be16 *tag;
u16 tx;
skb_push(skb, YT921X_TAG_LEN);
dsa_alloc_etype_header(skb, YT921X_TAG_LEN);
tag = dsa_etype_header_pos_tx(skb);
tag[0] = htons(ETH_P_YT921X);
/* VLAN tag unrelated when TX */
tag[1] = 0;
tag[2] = 0;
tx = YT921X_TAG_PORT_EN | YT921X_TAG_TX_PORTn(port);
tag[3] = htons(tx);
return skb;
}
static struct sk_buff *
yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev)
{
unsigned int port;
__be16 *tag;
u16 cmd;
u16 rx;
if (unlikely(!pskb_may_pull(skb, YT921X_TAG_LEN)))
return NULL;
tag = dsa_etype_header_pos_rx(skb);
if (unlikely(tag[0] != htons(ETH_P_YT921X))) {
dev_warn_ratelimited(&netdev->dev,
"Unexpected EtherType 0x%04x\n",
ntohs(tag[0]));
return NULL;
}
/* Locate which port this is coming from */
rx = ntohs(tag[2]);
if (unlikely((rx & YT921X_TAG_PORT_EN) == 0)) {
dev_warn_ratelimited(&netdev->dev,
"Unexpected rx tag 0x%04x\n", rx);
return NULL;
}
port = FIELD_GET(YT921X_TAG_RX_PORT_M, rx);
skb->dev = dsa_conduit_find_user(netdev, 0, port);
if (unlikely(!skb->dev)) {
dev_warn_ratelimited(&netdev->dev,
"Couldn't decode source port %u\n", port);
return NULL;
}
cmd = FIELD_GET(YT921X_TAG_RX_CMD_M, rx);
switch (cmd) {
case YT921X_TAG_RX_CMD_FORWARDED:
/* Already forwarded by hardware */
dsa_default_offload_fwd_mark(skb);
break;
case YT921X_TAG_RX_CMD_UNK_UCAST:
case YT921X_TAG_RX_CMD_UNK_MCAST:
/* NOTE: hardware doesn't distinguish between TRAP (copy to CPU
* only) and COPY (forward and copy to CPU). In order to perform
* a soft switch, NEVER use COPY action in the switch driver.
*/
break;
default:
dev_warn_ratelimited(&netdev->dev,
"Unexpected rx cmd 0x%02x\n", cmd);
break;
}
/* Remove YT921x tag and update checksum */
skb_pull_rcsum(skb, YT921X_TAG_LEN);
dsa_strip_etype_header(skb, YT921X_TAG_LEN);
return skb;
}
static const struct dsa_device_ops yt921x_netdev_ops = {
.name = YT921X_TAG_NAME,
.proto = DSA_TAG_PROTO_YT921X,
.xmit = yt921x_tag_xmit,
.rcv = yt921x_tag_rcv,
.needed_headroom = YT921X_TAG_LEN,
};
MODULE_DESCRIPTION("DSA tag driver for Motorcomm YT921x switches");
MODULE_LICENSE("GPL");
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_YT921X, YT921X_TAG_NAME);
module_dsa_tag_driver(yt921x_netdev_ops);