Skip to content

Commit baeb90e

Browse files
dangowrtfrank-w
authored andcommitted
net: dsa: add tag formats for MaxLinear switches
The MaxLinear MXL862xx family of switches can either be used with a 8-byte proprietary special tag or utilizing IEEE 802.1ad (aka. Q-in-Q) VLANs to destinguish user ports. Add support for both tag formats. Signed-off-by: Daniel Golle <[email protected]>
1 parent 9943c96 commit baeb90e

File tree

5 files changed

+409
-0
lines changed

5 files changed

+409
-0
lines changed

include/net/dsa.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ struct tc_action;
5757
#define DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE 29
5858
#define DSA_TAG_PROTO_YT921X_VALUE 30
5959
#define DSA_TAG_PROTO_MXL_GSW1XX_VALUE 31
60+
#define DSA_TAG_PROTO_MXL862_VALUE 32
61+
#define DSA_TAG_PROTO_MXL862_8021Q_VALUE 33
6062

6163
enum dsa_tag_protocol {
6264
DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE,
@@ -91,6 +93,8 @@ enum dsa_tag_protocol {
9193
DSA_TAG_PROTO_VSC73XX_8021Q = DSA_TAG_PROTO_VSC73XX_8021Q_VALUE,
9294
DSA_TAG_PROTO_YT921X = DSA_TAG_PROTO_YT921X_VALUE,
9395
DSA_TAG_PROTO_MXL_GSW1XX = DSA_TAG_PROTO_MXL_GSW1XX_VALUE,
96+
DSA_TAG_PROTO_MXL862 = DSA_TAG_PROTO_MXL862_VALUE,
97+
DSA_TAG_PROTO_MXL862_8021Q = DSA_TAG_PROTO_MXL862_8021Q_VALUE,
9498
};
9599

96100
struct dsa_switch;

net/dsa/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,19 @@ config NET_DSA_TAG_QCA
145145
Say Y or M if you want to enable support for tagging frames for
146146
the Qualcomm Atheros QCA8K switches.
147147

148+
config NET_DSA_TAG_MXL862
149+
tristate "Tag driver for MxL862xx switches"
150+
help
151+
Say Y or M if you want to enable support for tagging frames for the
152+
Maxlinear MxL862xx switches.
153+
154+
config NET_DSA_TAG_MXL862_8021Q
155+
tristate "Tag driver for MxL862xx switches, based on VLAN tags"
156+
help
157+
Say Y or M if you want to enable support for tagging frames for the
158+
Maxlinear MxL862xx switches. This tagging variant is based on 4-byte wide VLAN
159+
tags
160+
148161
config NET_DSA_TAG_RTL4_A
149162
tristate "Tag driver for Realtek 4 byte protocol A tags"
150163
help

net/dsa/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o
2929
obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o
3030
obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
3131
obj-$(CONFIG_NET_DSA_TAG_MXL_GSW1XX) += tag_mxl-gsw1xx.o
32+
obj-$(CONFIG_NET_DSA_TAG_MXL862) += tag_mxl862xx.o
33+
obj-$(CONFIG_NET_DSA_TAG_MXL862_8021Q) += tag_mxl862xx_8021q.o
3234
obj-$(CONFIG_NET_DSA_TAG_NONE) += tag_none.o
3335
obj-$(CONFIG_NET_DSA_TAG_OCELOT) += tag_ocelot.o
3436
obj-$(CONFIG_NET_DSA_TAG_OCELOT_8021Q) += tag_ocelot_8021q.o

net/dsa/tag_mxl862xx.c

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
// SPDX-License-Identifier: GPL-2.0+
2+
/*
3+
* net/dsa/tag_mxl862xx.c - DSA driver Special Tag support for MaxLinear 862xx switch chips
4+
*
5+
* Copyright (C) 2024 MaxLinear Inc.
6+
*
7+
* This program is free software; you can redistribute it and/or
8+
* modify it under the terms of the GNU General Public License
9+
* as published by the Free Software Foundation; either version 2
10+
* of the License, or (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20+
*
21+
*/
22+
23+
#include <linux/bitops.h>
24+
#include <linux/etherdevice.h>
25+
#include <linux/skbuff.h>
26+
#include <net/dsa.h>
27+
28+
#ifndef LINUX_VERSION_CODE
29+
#include <linux/version.h>
30+
#else
31+
#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
32+
#endif
33+
34+
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0))
35+
#include "dsa_priv.h"
36+
#else
37+
#include "tag.h"
38+
#endif
39+
40+
#define MXL862_NAME "mxl862xx"
41+
42+
/* To define the outgoing port and to discover the incoming port a special
43+
* tag is used by the GSW1xx.
44+
*
45+
* Dest MAC Src MAC special TAG EtherType
46+
* ...| 1 2 3 4 5 6 | 1 2 3 4 5 6 | 1 2 3 4 5 6 7 8 | 1 2 |...
47+
* |<--------------->|
48+
*/
49+
50+
/* special tag in TX path header */
51+
#define MXL862_TX_HEADER_LEN 8
52+
53+
#define MXL862_RX_HEADER_LEN 8
54+
55+
/* Byte 7 */
56+
#define MXL862_IGP_EGP_SHIFT 0
57+
#define MXL862_IGP_EGP_MASK GENMASK(3, 0)
58+
59+
static struct sk_buff *mxl862_tag_xmit(struct sk_buff *skb,
60+
struct net_device *dev)
61+
{
62+
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
63+
int err;
64+
#endif
65+
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0))
66+
struct dsa_port *dp = dsa_slave_to_port(dev);
67+
#else
68+
struct dsa_port *dp = dsa_user_to_port(dev);
69+
#endif
70+
struct dsa_port *cpu_dp = dp->cpu_dp;
71+
unsigned int cpu_port = cpu_dp->index + 1;
72+
unsigned int usr_port = dp->index + 1;
73+
74+
u8 *mxl862_tag;
75+
76+
if (skb == NULL)
77+
return skb;
78+
79+
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
80+
err = skb_cow_head(skb, MXL862_TX_HEADER_LEN);
81+
if (err)
82+
return NULL;
83+
#endif
84+
85+
/* provide additional space 'MXL862_TX_HEADER_LEN' bytes */
86+
skb_push(skb, MXL862_TX_HEADER_LEN);
87+
88+
/* shift MAC address to the beginnig of the enlarged buffer,
89+
* releasing the space required for DSA tag (between MAC address and Ethertype) */
90+
memmove(skb->data, skb->data + MXL862_TX_HEADER_LEN, 2 * ETH_ALEN);
91+
92+
/* special tag ingress */
93+
mxl862_tag = skb->data + 2 * ETH_ALEN;
94+
mxl862_tag[0] = 0x88;
95+
mxl862_tag[1] = 0xc3;
96+
mxl862_tag[2] = 0;
97+
mxl862_tag[3] = 0;
98+
mxl862_tag[4] = 0;
99+
mxl862_tag[5] = usr_port + 16 - cpu_port;
100+
mxl862_tag[6] = 0;
101+
mxl862_tag[7] = (cpu_port)&MXL862_IGP_EGP_MASK;
102+
103+
return skb;
104+
}
105+
106+
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0))
107+
static struct sk_buff *mxl862_tag_rcv(struct sk_buff *skb,
108+
struct net_device *dev,
109+
struct packet_type *pt)
110+
#else
111+
static struct sk_buff *mxl862_tag_rcv(struct sk_buff *skb,
112+
struct net_device *dev)
113+
#endif
114+
{
115+
int port;
116+
u8 *mxl862_tag;
117+
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0))
118+
struct dsa_port *dp;
119+
#endif
120+
121+
if (unlikely(!pskb_may_pull(skb, MXL862_RX_HEADER_LEN))) {
122+
dev_warn_ratelimited(&dev->dev,
123+
"Dropping packet, cannot pull SKB\n");
124+
return NULL;
125+
}
126+
127+
mxl862_tag = skb->data - 2;
128+
129+
if ((mxl862_tag[0] != 0x88) && (mxl862_tag[1] != 0xc3)) {
130+
dev_warn_ratelimited(
131+
&dev->dev,
132+
"Dropping packet due to invalid special tag marker\n");
133+
dev_warn_ratelimited(
134+
&dev->dev,
135+
"Rx Packet Tag: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
136+
mxl862_tag[0], mxl862_tag[1], mxl862_tag[2],
137+
mxl862_tag[3], mxl862_tag[4], mxl862_tag[5],
138+
mxl862_tag[6], mxl862_tag[7]);
139+
return NULL;
140+
}
141+
142+
/* Get source port information */
143+
port = (mxl862_tag[7] & MXL862_IGP_EGP_MASK) >> MXL862_IGP_EGP_SHIFT;
144+
port = port - 1;
145+
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0))
146+
skb->dev = dsa_master_find_slave(dev, 0, port);
147+
#else
148+
skb->dev = dsa_conduit_find_user(dev, 0, port);
149+
#endif
150+
if (!skb->dev) {
151+
dev_warn_ratelimited(
152+
&dev->dev,
153+
"Dropping packet due to invalid source port\n");
154+
dev_warn_ratelimited(
155+
&dev->dev,
156+
"Rx Packet Tag: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
157+
mxl862_tag[0], mxl862_tag[1], mxl862_tag[2],
158+
mxl862_tag[3], mxl862_tag[4], mxl862_tag[5],
159+
mxl862_tag[6], mxl862_tag[7]);
160+
return NULL;
161+
}
162+
163+
/* remove the MxL862xx special tag between the MAC addresses and the current ethertype field. */
164+
skb_pull_rcsum(skb, MXL862_RX_HEADER_LEN);
165+
memmove(skb->data - ETH_HLEN,
166+
skb->data - (ETH_HLEN + MXL862_RX_HEADER_LEN), 2 * ETH_ALEN);
167+
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0))
168+
dp = dsa_slave_to_port(skb->dev);
169+
if (dp->bridge_dev)
170+
skb->offload_fwd_mark = 1;
171+
#else
172+
dsa_default_offload_fwd_mark(skb);
173+
#endif
174+
175+
return skb;
176+
}
177+
178+
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0))
179+
const struct dsa_device_ops mxl862_netdev_ops = {
180+
.xmit = mxl862_tag_xmit,
181+
.rcv = mxl862_tag_rcv,
182+
};
183+
#else
184+
185+
static const struct dsa_device_ops mxl862_netdev_ops = {
186+
.name = "mxl862",
187+
.proto = DSA_TAG_PROTO_MXL862,
188+
.xmit = mxl862_tag_xmit,
189+
.rcv = mxl862_tag_rcv,
190+
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 0))
191+
.overhead = MXL862_RX_HEADER_LEN,
192+
#else
193+
.needed_headroom = MXL862_RX_HEADER_LEN,
194+
#endif
195+
};
196+
197+
MODULE_LICENSE("GPL");
198+
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0))
199+
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MXL862);
200+
#else
201+
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MXL862, MXL862_NAME);
202+
#endif
203+
204+
module_dsa_tag_driver(mxl862_netdev_ops);
205+
#endif
206+
207+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)