Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1/* SPDX-License-Identifier: GPL-2.0
2 * Copyright 2019-2021 NXP
3 */
4
5#ifndef _NET_DSA_TAG_OCELOT_H
6#define _NET_DSA_TAG_OCELOT_H
7
8#include <linux/if_bridge.h>
9#include <linux/if_vlan.h>
10#include <linux/kthread.h>
11#include <linux/packing.h>
12#include <linux/skbuff.h>
13#include <net/dsa.h>
14
15struct ocelot_skb_cb {
16 struct sk_buff *clone;
17 unsigned int ptp_class; /* valid only for clones */
18 u32 tstamp_lo;
19 u8 ptp_cmd;
20 u8 ts_id;
21};
22
23#define OCELOT_SKB_CB(skb) \
24 ((struct ocelot_skb_cb *)((skb)->cb))
25
26#define IFH_TAG_TYPE_C 0
27#define IFH_TAG_TYPE_S 1
28
29#define IFH_REW_OP_NOOP 0x0
30#define IFH_REW_OP_DSCP 0x1
31#define IFH_REW_OP_ONE_STEP_PTP 0x2
32#define IFH_REW_OP_TWO_STEP_PTP 0x3
33#define IFH_REW_OP_ORIGIN_PTP 0x5
34
35#define OCELOT_TAG_LEN 16
36#define OCELOT_SHORT_PREFIX_LEN 4
37#define OCELOT_LONG_PREFIX_LEN 16
38#define OCELOT_TOTAL_TAG_LEN (OCELOT_SHORT_PREFIX_LEN + OCELOT_TAG_LEN)
39
40/* The CPU injection header and the CPU extraction header can have 3 types of
41 * prefixes: long, short and no prefix. The format of the header itself is the
42 * same in all 3 cases.
43 *
44 * Extraction with long prefix:
45 *
46 * +-------------------+-------------------+------+------+------------+-------+
47 * | ff:ff:ff:ff:ff:ff | fe:ff:ff:ff:ff:ff | 8880 | 000a | extraction | frame |
48 * | | | | | header | |
49 * +-------------------+-------------------+------+------+------------+-------+
50 * 48 bits 48 bits 16 bits 16 bits 128 bits
51 *
52 * Extraction with short prefix:
53 *
54 * +------+------+------------+-------+
55 * | 8880 | 000a | extraction | frame |
56 * | | | header | |
57 * +------+------+------------+-------+
58 * 16 bits 16 bits 128 bits
59 *
60 * Extraction with no prefix:
61 *
62 * +------------+-------+
63 * | extraction | frame |
64 * | header | |
65 * +------------+-------+
66 * 128 bits
67 *
68 *
69 * Injection with long prefix:
70 *
71 * +-------------------+-------------------+------+------+------------+-------+
72 * | any dmac | any smac | 8880 | 000a | injection | frame |
73 * | | | | | header | |
74 * +-------------------+-------------------+------+------+------------+-------+
75 * 48 bits 48 bits 16 bits 16 bits 128 bits
76 *
77 * Injection with short prefix:
78 *
79 * +------+------+------------+-------+
80 * | 8880 | 000a | injection | frame |
81 * | | | header | |
82 * +------+------+------------+-------+
83 * 16 bits 16 bits 128 bits
84 *
85 * Injection with no prefix:
86 *
87 * +------------+-------+
88 * | injection | frame |
89 * | header | |
90 * +------------+-------+
91 * 128 bits
92 *
93 * The injection header looks like this (network byte order, bit 127
94 * is part of lowest address byte in memory, bit 0 is part of highest
95 * address byte):
96 *
97 * +------+------+------+------+------+------+------+------+
98 * 127:120 |BYPASS| MASQ | MASQ_PORT |REW_OP|REW_OP|
99 * +------+------+------+------+------+------+------+------+
100 * 119:112 | REW_OP |
101 * +------+------+------+------+------+------+------+------+
102 * 111:104 | REW_VAL |
103 * +------+------+------+------+------+------+------+------+
104 * 103: 96 | REW_VAL |
105 * +------+------+------+------+------+------+------+------+
106 * 95: 88 | REW_VAL |
107 * +------+------+------+------+------+------+------+------+
108 * 87: 80 | REW_VAL |
109 * +------+------+------+------+------+------+------+------+
110 * 79: 72 | RSV |
111 * +------+------+------+------+------+------+------+------+
112 * 71: 64 | RSV | DEST |
113 * +------+------+------+------+------+------+------+------+
114 * 63: 56 | DEST |
115 * +------+------+------+------+------+------+------+------+
116 * 55: 48 | RSV |
117 * +------+------+------+------+------+------+------+------+
118 * 47: 40 | RSV | SRC_PORT | RSV |TFRM_TIMER|
119 * +------+------+------+------+------+------+------+------+
120 * 39: 32 | TFRM_TIMER | RSV |
121 * +------+------+------+------+------+------+------+------+
122 * 31: 24 | RSV | DP | POP_CNT | CPUQ |
123 * +------+------+------+------+------+------+------+------+
124 * 23: 16 | CPUQ | QOS_CLASS |TAG_TYPE|
125 * +------+------+------+------+------+------+------+------+
126 * 15: 8 | PCP | DEI | VID |
127 * +------+------+------+------+------+------+------+------+
128 * 7: 0 | VID |
129 * +------+------+------+------+------+------+------+------+
130 *
131 * And the extraction header looks like this:
132 *
133 * +------+------+------+------+------+------+------+------+
134 * 127:120 | RSV | REW_OP |
135 * +------+------+------+------+------+------+------+------+
136 * 119:112 | REW_OP | REW_VAL |
137 * +------+------+------+------+------+------+------+------+
138 * 111:104 | REW_VAL |
139 * +------+------+------+------+------+------+------+------+
140 * 103: 96 | REW_VAL |
141 * +------+------+------+------+------+------+------+------+
142 * 95: 88 | REW_VAL |
143 * +------+------+------+------+------+------+------+------+
144 * 87: 80 | REW_VAL | LLEN |
145 * +------+------+------+------+------+------+------+------+
146 * 79: 72 | LLEN | WLEN |
147 * +------+------+------+------+------+------+------+------+
148 * 71: 64 | WLEN | RSV |
149 * +------+------+------+------+------+------+------+------+
150 * 63: 56 | RSV |
151 * +------+------+------+------+------+------+------+------+
152 * 55: 48 | RSV |
153 * +------+------+------+------+------+------+------+------+
154 * 47: 40 | RSV | SRC_PORT | ACL_ID |
155 * +------+------+------+------+------+------+------+------+
156 * 39: 32 | ACL_ID | RSV | SFLOW_ID |
157 * +------+------+------+------+------+------+------+------+
158 * 31: 24 |ACL_HIT| DP | LRN_FLAGS | CPUQ |
159 * +------+------+------+------+------+------+------+------+
160 * 23: 16 | CPUQ | QOS_CLASS |TAG_TYPE|
161 * +------+------+------+------+------+------+------+------+
162 * 15: 8 | PCP | DEI | VID |
163 * +------+------+------+------+------+------+------+------+
164 * 7: 0 | VID |
165 * +------+------+------+------+------+------+------+------+
166 */
167
168struct felix_deferred_xmit_work {
169 struct dsa_port *dp;
170 struct sk_buff *skb;
171 struct kthread_work work;
172};
173
174struct ocelot_8021q_tagger_data {
175 void (*xmit_work_fn)(struct kthread_work *work);
176};
177
178static inline struct ocelot_8021q_tagger_data *
179ocelot_8021q_tagger_data(struct dsa_switch *ds)
180{
181 BUG_ON(ds->dst->tag_ops->proto != DSA_TAG_PROTO_OCELOT_8021Q);
182
183 return ds->tagger_data;
184}
185
186static inline void ocelot_xfh_get_rew_val(void *extraction, u64 *rew_val)
187{
188 packing(extraction, rew_val, 116, 85, OCELOT_TAG_LEN, UNPACK, 0);
189}
190
191static inline void ocelot_xfh_get_len(void *extraction, u64 *len)
192{
193 u64 llen, wlen;
194
195 packing(extraction, &llen, 84, 79, OCELOT_TAG_LEN, UNPACK, 0);
196 packing(extraction, &wlen, 78, 71, OCELOT_TAG_LEN, UNPACK, 0);
197
198 *len = 60 * wlen + llen - 80;
199}
200
201static inline void ocelot_xfh_get_src_port(void *extraction, u64 *src_port)
202{
203 packing(extraction, src_port, 46, 43, OCELOT_TAG_LEN, UNPACK, 0);
204}
205
206static inline void ocelot_xfh_get_qos_class(void *extraction, u64 *qos_class)
207{
208 packing(extraction, qos_class, 19, 17, OCELOT_TAG_LEN, UNPACK, 0);
209}
210
211static inline void ocelot_xfh_get_tag_type(void *extraction, u64 *tag_type)
212{
213 packing(extraction, tag_type, 16, 16, OCELOT_TAG_LEN, UNPACK, 0);
214}
215
216static inline void ocelot_xfh_get_vlan_tci(void *extraction, u64 *vlan_tci)
217{
218 packing(extraction, vlan_tci, 15, 0, OCELOT_TAG_LEN, UNPACK, 0);
219}
220
221static inline void ocelot_ifh_set_bypass(void *injection, u64 bypass)
222{
223 packing(injection, &bypass, 127, 127, OCELOT_TAG_LEN, PACK, 0);
224}
225
226static inline void ocelot_ifh_set_rew_op(void *injection, u64 rew_op)
227{
228 packing(injection, &rew_op, 125, 117, OCELOT_TAG_LEN, PACK, 0);
229}
230
231static inline void ocelot_ifh_set_dest(void *injection, u64 dest)
232{
233 packing(injection, &dest, 67, 56, OCELOT_TAG_LEN, PACK, 0);
234}
235
236static inline void ocelot_ifh_set_qos_class(void *injection, u64 qos_class)
237{
238 packing(injection, &qos_class, 19, 17, OCELOT_TAG_LEN, PACK, 0);
239}
240
241static inline void seville_ifh_set_dest(void *injection, u64 dest)
242{
243 packing(injection, &dest, 67, 57, OCELOT_TAG_LEN, PACK, 0);
244}
245
246static inline void ocelot_ifh_set_src(void *injection, u64 src)
247{
248 packing(injection, &src, 46, 43, OCELOT_TAG_LEN, PACK, 0);
249}
250
251static inline void ocelot_ifh_set_tag_type(void *injection, u64 tag_type)
252{
253 packing(injection, &tag_type, 16, 16, OCELOT_TAG_LEN, PACK, 0);
254}
255
256static inline void ocelot_ifh_set_vlan_tci(void *injection, u64 vlan_tci)
257{
258 packing(injection, &vlan_tci, 15, 0, OCELOT_TAG_LEN, PACK, 0);
259}
260
261/* Determine the PTP REW_OP to use for injecting the given skb */
262static inline u32 ocelot_ptp_rew_op(struct sk_buff *skb)
263{
264 struct sk_buff *clone = OCELOT_SKB_CB(skb)->clone;
265 u8 ptp_cmd = OCELOT_SKB_CB(skb)->ptp_cmd;
266 u32 rew_op = 0;
267
268 if (ptp_cmd == IFH_REW_OP_TWO_STEP_PTP && clone) {
269 rew_op = ptp_cmd;
270 rew_op |= OCELOT_SKB_CB(clone)->ts_id << 3;
271 } else if (ptp_cmd == IFH_REW_OP_ORIGIN_PTP) {
272 rew_op = ptp_cmd;
273 }
274
275 return rew_op;
276}
277
278/**
279 * ocelot_xmit_get_vlan_info: Determine VLAN_TCI and TAG_TYPE for injected frame
280 * @skb: Pointer to socket buffer
281 * @br: Pointer to bridge device that the port is under, if any
282 * @vlan_tci:
283 * @tag_type:
284 *
285 * If the port is under a VLAN-aware bridge, remove the VLAN header from the
286 * payload and move it into the DSA tag, which will make the switch classify
287 * the packet to the bridge VLAN. Otherwise, leave the classified VLAN at zero,
288 * which is the pvid of standalone ports (OCELOT_STANDALONE_PVID), although not
289 * of VLAN-unaware bridge ports (that would be ocelot_vlan_unaware_pvid()).
290 * Anyway, VID 0 is fine because it is stripped on egress for these port modes,
291 * and source address learning is not performed for packets injected from the
292 * CPU anyway, so it doesn't matter that the VID is "wrong".
293 */
294static inline void ocelot_xmit_get_vlan_info(struct sk_buff *skb,
295 struct net_device *br,
296 u64 *vlan_tci, u64 *tag_type)
297{
298 struct vlan_ethhdr *hdr;
299 u16 proto, tci;
300
301 if (!br || !br_vlan_enabled(br)) {
302 *vlan_tci = 0;
303 *tag_type = IFH_TAG_TYPE_C;
304 return;
305 }
306
307 hdr = (struct vlan_ethhdr *)skb_mac_header(skb);
308 br_vlan_get_proto(br, &proto);
309
310 if (ntohs(hdr->h_vlan_proto) == proto) {
311 vlan_remove_tag(skb, &tci);
312 *vlan_tci = tci;
313 } else {
314 rcu_read_lock();
315 br_vlan_get_pvid_rcu(br, &tci);
316 rcu_read_unlock();
317 *vlan_tci = tci;
318 }
319
320 *tag_type = (proto != ETH_P_8021Q) ? IFH_TAG_TYPE_S : IFH_TAG_TYPE_C;
321}
322
323#endif