1 From 0254efd8d7e8f533b57bdf8665991fd5548c65a8 Mon Sep 17 00:00:00 2001
2 From: Vladimir Oltean <vladimir.oltean@nxp.com>
3 Date: Thu, 14 Nov 2019 17:03:29 +0200
4 Subject: [PATCH] net: dsa: ocelot: add tagger for Ocelot/Felix switches
6 While it is entirely possible that this tagger format is in fact more
7 generic than just these 2 switch families, I don't have that knowledge.
8 The Seville switch in NXP T1040 has a similar frame format, but there
9 are enough differences (e.g. DEST field starts at bit 57 instead of 56)
10 that calling this file tag_vitesse.c is a bit of a stretch at the
11 moment. The frame format has been listed in a comment so that people who
12 add support for further Vitesse switches can rework this tagger while
13 keeping compatibility with Felix.
15 The "ocelot" name was chosen instead of "felix" because even the Ocelot
16 switch can act as a DSA device when it is used in NPI mode, and the Felix
17 tagger format is almost identical. Currently it is only used for the
18 Felix switch embedded in the NXP LS1028A chip.
20 The ABI for this tagger should be considered "not stable" at the moment.
21 The DSA tag is always placed before the Ethernet header and therefore,
22 we are using the long prefix for RX tags to avoid putting the DSA master
23 port in promiscuous mode. Once there will be an API in DSA for drivers
24 to request DSA masters to be in promiscuous mode unconditionally, we
25 will switch to the "no prefix" extraction frame header, which will save
26 16 padding bytes for each RX frame.
28 Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
29 Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
30 Signed-off-by: David S. Miller <davem@davemloft.net>
33 include/net/dsa.h | 2 +
34 net/dsa/Kconfig | 7 ++
35 net/dsa/Makefile | 1 +
36 net/dsa/tag_ocelot.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++
37 5 files changed, 246 insertions(+)
38 create mode 100644 net/dsa/tag_ocelot.c
42 @@ -17355,6 +17355,13 @@ S: Maintained
43 F: drivers/input/serio/userio.c
44 F: include/uapi/linux/userio.h
46 +VITESSE FELIX ETHERNET SWITCH DRIVER
47 +M: Vladimir Oltean <vladimir.oltean@nxp.com>
48 +M: Claudiu Manoil <claudiu.manoil@nxp.com>
49 +L: netdev@vger.kernel.org
51 +F: net/dsa/tag_ocelot.c
53 VIVID VIRTUAL VIDEO DRIVER
54 M: Hans Verkuil <hverkuil@xs4all.nl>
55 L: linux-media@vger.kernel.org
56 --- a/include/net/dsa.h
57 +++ b/include/net/dsa.h
58 @@ -42,6 +42,7 @@ struct phylink_link_state;
59 #define DSA_TAG_PROTO_8021Q_VALUE 12
60 #define DSA_TAG_PROTO_SJA1105_VALUE 13
61 #define DSA_TAG_PROTO_KSZ8795_VALUE 14
62 +#define DSA_TAG_PROTO_OCELOT_VALUE 15
63 #define DSA_TAG_PROTO_RTL4_A_VALUE 17
65 enum dsa_tag_protocol {
66 @@ -60,6 +61,7 @@ enum dsa_tag_protocol {
67 DSA_TAG_PROTO_8021Q = DSA_TAG_PROTO_8021Q_VALUE,
68 DSA_TAG_PROTO_SJA1105 = DSA_TAG_PROTO_SJA1105_VALUE,
69 DSA_TAG_PROTO_KSZ8795 = DSA_TAG_PROTO_KSZ8795_VALUE,
70 + DSA_TAG_PROTO_OCELOT = DSA_TAG_PROTO_OCELOT_VALUE,
71 DSA_TAG_PROTO_RTL4_A = DSA_TAG_PROTO_RTL4_A_VALUE,
76 @@ -87,6 +87,13 @@ config NET_DSA_TAG_RTL4_A
77 Realtek switches with 4 byte protocol A tags, sich as found in
78 the Realtek RTL8366RB.
80 +config NET_DSA_TAG_OCELOT
81 + tristate "Tag driver for Ocelot family of switches"
84 + Say Y or M if you want to enable support for tagging frames for the
85 + Ocelot switches (VSC7511, VSC7512, VSC7513, VSC7514, VSC9959).
87 config NET_DSA_TAG_QCA
88 tristate "Tag driver for Qualcomm Atheros QCA8K switches"
90 --- a/net/dsa/Makefile
91 +++ b/net/dsa/Makefile
92 @@ -13,6 +13,7 @@ obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz
93 obj-$(CONFIG_NET_DSA_TAG_RTL4_A) += tag_rtl4_a.o
94 obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o
95 obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
96 +obj-$(CONFIG_NET_DSA_TAG_OCELOT) += tag_ocelot.o
97 obj-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o
98 obj-$(CONFIG_NET_DSA_TAG_SJA1105) += tag_sja1105.o
99 obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
101 +++ b/net/dsa/tag_ocelot.c
103 +// SPDX-License-Identifier: GPL-2.0
104 +/* Copyright 2019 NXP Semiconductors
106 +#include <soc/mscc/ocelot.h>
107 +#include <linux/packing.h>
108 +#include "dsa_priv.h"
110 +/* The CPU injection header and the CPU extraction header can have 3 types of
111 + * prefixes: long, short and no prefix. The format of the header itself is the
112 + * same in all 3 cases.
114 + * Extraction with long prefix:
116 + * +-------------------+-------------------+------+------+------------+-------+
117 + * | ff:ff:ff:ff:ff:ff | ff:ff:ff:ff:ff:ff | 8880 | 000a | extraction | frame |
118 + * | | | | | header | |
119 + * +-------------------+-------------------+------+------+------------+-------+
120 + * 48 bits 48 bits 16 bits 16 bits 128 bits
122 + * Extraction with short prefix:
124 + * +------+------+------------+-------+
125 + * | 8880 | 000a | extraction | frame |
127 + * +------+------+------------+-------+
128 + * 16 bits 16 bits 128 bits
130 + * Extraction with no prefix:
132 + * +------------+-------+
133 + * | extraction | frame |
135 + * +------------+-------+
139 + * Injection with long prefix:
141 + * +-------------------+-------------------+------+------+------------+-------+
142 + * | any dmac | any smac | 8880 | 000a | injection | frame |
143 + * | | | | | header | |
144 + * +-------------------+-------------------+------+------+------------+-------+
145 + * 48 bits 48 bits 16 bits 16 bits 128 bits
147 + * Injection with short prefix:
149 + * +------+------+------------+-------+
150 + * | 8880 | 000a | injection | frame |
152 + * +------+------+------------+-------+
153 + * 16 bits 16 bits 128 bits
155 + * Injection with no prefix:
157 + * +------------+-------+
158 + * | injection | frame |
160 + * +------------+-------+
163 + * The injection header looks like this (network byte order, bit 127
164 + * is part of lowest address byte in memory, bit 0 is part of highest
167 + * +------+------+------+------+------+------+------+------+
168 + * 127:120 |BYPASS| MASQ | MASQ_PORT |REW_OP|REW_OP|
169 + * +------+------+------+------+------+------+------+------+
170 + * 119:112 | REW_OP |
171 + * +------+------+------+------+------+------+------+------+
172 + * 111:104 | REW_VAL |
173 + * +------+------+------+------+------+------+------+------+
174 + * 103: 96 | REW_VAL |
175 + * +------+------+------+------+------+------+------+------+
176 + * 95: 88 | REW_VAL |
177 + * +------+------+------+------+------+------+------+------+
178 + * 87: 80 | REW_VAL |
179 + * +------+------+------+------+------+------+------+------+
181 + * +------+------+------+------+------+------+------+------+
182 + * 71: 64 | RSV | DEST |
183 + * +------+------+------+------+------+------+------+------+
185 + * +------+------+------+------+------+------+------+------+
187 + * +------+------+------+------+------+------+------+------+
188 + * 47: 40 | RSV | SRC_PORT | RSV |TFRM_TIMER|
189 + * +------+------+------+------+------+------+------+------+
190 + * 39: 32 | TFRM_TIMER | RSV |
191 + * +------+------+------+------+------+------+------+------+
192 + * 31: 24 | RSV | DP | POP_CNT | CPUQ |
193 + * +------+------+------+------+------+------+------+------+
194 + * 23: 16 | CPUQ | QOS_CLASS |TAG_TYPE|
195 + * +------+------+------+------+------+------+------+------+
196 + * 15: 8 | PCP | DEI | VID |
197 + * +------+------+------+------+------+------+------+------+
199 + * +------+------+------+------+------+------+------+------+
201 + * And the extraction header looks like this:
203 + * +------+------+------+------+------+------+------+------+
204 + * 127:120 | RSV | REW_OP |
205 + * +------+------+------+------+------+------+------+------+
206 + * 119:112 | REW_OP | REW_VAL |
207 + * +------+------+------+------+------+------+------+------+
208 + * 111:104 | REW_VAL |
209 + * +------+------+------+------+------+------+------+------+
210 + * 103: 96 | REW_VAL |
211 + * +------+------+------+------+------+------+------+------+
212 + * 95: 88 | REW_VAL |
213 + * +------+------+------+------+------+------+------+------+
214 + * 87: 80 | REW_VAL | LLEN |
215 + * +------+------+------+------+------+------+------+------+
216 + * 79: 72 | LLEN | WLEN |
217 + * +------+------+------+------+------+------+------+------+
218 + * 71: 64 | WLEN | RSV |
219 + * +------+------+------+------+------+------+------+------+
221 + * +------+------+------+------+------+------+------+------+
223 + * +------+------+------+------+------+------+------+------+
224 + * 47: 40 | RSV | SRC_PORT | ACL_ID |
225 + * +------+------+------+------+------+------+------+------+
226 + * 39: 32 | ACL_ID | RSV | SFLOW_ID |
227 + * +------+------+------+------+------+------+------+------+
228 + * 31: 24 |ACL_HIT| DP | LRN_FLAGS | CPUQ |
229 + * +------+------+------+------+------+------+------+------+
230 + * 23: 16 | CPUQ | QOS_CLASS |TAG_TYPE|
231 + * +------+------+------+------+------+------+------+------+
232 + * 15: 8 | PCP | DEI | VID |
233 + * +------+------+------+------+------+------+------+------+
235 + * +------+------+------+------+------+------+------+------+
238 +static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
239 + struct net_device *netdev)
241 + struct dsa_port *dp = dsa_slave_to_port(netdev);
242 + u64 bypass, dest, src, qos_class;
243 + struct dsa_switch *ds = dp->ds;
244 + int port = dp->index;
247 + if (unlikely(skb_cow_head(skb, OCELOT_TAG_LEN) < 0)) {
248 + netdev_err(netdev, "Cannot make room for tag.\n");
252 + injection = skb_push(skb, OCELOT_TAG_LEN);
254 + memset(injection, 0, OCELOT_TAG_LEN);
256 + src = dsa_upstream_port(ds, port);
259 + qos_class = skb->priority;
261 + packing(injection, &bypass, 127, 127, OCELOT_TAG_LEN, PACK, 0);
262 + packing(injection, &dest, 68, 56, OCELOT_TAG_LEN, PACK, 0);
263 + packing(injection, &src, 46, 43, OCELOT_TAG_LEN, PACK, 0);
264 + packing(injection, &qos_class, 19, 17, OCELOT_TAG_LEN, PACK, 0);
269 +static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
270 + struct net_device *netdev,
271 + struct packet_type *pt)
273 + u64 src_port, qos_class;
274 + u8 *start = skb->data;
277 + /* Revert skb->data by the amount consumed by the DSA master,
278 + * so it points to the beginning of the frame.
280 + skb_push(skb, ETH_HLEN);
281 + /* We don't care about the long prefix, it is just for easy entrance
282 + * into the DSA master's RX filter. Discard it now by moving it into
285 + skb_pull(skb, OCELOT_LONG_PREFIX_LEN);
286 + /* And skb->data now points to the extraction frame header.
287 + * Keep a pointer to it.
289 + extraction = skb->data;
290 + /* Now the EFH is part of the headroom as well */
291 + skb_pull(skb, OCELOT_TAG_LEN);
292 + /* Reset the pointer to the real MAC header */
293 + skb_reset_mac_header(skb);
294 + skb_reset_mac_len(skb);
295 + /* And move skb->data to the correct location again */
296 + skb_pull(skb, ETH_HLEN);
298 + /* Remove from inet csum the extraction header */
299 + skb_postpull_rcsum(skb, start, OCELOT_LONG_PREFIX_LEN + OCELOT_TAG_LEN);
301 + packing(extraction, &src_port, 46, 43, OCELOT_TAG_LEN, UNPACK, 0);
302 + packing(extraction, &qos_class, 19, 17, OCELOT_TAG_LEN, UNPACK, 0);
304 + skb->dev = dsa_master_find_slave(netdev, 0, src_port);
306 + /* The switch will reflect back some frames sent through
307 + * sockets opened on the bare DSA master. These will come back
308 + * with src_port equal to the index of the CPU port, for which
309 + * there is no slave registered. So don't print any error
310 + * message here (ignore and drop those frames).
314 + skb->offload_fwd_mark = 1;
315 + skb->priority = qos_class;
320 +static struct dsa_device_ops ocelot_netdev_ops = {
322 + .proto = DSA_TAG_PROTO_OCELOT,
323 + .xmit = ocelot_xmit,
325 + .overhead = OCELOT_TAG_LEN + OCELOT_LONG_PREFIX_LEN,
328 +MODULE_LICENSE("GPL v2");
329 +MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_OCELOT);
331 +module_dsa_tag_driver(ocelot_netdev_ops);