mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 11:06:41 -05:00
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:
committed by
Jakub Kicinski
parent
a9dff2b5f7
commit
ca4709843b
@@ -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;
|
||||
|
||||
@@ -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 ] */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
141
net/dsa/tag_yt921x.c
Normal 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);
|
||||
Reference in New Issue
Block a user