Commit | Line | Data |
---|---|---|
9c20346b AV |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright (c) 2018, Intel Corporation. */ | |
3 | ||
348048e7 | 4 | #include "ice_lib.h" |
9c20346b AV |
5 | #include "ice_switch.h" |
6 | ||
9daf8208 AV |
7 | #define ICE_ETH_DA_OFFSET 0 |
8 | #define ICE_ETH_ETHTYPE_OFFSET 12 | |
9 | #define ICE_ETH_VLAN_TCI_OFFSET 14 | |
10 | #define ICE_MAX_VLAN_ID 0xFFF | |
0f94570d | 11 | #define ICE_IPV6_ETHER_ID 0x86DD |
9daf8208 AV |
12 | |
13 | /* Dummy ethernet header needed in the ice_aqc_sw_rules_elem | |
14 | * struct to configure any switch filter rules. | |
15 | * {DA (6 bytes), SA(6 bytes), | |
16 | * Ether type (2 bytes for header without VLAN tag) OR | |
17 | * VLAN tag (4 bytes for header with VLAN tag) } | |
18 | * | |
19 | * Word on Hardcoded values | |
20 | * byte 0 = 0x2: to identify it as locally administered DA MAC | |
21 | * byte 6 = 0x2: to identify it as locally administered SA MAC | |
22 | * byte 12 = 0x81 & byte 13 = 0x00: | |
23 | * In case of VLAN filter first two bytes defines ether type (0x8100) | |
f9867df6 | 24 | * and remaining two bytes are placeholder for programming a given VLAN ID |
9daf8208 AV |
25 | * In case of Ether type filter it is treated as header without VLAN tag |
26 | * and byte 12 and 13 is used to program a given Ether type instead | |
27 | */ | |
28 | #define DUMMY_ETH_HDR_LEN 16 | |
29 | static const u8 dummy_eth_header[DUMMY_ETH_HDR_LEN] = { 0x2, 0, 0, 0, 0, 0, | |
30 | 0x2, 0, 0, 0, 0, 0, | |
31 | 0x81, 0, 0, 0}; | |
32 | ||
e33163a4 | 33 | enum { |
26395726 MSM |
34 | ICE_PKT_OUTER_IPV6 = BIT(0), |
35 | ICE_PKT_TUN_GTPC = BIT(1), | |
36 | ICE_PKT_TUN_GTPU = BIT(2), | |
37 | ICE_PKT_TUN_NVGRE = BIT(3), | |
38 | ICE_PKT_TUN_UDP = BIT(4), | |
39 | ICE_PKT_INNER_IPV6 = BIT(5), | |
40 | ICE_PKT_INNER_TCP = BIT(6), | |
41 | ICE_PKT_INNER_UDP = BIT(7), | |
42 | ICE_PKT_GTP_NOPAY = BIT(8), | |
43 | ICE_PKT_KMALLOC = BIT(9), | |
cd8efeee | 44 | ICE_PKT_PPPOE = BIT(10), |
cd634549 | 45 | ICE_PKT_L2TPV3 = BIT(11), |
e33163a4 AL |
46 | }; |
47 | ||
0f94570d GK |
48 | struct ice_dummy_pkt_offsets { |
49 | enum ice_protocol_type type; | |
50 | u16 offset; /* ICE_PROTOCOL_LAST indicates end of list */ | |
51 | }; | |
52 | ||
1b699f81 AL |
53 | struct ice_dummy_pkt_profile { |
54 | const struct ice_dummy_pkt_offsets *offsets; | |
55 | const u8 *pkt; | |
e33163a4 | 56 | u32 match; |
1b699f81 | 57 | u16 pkt_len; |
26395726 | 58 | u16 offsets_len; |
1b699f81 AL |
59 | }; |
60 | ||
26395726 MSM |
61 | #define ICE_DECLARE_PKT_OFFSETS(type) \ |
62 | static const struct ice_dummy_pkt_offsets \ | |
07a28842 AL |
63 | ice_dummy_##type##_packet_offsets[] |
64 | ||
26395726 | 65 | #define ICE_DECLARE_PKT_TEMPLATE(type) \ |
07a28842 AL |
66 | static const u8 ice_dummy_##type##_packet[] |
67 | ||
26395726 MSM |
68 | #define ICE_PKT_PROFILE(type, m) { \ |
69 | .match = (m), \ | |
70 | .pkt = ice_dummy_##type##_packet, \ | |
71 | .pkt_len = sizeof(ice_dummy_##type##_packet), \ | |
72 | .offsets = ice_dummy_##type##_packet_offsets, \ | |
73 | .offsets_len = sizeof(ice_dummy_##type##_packet_offsets), \ | |
e33163a4 | 74 | } |
1b699f81 | 75 | |
26395726 MSM |
76 | ICE_DECLARE_PKT_OFFSETS(vlan) = { |
77 | { ICE_VLAN_OFOS, 12 }, | |
78 | }; | |
79 | ||
80 | ICE_DECLARE_PKT_TEMPLATE(vlan) = { | |
81 | 0x81, 0x00, 0x00, 0x00, /* ICE_VLAN_OFOS 12 */ | |
82 | }; | |
83 | ||
84 | ICE_DECLARE_PKT_OFFSETS(qinq) = { | |
85 | { ICE_VLAN_EX, 12 }, | |
86 | { ICE_VLAN_IN, 16 }, | |
87 | }; | |
88 | ||
89 | ICE_DECLARE_PKT_TEMPLATE(qinq) = { | |
90 | 0x91, 0x00, 0x00, 0x00, /* ICE_VLAN_EX 12 */ | |
91 | 0x81, 0x00, 0x00, 0x00, /* ICE_VLAN_IN 16 */ | |
92 | }; | |
93 | ||
07a28842 | 94 | ICE_DECLARE_PKT_OFFSETS(gre_tcp) = { |
f0a35040 MS |
95 | { ICE_MAC_OFOS, 0 }, |
96 | { ICE_ETYPE_OL, 12 }, | |
97 | { ICE_IPV4_OFOS, 14 }, | |
98 | { ICE_NVGRE, 34 }, | |
99 | { ICE_MAC_IL, 42 }, | |
34a89775 | 100 | { ICE_ETYPE_IL, 54 }, |
f0a35040 MS |
101 | { ICE_IPV4_IL, 56 }, |
102 | { ICE_TCP_IL, 76 }, | |
103 | { ICE_PROTOCOL_LAST, 0 }, | |
104 | }; | |
105 | ||
07a28842 | 106 | ICE_DECLARE_PKT_TEMPLATE(gre_tcp) = { |
f0a35040 MS |
107 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
108 | 0x00, 0x00, 0x00, 0x00, | |
109 | 0x00, 0x00, 0x00, 0x00, | |
110 | ||
111 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ | |
112 | ||
113 | 0x45, 0x00, 0x00, 0x3E, /* ICE_IPV4_OFOS 14 */ | |
114 | 0x00, 0x00, 0x00, 0x00, | |
115 | 0x00, 0x2F, 0x00, 0x00, | |
116 | 0x00, 0x00, 0x00, 0x00, | |
117 | 0x00, 0x00, 0x00, 0x00, | |
118 | ||
119 | 0x80, 0x00, 0x65, 0x58, /* ICE_NVGRE 34 */ | |
120 | 0x00, 0x00, 0x00, 0x00, | |
121 | ||
122 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 42 */ | |
123 | 0x00, 0x00, 0x00, 0x00, | |
124 | 0x00, 0x00, 0x00, 0x00, | |
34a89775 MSM |
125 | |
126 | 0x08, 0x00, /* ICE_ETYPE_IL 54 */ | |
f0a35040 MS |
127 | |
128 | 0x45, 0x00, 0x00, 0x14, /* ICE_IPV4_IL 56 */ | |
129 | 0x00, 0x00, 0x00, 0x00, | |
130 | 0x00, 0x06, 0x00, 0x00, | |
131 | 0x00, 0x00, 0x00, 0x00, | |
132 | 0x00, 0x00, 0x00, 0x00, | |
133 | ||
134 | 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 76 */ | |
135 | 0x00, 0x00, 0x00, 0x00, | |
136 | 0x00, 0x00, 0x00, 0x00, | |
137 | 0x50, 0x02, 0x20, 0x00, | |
138 | 0x00, 0x00, 0x00, 0x00 | |
139 | }; | |
140 | ||
07a28842 | 141 | ICE_DECLARE_PKT_OFFSETS(gre_udp) = { |
f0a35040 MS |
142 | { ICE_MAC_OFOS, 0 }, |
143 | { ICE_ETYPE_OL, 12 }, | |
144 | { ICE_IPV4_OFOS, 14 }, | |
145 | { ICE_NVGRE, 34 }, | |
146 | { ICE_MAC_IL, 42 }, | |
34a89775 | 147 | { ICE_ETYPE_IL, 54 }, |
f0a35040 MS |
148 | { ICE_IPV4_IL, 56 }, |
149 | { ICE_UDP_ILOS, 76 }, | |
150 | { ICE_PROTOCOL_LAST, 0 }, | |
151 | }; | |
152 | ||
07a28842 | 153 | ICE_DECLARE_PKT_TEMPLATE(gre_udp) = { |
f0a35040 MS |
154 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
155 | 0x00, 0x00, 0x00, 0x00, | |
156 | 0x00, 0x00, 0x00, 0x00, | |
157 | ||
158 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ | |
159 | ||
160 | 0x45, 0x00, 0x00, 0x3E, /* ICE_IPV4_OFOS 14 */ | |
161 | 0x00, 0x00, 0x00, 0x00, | |
162 | 0x00, 0x2F, 0x00, 0x00, | |
163 | 0x00, 0x00, 0x00, 0x00, | |
164 | 0x00, 0x00, 0x00, 0x00, | |
165 | ||
166 | 0x80, 0x00, 0x65, 0x58, /* ICE_NVGRE 34 */ | |
167 | 0x00, 0x00, 0x00, 0x00, | |
168 | ||
169 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 42 */ | |
170 | 0x00, 0x00, 0x00, 0x00, | |
171 | 0x00, 0x00, 0x00, 0x00, | |
34a89775 MSM |
172 | |
173 | 0x08, 0x00, /* ICE_ETYPE_IL 54 */ | |
f0a35040 MS |
174 | |
175 | 0x45, 0x00, 0x00, 0x14, /* ICE_IPV4_IL 56 */ | |
176 | 0x00, 0x00, 0x00, 0x00, | |
177 | 0x00, 0x11, 0x00, 0x00, | |
178 | 0x00, 0x00, 0x00, 0x00, | |
179 | 0x00, 0x00, 0x00, 0x00, | |
180 | ||
181 | 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 76 */ | |
182 | 0x00, 0x08, 0x00, 0x00, | |
183 | }; | |
184 | ||
07a28842 | 185 | ICE_DECLARE_PKT_OFFSETS(udp_tun_tcp) = { |
8b032a55 MS |
186 | { ICE_MAC_OFOS, 0 }, |
187 | { ICE_ETYPE_OL, 12 }, | |
188 | { ICE_IPV4_OFOS, 14 }, | |
189 | { ICE_UDP_OF, 34 }, | |
190 | { ICE_VXLAN, 42 }, | |
191 | { ICE_GENEVE, 42 }, | |
192 | { ICE_VXLAN_GPE, 42 }, | |
193 | { ICE_MAC_IL, 50 }, | |
34a89775 | 194 | { ICE_ETYPE_IL, 62 }, |
8b032a55 MS |
195 | { ICE_IPV4_IL, 64 }, |
196 | { ICE_TCP_IL, 84 }, | |
197 | { ICE_PROTOCOL_LAST, 0 }, | |
198 | }; | |
199 | ||
07a28842 | 200 | ICE_DECLARE_PKT_TEMPLATE(udp_tun_tcp) = { |
8b032a55 MS |
201 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
202 | 0x00, 0x00, 0x00, 0x00, | |
203 | 0x00, 0x00, 0x00, 0x00, | |
204 | ||
205 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ | |
206 | ||
207 | 0x45, 0x00, 0x00, 0x5a, /* ICE_IPV4_OFOS 14 */ | |
208 | 0x00, 0x01, 0x00, 0x00, | |
209 | 0x40, 0x11, 0x00, 0x00, | |
210 | 0x00, 0x00, 0x00, 0x00, | |
211 | 0x00, 0x00, 0x00, 0x00, | |
212 | ||
213 | 0x00, 0x00, 0x12, 0xb5, /* ICE_UDP_OF 34 */ | |
214 | 0x00, 0x46, 0x00, 0x00, | |
215 | ||
216 | 0x00, 0x00, 0x65, 0x58, /* ICE_VXLAN 42 */ | |
217 | 0x00, 0x00, 0x00, 0x00, | |
218 | ||
219 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 50 */ | |
220 | 0x00, 0x00, 0x00, 0x00, | |
221 | 0x00, 0x00, 0x00, 0x00, | |
34a89775 MSM |
222 | |
223 | 0x08, 0x00, /* ICE_ETYPE_IL 62 */ | |
8b032a55 MS |
224 | |
225 | 0x45, 0x00, 0x00, 0x28, /* ICE_IPV4_IL 64 */ | |
226 | 0x00, 0x01, 0x00, 0x00, | |
227 | 0x40, 0x06, 0x00, 0x00, | |
228 | 0x00, 0x00, 0x00, 0x00, | |
229 | 0x00, 0x00, 0x00, 0x00, | |
230 | ||
231 | 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 84 */ | |
232 | 0x00, 0x00, 0x00, 0x00, | |
233 | 0x00, 0x00, 0x00, 0x00, | |
234 | 0x50, 0x02, 0x20, 0x00, | |
235 | 0x00, 0x00, 0x00, 0x00 | |
236 | }; | |
237 | ||
07a28842 | 238 | ICE_DECLARE_PKT_OFFSETS(udp_tun_udp) = { |
8b032a55 MS |
239 | { ICE_MAC_OFOS, 0 }, |
240 | { ICE_ETYPE_OL, 12 }, | |
241 | { ICE_IPV4_OFOS, 14 }, | |
242 | { ICE_UDP_OF, 34 }, | |
243 | { ICE_VXLAN, 42 }, | |
244 | { ICE_GENEVE, 42 }, | |
245 | { ICE_VXLAN_GPE, 42 }, | |
246 | { ICE_MAC_IL, 50 }, | |
34a89775 | 247 | { ICE_ETYPE_IL, 62 }, |
8b032a55 MS |
248 | { ICE_IPV4_IL, 64 }, |
249 | { ICE_UDP_ILOS, 84 }, | |
250 | { ICE_PROTOCOL_LAST, 0 }, | |
251 | }; | |
252 | ||
07a28842 | 253 | ICE_DECLARE_PKT_TEMPLATE(udp_tun_udp) = { |
8b032a55 MS |
254 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
255 | 0x00, 0x00, 0x00, 0x00, | |
256 | 0x00, 0x00, 0x00, 0x00, | |
257 | ||
258 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ | |
259 | ||
260 | 0x45, 0x00, 0x00, 0x4e, /* ICE_IPV4_OFOS 14 */ | |
261 | 0x00, 0x01, 0x00, 0x00, | |
262 | 0x00, 0x11, 0x00, 0x00, | |
263 | 0x00, 0x00, 0x00, 0x00, | |
264 | 0x00, 0x00, 0x00, 0x00, | |
265 | ||
266 | 0x00, 0x00, 0x12, 0xb5, /* ICE_UDP_OF 34 */ | |
267 | 0x00, 0x3a, 0x00, 0x00, | |
268 | ||
269 | 0x00, 0x00, 0x65, 0x58, /* ICE_VXLAN 42 */ | |
270 | 0x00, 0x00, 0x00, 0x00, | |
271 | ||
272 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 50 */ | |
273 | 0x00, 0x00, 0x00, 0x00, | |
274 | 0x00, 0x00, 0x00, 0x00, | |
34a89775 MSM |
275 | |
276 | 0x08, 0x00, /* ICE_ETYPE_IL 62 */ | |
8b032a55 MS |
277 | |
278 | 0x45, 0x00, 0x00, 0x1c, /* ICE_IPV4_IL 64 */ | |
279 | 0x00, 0x01, 0x00, 0x00, | |
280 | 0x00, 0x11, 0x00, 0x00, | |
281 | 0x00, 0x00, 0x00, 0x00, | |
282 | 0x00, 0x00, 0x00, 0x00, | |
283 | ||
284 | 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 84 */ | |
285 | 0x00, 0x08, 0x00, 0x00, | |
286 | }; | |
287 | ||
07a28842 | 288 | ICE_DECLARE_PKT_OFFSETS(gre_ipv6_tcp) = { |
34a89775 MSM |
289 | { ICE_MAC_OFOS, 0 }, |
290 | { ICE_ETYPE_OL, 12 }, | |
291 | { ICE_IPV4_OFOS, 14 }, | |
292 | { ICE_NVGRE, 34 }, | |
293 | { ICE_MAC_IL, 42 }, | |
294 | { ICE_ETYPE_IL, 54 }, | |
295 | { ICE_IPV6_IL, 56 }, | |
296 | { ICE_TCP_IL, 96 }, | |
297 | { ICE_PROTOCOL_LAST, 0 }, | |
298 | }; | |
299 | ||
07a28842 | 300 | ICE_DECLARE_PKT_TEMPLATE(gre_ipv6_tcp) = { |
34a89775 MSM |
301 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
302 | 0x00, 0x00, 0x00, 0x00, | |
303 | 0x00, 0x00, 0x00, 0x00, | |
304 | ||
305 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ | |
306 | ||
307 | 0x45, 0x00, 0x00, 0x66, /* ICE_IPV4_OFOS 14 */ | |
308 | 0x00, 0x00, 0x00, 0x00, | |
309 | 0x00, 0x2F, 0x00, 0x00, | |
310 | 0x00, 0x00, 0x00, 0x00, | |
311 | 0x00, 0x00, 0x00, 0x00, | |
312 | ||
313 | 0x80, 0x00, 0x65, 0x58, /* ICE_NVGRE 34 */ | |
314 | 0x00, 0x00, 0x00, 0x00, | |
315 | ||
316 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 42 */ | |
317 | 0x00, 0x00, 0x00, 0x00, | |
318 | 0x00, 0x00, 0x00, 0x00, | |
319 | ||
320 | 0x86, 0xdd, /* ICE_ETYPE_IL 54 */ | |
321 | ||
322 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_IL 56 */ | |
323 | 0x00, 0x08, 0x06, 0x40, | |
324 | 0x00, 0x00, 0x00, 0x00, | |
325 | 0x00, 0x00, 0x00, 0x00, | |
326 | 0x00, 0x00, 0x00, 0x00, | |
327 | 0x00, 0x00, 0x00, 0x00, | |
328 | 0x00, 0x00, 0x00, 0x00, | |
329 | 0x00, 0x00, 0x00, 0x00, | |
330 | 0x00, 0x00, 0x00, 0x00, | |
331 | 0x00, 0x00, 0x00, 0x00, | |
332 | ||
333 | 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 96 */ | |
334 | 0x00, 0x00, 0x00, 0x00, | |
335 | 0x00, 0x00, 0x00, 0x00, | |
336 | 0x50, 0x02, 0x20, 0x00, | |
337 | 0x00, 0x00, 0x00, 0x00 | |
338 | }; | |
339 | ||
07a28842 | 340 | ICE_DECLARE_PKT_OFFSETS(gre_ipv6_udp) = { |
34a89775 MSM |
341 | { ICE_MAC_OFOS, 0 }, |
342 | { ICE_ETYPE_OL, 12 }, | |
343 | { ICE_IPV4_OFOS, 14 }, | |
344 | { ICE_NVGRE, 34 }, | |
345 | { ICE_MAC_IL, 42 }, | |
346 | { ICE_ETYPE_IL, 54 }, | |
347 | { ICE_IPV6_IL, 56 }, | |
348 | { ICE_UDP_ILOS, 96 }, | |
349 | { ICE_PROTOCOL_LAST, 0 }, | |
350 | }; | |
351 | ||
07a28842 | 352 | ICE_DECLARE_PKT_TEMPLATE(gre_ipv6_udp) = { |
34a89775 MSM |
353 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
354 | 0x00, 0x00, 0x00, 0x00, | |
355 | 0x00, 0x00, 0x00, 0x00, | |
356 | ||
357 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ | |
358 | ||
359 | 0x45, 0x00, 0x00, 0x5a, /* ICE_IPV4_OFOS 14 */ | |
360 | 0x00, 0x00, 0x00, 0x00, | |
361 | 0x00, 0x2F, 0x00, 0x00, | |
362 | 0x00, 0x00, 0x00, 0x00, | |
363 | 0x00, 0x00, 0x00, 0x00, | |
364 | ||
365 | 0x80, 0x00, 0x65, 0x58, /* ICE_NVGRE 34 */ | |
366 | 0x00, 0x00, 0x00, 0x00, | |
367 | ||
368 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 42 */ | |
369 | 0x00, 0x00, 0x00, 0x00, | |
370 | 0x00, 0x00, 0x00, 0x00, | |
371 | ||
372 | 0x86, 0xdd, /* ICE_ETYPE_IL 54 */ | |
373 | ||
374 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_IL 56 */ | |
375 | 0x00, 0x08, 0x11, 0x40, | |
376 | 0x00, 0x00, 0x00, 0x00, | |
377 | 0x00, 0x00, 0x00, 0x00, | |
378 | 0x00, 0x00, 0x00, 0x00, | |
379 | 0x00, 0x00, 0x00, 0x00, | |
380 | 0x00, 0x00, 0x00, 0x00, | |
381 | 0x00, 0x00, 0x00, 0x00, | |
382 | 0x00, 0x00, 0x00, 0x00, | |
383 | 0x00, 0x00, 0x00, 0x00, | |
384 | ||
385 | 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 96 */ | |
386 | 0x00, 0x08, 0x00, 0x00, | |
387 | }; | |
388 | ||
07a28842 | 389 | ICE_DECLARE_PKT_OFFSETS(udp_tun_ipv6_tcp) = { |
34a89775 MSM |
390 | { ICE_MAC_OFOS, 0 }, |
391 | { ICE_ETYPE_OL, 12 }, | |
392 | { ICE_IPV4_OFOS, 14 }, | |
393 | { ICE_UDP_OF, 34 }, | |
394 | { ICE_VXLAN, 42 }, | |
395 | { ICE_GENEVE, 42 }, | |
396 | { ICE_VXLAN_GPE, 42 }, | |
397 | { ICE_MAC_IL, 50 }, | |
398 | { ICE_ETYPE_IL, 62 }, | |
399 | { ICE_IPV6_IL, 64 }, | |
400 | { ICE_TCP_IL, 104 }, | |
401 | { ICE_PROTOCOL_LAST, 0 }, | |
402 | }; | |
403 | ||
07a28842 | 404 | ICE_DECLARE_PKT_TEMPLATE(udp_tun_ipv6_tcp) = { |
34a89775 MSM |
405 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
406 | 0x00, 0x00, 0x00, 0x00, | |
407 | 0x00, 0x00, 0x00, 0x00, | |
408 | ||
409 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ | |
410 | ||
411 | 0x45, 0x00, 0x00, 0x6e, /* ICE_IPV4_OFOS 14 */ | |
412 | 0x00, 0x01, 0x00, 0x00, | |
413 | 0x40, 0x11, 0x00, 0x00, | |
414 | 0x00, 0x00, 0x00, 0x00, | |
415 | 0x00, 0x00, 0x00, 0x00, | |
416 | ||
417 | 0x00, 0x00, 0x12, 0xb5, /* ICE_UDP_OF 34 */ | |
418 | 0x00, 0x5a, 0x00, 0x00, | |
419 | ||
420 | 0x00, 0x00, 0x65, 0x58, /* ICE_VXLAN 42 */ | |
421 | 0x00, 0x00, 0x00, 0x00, | |
422 | ||
423 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 50 */ | |
424 | 0x00, 0x00, 0x00, 0x00, | |
425 | 0x00, 0x00, 0x00, 0x00, | |
426 | ||
427 | 0x86, 0xdd, /* ICE_ETYPE_IL 62 */ | |
428 | ||
429 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_IL 64 */ | |
430 | 0x00, 0x08, 0x06, 0x40, | |
431 | 0x00, 0x00, 0x00, 0x00, | |
432 | 0x00, 0x00, 0x00, 0x00, | |
433 | 0x00, 0x00, 0x00, 0x00, | |
434 | 0x00, 0x00, 0x00, 0x00, | |
435 | 0x00, 0x00, 0x00, 0x00, | |
436 | 0x00, 0x00, 0x00, 0x00, | |
437 | 0x00, 0x00, 0x00, 0x00, | |
438 | 0x00, 0x00, 0x00, 0x00, | |
439 | ||
440 | 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 104 */ | |
441 | 0x00, 0x00, 0x00, 0x00, | |
442 | 0x00, 0x00, 0x00, 0x00, | |
443 | 0x50, 0x02, 0x20, 0x00, | |
444 | 0x00, 0x00, 0x00, 0x00 | |
445 | }; | |
446 | ||
07a28842 | 447 | ICE_DECLARE_PKT_OFFSETS(udp_tun_ipv6_udp) = { |
34a89775 MSM |
448 | { ICE_MAC_OFOS, 0 }, |
449 | { ICE_ETYPE_OL, 12 }, | |
450 | { ICE_IPV4_OFOS, 14 }, | |
451 | { ICE_UDP_OF, 34 }, | |
452 | { ICE_VXLAN, 42 }, | |
453 | { ICE_GENEVE, 42 }, | |
454 | { ICE_VXLAN_GPE, 42 }, | |
455 | { ICE_MAC_IL, 50 }, | |
456 | { ICE_ETYPE_IL, 62 }, | |
457 | { ICE_IPV6_IL, 64 }, | |
458 | { ICE_UDP_ILOS, 104 }, | |
459 | { ICE_PROTOCOL_LAST, 0 }, | |
460 | }; | |
461 | ||
07a28842 | 462 | ICE_DECLARE_PKT_TEMPLATE(udp_tun_ipv6_udp) = { |
34a89775 MSM |
463 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
464 | 0x00, 0x00, 0x00, 0x00, | |
465 | 0x00, 0x00, 0x00, 0x00, | |
466 | ||
467 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ | |
468 | ||
469 | 0x45, 0x00, 0x00, 0x62, /* ICE_IPV4_OFOS 14 */ | |
470 | 0x00, 0x01, 0x00, 0x00, | |
471 | 0x00, 0x11, 0x00, 0x00, | |
472 | 0x00, 0x00, 0x00, 0x00, | |
473 | 0x00, 0x00, 0x00, 0x00, | |
474 | ||
475 | 0x00, 0x00, 0x12, 0xb5, /* ICE_UDP_OF 34 */ | |
476 | 0x00, 0x4e, 0x00, 0x00, | |
477 | ||
478 | 0x00, 0x00, 0x65, 0x58, /* ICE_VXLAN 42 */ | |
479 | 0x00, 0x00, 0x00, 0x00, | |
480 | ||
481 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_IL 50 */ | |
482 | 0x00, 0x00, 0x00, 0x00, | |
483 | 0x00, 0x00, 0x00, 0x00, | |
484 | ||
485 | 0x86, 0xdd, /* ICE_ETYPE_IL 62 */ | |
486 | ||
487 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_IL 64 */ | |
488 | 0x00, 0x08, 0x11, 0x40, | |
489 | 0x00, 0x00, 0x00, 0x00, | |
490 | 0x00, 0x00, 0x00, 0x00, | |
491 | 0x00, 0x00, 0x00, 0x00, | |
492 | 0x00, 0x00, 0x00, 0x00, | |
493 | 0x00, 0x00, 0x00, 0x00, | |
494 | 0x00, 0x00, 0x00, 0x00, | |
495 | 0x00, 0x00, 0x00, 0x00, | |
496 | 0x00, 0x00, 0x00, 0x00, | |
497 | ||
498 | 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 104 */ | |
499 | 0x00, 0x08, 0x00, 0x00, | |
500 | }; | |
501 | ||
0f94570d | 502 | /* offset info for MAC + IPv4 + UDP dummy packet */ |
07a28842 | 503 | ICE_DECLARE_PKT_OFFSETS(udp) = { |
0f94570d GK |
504 | { ICE_MAC_OFOS, 0 }, |
505 | { ICE_ETYPE_OL, 12 }, | |
506 | { ICE_IPV4_OFOS, 14 }, | |
507 | { ICE_UDP_ILOS, 34 }, | |
508 | { ICE_PROTOCOL_LAST, 0 }, | |
509 | }; | |
510 | ||
511 | /* Dummy packet for MAC + IPv4 + UDP */ | |
07a28842 | 512 | ICE_DECLARE_PKT_TEMPLATE(udp) = { |
0f94570d GK |
513 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
514 | 0x00, 0x00, 0x00, 0x00, | |
515 | 0x00, 0x00, 0x00, 0x00, | |
516 | ||
517 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ | |
518 | ||
519 | 0x45, 0x00, 0x00, 0x1c, /* ICE_IPV4_OFOS 14 */ | |
520 | 0x00, 0x01, 0x00, 0x00, | |
521 | 0x00, 0x11, 0x00, 0x00, | |
522 | 0x00, 0x00, 0x00, 0x00, | |
523 | 0x00, 0x00, 0x00, 0x00, | |
524 | ||
525 | 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 34 */ | |
526 | 0x00, 0x08, 0x00, 0x00, | |
527 | ||
528 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ | |
529 | }; | |
530 | ||
0f94570d | 531 | /* offset info for MAC + IPv4 + TCP dummy packet */ |
07a28842 | 532 | ICE_DECLARE_PKT_OFFSETS(tcp) = { |
0f94570d GK |
533 | { ICE_MAC_OFOS, 0 }, |
534 | { ICE_ETYPE_OL, 12 }, | |
535 | { ICE_IPV4_OFOS, 14 }, | |
536 | { ICE_TCP_IL, 34 }, | |
537 | { ICE_PROTOCOL_LAST, 0 }, | |
538 | }; | |
539 | ||
540 | /* Dummy packet for MAC + IPv4 + TCP */ | |
07a28842 | 541 | ICE_DECLARE_PKT_TEMPLATE(tcp) = { |
0f94570d GK |
542 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
543 | 0x00, 0x00, 0x00, 0x00, | |
544 | 0x00, 0x00, 0x00, 0x00, | |
545 | ||
546 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ | |
547 | ||
548 | 0x45, 0x00, 0x00, 0x28, /* ICE_IPV4_OFOS 14 */ | |
549 | 0x00, 0x01, 0x00, 0x00, | |
550 | 0x00, 0x06, 0x00, 0x00, | |
551 | 0x00, 0x00, 0x00, 0x00, | |
552 | 0x00, 0x00, 0x00, 0x00, | |
553 | ||
554 | 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 34 */ | |
555 | 0x00, 0x00, 0x00, 0x00, | |
556 | 0x00, 0x00, 0x00, 0x00, | |
557 | 0x50, 0x00, 0x00, 0x00, | |
558 | 0x00, 0x00, 0x00, 0x00, | |
559 | ||
560 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ | |
561 | }; | |
562 | ||
07a28842 | 563 | ICE_DECLARE_PKT_OFFSETS(tcp_ipv6) = { |
0f94570d GK |
564 | { ICE_MAC_OFOS, 0 }, |
565 | { ICE_ETYPE_OL, 12 }, | |
566 | { ICE_IPV6_OFOS, 14 }, | |
567 | { ICE_TCP_IL, 54 }, | |
568 | { ICE_PROTOCOL_LAST, 0 }, | |
569 | }; | |
570 | ||
07a28842 | 571 | ICE_DECLARE_PKT_TEMPLATE(tcp_ipv6) = { |
0f94570d GK |
572 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
573 | 0x00, 0x00, 0x00, 0x00, | |
574 | 0x00, 0x00, 0x00, 0x00, | |
575 | ||
576 | 0x86, 0xDD, /* ICE_ETYPE_OL 12 */ | |
577 | ||
578 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 40 */ | |
579 | 0x00, 0x14, 0x06, 0x00, /* Next header is TCP */ | |
580 | 0x00, 0x00, 0x00, 0x00, | |
581 | 0x00, 0x00, 0x00, 0x00, | |
582 | 0x00, 0x00, 0x00, 0x00, | |
583 | 0x00, 0x00, 0x00, 0x00, | |
584 | 0x00, 0x00, 0x00, 0x00, | |
585 | 0x00, 0x00, 0x00, 0x00, | |
586 | 0x00, 0x00, 0x00, 0x00, | |
587 | 0x00, 0x00, 0x00, 0x00, | |
588 | ||
589 | 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 54 */ | |
590 | 0x00, 0x00, 0x00, 0x00, | |
591 | 0x00, 0x00, 0x00, 0x00, | |
592 | 0x50, 0x00, 0x00, 0x00, | |
593 | 0x00, 0x00, 0x00, 0x00, | |
594 | ||
595 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ | |
596 | }; | |
597 | ||
0f94570d | 598 | /* IPv6 + UDP */ |
07a28842 | 599 | ICE_DECLARE_PKT_OFFSETS(udp_ipv6) = { |
0f94570d GK |
600 | { ICE_MAC_OFOS, 0 }, |
601 | { ICE_ETYPE_OL, 12 }, | |
602 | { ICE_IPV6_OFOS, 14 }, | |
603 | { ICE_UDP_ILOS, 54 }, | |
604 | { ICE_PROTOCOL_LAST, 0 }, | |
605 | }; | |
606 | ||
607 | /* IPv6 + UDP dummy packet */ | |
07a28842 | 608 | ICE_DECLARE_PKT_TEMPLATE(udp_ipv6) = { |
0f94570d GK |
609 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
610 | 0x00, 0x00, 0x00, 0x00, | |
611 | 0x00, 0x00, 0x00, 0x00, | |
612 | ||
613 | 0x86, 0xDD, /* ICE_ETYPE_OL 12 */ | |
614 | ||
615 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 40 */ | |
616 | 0x00, 0x10, 0x11, 0x00, /* Next header UDP */ | |
617 | 0x00, 0x00, 0x00, 0x00, | |
618 | 0x00, 0x00, 0x00, 0x00, | |
619 | 0x00, 0x00, 0x00, 0x00, | |
620 | 0x00, 0x00, 0x00, 0x00, | |
621 | 0x00, 0x00, 0x00, 0x00, | |
622 | 0x00, 0x00, 0x00, 0x00, | |
623 | 0x00, 0x00, 0x00, 0x00, | |
624 | 0x00, 0x00, 0x00, 0x00, | |
625 | ||
626 | 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 54 */ | |
627 | 0x00, 0x10, 0x00, 0x00, | |
628 | ||
629 | 0x00, 0x00, 0x00, 0x00, /* needed for ESP packets */ | |
630 | 0x00, 0x00, 0x00, 0x00, | |
631 | ||
632 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ | |
633 | }; | |
634 | ||
9a225f81 | 635 | /* Outer IPv4 + Outer UDP + GTP + Inner IPv4 + Inner TCP */ |
07a28842 | 636 | ICE_DECLARE_PKT_OFFSETS(ipv4_gtpu_ipv4_tcp) = { |
9a225f81 MS |
637 | { ICE_MAC_OFOS, 0 }, |
638 | { ICE_IPV4_OFOS, 14 }, | |
639 | { ICE_UDP_OF, 34 }, | |
640 | { ICE_GTP, 42 }, | |
641 | { ICE_IPV4_IL, 62 }, | |
642 | { ICE_TCP_IL, 82 }, | |
643 | { ICE_PROTOCOL_LAST, 0 }, | |
644 | }; | |
645 | ||
07a28842 | 646 | ICE_DECLARE_PKT_TEMPLATE(ipv4_gtpu_ipv4_tcp) = { |
9a225f81 MS |
647 | 0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */ |
648 | 0x00, 0x00, 0x00, 0x00, | |
649 | 0x00, 0x00, 0x00, 0x00, | |
650 | 0x08, 0x00, | |
651 | ||
652 | 0x45, 0x00, 0x00, 0x58, /* IP 14 */ | |
653 | 0x00, 0x00, 0x00, 0x00, | |
654 | 0x00, 0x11, 0x00, 0x00, | |
655 | 0x00, 0x00, 0x00, 0x00, | |
656 | 0x00, 0x00, 0x00, 0x00, | |
657 | ||
658 | 0x00, 0x00, 0x08, 0x68, /* UDP 34 */ | |
659 | 0x00, 0x44, 0x00, 0x00, | |
660 | ||
661 | 0x34, 0xff, 0x00, 0x34, /* ICE_GTP Header 42 */ | |
662 | 0x00, 0x00, 0x00, 0x00, | |
663 | 0x00, 0x00, 0x00, 0x85, | |
664 | ||
665 | 0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 54 */ | |
666 | 0x00, 0x00, 0x00, 0x00, | |
667 | ||
668 | 0x45, 0x00, 0x00, 0x28, /* IP 62 */ | |
669 | 0x00, 0x00, 0x00, 0x00, | |
670 | 0x00, 0x06, 0x00, 0x00, | |
671 | 0x00, 0x00, 0x00, 0x00, | |
672 | 0x00, 0x00, 0x00, 0x00, | |
673 | ||
674 | 0x00, 0x00, 0x00, 0x00, /* TCP 82 */ | |
675 | 0x00, 0x00, 0x00, 0x00, | |
676 | 0x00, 0x00, 0x00, 0x00, | |
677 | 0x50, 0x00, 0x00, 0x00, | |
678 | 0x00, 0x00, 0x00, 0x00, | |
679 | ||
680 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ | |
681 | }; | |
682 | ||
683 | /* Outer IPv4 + Outer UDP + GTP + Inner IPv4 + Inner UDP */ | |
07a28842 | 684 | ICE_DECLARE_PKT_OFFSETS(ipv4_gtpu_ipv4_udp) = { |
9a225f81 MS |
685 | { ICE_MAC_OFOS, 0 }, |
686 | { ICE_IPV4_OFOS, 14 }, | |
687 | { ICE_UDP_OF, 34 }, | |
688 | { ICE_GTP, 42 }, | |
689 | { ICE_IPV4_IL, 62 }, | |
690 | { ICE_UDP_ILOS, 82 }, | |
691 | { ICE_PROTOCOL_LAST, 0 }, | |
692 | }; | |
693 | ||
07a28842 | 694 | ICE_DECLARE_PKT_TEMPLATE(ipv4_gtpu_ipv4_udp) = { |
9a225f81 MS |
695 | 0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */ |
696 | 0x00, 0x00, 0x00, 0x00, | |
697 | 0x00, 0x00, 0x00, 0x00, | |
698 | 0x08, 0x00, | |
699 | ||
700 | 0x45, 0x00, 0x00, 0x4c, /* IP 14 */ | |
701 | 0x00, 0x00, 0x00, 0x00, | |
702 | 0x00, 0x11, 0x00, 0x00, | |
703 | 0x00, 0x00, 0x00, 0x00, | |
704 | 0x00, 0x00, 0x00, 0x00, | |
705 | ||
706 | 0x00, 0x00, 0x08, 0x68, /* UDP 34 */ | |
707 | 0x00, 0x38, 0x00, 0x00, | |
708 | ||
709 | 0x34, 0xff, 0x00, 0x28, /* ICE_GTP Header 42 */ | |
710 | 0x00, 0x00, 0x00, 0x00, | |
711 | 0x00, 0x00, 0x00, 0x85, | |
712 | ||
713 | 0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 54 */ | |
714 | 0x00, 0x00, 0x00, 0x00, | |
715 | ||
716 | 0x45, 0x00, 0x00, 0x1c, /* IP 62 */ | |
717 | 0x00, 0x00, 0x00, 0x00, | |
718 | 0x00, 0x11, 0x00, 0x00, | |
719 | 0x00, 0x00, 0x00, 0x00, | |
720 | 0x00, 0x00, 0x00, 0x00, | |
721 | ||
722 | 0x00, 0x00, 0x00, 0x00, /* UDP 82 */ | |
723 | 0x00, 0x08, 0x00, 0x00, | |
724 | ||
725 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ | |
726 | }; | |
727 | ||
728 | /* Outer IPv6 + Outer UDP + GTP + Inner IPv4 + Inner TCP */ | |
07a28842 | 729 | ICE_DECLARE_PKT_OFFSETS(ipv4_gtpu_ipv6_tcp) = { |
9a225f81 MS |
730 | { ICE_MAC_OFOS, 0 }, |
731 | { ICE_IPV4_OFOS, 14 }, | |
732 | { ICE_UDP_OF, 34 }, | |
733 | { ICE_GTP, 42 }, | |
734 | { ICE_IPV6_IL, 62 }, | |
735 | { ICE_TCP_IL, 102 }, | |
736 | { ICE_PROTOCOL_LAST, 0 }, | |
737 | }; | |
738 | ||
07a28842 | 739 | ICE_DECLARE_PKT_TEMPLATE(ipv4_gtpu_ipv6_tcp) = { |
9a225f81 MS |
740 | 0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */ |
741 | 0x00, 0x00, 0x00, 0x00, | |
742 | 0x00, 0x00, 0x00, 0x00, | |
743 | 0x08, 0x00, | |
744 | ||
745 | 0x45, 0x00, 0x00, 0x6c, /* IP 14 */ | |
746 | 0x00, 0x00, 0x00, 0x00, | |
747 | 0x00, 0x11, 0x00, 0x00, | |
748 | 0x00, 0x00, 0x00, 0x00, | |
749 | 0x00, 0x00, 0x00, 0x00, | |
750 | ||
751 | 0x00, 0x00, 0x08, 0x68, /* UDP 34 */ | |
752 | 0x00, 0x58, 0x00, 0x00, | |
753 | ||
754 | 0x34, 0xff, 0x00, 0x48, /* ICE_GTP Header 42 */ | |
755 | 0x00, 0x00, 0x00, 0x00, | |
756 | 0x00, 0x00, 0x00, 0x85, | |
757 | ||
758 | 0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 54 */ | |
759 | 0x00, 0x00, 0x00, 0x00, | |
760 | ||
761 | 0x60, 0x00, 0x00, 0x00, /* IPv6 62 */ | |
762 | 0x00, 0x14, 0x06, 0x00, | |
763 | 0x00, 0x00, 0x00, 0x00, | |
764 | 0x00, 0x00, 0x00, 0x00, | |
765 | 0x00, 0x00, 0x00, 0x00, | |
766 | 0x00, 0x00, 0x00, 0x00, | |
767 | 0x00, 0x00, 0x00, 0x00, | |
768 | 0x00, 0x00, 0x00, 0x00, | |
769 | 0x00, 0x00, 0x00, 0x00, | |
770 | 0x00, 0x00, 0x00, 0x00, | |
771 | ||
772 | 0x00, 0x00, 0x00, 0x00, /* TCP 102 */ | |
773 | 0x00, 0x00, 0x00, 0x00, | |
774 | 0x00, 0x00, 0x00, 0x00, | |
775 | 0x50, 0x00, 0x00, 0x00, | |
776 | 0x00, 0x00, 0x00, 0x00, | |
777 | ||
778 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ | |
779 | }; | |
780 | ||
07a28842 | 781 | ICE_DECLARE_PKT_OFFSETS(ipv4_gtpu_ipv6_udp) = { |
9a225f81 MS |
782 | { ICE_MAC_OFOS, 0 }, |
783 | { ICE_IPV4_OFOS, 14 }, | |
784 | { ICE_UDP_OF, 34 }, | |
785 | { ICE_GTP, 42 }, | |
786 | { ICE_IPV6_IL, 62 }, | |
787 | { ICE_UDP_ILOS, 102 }, | |
788 | { ICE_PROTOCOL_LAST, 0 }, | |
789 | }; | |
790 | ||
07a28842 | 791 | ICE_DECLARE_PKT_TEMPLATE(ipv4_gtpu_ipv6_udp) = { |
9a225f81 MS |
792 | 0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */ |
793 | 0x00, 0x00, 0x00, 0x00, | |
794 | 0x00, 0x00, 0x00, 0x00, | |
795 | 0x08, 0x00, | |
796 | ||
797 | 0x45, 0x00, 0x00, 0x60, /* IP 14 */ | |
798 | 0x00, 0x00, 0x00, 0x00, | |
799 | 0x00, 0x11, 0x00, 0x00, | |
800 | 0x00, 0x00, 0x00, 0x00, | |
801 | 0x00, 0x00, 0x00, 0x00, | |
802 | ||
803 | 0x00, 0x00, 0x08, 0x68, /* UDP 34 */ | |
804 | 0x00, 0x4c, 0x00, 0x00, | |
805 | ||
806 | 0x34, 0xff, 0x00, 0x3c, /* ICE_GTP Header 42 */ | |
807 | 0x00, 0x00, 0x00, 0x00, | |
808 | 0x00, 0x00, 0x00, 0x85, | |
809 | ||
810 | 0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 54 */ | |
811 | 0x00, 0x00, 0x00, 0x00, | |
812 | ||
813 | 0x60, 0x00, 0x00, 0x00, /* IPv6 62 */ | |
814 | 0x00, 0x08, 0x11, 0x00, | |
815 | 0x00, 0x00, 0x00, 0x00, | |
816 | 0x00, 0x00, 0x00, 0x00, | |
817 | 0x00, 0x00, 0x00, 0x00, | |
818 | 0x00, 0x00, 0x00, 0x00, | |
819 | 0x00, 0x00, 0x00, 0x00, | |
820 | 0x00, 0x00, 0x00, 0x00, | |
821 | 0x00, 0x00, 0x00, 0x00, | |
822 | 0x00, 0x00, 0x00, 0x00, | |
823 | ||
824 | 0x00, 0x00, 0x00, 0x00, /* UDP 102 */ | |
825 | 0x00, 0x08, 0x00, 0x00, | |
826 | ||
827 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ | |
828 | }; | |
829 | ||
07a28842 | 830 | ICE_DECLARE_PKT_OFFSETS(ipv6_gtpu_ipv4_tcp) = { |
9a225f81 MS |
831 | { ICE_MAC_OFOS, 0 }, |
832 | { ICE_IPV6_OFOS, 14 }, | |
833 | { ICE_UDP_OF, 54 }, | |
834 | { ICE_GTP, 62 }, | |
835 | { ICE_IPV4_IL, 82 }, | |
836 | { ICE_TCP_IL, 102 }, | |
837 | { ICE_PROTOCOL_LAST, 0 }, | |
838 | }; | |
839 | ||
07a28842 | 840 | ICE_DECLARE_PKT_TEMPLATE(ipv6_gtpu_ipv4_tcp) = { |
9a225f81 MS |
841 | 0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */ |
842 | 0x00, 0x00, 0x00, 0x00, | |
843 | 0x00, 0x00, 0x00, 0x00, | |
844 | 0x86, 0xdd, | |
845 | ||
846 | 0x60, 0x00, 0x00, 0x00, /* IPv6 14 */ | |
847 | 0x00, 0x44, 0x11, 0x00, | |
848 | 0x00, 0x00, 0x00, 0x00, | |
849 | 0x00, 0x00, 0x00, 0x00, | |
850 | 0x00, 0x00, 0x00, 0x00, | |
851 | 0x00, 0x00, 0x00, 0x00, | |
852 | 0x00, 0x00, 0x00, 0x00, | |
853 | 0x00, 0x00, 0x00, 0x00, | |
854 | 0x00, 0x00, 0x00, 0x00, | |
855 | 0x00, 0x00, 0x00, 0x00, | |
856 | ||
857 | 0x00, 0x00, 0x08, 0x68, /* UDP 54 */ | |
858 | 0x00, 0x44, 0x00, 0x00, | |
859 | ||
860 | 0x34, 0xff, 0x00, 0x34, /* ICE_GTP Header 62 */ | |
861 | 0x00, 0x00, 0x00, 0x00, | |
862 | 0x00, 0x00, 0x00, 0x85, | |
863 | ||
864 | 0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 74 */ | |
865 | 0x00, 0x00, 0x00, 0x00, | |
866 | ||
867 | 0x45, 0x00, 0x00, 0x28, /* IP 82 */ | |
868 | 0x00, 0x00, 0x00, 0x00, | |
869 | 0x00, 0x06, 0x00, 0x00, | |
870 | 0x00, 0x00, 0x00, 0x00, | |
871 | 0x00, 0x00, 0x00, 0x00, | |
872 | ||
873 | 0x00, 0x00, 0x00, 0x00, /* TCP 102 */ | |
874 | 0x00, 0x00, 0x00, 0x00, | |
875 | 0x00, 0x00, 0x00, 0x00, | |
876 | 0x50, 0x00, 0x00, 0x00, | |
877 | 0x00, 0x00, 0x00, 0x00, | |
878 | ||
879 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ | |
880 | }; | |
881 | ||
07a28842 | 882 | ICE_DECLARE_PKT_OFFSETS(ipv6_gtpu_ipv4_udp) = { |
9a225f81 MS |
883 | { ICE_MAC_OFOS, 0 }, |
884 | { ICE_IPV6_OFOS, 14 }, | |
885 | { ICE_UDP_OF, 54 }, | |
886 | { ICE_GTP, 62 }, | |
887 | { ICE_IPV4_IL, 82 }, | |
888 | { ICE_UDP_ILOS, 102 }, | |
889 | { ICE_PROTOCOL_LAST, 0 }, | |
890 | }; | |
891 | ||
07a28842 | 892 | ICE_DECLARE_PKT_TEMPLATE(ipv6_gtpu_ipv4_udp) = { |
9a225f81 MS |
893 | 0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */ |
894 | 0x00, 0x00, 0x00, 0x00, | |
895 | 0x00, 0x00, 0x00, 0x00, | |
896 | 0x86, 0xdd, | |
897 | ||
898 | 0x60, 0x00, 0x00, 0x00, /* IPv6 14 */ | |
899 | 0x00, 0x38, 0x11, 0x00, | |
900 | 0x00, 0x00, 0x00, 0x00, | |
901 | 0x00, 0x00, 0x00, 0x00, | |
902 | 0x00, 0x00, 0x00, 0x00, | |
903 | 0x00, 0x00, 0x00, 0x00, | |
904 | 0x00, 0x00, 0x00, 0x00, | |
905 | 0x00, 0x00, 0x00, 0x00, | |
906 | 0x00, 0x00, 0x00, 0x00, | |
907 | 0x00, 0x00, 0x00, 0x00, | |
908 | ||
909 | 0x00, 0x00, 0x08, 0x68, /* UDP 54 */ | |
910 | 0x00, 0x38, 0x00, 0x00, | |
911 | ||
912 | 0x34, 0xff, 0x00, 0x28, /* ICE_GTP Header 62 */ | |
913 | 0x00, 0x00, 0x00, 0x00, | |
914 | 0x00, 0x00, 0x00, 0x85, | |
915 | ||
916 | 0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 74 */ | |
917 | 0x00, 0x00, 0x00, 0x00, | |
918 | ||
919 | 0x45, 0x00, 0x00, 0x1c, /* IP 82 */ | |
920 | 0x00, 0x00, 0x00, 0x00, | |
921 | 0x00, 0x11, 0x00, 0x00, | |
922 | 0x00, 0x00, 0x00, 0x00, | |
923 | 0x00, 0x00, 0x00, 0x00, | |
924 | ||
925 | 0x00, 0x00, 0x00, 0x00, /* UDP 102 */ | |
926 | 0x00, 0x08, 0x00, 0x00, | |
927 | ||
928 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ | |
929 | }; | |
930 | ||
07a28842 | 931 | ICE_DECLARE_PKT_OFFSETS(ipv6_gtpu_ipv6_tcp) = { |
9a225f81 MS |
932 | { ICE_MAC_OFOS, 0 }, |
933 | { ICE_IPV6_OFOS, 14 }, | |
934 | { ICE_UDP_OF, 54 }, | |
935 | { ICE_GTP, 62 }, | |
936 | { ICE_IPV6_IL, 82 }, | |
937 | { ICE_TCP_IL, 122 }, | |
938 | { ICE_PROTOCOL_LAST, 0 }, | |
939 | }; | |
940 | ||
07a28842 | 941 | ICE_DECLARE_PKT_TEMPLATE(ipv6_gtpu_ipv6_tcp) = { |
9a225f81 MS |
942 | 0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */ |
943 | 0x00, 0x00, 0x00, 0x00, | |
944 | 0x00, 0x00, 0x00, 0x00, | |
945 | 0x86, 0xdd, | |
946 | ||
947 | 0x60, 0x00, 0x00, 0x00, /* IPv6 14 */ | |
948 | 0x00, 0x58, 0x11, 0x00, | |
949 | 0x00, 0x00, 0x00, 0x00, | |
950 | 0x00, 0x00, 0x00, 0x00, | |
951 | 0x00, 0x00, 0x00, 0x00, | |
952 | 0x00, 0x00, 0x00, 0x00, | |
953 | 0x00, 0x00, 0x00, 0x00, | |
954 | 0x00, 0x00, 0x00, 0x00, | |
955 | 0x00, 0x00, 0x00, 0x00, | |
956 | 0x00, 0x00, 0x00, 0x00, | |
957 | ||
958 | 0x00, 0x00, 0x08, 0x68, /* UDP 54 */ | |
959 | 0x00, 0x58, 0x00, 0x00, | |
960 | ||
961 | 0x34, 0xff, 0x00, 0x48, /* ICE_GTP Header 62 */ | |
962 | 0x00, 0x00, 0x00, 0x00, | |
963 | 0x00, 0x00, 0x00, 0x85, | |
964 | ||
965 | 0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 74 */ | |
966 | 0x00, 0x00, 0x00, 0x00, | |
967 | ||
968 | 0x60, 0x00, 0x00, 0x00, /* IPv6 82 */ | |
969 | 0x00, 0x14, 0x06, 0x00, | |
970 | 0x00, 0x00, 0x00, 0x00, | |
971 | 0x00, 0x00, 0x00, 0x00, | |
972 | 0x00, 0x00, 0x00, 0x00, | |
973 | 0x00, 0x00, 0x00, 0x00, | |
974 | 0x00, 0x00, 0x00, 0x00, | |
975 | 0x00, 0x00, 0x00, 0x00, | |
976 | 0x00, 0x00, 0x00, 0x00, | |
977 | 0x00, 0x00, 0x00, 0x00, | |
978 | ||
979 | 0x00, 0x00, 0x00, 0x00, /* TCP 122 */ | |
980 | 0x00, 0x00, 0x00, 0x00, | |
981 | 0x00, 0x00, 0x00, 0x00, | |
982 | 0x50, 0x00, 0x00, 0x00, | |
983 | 0x00, 0x00, 0x00, 0x00, | |
984 | ||
985 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ | |
986 | }; | |
987 | ||
07a28842 | 988 | ICE_DECLARE_PKT_OFFSETS(ipv6_gtpu_ipv6_udp) = { |
9a225f81 MS |
989 | { ICE_MAC_OFOS, 0 }, |
990 | { ICE_IPV6_OFOS, 14 }, | |
991 | { ICE_UDP_OF, 54 }, | |
992 | { ICE_GTP, 62 }, | |
993 | { ICE_IPV6_IL, 82 }, | |
994 | { ICE_UDP_ILOS, 122 }, | |
995 | { ICE_PROTOCOL_LAST, 0 }, | |
996 | }; | |
997 | ||
07a28842 | 998 | ICE_DECLARE_PKT_TEMPLATE(ipv6_gtpu_ipv6_udp) = { |
9a225f81 MS |
999 | 0x00, 0x00, 0x00, 0x00, /* Ethernet 0 */ |
1000 | 0x00, 0x00, 0x00, 0x00, | |
1001 | 0x00, 0x00, 0x00, 0x00, | |
1002 | 0x86, 0xdd, | |
1003 | ||
1004 | 0x60, 0x00, 0x00, 0x00, /* IPv6 14 */ | |
1005 | 0x00, 0x4c, 0x11, 0x00, | |
1006 | 0x00, 0x00, 0x00, 0x00, | |
1007 | 0x00, 0x00, 0x00, 0x00, | |
1008 | 0x00, 0x00, 0x00, 0x00, | |
1009 | 0x00, 0x00, 0x00, 0x00, | |
1010 | 0x00, 0x00, 0x00, 0x00, | |
1011 | 0x00, 0x00, 0x00, 0x00, | |
1012 | 0x00, 0x00, 0x00, 0x00, | |
1013 | 0x00, 0x00, 0x00, 0x00, | |
1014 | ||
1015 | 0x00, 0x00, 0x08, 0x68, /* UDP 54 */ | |
1016 | 0x00, 0x4c, 0x00, 0x00, | |
1017 | ||
1018 | 0x34, 0xff, 0x00, 0x3c, /* ICE_GTP Header 62 */ | |
1019 | 0x00, 0x00, 0x00, 0x00, | |
1020 | 0x00, 0x00, 0x00, 0x85, | |
1021 | ||
1022 | 0x02, 0x00, 0x00, 0x00, /* GTP_PDUSession_ExtensionHeader 74 */ | |
1023 | 0x00, 0x00, 0x00, 0x00, | |
1024 | ||
1025 | 0x60, 0x00, 0x00, 0x00, /* IPv6 82 */ | |
1026 | 0x00, 0x08, 0x11, 0x00, | |
1027 | 0x00, 0x00, 0x00, 0x00, | |
1028 | 0x00, 0x00, 0x00, 0x00, | |
1029 | 0x00, 0x00, 0x00, 0x00, | |
1030 | 0x00, 0x00, 0x00, 0x00, | |
1031 | 0x00, 0x00, 0x00, 0x00, | |
1032 | 0x00, 0x00, 0x00, 0x00, | |
1033 | 0x00, 0x00, 0x00, 0x00, | |
1034 | 0x00, 0x00, 0x00, 0x00, | |
1035 | ||
1036 | 0x00, 0x00, 0x00, 0x00, /* UDP 122 */ | |
1037 | 0x00, 0x08, 0x00, 0x00, | |
1038 | ||
1039 | 0x00, 0x00, /* 2 bytes for 4 byte alignment */ | |
1040 | }; | |
1041 | ||
07a28842 | 1042 | ICE_DECLARE_PKT_OFFSETS(ipv4_gtpu_ipv4) = { |
1b699f81 AL |
1043 | { ICE_MAC_OFOS, 0 }, |
1044 | { ICE_IPV4_OFOS, 14 }, | |
1045 | { ICE_UDP_OF, 34 }, | |
1046 | { ICE_GTP_NO_PAY, 42 }, | |
1047 | { ICE_PROTOCOL_LAST, 0 }, | |
1048 | }; | |
1049 | ||
07a28842 | 1050 | ICE_DECLARE_PKT_TEMPLATE(ipv4_gtpu_ipv4) = { |
9a225f81 MS |
1051 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
1052 | 0x00, 0x00, 0x00, 0x00, | |
1053 | 0x00, 0x00, 0x00, 0x00, | |
1054 | 0x08, 0x00, | |
1055 | ||
1056 | 0x45, 0x00, 0x00, 0x44, /* ICE_IPV4_OFOS 14 */ | |
1057 | 0x00, 0x00, 0x40, 0x00, | |
1058 | 0x40, 0x11, 0x00, 0x00, | |
1059 | 0x00, 0x00, 0x00, 0x00, | |
1060 | 0x00, 0x00, 0x00, 0x00, | |
1061 | ||
1062 | 0x08, 0x68, 0x08, 0x68, /* ICE_UDP_OF 34 */ | |
1063 | 0x00, 0x00, 0x00, 0x00, | |
1064 | ||
1065 | 0x34, 0xff, 0x00, 0x28, /* ICE_GTP 42 */ | |
1066 | 0x00, 0x00, 0x00, 0x00, | |
1067 | 0x00, 0x00, 0x00, 0x85, | |
1068 | ||
1069 | 0x02, 0x00, 0x00, 0x00, /* PDU Session extension header */ | |
1070 | 0x00, 0x00, 0x00, 0x00, | |
1071 | ||
1072 | 0x45, 0x00, 0x00, 0x14, /* ICE_IPV4_IL 62 */ | |
1073 | 0x00, 0x00, 0x40, 0x00, | |
1074 | 0x40, 0x00, 0x00, 0x00, | |
1075 | 0x00, 0x00, 0x00, 0x00, | |
1076 | 0x00, 0x00, 0x00, 0x00, | |
1077 | 0x00, 0x00, | |
1078 | }; | |
1079 | ||
07a28842 | 1080 | ICE_DECLARE_PKT_OFFSETS(ipv6_gtp) = { |
9a225f81 MS |
1081 | { ICE_MAC_OFOS, 0 }, |
1082 | { ICE_IPV6_OFOS, 14 }, | |
1083 | { ICE_UDP_OF, 54 }, | |
1084 | { ICE_GTP_NO_PAY, 62 }, | |
1085 | { ICE_PROTOCOL_LAST, 0 }, | |
1086 | }; | |
1087 | ||
07a28842 | 1088 | ICE_DECLARE_PKT_TEMPLATE(ipv6_gtp) = { |
9a225f81 MS |
1089 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ |
1090 | 0x00, 0x00, 0x00, 0x00, | |
1091 | 0x00, 0x00, 0x00, 0x00, | |
1092 | 0x86, 0xdd, | |
1093 | ||
1094 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 14 */ | |
1095 | 0x00, 0x6c, 0x11, 0x00, /* Next header UDP*/ | |
1096 | 0x00, 0x00, 0x00, 0x00, | |
1097 | 0x00, 0x00, 0x00, 0x00, | |
1098 | 0x00, 0x00, 0x00, 0x00, | |
1099 | 0x00, 0x00, 0x00, 0x00, | |
1100 | 0x00, 0x00, 0x00, 0x00, | |
1101 | 0x00, 0x00, 0x00, 0x00, | |
1102 | 0x00, 0x00, 0x00, 0x00, | |
1103 | 0x00, 0x00, 0x00, 0x00, | |
1104 | ||
1105 | 0x08, 0x68, 0x08, 0x68, /* ICE_UDP_OF 54 */ | |
1106 | 0x00, 0x00, 0x00, 0x00, | |
1107 | ||
1108 | 0x30, 0x00, 0x00, 0x28, /* ICE_GTP 62 */ | |
1109 | 0x00, 0x00, 0x00, 0x00, | |
1110 | ||
1111 | 0x00, 0x00, | |
1112 | }; | |
1113 | ||
cd8efeee MS |
1114 | ICE_DECLARE_PKT_OFFSETS(pppoe_ipv4_tcp) = { |
1115 | { ICE_MAC_OFOS, 0 }, | |
1116 | { ICE_ETYPE_OL, 12 }, | |
1117 | { ICE_PPPOE, 14 }, | |
1118 | { ICE_IPV4_OFOS, 22 }, | |
1119 | { ICE_TCP_IL, 42 }, | |
1120 | { ICE_PROTOCOL_LAST, 0 }, | |
1121 | }; | |
1122 | ||
1123 | ICE_DECLARE_PKT_TEMPLATE(pppoe_ipv4_tcp) = { | |
1124 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ | |
1125 | 0x00, 0x00, 0x00, 0x00, | |
1126 | 0x00, 0x00, 0x00, 0x00, | |
1127 | ||
1128 | 0x88, 0x64, /* ICE_ETYPE_OL 12 */ | |
1129 | ||
1130 | 0x11, 0x00, 0x00, 0x00, /* ICE_PPPOE 14 */ | |
1131 | 0x00, 0x16, | |
1132 | ||
1133 | 0x00, 0x21, /* PPP Link Layer 20 */ | |
1134 | ||
1135 | 0x45, 0x00, 0x00, 0x28, /* ICE_IPV4_OFOS 22 */ | |
1136 | 0x00, 0x01, 0x00, 0x00, | |
1137 | 0x00, 0x06, 0x00, 0x00, | |
1138 | 0x00, 0x00, 0x00, 0x00, | |
1139 | 0x00, 0x00, 0x00, 0x00, | |
1140 | ||
1141 | 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 42 */ | |
1142 | 0x00, 0x00, 0x00, 0x00, | |
1143 | 0x00, 0x00, 0x00, 0x00, | |
1144 | 0x50, 0x00, 0x00, 0x00, | |
1145 | 0x00, 0x00, 0x00, 0x00, | |
1146 | ||
1147 | 0x00, 0x00, /* 2 bytes for 4 bytes alignment */ | |
1148 | }; | |
1149 | ||
1150 | ICE_DECLARE_PKT_OFFSETS(pppoe_ipv4_udp) = { | |
1151 | { ICE_MAC_OFOS, 0 }, | |
1152 | { ICE_ETYPE_OL, 12 }, | |
1153 | { ICE_PPPOE, 14 }, | |
1154 | { ICE_IPV4_OFOS, 22 }, | |
1155 | { ICE_UDP_ILOS, 42 }, | |
1156 | { ICE_PROTOCOL_LAST, 0 }, | |
1157 | }; | |
1158 | ||
1159 | ICE_DECLARE_PKT_TEMPLATE(pppoe_ipv4_udp) = { | |
1160 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ | |
1161 | 0x00, 0x00, 0x00, 0x00, | |
1162 | 0x00, 0x00, 0x00, 0x00, | |
1163 | ||
1164 | 0x88, 0x64, /* ICE_ETYPE_OL 12 */ | |
1165 | ||
1166 | 0x11, 0x00, 0x00, 0x00, /* ICE_PPPOE 14 */ | |
1167 | 0x00, 0x16, | |
1168 | ||
1169 | 0x00, 0x21, /* PPP Link Layer 20 */ | |
1170 | ||
1171 | 0x45, 0x00, 0x00, 0x1c, /* ICE_IPV4_OFOS 22 */ | |
1172 | 0x00, 0x01, 0x00, 0x00, | |
1173 | 0x00, 0x11, 0x00, 0x00, | |
1174 | 0x00, 0x00, 0x00, 0x00, | |
1175 | 0x00, 0x00, 0x00, 0x00, | |
1176 | ||
1177 | 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 42 */ | |
1178 | 0x00, 0x08, 0x00, 0x00, | |
1179 | ||
1180 | 0x00, 0x00, /* 2 bytes for 4 bytes alignment */ | |
1181 | }; | |
1182 | ||
1183 | ICE_DECLARE_PKT_OFFSETS(pppoe_ipv6_tcp) = { | |
1184 | { ICE_MAC_OFOS, 0 }, | |
1185 | { ICE_ETYPE_OL, 12 }, | |
1186 | { ICE_PPPOE, 14 }, | |
1187 | { ICE_IPV6_OFOS, 22 }, | |
1188 | { ICE_TCP_IL, 62 }, | |
1189 | { ICE_PROTOCOL_LAST, 0 }, | |
1190 | }; | |
1191 | ||
1192 | ICE_DECLARE_PKT_TEMPLATE(pppoe_ipv6_tcp) = { | |
1193 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ | |
1194 | 0x00, 0x00, 0x00, 0x00, | |
1195 | 0x00, 0x00, 0x00, 0x00, | |
1196 | ||
1197 | 0x88, 0x64, /* ICE_ETYPE_OL 12 */ | |
1198 | ||
1199 | 0x11, 0x00, 0x00, 0x00, /* ICE_PPPOE 14 */ | |
1200 | 0x00, 0x2a, | |
1201 | ||
1202 | 0x00, 0x57, /* PPP Link Layer 20 */ | |
1203 | ||
1204 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 22 */ | |
1205 | 0x00, 0x14, 0x06, 0x00, /* Next header is TCP */ | |
1206 | 0x00, 0x00, 0x00, 0x00, | |
1207 | 0x00, 0x00, 0x00, 0x00, | |
1208 | 0x00, 0x00, 0x00, 0x00, | |
1209 | 0x00, 0x00, 0x00, 0x00, | |
1210 | 0x00, 0x00, 0x00, 0x00, | |
1211 | 0x00, 0x00, 0x00, 0x00, | |
1212 | 0x00, 0x00, 0x00, 0x00, | |
1213 | 0x00, 0x00, 0x00, 0x00, | |
1214 | ||
1215 | 0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 62 */ | |
1216 | 0x00, 0x00, 0x00, 0x00, | |
1217 | 0x00, 0x00, 0x00, 0x00, | |
1218 | 0x50, 0x00, 0x00, 0x00, | |
1219 | 0x00, 0x00, 0x00, 0x00, | |
1220 | ||
1221 | 0x00, 0x00, /* 2 bytes for 4 bytes alignment */ | |
1222 | }; | |
1223 | ||
1224 | ICE_DECLARE_PKT_OFFSETS(pppoe_ipv6_udp) = { | |
1225 | { ICE_MAC_OFOS, 0 }, | |
1226 | { ICE_ETYPE_OL, 12 }, | |
1227 | { ICE_PPPOE, 14 }, | |
1228 | { ICE_IPV6_OFOS, 22 }, | |
1229 | { ICE_UDP_ILOS, 62 }, | |
1230 | { ICE_PROTOCOL_LAST, 0 }, | |
1231 | }; | |
1232 | ||
1233 | ICE_DECLARE_PKT_TEMPLATE(pppoe_ipv6_udp) = { | |
1234 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ | |
1235 | 0x00, 0x00, 0x00, 0x00, | |
1236 | 0x00, 0x00, 0x00, 0x00, | |
1237 | ||
1238 | 0x88, 0x64, /* ICE_ETYPE_OL 12 */ | |
1239 | ||
1240 | 0x11, 0x00, 0x00, 0x00, /* ICE_PPPOE 14 */ | |
1241 | 0x00, 0x2a, | |
1242 | ||
1243 | 0x00, 0x57, /* PPP Link Layer 20 */ | |
1244 | ||
1245 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 22 */ | |
1246 | 0x00, 0x08, 0x11, 0x00, /* Next header UDP*/ | |
1247 | 0x00, 0x00, 0x00, 0x00, | |
1248 | 0x00, 0x00, 0x00, 0x00, | |
1249 | 0x00, 0x00, 0x00, 0x00, | |
1250 | 0x00, 0x00, 0x00, 0x00, | |
1251 | 0x00, 0x00, 0x00, 0x00, | |
1252 | 0x00, 0x00, 0x00, 0x00, | |
1253 | 0x00, 0x00, 0x00, 0x00, | |
1254 | 0x00, 0x00, 0x00, 0x00, | |
1255 | ||
1256 | 0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 62 */ | |
1257 | 0x00, 0x08, 0x00, 0x00, | |
1258 | ||
1259 | 0x00, 0x00, /* 2 bytes for 4 bytes alignment */ | |
1260 | }; | |
1261 | ||
cd634549 MS |
1262 | ICE_DECLARE_PKT_OFFSETS(ipv4_l2tpv3) = { |
1263 | { ICE_MAC_OFOS, 0 }, | |
1264 | { ICE_ETYPE_OL, 12 }, | |
1265 | { ICE_IPV4_OFOS, 14 }, | |
1266 | { ICE_L2TPV3, 34 }, | |
1267 | { ICE_PROTOCOL_LAST, 0 }, | |
1268 | }; | |
1269 | ||
1270 | ICE_DECLARE_PKT_TEMPLATE(ipv4_l2tpv3) = { | |
1271 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ | |
1272 | 0x00, 0x00, 0x00, 0x00, | |
1273 | 0x00, 0x00, 0x00, 0x00, | |
1274 | ||
1275 | 0x08, 0x00, /* ICE_ETYPE_OL 12 */ | |
1276 | ||
1277 | 0x45, 0x00, 0x00, 0x20, /* ICE_IPV4_IL 14 */ | |
1278 | 0x00, 0x00, 0x40, 0x00, | |
1279 | 0x40, 0x73, 0x00, 0x00, | |
1280 | 0x00, 0x00, 0x00, 0x00, | |
1281 | 0x00, 0x00, 0x00, 0x00, | |
1282 | ||
1283 | 0x00, 0x00, 0x00, 0x00, /* ICE_L2TPV3 34 */ | |
1284 | 0x00, 0x00, 0x00, 0x00, | |
1285 | 0x00, 0x00, 0x00, 0x00, | |
1286 | 0x00, 0x00, /* 2 bytes for 4 bytes alignment */ | |
1287 | }; | |
1288 | ||
1289 | ICE_DECLARE_PKT_OFFSETS(ipv6_l2tpv3) = { | |
1290 | { ICE_MAC_OFOS, 0 }, | |
1291 | { ICE_ETYPE_OL, 12 }, | |
1292 | { ICE_IPV6_OFOS, 14 }, | |
1293 | { ICE_L2TPV3, 54 }, | |
1294 | { ICE_PROTOCOL_LAST, 0 }, | |
1295 | }; | |
1296 | ||
1297 | ICE_DECLARE_PKT_TEMPLATE(ipv6_l2tpv3) = { | |
1298 | 0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ | |
1299 | 0x00, 0x00, 0x00, 0x00, | |
1300 | 0x00, 0x00, 0x00, 0x00, | |
1301 | ||
1302 | 0x86, 0xDD, /* ICE_ETYPE_OL 12 */ | |
1303 | ||
1304 | 0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_IL 14 */ | |
1305 | 0x00, 0x0c, 0x73, 0x40, | |
1306 | 0x00, 0x00, 0x00, 0x00, | |
1307 | 0x00, 0x00, 0x00, 0x00, | |
1308 | 0x00, 0x00, 0x00, 0x00, | |
1309 | 0x00, 0x00, 0x00, 0x00, | |
1310 | 0x00, 0x00, 0x00, 0x00, | |
1311 | 0x00, 0x00, 0x00, 0x00, | |
1312 | 0x00, 0x00, 0x00, 0x00, | |
1313 | 0x00, 0x00, 0x00, 0x00, | |
1314 | ||
1315 | 0x00, 0x00, 0x00, 0x00, /* ICE_L2TPV3 54 */ | |
1316 | 0x00, 0x00, 0x00, 0x00, | |
1317 | 0x00, 0x00, 0x00, 0x00, | |
1318 | 0x00, 0x00, /* 2 bytes for 4 bytes alignment */ | |
1319 | }; | |
1320 | ||
e33163a4 AL |
1321 | static const struct ice_dummy_pkt_profile ice_dummy_pkt_profiles[] = { |
1322 | ICE_PKT_PROFILE(ipv6_gtp, ICE_PKT_TUN_GTPU | ICE_PKT_OUTER_IPV6 | | |
1323 | ICE_PKT_GTP_NOPAY), | |
1324 | ICE_PKT_PROFILE(ipv6_gtpu_ipv6_udp, ICE_PKT_TUN_GTPU | | |
1325 | ICE_PKT_OUTER_IPV6 | | |
1326 | ICE_PKT_INNER_IPV6 | | |
1327 | ICE_PKT_INNER_UDP), | |
1328 | ICE_PKT_PROFILE(ipv6_gtpu_ipv6_tcp, ICE_PKT_TUN_GTPU | | |
1329 | ICE_PKT_OUTER_IPV6 | | |
1330 | ICE_PKT_INNER_IPV6), | |
1331 | ICE_PKT_PROFILE(ipv6_gtpu_ipv4_udp, ICE_PKT_TUN_GTPU | | |
1332 | ICE_PKT_OUTER_IPV6 | | |
1333 | ICE_PKT_INNER_UDP), | |
1334 | ICE_PKT_PROFILE(ipv6_gtpu_ipv4_tcp, ICE_PKT_TUN_GTPU | | |
1335 | ICE_PKT_OUTER_IPV6), | |
1336 | ICE_PKT_PROFILE(ipv4_gtpu_ipv4, ICE_PKT_TUN_GTPU | ICE_PKT_GTP_NOPAY), | |
1337 | ICE_PKT_PROFILE(ipv4_gtpu_ipv6_udp, ICE_PKT_TUN_GTPU | | |
1338 | ICE_PKT_INNER_IPV6 | | |
1339 | ICE_PKT_INNER_UDP), | |
1340 | ICE_PKT_PROFILE(ipv4_gtpu_ipv6_tcp, ICE_PKT_TUN_GTPU | | |
1341 | ICE_PKT_INNER_IPV6), | |
1342 | ICE_PKT_PROFILE(ipv4_gtpu_ipv4_udp, ICE_PKT_TUN_GTPU | | |
1343 | ICE_PKT_INNER_UDP), | |
1344 | ICE_PKT_PROFILE(ipv4_gtpu_ipv4_tcp, ICE_PKT_TUN_GTPU), | |
1345 | ICE_PKT_PROFILE(ipv6_gtp, ICE_PKT_TUN_GTPC | ICE_PKT_OUTER_IPV6), | |
1346 | ICE_PKT_PROFILE(ipv4_gtpu_ipv4, ICE_PKT_TUN_GTPC), | |
cd8efeee MS |
1347 | ICE_PKT_PROFILE(pppoe_ipv6_udp, ICE_PKT_PPPOE | ICE_PKT_OUTER_IPV6 | |
1348 | ICE_PKT_INNER_UDP), | |
1349 | ICE_PKT_PROFILE(pppoe_ipv6_tcp, ICE_PKT_PPPOE | ICE_PKT_OUTER_IPV6), | |
1350 | ICE_PKT_PROFILE(pppoe_ipv4_udp, ICE_PKT_PPPOE | ICE_PKT_INNER_UDP), | |
1351 | ICE_PKT_PROFILE(pppoe_ipv4_tcp, ICE_PKT_PPPOE), | |
e33163a4 AL |
1352 | ICE_PKT_PROFILE(gre_ipv6_tcp, ICE_PKT_TUN_NVGRE | ICE_PKT_INNER_IPV6 | |
1353 | ICE_PKT_INNER_TCP), | |
1354 | ICE_PKT_PROFILE(gre_tcp, ICE_PKT_TUN_NVGRE | ICE_PKT_INNER_TCP), | |
1355 | ICE_PKT_PROFILE(gre_ipv6_udp, ICE_PKT_TUN_NVGRE | ICE_PKT_INNER_IPV6), | |
1356 | ICE_PKT_PROFILE(gre_udp, ICE_PKT_TUN_NVGRE), | |
1357 | ICE_PKT_PROFILE(udp_tun_ipv6_tcp, ICE_PKT_TUN_UDP | | |
1358 | ICE_PKT_INNER_IPV6 | | |
1359 | ICE_PKT_INNER_TCP), | |
cd634549 MS |
1360 | ICE_PKT_PROFILE(ipv6_l2tpv3, ICE_PKT_L2TPV3 | ICE_PKT_OUTER_IPV6), |
1361 | ICE_PKT_PROFILE(ipv4_l2tpv3, ICE_PKT_L2TPV3), | |
e33163a4 AL |
1362 | ICE_PKT_PROFILE(udp_tun_tcp, ICE_PKT_TUN_UDP | ICE_PKT_INNER_TCP), |
1363 | ICE_PKT_PROFILE(udp_tun_ipv6_udp, ICE_PKT_TUN_UDP | | |
1364 | ICE_PKT_INNER_IPV6), | |
1365 | ICE_PKT_PROFILE(udp_tun_udp, ICE_PKT_TUN_UDP), | |
e33163a4 | 1366 | ICE_PKT_PROFILE(udp_ipv6, ICE_PKT_OUTER_IPV6 | ICE_PKT_INNER_UDP), |
e33163a4 | 1367 | ICE_PKT_PROFILE(udp, ICE_PKT_INNER_UDP), |
e33163a4 | 1368 | ICE_PKT_PROFILE(tcp_ipv6, ICE_PKT_OUTER_IPV6), |
e33163a4 AL |
1369 | ICE_PKT_PROFILE(tcp, 0), |
1370 | }; | |
1371 | ||
6e1ff618 AL |
1372 | #define ICE_SW_RULE_RX_TX_HDR_SIZE(s, l) struct_size((s), hdr_data, (l)) |
1373 | #define ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s) \ | |
1374 | ICE_SW_RULE_RX_TX_HDR_SIZE((s), DUMMY_ETH_HDR_LEN) | |
1375 | #define ICE_SW_RULE_RX_TX_NO_HDR_SIZE(s) \ | |
1376 | ICE_SW_RULE_RX_TX_HDR_SIZE((s), 0) | |
1377 | #define ICE_SW_RULE_LG_ACT_SIZE(s, n) struct_size((s), act, (n)) | |
1378 | #define ICE_SW_RULE_VSI_LIST_SIZE(s, n) struct_size((s), vsi, (n)) | |
9daf8208 | 1379 | |
fd2a6b71 DN |
1380 | /* this is a recipe to profile association bitmap */ |
1381 | static DECLARE_BITMAP(recipe_to_profile[ICE_MAX_NUM_RECIPES], | |
1382 | ICE_MAX_NUM_PROFILES); | |
1383 | ||
1384 | /* this is a profile to recipe association bitmap */ | |
1385 | static DECLARE_BITMAP(profile_to_recipe[ICE_MAX_NUM_PROFILES], | |
1386 | ICE_MAX_NUM_RECIPES); | |
1387 | ||
80d144c9 AV |
1388 | /** |
1389 | * ice_init_def_sw_recp - initialize the recipe book keeping tables | |
f9867df6 | 1390 | * @hw: pointer to the HW struct |
80d144c9 AV |
1391 | * |
1392 | * Allocate memory for the entire recipe table and initialize the structures/ | |
1393 | * entries corresponding to basic recipes. | |
1394 | */ | |
5e24d598 | 1395 | int ice_init_def_sw_recp(struct ice_hw *hw) |
80d144c9 AV |
1396 | { |
1397 | struct ice_sw_recipe *recps; | |
1398 | u8 i; | |
1399 | ||
1400 | recps = devm_kcalloc(ice_hw_to_dev(hw), ICE_MAX_NUM_RECIPES, | |
c6dfd690 | 1401 | sizeof(*recps), GFP_KERNEL); |
80d144c9 | 1402 | if (!recps) |
d54699e2 | 1403 | return -ENOMEM; |
80d144c9 | 1404 | |
450052a4 | 1405 | for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) { |
80d144c9 AV |
1406 | recps[i].root_rid = i; |
1407 | INIT_LIST_HEAD(&recps[i].filt_rules); | |
334cb062 | 1408 | INIT_LIST_HEAD(&recps[i].filt_replay_rules); |
450052a4 | 1409 | INIT_LIST_HEAD(&recps[i].rg_list); |
80d144c9 AV |
1410 | mutex_init(&recps[i].filt_rule_lock); |
1411 | } | |
1412 | ||
1413 | hw->switch_info->recp_list = recps; | |
1414 | ||
1415 | return 0; | |
1416 | } | |
1417 | ||
9c20346b AV |
1418 | /** |
1419 | * ice_aq_get_sw_cfg - get switch configuration | |
1420 | * @hw: pointer to the hardware structure | |
1421 | * @buf: pointer to the result buffer | |
1422 | * @buf_size: length of the buffer available for response | |
1423 | * @req_desc: pointer to requested descriptor | |
1424 | * @num_elems: pointer to number of elements | |
1425 | * @cd: pointer to command details structure or NULL | |
1426 | * | |
b3c38904 | 1427 | * Get switch configuration (0x0200) to be placed in buf. |
9c20346b AV |
1428 | * This admin command returns information such as initial VSI/port number |
1429 | * and switch ID it belongs to. | |
1430 | * | |
1431 | * NOTE: *req_desc is both an input/output parameter. | |
1432 | * The caller of this function first calls this function with *request_desc set | |
df17b7e0 | 1433 | * to 0. If the response from f/w has *req_desc set to 0, all the switch |
9c20346b AV |
1434 | * configuration information has been returned; if non-zero (meaning not all |
1435 | * the information was returned), the caller should call this function again | |
1436 | * with *req_desc set to the previous value returned by f/w to get the | |
1437 | * next block of switch configuration information. | |
1438 | * | |
1439 | * *num_elems is output only parameter. This reflects the number of elements | |
1440 | * in response buffer. The caller of this function to use *num_elems while | |
1441 | * parsing the response buffer. | |
1442 | */ | |
5e24d598 | 1443 | static int |
b3c38904 | 1444 | ice_aq_get_sw_cfg(struct ice_hw *hw, struct ice_aqc_get_sw_cfg_resp_elem *buf, |
9c20346b AV |
1445 | u16 buf_size, u16 *req_desc, u16 *num_elems, |
1446 | struct ice_sq_cd *cd) | |
1447 | { | |
1448 | struct ice_aqc_get_sw_cfg *cmd; | |
9c20346b | 1449 | struct ice_aq_desc desc; |
5e24d598 | 1450 | int status; |
9c20346b AV |
1451 | |
1452 | ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_sw_cfg); | |
1453 | cmd = &desc.params.get_sw_conf; | |
1454 | cmd->element = cpu_to_le16(*req_desc); | |
1455 | ||
1456 | status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); | |
1457 | if (!status) { | |
1458 | *req_desc = le16_to_cpu(cmd->element); | |
1459 | *num_elems = le16_to_cpu(cmd->num_elems); | |
1460 | } | |
1461 | ||
1462 | return status; | |
1463 | } | |
1464 | ||
3a858ba3 AV |
1465 | /** |
1466 | * ice_aq_add_vsi | |
f9867df6 | 1467 | * @hw: pointer to the HW struct |
3a858ba3 AV |
1468 | * @vsi_ctx: pointer to a VSI context struct |
1469 | * @cd: pointer to command details structure or NULL | |
1470 | * | |
1471 | * Add a VSI context to the hardware (0x0210) | |
1472 | */ | |
5e24d598 | 1473 | static int |
3a858ba3 AV |
1474 | ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, |
1475 | struct ice_sq_cd *cd) | |
1476 | { | |
1477 | struct ice_aqc_add_update_free_vsi_resp *res; | |
1478 | struct ice_aqc_add_get_update_free_vsi *cmd; | |
3a858ba3 | 1479 | struct ice_aq_desc desc; |
5e24d598 | 1480 | int status; |
3a858ba3 AV |
1481 | |
1482 | cmd = &desc.params.vsi_cmd; | |
0f9d5027 | 1483 | res = &desc.params.add_update_free_vsi_res; |
3a858ba3 AV |
1484 | |
1485 | ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_vsi); | |
1486 | ||
1487 | if (!vsi_ctx->alloc_from_pool) | |
1488 | cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | | |
1489 | ICE_AQ_VSI_IS_VALID); | |
1071a835 | 1490 | cmd->vf_id = vsi_ctx->vf_num; |
3a858ba3 AV |
1491 | |
1492 | cmd->vsi_flags = cpu_to_le16(vsi_ctx->flags); | |
1493 | ||
1494 | desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); | |
1495 | ||
1496 | status = ice_aq_send_cmd(hw, &desc, &vsi_ctx->info, | |
1497 | sizeof(vsi_ctx->info), cd); | |
1498 | ||
1499 | if (!status) { | |
1500 | vsi_ctx->vsi_num = le16_to_cpu(res->vsi_num) & ICE_AQ_VSI_NUM_M; | |
1501 | vsi_ctx->vsis_allocd = le16_to_cpu(res->vsi_used); | |
1502 | vsi_ctx->vsis_unallocated = le16_to_cpu(res->vsi_free); | |
1503 | } | |
1504 | ||
1505 | return status; | |
1506 | } | |
1507 | ||
0f9d5027 AV |
1508 | /** |
1509 | * ice_aq_free_vsi | |
f9867df6 | 1510 | * @hw: pointer to the HW struct |
0f9d5027 AV |
1511 | * @vsi_ctx: pointer to a VSI context struct |
1512 | * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources | |
1513 | * @cd: pointer to command details structure or NULL | |
1514 | * | |
1515 | * Free VSI context info from hardware (0x0213) | |
1516 | */ | |
5e24d598 | 1517 | static int |
0f9d5027 AV |
1518 | ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, |
1519 | bool keep_vsi_alloc, struct ice_sq_cd *cd) | |
1520 | { | |
1521 | struct ice_aqc_add_update_free_vsi_resp *resp; | |
1522 | struct ice_aqc_add_get_update_free_vsi *cmd; | |
1523 | struct ice_aq_desc desc; | |
5e24d598 | 1524 | int status; |
0f9d5027 AV |
1525 | |
1526 | cmd = &desc.params.vsi_cmd; | |
1527 | resp = &desc.params.add_update_free_vsi_res; | |
1528 | ||
1529 | ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_free_vsi); | |
1530 | ||
1531 | cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID); | |
1532 | if (keep_vsi_alloc) | |
1533 | cmd->cmd_flags = cpu_to_le16(ICE_AQ_VSI_KEEP_ALLOC); | |
1534 | ||
1535 | status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd); | |
1536 | if (!status) { | |
1537 | vsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used); | |
1538 | vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free); | |
1539 | } | |
1540 | ||
1541 | return status; | |
1542 | } | |
1543 | ||
3a858ba3 AV |
1544 | /** |
1545 | * ice_aq_update_vsi | |
f9867df6 | 1546 | * @hw: pointer to the HW struct |
3a858ba3 AV |
1547 | * @vsi_ctx: pointer to a VSI context struct |
1548 | * @cd: pointer to command details structure or NULL | |
1549 | * | |
1550 | * Update VSI context in the hardware (0x0211) | |
1551 | */ | |
5e24d598 | 1552 | static int |
3a858ba3 AV |
1553 | ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, |
1554 | struct ice_sq_cd *cd) | |
1555 | { | |
1556 | struct ice_aqc_add_update_free_vsi_resp *resp; | |
1557 | struct ice_aqc_add_get_update_free_vsi *cmd; | |
1558 | struct ice_aq_desc desc; | |
5e24d598 | 1559 | int status; |
3a858ba3 AV |
1560 | |
1561 | cmd = &desc.params.vsi_cmd; | |
0f9d5027 | 1562 | resp = &desc.params.add_update_free_vsi_res; |
3a858ba3 AV |
1563 | |
1564 | ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_vsi); | |
1565 | ||
1566 | cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID); | |
1567 | ||
1568 | desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); | |
1569 | ||
1570 | status = ice_aq_send_cmd(hw, &desc, &vsi_ctx->info, | |
1571 | sizeof(vsi_ctx->info), cd); | |
1572 | ||
1573 | if (!status) { | |
1574 | vsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used); | |
1575 | vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free); | |
1576 | } | |
1577 | ||
1578 | return status; | |
1579 | } | |
1580 | ||
0f9d5027 AV |
1581 | /** |
1582 | * ice_is_vsi_valid - check whether the VSI is valid or not | |
f9867df6 | 1583 | * @hw: pointer to the HW struct |
0f9d5027 AV |
1584 | * @vsi_handle: VSI handle |
1585 | * | |
1586 | * check whether the VSI is valid or not | |
1587 | */ | |
4fb33f31 | 1588 | bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle) |
0f9d5027 AV |
1589 | { |
1590 | return vsi_handle < ICE_MAX_VSI && hw->vsi_ctx[vsi_handle]; | |
1591 | } | |
1592 | ||
1593 | /** | |
f9867df6 AV |
1594 | * ice_get_hw_vsi_num - return the HW VSI number |
1595 | * @hw: pointer to the HW struct | |
0f9d5027 AV |
1596 | * @vsi_handle: VSI handle |
1597 | * | |
f9867df6 | 1598 | * return the HW VSI number |
0f9d5027 AV |
1599 | * Caution: call this function only if VSI is valid (ice_is_vsi_valid) |
1600 | */ | |
4fb33f31 | 1601 | u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle) |
0f9d5027 AV |
1602 | { |
1603 | return hw->vsi_ctx[vsi_handle]->vsi_num; | |
1604 | } | |
1605 | ||
1606 | /** | |
1607 | * ice_get_vsi_ctx - return the VSI context entry for a given VSI handle | |
f9867df6 | 1608 | * @hw: pointer to the HW struct |
0f9d5027 AV |
1609 | * @vsi_handle: VSI handle |
1610 | * | |
1611 | * return the VSI context entry for a given VSI handle | |
1612 | */ | |
4fb33f31 | 1613 | struct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle) |
0f9d5027 AV |
1614 | { |
1615 | return (vsi_handle >= ICE_MAX_VSI) ? NULL : hw->vsi_ctx[vsi_handle]; | |
1616 | } | |
1617 | ||
1618 | /** | |
1619 | * ice_save_vsi_ctx - save the VSI context for a given VSI handle | |
f9867df6 | 1620 | * @hw: pointer to the HW struct |
0f9d5027 AV |
1621 | * @vsi_handle: VSI handle |
1622 | * @vsi: VSI context pointer | |
1623 | * | |
1624 | * save the VSI context entry for a given VSI handle | |
1625 | */ | |
c8b7abdd BA |
1626 | static void |
1627 | ice_save_vsi_ctx(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi) | |
0f9d5027 AV |
1628 | { |
1629 | hw->vsi_ctx[vsi_handle] = vsi; | |
1630 | } | |
1631 | ||
bb87ee0e AV |
1632 | /** |
1633 | * ice_clear_vsi_q_ctx - clear VSI queue contexts for all TCs | |
1634 | * @hw: pointer to the HW struct | |
1635 | * @vsi_handle: VSI handle | |
1636 | */ | |
1637 | static void ice_clear_vsi_q_ctx(struct ice_hw *hw, u16 vsi_handle) | |
1638 | { | |
1639 | struct ice_vsi_ctx *vsi; | |
1640 | u8 i; | |
1641 | ||
1642 | vsi = ice_get_vsi_ctx(hw, vsi_handle); | |
1643 | if (!vsi) | |
1644 | return; | |
1645 | ice_for_each_traffic_class(i) { | |
1646 | if (vsi->lan_q_ctx[i]) { | |
1647 | devm_kfree(ice_hw_to_dev(hw), vsi->lan_q_ctx[i]); | |
1648 | vsi->lan_q_ctx[i] = NULL; | |
1649 | } | |
348048e7 DE |
1650 | if (vsi->rdma_q_ctx[i]) { |
1651 | devm_kfree(ice_hw_to_dev(hw), vsi->rdma_q_ctx[i]); | |
1652 | vsi->rdma_q_ctx[i] = NULL; | |
1653 | } | |
bb87ee0e AV |
1654 | } |
1655 | } | |
1656 | ||
0f9d5027 AV |
1657 | /** |
1658 | * ice_clear_vsi_ctx - clear the VSI context entry | |
f9867df6 | 1659 | * @hw: pointer to the HW struct |
0f9d5027 AV |
1660 | * @vsi_handle: VSI handle |
1661 | * | |
1662 | * clear the VSI context entry | |
1663 | */ | |
1664 | static void ice_clear_vsi_ctx(struct ice_hw *hw, u16 vsi_handle) | |
1665 | { | |
1666 | struct ice_vsi_ctx *vsi; | |
1667 | ||
1668 | vsi = ice_get_vsi_ctx(hw, vsi_handle); | |
1669 | if (vsi) { | |
bb87ee0e | 1670 | ice_clear_vsi_q_ctx(hw, vsi_handle); |
0f9d5027 AV |
1671 | devm_kfree(ice_hw_to_dev(hw), vsi); |
1672 | hw->vsi_ctx[vsi_handle] = NULL; | |
1673 | } | |
1674 | } | |
1675 | ||
33e055fc VR |
1676 | /** |
1677 | * ice_clear_all_vsi_ctx - clear all the VSI context entries | |
f9867df6 | 1678 | * @hw: pointer to the HW struct |
33e055fc VR |
1679 | */ |
1680 | void ice_clear_all_vsi_ctx(struct ice_hw *hw) | |
1681 | { | |
1682 | u16 i; | |
1683 | ||
1684 | for (i = 0; i < ICE_MAX_VSI; i++) | |
1685 | ice_clear_vsi_ctx(hw, i); | |
1686 | } | |
1687 | ||
0f9d5027 AV |
1688 | /** |
1689 | * ice_add_vsi - add VSI context to the hardware and VSI handle list | |
f9867df6 | 1690 | * @hw: pointer to the HW struct |
0f9d5027 | 1691 | * @vsi_handle: unique VSI handle provided by drivers |
3a858ba3 | 1692 | * @vsi_ctx: pointer to a VSI context struct |
3a858ba3 AV |
1693 | * @cd: pointer to command details structure or NULL |
1694 | * | |
0f9d5027 AV |
1695 | * Add a VSI context to the hardware also add it into the VSI handle list. |
1696 | * If this function gets called after reset for existing VSIs then update | |
1697 | * with the new HW VSI number in the corresponding VSI handle list entry. | |
3a858ba3 | 1698 | */ |
5e24d598 | 1699 | int |
0f9d5027 AV |
1700 | ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, |
1701 | struct ice_sq_cd *cd) | |
3a858ba3 | 1702 | { |
0f9d5027 | 1703 | struct ice_vsi_ctx *tmp_vsi_ctx; |
5e24d598 | 1704 | int status; |
3a858ba3 | 1705 | |
0f9d5027 | 1706 | if (vsi_handle >= ICE_MAX_VSI) |
d54699e2 | 1707 | return -EINVAL; |
0f9d5027 AV |
1708 | status = ice_aq_add_vsi(hw, vsi_ctx, cd); |
1709 | if (status) | |
1710 | return status; | |
1711 | tmp_vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle); | |
1712 | if (!tmp_vsi_ctx) { | |
f9867df6 | 1713 | /* Create a new VSI context */ |
0f9d5027 AV |
1714 | tmp_vsi_ctx = devm_kzalloc(ice_hw_to_dev(hw), |
1715 | sizeof(*tmp_vsi_ctx), GFP_KERNEL); | |
1716 | if (!tmp_vsi_ctx) { | |
1717 | ice_aq_free_vsi(hw, vsi_ctx, false, cd); | |
d54699e2 | 1718 | return -ENOMEM; |
0f9d5027 AV |
1719 | } |
1720 | *tmp_vsi_ctx = *vsi_ctx; | |
1721 | ice_save_vsi_ctx(hw, vsi_handle, tmp_vsi_ctx); | |
1722 | } else { | |
1723 | /* update with new HW VSI num */ | |
87a2e498 | 1724 | tmp_vsi_ctx->vsi_num = vsi_ctx->vsi_num; |
0f9d5027 | 1725 | } |
3a858ba3 | 1726 | |
1b5c19c7 | 1727 | return 0; |
0f9d5027 | 1728 | } |
3a858ba3 | 1729 | |
0f9d5027 AV |
1730 | /** |
1731 | * ice_free_vsi- free VSI context from hardware and VSI handle list | |
f9867df6 | 1732 | * @hw: pointer to the HW struct |
0f9d5027 AV |
1733 | * @vsi_handle: unique VSI handle |
1734 | * @vsi_ctx: pointer to a VSI context struct | |
1735 | * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources | |
1736 | * @cd: pointer to command details structure or NULL | |
1737 | * | |
1738 | * Free VSI context info from hardware as well as from VSI handle list | |
1739 | */ | |
5e24d598 | 1740 | int |
0f9d5027 AV |
1741 | ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, |
1742 | bool keep_vsi_alloc, struct ice_sq_cd *cd) | |
1743 | { | |
5e24d598 | 1744 | int status; |
3a858ba3 | 1745 | |
0f9d5027 | 1746 | if (!ice_is_vsi_valid(hw, vsi_handle)) |
d54699e2 | 1747 | return -EINVAL; |
0f9d5027 AV |
1748 | vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle); |
1749 | status = ice_aq_free_vsi(hw, vsi_ctx, keep_vsi_alloc, cd); | |
1750 | if (!status) | |
1751 | ice_clear_vsi_ctx(hw, vsi_handle); | |
3a858ba3 AV |
1752 | return status; |
1753 | } | |
1754 | ||
5726ca0e AV |
1755 | /** |
1756 | * ice_update_vsi | |
f9867df6 | 1757 | * @hw: pointer to the HW struct |
5726ca0e AV |
1758 | * @vsi_handle: unique VSI handle |
1759 | * @vsi_ctx: pointer to a VSI context struct | |
1760 | * @cd: pointer to command details structure or NULL | |
1761 | * | |
1762 | * Update VSI context in the hardware | |
1763 | */ | |
5e24d598 | 1764 | int |
5726ca0e AV |
1765 | ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, |
1766 | struct ice_sq_cd *cd) | |
1767 | { | |
1768 | if (!ice_is_vsi_valid(hw, vsi_handle)) | |
d54699e2 | 1769 | return -EINVAL; |
5726ca0e AV |
1770 | vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle); |
1771 | return ice_aq_update_vsi(hw, vsi_ctx, cd); | |
1772 | } | |
1773 | ||
348048e7 DE |
1774 | /** |
1775 | * ice_cfg_rdma_fltr - enable/disable RDMA filtering on VSI | |
1776 | * @hw: pointer to HW struct | |
1777 | * @vsi_handle: VSI SW index | |
1778 | * @enable: boolean for enable/disable | |
1779 | */ | |
1780 | int | |
1781 | ice_cfg_rdma_fltr(struct ice_hw *hw, u16 vsi_handle, bool enable) | |
1782 | { | |
1783 | struct ice_vsi_ctx *ctx; | |
1784 | ||
1785 | ctx = ice_get_vsi_ctx(hw, vsi_handle); | |
1786 | if (!ctx) | |
1787 | return -EIO; | |
1788 | ||
1789 | if (enable) | |
1790 | ctx->info.q_opt_flags |= ICE_AQ_VSI_Q_OPT_PE_FLTR_EN; | |
1791 | else | |
1792 | ctx->info.q_opt_flags &= ~ICE_AQ_VSI_Q_OPT_PE_FLTR_EN; | |
1793 | ||
d54699e2 | 1794 | return ice_update_vsi(hw, vsi_handle, ctx, NULL); |
348048e7 DE |
1795 | } |
1796 | ||
9daf8208 AV |
1797 | /** |
1798 | * ice_aq_alloc_free_vsi_list | |
f9867df6 AV |
1799 | * @hw: pointer to the HW struct |
1800 | * @vsi_list_id: VSI list ID returned or used for lookup | |
9daf8208 AV |
1801 | * @lkup_type: switch rule filter lookup type |
1802 | * @opc: switch rules population command type - pass in the command opcode | |
1803 | * | |
1804 | * allocates or free a VSI list resource | |
1805 | */ | |
5e24d598 | 1806 | static int |
9daf8208 AV |
1807 | ice_aq_alloc_free_vsi_list(struct ice_hw *hw, u16 *vsi_list_id, |
1808 | enum ice_sw_lkup_type lkup_type, | |
1809 | enum ice_adminq_opc opc) | |
1810 | { | |
1811 | struct ice_aqc_alloc_free_res_elem *sw_buf; | |
1812 | struct ice_aqc_res_elem *vsi_ele; | |
9daf8208 | 1813 | u16 buf_len; |
5518ac2a | 1814 | int status; |
9daf8208 | 1815 | |
66486d89 | 1816 | buf_len = struct_size(sw_buf, elem, 1); |
9daf8208 AV |
1817 | sw_buf = devm_kzalloc(ice_hw_to_dev(hw), buf_len, GFP_KERNEL); |
1818 | if (!sw_buf) | |
d54699e2 | 1819 | return -ENOMEM; |
9daf8208 AV |
1820 | sw_buf->num_elems = cpu_to_le16(1); |
1821 | ||
1822 | if (lkup_type == ICE_SW_LKUP_MAC || | |
1823 | lkup_type == ICE_SW_LKUP_MAC_VLAN || | |
1824 | lkup_type == ICE_SW_LKUP_ETHERTYPE || | |
1825 | lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC || | |
1826 | lkup_type == ICE_SW_LKUP_PROMISC || | |
d7393425 MW |
1827 | lkup_type == ICE_SW_LKUP_PROMISC_VLAN || |
1828 | lkup_type == ICE_SW_LKUP_DFLT) { | |
9daf8208 AV |
1829 | sw_buf->res_type = cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_REP); |
1830 | } else if (lkup_type == ICE_SW_LKUP_VLAN) { | |
1831 | sw_buf->res_type = | |
1832 | cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_PRUNE); | |
1833 | } else { | |
d54699e2 | 1834 | status = -EINVAL; |
9daf8208 AV |
1835 | goto ice_aq_alloc_free_vsi_list_exit; |
1836 | } | |
1837 | ||
1838 | if (opc == ice_aqc_opc_free_res) | |
1839 | sw_buf->elem[0].e.sw_resp = cpu_to_le16(*vsi_list_id); | |
1840 | ||
1841 | status = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len, opc, NULL); | |
1842 | if (status) | |
1843 | goto ice_aq_alloc_free_vsi_list_exit; | |
1844 | ||
1845 | if (opc == ice_aqc_opc_alloc_res) { | |
1846 | vsi_ele = &sw_buf->elem[0]; | |
1847 | *vsi_list_id = le16_to_cpu(vsi_ele->e.sw_resp); | |
1848 | } | |
1849 | ||
1850 | ice_aq_alloc_free_vsi_list_exit: | |
1851 | devm_kfree(ice_hw_to_dev(hw), sw_buf); | |
1852 | return status; | |
1853 | } | |
1854 | ||
1855 | /** | |
1856 | * ice_aq_sw_rules - add/update/remove switch rules | |
f9867df6 | 1857 | * @hw: pointer to the HW struct |
9daf8208 AV |
1858 | * @rule_list: pointer to switch rule population list |
1859 | * @rule_list_sz: total size of the rule list in bytes | |
1860 | * @num_rules: number of switch rules in the rule_list | |
1861 | * @opc: switch rules population command type - pass in the command opcode | |
1862 | * @cd: pointer to command details structure or NULL | |
1863 | * | |
1864 | * Add(0x02a0)/Update(0x02a1)/Remove(0x02a2) switch rules commands to firmware | |
1865 | */ | |
5e24d598 | 1866 | int |
9daf8208 AV |
1867 | ice_aq_sw_rules(struct ice_hw *hw, void *rule_list, u16 rule_list_sz, |
1868 | u8 num_rules, enum ice_adminq_opc opc, struct ice_sq_cd *cd) | |
1869 | { | |
1870 | struct ice_aq_desc desc; | |
5e24d598 | 1871 | int status; |
9daf8208 AV |
1872 | |
1873 | if (opc != ice_aqc_opc_add_sw_rules && | |
1874 | opc != ice_aqc_opc_update_sw_rules && | |
1875 | opc != ice_aqc_opc_remove_sw_rules) | |
d54699e2 | 1876 | return -EINVAL; |
9daf8208 AV |
1877 | |
1878 | ice_fill_dflt_direct_cmd_desc(&desc, opc); | |
1879 | ||
1880 | desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); | |
1881 | desc.params.sw_rules.num_rules_fltr_entry_index = | |
1882 | cpu_to_le16(num_rules); | |
ca1fdb88 KP |
1883 | status = ice_aq_send_cmd(hw, &desc, rule_list, rule_list_sz, cd); |
1884 | if (opc != ice_aqc_opc_add_sw_rules && | |
1885 | hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT) | |
d54699e2 | 1886 | status = -ENOENT; |
ca1fdb88 KP |
1887 | |
1888 | return status; | |
9daf8208 AV |
1889 | } |
1890 | ||
7715ec32 GK |
1891 | /** |
1892 | * ice_aq_add_recipe - add switch recipe | |
1893 | * @hw: pointer to the HW struct | |
1894 | * @s_recipe_list: pointer to switch rule population list | |
1895 | * @num_recipes: number of switch recipes in the list | |
1896 | * @cd: pointer to command details structure or NULL | |
1897 | * | |
1898 | * Add(0x0290) | |
1899 | */ | |
5e24d598 | 1900 | static int |
7715ec32 GK |
1901 | ice_aq_add_recipe(struct ice_hw *hw, |
1902 | struct ice_aqc_recipe_data_elem *s_recipe_list, | |
1903 | u16 num_recipes, struct ice_sq_cd *cd) | |
1904 | { | |
1905 | struct ice_aqc_add_get_recipe *cmd; | |
1906 | struct ice_aq_desc desc; | |
1907 | u16 buf_size; | |
1908 | ||
1909 | cmd = &desc.params.add_get_recipe; | |
1910 | ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_recipe); | |
1911 | ||
1912 | cmd->num_sub_recipes = cpu_to_le16(num_recipes); | |
1913 | desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); | |
1914 | ||
1915 | buf_size = num_recipes * sizeof(*s_recipe_list); | |
1916 | ||
1917 | return ice_aq_send_cmd(hw, &desc, s_recipe_list, buf_size, cd); | |
1918 | } | |
1919 | ||
1920 | /** | |
1921 | * ice_aq_get_recipe - get switch recipe | |
1922 | * @hw: pointer to the HW struct | |
1923 | * @s_recipe_list: pointer to switch rule population list | |
1924 | * @num_recipes: pointer to the number of recipes (input and output) | |
1925 | * @recipe_root: root recipe number of recipe(s) to retrieve | |
1926 | * @cd: pointer to command details structure or NULL | |
1927 | * | |
1928 | * Get(0x0292) | |
1929 | * | |
1930 | * On input, *num_recipes should equal the number of entries in s_recipe_list. | |
1931 | * On output, *num_recipes will equal the number of entries returned in | |
1932 | * s_recipe_list. | |
1933 | * | |
1934 | * The caller must supply enough space in s_recipe_list to hold all possible | |
1935 | * recipes and *num_recipes must equal ICE_MAX_NUM_RECIPES. | |
1936 | */ | |
5e24d598 | 1937 | static int |
7715ec32 GK |
1938 | ice_aq_get_recipe(struct ice_hw *hw, |
1939 | struct ice_aqc_recipe_data_elem *s_recipe_list, | |
1940 | u16 *num_recipes, u16 recipe_root, struct ice_sq_cd *cd) | |
1941 | { | |
1942 | struct ice_aqc_add_get_recipe *cmd; | |
1943 | struct ice_aq_desc desc; | |
7715ec32 | 1944 | u16 buf_size; |
5518ac2a | 1945 | int status; |
7715ec32 GK |
1946 | |
1947 | if (*num_recipes != ICE_MAX_NUM_RECIPES) | |
d54699e2 | 1948 | return -EINVAL; |
7715ec32 GK |
1949 | |
1950 | cmd = &desc.params.add_get_recipe; | |
1951 | ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_recipe); | |
1952 | ||
1953 | cmd->return_index = cpu_to_le16(recipe_root); | |
1954 | cmd->num_sub_recipes = 0; | |
1955 | ||
1956 | buf_size = *num_recipes * sizeof(*s_recipe_list); | |
1957 | ||
1958 | status = ice_aq_send_cmd(hw, &desc, s_recipe_list, buf_size, cd); | |
1959 | *num_recipes = le16_to_cpu(cmd->num_sub_recipes); | |
1960 | ||
1961 | return status; | |
1962 | } | |
1963 | ||
a1ffafb0 BC |
1964 | /** |
1965 | * ice_update_recipe_lkup_idx - update a default recipe based on the lkup_idx | |
1966 | * @hw: pointer to the HW struct | |
1967 | * @params: parameters used to update the default recipe | |
1968 | * | |
1969 | * This function only supports updating default recipes and it only supports | |
1970 | * updating a single recipe based on the lkup_idx at a time. | |
1971 | * | |
1972 | * This is done as a read-modify-write operation. First, get the current recipe | |
1973 | * contents based on the recipe's ID. Then modify the field vector index and | |
1974 | * mask if it's valid at the lkup_idx. Finally, use the add recipe AQ to update | |
1975 | * the pre-existing recipe with the modifications. | |
1976 | */ | |
1977 | int | |
1978 | ice_update_recipe_lkup_idx(struct ice_hw *hw, | |
1979 | struct ice_update_recipe_lkup_idx_params *params) | |
1980 | { | |
1981 | struct ice_aqc_recipe_data_elem *rcp_list; | |
1982 | u16 num_recps = ICE_MAX_NUM_RECIPES; | |
1983 | int status; | |
1984 | ||
1985 | rcp_list = kcalloc(num_recps, sizeof(*rcp_list), GFP_KERNEL); | |
1986 | if (!rcp_list) | |
1987 | return -ENOMEM; | |
1988 | ||
1989 | /* read current recipe list from firmware */ | |
1990 | rcp_list->recipe_indx = params->rid; | |
1991 | status = ice_aq_get_recipe(hw, rcp_list, &num_recps, params->rid, NULL); | |
1992 | if (status) { | |
1993 | ice_debug(hw, ICE_DBG_SW, "Failed to get recipe %d, status %d\n", | |
1994 | params->rid, status); | |
1995 | goto error_out; | |
1996 | } | |
1997 | ||
1998 | /* only modify existing recipe's lkup_idx and mask if valid, while | |
1999 | * leaving all other fields the same, then update the recipe firmware | |
2000 | */ | |
2001 | rcp_list->content.lkup_indx[params->lkup_idx] = params->fv_idx; | |
2002 | if (params->mask_valid) | |
2003 | rcp_list->content.mask[params->lkup_idx] = | |
2004 | cpu_to_le16(params->mask); | |
2005 | ||
2006 | if (params->ignore_valid) | |
2007 | rcp_list->content.lkup_indx[params->lkup_idx] |= | |
2008 | ICE_AQ_RECIPE_LKUP_IGNORE; | |
2009 | ||
2010 | status = ice_aq_add_recipe(hw, &rcp_list[0], 1, NULL); | |
2011 | if (status) | |
2012 | ice_debug(hw, ICE_DBG_SW, "Failed to update recipe %d lkup_idx %d fv_idx %d mask %d mask_valid %s, status %d\n", | |
2013 | params->rid, params->lkup_idx, params->fv_idx, | |
2014 | params->mask, params->mask_valid ? "true" : "false", | |
2015 | status); | |
2016 | ||
2017 | error_out: | |
2018 | kfree(rcp_list); | |
2019 | return status; | |
2020 | } | |
2021 | ||
7715ec32 GK |
2022 | /** |
2023 | * ice_aq_map_recipe_to_profile - Map recipe to packet profile | |
2024 | * @hw: pointer to the HW struct | |
2025 | * @profile_id: package profile ID to associate the recipe with | |
2026 | * @r_bitmap: Recipe bitmap filled in and need to be returned as response | |
2027 | * @cd: pointer to command details structure or NULL | |
2028 | * Recipe to profile association (0x0291) | |
2029 | */ | |
5e24d598 | 2030 | static int |
7715ec32 GK |
2031 | ice_aq_map_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap, |
2032 | struct ice_sq_cd *cd) | |
2033 | { | |
2034 | struct ice_aqc_recipe_to_profile *cmd; | |
2035 | struct ice_aq_desc desc; | |
2036 | ||
2037 | cmd = &desc.params.recipe_to_profile; | |
2038 | ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_recipe_to_profile); | |
2039 | cmd->profile_id = cpu_to_le16(profile_id); | |
2040 | /* Set the recipe ID bit in the bitmask to let the device know which | |
2041 | * profile we are associating the recipe to | |
2042 | */ | |
2043 | memcpy(cmd->recipe_assoc, r_bitmap, sizeof(cmd->recipe_assoc)); | |
2044 | ||
2045 | return ice_aq_send_cmd(hw, &desc, NULL, 0, cd); | |
2046 | } | |
2047 | ||
2048 | /** | |
2049 | * ice_aq_get_recipe_to_profile - Map recipe to packet profile | |
2050 | * @hw: pointer to the HW struct | |
2051 | * @profile_id: package profile ID to associate the recipe with | |
2052 | * @r_bitmap: Recipe bitmap filled in and need to be returned as response | |
2053 | * @cd: pointer to command details structure or NULL | |
2054 | * Associate profile ID with given recipe (0x0293) | |
2055 | */ | |
5e24d598 | 2056 | static int |
7715ec32 GK |
2057 | ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap, |
2058 | struct ice_sq_cd *cd) | |
2059 | { | |
2060 | struct ice_aqc_recipe_to_profile *cmd; | |
2061 | struct ice_aq_desc desc; | |
5e24d598 | 2062 | int status; |
7715ec32 GK |
2063 | |
2064 | cmd = &desc.params.recipe_to_profile; | |
2065 | ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_recipe_to_profile); | |
2066 | cmd->profile_id = cpu_to_le16(profile_id); | |
2067 | ||
2068 | status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd); | |
2069 | if (!status) | |
2070 | memcpy(r_bitmap, cmd->recipe_assoc, sizeof(cmd->recipe_assoc)); | |
2071 | ||
2072 | return status; | |
2073 | } | |
2074 | ||
2075 | /** | |
2076 | * ice_alloc_recipe - add recipe resource | |
2077 | * @hw: pointer to the hardware structure | |
2078 | * @rid: recipe ID returned as response to AQ call | |
2079 | */ | |
5e24d598 | 2080 | static int ice_alloc_recipe(struct ice_hw *hw, u16 *rid) |
7715ec32 GK |
2081 | { |
2082 | struct ice_aqc_alloc_free_res_elem *sw_buf; | |
7715ec32 | 2083 | u16 buf_len; |
5518ac2a | 2084 | int status; |
7715ec32 GK |
2085 | |
2086 | buf_len = struct_size(sw_buf, elem, 1); | |
2087 | sw_buf = kzalloc(buf_len, GFP_KERNEL); | |
2088 | if (!sw_buf) | |
d54699e2 | 2089 | return -ENOMEM; |
7715ec32 GK |
2090 | |
2091 | sw_buf->num_elems = cpu_to_le16(1); | |
2092 | sw_buf->res_type = cpu_to_le16((ICE_AQC_RES_TYPE_RECIPE << | |
2093 | ICE_AQC_RES_TYPE_S) | | |
2094 | ICE_AQC_RES_TYPE_FLAG_SHARED); | |
2095 | status = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len, | |
2096 | ice_aqc_opc_alloc_res, NULL); | |
2097 | if (!status) | |
2098 | *rid = le16_to_cpu(sw_buf->elem[0].e.sw_resp); | |
2099 | kfree(sw_buf); | |
2100 | ||
2101 | return status; | |
2102 | } | |
2103 | ||
fd2a6b71 DN |
2104 | /** |
2105 | * ice_get_recp_to_prof_map - updates recipe to profile mapping | |
2106 | * @hw: pointer to hardware structure | |
2107 | * | |
2108 | * This function is used to populate recipe_to_profile matrix where index to | |
2109 | * this array is the recipe ID and the element is the mapping of which profiles | |
2110 | * is this recipe mapped to. | |
2111 | */ | |
2112 | static void ice_get_recp_to_prof_map(struct ice_hw *hw) | |
2113 | { | |
2114 | DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES); | |
2115 | u16 i; | |
2116 | ||
2117 | for (i = 0; i < hw->switch_info->max_used_prof_index + 1; i++) { | |
2118 | u16 j; | |
2119 | ||
2120 | bitmap_zero(profile_to_recipe[i], ICE_MAX_NUM_RECIPES); | |
2121 | bitmap_zero(r_bitmap, ICE_MAX_NUM_RECIPES); | |
2122 | if (ice_aq_get_recipe_to_profile(hw, i, (u8 *)r_bitmap, NULL)) | |
2123 | continue; | |
2124 | bitmap_copy(profile_to_recipe[i], r_bitmap, | |
2125 | ICE_MAX_NUM_RECIPES); | |
2126 | for_each_set_bit(j, r_bitmap, ICE_MAX_NUM_RECIPES) | |
2127 | set_bit(i, recipe_to_profile[j]); | |
2128 | } | |
2129 | } | |
2130 | ||
2131 | /** | |
2132 | * ice_collect_result_idx - copy result index values | |
2133 | * @buf: buffer that contains the result index | |
2134 | * @recp: the recipe struct to copy data into | |
2135 | */ | |
2136 | static void | |
2137 | ice_collect_result_idx(struct ice_aqc_recipe_data_elem *buf, | |
2138 | struct ice_sw_recipe *recp) | |
2139 | { | |
2140 | if (buf->content.result_indx & ICE_AQ_RECIPE_RESULT_EN) | |
2141 | set_bit(buf->content.result_indx & ~ICE_AQ_RECIPE_RESULT_EN, | |
2142 | recp->res_idxs); | |
2143 | } | |
2144 | ||
2145 | /** | |
2146 | * ice_get_recp_frm_fw - update SW bookkeeping from FW recipe entries | |
2147 | * @hw: pointer to hardware structure | |
2148 | * @recps: struct that we need to populate | |
2149 | * @rid: recipe ID that we are populating | |
2150 | * @refresh_required: true if we should get recipe to profile mapping from FW | |
2151 | * | |
2152 | * This function is used to populate all the necessary entries into our | |
2153 | * bookkeeping so that we have a current list of all the recipes that are | |
2154 | * programmed in the firmware. | |
2155 | */ | |
5e24d598 | 2156 | static int |
fd2a6b71 DN |
2157 | ice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid, |
2158 | bool *refresh_required) | |
2159 | { | |
2160 | DECLARE_BITMAP(result_bm, ICE_MAX_FV_WORDS); | |
2161 | struct ice_aqc_recipe_data_elem *tmp; | |
2162 | u16 num_recps = ICE_MAX_NUM_RECIPES; | |
2163 | struct ice_prot_lkup_ext *lkup_exts; | |
fd2a6b71 DN |
2164 | u8 fv_word_idx = 0; |
2165 | u16 sub_recps; | |
5518ac2a | 2166 | int status; |
fd2a6b71 DN |
2167 | |
2168 | bitmap_zero(result_bm, ICE_MAX_FV_WORDS); | |
2169 | ||
2170 | /* we need a buffer big enough to accommodate all the recipes */ | |
2171 | tmp = kcalloc(ICE_MAX_NUM_RECIPES, sizeof(*tmp), GFP_KERNEL); | |
2172 | if (!tmp) | |
d54699e2 | 2173 | return -ENOMEM; |
fd2a6b71 DN |
2174 | |
2175 | tmp[0].recipe_indx = rid; | |
2176 | status = ice_aq_get_recipe(hw, tmp, &num_recps, rid, NULL); | |
2177 | /* non-zero status meaning recipe doesn't exist */ | |
2178 | if (status) | |
2179 | goto err_unroll; | |
2180 | ||
2181 | /* Get recipe to profile map so that we can get the fv from lkups that | |
2182 | * we read for a recipe from FW. Since we want to minimize the number of | |
2183 | * times we make this FW call, just make one call and cache the copy | |
2184 | * until a new recipe is added. This operation is only required the | |
2185 | * first time to get the changes from FW. Then to search existing | |
2186 | * entries we don't need to update the cache again until another recipe | |
2187 | * gets added. | |
2188 | */ | |
2189 | if (*refresh_required) { | |
2190 | ice_get_recp_to_prof_map(hw); | |
2191 | *refresh_required = false; | |
2192 | } | |
2193 | ||
2194 | /* Start populating all the entries for recps[rid] based on lkups from | |
2195 | * firmware. Note that we are only creating the root recipe in our | |
2196 | * database. | |
2197 | */ | |
2198 | lkup_exts = &recps[rid].lkup_exts; | |
2199 | ||
2200 | for (sub_recps = 0; sub_recps < num_recps; sub_recps++) { | |
2201 | struct ice_aqc_recipe_data_elem root_bufs = tmp[sub_recps]; | |
2202 | struct ice_recp_grp_entry *rg_entry; | |
2203 | u8 i, prof, idx, prot = 0; | |
2204 | bool is_root; | |
2205 | u16 off = 0; | |
2206 | ||
2207 | rg_entry = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*rg_entry), | |
2208 | GFP_KERNEL); | |
2209 | if (!rg_entry) { | |
d54699e2 | 2210 | status = -ENOMEM; |
fd2a6b71 DN |
2211 | goto err_unroll; |
2212 | } | |
2213 | ||
2214 | idx = root_bufs.recipe_indx; | |
2215 | is_root = root_bufs.content.rid & ICE_AQ_RECIPE_ID_IS_ROOT; | |
2216 | ||
2217 | /* Mark all result indices in this chain */ | |
2218 | if (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN) | |
2219 | set_bit(root_bufs.content.result_indx & ~ICE_AQ_RECIPE_RESULT_EN, | |
2220 | result_bm); | |
2221 | ||
2222 | /* get the first profile that is associated with rid */ | |
2223 | prof = find_first_bit(recipe_to_profile[idx], | |
2224 | ICE_MAX_NUM_PROFILES); | |
2225 | for (i = 0; i < ICE_NUM_WORDS_RECIPE; i++) { | |
2226 | u8 lkup_indx = root_bufs.content.lkup_indx[i + 1]; | |
2227 | ||
2228 | rg_entry->fv_idx[i] = lkup_indx; | |
2229 | rg_entry->fv_mask[i] = | |
2230 | le16_to_cpu(root_bufs.content.mask[i + 1]); | |
2231 | ||
2232 | /* If the recipe is a chained recipe then all its | |
2233 | * child recipe's result will have a result index. | |
2234 | * To fill fv_words we should not use those result | |
2235 | * index, we only need the protocol ids and offsets. | |
2236 | * We will skip all the fv_idx which stores result | |
2237 | * index in them. We also need to skip any fv_idx which | |
2238 | * has ICE_AQ_RECIPE_LKUP_IGNORE or 0 since it isn't a | |
2239 | * valid offset value. | |
2240 | */ | |
2241 | if (test_bit(rg_entry->fv_idx[i], hw->switch_info->prof_res_bm[prof]) || | |
2242 | rg_entry->fv_idx[i] & ICE_AQ_RECIPE_LKUP_IGNORE || | |
2243 | rg_entry->fv_idx[i] == 0) | |
2244 | continue; | |
2245 | ||
2246 | ice_find_prot_off(hw, ICE_BLK_SW, prof, | |
2247 | rg_entry->fv_idx[i], &prot, &off); | |
2248 | lkup_exts->fv_words[fv_word_idx].prot_id = prot; | |
2249 | lkup_exts->fv_words[fv_word_idx].off = off; | |
2250 | lkup_exts->field_mask[fv_word_idx] = | |
2251 | rg_entry->fv_mask[i]; | |
2252 | fv_word_idx++; | |
2253 | } | |
2254 | /* populate rg_list with the data from the child entry of this | |
2255 | * recipe | |
2256 | */ | |
2257 | list_add(&rg_entry->l_entry, &recps[rid].rg_list); | |
2258 | ||
2259 | /* Propagate some data to the recipe database */ | |
2260 | recps[idx].is_root = !!is_root; | |
2261 | recps[idx].priority = root_bufs.content.act_ctrl_fwd_priority; | |
2262 | bitmap_zero(recps[idx].res_idxs, ICE_MAX_FV_WORDS); | |
2263 | if (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN) { | |
2264 | recps[idx].chain_idx = root_bufs.content.result_indx & | |
2265 | ~ICE_AQ_RECIPE_RESULT_EN; | |
2266 | set_bit(recps[idx].chain_idx, recps[idx].res_idxs); | |
2267 | } else { | |
2268 | recps[idx].chain_idx = ICE_INVAL_CHAIN_IND; | |
2269 | } | |
2270 | ||
2271 | if (!is_root) | |
2272 | continue; | |
2273 | ||
2274 | /* Only do the following for root recipes entries */ | |
2275 | memcpy(recps[idx].r_bitmap, root_bufs.recipe_bitmap, | |
2276 | sizeof(recps[idx].r_bitmap)); | |
2277 | recps[idx].root_rid = root_bufs.content.rid & | |
2278 | ~ICE_AQ_RECIPE_ID_IS_ROOT; | |
2279 | recps[idx].priority = root_bufs.content.act_ctrl_fwd_priority; | |
2280 | } | |
2281 | ||
2282 | /* Complete initialization of the root recipe entry */ | |
2283 | lkup_exts->n_val_words = fv_word_idx; | |
2284 | recps[rid].big_recp = (num_recps > 1); | |
2285 | recps[rid].n_grp_count = (u8)num_recps; | |
2286 | recps[rid].root_buf = devm_kmemdup(ice_hw_to_dev(hw), tmp, | |
2287 | recps[rid].n_grp_count * sizeof(*recps[rid].root_buf), | |
2288 | GFP_KERNEL); | |
c8e51a01 | 2289 | if (!recps[rid].root_buf) { |
d54699e2 | 2290 | status = -ENOMEM; |
fd2a6b71 | 2291 | goto err_unroll; |
c8e51a01 | 2292 | } |
fd2a6b71 DN |
2293 | |
2294 | /* Copy result indexes */ | |
2295 | bitmap_copy(recps[rid].res_idxs, result_bm, ICE_MAX_FV_WORDS); | |
2296 | recps[rid].recp_created = true; | |
2297 | ||
2298 | err_unroll: | |
2299 | kfree(tmp); | |
2300 | return status; | |
2301 | } | |
2302 | ||
9c20346b AV |
2303 | /* ice_init_port_info - Initialize port_info with switch configuration data |
2304 | * @pi: pointer to port_info | |
2305 | * @vsi_port_num: VSI number or port number | |
2306 | * @type: Type of switch element (port or VSI) | |
2307 | * @swid: switch ID of the switch the element is attached to | |
2308 | * @pf_vf_num: PF or VF number | |
2309 | * @is_vf: true if the element is a VF, false otherwise | |
2310 | */ | |
2311 | static void | |
2312 | ice_init_port_info(struct ice_port_info *pi, u16 vsi_port_num, u8 type, | |
2313 | u16 swid, u16 pf_vf_num, bool is_vf) | |
2314 | { | |
2315 | switch (type) { | |
2316 | case ICE_AQC_GET_SW_CONF_RESP_PHYS_PORT: | |
2317 | pi->lport = (u8)(vsi_port_num & ICE_LPORT_MASK); | |
2318 | pi->sw_id = swid; | |
2319 | pi->pf_vf_num = pf_vf_num; | |
2320 | pi->is_vf = is_vf; | |
9c20346b AV |
2321 | break; |
2322 | default: | |
9228d8b2 | 2323 | ice_debug(pi->hw, ICE_DBG_SW, "incorrect VSI/port type received\n"); |
9c20346b AV |
2324 | break; |
2325 | } | |
2326 | } | |
2327 | ||
2328 | /* ice_get_initial_sw_cfg - Get initial port and default VSI data | |
2329 | * @hw: pointer to the hardware structure | |
2330 | */ | |
5e24d598 | 2331 | int ice_get_initial_sw_cfg(struct ice_hw *hw) |
9c20346b | 2332 | { |
b3c38904 | 2333 | struct ice_aqc_get_sw_cfg_resp_elem *rbuf; |
9c20346b AV |
2334 | u16 req_desc = 0; |
2335 | u16 num_elems; | |
5518ac2a | 2336 | int status; |
9c20346b AV |
2337 | u16 i; |
2338 | ||
1b9e740d | 2339 | rbuf = kzalloc(ICE_SW_CFG_MAX_BUF_LEN, GFP_KERNEL); |
9c20346b | 2340 | if (!rbuf) |
d54699e2 | 2341 | return -ENOMEM; |
9c20346b AV |
2342 | |
2343 | /* Multiple calls to ice_aq_get_sw_cfg may be required | |
2344 | * to get all the switch configuration information. The need | |
2345 | * for additional calls is indicated by ice_aq_get_sw_cfg | |
2346 | * writing a non-zero value in req_desc | |
2347 | */ | |
2348 | do { | |
b3c38904 BA |
2349 | struct ice_aqc_get_sw_cfg_resp_elem *ele; |
2350 | ||
9c20346b AV |
2351 | status = ice_aq_get_sw_cfg(hw, rbuf, ICE_SW_CFG_MAX_BUF_LEN, |
2352 | &req_desc, &num_elems, NULL); | |
2353 | ||
2354 | if (status) | |
2355 | break; | |
2356 | ||
b3c38904 | 2357 | for (i = 0, ele = rbuf; i < num_elems; i++, ele++) { |
9c20346b AV |
2358 | u16 pf_vf_num, swid, vsi_port_num; |
2359 | bool is_vf = false; | |
6dae8aa0 | 2360 | u8 res_type; |
9c20346b | 2361 | |
9c20346b AV |
2362 | vsi_port_num = le16_to_cpu(ele->vsi_port_num) & |
2363 | ICE_AQC_GET_SW_CONF_RESP_VSI_PORT_NUM_M; | |
2364 | ||
2365 | pf_vf_num = le16_to_cpu(ele->pf_vf_num) & | |
2366 | ICE_AQC_GET_SW_CONF_RESP_FUNC_NUM_M; | |
2367 | ||
2368 | swid = le16_to_cpu(ele->swid); | |
2369 | ||
2370 | if (le16_to_cpu(ele->pf_vf_num) & | |
2371 | ICE_AQC_GET_SW_CONF_RESP_IS_VF) | |
2372 | is_vf = true; | |
2373 | ||
88865fc4 KK |
2374 | res_type = (u8)(le16_to_cpu(ele->vsi_port_num) >> |
2375 | ICE_AQC_GET_SW_CONF_RESP_TYPE_S); | |
9c20346b | 2376 | |
6dae8aa0 | 2377 | if (res_type == ICE_AQC_GET_SW_CONF_RESP_VSI) { |
9c20346b AV |
2378 | /* FW VSI is not needed. Just continue. */ |
2379 | continue; | |
2380 | } | |
2381 | ||
2382 | ice_init_port_info(hw->port_info, vsi_port_num, | |
6dae8aa0 | 2383 | res_type, swid, pf_vf_num, is_vf); |
9c20346b AV |
2384 | } |
2385 | } while (req_desc && !status); | |
2386 | ||
1b9e740d | 2387 | kfree(rbuf); |
9c20346b AV |
2388 | return status; |
2389 | } | |
9daf8208 AV |
2390 | |
2391 | /** | |
2392 | * ice_fill_sw_info - Helper function to populate lb_en and lan_en | |
2393 | * @hw: pointer to the hardware structure | |
6a7e6993 | 2394 | * @fi: filter info structure to fill/update |
9daf8208 AV |
2395 | * |
2396 | * This helper function populates the lb_en and lan_en elements of the provided | |
2397 | * ice_fltr_info struct using the switch's type and characteristics of the | |
2398 | * switch rule being configured. | |
2399 | */ | |
6a7e6993 | 2400 | static void ice_fill_sw_info(struct ice_hw *hw, struct ice_fltr_info *fi) |
9daf8208 | 2401 | { |
6a7e6993 YRPB |
2402 | fi->lb_en = false; |
2403 | fi->lan_en = false; | |
2404 | if ((fi->flag & ICE_FLTR_TX) && | |
2405 | (fi->fltr_act == ICE_FWD_TO_VSI || | |
2406 | fi->fltr_act == ICE_FWD_TO_VSI_LIST || | |
2407 | fi->fltr_act == ICE_FWD_TO_Q || | |
2408 | fi->fltr_act == ICE_FWD_TO_QGRP)) { | |
b58dafbc CB |
2409 | /* Setting LB for prune actions will result in replicated |
2410 | * packets to the internal switch that will be dropped. | |
2411 | */ | |
2412 | if (fi->lkup_type != ICE_SW_LKUP_VLAN) | |
2413 | fi->lb_en = true; | |
2414 | ||
277b3a45 | 2415 | /* Set lan_en to TRUE if |
6a7e6993 YRPB |
2416 | * 1. The switch is a VEB AND |
2417 | * 2 | |
26069b44 | 2418 | * 2.1 The lookup is a directional lookup like ethertype, |
f9867df6 | 2419 | * promiscuous, ethertype-MAC, promiscuous-VLAN |
26069b44 YRPB |
2420 | * and default-port OR |
2421 | * 2.2 The lookup is VLAN, OR | |
277b3a45 YRPB |
2422 | * 2.3 The lookup is MAC with mcast or bcast addr for MAC, OR |
2423 | * 2.4 The lookup is MAC_VLAN with mcast or bcast addr for MAC. | |
6a7e6993 | 2424 | * |
277b3a45 YRPB |
2425 | * OR |
2426 | * | |
2427 | * The switch is a VEPA. | |
2428 | * | |
2429 | * In all other cases, the LAN enable has to be set to false. | |
6a7e6993 | 2430 | */ |
277b3a45 | 2431 | if (hw->evb_veb) { |
26069b44 YRPB |
2432 | if (fi->lkup_type == ICE_SW_LKUP_ETHERTYPE || |
2433 | fi->lkup_type == ICE_SW_LKUP_PROMISC || | |
2434 | fi->lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC || | |
2435 | fi->lkup_type == ICE_SW_LKUP_PROMISC_VLAN || | |
277b3a45 | 2436 | fi->lkup_type == ICE_SW_LKUP_DFLT || |
26069b44 | 2437 | fi->lkup_type == ICE_SW_LKUP_VLAN || |
277b3a45 YRPB |
2438 | (fi->lkup_type == ICE_SW_LKUP_MAC && |
2439 | !is_unicast_ether_addr(fi->l_data.mac.mac_addr)) || | |
2440 | (fi->lkup_type == ICE_SW_LKUP_MAC_VLAN && | |
2441 | !is_unicast_ether_addr(fi->l_data.mac.mac_addr))) | |
2442 | fi->lan_en = true; | |
2443 | } else { | |
6a7e6993 | 2444 | fi->lan_en = true; |
277b3a45 | 2445 | } |
9daf8208 AV |
2446 | } |
2447 | } | |
2448 | ||
2449 | /** | |
2450 | * ice_fill_sw_rule - Helper function to fill switch rule structure | |
2451 | * @hw: pointer to the hardware structure | |
2452 | * @f_info: entry containing packet forwarding information | |
2453 | * @s_rule: switch rule structure to be filled in based on mac_entry | |
2454 | * @opc: switch rules population command type - pass in the command opcode | |
2455 | */ | |
2456 | static void | |
2457 | ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info, | |
6e1ff618 AL |
2458 | struct ice_sw_rule_lkup_rx_tx *s_rule, |
2459 | enum ice_adminq_opc opc) | |
9daf8208 AV |
2460 | { |
2461 | u16 vlan_id = ICE_MAX_VLAN_ID + 1; | |
2bfefa2d | 2462 | u16 vlan_tpid = ETH_P_8021Q; |
9daf8208 | 2463 | void *daddr = NULL; |
74118f7a ZX |
2464 | u16 eth_hdr_sz; |
2465 | u8 *eth_hdr; | |
9daf8208 AV |
2466 | u32 act = 0; |
2467 | __be16 *off; | |
be8ff000 | 2468 | u8 q_rgn; |
9daf8208 AV |
2469 | |
2470 | if (opc == ice_aqc_opc_remove_sw_rules) { | |
6e1ff618 AL |
2471 | s_rule->act = 0; |
2472 | s_rule->index = cpu_to_le16(f_info->fltr_rule_id); | |
2473 | s_rule->hdr_len = 0; | |
9daf8208 AV |
2474 | return; |
2475 | } | |
2476 | ||
74118f7a | 2477 | eth_hdr_sz = sizeof(dummy_eth_header); |
6e1ff618 | 2478 | eth_hdr = s_rule->hdr_data; |
74118f7a | 2479 | |
9daf8208 | 2480 | /* initialize the ether header with a dummy header */ |
74118f7a | 2481 | memcpy(eth_hdr, dummy_eth_header, eth_hdr_sz); |
9daf8208 AV |
2482 | ice_fill_sw_info(hw, f_info); |
2483 | ||
2484 | switch (f_info->fltr_act) { | |
2485 | case ICE_FWD_TO_VSI: | |
5726ca0e | 2486 | act |= (f_info->fwd_id.hw_vsi_id << ICE_SINGLE_ACT_VSI_ID_S) & |
9daf8208 AV |
2487 | ICE_SINGLE_ACT_VSI_ID_M; |
2488 | if (f_info->lkup_type != ICE_SW_LKUP_VLAN) | |
2489 | act |= ICE_SINGLE_ACT_VSI_FORWARDING | | |
2490 | ICE_SINGLE_ACT_VALID_BIT; | |
2491 | break; | |
2492 | case ICE_FWD_TO_VSI_LIST: | |
2493 | act |= ICE_SINGLE_ACT_VSI_LIST; | |
2494 | act |= (f_info->fwd_id.vsi_list_id << | |
2495 | ICE_SINGLE_ACT_VSI_LIST_ID_S) & | |
2496 | ICE_SINGLE_ACT_VSI_LIST_ID_M; | |
2497 | if (f_info->lkup_type != ICE_SW_LKUP_VLAN) | |
2498 | act |= ICE_SINGLE_ACT_VSI_FORWARDING | | |
2499 | ICE_SINGLE_ACT_VALID_BIT; | |
2500 | break; | |
2501 | case ICE_FWD_TO_Q: | |
2502 | act |= ICE_SINGLE_ACT_TO_Q; | |
2503 | act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) & | |
2504 | ICE_SINGLE_ACT_Q_INDEX_M; | |
2505 | break; | |
be8ff000 AV |
2506 | case ICE_DROP_PACKET: |
2507 | act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP | | |
2508 | ICE_SINGLE_ACT_VALID_BIT; | |
2509 | break; | |
9daf8208 | 2510 | case ICE_FWD_TO_QGRP: |
be8ff000 AV |
2511 | q_rgn = f_info->qgrp_size > 0 ? |
2512 | (u8)ilog2(f_info->qgrp_size) : 0; | |
9daf8208 | 2513 | act |= ICE_SINGLE_ACT_TO_Q; |
be8ff000 AV |
2514 | act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) & |
2515 | ICE_SINGLE_ACT_Q_INDEX_M; | |
2516 | act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) & | |
9daf8208 AV |
2517 | ICE_SINGLE_ACT_Q_REGION_M; |
2518 | break; | |
9daf8208 AV |
2519 | default: |
2520 | return; | |
2521 | } | |
2522 | ||
2523 | if (f_info->lb_en) | |
2524 | act |= ICE_SINGLE_ACT_LB_ENABLE; | |
2525 | if (f_info->lan_en) | |
2526 | act |= ICE_SINGLE_ACT_LAN_ENABLE; | |
2527 | ||
2528 | switch (f_info->lkup_type) { | |
2529 | case ICE_SW_LKUP_MAC: | |
2530 | daddr = f_info->l_data.mac.mac_addr; | |
2531 | break; | |
2532 | case ICE_SW_LKUP_VLAN: | |
2533 | vlan_id = f_info->l_data.vlan.vlan_id; | |
2bfefa2d BC |
2534 | if (f_info->l_data.vlan.tpid_valid) |
2535 | vlan_tpid = f_info->l_data.vlan.tpid; | |
9daf8208 AV |
2536 | if (f_info->fltr_act == ICE_FWD_TO_VSI || |
2537 | f_info->fltr_act == ICE_FWD_TO_VSI_LIST) { | |
2538 | act |= ICE_SINGLE_ACT_PRUNE; | |
2539 | act |= ICE_SINGLE_ACT_EGRESS | ICE_SINGLE_ACT_INGRESS; | |
2540 | } | |
2541 | break; | |
2542 | case ICE_SW_LKUP_ETHERTYPE_MAC: | |
2543 | daddr = f_info->l_data.ethertype_mac.mac_addr; | |
4e83fc93 | 2544 | fallthrough; |
9daf8208 | 2545 | case ICE_SW_LKUP_ETHERTYPE: |
feee3cb3 | 2546 | off = (__force __be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET); |
9daf8208 AV |
2547 | *off = cpu_to_be16(f_info->l_data.ethertype_mac.ethertype); |
2548 | break; | |
2549 | case ICE_SW_LKUP_MAC_VLAN: | |
2550 | daddr = f_info->l_data.mac_vlan.mac_addr; | |
2551 | vlan_id = f_info->l_data.mac_vlan.vlan_id; | |
2552 | break; | |
2553 | case ICE_SW_LKUP_PROMISC_VLAN: | |
2554 | vlan_id = f_info->l_data.mac_vlan.vlan_id; | |
4e83fc93 | 2555 | fallthrough; |
9daf8208 AV |
2556 | case ICE_SW_LKUP_PROMISC: |
2557 | daddr = f_info->l_data.mac_vlan.mac_addr; | |
2558 | break; | |
2559 | default: | |
2560 | break; | |
2561 | } | |
2562 | ||
6e1ff618 | 2563 | s_rule->hdr.type = (f_info->flag & ICE_FLTR_RX) ? |
9daf8208 AV |
2564 | cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX) : |
2565 | cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_TX); | |
2566 | ||
2567 | /* Recipe set depending on lookup type */ | |
6e1ff618 AL |
2568 | s_rule->recipe_id = cpu_to_le16(f_info->lkup_type); |
2569 | s_rule->src = cpu_to_le16(f_info->src); | |
2570 | s_rule->act = cpu_to_le32(act); | |
9daf8208 AV |
2571 | |
2572 | if (daddr) | |
74118f7a | 2573 | ether_addr_copy(eth_hdr + ICE_ETH_DA_OFFSET, daddr); |
9daf8208 AV |
2574 | |
2575 | if (!(vlan_id > ICE_MAX_VLAN_ID)) { | |
feee3cb3 | 2576 | off = (__force __be16 *)(eth_hdr + ICE_ETH_VLAN_TCI_OFFSET); |
9daf8208 | 2577 | *off = cpu_to_be16(vlan_id); |
2bfefa2d BC |
2578 | off = (__force __be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET); |
2579 | *off = cpu_to_be16(vlan_tpid); | |
9daf8208 AV |
2580 | } |
2581 | ||
2582 | /* Create the switch rule with the final dummy Ethernet header */ | |
2583 | if (opc != ice_aqc_opc_update_sw_rules) | |
6e1ff618 | 2584 | s_rule->hdr_len = cpu_to_le16(eth_hdr_sz); |
9daf8208 AV |
2585 | } |
2586 | ||
2587 | /** | |
2588 | * ice_add_marker_act | |
2589 | * @hw: pointer to the hardware structure | |
2590 | * @m_ent: the management entry for which sw marker needs to be added | |
2591 | * @sw_marker: sw marker to tag the Rx descriptor with | |
f9867df6 | 2592 | * @l_id: large action resource ID |
9daf8208 AV |
2593 | * |
2594 | * Create a large action to hold software marker and update the switch rule | |
2595 | * entry pointed by m_ent with newly created large action | |
2596 | */ | |
5e24d598 | 2597 | static int |
9daf8208 AV |
2598 | ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent, |
2599 | u16 sw_marker, u16 l_id) | |
2600 | { | |
6e1ff618 AL |
2601 | struct ice_sw_rule_lkup_rx_tx *rx_tx; |
2602 | struct ice_sw_rule_lg_act *lg_act; | |
9daf8208 AV |
2603 | /* For software marker we need 3 large actions |
2604 | * 1. FWD action: FWD TO VSI or VSI LIST | |
f9867df6 AV |
2605 | * 2. GENERIC VALUE action to hold the profile ID |
2606 | * 3. GENERIC VALUE action to hold the software marker ID | |
9daf8208 AV |
2607 | */ |
2608 | const u16 num_lg_acts = 3; | |
9daf8208 AV |
2609 | u16 lg_act_size; |
2610 | u16 rules_size; | |
5518ac2a | 2611 | int status; |
9daf8208 | 2612 | u32 act; |
5726ca0e | 2613 | u16 id; |
9daf8208 AV |
2614 | |
2615 | if (m_ent->fltr_info.lkup_type != ICE_SW_LKUP_MAC) | |
d54699e2 | 2616 | return -EINVAL; |
9daf8208 AV |
2617 | |
2618 | /* Create two back-to-back switch rules and submit them to the HW using | |
2619 | * one memory buffer: | |
2620 | * 1. Large Action | |
d337f2af | 2621 | * 2. Look up Tx Rx |
9daf8208 | 2622 | */ |
6e1ff618 AL |
2623 | lg_act_size = (u16)ICE_SW_RULE_LG_ACT_SIZE(lg_act, num_lg_acts); |
2624 | rules_size = lg_act_size + ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(rx_tx); | |
9daf8208 AV |
2625 | lg_act = devm_kzalloc(ice_hw_to_dev(hw), rules_size, GFP_KERNEL); |
2626 | if (!lg_act) | |
d54699e2 | 2627 | return -ENOMEM; |
9daf8208 | 2628 | |
6e1ff618 | 2629 | rx_tx = (typeof(rx_tx))((u8 *)lg_act + lg_act_size); |
9daf8208 AV |
2630 | |
2631 | /* Fill in the first switch rule i.e. large action */ | |
6e1ff618 AL |
2632 | lg_act->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LG_ACT); |
2633 | lg_act->index = cpu_to_le16(l_id); | |
2634 | lg_act->size = cpu_to_le16(num_lg_acts); | |
9daf8208 AV |
2635 | |
2636 | /* First action VSI forwarding or VSI list forwarding depending on how | |
2637 | * many VSIs | |
2638 | */ | |
5726ca0e AV |
2639 | id = (m_ent->vsi_count > 1) ? m_ent->fltr_info.fwd_id.vsi_list_id : |
2640 | m_ent->fltr_info.fwd_id.hw_vsi_id; | |
9daf8208 AV |
2641 | |
2642 | act = ICE_LG_ACT_VSI_FORWARDING | ICE_LG_ACT_VALID_BIT; | |
66486d89 | 2643 | act |= (id << ICE_LG_ACT_VSI_LIST_ID_S) & ICE_LG_ACT_VSI_LIST_ID_M; |
9daf8208 AV |
2644 | if (m_ent->vsi_count > 1) |
2645 | act |= ICE_LG_ACT_VSI_LIST; | |
6e1ff618 | 2646 | lg_act->act[0] = cpu_to_le32(act); |
9daf8208 AV |
2647 | |
2648 | /* Second action descriptor type */ | |
2649 | act = ICE_LG_ACT_GENERIC; | |
2650 | ||
2651 | act |= (1 << ICE_LG_ACT_GENERIC_VALUE_S) & ICE_LG_ACT_GENERIC_VALUE_M; | |
6e1ff618 | 2652 | lg_act->act[1] = cpu_to_le32(act); |
9daf8208 | 2653 | |
4381147d AV |
2654 | act = (ICE_LG_ACT_GENERIC_OFF_RX_DESC_PROF_IDX << |
2655 | ICE_LG_ACT_GENERIC_OFFSET_S) & ICE_LG_ACT_GENERIC_OFFSET_M; | |
9daf8208 AV |
2656 | |
2657 | /* Third action Marker value */ | |
2658 | act |= ICE_LG_ACT_GENERIC; | |
2659 | act |= (sw_marker << ICE_LG_ACT_GENERIC_VALUE_S) & | |
2660 | ICE_LG_ACT_GENERIC_VALUE_M; | |
2661 | ||
6e1ff618 | 2662 | lg_act->act[2] = cpu_to_le32(act); |
9daf8208 | 2663 | |
d337f2af | 2664 | /* call the fill switch rule to fill the lookup Tx Rx structure */ |
9daf8208 AV |
2665 | ice_fill_sw_rule(hw, &m_ent->fltr_info, rx_tx, |
2666 | ice_aqc_opc_update_sw_rules); | |
2667 | ||
f9867df6 | 2668 | /* Update the action to point to the large action ID */ |
6e1ff618 AL |
2669 | rx_tx->act = cpu_to_le32(ICE_SINGLE_ACT_PTR | |
2670 | ((l_id << ICE_SINGLE_ACT_PTR_VAL_S) & | |
2671 | ICE_SINGLE_ACT_PTR_VAL_M)); | |
9daf8208 | 2672 | |
f9867df6 | 2673 | /* Use the filter rule ID of the previously created rule with single |
9daf8208 AV |
2674 | * act. Once the update happens, hardware will treat this as large |
2675 | * action | |
2676 | */ | |
6e1ff618 | 2677 | rx_tx->index = cpu_to_le16(m_ent->fltr_info.fltr_rule_id); |
9daf8208 AV |
2678 | |
2679 | status = ice_aq_sw_rules(hw, lg_act, rules_size, 2, | |
2680 | ice_aqc_opc_update_sw_rules, NULL); | |
2681 | if (!status) { | |
2682 | m_ent->lg_act_idx = l_id; | |
2683 | m_ent->sw_marker_id = sw_marker; | |
2684 | } | |
2685 | ||
2686 | devm_kfree(ice_hw_to_dev(hw), lg_act); | |
2687 | return status; | |
2688 | } | |
2689 | ||
2690 | /** | |
2691 | * ice_create_vsi_list_map | |
2692 | * @hw: pointer to the hardware structure | |
5726ca0e AV |
2693 | * @vsi_handle_arr: array of VSI handles to set in the VSI mapping |
2694 | * @num_vsi: number of VSI handles in the array | |
f9867df6 | 2695 | * @vsi_list_id: VSI list ID generated as part of allocate resource |
9daf8208 | 2696 | * |
f9867df6 AV |
2697 | * Helper function to create a new entry of VSI list ID to VSI mapping |
2698 | * using the given VSI list ID | |
9daf8208 AV |
2699 | */ |
2700 | static struct ice_vsi_list_map_info * | |
5726ca0e | 2701 | ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi, |
9daf8208 AV |
2702 | u16 vsi_list_id) |
2703 | { | |
2704 | struct ice_switch_info *sw = hw->switch_info; | |
2705 | struct ice_vsi_list_map_info *v_map; | |
2706 | int i; | |
2707 | ||
36ac7911 | 2708 | v_map = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*v_map), GFP_KERNEL); |
9daf8208 AV |
2709 | if (!v_map) |
2710 | return NULL; | |
2711 | ||
2712 | v_map->vsi_list_id = vsi_list_id; | |
5726ca0e | 2713 | v_map->ref_cnt = 1; |
9daf8208 | 2714 | for (i = 0; i < num_vsi; i++) |
5726ca0e | 2715 | set_bit(vsi_handle_arr[i], v_map->vsi_map); |
9daf8208 AV |
2716 | |
2717 | list_add(&v_map->list_entry, &sw->vsi_list_map_head); | |
2718 | return v_map; | |
2719 | } | |
2720 | ||
2721 | /** | |
2722 | * ice_update_vsi_list_rule | |
2723 | * @hw: pointer to the hardware structure | |
5726ca0e AV |
2724 | * @vsi_handle_arr: array of VSI handles to form a VSI list |
2725 | * @num_vsi: number of VSI handles in the array | |
f9867df6 | 2726 | * @vsi_list_id: VSI list ID generated as part of allocate resource |
9daf8208 AV |
2727 | * @remove: Boolean value to indicate if this is a remove action |
2728 | * @opc: switch rules population command type - pass in the command opcode | |
2729 | * @lkup_type: lookup type of the filter | |
2730 | * | |
2731 | * Call AQ command to add a new switch rule or update existing switch rule | |
f9867df6 | 2732 | * using the given VSI list ID |
9daf8208 | 2733 | */ |
5e24d598 | 2734 | static int |
5726ca0e | 2735 | ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi, |
9daf8208 AV |
2736 | u16 vsi_list_id, bool remove, enum ice_adminq_opc opc, |
2737 | enum ice_sw_lkup_type lkup_type) | |
2738 | { | |
6e1ff618 | 2739 | struct ice_sw_rule_vsi_list *s_rule; |
9daf8208 | 2740 | u16 s_rule_size; |
6dae8aa0 | 2741 | u16 rule_type; |
5518ac2a | 2742 | int status; |
9daf8208 AV |
2743 | int i; |
2744 | ||
2745 | if (!num_vsi) | |
d54699e2 | 2746 | return -EINVAL; |
9daf8208 AV |
2747 | |
2748 | if (lkup_type == ICE_SW_LKUP_MAC || | |
2749 | lkup_type == ICE_SW_LKUP_MAC_VLAN || | |
2750 | lkup_type == ICE_SW_LKUP_ETHERTYPE || | |
2751 | lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC || | |
2752 | lkup_type == ICE_SW_LKUP_PROMISC || | |
d7393425 MW |
2753 | lkup_type == ICE_SW_LKUP_PROMISC_VLAN || |
2754 | lkup_type == ICE_SW_LKUP_DFLT) | |
6dae8aa0 BA |
2755 | rule_type = remove ? ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR : |
2756 | ICE_AQC_SW_RULES_T_VSI_LIST_SET; | |
9daf8208 | 2757 | else if (lkup_type == ICE_SW_LKUP_VLAN) |
6dae8aa0 BA |
2758 | rule_type = remove ? ICE_AQC_SW_RULES_T_PRUNE_LIST_CLEAR : |
2759 | ICE_AQC_SW_RULES_T_PRUNE_LIST_SET; | |
9daf8208 | 2760 | else |
d54699e2 | 2761 | return -EINVAL; |
9daf8208 | 2762 | |
6e1ff618 | 2763 | s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(s_rule, num_vsi); |
9daf8208 AV |
2764 | s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL); |
2765 | if (!s_rule) | |
d54699e2 | 2766 | return -ENOMEM; |
5726ca0e AV |
2767 | for (i = 0; i < num_vsi; i++) { |
2768 | if (!ice_is_vsi_valid(hw, vsi_handle_arr[i])) { | |
d54699e2 | 2769 | status = -EINVAL; |
5726ca0e AV |
2770 | goto exit; |
2771 | } | |
2772 | /* AQ call requires hw_vsi_id(s) */ | |
6e1ff618 | 2773 | s_rule->vsi[i] = |
5726ca0e AV |
2774 | cpu_to_le16(ice_get_hw_vsi_num(hw, vsi_handle_arr[i])); |
2775 | } | |
9daf8208 | 2776 | |
6e1ff618 AL |
2777 | s_rule->hdr.type = cpu_to_le16(rule_type); |
2778 | s_rule->number_vsi = cpu_to_le16(num_vsi); | |
2779 | s_rule->index = cpu_to_le16(vsi_list_id); | |
9daf8208 AV |
2780 | |
2781 | status = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, opc, NULL); | |
2782 | ||
5726ca0e | 2783 | exit: |
9daf8208 AV |
2784 | devm_kfree(ice_hw_to_dev(hw), s_rule); |
2785 | return status; | |
2786 | } | |
2787 | ||
2788 | /** | |
2789 | * ice_create_vsi_list_rule - Creates and populates a VSI list rule | |
f9867df6 | 2790 | * @hw: pointer to the HW struct |
5726ca0e AV |
2791 | * @vsi_handle_arr: array of VSI handles to form a VSI list |
2792 | * @num_vsi: number of VSI handles in the array | |
9daf8208 AV |
2793 | * @vsi_list_id: stores the ID of the VSI list to be created |
2794 | * @lkup_type: switch rule filter's lookup type | |
2795 | */ | |
5e24d598 | 2796 | static int |
5726ca0e | 2797 | ice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi, |
9daf8208 AV |
2798 | u16 *vsi_list_id, enum ice_sw_lkup_type lkup_type) |
2799 | { | |
5e24d598 | 2800 | int status; |
9daf8208 AV |
2801 | |
2802 | status = ice_aq_alloc_free_vsi_list(hw, vsi_list_id, lkup_type, | |
2803 | ice_aqc_opc_alloc_res); | |
2804 | if (status) | |
2805 | return status; | |
2806 | ||
2807 | /* Update the newly created VSI list to include the specified VSIs */ | |
5726ca0e AV |
2808 | return ice_update_vsi_list_rule(hw, vsi_handle_arr, num_vsi, |
2809 | *vsi_list_id, false, | |
2810 | ice_aqc_opc_add_sw_rules, lkup_type); | |
9daf8208 AV |
2811 | } |
2812 | ||
2813 | /** | |
2814 | * ice_create_pkt_fwd_rule | |
2815 | * @hw: pointer to the hardware structure | |
2816 | * @f_entry: entry containing packet forwarding information | |
2817 | * | |
2818 | * Create switch rule with given filter information and add an entry | |
2819 | * to the corresponding filter management list to track this switch rule | |
2820 | * and VSI mapping | |
2821 | */ | |
5e24d598 | 2822 | static int |
9daf8208 AV |
2823 | ice_create_pkt_fwd_rule(struct ice_hw *hw, |
2824 | struct ice_fltr_list_entry *f_entry) | |
2825 | { | |
9daf8208 | 2826 | struct ice_fltr_mgmt_list_entry *fm_entry; |
6e1ff618 | 2827 | struct ice_sw_rule_lkup_rx_tx *s_rule; |
9daf8208 | 2828 | enum ice_sw_lkup_type l_type; |
80d144c9 | 2829 | struct ice_sw_recipe *recp; |
5e24d598 | 2830 | int status; |
9daf8208 AV |
2831 | |
2832 | s_rule = devm_kzalloc(ice_hw_to_dev(hw), | |
6e1ff618 AL |
2833 | ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule), |
2834 | GFP_KERNEL); | |
9daf8208 | 2835 | if (!s_rule) |
d54699e2 | 2836 | return -ENOMEM; |
9daf8208 AV |
2837 | fm_entry = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*fm_entry), |
2838 | GFP_KERNEL); | |
2839 | if (!fm_entry) { | |
d54699e2 | 2840 | status = -ENOMEM; |
9daf8208 AV |
2841 | goto ice_create_pkt_fwd_rule_exit; |
2842 | } | |
2843 | ||
2844 | fm_entry->fltr_info = f_entry->fltr_info; | |
2845 | ||
2846 | /* Initialize all the fields for the management entry */ | |
2847 | fm_entry->vsi_count = 1; | |
2848 | fm_entry->lg_act_idx = ICE_INVAL_LG_ACT_INDEX; | |
2849 | fm_entry->sw_marker_id = ICE_INVAL_SW_MARKER_ID; | |
2850 | fm_entry->counter_index = ICE_INVAL_COUNTER_ID; | |
2851 | ||
2852 | ice_fill_sw_rule(hw, &fm_entry->fltr_info, s_rule, | |
2853 | ice_aqc_opc_add_sw_rules); | |
2854 | ||
6e1ff618 AL |
2855 | status = ice_aq_sw_rules(hw, s_rule, |
2856 | ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule), 1, | |
9daf8208 AV |
2857 | ice_aqc_opc_add_sw_rules, NULL); |
2858 | if (status) { | |
2859 | devm_kfree(ice_hw_to_dev(hw), fm_entry); | |
2860 | goto ice_create_pkt_fwd_rule_exit; | |
2861 | } | |
2862 | ||
6e1ff618 AL |
2863 | f_entry->fltr_info.fltr_rule_id = le16_to_cpu(s_rule->index); |
2864 | fm_entry->fltr_info.fltr_rule_id = le16_to_cpu(s_rule->index); | |
9daf8208 AV |
2865 | |
2866 | /* The book keeping entries will get removed when base driver | |
2867 | * calls remove filter AQ command | |
2868 | */ | |
2869 | l_type = fm_entry->fltr_info.lkup_type; | |
80d144c9 AV |
2870 | recp = &hw->switch_info->recp_list[l_type]; |
2871 | list_add(&fm_entry->list_entry, &recp->filt_rules); | |
2872 | ||
9daf8208 AV |
2873 | ice_create_pkt_fwd_rule_exit: |
2874 | devm_kfree(ice_hw_to_dev(hw), s_rule); | |
2875 | return status; | |
2876 | } | |
2877 | ||
2878 | /** | |
2879 | * ice_update_pkt_fwd_rule | |
2880 | * @hw: pointer to the hardware structure | |
80d144c9 | 2881 | * @f_info: filter information for switch rule |
9daf8208 AV |
2882 | * |
2883 | * Call AQ command to update a previously created switch rule with a | |
f9867df6 | 2884 | * VSI list ID |
9daf8208 | 2885 | */ |
5e24d598 | 2886 | static int |
80d144c9 | 2887 | ice_update_pkt_fwd_rule(struct ice_hw *hw, struct ice_fltr_info *f_info) |
9daf8208 | 2888 | { |
6e1ff618 | 2889 | struct ice_sw_rule_lkup_rx_tx *s_rule; |
5e24d598 | 2890 | int status; |
9daf8208 AV |
2891 | |
2892 | s_rule = devm_kzalloc(ice_hw_to_dev(hw), | |
6e1ff618 AL |
2893 | ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule), |
2894 | GFP_KERNEL); | |
9daf8208 | 2895 | if (!s_rule) |
d54699e2 | 2896 | return -ENOMEM; |
9daf8208 | 2897 | |
80d144c9 | 2898 | ice_fill_sw_rule(hw, f_info, s_rule, ice_aqc_opc_update_sw_rules); |
9daf8208 | 2899 | |
6e1ff618 | 2900 | s_rule->index = cpu_to_le16(f_info->fltr_rule_id); |
9daf8208 AV |
2901 | |
2902 | /* Update switch rule with new rule set to forward VSI list */ | |
6e1ff618 AL |
2903 | status = ice_aq_sw_rules(hw, s_rule, |
2904 | ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule), 1, | |
9daf8208 AV |
2905 | ice_aqc_opc_update_sw_rules, NULL); |
2906 | ||
2907 | devm_kfree(ice_hw_to_dev(hw), s_rule); | |
2908 | return status; | |
2909 | } | |
2910 | ||
b1edc14a MFIP |
2911 | /** |
2912 | * ice_update_sw_rule_bridge_mode | |
f9867df6 | 2913 | * @hw: pointer to the HW struct |
b1edc14a MFIP |
2914 | * |
2915 | * Updates unicast switch filter rules based on VEB/VEPA mode | |
2916 | */ | |
5e24d598 | 2917 | int ice_update_sw_rule_bridge_mode(struct ice_hw *hw) |
b1edc14a MFIP |
2918 | { |
2919 | struct ice_switch_info *sw = hw->switch_info; | |
2920 | struct ice_fltr_mgmt_list_entry *fm_entry; | |
b1edc14a MFIP |
2921 | struct list_head *rule_head; |
2922 | struct mutex *rule_lock; /* Lock to protect filter rule list */ | |
5518ac2a | 2923 | int status = 0; |
b1edc14a MFIP |
2924 | |
2925 | rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock; | |
2926 | rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules; | |
2927 | ||
2928 | mutex_lock(rule_lock); | |
2929 | list_for_each_entry(fm_entry, rule_head, list_entry) { | |
2930 | struct ice_fltr_info *fi = &fm_entry->fltr_info; | |
2931 | u8 *addr = fi->l_data.mac.mac_addr; | |
2932 | ||
2933 | /* Update unicast Tx rules to reflect the selected | |
2934 | * VEB/VEPA mode | |
2935 | */ | |
2936 | if ((fi->flag & ICE_FLTR_TX) && is_unicast_ether_addr(addr) && | |
2937 | (fi->fltr_act == ICE_FWD_TO_VSI || | |
2938 | fi->fltr_act == ICE_FWD_TO_VSI_LIST || | |
2939 | fi->fltr_act == ICE_FWD_TO_Q || | |
2940 | fi->fltr_act == ICE_FWD_TO_QGRP)) { | |
2941 | status = ice_update_pkt_fwd_rule(hw, fi); | |
2942 | if (status) | |
2943 | break; | |
2944 | } | |
2945 | } | |
2946 | ||
2947 | mutex_unlock(rule_lock); | |
2948 | ||
2949 | return status; | |
2950 | } | |
2951 | ||
9daf8208 | 2952 | /** |
80d144c9 | 2953 | * ice_add_update_vsi_list |
9daf8208 AV |
2954 | * @hw: pointer to the hardware structure |
2955 | * @m_entry: pointer to current filter management list entry | |
2956 | * @cur_fltr: filter information from the book keeping entry | |
2957 | * @new_fltr: filter information with the new VSI to be added | |
2958 | * | |
2959 | * Call AQ command to add or update previously created VSI list with new VSI. | |
2960 | * | |
2961 | * Helper function to do book keeping associated with adding filter information | |
d337f2af AV |
2962 | * The algorithm to do the book keeping is described below : |
2963 | * When a VSI needs to subscribe to a given filter (MAC/VLAN/Ethtype etc.) | |
9daf8208 AV |
2964 | * if only one VSI has been added till now |
2965 | * Allocate a new VSI list and add two VSIs | |
2966 | * to this list using switch rule command | |
2967 | * Update the previously created switch rule with the | |
f9867df6 | 2968 | * newly created VSI list ID |
9daf8208 AV |
2969 | * if a VSI list was previously created |
2970 | * Add the new VSI to the previously created VSI list set | |
2971 | * using the update switch rule command | |
2972 | */ | |
5e24d598 | 2973 | static int |
80d144c9 AV |
2974 | ice_add_update_vsi_list(struct ice_hw *hw, |
2975 | struct ice_fltr_mgmt_list_entry *m_entry, | |
2976 | struct ice_fltr_info *cur_fltr, | |
2977 | struct ice_fltr_info *new_fltr) | |
9daf8208 | 2978 | { |
9daf8208 | 2979 | u16 vsi_list_id = 0; |
5518ac2a | 2980 | int status = 0; |
9daf8208 AV |
2981 | |
2982 | if ((cur_fltr->fltr_act == ICE_FWD_TO_Q || | |
2983 | cur_fltr->fltr_act == ICE_FWD_TO_QGRP)) | |
d54699e2 | 2984 | return -EOPNOTSUPP; |
9daf8208 AV |
2985 | |
2986 | if ((new_fltr->fltr_act == ICE_FWD_TO_Q || | |
2987 | new_fltr->fltr_act == ICE_FWD_TO_QGRP) && | |
2988 | (cur_fltr->fltr_act == ICE_FWD_TO_VSI || | |
2989 | cur_fltr->fltr_act == ICE_FWD_TO_VSI_LIST)) | |
d54699e2 | 2990 | return -EOPNOTSUPP; |
9daf8208 AV |
2991 | |
2992 | if (m_entry->vsi_count < 2 && !m_entry->vsi_list_info) { | |
2993 | /* Only one entry existed in the mapping and it was not already | |
2994 | * a part of a VSI list. So, create a VSI list with the old and | |
2995 | * new VSIs. | |
2996 | */ | |
80d144c9 | 2997 | struct ice_fltr_info tmp_fltr; |
5726ca0e | 2998 | u16 vsi_handle_arr[2]; |
9daf8208 AV |
2999 | |
3000 | /* A rule already exists with the new VSI being added */ | |
5726ca0e | 3001 | if (cur_fltr->fwd_id.hw_vsi_id == new_fltr->fwd_id.hw_vsi_id) |
d54699e2 | 3002 | return -EEXIST; |
9daf8208 | 3003 | |
5726ca0e AV |
3004 | vsi_handle_arr[0] = cur_fltr->vsi_handle; |
3005 | vsi_handle_arr[1] = new_fltr->vsi_handle; | |
3006 | status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2, | |
9daf8208 AV |
3007 | &vsi_list_id, |
3008 | new_fltr->lkup_type); | |
3009 | if (status) | |
3010 | return status; | |
3011 | ||
80d144c9 AV |
3012 | tmp_fltr = *new_fltr; |
3013 | tmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id; | |
3014 | tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST; | |
3015 | tmp_fltr.fwd_id.vsi_list_id = vsi_list_id; | |
9daf8208 AV |
3016 | /* Update the previous switch rule of "MAC forward to VSI" to |
3017 | * "MAC fwd to VSI list" | |
3018 | */ | |
80d144c9 | 3019 | status = ice_update_pkt_fwd_rule(hw, &tmp_fltr); |
9daf8208 AV |
3020 | if (status) |
3021 | return status; | |
3022 | ||
3023 | cur_fltr->fwd_id.vsi_list_id = vsi_list_id; | |
3024 | cur_fltr->fltr_act = ICE_FWD_TO_VSI_LIST; | |
3025 | m_entry->vsi_list_info = | |
5726ca0e | 3026 | ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2, |
9daf8208 AV |
3027 | vsi_list_id); |
3028 | ||
7a91d3f0 | 3029 | if (!m_entry->vsi_list_info) |
d54699e2 | 3030 | return -ENOMEM; |
7a91d3f0 | 3031 | |
9daf8208 AV |
3032 | /* If this entry was large action then the large action needs |
3033 | * to be updated to point to FWD to VSI list | |
3034 | */ | |
3035 | if (m_entry->sw_marker_id != ICE_INVAL_SW_MARKER_ID) | |
3036 | status = | |
3037 | ice_add_marker_act(hw, m_entry, | |
3038 | m_entry->sw_marker_id, | |
3039 | m_entry->lg_act_idx); | |
3040 | } else { | |
5726ca0e | 3041 | u16 vsi_handle = new_fltr->vsi_handle; |
9daf8208 AV |
3042 | enum ice_adminq_opc opcode; |
3043 | ||
f25dad19 | 3044 | if (!m_entry->vsi_list_info) |
d54699e2 | 3045 | return -EIO; |
f25dad19 | 3046 | |
9daf8208 | 3047 | /* A rule already exists with the new VSI being added */ |
5726ca0e | 3048 | if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map)) |
9daf8208 AV |
3049 | return 0; |
3050 | ||
3051 | /* Update the previously created VSI list set with | |
f9867df6 | 3052 | * the new VSI ID passed in |
9daf8208 AV |
3053 | */ |
3054 | vsi_list_id = cur_fltr->fwd_id.vsi_list_id; | |
3055 | opcode = ice_aqc_opc_update_sw_rules; | |
3056 | ||
5726ca0e AV |
3057 | status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, |
3058 | vsi_list_id, false, opcode, | |
9daf8208 | 3059 | new_fltr->lkup_type); |
f9867df6 | 3060 | /* update VSI list mapping info with new VSI ID */ |
9daf8208 | 3061 | if (!status) |
5726ca0e | 3062 | set_bit(vsi_handle, m_entry->vsi_list_info->vsi_map); |
9daf8208 AV |
3063 | } |
3064 | if (!status) | |
3065 | m_entry->vsi_count++; | |
3066 | return status; | |
3067 | } | |
3068 | ||
3069 | /** | |
80d144c9 | 3070 | * ice_find_rule_entry - Search a rule entry |
9daf8208 | 3071 | * @hw: pointer to the hardware structure |
80d144c9 AV |
3072 | * @recp_id: lookup type for which the specified rule needs to be searched |
3073 | * @f_info: rule information | |
9daf8208 | 3074 | * |
80d144c9 AV |
3075 | * Helper function to search for a given rule entry |
3076 | * Returns pointer to entry storing the rule if found | |
9daf8208 AV |
3077 | */ |
3078 | static struct ice_fltr_mgmt_list_entry * | |
80d144c9 | 3079 | ice_find_rule_entry(struct ice_hw *hw, u8 recp_id, struct ice_fltr_info *f_info) |
9daf8208 | 3080 | { |
80d144c9 | 3081 | struct ice_fltr_mgmt_list_entry *list_itr, *ret = NULL; |
9daf8208 | 3082 | struct ice_switch_info *sw = hw->switch_info; |
80d144c9 AV |
3083 | struct list_head *list_head; |
3084 | ||
3085 | list_head = &sw->recp_list[recp_id].filt_rules; | |
3086 | list_for_each_entry(list_itr, list_head, list_entry) { | |
3087 | if (!memcmp(&f_info->l_data, &list_itr->fltr_info.l_data, | |
3088 | sizeof(f_info->l_data)) && | |
3089 | f_info->flag == list_itr->fltr_info.flag) { | |
3090 | ret = list_itr; | |
9daf8208 AV |
3091 | break; |
3092 | } | |
3093 | } | |
80d144c9 | 3094 | return ret; |
9daf8208 AV |
3095 | } |
3096 | ||
5726ca0e AV |
3097 | /** |
3098 | * ice_find_vsi_list_entry - Search VSI list map with VSI count 1 | |
3099 | * @hw: pointer to the hardware structure | |
3100 | * @recp_id: lookup type for which VSI lists needs to be searched | |
3101 | * @vsi_handle: VSI handle to be found in VSI list | |
f9867df6 | 3102 | * @vsi_list_id: VSI list ID found containing vsi_handle |
5726ca0e AV |
3103 | * |
3104 | * Helper function to search a VSI list with single entry containing given VSI | |
3105 | * handle element. This can be extended further to search VSI list with more | |
3106 | * than 1 vsi_count. Returns pointer to VSI list entry if found. | |
3107 | */ | |
3108 | static struct ice_vsi_list_map_info * | |
3109 | ice_find_vsi_list_entry(struct ice_hw *hw, u8 recp_id, u16 vsi_handle, | |
3110 | u16 *vsi_list_id) | |
3111 | { | |
3112 | struct ice_vsi_list_map_info *map_info = NULL; | |
3113 | struct ice_switch_info *sw = hw->switch_info; | |
3114 | struct ice_fltr_mgmt_list_entry *list_itr; | |
3115 | struct list_head *list_head; | |
3116 | ||
3117 | list_head = &sw->recp_list[recp_id].filt_rules; | |
3118 | list_for_each_entry(list_itr, list_head, list_entry) { | |
3119 | if (list_itr->vsi_count == 1 && list_itr->vsi_list_info) { | |
3120 | map_info = list_itr->vsi_list_info; | |
3121 | if (test_bit(vsi_handle, map_info->vsi_map)) { | |
3122 | *vsi_list_id = map_info->vsi_list_id; | |
3123 | return map_info; | |
3124 | } | |
3125 | } | |
3126 | } | |
3127 | return NULL; | |
3128 | } | |
3129 | ||
9daf8208 | 3130 | /** |
80d144c9 | 3131 | * ice_add_rule_internal - add rule for a given lookup type |
9daf8208 | 3132 | * @hw: pointer to the hardware structure |
f9867df6 | 3133 | * @recp_id: lookup type (recipe ID) for which rule has to be added |
9daf8208 AV |
3134 | * @f_entry: structure containing MAC forwarding information |
3135 | * | |
80d144c9 | 3136 | * Adds or updates the rule lists for a given recipe |
9daf8208 | 3137 | */ |
5e24d598 | 3138 | static int |
80d144c9 AV |
3139 | ice_add_rule_internal(struct ice_hw *hw, u8 recp_id, |
3140 | struct ice_fltr_list_entry *f_entry) | |
9daf8208 | 3141 | { |
80d144c9 | 3142 | struct ice_switch_info *sw = hw->switch_info; |
9daf8208 AV |
3143 | struct ice_fltr_info *new_fltr, *cur_fltr; |
3144 | struct ice_fltr_mgmt_list_entry *m_entry; | |
80d144c9 | 3145 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
5e24d598 | 3146 | int status = 0; |
9daf8208 | 3147 | |
5726ca0e | 3148 | if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle)) |
d54699e2 | 3149 | return -EINVAL; |
5726ca0e AV |
3150 | f_entry->fltr_info.fwd_id.hw_vsi_id = |
3151 | ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle); | |
3152 | ||
80d144c9 | 3153 | rule_lock = &sw->recp_list[recp_id].filt_rule_lock; |
9daf8208 | 3154 | |
80d144c9 AV |
3155 | mutex_lock(rule_lock); |
3156 | new_fltr = &f_entry->fltr_info; | |
3157 | if (new_fltr->flag & ICE_FLTR_RX) | |
3158 | new_fltr->src = hw->port_info->lport; | |
3159 | else if (new_fltr->flag & ICE_FLTR_TX) | |
5726ca0e | 3160 | new_fltr->src = f_entry->fltr_info.fwd_id.hw_vsi_id; |
80d144c9 AV |
3161 | |
3162 | m_entry = ice_find_rule_entry(hw, recp_id, new_fltr); | |
3163 | if (!m_entry) { | |
3164 | mutex_unlock(rule_lock); | |
9daf8208 | 3165 | return ice_create_pkt_fwd_rule(hw, f_entry); |
80d144c9 | 3166 | } |
9daf8208 AV |
3167 | |
3168 | cur_fltr = &m_entry->fltr_info; | |
80d144c9 AV |
3169 | status = ice_add_update_vsi_list(hw, m_entry, cur_fltr, new_fltr); |
3170 | mutex_unlock(rule_lock); | |
3171 | ||
3172 | return status; | |
3173 | } | |
3174 | ||
3175 | /** | |
3176 | * ice_remove_vsi_list_rule | |
3177 | * @hw: pointer to the hardware structure | |
f9867df6 | 3178 | * @vsi_list_id: VSI list ID generated as part of allocate resource |
80d144c9 AV |
3179 | * @lkup_type: switch rule filter lookup type |
3180 | * | |
3181 | * The VSI list should be emptied before this function is called to remove the | |
3182 | * VSI list. | |
3183 | */ | |
5e24d598 | 3184 | static int |
80d144c9 AV |
3185 | ice_remove_vsi_list_rule(struct ice_hw *hw, u16 vsi_list_id, |
3186 | enum ice_sw_lkup_type lkup_type) | |
3187 | { | |
6e1ff618 | 3188 | struct ice_sw_rule_vsi_list *s_rule; |
80d144c9 | 3189 | u16 s_rule_size; |
5518ac2a | 3190 | int status; |
80d144c9 | 3191 | |
6e1ff618 | 3192 | s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(s_rule, 0); |
80d144c9 AV |
3193 | s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL); |
3194 | if (!s_rule) | |
d54699e2 | 3195 | return -ENOMEM; |
80d144c9 | 3196 | |
6e1ff618 AL |
3197 | s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR); |
3198 | s_rule->index = cpu_to_le16(vsi_list_id); | |
80d144c9 AV |
3199 | |
3200 | /* Free the vsi_list resource that we allocated. It is assumed that the | |
3201 | * list is empty at this point. | |
3202 | */ | |
3203 | status = ice_aq_alloc_free_vsi_list(hw, &vsi_list_id, lkup_type, | |
3204 | ice_aqc_opc_free_res); | |
9daf8208 | 3205 | |
80d144c9 AV |
3206 | devm_kfree(ice_hw_to_dev(hw), s_rule); |
3207 | return status; | |
3208 | } | |
3209 | ||
3210 | /** | |
3211 | * ice_rem_update_vsi_list | |
3212 | * @hw: pointer to the hardware structure | |
5726ca0e | 3213 | * @vsi_handle: VSI handle of the VSI to remove |
80d144c9 AV |
3214 | * @fm_list: filter management entry for which the VSI list management needs to |
3215 | * be done | |
3216 | */ | |
5e24d598 | 3217 | static int |
5726ca0e | 3218 | ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle, |
80d144c9 AV |
3219 | struct ice_fltr_mgmt_list_entry *fm_list) |
3220 | { | |
3221 | enum ice_sw_lkup_type lkup_type; | |
80d144c9 | 3222 | u16 vsi_list_id; |
5518ac2a | 3223 | int status = 0; |
80d144c9 AV |
3224 | |
3225 | if (fm_list->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST || | |
3226 | fm_list->vsi_count == 0) | |
d54699e2 | 3227 | return -EINVAL; |
80d144c9 AV |
3228 | |
3229 | /* A rule with the VSI being removed does not exist */ | |
5726ca0e | 3230 | if (!test_bit(vsi_handle, fm_list->vsi_list_info->vsi_map)) |
d54699e2 | 3231 | return -ENOENT; |
80d144c9 AV |
3232 | |
3233 | lkup_type = fm_list->fltr_info.lkup_type; | |
3234 | vsi_list_id = fm_list->fltr_info.fwd_id.vsi_list_id; | |
5726ca0e | 3235 | status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, vsi_list_id, true, |
80d144c9 AV |
3236 | ice_aqc_opc_update_sw_rules, |
3237 | lkup_type); | |
3238 | if (status) | |
3239 | return status; | |
3240 | ||
3241 | fm_list->vsi_count--; | |
5726ca0e | 3242 | clear_bit(vsi_handle, fm_list->vsi_list_info->vsi_map); |
80d144c9 | 3243 | |
c60cdb13 BC |
3244 | if (fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) { |
3245 | struct ice_fltr_info tmp_fltr_info = fm_list->fltr_info; | |
80d144c9 AV |
3246 | struct ice_vsi_list_map_info *vsi_list_info = |
3247 | fm_list->vsi_list_info; | |
5726ca0e | 3248 | u16 rem_vsi_handle; |
80d144c9 | 3249 | |
5726ca0e AV |
3250 | rem_vsi_handle = find_first_bit(vsi_list_info->vsi_map, |
3251 | ICE_MAX_VSI); | |
3252 | if (!ice_is_vsi_valid(hw, rem_vsi_handle)) | |
d54699e2 | 3253 | return -EIO; |
c60cdb13 BC |
3254 | |
3255 | /* Make sure VSI list is empty before removing it below */ | |
5726ca0e | 3256 | status = ice_update_vsi_list_rule(hw, &rem_vsi_handle, 1, |
80d144c9 AV |
3257 | vsi_list_id, true, |
3258 | ice_aqc_opc_update_sw_rules, | |
3259 | lkup_type); | |
3260 | if (status) | |
3261 | return status; | |
3262 | ||
c60cdb13 BC |
3263 | tmp_fltr_info.fltr_act = ICE_FWD_TO_VSI; |
3264 | tmp_fltr_info.fwd_id.hw_vsi_id = | |
3265 | ice_get_hw_vsi_num(hw, rem_vsi_handle); | |
3266 | tmp_fltr_info.vsi_handle = rem_vsi_handle; | |
3267 | status = ice_update_pkt_fwd_rule(hw, &tmp_fltr_info); | |
3268 | if (status) { | |
9228d8b2 | 3269 | ice_debug(hw, ICE_DBG_SW, "Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\n", |
c60cdb13 BC |
3270 | tmp_fltr_info.fwd_id.hw_vsi_id, status); |
3271 | return status; | |
3272 | } | |
3273 | ||
3274 | fm_list->fltr_info = tmp_fltr_info; | |
3275 | } | |
3276 | ||
3277 | if ((fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) || | |
3278 | (fm_list->vsi_count == 0 && lkup_type == ICE_SW_LKUP_VLAN)) { | |
3279 | struct ice_vsi_list_map_info *vsi_list_info = | |
3280 | fm_list->vsi_list_info; | |
3281 | ||
80d144c9 AV |
3282 | /* Remove the VSI list since it is no longer used */ |
3283 | status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type); | |
c60cdb13 | 3284 | if (status) { |
9228d8b2 | 3285 | ice_debug(hw, ICE_DBG_SW, "Failed to remove VSI list %d, error %d\n", |
c60cdb13 | 3286 | vsi_list_id, status); |
80d144c9 | 3287 | return status; |
c60cdb13 | 3288 | } |
80d144c9 AV |
3289 | |
3290 | list_del(&vsi_list_info->list_entry); | |
3291 | devm_kfree(ice_hw_to_dev(hw), vsi_list_info); | |
3292 | fm_list->vsi_list_info = NULL; | |
3293 | } | |
3294 | ||
3295 | return status; | |
3296 | } | |
3297 | ||
3298 | /** | |
3299 | * ice_remove_rule_internal - Remove a filter rule of a given type | |
3300 | * @hw: pointer to the hardware structure | |
f9867df6 | 3301 | * @recp_id: recipe ID for which the rule needs to removed |
80d144c9 AV |
3302 | * @f_entry: rule entry containing filter information |
3303 | */ | |
5e24d598 | 3304 | static int |
80d144c9 AV |
3305 | ice_remove_rule_internal(struct ice_hw *hw, u8 recp_id, |
3306 | struct ice_fltr_list_entry *f_entry) | |
3307 | { | |
3308 | struct ice_switch_info *sw = hw->switch_info; | |
3309 | struct ice_fltr_mgmt_list_entry *list_elem; | |
3310 | struct mutex *rule_lock; /* Lock to protect filter rule list */ | |
80d144c9 | 3311 | bool remove_rule = false; |
5726ca0e | 3312 | u16 vsi_handle; |
5518ac2a | 3313 | int status = 0; |
5726ca0e AV |
3314 | |
3315 | if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle)) | |
d54699e2 | 3316 | return -EINVAL; |
5726ca0e AV |
3317 | f_entry->fltr_info.fwd_id.hw_vsi_id = |
3318 | ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle); | |
80d144c9 AV |
3319 | |
3320 | rule_lock = &sw->recp_list[recp_id].filt_rule_lock; | |
3321 | mutex_lock(rule_lock); | |
3322 | list_elem = ice_find_rule_entry(hw, recp_id, &f_entry->fltr_info); | |
3323 | if (!list_elem) { | |
d54699e2 | 3324 | status = -ENOENT; |
80d144c9 AV |
3325 | goto exit; |
3326 | } | |
3327 | ||
3328 | if (list_elem->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST) { | |
3329 | remove_rule = true; | |
5726ca0e | 3330 | } else if (!list_elem->vsi_list_info) { |
d54699e2 | 3331 | status = -ENOENT; |
5726ca0e | 3332 | goto exit; |
f9264dd6 JK |
3333 | } else if (list_elem->vsi_list_info->ref_cnt > 1) { |
3334 | /* a ref_cnt > 1 indicates that the vsi_list is being | |
3335 | * shared by multiple rules. Decrement the ref_cnt and | |
3336 | * remove this rule, but do not modify the list, as it | |
3337 | * is in-use by other rules. | |
3338 | */ | |
3339 | list_elem->vsi_list_info->ref_cnt--; | |
3340 | remove_rule = true; | |
80d144c9 | 3341 | } else { |
f9264dd6 JK |
3342 | /* a ref_cnt of 1 indicates the vsi_list is only used |
3343 | * by one rule. However, the original removal request is only | |
3344 | * for a single VSI. Update the vsi_list first, and only | |
3345 | * remove the rule if there are no further VSIs in this list. | |
3346 | */ | |
5726ca0e AV |
3347 | vsi_handle = f_entry->fltr_info.vsi_handle; |
3348 | status = ice_rem_update_vsi_list(hw, vsi_handle, list_elem); | |
80d144c9 AV |
3349 | if (status) |
3350 | goto exit; | |
f9867df6 | 3351 | /* if VSI count goes to zero after updating the VSI list */ |
80d144c9 AV |
3352 | if (list_elem->vsi_count == 0) |
3353 | remove_rule = true; | |
3354 | } | |
3355 | ||
3356 | if (remove_rule) { | |
3357 | /* Remove the lookup rule */ | |
6e1ff618 | 3358 | struct ice_sw_rule_lkup_rx_tx *s_rule; |
80d144c9 AV |
3359 | |
3360 | s_rule = devm_kzalloc(ice_hw_to_dev(hw), | |
6e1ff618 | 3361 | ICE_SW_RULE_RX_TX_NO_HDR_SIZE(s_rule), |
80d144c9 AV |
3362 | GFP_KERNEL); |
3363 | if (!s_rule) { | |
d54699e2 | 3364 | status = -ENOMEM; |
80d144c9 AV |
3365 | goto exit; |
3366 | } | |
3367 | ||
3368 | ice_fill_sw_rule(hw, &list_elem->fltr_info, s_rule, | |
3369 | ice_aqc_opc_remove_sw_rules); | |
3370 | ||
3371 | status = ice_aq_sw_rules(hw, s_rule, | |
6e1ff618 AL |
3372 | ICE_SW_RULE_RX_TX_NO_HDR_SIZE(s_rule), |
3373 | 1, ice_aqc_opc_remove_sw_rules, NULL); | |
80d144c9 AV |
3374 | |
3375 | /* Remove a book keeping from the list */ | |
3376 | devm_kfree(ice_hw_to_dev(hw), s_rule); | |
3377 | ||
8132e17d JC |
3378 | if (status) |
3379 | goto exit; | |
3380 | ||
80d144c9 AV |
3381 | list_del(&list_elem->list_entry); |
3382 | devm_kfree(ice_hw_to_dev(hw), list_elem); | |
3383 | } | |
3384 | exit: | |
3385 | mutex_unlock(rule_lock); | |
3386 | return status; | |
9daf8208 AV |
3387 | } |
3388 | ||
9fea7498 KP |
3389 | /** |
3390 | * ice_mac_fltr_exist - does this MAC filter exist for given VSI | |
3391 | * @hw: pointer to the hardware structure | |
3392 | * @mac: MAC address to be checked (for MAC filter) | |
3393 | * @vsi_handle: check MAC filter for this VSI | |
3394 | */ | |
3395 | bool ice_mac_fltr_exist(struct ice_hw *hw, u8 *mac, u16 vsi_handle) | |
3396 | { | |
3397 | struct ice_fltr_mgmt_list_entry *entry; | |
3398 | struct list_head *rule_head; | |
3399 | struct ice_switch_info *sw; | |
3400 | struct mutex *rule_lock; /* Lock to protect filter rule list */ | |
3401 | u16 hw_vsi_id; | |
3402 | ||
3403 | if (!ice_is_vsi_valid(hw, vsi_handle)) | |
3404 | return false; | |
3405 | ||
3406 | hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); | |
3407 | sw = hw->switch_info; | |
3408 | rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules; | |
3409 | if (!rule_head) | |
3410 | return false; | |
3411 | ||
3412 | rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock; | |
3413 | mutex_lock(rule_lock); | |
3414 | list_for_each_entry(entry, rule_head, list_entry) { | |
3415 | struct ice_fltr_info *f_info = &entry->fltr_info; | |
3416 | u8 *mac_addr = &f_info->l_data.mac.mac_addr[0]; | |
3417 | ||
3418 | if (is_zero_ether_addr(mac_addr)) | |
3419 | continue; | |
3420 | ||
3421 | if (f_info->flag != ICE_FLTR_TX || | |
3422 | f_info->src_id != ICE_SRC_ID_VSI || | |
3423 | f_info->lkup_type != ICE_SW_LKUP_MAC || | |
3424 | f_info->fltr_act != ICE_FWD_TO_VSI || | |
3425 | hw_vsi_id != f_info->fwd_id.hw_vsi_id) | |
3426 | continue; | |
3427 | ||
3428 | if (ether_addr_equal(mac, mac_addr)) { | |
3429 | mutex_unlock(rule_lock); | |
3430 | return true; | |
3431 | } | |
3432 | } | |
3433 | mutex_unlock(rule_lock); | |
3434 | return false; | |
3435 | } | |
3436 | ||
3437 | /** | |
3438 | * ice_vlan_fltr_exist - does this VLAN filter exist for given VSI | |
3439 | * @hw: pointer to the hardware structure | |
3440 | * @vlan_id: VLAN ID | |
3441 | * @vsi_handle: check MAC filter for this VSI | |
3442 | */ | |
3443 | bool ice_vlan_fltr_exist(struct ice_hw *hw, u16 vlan_id, u16 vsi_handle) | |
3444 | { | |
3445 | struct ice_fltr_mgmt_list_entry *entry; | |
3446 | struct list_head *rule_head; | |
3447 | struct ice_switch_info *sw; | |
3448 | struct mutex *rule_lock; /* Lock to protect filter rule list */ | |
3449 | u16 hw_vsi_id; | |
3450 | ||
3451 | if (vlan_id > ICE_MAX_VLAN_ID) | |
3452 | return false; | |
3453 | ||
3454 | if (!ice_is_vsi_valid(hw, vsi_handle)) | |
3455 | return false; | |
3456 | ||
3457 | hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); | |
3458 | sw = hw->switch_info; | |
3459 | rule_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules; | |
3460 | if (!rule_head) | |
3461 | return false; | |
3462 | ||
3463 | rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock; | |
3464 | mutex_lock(rule_lock); | |
3465 | list_for_each_entry(entry, rule_head, list_entry) { | |
3466 | struct ice_fltr_info *f_info = &entry->fltr_info; | |
3467 | u16 entry_vlan_id = f_info->l_data.vlan.vlan_id; | |
3468 | struct ice_vsi_list_map_info *map_info; | |
3469 | ||
3470 | if (entry_vlan_id > ICE_MAX_VLAN_ID) | |
3471 | continue; | |
3472 | ||
3473 | if (f_info->flag != ICE_FLTR_TX || | |
3474 | f_info->src_id != ICE_SRC_ID_VSI || | |
3475 | f_info->lkup_type != ICE_SW_LKUP_VLAN) | |
3476 | continue; | |
3477 | ||
3478 | /* Only allowed filter action are FWD_TO_VSI/_VSI_LIST */ | |
3479 | if (f_info->fltr_act != ICE_FWD_TO_VSI && | |
3480 | f_info->fltr_act != ICE_FWD_TO_VSI_LIST) | |
3481 | continue; | |
3482 | ||
3483 | if (f_info->fltr_act == ICE_FWD_TO_VSI) { | |
3484 | if (hw_vsi_id != f_info->fwd_id.hw_vsi_id) | |
3485 | continue; | |
3486 | } else if (f_info->fltr_act == ICE_FWD_TO_VSI_LIST) { | |
3487 | /* If filter_action is FWD_TO_VSI_LIST, make sure | |
3488 | * that VSI being checked is part of VSI list | |
3489 | */ | |
3490 | if (entry->vsi_count == 1 && | |
3491 | entry->vsi_list_info) { | |
3492 | map_info = entry->vsi_list_info; | |
3493 | if (!test_bit(vsi_handle, map_info->vsi_map)) | |
3494 | continue; | |
3495 | } | |
3496 | } | |
3497 | ||
3498 | if (vlan_id == entry_vlan_id) { | |
3499 | mutex_unlock(rule_lock); | |
3500 | return true; | |
3501 | } | |
3502 | } | |
3503 | mutex_unlock(rule_lock); | |
3504 | ||
3505 | return false; | |
3506 | } | |
3507 | ||
9daf8208 AV |
3508 | /** |
3509 | * ice_add_mac - Add a MAC address based filter rule | |
3510 | * @hw: pointer to the hardware structure | |
3511 | * @m_list: list of MAC addresses and forwarding information | |
9daf8208 | 3512 | */ |
5e24d598 | 3513 | int ice_add_mac(struct ice_hw *hw, struct list_head *m_list) |
9daf8208 | 3514 | { |
9daf8208 | 3515 | struct ice_fltr_list_entry *m_list_itr; |
5518ac2a | 3516 | int status = 0; |
9daf8208 AV |
3517 | |
3518 | if (!m_list || !hw) | |
d54699e2 | 3519 | return -EINVAL; |
9daf8208 AV |
3520 | |
3521 | list_for_each_entry(m_list_itr, m_list, list_entry) { | |
3522 | u8 *add = &m_list_itr->fltr_info.l_data.mac.mac_addr[0]; | |
5726ca0e AV |
3523 | u16 vsi_handle; |
3524 | u16 hw_vsi_id; | |
9daf8208 | 3525 | |
80d144c9 | 3526 | m_list_itr->fltr_info.flag = ICE_FLTR_TX; |
5726ca0e AV |
3527 | vsi_handle = m_list_itr->fltr_info.vsi_handle; |
3528 | if (!ice_is_vsi_valid(hw, vsi_handle)) | |
d54699e2 | 3529 | return -EINVAL; |
5726ca0e AV |
3530 | hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); |
3531 | m_list_itr->fltr_info.fwd_id.hw_vsi_id = hw_vsi_id; | |
f9867df6 | 3532 | /* update the src in case it is VSI num */ |
5726ca0e | 3533 | if (m_list_itr->fltr_info.src_id != ICE_SRC_ID_VSI) |
d54699e2 | 3534 | return -EINVAL; |
5726ca0e | 3535 | m_list_itr->fltr_info.src = hw_vsi_id; |
80d144c9 AV |
3536 | if (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC || |
3537 | is_zero_ether_addr(add)) | |
d54699e2 | 3538 | return -EINVAL; |
9daf8208 | 3539 | |
e1e9db57 SD |
3540 | m_list_itr->status = ice_add_rule_internal(hw, ICE_SW_LKUP_MAC, |
3541 | m_list_itr); | |
3542 | if (m_list_itr->status) | |
3543 | return m_list_itr->status; | |
9daf8208 AV |
3544 | } |
3545 | ||
9daf8208 AV |
3546 | return status; |
3547 | } | |
3548 | ||
d76a60ba AV |
3549 | /** |
3550 | * ice_add_vlan_internal - Add one VLAN based filter rule | |
3551 | * @hw: pointer to the hardware structure | |
3552 | * @f_entry: filter entry containing one VLAN information | |
3553 | */ | |
5e24d598 | 3554 | static int |
d76a60ba AV |
3555 | ice_add_vlan_internal(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry) |
3556 | { | |
80d144c9 | 3557 | struct ice_switch_info *sw = hw->switch_info; |
d76a60ba | 3558 | struct ice_fltr_mgmt_list_entry *v_list_itr; |
5726ca0e AV |
3559 | struct ice_fltr_info *new_fltr, *cur_fltr; |
3560 | enum ice_sw_lkup_type lkup_type; | |
3561 | u16 vsi_list_id = 0, vsi_handle; | |
80d144c9 | 3562 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
5e24d598 | 3563 | int status = 0; |
d76a60ba | 3564 | |
5726ca0e | 3565 | if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle)) |
d54699e2 | 3566 | return -EINVAL; |
5726ca0e AV |
3567 | |
3568 | f_entry->fltr_info.fwd_id.hw_vsi_id = | |
3569 | ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle); | |
d76a60ba | 3570 | new_fltr = &f_entry->fltr_info; |
5726ca0e | 3571 | |
f9867df6 | 3572 | /* VLAN ID should only be 12 bits */ |
d76a60ba | 3573 | if (new_fltr->l_data.vlan.vlan_id > ICE_MAX_VLAN_ID) |
d54699e2 | 3574 | return -EINVAL; |
d76a60ba | 3575 | |
5726ca0e | 3576 | if (new_fltr->src_id != ICE_SRC_ID_VSI) |
d54699e2 | 3577 | return -EINVAL; |
5726ca0e AV |
3578 | |
3579 | new_fltr->src = new_fltr->fwd_id.hw_vsi_id; | |
3580 | lkup_type = new_fltr->lkup_type; | |
3581 | vsi_handle = new_fltr->vsi_handle; | |
80d144c9 AV |
3582 | rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock; |
3583 | mutex_lock(rule_lock); | |
3584 | v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN, new_fltr); | |
d76a60ba | 3585 | if (!v_list_itr) { |
5726ca0e | 3586 | struct ice_vsi_list_map_info *map_info = NULL; |
d76a60ba AV |
3587 | |
3588 | if (new_fltr->fltr_act == ICE_FWD_TO_VSI) { | |
5726ca0e AV |
3589 | /* All VLAN pruning rules use a VSI list. Check if |
3590 | * there is already a VSI list containing VSI that we | |
3591 | * want to add. If found, use the same vsi_list_id for | |
3592 | * this new VLAN rule or else create a new list. | |
d76a60ba | 3593 | */ |
5726ca0e AV |
3594 | map_info = ice_find_vsi_list_entry(hw, ICE_SW_LKUP_VLAN, |
3595 | vsi_handle, | |
3596 | &vsi_list_id); | |
3597 | if (!map_info) { | |
3598 | status = ice_create_vsi_list_rule(hw, | |
3599 | &vsi_handle, | |
3600 | 1, | |
3601 | &vsi_list_id, | |
3602 | lkup_type); | |
3603 | if (status) | |
3604 | goto exit; | |
3605 | } | |
3606 | /* Convert the action to forwarding to a VSI list. */ | |
d76a60ba AV |
3607 | new_fltr->fltr_act = ICE_FWD_TO_VSI_LIST; |
3608 | new_fltr->fwd_id.vsi_list_id = vsi_list_id; | |
3609 | } | |
3610 | ||
3611 | status = ice_create_pkt_fwd_rule(hw, f_entry); | |
5726ca0e | 3612 | if (!status) { |
80d144c9 AV |
3613 | v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN, |
3614 | new_fltr); | |
3615 | if (!v_list_itr) { | |
d54699e2 | 3616 | status = -ENOENT; |
80d144c9 AV |
3617 | goto exit; |
3618 | } | |
5726ca0e AV |
3619 | /* reuse VSI list for new rule and increment ref_cnt */ |
3620 | if (map_info) { | |
3621 | v_list_itr->vsi_list_info = map_info; | |
3622 | map_info->ref_cnt++; | |
3623 | } else { | |
3624 | v_list_itr->vsi_list_info = | |
3625 | ice_create_vsi_list_map(hw, &vsi_handle, | |
3626 | 1, vsi_list_id); | |
3627 | } | |
d76a60ba | 3628 | } |
5726ca0e | 3629 | } else if (v_list_itr->vsi_list_info->ref_cnt == 1) { |
f9867df6 | 3630 | /* Update existing VSI list to add new VSI ID only if it used |
5726ca0e AV |
3631 | * by one VLAN rule. |
3632 | */ | |
3633 | cur_fltr = &v_list_itr->fltr_info; | |
3634 | status = ice_add_update_vsi_list(hw, v_list_itr, cur_fltr, | |
3635 | new_fltr); | |
3636 | } else { | |
3637 | /* If VLAN rule exists and VSI list being used by this rule is | |
3638 | * referenced by more than 1 VLAN rule. Then create a new VSI | |
3639 | * list appending previous VSI with new VSI and update existing | |
f9867df6 | 3640 | * VLAN rule to point to new VSI list ID |
5726ca0e AV |
3641 | */ |
3642 | struct ice_fltr_info tmp_fltr; | |
3643 | u16 vsi_handle_arr[2]; | |
3644 | u16 cur_handle; | |
d76a60ba | 3645 | |
5726ca0e AV |
3646 | /* Current implementation only supports reusing VSI list with |
3647 | * one VSI count. We should never hit below condition | |
3648 | */ | |
3649 | if (v_list_itr->vsi_count > 1 && | |
3650 | v_list_itr->vsi_list_info->ref_cnt > 1) { | |
9228d8b2 | 3651 | ice_debug(hw, ICE_DBG_SW, "Invalid configuration: Optimization to reuse VSI list with more than one VSI is not being done yet\n"); |
d54699e2 | 3652 | status = -EIO; |
5726ca0e AV |
3653 | goto exit; |
3654 | } | |
d76a60ba | 3655 | |
5726ca0e AV |
3656 | cur_handle = |
3657 | find_first_bit(v_list_itr->vsi_list_info->vsi_map, | |
3658 | ICE_MAX_VSI); | |
3659 | ||
3660 | /* A rule already exists with the new VSI being added */ | |
3661 | if (cur_handle == vsi_handle) { | |
d54699e2 | 3662 | status = -EEXIST; |
5726ca0e AV |
3663 | goto exit; |
3664 | } | |
3665 | ||
3666 | vsi_handle_arr[0] = cur_handle; | |
3667 | vsi_handle_arr[1] = vsi_handle; | |
3668 | status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2, | |
3669 | &vsi_list_id, lkup_type); | |
3670 | if (status) | |
3671 | goto exit; | |
3672 | ||
3673 | tmp_fltr = v_list_itr->fltr_info; | |
3674 | tmp_fltr.fltr_rule_id = v_list_itr->fltr_info.fltr_rule_id; | |
3675 | tmp_fltr.fwd_id.vsi_list_id = vsi_list_id; | |
3676 | tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST; | |
3677 | /* Update the previous switch rule to a new VSI list which | |
df17b7e0 | 3678 | * includes current VSI that is requested |
5726ca0e AV |
3679 | */ |
3680 | status = ice_update_pkt_fwd_rule(hw, &tmp_fltr); | |
3681 | if (status) | |
3682 | goto exit; | |
3683 | ||
3684 | /* before overriding VSI list map info. decrement ref_cnt of | |
3685 | * previous VSI list | |
3686 | */ | |
3687 | v_list_itr->vsi_list_info->ref_cnt--; | |
3688 | ||
3689 | /* now update to newly created list */ | |
3690 | v_list_itr->fltr_info.fwd_id.vsi_list_id = vsi_list_id; | |
3691 | v_list_itr->vsi_list_info = | |
3692 | ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2, | |
3693 | vsi_list_id); | |
3694 | v_list_itr->vsi_count++; | |
3695 | } | |
80d144c9 AV |
3696 | |
3697 | exit: | |
3698 | mutex_unlock(rule_lock); | |
3699 | return status; | |
d76a60ba AV |
3700 | } |
3701 | ||
3702 | /** | |
3703 | * ice_add_vlan - Add VLAN based filter rule | |
3704 | * @hw: pointer to the hardware structure | |
3705 | * @v_list: list of VLAN entries and forwarding information | |
3706 | */ | |
5e24d598 | 3707 | int ice_add_vlan(struct ice_hw *hw, struct list_head *v_list) |
d76a60ba AV |
3708 | { |
3709 | struct ice_fltr_list_entry *v_list_itr; | |
3710 | ||
3711 | if (!v_list || !hw) | |
d54699e2 | 3712 | return -EINVAL; |
d76a60ba AV |
3713 | |
3714 | list_for_each_entry(v_list_itr, v_list, list_entry) { | |
d76a60ba | 3715 | if (v_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_VLAN) |
d54699e2 | 3716 | return -EINVAL; |
80d144c9 AV |
3717 | v_list_itr->fltr_info.flag = ICE_FLTR_TX; |
3718 | v_list_itr->status = ice_add_vlan_internal(hw, v_list_itr); | |
3719 | if (v_list_itr->status) | |
3720 | return v_list_itr->status; | |
d76a60ba AV |
3721 | } |
3722 | return 0; | |
3723 | } | |
3724 | ||
d95276ce AA |
3725 | /** |
3726 | * ice_add_eth_mac - Add ethertype and MAC based filter rule | |
3727 | * @hw: pointer to the hardware structure | |
3728 | * @em_list: list of ether type MAC filter, MAC is optional | |
2e0e6228 DE |
3729 | * |
3730 | * This function requires the caller to populate the entries in | |
3731 | * the filter list with the necessary fields (including flags to | |
3732 | * indicate Tx or Rx rules). | |
d95276ce | 3733 | */ |
5518ac2a | 3734 | int ice_add_eth_mac(struct ice_hw *hw, struct list_head *em_list) |
d95276ce AA |
3735 | { |
3736 | struct ice_fltr_list_entry *em_list_itr; | |
3737 | ||
3738 | if (!em_list || !hw) | |
d54699e2 | 3739 | return -EINVAL; |
d95276ce AA |
3740 | |
3741 | list_for_each_entry(em_list_itr, em_list, list_entry) { | |
3742 | enum ice_sw_lkup_type l_type = | |
3743 | em_list_itr->fltr_info.lkup_type; | |
3744 | ||
3745 | if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC && | |
3746 | l_type != ICE_SW_LKUP_ETHERTYPE) | |
d54699e2 | 3747 | return -EINVAL; |
d95276ce | 3748 | |
d95276ce AA |
3749 | em_list_itr->status = ice_add_rule_internal(hw, l_type, |
3750 | em_list_itr); | |
3751 | if (em_list_itr->status) | |
3752 | return em_list_itr->status; | |
3753 | } | |
3754 | return 0; | |
3755 | } | |
3756 | ||
3757 | /** | |
3758 | * ice_remove_eth_mac - Remove an ethertype (or MAC) based filter rule | |
3759 | * @hw: pointer to the hardware structure | |
3760 | * @em_list: list of ethertype or ethertype MAC entries | |
3761 | */ | |
5518ac2a | 3762 | int ice_remove_eth_mac(struct ice_hw *hw, struct list_head *em_list) |
d95276ce AA |
3763 | { |
3764 | struct ice_fltr_list_entry *em_list_itr, *tmp; | |
3765 | ||
3766 | if (!em_list || !hw) | |
d54699e2 | 3767 | return -EINVAL; |
d95276ce AA |
3768 | |
3769 | list_for_each_entry_safe(em_list_itr, tmp, em_list, list_entry) { | |
3770 | enum ice_sw_lkup_type l_type = | |
3771 | em_list_itr->fltr_info.lkup_type; | |
3772 | ||
3773 | if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC && | |
3774 | l_type != ICE_SW_LKUP_ETHERTYPE) | |
d54699e2 | 3775 | return -EINVAL; |
d95276ce AA |
3776 | |
3777 | em_list_itr->status = ice_remove_rule_internal(hw, l_type, | |
3778 | em_list_itr); | |
3779 | if (em_list_itr->status) | |
3780 | return em_list_itr->status; | |
3781 | } | |
3782 | return 0; | |
3783 | } | |
3784 | ||
0f9d5027 AV |
3785 | /** |
3786 | * ice_rem_sw_rule_info | |
3787 | * @hw: pointer to the hardware structure | |
3788 | * @rule_head: pointer to the switch list structure that we want to delete | |
3789 | */ | |
3790 | static void | |
3791 | ice_rem_sw_rule_info(struct ice_hw *hw, struct list_head *rule_head) | |
3792 | { | |
3793 | if (!list_empty(rule_head)) { | |
3794 | struct ice_fltr_mgmt_list_entry *entry; | |
3795 | struct ice_fltr_mgmt_list_entry *tmp; | |
3796 | ||
3797 | list_for_each_entry_safe(entry, tmp, rule_head, list_entry) { | |
3798 | list_del(&entry->list_entry); | |
3799 | devm_kfree(ice_hw_to_dev(hw), entry); | |
3800 | } | |
3801 | } | |
3802 | } | |
3803 | ||
8b8ef05b VR |
3804 | /** |
3805 | * ice_rem_adv_rule_info | |
3806 | * @hw: pointer to the hardware structure | |
3807 | * @rule_head: pointer to the switch list structure that we want to delete | |
3808 | */ | |
3809 | static void | |
3810 | ice_rem_adv_rule_info(struct ice_hw *hw, struct list_head *rule_head) | |
3811 | { | |
3812 | struct ice_adv_fltr_mgmt_list_entry *tmp_entry; | |
3813 | struct ice_adv_fltr_mgmt_list_entry *lst_itr; | |
3814 | ||
3815 | if (list_empty(rule_head)) | |
3816 | return; | |
3817 | ||
3818 | list_for_each_entry_safe(lst_itr, tmp_entry, rule_head, list_entry) { | |
3819 | list_del(&lst_itr->list_entry); | |
3820 | devm_kfree(ice_hw_to_dev(hw), lst_itr->lkups); | |
3821 | devm_kfree(ice_hw_to_dev(hw), lst_itr); | |
3822 | } | |
3823 | } | |
3824 | ||
9daf8208 | 3825 | /** |
80d144c9 | 3826 | * ice_cfg_dflt_vsi - change state of VSI to set/clear default |
d7393425 | 3827 | * @pi: pointer to the port_info structure |
5726ca0e | 3828 | * @vsi_handle: VSI handle to set as default |
e94d4478 AV |
3829 | * @set: true to add the above mentioned switch rule, false to remove it |
3830 | * @direction: ICE_FLTR_RX or ICE_FLTR_TX | |
80d144c9 AV |
3831 | * |
3832 | * add filter rule to set/unset given VSI as default VSI for the switch | |
3833 | * (represented by swid) | |
e94d4478 | 3834 | */ |
d7393425 MW |
3835 | int |
3836 | ice_cfg_dflt_vsi(struct ice_port_info *pi, u16 vsi_handle, bool set, | |
3837 | u8 direction) | |
e94d4478 | 3838 | { |
d7393425 | 3839 | struct ice_fltr_list_entry f_list_entry; |
e94d4478 | 3840 | struct ice_fltr_info f_info; |
d7393425 | 3841 | struct ice_hw *hw = pi->hw; |
5726ca0e | 3842 | u16 hw_vsi_id; |
5518ac2a | 3843 | int status; |
5726ca0e AV |
3844 | |
3845 | if (!ice_is_vsi_valid(hw, vsi_handle)) | |
d54699e2 | 3846 | return -EINVAL; |
e94d4478 | 3847 | |
d7393425 | 3848 | hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); |
e94d4478 AV |
3849 | |
3850 | memset(&f_info, 0, sizeof(f_info)); | |
3851 | ||
3852 | f_info.lkup_type = ICE_SW_LKUP_DFLT; | |
3853 | f_info.flag = direction; | |
3854 | f_info.fltr_act = ICE_FWD_TO_VSI; | |
5726ca0e | 3855 | f_info.fwd_id.hw_vsi_id = hw_vsi_id; |
d7393425 | 3856 | f_info.vsi_handle = vsi_handle; |
e94d4478 AV |
3857 | |
3858 | if (f_info.flag & ICE_FLTR_RX) { | |
3859 | f_info.src = hw->port_info->lport; | |
5726ca0e | 3860 | f_info.src_id = ICE_SRC_ID_LPORT; |
e94d4478 | 3861 | } else if (f_info.flag & ICE_FLTR_TX) { |
5726ca0e AV |
3862 | f_info.src_id = ICE_SRC_ID_VSI; |
3863 | f_info.src = hw_vsi_id; | |
e94d4478 | 3864 | } |
d7393425 | 3865 | f_list_entry.fltr_info = f_info; |
e94d4478 AV |
3866 | |
3867 | if (set) | |
d7393425 MW |
3868 | status = ice_add_rule_internal(hw, ICE_SW_LKUP_DFLT, |
3869 | &f_list_entry); | |
e94d4478 | 3870 | else |
d7393425 MW |
3871 | status = ice_remove_rule_internal(hw, ICE_SW_LKUP_DFLT, |
3872 | &f_list_entry); | |
3873 | ||
3874 | return status; | |
3875 | } | |
3876 | ||
3877 | /** | |
3878 | * ice_vsi_uses_fltr - Determine if given VSI uses specified filter | |
3879 | * @fm_entry: filter entry to inspect | |
3880 | * @vsi_handle: VSI handle to compare with filter info | |
3881 | */ | |
3882 | static bool | |
3883 | ice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_handle) | |
3884 | { | |
3885 | return ((fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI && | |
3886 | fm_entry->fltr_info.vsi_handle == vsi_handle) || | |
3887 | (fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST && | |
3888 | fm_entry->vsi_list_info && | |
3889 | (test_bit(vsi_handle, fm_entry->vsi_list_info->vsi_map)))); | |
3890 | } | |
3891 | ||
3892 | /** | |
3893 | * ice_check_if_dflt_vsi - check if VSI is default VSI | |
3894 | * @pi: pointer to the port_info structure | |
3895 | * @vsi_handle: vsi handle to check for in filter list | |
3896 | * @rule_exists: indicates if there are any VSI's in the rule list | |
3897 | * | |
3898 | * checks if the VSI is in a default VSI list, and also indicates | |
3899 | * if the default VSI list is empty | |
3900 | */ | |
3901 | bool | |
3902 | ice_check_if_dflt_vsi(struct ice_port_info *pi, u16 vsi_handle, | |
3903 | bool *rule_exists) | |
3904 | { | |
3905 | struct ice_fltr_mgmt_list_entry *fm_entry; | |
3906 | struct ice_sw_recipe *recp_list; | |
3907 | struct list_head *rule_head; | |
3908 | struct mutex *rule_lock; /* Lock to protect filter rule list */ | |
3909 | bool ret = false; | |
3910 | ||
3911 | recp_list = &pi->hw->switch_info->recp_list[ICE_SW_LKUP_DFLT]; | |
3912 | rule_lock = &recp_list->filt_rule_lock; | |
3913 | rule_head = &recp_list->filt_rules; | |
3914 | ||
3915 | mutex_lock(rule_lock); | |
3916 | ||
3917 | if (rule_exists && !list_empty(rule_head)) | |
3918 | *rule_exists = true; | |
3919 | ||
3920 | list_for_each_entry(fm_entry, rule_head, list_entry) { | |
3921 | if (ice_vsi_uses_fltr(fm_entry, vsi_handle)) { | |
3922 | ret = true; | |
3923 | break; | |
e94d4478 AV |
3924 | } |
3925 | } | |
3926 | ||
d7393425 MW |
3927 | mutex_unlock(rule_lock); |
3928 | ||
3929 | return ret; | |
e94d4478 AV |
3930 | } |
3931 | ||
d76a60ba | 3932 | /** |
80d144c9 | 3933 | * ice_remove_mac - remove a MAC address based filter rule |
d76a60ba | 3934 | * @hw: pointer to the hardware structure |
80d144c9 AV |
3935 | * @m_list: list of MAC addresses and forwarding information |
3936 | * | |
3937 | * This function removes either a MAC filter rule or a specific VSI from a | |
3938 | * VSI list for a multicast MAC address. | |
3939 | * | |
5518ac2a TN |
3940 | * Returns -ENOENT if a given entry was not added by ice_add_mac. Caller should |
3941 | * be aware that this call will only work if all the entries passed into m_list | |
3942 | * were added previously. It will not attempt to do a partial remove of entries | |
3943 | * that were found. | |
d76a60ba | 3944 | */ |
5e24d598 | 3945 | int ice_remove_mac(struct ice_hw *hw, struct list_head *m_list) |
d76a60ba | 3946 | { |
072f0c3d | 3947 | struct ice_fltr_list_entry *list_itr, *tmp; |
d76a60ba | 3948 | |
80d144c9 | 3949 | if (!m_list) |
d54699e2 | 3950 | return -EINVAL; |
d76a60ba | 3951 | |
072f0c3d | 3952 | list_for_each_entry_safe(list_itr, tmp, m_list, list_entry) { |
80d144c9 | 3953 | enum ice_sw_lkup_type l_type = list_itr->fltr_info.lkup_type; |
8b2c8582 | 3954 | u16 vsi_handle; |
80d144c9 AV |
3955 | |
3956 | if (l_type != ICE_SW_LKUP_MAC) | |
d54699e2 | 3957 | return -EINVAL; |
8b2c8582 AA |
3958 | |
3959 | vsi_handle = list_itr->fltr_info.vsi_handle; | |
3960 | if (!ice_is_vsi_valid(hw, vsi_handle)) | |
d54699e2 | 3961 | return -EINVAL; |
8b2c8582 AA |
3962 | |
3963 | list_itr->fltr_info.fwd_id.hw_vsi_id = | |
3964 | ice_get_hw_vsi_num(hw, vsi_handle); | |
e1e9db57 | 3965 | |
80d144c9 AV |
3966 | list_itr->status = ice_remove_rule_internal(hw, |
3967 | ICE_SW_LKUP_MAC, | |
3968 | list_itr); | |
3969 | if (list_itr->status) | |
3970 | return list_itr->status; | |
3971 | } | |
3972 | return 0; | |
d76a60ba AV |
3973 | } |
3974 | ||
3975 | /** | |
3976 | * ice_remove_vlan - Remove VLAN based filter rule | |
3977 | * @hw: pointer to the hardware structure | |
3978 | * @v_list: list of VLAN entries and forwarding information | |
3979 | */ | |
5518ac2a | 3980 | int ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list) |
d76a60ba | 3981 | { |
072f0c3d | 3982 | struct ice_fltr_list_entry *v_list_itr, *tmp; |
d76a60ba AV |
3983 | |
3984 | if (!v_list || !hw) | |
d54699e2 | 3985 | return -EINVAL; |
d76a60ba | 3986 | |
072f0c3d | 3987 | list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) { |
80d144c9 AV |
3988 | enum ice_sw_lkup_type l_type = v_list_itr->fltr_info.lkup_type; |
3989 | ||
3990 | if (l_type != ICE_SW_LKUP_VLAN) | |
d54699e2 | 3991 | return -EINVAL; |
80d144c9 AV |
3992 | v_list_itr->status = ice_remove_rule_internal(hw, |
3993 | ICE_SW_LKUP_VLAN, | |
3994 | v_list_itr); | |
3995 | if (v_list_itr->status) | |
3996 | return v_list_itr->status; | |
d76a60ba | 3997 | } |
80d144c9 AV |
3998 | return 0; |
3999 | } | |
4000 | ||
80d144c9 AV |
4001 | /** |
4002 | * ice_add_entry_to_vsi_fltr_list - Add copy of fltr_list_entry to remove list | |
4003 | * @hw: pointer to the hardware structure | |
5726ca0e | 4004 | * @vsi_handle: VSI handle to remove filters from |
80d144c9 AV |
4005 | * @vsi_list_head: pointer to the list to add entry to |
4006 | * @fi: pointer to fltr_info of filter entry to copy & add | |
4007 | * | |
4008 | * Helper function, used when creating a list of filters to remove from | |
4009 | * a specific VSI. The entry added to vsi_list_head is a COPY of the | |
4010 | * original filter entry, with the exception of fltr_info.fltr_act and | |
4011 | * fltr_info.fwd_id fields. These are set such that later logic can | |
4012 | * extract which VSI to remove the fltr from, and pass on that information. | |
4013 | */ | |
5e24d598 | 4014 | static int |
5726ca0e | 4015 | ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle, |
80d144c9 AV |
4016 | struct list_head *vsi_list_head, |
4017 | struct ice_fltr_info *fi) | |
4018 | { | |
4019 | struct ice_fltr_list_entry *tmp; | |
4020 | ||
4021 | /* this memory is freed up in the caller function | |
4022 | * once filters for this VSI are removed | |
4023 | */ | |
4024 | tmp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*tmp), GFP_KERNEL); | |
4025 | if (!tmp) | |
d54699e2 | 4026 | return -ENOMEM; |
80d144c9 AV |
4027 | |
4028 | tmp->fltr_info = *fi; | |
4029 | ||
4030 | /* Overwrite these fields to indicate which VSI to remove filter from, | |
4031 | * so find and remove logic can extract the information from the | |
4032 | * list entries. Note that original entries will still have proper | |
4033 | * values. | |
4034 | */ | |
4035 | tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; | |
5726ca0e AV |
4036 | tmp->fltr_info.vsi_handle = vsi_handle; |
4037 | tmp->fltr_info.fwd_id.hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); | |
80d144c9 AV |
4038 | |
4039 | list_add(&tmp->list_entry, vsi_list_head); | |
4040 | ||
4041 | return 0; | |
d76a60ba AV |
4042 | } |
4043 | ||
9daf8208 AV |
4044 | /** |
4045 | * ice_add_to_vsi_fltr_list - Add VSI filters to the list | |
4046 | * @hw: pointer to the hardware structure | |
5726ca0e | 4047 | * @vsi_handle: VSI handle to remove filters from |
9daf8208 | 4048 | * @lkup_list_head: pointer to the list that has certain lookup type filters |
5726ca0e | 4049 | * @vsi_list_head: pointer to the list pertaining to VSI with vsi_handle |
80d144c9 AV |
4050 | * |
4051 | * Locates all filters in lkup_list_head that are used by the given VSI, | |
4052 | * and adds COPIES of those entries to vsi_list_head (intended to be used | |
4053 | * to remove the listed filters). | |
4054 | * Note that this means all entries in vsi_list_head must be explicitly | |
4055 | * deallocated by the caller when done with list. | |
9daf8208 | 4056 | */ |
5e24d598 | 4057 | static int |
5726ca0e | 4058 | ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle, |
9daf8208 AV |
4059 | struct list_head *lkup_list_head, |
4060 | struct list_head *vsi_list_head) | |
4061 | { | |
4062 | struct ice_fltr_mgmt_list_entry *fm_entry; | |
5e24d598 | 4063 | int status = 0; |
9daf8208 | 4064 | |
f9867df6 | 4065 | /* check to make sure VSI ID is valid and within boundary */ |
5726ca0e | 4066 | if (!ice_is_vsi_valid(hw, vsi_handle)) |
d54699e2 | 4067 | return -EINVAL; |
9daf8208 AV |
4068 | |
4069 | list_for_each_entry(fm_entry, lkup_list_head, list_entry) { | |
7a91d3f0 | 4070 | if (!ice_vsi_uses_fltr(fm_entry, vsi_handle)) |
80d144c9 | 4071 | continue; |
9daf8208 | 4072 | |
5726ca0e | 4073 | status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle, |
7a91d3f0 JB |
4074 | vsi_list_head, |
4075 | &fm_entry->fltr_info); | |
80d144c9 AV |
4076 | if (status) |
4077 | return status; | |
9daf8208 | 4078 | } |
80d144c9 | 4079 | return status; |
9daf8208 AV |
4080 | } |
4081 | ||
5eda8afd AA |
4082 | /** |
4083 | * ice_determine_promisc_mask | |
4084 | * @fi: filter info to parse | |
4085 | * | |
4086 | * Helper function to determine which ICE_PROMISC_ mask corresponds | |
4087 | * to given filter into. | |
4088 | */ | |
4089 | static u8 ice_determine_promisc_mask(struct ice_fltr_info *fi) | |
4090 | { | |
4091 | u16 vid = fi->l_data.mac_vlan.vlan_id; | |
4092 | u8 *macaddr = fi->l_data.mac.mac_addr; | |
4093 | bool is_tx_fltr = false; | |
4094 | u8 promisc_mask = 0; | |
4095 | ||
4096 | if (fi->flag == ICE_FLTR_TX) | |
4097 | is_tx_fltr = true; | |
4098 | ||
4099 | if (is_broadcast_ether_addr(macaddr)) | |
4100 | promisc_mask |= is_tx_fltr ? | |
4101 | ICE_PROMISC_BCAST_TX : ICE_PROMISC_BCAST_RX; | |
4102 | else if (is_multicast_ether_addr(macaddr)) | |
4103 | promisc_mask |= is_tx_fltr ? | |
4104 | ICE_PROMISC_MCAST_TX : ICE_PROMISC_MCAST_RX; | |
4105 | else if (is_unicast_ether_addr(macaddr)) | |
4106 | promisc_mask |= is_tx_fltr ? | |
4107 | ICE_PROMISC_UCAST_TX : ICE_PROMISC_UCAST_RX; | |
4108 | if (vid) | |
4109 | promisc_mask |= is_tx_fltr ? | |
4110 | ICE_PROMISC_VLAN_TX : ICE_PROMISC_VLAN_RX; | |
4111 | ||
4112 | return promisc_mask; | |
4113 | } | |
4114 | ||
4115 | /** | |
4116 | * ice_remove_promisc - Remove promisc based filter rules | |
4117 | * @hw: pointer to the hardware structure | |
f9867df6 | 4118 | * @recp_id: recipe ID for which the rule needs to removed |
5eda8afd AA |
4119 | * @v_list: list of promisc entries |
4120 | */ | |
5e24d598 | 4121 | static int |
5518ac2a | 4122 | ice_remove_promisc(struct ice_hw *hw, u8 recp_id, struct list_head *v_list) |
5eda8afd AA |
4123 | { |
4124 | struct ice_fltr_list_entry *v_list_itr, *tmp; | |
4125 | ||
4126 | list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) { | |
4127 | v_list_itr->status = | |
4128 | ice_remove_rule_internal(hw, recp_id, v_list_itr); | |
4129 | if (v_list_itr->status) | |
4130 | return v_list_itr->status; | |
4131 | } | |
4132 | return 0; | |
4133 | } | |
4134 | ||
4135 | /** | |
4136 | * ice_clear_vsi_promisc - clear specified promiscuous mode(s) for given VSI | |
4137 | * @hw: pointer to the hardware structure | |
4138 | * @vsi_handle: VSI handle to clear mode | |
4139 | * @promisc_mask: mask of promiscuous config bits to clear | |
4140 | * @vid: VLAN ID to clear VLAN promiscuous | |
4141 | */ | |
5e24d598 | 4142 | int |
5eda8afd AA |
4143 | ice_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, |
4144 | u16 vid) | |
4145 | { | |
4146 | struct ice_switch_info *sw = hw->switch_info; | |
4147 | struct ice_fltr_list_entry *fm_entry, *tmp; | |
4148 | struct list_head remove_list_head; | |
4149 | struct ice_fltr_mgmt_list_entry *itr; | |
4150 | struct list_head *rule_head; | |
4151 | struct mutex *rule_lock; /* Lock to protect filter rule list */ | |
5e24d598 | 4152 | int status = 0; |
5eda8afd AA |
4153 | u8 recipe_id; |
4154 | ||
4155 | if (!ice_is_vsi_valid(hw, vsi_handle)) | |
d54699e2 | 4156 | return -EINVAL; |
5eda8afd | 4157 | |
1bc7a4ab | 4158 | if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX)) |
5eda8afd AA |
4159 | recipe_id = ICE_SW_LKUP_PROMISC_VLAN; |
4160 | else | |
4161 | recipe_id = ICE_SW_LKUP_PROMISC; | |
4162 | ||
4163 | rule_head = &sw->recp_list[recipe_id].filt_rules; | |
4164 | rule_lock = &sw->recp_list[recipe_id].filt_rule_lock; | |
4165 | ||
4166 | INIT_LIST_HEAD(&remove_list_head); | |
4167 | ||
4168 | mutex_lock(rule_lock); | |
4169 | list_for_each_entry(itr, rule_head, list_entry) { | |
1bc7a4ab | 4170 | struct ice_fltr_info *fltr_info; |
5eda8afd AA |
4171 | u8 fltr_promisc_mask = 0; |
4172 | ||
4173 | if (!ice_vsi_uses_fltr(itr, vsi_handle)) | |
4174 | continue; | |
1bc7a4ab BC |
4175 | fltr_info = &itr->fltr_info; |
4176 | ||
4177 | if (recipe_id == ICE_SW_LKUP_PROMISC_VLAN && | |
4178 | vid != fltr_info->l_data.mac_vlan.vlan_id) | |
4179 | continue; | |
5eda8afd | 4180 | |
1bc7a4ab | 4181 | fltr_promisc_mask |= ice_determine_promisc_mask(fltr_info); |
5eda8afd AA |
4182 | |
4183 | /* Skip if filter is not completely specified by given mask */ | |
4184 | if (fltr_promisc_mask & ~promisc_mask) | |
4185 | continue; | |
4186 | ||
4187 | status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle, | |
4188 | &remove_list_head, | |
1bc7a4ab | 4189 | fltr_info); |
5eda8afd AA |
4190 | if (status) { |
4191 | mutex_unlock(rule_lock); | |
4192 | goto free_fltr_list; | |
4193 | } | |
4194 | } | |
4195 | mutex_unlock(rule_lock); | |
4196 | ||
4197 | status = ice_remove_promisc(hw, recipe_id, &remove_list_head); | |
4198 | ||
4199 | free_fltr_list: | |
4200 | list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) { | |
4201 | list_del(&fm_entry->list_entry); | |
4202 | devm_kfree(ice_hw_to_dev(hw), fm_entry); | |
4203 | } | |
4204 | ||
4205 | return status; | |
4206 | } | |
4207 | ||
4208 | /** | |
4209 | * ice_set_vsi_promisc - set given VSI to given promiscuous mode(s) | |
4210 | * @hw: pointer to the hardware structure | |
4211 | * @vsi_handle: VSI handle to configure | |
4212 | * @promisc_mask: mask of promiscuous config bits | |
4213 | * @vid: VLAN ID to set VLAN promiscuous | |
4214 | */ | |
5e24d598 | 4215 | int |
5eda8afd AA |
4216 | ice_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, u16 vid) |
4217 | { | |
4218 | enum { UCAST_FLTR = 1, MCAST_FLTR, BCAST_FLTR }; | |
4219 | struct ice_fltr_list_entry f_list_entry; | |
4220 | struct ice_fltr_info new_fltr; | |
5eda8afd | 4221 | bool is_tx_fltr; |
5518ac2a | 4222 | int status = 0; |
5eda8afd AA |
4223 | u16 hw_vsi_id; |
4224 | int pkt_type; | |
4225 | u8 recipe_id; | |
4226 | ||
4227 | if (!ice_is_vsi_valid(hw, vsi_handle)) | |
d54699e2 | 4228 | return -EINVAL; |
5eda8afd AA |
4229 | hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); |
4230 | ||
4231 | memset(&new_fltr, 0, sizeof(new_fltr)); | |
4232 | ||
4233 | if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX)) { | |
4234 | new_fltr.lkup_type = ICE_SW_LKUP_PROMISC_VLAN; | |
4235 | new_fltr.l_data.mac_vlan.vlan_id = vid; | |
4236 | recipe_id = ICE_SW_LKUP_PROMISC_VLAN; | |
4237 | } else { | |
4238 | new_fltr.lkup_type = ICE_SW_LKUP_PROMISC; | |
4239 | recipe_id = ICE_SW_LKUP_PROMISC; | |
4240 | } | |
4241 | ||
4242 | /* Separate filters must be set for each direction/packet type | |
4243 | * combination, so we will loop over the mask value, store the | |
4244 | * individual type, and clear it out in the input mask as it | |
4245 | * is found. | |
4246 | */ | |
4247 | while (promisc_mask) { | |
4248 | u8 *mac_addr; | |
4249 | ||
4250 | pkt_type = 0; | |
4251 | is_tx_fltr = false; | |
4252 | ||
4253 | if (promisc_mask & ICE_PROMISC_UCAST_RX) { | |
4254 | promisc_mask &= ~ICE_PROMISC_UCAST_RX; | |
4255 | pkt_type = UCAST_FLTR; | |
4256 | } else if (promisc_mask & ICE_PROMISC_UCAST_TX) { | |
4257 | promisc_mask &= ~ICE_PROMISC_UCAST_TX; | |
4258 | pkt_type = UCAST_FLTR; | |
4259 | is_tx_fltr = true; | |
4260 | } else if (promisc_mask & ICE_PROMISC_MCAST_RX) { | |
4261 | promisc_mask &= ~ICE_PROMISC_MCAST_RX; | |
4262 | pkt_type = MCAST_FLTR; | |
4263 | } else if (promisc_mask & ICE_PROMISC_MCAST_TX) { | |
4264 | promisc_mask &= ~ICE_PROMISC_MCAST_TX; | |
4265 | pkt_type = MCAST_FLTR; | |
4266 | is_tx_fltr = true; | |
4267 | } else if (promisc_mask & ICE_PROMISC_BCAST_RX) { | |
4268 | promisc_mask &= ~ICE_PROMISC_BCAST_RX; | |
4269 | pkt_type = BCAST_FLTR; | |
4270 | } else if (promisc_mask & ICE_PROMISC_BCAST_TX) { | |
4271 | promisc_mask &= ~ICE_PROMISC_BCAST_TX; | |
4272 | pkt_type = BCAST_FLTR; | |
4273 | is_tx_fltr = true; | |
4274 | } | |
4275 | ||
4276 | /* Check for VLAN promiscuous flag */ | |
4277 | if (promisc_mask & ICE_PROMISC_VLAN_RX) { | |
4278 | promisc_mask &= ~ICE_PROMISC_VLAN_RX; | |
4279 | } else if (promisc_mask & ICE_PROMISC_VLAN_TX) { | |
4280 | promisc_mask &= ~ICE_PROMISC_VLAN_TX; | |
4281 | is_tx_fltr = true; | |
4282 | } | |
4283 | ||
4284 | /* Set filter DA based on packet type */ | |
4285 | mac_addr = new_fltr.l_data.mac.mac_addr; | |
4286 | if (pkt_type == BCAST_FLTR) { | |
4287 | eth_broadcast_addr(mac_addr); | |
4288 | } else if (pkt_type == MCAST_FLTR || | |
4289 | pkt_type == UCAST_FLTR) { | |
4290 | /* Use the dummy ether header DA */ | |
4291 | ether_addr_copy(mac_addr, dummy_eth_header); | |
4292 | if (pkt_type == MCAST_FLTR) | |
4293 | mac_addr[0] |= 0x1; /* Set multicast bit */ | |
4294 | } | |
4295 | ||
4296 | /* Need to reset this to zero for all iterations */ | |
4297 | new_fltr.flag = 0; | |
4298 | if (is_tx_fltr) { | |
4299 | new_fltr.flag |= ICE_FLTR_TX; | |
4300 | new_fltr.src = hw_vsi_id; | |
4301 | } else { | |
4302 | new_fltr.flag |= ICE_FLTR_RX; | |
4303 | new_fltr.src = hw->port_info->lport; | |
4304 | } | |
4305 | ||
4306 | new_fltr.fltr_act = ICE_FWD_TO_VSI; | |
4307 | new_fltr.vsi_handle = vsi_handle; | |
4308 | new_fltr.fwd_id.hw_vsi_id = hw_vsi_id; | |
4309 | f_list_entry.fltr_info = new_fltr; | |
4310 | ||
4311 | status = ice_add_rule_internal(hw, recipe_id, &f_list_entry); | |
4312 | if (status) | |
4313 | goto set_promisc_exit; | |
4314 | } | |
4315 | ||
4316 | set_promisc_exit: | |
4317 | return status; | |
4318 | } | |
4319 | ||
4320 | /** | |
4321 | * ice_set_vlan_vsi_promisc | |
4322 | * @hw: pointer to the hardware structure | |
4323 | * @vsi_handle: VSI handle to configure | |
4324 | * @promisc_mask: mask of promiscuous config bits | |
4325 | * @rm_vlan_promisc: Clear VLANs VSI promisc mode | |
4326 | * | |
4327 | * Configure VSI with all associated VLANs to given promiscuous mode(s) | |
4328 | */ | |
5e24d598 | 4329 | int |
5eda8afd AA |
4330 | ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, |
4331 | bool rm_vlan_promisc) | |
4332 | { | |
4333 | struct ice_switch_info *sw = hw->switch_info; | |
4334 | struct ice_fltr_list_entry *list_itr, *tmp; | |
4335 | struct list_head vsi_list_head; | |
4336 | struct list_head *vlan_head; | |
4337 | struct mutex *vlan_lock; /* Lock to protect filter rule list */ | |
5eda8afd | 4338 | u16 vlan_id; |
5518ac2a | 4339 | int status; |
5eda8afd AA |
4340 | |
4341 | INIT_LIST_HEAD(&vsi_list_head); | |
4342 | vlan_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock; | |
4343 | vlan_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules; | |
4344 | mutex_lock(vlan_lock); | |
4345 | status = ice_add_to_vsi_fltr_list(hw, vsi_handle, vlan_head, | |
4346 | &vsi_list_head); | |
4347 | mutex_unlock(vlan_lock); | |
4348 | if (status) | |
4349 | goto free_fltr_list; | |
4350 | ||
4351 | list_for_each_entry(list_itr, &vsi_list_head, list_entry) { | |
ffa9ed86 GS |
4352 | /* Avoid enabling or disabling VLAN zero twice when in double |
4353 | * VLAN mode | |
4354 | */ | |
4355 | if (ice_is_dvm_ena(hw) && | |
4356 | list_itr->fltr_info.l_data.vlan.tpid == 0) | |
4357 | continue; | |
4358 | ||
5eda8afd AA |
4359 | vlan_id = list_itr->fltr_info.l_data.vlan.vlan_id; |
4360 | if (rm_vlan_promisc) | |
4361 | status = ice_clear_vsi_promisc(hw, vsi_handle, | |
4362 | promisc_mask, vlan_id); | |
4363 | else | |
4364 | status = ice_set_vsi_promisc(hw, vsi_handle, | |
4365 | promisc_mask, vlan_id); | |
11e551a2 | 4366 | if (status && status != -EEXIST) |
5eda8afd AA |
4367 | break; |
4368 | } | |
4369 | ||
4370 | free_fltr_list: | |
4371 | list_for_each_entry_safe(list_itr, tmp, &vsi_list_head, list_entry) { | |
4372 | list_del(&list_itr->list_entry); | |
4373 | devm_kfree(ice_hw_to_dev(hw), list_itr); | |
4374 | } | |
4375 | return status; | |
4376 | } | |
4377 | ||
9daf8208 AV |
4378 | /** |
4379 | * ice_remove_vsi_lkup_fltr - Remove lookup type filters for a VSI | |
4380 | * @hw: pointer to the hardware structure | |
5726ca0e | 4381 | * @vsi_handle: VSI handle to remove filters from |
9daf8208 AV |
4382 | * @lkup: switch rule filter lookup type |
4383 | */ | |
4384 | static void | |
5726ca0e | 4385 | ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_handle, |
9daf8208 AV |
4386 | enum ice_sw_lkup_type lkup) |
4387 | { | |
4388 | struct ice_switch_info *sw = hw->switch_info; | |
4389 | struct ice_fltr_list_entry *fm_entry; | |
4390 | struct list_head remove_list_head; | |
80d144c9 | 4391 | struct list_head *rule_head; |
9daf8208 | 4392 | struct ice_fltr_list_entry *tmp; |
80d144c9 | 4393 | struct mutex *rule_lock; /* Lock to protect filter rule list */ |
5e24d598 | 4394 | int status; |
9daf8208 AV |
4395 | |
4396 | INIT_LIST_HEAD(&remove_list_head); | |
80d144c9 AV |
4397 | rule_lock = &sw->recp_list[lkup].filt_rule_lock; |
4398 | rule_head = &sw->recp_list[lkup].filt_rules; | |
4399 | mutex_lock(rule_lock); | |
5726ca0e | 4400 | status = ice_add_to_vsi_fltr_list(hw, vsi_handle, rule_head, |
80d144c9 AV |
4401 | &remove_list_head); |
4402 | mutex_unlock(rule_lock); | |
4403 | if (status) | |
b7eeb527 | 4404 | goto free_fltr_list; |
80d144c9 | 4405 | |
9daf8208 AV |
4406 | switch (lkup) { |
4407 | case ICE_SW_LKUP_MAC: | |
80d144c9 | 4408 | ice_remove_mac(hw, &remove_list_head); |
9daf8208 AV |
4409 | break; |
4410 | case ICE_SW_LKUP_VLAN: | |
80d144c9 | 4411 | ice_remove_vlan(hw, &remove_list_head); |
d76a60ba | 4412 | break; |
5eda8afd AA |
4413 | case ICE_SW_LKUP_PROMISC: |
4414 | case ICE_SW_LKUP_PROMISC_VLAN: | |
4415 | ice_remove_promisc(hw, lkup, &remove_list_head); | |
4416 | break; | |
9daf8208 AV |
4417 | case ICE_SW_LKUP_MAC_VLAN: |
4418 | case ICE_SW_LKUP_ETHERTYPE: | |
4419 | case ICE_SW_LKUP_ETHERTYPE_MAC: | |
9daf8208 | 4420 | case ICE_SW_LKUP_DFLT: |
80d144c9 AV |
4421 | case ICE_SW_LKUP_LAST: |
4422 | default: | |
4423 | ice_debug(hw, ICE_DBG_SW, "Unsupported lookup type %d\n", lkup); | |
9daf8208 AV |
4424 | break; |
4425 | } | |
4426 | ||
b7eeb527 | 4427 | free_fltr_list: |
9daf8208 AV |
4428 | list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) { |
4429 | list_del(&fm_entry->list_entry); | |
4430 | devm_kfree(ice_hw_to_dev(hw), fm_entry); | |
4431 | } | |
4432 | } | |
4433 | ||
4434 | /** | |
4435 | * ice_remove_vsi_fltr - Remove all filters for a VSI | |
4436 | * @hw: pointer to the hardware structure | |
5726ca0e | 4437 | * @vsi_handle: VSI handle to remove filters from |
9daf8208 | 4438 | */ |
5726ca0e | 4439 | void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle) |
9daf8208 | 4440 | { |
5726ca0e AV |
4441 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC); |
4442 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC_VLAN); | |
4443 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC); | |
4444 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_VLAN); | |
4445 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_DFLT); | |
4446 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE); | |
4447 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE_MAC); | |
4448 | ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC_VLAN); | |
9daf8208 | 4449 | } |
0f9d5027 | 4450 | |
148beb61 HT |
4451 | /** |
4452 | * ice_alloc_res_cntr - allocating resource counter | |
4453 | * @hw: pointer to the hardware structure | |
4454 | * @type: type of resource | |
4455 | * @alloc_shared: if set it is shared else dedicated | |
4456 | * @num_items: number of entries requested for FD resource type | |
4457 | * @counter_id: counter index returned by AQ call | |
4458 | */ | |
5e24d598 | 4459 | int |
148beb61 HT |
4460 | ice_alloc_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items, |
4461 | u16 *counter_id) | |
4462 | { | |
4463 | struct ice_aqc_alloc_free_res_elem *buf; | |
148beb61 | 4464 | u16 buf_len; |
5518ac2a | 4465 | int status; |
148beb61 HT |
4466 | |
4467 | /* Allocate resource */ | |
66486d89 | 4468 | buf_len = struct_size(buf, elem, 1); |
148beb61 HT |
4469 | buf = kzalloc(buf_len, GFP_KERNEL); |
4470 | if (!buf) | |
d54699e2 | 4471 | return -ENOMEM; |
148beb61 HT |
4472 | |
4473 | buf->num_elems = cpu_to_le16(num_items); | |
4474 | buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) & | |
4475 | ICE_AQC_RES_TYPE_M) | alloc_shared); | |
4476 | ||
4477 | status = ice_aq_alloc_free_res(hw, 1, buf, buf_len, | |
4478 | ice_aqc_opc_alloc_res, NULL); | |
4479 | if (status) | |
4480 | goto exit; | |
4481 | ||
4482 | *counter_id = le16_to_cpu(buf->elem[0].e.sw_resp); | |
4483 | ||
4484 | exit: | |
4485 | kfree(buf); | |
4486 | return status; | |
4487 | } | |
4488 | ||
4489 | /** | |
4490 | * ice_free_res_cntr - free resource counter | |
4491 | * @hw: pointer to the hardware structure | |
4492 | * @type: type of resource | |
4493 | * @alloc_shared: if set it is shared else dedicated | |
4494 | * @num_items: number of entries to be freed for FD resource type | |
4495 | * @counter_id: counter ID resource which needs to be freed | |
4496 | */ | |
5e24d598 | 4497 | int |
148beb61 HT |
4498 | ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items, |
4499 | u16 counter_id) | |
4500 | { | |
4501 | struct ice_aqc_alloc_free_res_elem *buf; | |
148beb61 | 4502 | u16 buf_len; |
5518ac2a | 4503 | int status; |
148beb61 HT |
4504 | |
4505 | /* Free resource */ | |
66486d89 | 4506 | buf_len = struct_size(buf, elem, 1); |
148beb61 HT |
4507 | buf = kzalloc(buf_len, GFP_KERNEL); |
4508 | if (!buf) | |
d54699e2 | 4509 | return -ENOMEM; |
148beb61 HT |
4510 | |
4511 | buf->num_elems = cpu_to_le16(num_items); | |
4512 | buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) & | |
4513 | ICE_AQC_RES_TYPE_M) | alloc_shared); | |
4514 | buf->elem[0].e.sw_resp = cpu_to_le16(counter_id); | |
4515 | ||
4516 | status = ice_aq_alloc_free_res(hw, 1, buf, buf_len, | |
4517 | ice_aqc_opc_free_res, NULL); | |
4518 | if (status) | |
9228d8b2 | 4519 | ice_debug(hw, ICE_DBG_SW, "counter resource could not be freed\n"); |
148beb61 HT |
4520 | |
4521 | kfree(buf); | |
4522 | return status; | |
4523 | } | |
4524 | ||
fd2a6b71 DN |
4525 | /* This is mapping table entry that maps every word within a given protocol |
4526 | * structure to the real byte offset as per the specification of that | |
4527 | * protocol header. | |
4528 | * for example dst address is 3 words in ethertype header and corresponding | |
4529 | * bytes are 0, 2, 3 in the actual packet header and src address is at 4, 6, 8 | |
4530 | * IMPORTANT: Every structure part of "ice_prot_hdr" union should have a | |
4531 | * matching entry describing its field. This needs to be updated if new | |
4532 | * structure is added to that union. | |
4533 | */ | |
4534 | static const struct ice_prot_ext_tbl_entry ice_prot_ext[ICE_PROTOCOL_LAST] = { | |
4535 | { ICE_MAC_OFOS, { 0, 2, 4, 6, 8, 10, 12 } }, | |
4536 | { ICE_MAC_IL, { 0, 2, 4, 6, 8, 10, 12 } }, | |
4537 | { ICE_ETYPE_OL, { 0 } }, | |
34a89775 | 4538 | { ICE_ETYPE_IL, { 0 } }, |
fd2a6b71 DN |
4539 | { ICE_VLAN_OFOS, { 2, 0 } }, |
4540 | { ICE_IPV4_OFOS, { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 } }, | |
4541 | { ICE_IPV4_IL, { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 } }, | |
4542 | { ICE_IPV6_OFOS, { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, | |
4543 | 26, 28, 30, 32, 34, 36, 38 } }, | |
4544 | { ICE_IPV6_IL, { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, | |
4545 | 26, 28, 30, 32, 34, 36, 38 } }, | |
4546 | { ICE_TCP_IL, { 0, 2 } }, | |
4547 | { ICE_UDP_OF, { 0, 2 } }, | |
4548 | { ICE_UDP_ILOS, { 0, 2 } }, | |
8b032a55 MS |
4549 | { ICE_VXLAN, { 8, 10, 12, 14 } }, |
4550 | { ICE_GENEVE, { 8, 10, 12, 14 } }, | |
9a225f81 MS |
4551 | { ICE_NVGRE, { 0, 2, 4, 6 } }, |
4552 | { ICE_GTP, { 8, 10, 12, 14, 16, 18, 20, 22 } }, | |
4553 | { ICE_GTP_NO_PAY, { 8, 10, 12, 14 } }, | |
cd8efeee | 4554 | { ICE_PPPOE, { 0, 2, 4, 6 } }, |
cd634549 | 4555 | { ICE_L2TPV3, { 0, 2, 4, 6, 8, 10 } }, |
06bca7c2 MSM |
4556 | { ICE_VLAN_EX, { 2, 0 } }, |
4557 | { ICE_VLAN_IN, { 2, 0 } }, | |
fd2a6b71 DN |
4558 | }; |
4559 | ||
4560 | static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = { | |
4561 | { ICE_MAC_OFOS, ICE_MAC_OFOS_HW }, | |
4562 | { ICE_MAC_IL, ICE_MAC_IL_HW }, | |
4563 | { ICE_ETYPE_OL, ICE_ETYPE_OL_HW }, | |
34a89775 | 4564 | { ICE_ETYPE_IL, ICE_ETYPE_IL_HW }, |
fd2a6b71 DN |
4565 | { ICE_VLAN_OFOS, ICE_VLAN_OL_HW }, |
4566 | { ICE_IPV4_OFOS, ICE_IPV4_OFOS_HW }, | |
4567 | { ICE_IPV4_IL, ICE_IPV4_IL_HW }, | |
4568 | { ICE_IPV6_OFOS, ICE_IPV6_OFOS_HW }, | |
4569 | { ICE_IPV6_IL, ICE_IPV6_IL_HW }, | |
4570 | { ICE_TCP_IL, ICE_TCP_IL_HW }, | |
4571 | { ICE_UDP_OF, ICE_UDP_OF_HW }, | |
4572 | { ICE_UDP_ILOS, ICE_UDP_ILOS_HW }, | |
8b032a55 MS |
4573 | { ICE_VXLAN, ICE_UDP_OF_HW }, |
4574 | { ICE_GENEVE, ICE_UDP_OF_HW }, | |
9a225f81 MS |
4575 | { ICE_NVGRE, ICE_GRE_OF_HW }, |
4576 | { ICE_GTP, ICE_UDP_OF_HW }, | |
4577 | { ICE_GTP_NO_PAY, ICE_UDP_ILOS_HW }, | |
cd8efeee | 4578 | { ICE_PPPOE, ICE_PPPOE_HW }, |
cd634549 | 4579 | { ICE_L2TPV3, ICE_L2TPV3_HW }, |
06bca7c2 MSM |
4580 | { ICE_VLAN_EX, ICE_VLAN_OF_HW }, |
4581 | { ICE_VLAN_IN, ICE_VLAN_OL_HW }, | |
fd2a6b71 DN |
4582 | }; |
4583 | ||
4584 | /** | |
4585 | * ice_find_recp - find a recipe | |
4586 | * @hw: pointer to the hardware structure | |
4587 | * @lkup_exts: extension sequence to match | |
de6acd1c | 4588 | * @tun_type: type of recipe tunnel |
fd2a6b71 DN |
4589 | * |
4590 | * Returns index of matching recipe, or ICE_MAX_NUM_RECIPES if not found. | |
4591 | */ | |
de6acd1c MS |
4592 | static u16 |
4593 | ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts, | |
4594 | enum ice_sw_tunnel_type tun_type) | |
fd2a6b71 DN |
4595 | { |
4596 | bool refresh_required = true; | |
4597 | struct ice_sw_recipe *recp; | |
4598 | u8 i; | |
4599 | ||
4600 | /* Walk through existing recipes to find a match */ | |
4601 | recp = hw->switch_info->recp_list; | |
4602 | for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) { | |
4603 | /* If recipe was not created for this ID, in SW bookkeeping, | |
4604 | * check if FW has an entry for this recipe. If the FW has an | |
4605 | * entry update it in our SW bookkeeping and continue with the | |
4606 | * matching. | |
4607 | */ | |
4608 | if (!recp[i].recp_created) | |
4609 | if (ice_get_recp_frm_fw(hw, | |
4610 | hw->switch_info->recp_list, i, | |
4611 | &refresh_required)) | |
4612 | continue; | |
4613 | ||
4614 | /* Skip inverse action recipes */ | |
4615 | if (recp[i].root_buf && recp[i].root_buf->content.act_ctrl & | |
4616 | ICE_AQ_RECIPE_ACT_INV_ACT) | |
4617 | continue; | |
4618 | ||
4619 | /* if number of words we are looking for match */ | |
4620 | if (lkup_exts->n_val_words == recp[i].lkup_exts.n_val_words) { | |
4621 | struct ice_fv_word *ar = recp[i].lkup_exts.fv_words; | |
4622 | struct ice_fv_word *be = lkup_exts->fv_words; | |
4623 | u16 *cr = recp[i].lkup_exts.field_mask; | |
4624 | u16 *de = lkup_exts->field_mask; | |
4625 | bool found = true; | |
4626 | u8 pe, qr; | |
4627 | ||
4628 | /* ar, cr, and qr are related to the recipe words, while | |
4629 | * be, de, and pe are related to the lookup words | |
4630 | */ | |
4631 | for (pe = 0; pe < lkup_exts->n_val_words; pe++) { | |
4632 | for (qr = 0; qr < recp[i].lkup_exts.n_val_words; | |
4633 | qr++) { | |
4634 | if (ar[qr].off == be[pe].off && | |
4635 | ar[qr].prot_id == be[pe].prot_id && | |
4636 | cr[qr] == de[pe]) | |
4637 | /* Found the "pe"th word in the | |
4638 | * given recipe | |
4639 | */ | |
4640 | break; | |
4641 | } | |
4642 | /* After walking through all the words in the | |
4643 | * "i"th recipe if "p"th word was not found then | |
4644 | * this recipe is not what we are looking for. | |
4645 | * So break out from this loop and try the next | |
4646 | * recipe | |
4647 | */ | |
4648 | if (qr >= recp[i].lkup_exts.n_val_words) { | |
4649 | found = false; | |
4650 | break; | |
4651 | } | |
4652 | } | |
4653 | /* If for "i"th recipe the found was never set to false | |
4654 | * then it means we found our match | |
de6acd1c | 4655 | * Also tun type of recipe needs to be checked |
fd2a6b71 | 4656 | */ |
de6acd1c | 4657 | if (found && recp[i].tun_type == tun_type) |
fd2a6b71 DN |
4658 | return i; /* Return the recipe ID */ |
4659 | } | |
4660 | } | |
4661 | return ICE_MAX_NUM_RECIPES; | |
4662 | } | |
4663 | ||
a1ffafb0 BC |
4664 | /** |
4665 | * ice_change_proto_id_to_dvm - change proto id in prot_id_tbl | |
4666 | * | |
4667 | * As protocol id for outer vlan is different in dvm and svm, if dvm is | |
4668 | * supported protocol array record for outer vlan has to be modified to | |
4669 | * reflect the value proper for DVM. | |
4670 | */ | |
4671 | void ice_change_proto_id_to_dvm(void) | |
4672 | { | |
4673 | u8 i; | |
4674 | ||
4675 | for (i = 0; i < ARRAY_SIZE(ice_prot_id_tbl); i++) | |
4676 | if (ice_prot_id_tbl[i].type == ICE_VLAN_OFOS && | |
4677 | ice_prot_id_tbl[i].protocol_id != ICE_VLAN_OF_HW) | |
4678 | ice_prot_id_tbl[i].protocol_id = ICE_VLAN_OF_HW; | |
4679 | } | |
4680 | ||
fd2a6b71 DN |
4681 | /** |
4682 | * ice_prot_type_to_id - get protocol ID from protocol type | |
4683 | * @type: protocol type | |
4684 | * @id: pointer to variable that will receive the ID | |
4685 | * | |
4686 | * Returns true if found, false otherwise | |
4687 | */ | |
4688 | static bool ice_prot_type_to_id(enum ice_protocol_type type, u8 *id) | |
4689 | { | |
4690 | u8 i; | |
4691 | ||
4692 | for (i = 0; i < ARRAY_SIZE(ice_prot_id_tbl); i++) | |
4693 | if (ice_prot_id_tbl[i].type == type) { | |
4694 | *id = ice_prot_id_tbl[i].protocol_id; | |
4695 | return true; | |
4696 | } | |
4697 | return false; | |
4698 | } | |
4699 | ||
4700 | /** | |
4701 | * ice_fill_valid_words - count valid words | |
4702 | * @rule: advanced rule with lookup information | |
4703 | * @lkup_exts: byte offset extractions of the words that are valid | |
4704 | * | |
4705 | * calculate valid words in a lookup rule using mask value | |
4706 | */ | |
4707 | static u8 | |
4708 | ice_fill_valid_words(struct ice_adv_lkup_elem *rule, | |
4709 | struct ice_prot_lkup_ext *lkup_exts) | |
4710 | { | |
4711 | u8 j, word, prot_id, ret_val; | |
4712 | ||
4713 | if (!ice_prot_type_to_id(rule->type, &prot_id)) | |
4714 | return 0; | |
4715 | ||
4716 | word = lkup_exts->n_val_words; | |
4717 | ||
4718 | for (j = 0; j < sizeof(rule->m_u) / sizeof(u16); j++) | |
4719 | if (((u16 *)&rule->m_u)[j] && | |
4720 | rule->type < ARRAY_SIZE(ice_prot_ext)) { | |
4721 | /* No more space to accommodate */ | |
4722 | if (word >= ICE_MAX_CHAIN_WORDS) | |
4723 | return 0; | |
4724 | lkup_exts->fv_words[word].off = | |
4725 | ice_prot_ext[rule->type].offs[j]; | |
4726 | lkup_exts->fv_words[word].prot_id = | |
4727 | ice_prot_id_tbl[rule->type].protocol_id; | |
4728 | lkup_exts->field_mask[word] = | |
4729 | be16_to_cpu(((__force __be16 *)&rule->m_u)[j]); | |
4730 | word++; | |
4731 | } | |
4732 | ||
4733 | ret_val = word - lkup_exts->n_val_words; | |
4734 | lkup_exts->n_val_words = word; | |
4735 | ||
4736 | return ret_val; | |
4737 | } | |
4738 | ||
4739 | /** | |
4740 | * ice_create_first_fit_recp_def - Create a recipe grouping | |
4741 | * @hw: pointer to the hardware structure | |
4742 | * @lkup_exts: an array of protocol header extractions | |
4743 | * @rg_list: pointer to a list that stores new recipe groups | |
4744 | * @recp_cnt: pointer to a variable that stores returned number of recipe groups | |
4745 | * | |
4746 | * Using first fit algorithm, take all the words that are still not done | |
4747 | * and start grouping them in 4-word groups. Each group makes up one | |
4748 | * recipe. | |
4749 | */ | |
5e24d598 | 4750 | static int |
fd2a6b71 DN |
4751 | ice_create_first_fit_recp_def(struct ice_hw *hw, |
4752 | struct ice_prot_lkup_ext *lkup_exts, | |
4753 | struct list_head *rg_list, | |
4754 | u8 *recp_cnt) | |
4755 | { | |
4756 | struct ice_pref_recipe_group *grp = NULL; | |
4757 | u8 j; | |
4758 | ||
4759 | *recp_cnt = 0; | |
4760 | ||
4761 | /* Walk through every word in the rule to check if it is not done. If so | |
4762 | * then this word needs to be part of a new recipe. | |
4763 | */ | |
4764 | for (j = 0; j < lkup_exts->n_val_words; j++) | |
4765 | if (!test_bit(j, lkup_exts->done)) { | |
4766 | if (!grp || | |
4767 | grp->n_val_pairs == ICE_NUM_WORDS_RECIPE) { | |
4768 | struct ice_recp_grp_entry *entry; | |
4769 | ||
4770 | entry = devm_kzalloc(ice_hw_to_dev(hw), | |
4771 | sizeof(*entry), | |
4772 | GFP_KERNEL); | |
4773 | if (!entry) | |
d54699e2 | 4774 | return -ENOMEM; |
fd2a6b71 DN |
4775 | list_add(&entry->l_entry, rg_list); |
4776 | grp = &entry->r_group; | |
4777 | (*recp_cnt)++; | |
4778 | } | |
4779 | ||
4780 | grp->pairs[grp->n_val_pairs].prot_id = | |
4781 | lkup_exts->fv_words[j].prot_id; | |
4782 | grp->pairs[grp->n_val_pairs].off = | |
4783 | lkup_exts->fv_words[j].off; | |
4784 | grp->mask[grp->n_val_pairs] = lkup_exts->field_mask[j]; | |
4785 | grp->n_val_pairs++; | |
4786 | } | |
4787 | ||
4788 | return 0; | |
4789 | } | |
4790 | ||
4791 | /** | |
4792 | * ice_fill_fv_word_index - fill in the field vector indices for a recipe group | |
4793 | * @hw: pointer to the hardware structure | |
4794 | * @fv_list: field vector with the extraction sequence information | |
4795 | * @rg_list: recipe groupings with protocol-offset pairs | |
4796 | * | |
4797 | * Helper function to fill in the field vector indices for protocol-offset | |
4798 | * pairs. These indexes are then ultimately programmed into a recipe. | |
4799 | */ | |
5e24d598 | 4800 | static int |
fd2a6b71 DN |
4801 | ice_fill_fv_word_index(struct ice_hw *hw, struct list_head *fv_list, |
4802 | struct list_head *rg_list) | |
4803 | { | |
4804 | struct ice_sw_fv_list_entry *fv; | |
4805 | struct ice_recp_grp_entry *rg; | |
4806 | struct ice_fv_word *fv_ext; | |
4807 | ||
4808 | if (list_empty(fv_list)) | |
4809 | return 0; | |
4810 | ||
4811 | fv = list_first_entry(fv_list, struct ice_sw_fv_list_entry, | |
4812 | list_entry); | |
4813 | fv_ext = fv->fv_ptr->ew; | |
4814 | ||
4815 | list_for_each_entry(rg, rg_list, l_entry) { | |
4816 | u8 i; | |
4817 | ||
4818 | for (i = 0; i < rg->r_group.n_val_pairs; i++) { | |
4819 | struct ice_fv_word *pr; | |
4820 | bool found = false; | |
4821 | u16 mask; | |
4822 | u8 j; | |
4823 | ||
4824 | pr = &rg->r_group.pairs[i]; | |
4825 | mask = rg->r_group.mask[i]; | |
4826 | ||
4827 | for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++) | |
4828 | if (fv_ext[j].prot_id == pr->prot_id && | |
4829 | fv_ext[j].off == pr->off) { | |
4830 | found = true; | |
4831 | ||
4832 | /* Store index of field vector */ | |
4833 | rg->fv_idx[i] = j; | |
4834 | rg->fv_mask[i] = mask; | |
4835 | break; | |
4836 | } | |
4837 | ||
4838 | /* Protocol/offset could not be found, caller gave an | |
4839 | * invalid pair | |
4840 | */ | |
4841 | if (!found) | |
d54699e2 | 4842 | return -EINVAL; |
fd2a6b71 DN |
4843 | } |
4844 | } | |
4845 | ||
4846 | return 0; | |
4847 | } | |
4848 | ||
4849 | /** | |
4850 | * ice_find_free_recp_res_idx - find free result indexes for recipe | |
4851 | * @hw: pointer to hardware structure | |
4852 | * @profiles: bitmap of profiles that will be associated with the new recipe | |
4853 | * @free_idx: pointer to variable to receive the free index bitmap | |
4854 | * | |
4855 | * The algorithm used here is: | |
4856 | * 1. When creating a new recipe, create a set P which contains all | |
4857 | * Profiles that will be associated with our new recipe | |
4858 | * | |
4859 | * 2. For each Profile p in set P: | |
4860 | * a. Add all recipes associated with Profile p into set R | |
4861 | * b. Optional : PossibleIndexes &= profile[p].possibleIndexes | |
4862 | * [initially PossibleIndexes should be 0xFFFFFFFFFFFFFFFF] | |
4863 | * i. Or just assume they all have the same possible indexes: | |
4864 | * 44, 45, 46, 47 | |
4865 | * i.e., PossibleIndexes = 0x0000F00000000000 | |
4866 | * | |
4867 | * 3. For each Recipe r in set R: | |
4868 | * a. UsedIndexes |= (bitwise or ) recipe[r].res_indexes | |
4869 | * b. FreeIndexes = UsedIndexes ^ PossibleIndexes | |
4870 | * | |
4871 | * FreeIndexes will contain the bits indicating the indexes free for use, | |
4872 | * then the code needs to update the recipe[r].used_result_idx_bits to | |
4873 | * indicate which indexes were selected for use by this recipe. | |
4874 | */ | |
4875 | static u16 | |
4876 | ice_find_free_recp_res_idx(struct ice_hw *hw, const unsigned long *profiles, | |
4877 | unsigned long *free_idx) | |
4878 | { | |
4879 | DECLARE_BITMAP(possible_idx, ICE_MAX_FV_WORDS); | |
4880 | DECLARE_BITMAP(recipes, ICE_MAX_NUM_RECIPES); | |
4881 | DECLARE_BITMAP(used_idx, ICE_MAX_FV_WORDS); | |
4882 | u16 bit; | |
4883 | ||
fd2a6b71 DN |
4884 | bitmap_zero(recipes, ICE_MAX_NUM_RECIPES); |
4885 | bitmap_zero(used_idx, ICE_MAX_FV_WORDS); | |
fd2a6b71 | 4886 | |
2f7ee2a7 | 4887 | bitmap_fill(possible_idx, ICE_MAX_FV_WORDS); |
fd2a6b71 DN |
4888 | |
4889 | /* For each profile we are going to associate the recipe with, add the | |
4890 | * recipes that are associated with that profile. This will give us | |
4891 | * the set of recipes that our recipe may collide with. Also, determine | |
4892 | * what possible result indexes are usable given this set of profiles. | |
4893 | */ | |
4894 | for_each_set_bit(bit, profiles, ICE_MAX_NUM_PROFILES) { | |
4895 | bitmap_or(recipes, recipes, profile_to_recipe[bit], | |
4896 | ICE_MAX_NUM_RECIPES); | |
4897 | bitmap_and(possible_idx, possible_idx, | |
4898 | hw->switch_info->prof_res_bm[bit], | |
4899 | ICE_MAX_FV_WORDS); | |
4900 | } | |
4901 | ||
4902 | /* For each recipe that our new recipe may collide with, determine | |
4903 | * which indexes have been used. | |
4904 | */ | |
4905 | for_each_set_bit(bit, recipes, ICE_MAX_NUM_RECIPES) | |
4906 | bitmap_or(used_idx, used_idx, | |
4907 | hw->switch_info->recp_list[bit].res_idxs, | |
4908 | ICE_MAX_FV_WORDS); | |
4909 | ||
4910 | bitmap_xor(free_idx, used_idx, possible_idx, ICE_MAX_FV_WORDS); | |
4911 | ||
4912 | /* return number of free indexes */ | |
4913 | return (u16)bitmap_weight(free_idx, ICE_MAX_FV_WORDS); | |
4914 | } | |
4915 | ||
4916 | /** | |
4917 | * ice_add_sw_recipe - function to call AQ calls to create switch recipe | |
4918 | * @hw: pointer to hardware structure | |
4919 | * @rm: recipe management list entry | |
fd2a6b71 DN |
4920 | * @profiles: bitmap of profiles that will be associated. |
4921 | */ | |
5e24d598 | 4922 | static int |
fd2a6b71 | 4923 | ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm, |
8b032a55 | 4924 | unsigned long *profiles) |
fd2a6b71 DN |
4925 | { |
4926 | DECLARE_BITMAP(result_idx_bm, ICE_MAX_FV_WORDS); | |
4927 | struct ice_aqc_recipe_data_elem *tmp; | |
4928 | struct ice_aqc_recipe_data_elem *buf; | |
4929 | struct ice_recp_grp_entry *entry; | |
fd2a6b71 DN |
4930 | u16 free_res_idx; |
4931 | u16 recipe_count; | |
4932 | u8 chain_idx; | |
4933 | u8 recps = 0; | |
5518ac2a | 4934 | int status; |
fd2a6b71 DN |
4935 | |
4936 | /* When more than one recipe are required, another recipe is needed to | |
4937 | * chain them together. Matching a tunnel metadata ID takes up one of | |
4938 | * the match fields in the chaining recipe reducing the number of | |
4939 | * chained recipes by one. | |
4940 | */ | |
4941 | /* check number of free result indices */ | |
4942 | bitmap_zero(result_idx_bm, ICE_MAX_FV_WORDS); | |
4943 | free_res_idx = ice_find_free_recp_res_idx(hw, profiles, result_idx_bm); | |
4944 | ||
4945 | ice_debug(hw, ICE_DBG_SW, "Result idx slots: %d, need %d\n", | |
4946 | free_res_idx, rm->n_grp_count); | |
4947 | ||
4948 | if (rm->n_grp_count > 1) { | |
4949 | if (rm->n_grp_count > free_res_idx) | |
d54699e2 | 4950 | return -ENOSPC; |
fd2a6b71 DN |
4951 | |
4952 | rm->n_grp_count++; | |
4953 | } | |
4954 | ||
4955 | if (rm->n_grp_count > ICE_MAX_CHAIN_RECIPE) | |
d54699e2 | 4956 | return -ENOSPC; |
fd2a6b71 DN |
4957 | |
4958 | tmp = kcalloc(ICE_MAX_NUM_RECIPES, sizeof(*tmp), GFP_KERNEL); | |
4959 | if (!tmp) | |
d54699e2 | 4960 | return -ENOMEM; |
fd2a6b71 DN |
4961 | |
4962 | buf = devm_kcalloc(ice_hw_to_dev(hw), rm->n_grp_count, sizeof(*buf), | |
4963 | GFP_KERNEL); | |
4964 | if (!buf) { | |
d54699e2 | 4965 | status = -ENOMEM; |
fd2a6b71 DN |
4966 | goto err_mem; |
4967 | } | |
4968 | ||
4969 | bitmap_zero(rm->r_bitmap, ICE_MAX_NUM_RECIPES); | |
4970 | recipe_count = ICE_MAX_NUM_RECIPES; | |
4971 | status = ice_aq_get_recipe(hw, tmp, &recipe_count, ICE_SW_LKUP_MAC, | |
4972 | NULL); | |
4973 | if (status || recipe_count == 0) | |
4974 | goto err_unroll; | |
4975 | ||
4976 | /* Allocate the recipe resources, and configure them according to the | |
4977 | * match fields from protocol headers and extracted field vectors. | |
4978 | */ | |
4979 | chain_idx = find_first_bit(result_idx_bm, ICE_MAX_FV_WORDS); | |
4980 | list_for_each_entry(entry, &rm->rg_list, l_entry) { | |
4981 | u8 i; | |
4982 | ||
4983 | status = ice_alloc_recipe(hw, &entry->rid); | |
4984 | if (status) | |
4985 | goto err_unroll; | |
4986 | ||
4987 | /* Clear the result index of the located recipe, as this will be | |
4988 | * updated, if needed, later in the recipe creation process. | |
4989 | */ | |
4990 | tmp[0].content.result_indx = 0; | |
4991 | ||
4992 | buf[recps] = tmp[0]; | |
4993 | buf[recps].recipe_indx = (u8)entry->rid; | |
4994 | /* if the recipe is a non-root recipe RID should be programmed | |
4995 | * as 0 for the rules to be applied correctly. | |
4996 | */ | |
4997 | buf[recps].content.rid = 0; | |
4998 | memset(&buf[recps].content.lkup_indx, 0, | |
4999 | sizeof(buf[recps].content.lkup_indx)); | |
5000 | ||
5001 | /* All recipes use look-up index 0 to match switch ID. */ | |
5002 | buf[recps].content.lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX; | |
5003 | buf[recps].content.mask[0] = | |
5004 | cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK); | |
5005 | /* Setup lkup_indx 1..4 to INVALID/ignore and set the mask | |
5006 | * to be 0 | |
5007 | */ | |
5008 | for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) { | |
5009 | buf[recps].content.lkup_indx[i] = 0x80; | |
5010 | buf[recps].content.mask[i] = 0; | |
5011 | } | |
5012 | ||
5013 | for (i = 0; i < entry->r_group.n_val_pairs; i++) { | |
5014 | buf[recps].content.lkup_indx[i + 1] = entry->fv_idx[i]; | |
5015 | buf[recps].content.mask[i + 1] = | |
5016 | cpu_to_le16(entry->fv_mask[i]); | |
5017 | } | |
5018 | ||
5019 | if (rm->n_grp_count > 1) { | |
5020 | /* Checks to see if there really is a valid result index | |
5021 | * that can be used. | |
5022 | */ | |
5023 | if (chain_idx >= ICE_MAX_FV_WORDS) { | |
5024 | ice_debug(hw, ICE_DBG_SW, "No chain index available\n"); | |
d54699e2 | 5025 | status = -ENOSPC; |
fd2a6b71 DN |
5026 | goto err_unroll; |
5027 | } | |
5028 | ||
5029 | entry->chain_idx = chain_idx; | |
5030 | buf[recps].content.result_indx = | |
5031 | ICE_AQ_RECIPE_RESULT_EN | | |
5032 | ((chain_idx << ICE_AQ_RECIPE_RESULT_DATA_S) & | |
5033 | ICE_AQ_RECIPE_RESULT_DATA_M); | |
5034 | clear_bit(chain_idx, result_idx_bm); | |
5035 | chain_idx = find_first_bit(result_idx_bm, | |
5036 | ICE_MAX_FV_WORDS); | |
5037 | } | |
5038 | ||
5039 | /* fill recipe dependencies */ | |
5040 | bitmap_zero((unsigned long *)buf[recps].recipe_bitmap, | |
5041 | ICE_MAX_NUM_RECIPES); | |
5042 | set_bit(buf[recps].recipe_indx, | |
5043 | (unsigned long *)buf[recps].recipe_bitmap); | |
5044 | buf[recps].content.act_ctrl_fwd_priority = rm->priority; | |
5045 | recps++; | |
5046 | } | |
5047 | ||
5048 | if (rm->n_grp_count == 1) { | |
5049 | rm->root_rid = buf[0].recipe_indx; | |
5050 | set_bit(buf[0].recipe_indx, rm->r_bitmap); | |
5051 | buf[0].content.rid = rm->root_rid | ICE_AQ_RECIPE_ID_IS_ROOT; | |
5052 | if (sizeof(buf[0].recipe_bitmap) >= sizeof(rm->r_bitmap)) { | |
5053 | memcpy(buf[0].recipe_bitmap, rm->r_bitmap, | |
5054 | sizeof(buf[0].recipe_bitmap)); | |
5055 | } else { | |
d54699e2 | 5056 | status = -EINVAL; |
fd2a6b71 DN |
5057 | goto err_unroll; |
5058 | } | |
5059 | /* Applicable only for ROOT_RECIPE, set the fwd_priority for | |
5060 | * the recipe which is getting created if specified | |
5061 | * by user. Usually any advanced switch filter, which results | |
5062 | * into new extraction sequence, ended up creating a new recipe | |
5063 | * of type ROOT and usually recipes are associated with profiles | |
5064 | * Switch rule referreing newly created recipe, needs to have | |
5065 | * either/or 'fwd' or 'join' priority, otherwise switch rule | |
5066 | * evaluation will not happen correctly. In other words, if | |
5067 | * switch rule to be evaluated on priority basis, then recipe | |
5068 | * needs to have priority, otherwise it will be evaluated last. | |
5069 | */ | |
5070 | buf[0].content.act_ctrl_fwd_priority = rm->priority; | |
5071 | } else { | |
5072 | struct ice_recp_grp_entry *last_chain_entry; | |
5073 | u16 rid, i; | |
5074 | ||
5075 | /* Allocate the last recipe that will chain the outcomes of the | |
5076 | * other recipes together | |
5077 | */ | |
5078 | status = ice_alloc_recipe(hw, &rid); | |
5079 | if (status) | |
5080 | goto err_unroll; | |
5081 | ||
5082 | buf[recps].recipe_indx = (u8)rid; | |
5083 | buf[recps].content.rid = (u8)rid; | |
5084 | buf[recps].content.rid |= ICE_AQ_RECIPE_ID_IS_ROOT; | |
5085 | /* the new entry created should also be part of rg_list to | |
5086 | * make sure we have complete recipe | |
5087 | */ | |
5088 | last_chain_entry = devm_kzalloc(ice_hw_to_dev(hw), | |
5089 | sizeof(*last_chain_entry), | |
5090 | GFP_KERNEL); | |
5091 | if (!last_chain_entry) { | |
d54699e2 | 5092 | status = -ENOMEM; |
fd2a6b71 DN |
5093 | goto err_unroll; |
5094 | } | |
5095 | last_chain_entry->rid = rid; | |
5096 | memset(&buf[recps].content.lkup_indx, 0, | |
5097 | sizeof(buf[recps].content.lkup_indx)); | |
5098 | /* All recipes use look-up index 0 to match switch ID. */ | |
5099 | buf[recps].content.lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX; | |
5100 | buf[recps].content.mask[0] = | |
5101 | cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK); | |
5102 | for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) { | |
5103 | buf[recps].content.lkup_indx[i] = | |
5104 | ICE_AQ_RECIPE_LKUP_IGNORE; | |
5105 | buf[recps].content.mask[i] = 0; | |
5106 | } | |
5107 | ||
5108 | i = 1; | |
5109 | /* update r_bitmap with the recp that is used for chaining */ | |
5110 | set_bit(rid, rm->r_bitmap); | |
5111 | /* this is the recipe that chains all the other recipes so it | |
5112 | * should not have a chaining ID to indicate the same | |
5113 | */ | |
5114 | last_chain_entry->chain_idx = ICE_INVAL_CHAIN_IND; | |
5115 | list_for_each_entry(entry, &rm->rg_list, l_entry) { | |
5116 | last_chain_entry->fv_idx[i] = entry->chain_idx; | |
5117 | buf[recps].content.lkup_indx[i] = entry->chain_idx; | |
5118 | buf[recps].content.mask[i++] = cpu_to_le16(0xFFFF); | |
5119 | set_bit(entry->rid, rm->r_bitmap); | |
5120 | } | |
5121 | list_add(&last_chain_entry->l_entry, &rm->rg_list); | |
5122 | if (sizeof(buf[recps].recipe_bitmap) >= | |
5123 | sizeof(rm->r_bitmap)) { | |
5124 | memcpy(buf[recps].recipe_bitmap, rm->r_bitmap, | |
5125 | sizeof(buf[recps].recipe_bitmap)); | |
5126 | } else { | |
d54699e2 | 5127 | status = -EINVAL; |
fd2a6b71 DN |
5128 | goto err_unroll; |
5129 | } | |
5130 | buf[recps].content.act_ctrl_fwd_priority = rm->priority; | |
5131 | ||
fd2a6b71 DN |
5132 | recps++; |
5133 | rm->root_rid = (u8)rid; | |
5134 | } | |
5135 | status = ice_acquire_change_lock(hw, ICE_RES_WRITE); | |
5136 | if (status) | |
5137 | goto err_unroll; | |
5138 | ||
5139 | status = ice_aq_add_recipe(hw, buf, rm->n_grp_count, NULL); | |
5140 | ice_release_change_lock(hw); | |
5141 | if (status) | |
5142 | goto err_unroll; | |
5143 | ||
5144 | /* Every recipe that just got created add it to the recipe | |
5145 | * book keeping list | |
5146 | */ | |
5147 | list_for_each_entry(entry, &rm->rg_list, l_entry) { | |
5148 | struct ice_switch_info *sw = hw->switch_info; | |
5149 | bool is_root, idx_found = false; | |
5150 | struct ice_sw_recipe *recp; | |
5151 | u16 idx, buf_idx = 0; | |
5152 | ||
5153 | /* find buffer index for copying some data */ | |
5154 | for (idx = 0; idx < rm->n_grp_count; idx++) | |
5155 | if (buf[idx].recipe_indx == entry->rid) { | |
5156 | buf_idx = idx; | |
5157 | idx_found = true; | |
5158 | } | |
5159 | ||
5160 | if (!idx_found) { | |
d54699e2 | 5161 | status = -EIO; |
fd2a6b71 DN |
5162 | goto err_unroll; |
5163 | } | |
5164 | ||
5165 | recp = &sw->recp_list[entry->rid]; | |
5166 | is_root = (rm->root_rid == entry->rid); | |
5167 | recp->is_root = is_root; | |
5168 | ||
5169 | recp->root_rid = entry->rid; | |
5170 | recp->big_recp = (is_root && rm->n_grp_count > 1); | |
5171 | ||
5172 | memcpy(&recp->ext_words, entry->r_group.pairs, | |
5173 | entry->r_group.n_val_pairs * sizeof(struct ice_fv_word)); | |
5174 | ||
5175 | memcpy(recp->r_bitmap, buf[buf_idx].recipe_bitmap, | |
5176 | sizeof(recp->r_bitmap)); | |
5177 | ||
5178 | /* Copy non-result fv index values and masks to recipe. This | |
5179 | * call will also update the result recipe bitmask. | |
5180 | */ | |
5181 | ice_collect_result_idx(&buf[buf_idx], recp); | |
5182 | ||
5183 | /* for non-root recipes, also copy to the root, this allows | |
5184 | * easier matching of a complete chained recipe | |
5185 | */ | |
5186 | if (!is_root) | |
5187 | ice_collect_result_idx(&buf[buf_idx], | |
5188 | &sw->recp_list[rm->root_rid]); | |
5189 | ||
5190 | recp->n_ext_words = entry->r_group.n_val_pairs; | |
5191 | recp->chain_idx = entry->chain_idx; | |
5192 | recp->priority = buf[buf_idx].content.act_ctrl_fwd_priority; | |
5193 | recp->n_grp_count = rm->n_grp_count; | |
8b032a55 | 5194 | recp->tun_type = rm->tun_type; |
fd2a6b71 DN |
5195 | recp->recp_created = true; |
5196 | } | |
5197 | rm->root_buf = buf; | |
5198 | kfree(tmp); | |
5199 | return status; | |
5200 | ||
5201 | err_unroll: | |
5202 | err_mem: | |
5203 | kfree(tmp); | |
5204 | devm_kfree(ice_hw_to_dev(hw), buf); | |
5205 | return status; | |
5206 | } | |
5207 | ||
5208 | /** | |
5209 | * ice_create_recipe_group - creates recipe group | |
5210 | * @hw: pointer to hardware structure | |
5211 | * @rm: recipe management list entry | |
5212 | * @lkup_exts: lookup elements | |
5213 | */ | |
5e24d598 | 5214 | static int |
fd2a6b71 DN |
5215 | ice_create_recipe_group(struct ice_hw *hw, struct ice_sw_recipe *rm, |
5216 | struct ice_prot_lkup_ext *lkup_exts) | |
5217 | { | |
fd2a6b71 | 5218 | u8 recp_count = 0; |
5518ac2a | 5219 | int status; |
fd2a6b71 DN |
5220 | |
5221 | rm->n_grp_count = 0; | |
5222 | ||
5223 | /* Create recipes for words that are marked not done by packing them | |
5224 | * as best fit. | |
5225 | */ | |
5226 | status = ice_create_first_fit_recp_def(hw, lkup_exts, | |
5227 | &rm->rg_list, &recp_count); | |
5228 | if (!status) { | |
5229 | rm->n_grp_count += recp_count; | |
5230 | rm->n_ext_words = lkup_exts->n_val_words; | |
5231 | memcpy(&rm->ext_words, lkup_exts->fv_words, | |
5232 | sizeof(rm->ext_words)); | |
5233 | memcpy(rm->word_masks, lkup_exts->field_mask, | |
5234 | sizeof(rm->word_masks)); | |
5235 | } | |
5236 | ||
5237 | return status; | |
5238 | } | |
5239 | ||
8b032a55 MS |
5240 | /** |
5241 | * ice_tun_type_match_word - determine if tun type needs a match mask | |
5242 | * @tun_type: tunnel type | |
5243 | * @mask: mask to be used for the tunnel | |
5244 | */ | |
5245 | static bool ice_tun_type_match_word(enum ice_sw_tunnel_type tun_type, u16 *mask) | |
5246 | { | |
5247 | switch (tun_type) { | |
5248 | case ICE_SW_TUN_GENEVE: | |
5249 | case ICE_SW_TUN_VXLAN: | |
f0a35040 | 5250 | case ICE_SW_TUN_NVGRE: |
9a225f81 MS |
5251 | case ICE_SW_TUN_GTPU: |
5252 | case ICE_SW_TUN_GTPC: | |
8b032a55 MS |
5253 | *mask = ICE_TUN_FLAG_MASK; |
5254 | return true; | |
5255 | ||
5256 | default: | |
5257 | *mask = 0; | |
5258 | return false; | |
5259 | } | |
5260 | } | |
5261 | ||
5262 | /** | |
5263 | * ice_add_special_words - Add words that are not protocols, such as metadata | |
5264 | * @rinfo: other information regarding the rule e.g. priority and action info | |
5265 | * @lkup_exts: lookup word structure | |
ea71b967 | 5266 | * @dvm_ena: is double VLAN mode enabled |
8b032a55 | 5267 | */ |
d54699e2 | 5268 | static int |
8b032a55 | 5269 | ice_add_special_words(struct ice_adv_rule_info *rinfo, |
ea71b967 | 5270 | struct ice_prot_lkup_ext *lkup_exts, bool dvm_ena) |
8b032a55 MS |
5271 | { |
5272 | u16 mask; | |
5273 | ||
5274 | /* If this is a tunneled packet, then add recipe index to match the | |
5275 | * tunnel bit in the packet metadata flags. | |
5276 | */ | |
5277 | if (ice_tun_type_match_word(rinfo->tun_type, &mask)) { | |
5278 | if (lkup_exts->n_val_words < ICE_MAX_CHAIN_WORDS) { | |
5279 | u8 word = lkup_exts->n_val_words++; | |
5280 | ||
5281 | lkup_exts->fv_words[word].prot_id = ICE_META_DATA_ID_HW; | |
5282 | lkup_exts->fv_words[word].off = ICE_TUN_FLAG_MDID_OFF; | |
5283 | lkup_exts->field_mask[word] = mask; | |
5284 | } else { | |
d54699e2 | 5285 | return -ENOSPC; |
8b032a55 MS |
5286 | } |
5287 | } | |
5288 | ||
ea71b967 MSM |
5289 | if (rinfo->vlan_type != 0 && dvm_ena) { |
5290 | if (lkup_exts->n_val_words < ICE_MAX_CHAIN_WORDS) { | |
5291 | u8 word = lkup_exts->n_val_words++; | |
5292 | ||
5293 | lkup_exts->fv_words[word].prot_id = ICE_META_DATA_ID_HW; | |
5294 | lkup_exts->fv_words[word].off = ICE_VLAN_FLAG_MDID_OFF; | |
5295 | lkup_exts->field_mask[word] = | |
5296 | ICE_PKT_FLAGS_0_TO_15_VLAN_FLAGS_MASK; | |
5297 | } else { | |
5298 | return -ENOSPC; | |
5299 | } | |
5300 | } | |
5301 | ||
8b032a55 MS |
5302 | return 0; |
5303 | } | |
5304 | ||
fd2a6b71 DN |
5305 | /* ice_get_compat_fv_bitmap - Get compatible field vector bitmap for rule |
5306 | * @hw: pointer to hardware structure | |
5307 | * @rinfo: other information regarding the rule e.g. priority and action info | |
5308 | * @bm: pointer to memory for returning the bitmap of field vectors | |
5309 | */ | |
5310 | static void | |
5311 | ice_get_compat_fv_bitmap(struct ice_hw *hw, struct ice_adv_rule_info *rinfo, | |
5312 | unsigned long *bm) | |
5313 | { | |
8b032a55 MS |
5314 | enum ice_prof_type prof_type; |
5315 | ||
fd2a6b71 DN |
5316 | bitmap_zero(bm, ICE_MAX_NUM_PROFILES); |
5317 | ||
8b032a55 MS |
5318 | switch (rinfo->tun_type) { |
5319 | case ICE_NON_TUN: | |
5320 | prof_type = ICE_PROF_NON_TUN; | |
5321 | break; | |
5322 | case ICE_ALL_TUNNELS: | |
5323 | prof_type = ICE_PROF_TUN_ALL; | |
5324 | break; | |
5325 | case ICE_SW_TUN_GENEVE: | |
5326 | case ICE_SW_TUN_VXLAN: | |
5327 | prof_type = ICE_PROF_TUN_UDP; | |
5328 | break; | |
f0a35040 MS |
5329 | case ICE_SW_TUN_NVGRE: |
5330 | prof_type = ICE_PROF_TUN_GRE; | |
5331 | break; | |
9a225f81 MS |
5332 | case ICE_SW_TUN_GTPU: |
5333 | prof_type = ICE_PROF_TUN_GTPU; | |
5334 | break; | |
5335 | case ICE_SW_TUN_GTPC: | |
5336 | prof_type = ICE_PROF_TUN_GTPC; | |
5337 | break; | |
b70bc066 | 5338 | case ICE_SW_TUN_AND_NON_TUN: |
8b032a55 MS |
5339 | default: |
5340 | prof_type = ICE_PROF_ALL; | |
5341 | break; | |
5342 | } | |
5343 | ||
5344 | ice_get_sw_fv_bitmap(hw, prof_type, bm); | |
fd2a6b71 DN |
5345 | } |
5346 | ||
5347 | /** | |
5348 | * ice_add_adv_recipe - Add an advanced recipe that is not part of the default | |
5349 | * @hw: pointer to hardware structure | |
5350 | * @lkups: lookup elements or match criteria for the advanced recipe, one | |
5351 | * structure per protocol header | |
5352 | * @lkups_cnt: number of protocols | |
5353 | * @rinfo: other information regarding the rule e.g. priority and action info | |
5354 | * @rid: return the recipe ID of the recipe created | |
5355 | */ | |
5e24d598 | 5356 | static int |
fd2a6b71 DN |
5357 | ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, |
5358 | u16 lkups_cnt, struct ice_adv_rule_info *rinfo, u16 *rid) | |
5359 | { | |
5360 | DECLARE_BITMAP(fv_bitmap, ICE_MAX_NUM_PROFILES); | |
5361 | DECLARE_BITMAP(profiles, ICE_MAX_NUM_PROFILES); | |
5362 | struct ice_prot_lkup_ext *lkup_exts; | |
5363 | struct ice_recp_grp_entry *r_entry; | |
5364 | struct ice_sw_fv_list_entry *fvit; | |
5365 | struct ice_recp_grp_entry *r_tmp; | |
5366 | struct ice_sw_fv_list_entry *tmp; | |
fd2a6b71 | 5367 | struct ice_sw_recipe *rm; |
5518ac2a | 5368 | int status = 0; |
fd2a6b71 DN |
5369 | u8 i; |
5370 | ||
5371 | if (!lkups_cnt) | |
d54699e2 | 5372 | return -EINVAL; |
fd2a6b71 DN |
5373 | |
5374 | lkup_exts = kzalloc(sizeof(*lkup_exts), GFP_KERNEL); | |
5375 | if (!lkup_exts) | |
d54699e2 | 5376 | return -ENOMEM; |
fd2a6b71 DN |
5377 | |
5378 | /* Determine the number of words to be matched and if it exceeds a | |
5379 | * recipe's restrictions | |
5380 | */ | |
5381 | for (i = 0; i < lkups_cnt; i++) { | |
5382 | u16 count; | |
5383 | ||
5384 | if (lkups[i].type >= ICE_PROTOCOL_LAST) { | |
d54699e2 | 5385 | status = -EIO; |
fd2a6b71 DN |
5386 | goto err_free_lkup_exts; |
5387 | } | |
5388 | ||
5389 | count = ice_fill_valid_words(&lkups[i], lkup_exts); | |
5390 | if (!count) { | |
d54699e2 | 5391 | status = -EIO; |
fd2a6b71 DN |
5392 | goto err_free_lkup_exts; |
5393 | } | |
5394 | } | |
5395 | ||
5396 | rm = kzalloc(sizeof(*rm), GFP_KERNEL); | |
5397 | if (!rm) { | |
d54699e2 | 5398 | status = -ENOMEM; |
fd2a6b71 DN |
5399 | goto err_free_lkup_exts; |
5400 | } | |
5401 | ||
5402 | /* Get field vectors that contain fields extracted from all the protocol | |
5403 | * headers being programmed. | |
5404 | */ | |
5405 | INIT_LIST_HEAD(&rm->fv_list); | |
5406 | INIT_LIST_HEAD(&rm->rg_list); | |
5407 | ||
5408 | /* Get bitmap of field vectors (profiles) that are compatible with the | |
5409 | * rule request; only these will be searched in the subsequent call to | |
e5dd661b | 5410 | * ice_get_sw_fv_list. |
fd2a6b71 DN |
5411 | */ |
5412 | ice_get_compat_fv_bitmap(hw, rinfo, fv_bitmap); | |
5413 | ||
e5dd661b | 5414 | status = ice_get_sw_fv_list(hw, lkup_exts, fv_bitmap, &rm->fv_list); |
fd2a6b71 DN |
5415 | if (status) |
5416 | goto err_unroll; | |
5417 | ||
8b032a55 MS |
5418 | /* Create any special protocol/offset pairs, such as looking at tunnel |
5419 | * bits by extracting metadata | |
5420 | */ | |
ea71b967 | 5421 | status = ice_add_special_words(rinfo, lkup_exts, ice_is_dvm_ena(hw)); |
8b032a55 | 5422 | if (status) |
4a606ce6 | 5423 | goto err_unroll; |
8b032a55 | 5424 | |
fd2a6b71 DN |
5425 | /* Group match words into recipes using preferred recipe grouping |
5426 | * criteria. | |
5427 | */ | |
5428 | status = ice_create_recipe_group(hw, rm, lkup_exts); | |
5429 | if (status) | |
5430 | goto err_unroll; | |
5431 | ||
5432 | /* set the recipe priority if specified */ | |
5433 | rm->priority = (u8)rinfo->priority; | |
5434 | ||
5435 | /* Find offsets from the field vector. Pick the first one for all the | |
5436 | * recipes. | |
5437 | */ | |
5438 | status = ice_fill_fv_word_index(hw, &rm->fv_list, &rm->rg_list); | |
5439 | if (status) | |
5440 | goto err_unroll; | |
5441 | ||
5442 | /* get bitmap of all profiles the recipe will be associated with */ | |
5443 | bitmap_zero(profiles, ICE_MAX_NUM_PROFILES); | |
5444 | list_for_each_entry(fvit, &rm->fv_list, list_entry) { | |
5445 | ice_debug(hw, ICE_DBG_SW, "profile: %d\n", fvit->profile_id); | |
5446 | set_bit((u16)fvit->profile_id, profiles); | |
5447 | } | |
5448 | ||
5449 | /* Look for a recipe which matches our requested fv / mask list */ | |
de6acd1c | 5450 | *rid = ice_find_recp(hw, lkup_exts, rinfo->tun_type); |
fd2a6b71 DN |
5451 | if (*rid < ICE_MAX_NUM_RECIPES) |
5452 | /* Success if found a recipe that match the existing criteria */ | |
5453 | goto err_unroll; | |
5454 | ||
de6acd1c | 5455 | rm->tun_type = rinfo->tun_type; |
fd2a6b71 | 5456 | /* Recipe we need does not exist, add a recipe */ |
8b032a55 | 5457 | status = ice_add_sw_recipe(hw, rm, profiles); |
fd2a6b71 DN |
5458 | if (status) |
5459 | goto err_unroll; | |
5460 | ||
5461 | /* Associate all the recipes created with all the profiles in the | |
5462 | * common field vector. | |
5463 | */ | |
5464 | list_for_each_entry(fvit, &rm->fv_list, list_entry) { | |
5465 | DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES); | |
5466 | u16 j; | |
5467 | ||
5468 | status = ice_aq_get_recipe_to_profile(hw, fvit->profile_id, | |
5469 | (u8 *)r_bitmap, NULL); | |
5470 | if (status) | |
5471 | goto err_unroll; | |
5472 | ||
5473 | bitmap_or(r_bitmap, r_bitmap, rm->r_bitmap, | |
5474 | ICE_MAX_NUM_RECIPES); | |
5475 | status = ice_acquire_change_lock(hw, ICE_RES_WRITE); | |
5476 | if (status) | |
5477 | goto err_unroll; | |
5478 | ||
5479 | status = ice_aq_map_recipe_to_profile(hw, fvit->profile_id, | |
5480 | (u8 *)r_bitmap, | |
5481 | NULL); | |
5482 | ice_release_change_lock(hw); | |
5483 | ||
5484 | if (status) | |
5485 | goto err_unroll; | |
5486 | ||
5487 | /* Update profile to recipe bitmap array */ | |
5488 | bitmap_copy(profile_to_recipe[fvit->profile_id], r_bitmap, | |
5489 | ICE_MAX_NUM_RECIPES); | |
5490 | ||
5491 | /* Update recipe to profile bitmap array */ | |
5492 | for_each_set_bit(j, rm->r_bitmap, ICE_MAX_NUM_RECIPES) | |
5493 | set_bit((u16)fvit->profile_id, recipe_to_profile[j]); | |
5494 | } | |
5495 | ||
5496 | *rid = rm->root_rid; | |
5497 | memcpy(&hw->switch_info->recp_list[*rid].lkup_exts, lkup_exts, | |
5498 | sizeof(*lkup_exts)); | |
5499 | err_unroll: | |
5500 | list_for_each_entry_safe(r_entry, r_tmp, &rm->rg_list, l_entry) { | |
5501 | list_del(&r_entry->l_entry); | |
5502 | devm_kfree(ice_hw_to_dev(hw), r_entry); | |
5503 | } | |
5504 | ||
5505 | list_for_each_entry_safe(fvit, tmp, &rm->fv_list, list_entry) { | |
5506 | list_del(&fvit->list_entry); | |
5507 | devm_kfree(ice_hw_to_dev(hw), fvit); | |
5508 | } | |
5509 | ||
5510 | if (rm->root_buf) | |
5511 | devm_kfree(ice_hw_to_dev(hw), rm->root_buf); | |
5512 | ||
5513 | kfree(rm); | |
5514 | ||
5515 | err_free_lkup_exts: | |
5516 | kfree(lkup_exts); | |
5517 | ||
5518 | return status; | |
5519 | } | |
5520 | ||
26395726 MSM |
5521 | /** |
5522 | * ice_dummy_packet_add_vlan - insert VLAN header to dummy pkt | |
5523 | * | |
5524 | * @dummy_pkt: dummy packet profile pattern to which VLAN tag(s) will be added | |
5525 | * @num_vlan: number of VLAN tags | |
5526 | */ | |
5527 | static struct ice_dummy_pkt_profile * | |
5528 | ice_dummy_packet_add_vlan(const struct ice_dummy_pkt_profile *dummy_pkt, | |
5529 | u32 num_vlan) | |
5530 | { | |
5531 | struct ice_dummy_pkt_profile *profile; | |
5532 | struct ice_dummy_pkt_offsets *offsets; | |
5533 | u32 buf_len, off, etype_off, i; | |
5534 | u8 *pkt; | |
5535 | ||
5536 | if (num_vlan < 1 || num_vlan > 2) | |
5537 | return ERR_PTR(-EINVAL); | |
5538 | ||
5539 | off = num_vlan * VLAN_HLEN; | |
5540 | ||
5541 | buf_len = array_size(num_vlan, sizeof(ice_dummy_vlan_packet_offsets)) + | |
5542 | dummy_pkt->offsets_len; | |
5543 | offsets = kzalloc(buf_len, GFP_KERNEL); | |
5544 | if (!offsets) | |
5545 | return ERR_PTR(-ENOMEM); | |
5546 | ||
5547 | offsets[0] = dummy_pkt->offsets[0]; | |
5548 | if (num_vlan == 2) { | |
5549 | offsets[1] = ice_dummy_qinq_packet_offsets[0]; | |
5550 | offsets[2] = ice_dummy_qinq_packet_offsets[1]; | |
5551 | } else if (num_vlan == 1) { | |
5552 | offsets[1] = ice_dummy_vlan_packet_offsets[0]; | |
5553 | } | |
5554 | ||
5555 | for (i = 1; dummy_pkt->offsets[i].type != ICE_PROTOCOL_LAST; i++) { | |
5556 | offsets[i + num_vlan].type = dummy_pkt->offsets[i].type; | |
5557 | offsets[i + num_vlan].offset = | |
5558 | dummy_pkt->offsets[i].offset + off; | |
5559 | } | |
5560 | offsets[i + num_vlan] = dummy_pkt->offsets[i]; | |
5561 | ||
5562 | etype_off = dummy_pkt->offsets[1].offset; | |
5563 | ||
5564 | buf_len = array_size(num_vlan, sizeof(ice_dummy_vlan_packet)) + | |
5565 | dummy_pkt->pkt_len; | |
5566 | pkt = kzalloc(buf_len, GFP_KERNEL); | |
5567 | if (!pkt) { | |
5568 | kfree(offsets); | |
5569 | return ERR_PTR(-ENOMEM); | |
5570 | } | |
5571 | ||
5572 | memcpy(pkt, dummy_pkt->pkt, etype_off); | |
5573 | memcpy(pkt + etype_off, | |
5574 | num_vlan == 2 ? ice_dummy_qinq_packet : ice_dummy_vlan_packet, | |
5575 | off); | |
5576 | memcpy(pkt + etype_off + off, dummy_pkt->pkt + etype_off, | |
5577 | dummy_pkt->pkt_len - etype_off); | |
5578 | ||
5579 | profile = kzalloc(sizeof(*profile), GFP_KERNEL); | |
5580 | if (!profile) { | |
5581 | kfree(offsets); | |
5582 | kfree(pkt); | |
5583 | return ERR_PTR(-ENOMEM); | |
5584 | } | |
5585 | ||
5586 | profile->offsets = offsets; | |
5587 | profile->pkt = pkt; | |
5588 | profile->pkt_len = buf_len; | |
5589 | profile->match |= ICE_PKT_KMALLOC; | |
5590 | ||
5591 | return profile; | |
5592 | } | |
5593 | ||
0f94570d GK |
5594 | /** |
5595 | * ice_find_dummy_packet - find dummy packet | |
5596 | * | |
5597 | * @lkups: lookup elements or match criteria for the advanced recipe, one | |
5598 | * structure per protocol header | |
5599 | * @lkups_cnt: number of protocols | |
8b032a55 | 5600 | * @tun_type: tunnel type |
1b699f81 AL |
5601 | * |
5602 | * Returns the &ice_dummy_pkt_profile corresponding to these lookup params. | |
0f94570d | 5603 | */ |
e33163a4 | 5604 | static const struct ice_dummy_pkt_profile * |
0f94570d | 5605 | ice_find_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt, |
1b699f81 | 5606 | enum ice_sw_tunnel_type tun_type) |
0f94570d | 5607 | { |
e33163a4 | 5608 | const struct ice_dummy_pkt_profile *ret = ice_dummy_pkt_profiles; |
26395726 | 5609 | u32 match = 0, vlan_count = 0; |
0f94570d GK |
5610 | u16 i; |
5611 | ||
e33163a4 AL |
5612 | switch (tun_type) { |
5613 | case ICE_SW_TUN_GTPC: | |
5614 | match |= ICE_PKT_TUN_GTPC; | |
5615 | break; | |
5616 | case ICE_SW_TUN_GTPU: | |
5617 | match |= ICE_PKT_TUN_GTPU; | |
5618 | break; | |
5619 | case ICE_SW_TUN_NVGRE: | |
5620 | match |= ICE_PKT_TUN_NVGRE; | |
5621 | break; | |
5622 | case ICE_SW_TUN_GENEVE: | |
5623 | case ICE_SW_TUN_VXLAN: | |
5624 | match |= ICE_PKT_TUN_UDP; | |
5625 | break; | |
5626 | default: | |
5627 | break; | |
5628 | } | |
5629 | ||
0f94570d GK |
5630 | for (i = 0; i < lkups_cnt; i++) { |
5631 | if (lkups[i].type == ICE_UDP_ILOS) | |
e33163a4 | 5632 | match |= ICE_PKT_INNER_UDP; |
0f94570d | 5633 | else if (lkups[i].type == ICE_TCP_IL) |
e33163a4 | 5634 | match |= ICE_PKT_INNER_TCP; |
0f94570d | 5635 | else if (lkups[i].type == ICE_IPV6_OFOS) |
e33163a4 | 5636 | match |= ICE_PKT_OUTER_IPV6; |
06bca7c2 MSM |
5637 | else if (lkups[i].type == ICE_VLAN_OFOS || |
5638 | lkups[i].type == ICE_VLAN_EX) | |
26395726 | 5639 | vlan_count++; |
06bca7c2 | 5640 | else if (lkups[i].type == ICE_VLAN_IN) |
26395726 | 5641 | vlan_count++; |
0f94570d GK |
5642 | else if (lkups[i].type == ICE_ETYPE_OL && |
5643 | lkups[i].h_u.ethertype.ethtype_id == | |
5644 | cpu_to_be16(ICE_IPV6_ETHER_ID) && | |
5645 | lkups[i].m_u.ethertype.ethtype_id == | |
34a89775 | 5646 | cpu_to_be16(0xFFFF)) |
e33163a4 | 5647 | match |= ICE_PKT_OUTER_IPV6; |
34a89775 MSM |
5648 | else if (lkups[i].type == ICE_ETYPE_IL && |
5649 | lkups[i].h_u.ethertype.ethtype_id == | |
5650 | cpu_to_be16(ICE_IPV6_ETHER_ID) && | |
5651 | lkups[i].m_u.ethertype.ethtype_id == | |
5652 | cpu_to_be16(0xFFFF)) | |
e33163a4 | 5653 | match |= ICE_PKT_INNER_IPV6; |
9a225f81 | 5654 | else if (lkups[i].type == ICE_IPV6_IL) |
e33163a4 | 5655 | match |= ICE_PKT_INNER_IPV6; |
9a225f81 | 5656 | else if (lkups[i].type == ICE_GTP_NO_PAY) |
e33163a4 | 5657 | match |= ICE_PKT_GTP_NOPAY; |
cd8efeee MS |
5658 | else if (lkups[i].type == ICE_PPPOE) { |
5659 | match |= ICE_PKT_PPPOE; | |
5660 | if (lkups[i].h_u.pppoe_hdr.ppp_prot_id == | |
5661 | htons(PPP_IPV6)) | |
5662 | match |= ICE_PKT_OUTER_IPV6; | |
cd634549 MS |
5663 | } else if (lkups[i].type == ICE_L2TPV3) |
5664 | match |= ICE_PKT_L2TPV3; | |
9a225f81 MS |
5665 | } |
5666 | ||
e33163a4 AL |
5667 | while (ret->match && (match & ret->match) != ret->match) |
5668 | ret++; | |
f0a35040 | 5669 | |
26395726 MSM |
5670 | if (vlan_count != 0) |
5671 | ret = ice_dummy_packet_add_vlan(ret, vlan_count); | |
5672 | ||
e33163a4 | 5673 | return ret; |
0f94570d GK |
5674 | } |
5675 | ||
5676 | /** | |
5677 | * ice_fill_adv_dummy_packet - fill a dummy packet with given match criteria | |
5678 | * | |
5679 | * @lkups: lookup elements or match criteria for the advanced recipe, one | |
5680 | * structure per protocol header | |
5681 | * @lkups_cnt: number of protocols | |
5682 | * @s_rule: stores rule information from the match criteria | |
1b699f81 | 5683 | * @profile: dummy packet profile (the template, its size and header offsets) |
0f94570d | 5684 | */ |
5e24d598 | 5685 | static int |
0f94570d | 5686 | ice_fill_adv_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt, |
6e1ff618 | 5687 | struct ice_sw_rule_lkup_rx_tx *s_rule, |
1b699f81 | 5688 | const struct ice_dummy_pkt_profile *profile) |
0f94570d GK |
5689 | { |
5690 | u8 *pkt; | |
5691 | u16 i; | |
5692 | ||
5693 | /* Start with a packet with a pre-defined/dummy content. Then, fill | |
5694 | * in the header values to be looked up or matched. | |
5695 | */ | |
6e1ff618 | 5696 | pkt = s_rule->hdr_data; |
0f94570d | 5697 | |
1b699f81 | 5698 | memcpy(pkt, profile->pkt, profile->pkt_len); |
0f94570d GK |
5699 | |
5700 | for (i = 0; i < lkups_cnt; i++) { | |
1b699f81 | 5701 | const struct ice_dummy_pkt_offsets *offsets = profile->offsets; |
0f94570d GK |
5702 | enum ice_protocol_type type; |
5703 | u16 offset = 0, len = 0, j; | |
5704 | bool found = false; | |
5705 | ||
5706 | /* find the start of this layer; it should be found since this | |
5707 | * was already checked when search for the dummy packet | |
5708 | */ | |
5709 | type = lkups[i].type; | |
5710 | for (j = 0; offsets[j].type != ICE_PROTOCOL_LAST; j++) { | |
5711 | if (type == offsets[j].type) { | |
5712 | offset = offsets[j].offset; | |
5713 | found = true; | |
5714 | break; | |
5715 | } | |
5716 | } | |
5717 | /* this should never happen in a correct calling sequence */ | |
5718 | if (!found) | |
d54699e2 | 5719 | return -EINVAL; |
0f94570d GK |
5720 | |
5721 | switch (lkups[i].type) { | |
5722 | case ICE_MAC_OFOS: | |
5723 | case ICE_MAC_IL: | |
5724 | len = sizeof(struct ice_ether_hdr); | |
5725 | break; | |
5726 | case ICE_ETYPE_OL: | |
34a89775 | 5727 | case ICE_ETYPE_IL: |
0f94570d GK |
5728 | len = sizeof(struct ice_ethtype_hdr); |
5729 | break; | |
5730 | case ICE_VLAN_OFOS: | |
06bca7c2 MSM |
5731 | case ICE_VLAN_EX: |
5732 | case ICE_VLAN_IN: | |
0f94570d GK |
5733 | len = sizeof(struct ice_vlan_hdr); |
5734 | break; | |
5735 | case ICE_IPV4_OFOS: | |
5736 | case ICE_IPV4_IL: | |
5737 | len = sizeof(struct ice_ipv4_hdr); | |
5738 | break; | |
5739 | case ICE_IPV6_OFOS: | |
5740 | case ICE_IPV6_IL: | |
5741 | len = sizeof(struct ice_ipv6_hdr); | |
5742 | break; | |
5743 | case ICE_TCP_IL: | |
5744 | case ICE_UDP_OF: | |
5745 | case ICE_UDP_ILOS: | |
5746 | len = sizeof(struct ice_l4_hdr); | |
5747 | break; | |
5748 | case ICE_SCTP_IL: | |
5749 | len = sizeof(struct ice_sctp_hdr); | |
5750 | break; | |
f0a35040 MS |
5751 | case ICE_NVGRE: |
5752 | len = sizeof(struct ice_nvgre_hdr); | |
5753 | break; | |
8b032a55 MS |
5754 | case ICE_VXLAN: |
5755 | case ICE_GENEVE: | |
5756 | len = sizeof(struct ice_udp_tnl_hdr); | |
5757 | break; | |
9a225f81 MS |
5758 | case ICE_GTP_NO_PAY: |
5759 | case ICE_GTP: | |
5760 | len = sizeof(struct ice_udp_gtp_hdr); | |
5761 | break; | |
cd8efeee MS |
5762 | case ICE_PPPOE: |
5763 | len = sizeof(struct ice_pppoe_hdr); | |
5764 | break; | |
cd634549 MS |
5765 | case ICE_L2TPV3: |
5766 | len = sizeof(struct ice_l2tpv3_sess_hdr); | |
5767 | break; | |
0f94570d | 5768 | default: |
d54699e2 | 5769 | return -EINVAL; |
0f94570d GK |
5770 | } |
5771 | ||
5772 | /* the length should be a word multiple */ | |
5773 | if (len % ICE_BYTES_PER_WORD) | |
d54699e2 | 5774 | return -EIO; |
0f94570d GK |
5775 | |
5776 | /* We have the offset to the header start, the length, the | |
5777 | * caller's header values and mask. Use this information to | |
5778 | * copy the data into the dummy packet appropriately based on | |
5779 | * the mask. Note that we need to only write the bits as | |
5780 | * indicated by the mask to make sure we don't improperly write | |
5781 | * over any significant packet data. | |
5782 | */ | |
27ffa273 AL |
5783 | for (j = 0; j < len / sizeof(u16); j++) { |
5784 | u16 *ptr = (u16 *)(pkt + offset); | |
5785 | u16 mask = lkups[i].m_raw[j]; | |
5786 | ||
5787 | if (!mask) | |
5788 | continue; | |
5789 | ||
5790 | ptr[j] = (ptr[j] & ~mask) | (lkups[i].h_raw[j] & mask); | |
5791 | } | |
0f94570d GK |
5792 | } |
5793 | ||
6e1ff618 | 5794 | s_rule->hdr_len = cpu_to_le16(profile->pkt_len); |
0f94570d GK |
5795 | |
5796 | return 0; | |
5797 | } | |
5798 | ||
8b032a55 MS |
5799 | /** |
5800 | * ice_fill_adv_packet_tun - fill dummy packet with udp tunnel port | |
5801 | * @hw: pointer to the hardware structure | |
5802 | * @tun_type: tunnel type | |
5803 | * @pkt: dummy packet to fill in | |
5804 | * @offsets: offset info for the dummy packet | |
5805 | */ | |
d54699e2 | 5806 | static int |
8b032a55 MS |
5807 | ice_fill_adv_packet_tun(struct ice_hw *hw, enum ice_sw_tunnel_type tun_type, |
5808 | u8 *pkt, const struct ice_dummy_pkt_offsets *offsets) | |
5809 | { | |
5810 | u16 open_port, i; | |
5811 | ||
5812 | switch (tun_type) { | |
5813 | case ICE_SW_TUN_VXLAN: | |
de6acd1c | 5814 | if (!ice_get_open_tunnel_port(hw, &open_port, TNL_VXLAN)) |
d54699e2 | 5815 | return -EIO; |
de6acd1c | 5816 | break; |
8b032a55 | 5817 | case ICE_SW_TUN_GENEVE: |
de6acd1c | 5818 | if (!ice_get_open_tunnel_port(hw, &open_port, TNL_GENEVE)) |
d54699e2 | 5819 | return -EIO; |
8b032a55 | 5820 | break; |
8b032a55 MS |
5821 | default: |
5822 | /* Nothing needs to be done for this tunnel type */ | |
5823 | return 0; | |
5824 | } | |
5825 | ||
5826 | /* Find the outer UDP protocol header and insert the port number */ | |
5827 | for (i = 0; offsets[i].type != ICE_PROTOCOL_LAST; i++) { | |
5828 | if (offsets[i].type == ICE_UDP_OF) { | |
5829 | struct ice_l4_hdr *hdr; | |
5830 | u16 offset; | |
5831 | ||
5832 | offset = offsets[i].offset; | |
5833 | hdr = (struct ice_l4_hdr *)&pkt[offset]; | |
5834 | hdr->dst_port = cpu_to_be16(open_port); | |
5835 | ||
5836 | return 0; | |
5837 | } | |
5838 | } | |
5839 | ||
d54699e2 | 5840 | return -EIO; |
8b032a55 MS |
5841 | } |
5842 | ||
ea71b967 MSM |
5843 | /** |
5844 | * ice_fill_adv_packet_vlan - fill dummy packet with VLAN tag type | |
5845 | * @vlan_type: VLAN tag type | |
5846 | * @pkt: dummy packet to fill in | |
5847 | * @offsets: offset info for the dummy packet | |
5848 | */ | |
5849 | static int | |
5850 | ice_fill_adv_packet_vlan(u16 vlan_type, u8 *pkt, | |
5851 | const struct ice_dummy_pkt_offsets *offsets) | |
5852 | { | |
5853 | u16 i; | |
5854 | ||
5855 | /* Find VLAN header and insert VLAN TPID */ | |
5856 | for (i = 0; offsets[i].type != ICE_PROTOCOL_LAST; i++) { | |
5857 | if (offsets[i].type == ICE_VLAN_OFOS || | |
5858 | offsets[i].type == ICE_VLAN_EX) { | |
5859 | struct ice_vlan_hdr *hdr; | |
5860 | u16 offset; | |
5861 | ||
5862 | offset = offsets[i].offset; | |
5863 | hdr = (struct ice_vlan_hdr *)&pkt[offset]; | |
5864 | hdr->type = cpu_to_be16(vlan_type); | |
5865 | ||
5866 | return 0; | |
5867 | } | |
5868 | } | |
5869 | ||
5870 | return -EIO; | |
5871 | } | |
5872 | ||
0f94570d GK |
5873 | /** |
5874 | * ice_find_adv_rule_entry - Search a rule entry | |
5875 | * @hw: pointer to the hardware structure | |
5876 | * @lkups: lookup elements or match criteria for the advanced recipe, one | |
5877 | * structure per protocol header | |
5878 | * @lkups_cnt: number of protocols | |
5879 | * @recp_id: recipe ID for which we are finding the rule | |
5880 | * @rinfo: other information regarding the rule e.g. priority and action info | |
5881 | * | |
5882 | * Helper function to search for a given advance rule entry | |
5883 | * Returns pointer to entry storing the rule if found | |
5884 | */ | |
5885 | static struct ice_adv_fltr_mgmt_list_entry * | |
5886 | ice_find_adv_rule_entry(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, | |
5887 | u16 lkups_cnt, u16 recp_id, | |
5888 | struct ice_adv_rule_info *rinfo) | |
5889 | { | |
5890 | struct ice_adv_fltr_mgmt_list_entry *list_itr; | |
5891 | struct ice_switch_info *sw = hw->switch_info; | |
5892 | int i; | |
5893 | ||
5894 | list_for_each_entry(list_itr, &sw->recp_list[recp_id].filt_rules, | |
5895 | list_entry) { | |
5896 | bool lkups_matched = true; | |
5897 | ||
5898 | if (lkups_cnt != list_itr->lkups_cnt) | |
5899 | continue; | |
5900 | for (i = 0; i < list_itr->lkups_cnt; i++) | |
5901 | if (memcmp(&list_itr->lkups[i], &lkups[i], | |
5902 | sizeof(*lkups))) { | |
5903 | lkups_matched = false; | |
5904 | break; | |
5905 | } | |
5906 | if (rinfo->sw_act.flag == list_itr->rule_info.sw_act.flag && | |
8b032a55 | 5907 | rinfo->tun_type == list_itr->rule_info.tun_type && |
ea71b967 | 5908 | rinfo->vlan_type == list_itr->rule_info.vlan_type && |
0f94570d GK |
5909 | lkups_matched) |
5910 | return list_itr; | |
5911 | } | |
5912 | return NULL; | |
5913 | } | |
5914 | ||
5915 | /** | |
5916 | * ice_adv_add_update_vsi_list | |
5917 | * @hw: pointer to the hardware structure | |
5918 | * @m_entry: pointer to current adv filter management list entry | |
5919 | * @cur_fltr: filter information from the book keeping entry | |
5920 | * @new_fltr: filter information with the new VSI to be added | |
5921 | * | |
5922 | * Call AQ command to add or update previously created VSI list with new VSI. | |
5923 | * | |
5924 | * Helper function to do book keeping associated with adding filter information | |
5925 | * The algorithm to do the booking keeping is described below : | |
5926 | * When a VSI needs to subscribe to a given advanced filter | |
5927 | * if only one VSI has been added till now | |
5928 | * Allocate a new VSI list and add two VSIs | |
5929 | * to this list using switch rule command | |
5930 | * Update the previously created switch rule with the | |
5931 | * newly created VSI list ID | |
5932 | * if a VSI list was previously created | |
5933 | * Add the new VSI to the previously created VSI list set | |
5934 | * using the update switch rule command | |
5935 | */ | |
5e24d598 | 5936 | static int |
0f94570d GK |
5937 | ice_adv_add_update_vsi_list(struct ice_hw *hw, |
5938 | struct ice_adv_fltr_mgmt_list_entry *m_entry, | |
5939 | struct ice_adv_rule_info *cur_fltr, | |
5940 | struct ice_adv_rule_info *new_fltr) | |
5941 | { | |
0f94570d | 5942 | u16 vsi_list_id = 0; |
5518ac2a | 5943 | int status; |
0f94570d GK |
5944 | |
5945 | if (cur_fltr->sw_act.fltr_act == ICE_FWD_TO_Q || | |
5946 | cur_fltr->sw_act.fltr_act == ICE_FWD_TO_QGRP || | |
5947 | cur_fltr->sw_act.fltr_act == ICE_DROP_PACKET) | |
d54699e2 | 5948 | return -EOPNOTSUPP; |
0f94570d GK |
5949 | |
5950 | if ((new_fltr->sw_act.fltr_act == ICE_FWD_TO_Q || | |
5951 | new_fltr->sw_act.fltr_act == ICE_FWD_TO_QGRP) && | |
5952 | (cur_fltr->sw_act.fltr_act == ICE_FWD_TO_VSI || | |
5953 | cur_fltr->sw_act.fltr_act == ICE_FWD_TO_VSI_LIST)) | |
d54699e2 | 5954 | return -EOPNOTSUPP; |
0f94570d GK |
5955 | |
5956 | if (m_entry->vsi_count < 2 && !m_entry->vsi_list_info) { | |
5957 | /* Only one entry existed in the mapping and it was not already | |
5958 | * a part of a VSI list. So, create a VSI list with the old and | |
5959 | * new VSIs. | |
5960 | */ | |
5961 | struct ice_fltr_info tmp_fltr; | |
5962 | u16 vsi_handle_arr[2]; | |
5963 | ||
5964 | /* A rule already exists with the new VSI being added */ | |
5965 | if (cur_fltr->sw_act.fwd_id.hw_vsi_id == | |
5966 | new_fltr->sw_act.fwd_id.hw_vsi_id) | |
d54699e2 | 5967 | return -EEXIST; |
0f94570d GK |
5968 | |
5969 | vsi_handle_arr[0] = cur_fltr->sw_act.vsi_handle; | |
5970 | vsi_handle_arr[1] = new_fltr->sw_act.vsi_handle; | |
5971 | status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2, | |
5972 | &vsi_list_id, | |
5973 | ICE_SW_LKUP_LAST); | |
5974 | if (status) | |
5975 | return status; | |
5976 | ||
5977 | memset(&tmp_fltr, 0, sizeof(tmp_fltr)); | |
5978 | tmp_fltr.flag = m_entry->rule_info.sw_act.flag; | |
5979 | tmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id; | |
5980 | tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST; | |
5981 | tmp_fltr.fwd_id.vsi_list_id = vsi_list_id; | |
5982 | tmp_fltr.lkup_type = ICE_SW_LKUP_LAST; | |
5983 | ||
5984 | /* Update the previous switch rule of "forward to VSI" to | |
5985 | * "fwd to VSI list" | |
5986 | */ | |
5987 | status = ice_update_pkt_fwd_rule(hw, &tmp_fltr); | |
5988 | if (status) | |
5989 | return status; | |
5990 | ||
5991 | cur_fltr->sw_act.fwd_id.vsi_list_id = vsi_list_id; | |
5992 | cur_fltr->sw_act.fltr_act = ICE_FWD_TO_VSI_LIST; | |
5993 | m_entry->vsi_list_info = | |
5994 | ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2, | |
5995 | vsi_list_id); | |
5996 | } else { | |
5997 | u16 vsi_handle = new_fltr->sw_act.vsi_handle; | |
5998 | ||
5999 | if (!m_entry->vsi_list_info) | |
d54699e2 | 6000 | return -EIO; |
0f94570d GK |
6001 | |
6002 | /* A rule already exists with the new VSI being added */ | |
6003 | if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map)) | |
6004 | return 0; | |
6005 | ||
6006 | /* Update the previously created VSI list set with | |
6007 | * the new VSI ID passed in | |
6008 | */ | |
6009 | vsi_list_id = cur_fltr->sw_act.fwd_id.vsi_list_id; | |
6010 | ||
6011 | status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, | |
6012 | vsi_list_id, false, | |
6013 | ice_aqc_opc_update_sw_rules, | |
6014 | ICE_SW_LKUP_LAST); | |
6015 | /* update VSI list mapping info with new VSI ID */ | |
6016 | if (!status) | |
6017 | set_bit(vsi_handle, m_entry->vsi_list_info->vsi_map); | |
6018 | } | |
6019 | if (!status) | |
6020 | m_entry->vsi_count++; | |
6021 | return status; | |
6022 | } | |
6023 | ||
6024 | /** | |
6025 | * ice_add_adv_rule - helper function to create an advanced switch rule | |
6026 | * @hw: pointer to the hardware structure | |
6027 | * @lkups: information on the words that needs to be looked up. All words | |
6028 | * together makes one recipe | |
6029 | * @lkups_cnt: num of entries in the lkups array | |
6030 | * @rinfo: other information related to the rule that needs to be programmed | |
6031 | * @added_entry: this will return recipe_id, rule_id and vsi_handle. should be | |
6032 | * ignored is case of error. | |
6033 | * | |
6034 | * This function can program only 1 rule at a time. The lkups is used to | |
6035 | * describe the all the words that forms the "lookup" portion of the recipe. | |
6036 | * These words can span multiple protocols. Callers to this function need to | |
6037 | * pass in a list of protocol headers with lookup information along and mask | |
6038 | * that determines which words are valid from the given protocol header. | |
6039 | * rinfo describes other information related to this rule such as forwarding | |
6040 | * IDs, priority of this rule, etc. | |
6041 | */ | |
5e24d598 | 6042 | int |
0f94570d GK |
6043 | ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, |
6044 | u16 lkups_cnt, struct ice_adv_rule_info *rinfo, | |
6045 | struct ice_rule_query_data *added_entry) | |
6046 | { | |
6047 | struct ice_adv_fltr_mgmt_list_entry *m_entry, *adv_fltr = NULL; | |
6e1ff618 | 6048 | struct ice_sw_rule_lkup_rx_tx *s_rule = NULL; |
e33163a4 | 6049 | const struct ice_dummy_pkt_profile *profile; |
1b699f81 | 6050 | u16 rid = 0, i, rule_buf_sz, vsi_handle; |
0f94570d GK |
6051 | struct list_head *rule_head; |
6052 | struct ice_switch_info *sw; | |
0f94570d GK |
6053 | u16 word_cnt; |
6054 | u32 act = 0; | |
5518ac2a | 6055 | int status; |
0f94570d GK |
6056 | u8 q_rgn; |
6057 | ||
6058 | /* Initialize profile to result index bitmap */ | |
6059 | if (!hw->switch_info->prof_res_bm_init) { | |
6060 | hw->switch_info->prof_res_bm_init = 1; | |
6061 | ice_init_prof_result_bm(hw); | |
6062 | } | |
6063 | ||
6064 | if (!lkups_cnt) | |
d54699e2 | 6065 | return -EINVAL; |
0f94570d GK |
6066 | |
6067 | /* get # of words we need to match */ | |
6068 | word_cnt = 0; | |
6069 | for (i = 0; i < lkups_cnt; i++) { | |
135a161a | 6070 | u16 j; |
0f94570d | 6071 | |
135a161a AL |
6072 | for (j = 0; j < ARRAY_SIZE(lkups->m_raw); j++) |
6073 | if (lkups[i].m_raw[j]) | |
0f94570d GK |
6074 | word_cnt++; |
6075 | } | |
6076 | ||
bd1ffe8e | 6077 | if (!word_cnt) |
d54699e2 | 6078 | return -EINVAL; |
0f94570d | 6079 | |
bd1ffe8e WD |
6080 | if (word_cnt > ICE_MAX_CHAIN_WORDS) |
6081 | return -ENOSPC; | |
6082 | ||
1b699f81 AL |
6083 | /* locate a dummy packet */ |
6084 | profile = ice_find_dummy_packet(lkups, lkups_cnt, rinfo->tun_type); | |
26395726 MSM |
6085 | if (IS_ERR(profile)) |
6086 | return PTR_ERR(profile); | |
0f94570d GK |
6087 | |
6088 | if (!(rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI || | |
6089 | rinfo->sw_act.fltr_act == ICE_FWD_TO_Q || | |
6090 | rinfo->sw_act.fltr_act == ICE_FWD_TO_QGRP || | |
26395726 MSM |
6091 | rinfo->sw_act.fltr_act == ICE_DROP_PACKET)) { |
6092 | status = -EIO; | |
6093 | goto free_pkt_profile; | |
6094 | } | |
0f94570d GK |
6095 | |
6096 | vsi_handle = rinfo->sw_act.vsi_handle; | |
26395726 MSM |
6097 | if (!ice_is_vsi_valid(hw, vsi_handle)) { |
6098 | status = -EINVAL; | |
6099 | goto free_pkt_profile; | |
6100 | } | |
0f94570d GK |
6101 | |
6102 | if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI) | |
6103 | rinfo->sw_act.fwd_id.hw_vsi_id = | |
6104 | ice_get_hw_vsi_num(hw, vsi_handle); | |
6105 | if (rinfo->sw_act.flag & ICE_FLTR_TX) | |
6106 | rinfo->sw_act.src = ice_get_hw_vsi_num(hw, vsi_handle); | |
6107 | ||
6108 | status = ice_add_adv_recipe(hw, lkups, lkups_cnt, rinfo, &rid); | |
6109 | if (status) | |
26395726 | 6110 | goto free_pkt_profile; |
0f94570d GK |
6111 | m_entry = ice_find_adv_rule_entry(hw, lkups, lkups_cnt, rid, rinfo); |
6112 | if (m_entry) { | |
6113 | /* we have to add VSI to VSI_LIST and increment vsi_count. | |
6114 | * Also Update VSI list so that we can change forwarding rule | |
6115 | * if the rule already exists, we will check if it exists with | |
6116 | * same vsi_id, if not then add it to the VSI list if it already | |
6117 | * exists if not then create a VSI list and add the existing VSI | |
6118 | * ID and the new VSI ID to the list | |
6119 | * We will add that VSI to the list | |
6120 | */ | |
6121 | status = ice_adv_add_update_vsi_list(hw, m_entry, | |
6122 | &m_entry->rule_info, | |
6123 | rinfo); | |
6124 | if (added_entry) { | |
6125 | added_entry->rid = rid; | |
6126 | added_entry->rule_id = m_entry->rule_info.fltr_rule_id; | |
6127 | added_entry->vsi_handle = rinfo->sw_act.vsi_handle; | |
6128 | } | |
26395726 | 6129 | goto free_pkt_profile; |
0f94570d | 6130 | } |
6e1ff618 | 6131 | rule_buf_sz = ICE_SW_RULE_RX_TX_HDR_SIZE(s_rule, profile->pkt_len); |
0f94570d | 6132 | s_rule = kzalloc(rule_buf_sz, GFP_KERNEL); |
26395726 MSM |
6133 | if (!s_rule) { |
6134 | status = -ENOMEM; | |
6135 | goto free_pkt_profile; | |
6136 | } | |
73b483b7 WD |
6137 | if (!rinfo->flags_info.act_valid) { |
6138 | act |= ICE_SINGLE_ACT_LAN_ENABLE; | |
6139 | act |= ICE_SINGLE_ACT_LB_ENABLE; | |
6140 | } else { | |
6141 | act |= rinfo->flags_info.act & (ICE_SINGLE_ACT_LAN_ENABLE | | |
6142 | ICE_SINGLE_ACT_LB_ENABLE); | |
6143 | } | |
6144 | ||
0f94570d GK |
6145 | switch (rinfo->sw_act.fltr_act) { |
6146 | case ICE_FWD_TO_VSI: | |
6147 | act |= (rinfo->sw_act.fwd_id.hw_vsi_id << | |
6148 | ICE_SINGLE_ACT_VSI_ID_S) & ICE_SINGLE_ACT_VSI_ID_M; | |
6149 | act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_VALID_BIT; | |
6150 | break; | |
6151 | case ICE_FWD_TO_Q: | |
6152 | act |= ICE_SINGLE_ACT_TO_Q; | |
6153 | act |= (rinfo->sw_act.fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) & | |
6154 | ICE_SINGLE_ACT_Q_INDEX_M; | |
6155 | break; | |
6156 | case ICE_FWD_TO_QGRP: | |
6157 | q_rgn = rinfo->sw_act.qgrp_size > 0 ? | |
6158 | (u8)ilog2(rinfo->sw_act.qgrp_size) : 0; | |
6159 | act |= ICE_SINGLE_ACT_TO_Q; | |
6160 | act |= (rinfo->sw_act.fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) & | |
6161 | ICE_SINGLE_ACT_Q_INDEX_M; | |
6162 | act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) & | |
6163 | ICE_SINGLE_ACT_Q_REGION_M; | |
6164 | break; | |
6165 | case ICE_DROP_PACKET: | |
6166 | act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP | | |
6167 | ICE_SINGLE_ACT_VALID_BIT; | |
6168 | break; | |
6169 | default: | |
d54699e2 | 6170 | status = -EIO; |
0f94570d GK |
6171 | goto err_ice_add_adv_rule; |
6172 | } | |
6173 | ||
6174 | /* set the rule LOOKUP type based on caller specified 'Rx' | |
6175 | * instead of hardcoding it to be either LOOKUP_TX/RX | |
6176 | * | |
6177 | * for 'Rx' set the source to be the port number | |
6178 | * for 'Tx' set the source to be the source HW VSI number (determined | |
6179 | * by caller) | |
6180 | */ | |
6181 | if (rinfo->rx) { | |
6e1ff618 AL |
6182 | s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX); |
6183 | s_rule->src = cpu_to_le16(hw->port_info->lport); | |
0f94570d | 6184 | } else { |
6e1ff618 AL |
6185 | s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_TX); |
6186 | s_rule->src = cpu_to_le16(rinfo->sw_act.src); | |
0f94570d GK |
6187 | } |
6188 | ||
6e1ff618 AL |
6189 | s_rule->recipe_id = cpu_to_le16(rid); |
6190 | s_rule->act = cpu_to_le32(act); | |
0f94570d | 6191 | |
e33163a4 | 6192 | status = ice_fill_adv_dummy_packet(lkups, lkups_cnt, s_rule, profile); |
0f94570d GK |
6193 | if (status) |
6194 | goto err_ice_add_adv_rule; | |
6195 | ||
b70bc066 WD |
6196 | if (rinfo->tun_type != ICE_NON_TUN && |
6197 | rinfo->tun_type != ICE_SW_TUN_AND_NON_TUN) { | |
8b032a55 | 6198 | status = ice_fill_adv_packet_tun(hw, rinfo->tun_type, |
6e1ff618 | 6199 | s_rule->hdr_data, |
e33163a4 | 6200 | profile->offsets); |
8b032a55 MS |
6201 | if (status) |
6202 | goto err_ice_add_adv_rule; | |
6203 | } | |
6204 | ||
ea71b967 MSM |
6205 | if (rinfo->vlan_type != 0 && ice_is_dvm_ena(hw)) { |
6206 | status = ice_fill_adv_packet_vlan(rinfo->vlan_type, | |
6207 | s_rule->hdr_data, | |
6208 | profile->offsets); | |
6209 | if (status) | |
6210 | goto err_ice_add_adv_rule; | |
6211 | } | |
6212 | ||
0f94570d GK |
6213 | status = ice_aq_sw_rules(hw, (struct ice_aqc_sw_rules *)s_rule, |
6214 | rule_buf_sz, 1, ice_aqc_opc_add_sw_rules, | |
6215 | NULL); | |
6216 | if (status) | |
6217 | goto err_ice_add_adv_rule; | |
6218 | adv_fltr = devm_kzalloc(ice_hw_to_dev(hw), | |
6219 | sizeof(struct ice_adv_fltr_mgmt_list_entry), | |
6220 | GFP_KERNEL); | |
6221 | if (!adv_fltr) { | |
d54699e2 | 6222 | status = -ENOMEM; |
0f94570d GK |
6223 | goto err_ice_add_adv_rule; |
6224 | } | |
6225 | ||
6226 | adv_fltr->lkups = devm_kmemdup(ice_hw_to_dev(hw), lkups, | |
6227 | lkups_cnt * sizeof(*lkups), GFP_KERNEL); | |
6228 | if (!adv_fltr->lkups) { | |
d54699e2 | 6229 | status = -ENOMEM; |
0f94570d GK |
6230 | goto err_ice_add_adv_rule; |
6231 | } | |
6232 | ||
6233 | adv_fltr->lkups_cnt = lkups_cnt; | |
6234 | adv_fltr->rule_info = *rinfo; | |
6e1ff618 | 6235 | adv_fltr->rule_info.fltr_rule_id = le16_to_cpu(s_rule->index); |
0f94570d GK |
6236 | sw = hw->switch_info; |
6237 | sw->recp_list[rid].adv_rule = true; | |
6238 | rule_head = &sw->recp_list[rid].filt_rules; | |
6239 | ||
6240 | if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI) | |
6241 | adv_fltr->vsi_count = 1; | |
6242 | ||
6243 | /* Add rule entry to book keeping list */ | |
6244 | list_add(&adv_fltr->list_entry, rule_head); | |
6245 | if (added_entry) { | |
6246 | added_entry->rid = rid; | |
6247 | added_entry->rule_id = adv_fltr->rule_info.fltr_rule_id; | |
6248 | added_entry->vsi_handle = rinfo->sw_act.vsi_handle; | |
6249 | } | |
6250 | err_ice_add_adv_rule: | |
6251 | if (status && adv_fltr) { | |
6252 | devm_kfree(ice_hw_to_dev(hw), adv_fltr->lkups); | |
6253 | devm_kfree(ice_hw_to_dev(hw), adv_fltr); | |
6254 | } | |
6255 | ||
6256 | kfree(s_rule); | |
6257 | ||
26395726 MSM |
6258 | free_pkt_profile: |
6259 | if (profile->match & ICE_PKT_KMALLOC) { | |
6260 | kfree(profile->offsets); | |
6261 | kfree(profile->pkt); | |
6262 | kfree(profile); | |
6263 | } | |
6264 | ||
0f94570d GK |
6265 | return status; |
6266 | } | |
6267 | ||
0f9d5027 | 6268 | /** |
334cb062 | 6269 | * ice_replay_vsi_fltr - Replay filters for requested VSI |
0f9d5027 | 6270 | * @hw: pointer to the hardware structure |
334cb062 | 6271 | * @vsi_handle: driver VSI handle |
f9867df6 | 6272 | * @recp_id: Recipe ID for which rules need to be replayed |
334cb062 AV |
6273 | * @list_head: list for which filters need to be replayed |
6274 | * | |
6275 | * Replays the filter of recipe recp_id for a VSI represented via vsi_handle. | |
6276 | * It is required to pass valid VSI handle. | |
0f9d5027 | 6277 | */ |
5e24d598 | 6278 | static int |
334cb062 AV |
6279 | ice_replay_vsi_fltr(struct ice_hw *hw, u16 vsi_handle, u8 recp_id, |
6280 | struct list_head *list_head) | |
0f9d5027 AV |
6281 | { |
6282 | struct ice_fltr_mgmt_list_entry *itr; | |
5e24d598 | 6283 | int status = 0; |
334cb062 | 6284 | u16 hw_vsi_id; |
0f9d5027 AV |
6285 | |
6286 | if (list_empty(list_head)) | |
6287 | return status; | |
334cb062 | 6288 | hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); |
0f9d5027 | 6289 | |
334cb062 | 6290 | list_for_each_entry(itr, list_head, list_entry) { |
0f9d5027 AV |
6291 | struct ice_fltr_list_entry f_entry; |
6292 | ||
6293 | f_entry.fltr_info = itr->fltr_info; | |
334cb062 AV |
6294 | if (itr->vsi_count < 2 && recp_id != ICE_SW_LKUP_VLAN && |
6295 | itr->fltr_info.vsi_handle == vsi_handle) { | |
f9867df6 | 6296 | /* update the src in case it is VSI num */ |
334cb062 AV |
6297 | if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI) |
6298 | f_entry.fltr_info.src = hw_vsi_id; | |
0f9d5027 AV |
6299 | status = ice_add_rule_internal(hw, recp_id, &f_entry); |
6300 | if (status) | |
6301 | goto end; | |
6302 | continue; | |
6303 | } | |
072f0c3d DE |
6304 | if (!itr->vsi_list_info || |
6305 | !test_bit(vsi_handle, itr->vsi_list_info->vsi_map)) | |
334cb062 AV |
6306 | continue; |
6307 | /* Clearing it so that the logic can add it back */ | |
6308 | clear_bit(vsi_handle, itr->vsi_list_info->vsi_map); | |
6309 | f_entry.fltr_info.vsi_handle = vsi_handle; | |
6310 | f_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI; | |
f9867df6 | 6311 | /* update the src in case it is VSI num */ |
334cb062 AV |
6312 | if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI) |
6313 | f_entry.fltr_info.src = hw_vsi_id; | |
6314 | if (recp_id == ICE_SW_LKUP_VLAN) | |
6315 | status = ice_add_vlan_internal(hw, &f_entry); | |
6316 | else | |
6317 | status = ice_add_rule_internal(hw, recp_id, &f_entry); | |
6318 | if (status) | |
6319 | goto end; | |
0f9d5027 AV |
6320 | } |
6321 | end: | |
0f9d5027 AV |
6322 | return status; |
6323 | } | |
6324 | ||
8bb98f33 SS |
6325 | /** |
6326 | * ice_adv_rem_update_vsi_list | |
6327 | * @hw: pointer to the hardware structure | |
6328 | * @vsi_handle: VSI handle of the VSI to remove | |
6329 | * @fm_list: filter management entry for which the VSI list management needs to | |
6330 | * be done | |
6331 | */ | |
5e24d598 | 6332 | static int |
8bb98f33 SS |
6333 | ice_adv_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle, |
6334 | struct ice_adv_fltr_mgmt_list_entry *fm_list) | |
6335 | { | |
6336 | struct ice_vsi_list_map_info *vsi_list_info; | |
6337 | enum ice_sw_lkup_type lkup_type; | |
8bb98f33 | 6338 | u16 vsi_list_id; |
5518ac2a | 6339 | int status; |
8bb98f33 SS |
6340 | |
6341 | if (fm_list->rule_info.sw_act.fltr_act != ICE_FWD_TO_VSI_LIST || | |
6342 | fm_list->vsi_count == 0) | |
d54699e2 | 6343 | return -EINVAL; |
8bb98f33 SS |
6344 | |
6345 | /* A rule with the VSI being removed does not exist */ | |
6346 | if (!test_bit(vsi_handle, fm_list->vsi_list_info->vsi_map)) | |
d54699e2 | 6347 | return -ENOENT; |
8bb98f33 SS |
6348 | |
6349 | lkup_type = ICE_SW_LKUP_LAST; | |
6350 | vsi_list_id = fm_list->rule_info.sw_act.fwd_id.vsi_list_id; | |
6351 | status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, vsi_list_id, true, | |
6352 | ice_aqc_opc_update_sw_rules, | |
6353 | lkup_type); | |
6354 | if (status) | |
6355 | return status; | |
6356 | ||
6357 | fm_list->vsi_count--; | |
6358 | clear_bit(vsi_handle, fm_list->vsi_list_info->vsi_map); | |
6359 | vsi_list_info = fm_list->vsi_list_info; | |
6360 | if (fm_list->vsi_count == 1) { | |
6361 | struct ice_fltr_info tmp_fltr; | |
6362 | u16 rem_vsi_handle; | |
6363 | ||
6364 | rem_vsi_handle = find_first_bit(vsi_list_info->vsi_map, | |
6365 | ICE_MAX_VSI); | |
6366 | if (!ice_is_vsi_valid(hw, rem_vsi_handle)) | |
d54699e2 | 6367 | return -EIO; |
8bb98f33 SS |
6368 | |
6369 | /* Make sure VSI list is empty before removing it below */ | |
6370 | status = ice_update_vsi_list_rule(hw, &rem_vsi_handle, 1, | |
6371 | vsi_list_id, true, | |
6372 | ice_aqc_opc_update_sw_rules, | |
6373 | lkup_type); | |
6374 | if (status) | |
6375 | return status; | |
6376 | ||
6377 | memset(&tmp_fltr, 0, sizeof(tmp_fltr)); | |
6378 | tmp_fltr.flag = fm_list->rule_info.sw_act.flag; | |
6379 | tmp_fltr.fltr_rule_id = fm_list->rule_info.fltr_rule_id; | |
6380 | fm_list->rule_info.sw_act.fltr_act = ICE_FWD_TO_VSI; | |
6381 | tmp_fltr.fltr_act = ICE_FWD_TO_VSI; | |
6382 | tmp_fltr.fwd_id.hw_vsi_id = | |
6383 | ice_get_hw_vsi_num(hw, rem_vsi_handle); | |
6384 | fm_list->rule_info.sw_act.fwd_id.hw_vsi_id = | |
6385 | ice_get_hw_vsi_num(hw, rem_vsi_handle); | |
6386 | fm_list->rule_info.sw_act.vsi_handle = rem_vsi_handle; | |
6387 | ||
6388 | /* Update the previous switch rule of "MAC forward to VSI" to | |
6389 | * "MAC fwd to VSI list" | |
6390 | */ | |
6391 | status = ice_update_pkt_fwd_rule(hw, &tmp_fltr); | |
6392 | if (status) { | |
6393 | ice_debug(hw, ICE_DBG_SW, "Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\n", | |
6394 | tmp_fltr.fwd_id.hw_vsi_id, status); | |
6395 | return status; | |
6396 | } | |
6397 | fm_list->vsi_list_info->ref_cnt--; | |
6398 | ||
6399 | /* Remove the VSI list since it is no longer used */ | |
6400 | status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type); | |
6401 | if (status) { | |
6402 | ice_debug(hw, ICE_DBG_SW, "Failed to remove VSI list %d, error %d\n", | |
6403 | vsi_list_id, status); | |
6404 | return status; | |
6405 | } | |
6406 | ||
6407 | list_del(&vsi_list_info->list_entry); | |
6408 | devm_kfree(ice_hw_to_dev(hw), vsi_list_info); | |
6409 | fm_list->vsi_list_info = NULL; | |
6410 | } | |
6411 | ||
6412 | return status; | |
6413 | } | |
6414 | ||
6415 | /** | |
6416 | * ice_rem_adv_rule - removes existing advanced switch rule | |
6417 | * @hw: pointer to the hardware structure | |
6418 | * @lkups: information on the words that needs to be looked up. All words | |
6419 | * together makes one recipe | |
6420 | * @lkups_cnt: num of entries in the lkups array | |
6421 | * @rinfo: Its the pointer to the rule information for the rule | |
6422 | * | |
6423 | * This function can be used to remove 1 rule at a time. The lkups is | |
6424 | * used to describe all the words that forms the "lookup" portion of the | |
6425 | * rule. These words can span multiple protocols. Callers to this function | |
6426 | * need to pass in a list of protocol headers with lookup information along | |
6427 | * and mask that determines which words are valid from the given protocol | |
6428 | * header. rinfo describes other information related to this rule such as | |
6429 | * forwarding IDs, priority of this rule, etc. | |
6430 | */ | |
5e24d598 | 6431 | static int |
8bb98f33 SS |
6432 | ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, |
6433 | u16 lkups_cnt, struct ice_adv_rule_info *rinfo) | |
6434 | { | |
6435 | struct ice_adv_fltr_mgmt_list_entry *list_elem; | |
6436 | struct ice_prot_lkup_ext lkup_exts; | |
8bb98f33 SS |
6437 | bool remove_rule = false; |
6438 | struct mutex *rule_lock; /* Lock to protect filter rule list */ | |
6439 | u16 i, rid, vsi_handle; | |
5518ac2a | 6440 | int status = 0; |
8bb98f33 SS |
6441 | |
6442 | memset(&lkup_exts, 0, sizeof(lkup_exts)); | |
6443 | for (i = 0; i < lkups_cnt; i++) { | |
6444 | u16 count; | |
6445 | ||
6446 | if (lkups[i].type >= ICE_PROTOCOL_LAST) | |
d54699e2 | 6447 | return -EIO; |
8bb98f33 SS |
6448 | |
6449 | count = ice_fill_valid_words(&lkups[i], &lkup_exts); | |
6450 | if (!count) | |
d54699e2 | 6451 | return -EIO; |
8bb98f33 SS |
6452 | } |
6453 | ||
8b032a55 MS |
6454 | /* Create any special protocol/offset pairs, such as looking at tunnel |
6455 | * bits by extracting metadata | |
6456 | */ | |
ea71b967 | 6457 | status = ice_add_special_words(rinfo, &lkup_exts, ice_is_dvm_ena(hw)); |
8b032a55 MS |
6458 | if (status) |
6459 | return status; | |
6460 | ||
de6acd1c | 6461 | rid = ice_find_recp(hw, &lkup_exts, rinfo->tun_type); |
8bb98f33 SS |
6462 | /* If did not find a recipe that match the existing criteria */ |
6463 | if (rid == ICE_MAX_NUM_RECIPES) | |
d54699e2 | 6464 | return -EINVAL; |
8bb98f33 SS |
6465 | |
6466 | rule_lock = &hw->switch_info->recp_list[rid].filt_rule_lock; | |
6467 | list_elem = ice_find_adv_rule_entry(hw, lkups, lkups_cnt, rid, rinfo); | |
6468 | /* the rule is already removed */ | |
6469 | if (!list_elem) | |
6470 | return 0; | |
6471 | mutex_lock(rule_lock); | |
6472 | if (list_elem->rule_info.sw_act.fltr_act != ICE_FWD_TO_VSI_LIST) { | |
6473 | remove_rule = true; | |
6474 | } else if (list_elem->vsi_count > 1) { | |
6475 | remove_rule = false; | |
6476 | vsi_handle = rinfo->sw_act.vsi_handle; | |
6477 | status = ice_adv_rem_update_vsi_list(hw, vsi_handle, list_elem); | |
6478 | } else { | |
6479 | vsi_handle = rinfo->sw_act.vsi_handle; | |
6480 | status = ice_adv_rem_update_vsi_list(hw, vsi_handle, list_elem); | |
6481 | if (status) { | |
6482 | mutex_unlock(rule_lock); | |
6483 | return status; | |
6484 | } | |
6485 | if (list_elem->vsi_count == 0) | |
6486 | remove_rule = true; | |
6487 | } | |
6488 | mutex_unlock(rule_lock); | |
6489 | if (remove_rule) { | |
6e1ff618 | 6490 | struct ice_sw_rule_lkup_rx_tx *s_rule; |
8bb98f33 SS |
6491 | u16 rule_buf_sz; |
6492 | ||
6e1ff618 | 6493 | rule_buf_sz = ICE_SW_RULE_RX_TX_NO_HDR_SIZE(s_rule); |
8bb98f33 SS |
6494 | s_rule = kzalloc(rule_buf_sz, GFP_KERNEL); |
6495 | if (!s_rule) | |
d54699e2 | 6496 | return -ENOMEM; |
6e1ff618 AL |
6497 | s_rule->act = 0; |
6498 | s_rule->index = cpu_to_le16(list_elem->rule_info.fltr_rule_id); | |
6499 | s_rule->hdr_len = 0; | |
8bb98f33 SS |
6500 | status = ice_aq_sw_rules(hw, (struct ice_aqc_sw_rules *)s_rule, |
6501 | rule_buf_sz, 1, | |
6502 | ice_aqc_opc_remove_sw_rules, NULL); | |
d54699e2 | 6503 | if (!status || status == -ENOENT) { |
8bb98f33 SS |
6504 | struct ice_switch_info *sw = hw->switch_info; |
6505 | ||
6506 | mutex_lock(rule_lock); | |
6507 | list_del(&list_elem->list_entry); | |
6508 | devm_kfree(ice_hw_to_dev(hw), list_elem->lkups); | |
6509 | devm_kfree(ice_hw_to_dev(hw), list_elem); | |
6510 | mutex_unlock(rule_lock); | |
6511 | if (list_empty(&sw->recp_list[rid].filt_rules)) | |
6512 | sw->recp_list[rid].adv_rule = false; | |
6513 | } | |
6514 | kfree(s_rule); | |
6515 | } | |
6516 | return status; | |
6517 | } | |
6518 | ||
6519 | /** | |
6520 | * ice_rem_adv_rule_by_id - removes existing advanced switch rule by ID | |
6521 | * @hw: pointer to the hardware structure | |
6522 | * @remove_entry: data struct which holds rule_id, VSI handle and recipe ID | |
6523 | * | |
6524 | * This function is used to remove 1 rule at a time. The removal is based on | |
6525 | * the remove_entry parameter. This function will remove rule for a given | |
6526 | * vsi_handle with a given rule_id which is passed as parameter in remove_entry | |
6527 | */ | |
5e24d598 | 6528 | int |
8bb98f33 SS |
6529 | ice_rem_adv_rule_by_id(struct ice_hw *hw, |
6530 | struct ice_rule_query_data *remove_entry) | |
6531 | { | |
6532 | struct ice_adv_fltr_mgmt_list_entry *list_itr; | |
6533 | struct list_head *list_head; | |
6534 | struct ice_adv_rule_info rinfo; | |
6535 | struct ice_switch_info *sw; | |
6536 | ||
6537 | sw = hw->switch_info; | |
6538 | if (!sw->recp_list[remove_entry->rid].recp_created) | |
d54699e2 | 6539 | return -EINVAL; |
8bb98f33 SS |
6540 | list_head = &sw->recp_list[remove_entry->rid].filt_rules; |
6541 | list_for_each_entry(list_itr, list_head, list_entry) { | |
6542 | if (list_itr->rule_info.fltr_rule_id == | |
6543 | remove_entry->rule_id) { | |
6544 | rinfo = list_itr->rule_info; | |
6545 | rinfo.sw_act.vsi_handle = remove_entry->vsi_handle; | |
6546 | return ice_rem_adv_rule(hw, list_itr->lkups, | |
6547 | list_itr->lkups_cnt, &rinfo); | |
6548 | } | |
6549 | } | |
6550 | /* either list is empty or unable to find rule */ | |
d54699e2 | 6551 | return -ENOENT; |
8bb98f33 SS |
6552 | } |
6553 | ||
c1e5da5d WD |
6554 | /** |
6555 | * ice_rem_adv_rule_for_vsi - removes existing advanced switch rules for a | |
6556 | * given VSI handle | |
6557 | * @hw: pointer to the hardware structure | |
6558 | * @vsi_handle: VSI handle for which we are supposed to remove all the rules. | |
6559 | * | |
6560 | * This function is used to remove all the rules for a given VSI and as soon | |
6561 | * as removing a rule fails, it will return immediately with the error code, | |
6562 | * else it will return success. | |
6563 | */ | |
6564 | int ice_rem_adv_rule_for_vsi(struct ice_hw *hw, u16 vsi_handle) | |
6565 | { | |
6566 | struct ice_adv_fltr_mgmt_list_entry *list_itr, *tmp_entry; | |
6567 | struct ice_vsi_list_map_info *map_info; | |
6568 | struct ice_adv_rule_info rinfo; | |
6569 | struct list_head *list_head; | |
6570 | struct ice_switch_info *sw; | |
6571 | int status; | |
6572 | u8 rid; | |
6573 | ||
6574 | sw = hw->switch_info; | |
6575 | for (rid = 0; rid < ICE_MAX_NUM_RECIPES; rid++) { | |
6576 | if (!sw->recp_list[rid].recp_created) | |
6577 | continue; | |
6578 | if (!sw->recp_list[rid].adv_rule) | |
6579 | continue; | |
6580 | ||
6581 | list_head = &sw->recp_list[rid].filt_rules; | |
6582 | list_for_each_entry_safe(list_itr, tmp_entry, list_head, | |
6583 | list_entry) { | |
6584 | rinfo = list_itr->rule_info; | |
6585 | ||
6586 | if (rinfo.sw_act.fltr_act == ICE_FWD_TO_VSI_LIST) { | |
6587 | map_info = list_itr->vsi_list_info; | |
6588 | if (!map_info) | |
6589 | continue; | |
6590 | ||
6591 | if (!test_bit(vsi_handle, map_info->vsi_map)) | |
6592 | continue; | |
6593 | } else if (rinfo.sw_act.vsi_handle != vsi_handle) { | |
6594 | continue; | |
6595 | } | |
6596 | ||
6597 | rinfo.sw_act.vsi_handle = vsi_handle; | |
6598 | status = ice_rem_adv_rule(hw, list_itr->lkups, | |
6599 | list_itr->lkups_cnt, &rinfo); | |
6600 | if (status) | |
6601 | return status; | |
6602 | } | |
6603 | } | |
6604 | return 0; | |
6605 | } | |
6606 | ||
c36a2b97 VR |
6607 | /** |
6608 | * ice_replay_vsi_adv_rule - Replay advanced rule for requested VSI | |
6609 | * @hw: pointer to the hardware structure | |
6610 | * @vsi_handle: driver VSI handle | |
6611 | * @list_head: list for which filters need to be replayed | |
6612 | * | |
6613 | * Replay the advanced rule for the given VSI. | |
6614 | */ | |
6615 | static int | |
6616 | ice_replay_vsi_adv_rule(struct ice_hw *hw, u16 vsi_handle, | |
6617 | struct list_head *list_head) | |
6618 | { | |
6619 | struct ice_rule_query_data added_entry = { 0 }; | |
6620 | struct ice_adv_fltr_mgmt_list_entry *adv_fltr; | |
6621 | int status = 0; | |
6622 | ||
6623 | if (list_empty(list_head)) | |
6624 | return status; | |
6625 | list_for_each_entry(adv_fltr, list_head, list_entry) { | |
6626 | struct ice_adv_rule_info *rinfo = &adv_fltr->rule_info; | |
6627 | u16 lk_cnt = adv_fltr->lkups_cnt; | |
6628 | ||
6629 | if (vsi_handle != rinfo->sw_act.vsi_handle) | |
6630 | continue; | |
6631 | status = ice_add_adv_rule(hw, adv_fltr->lkups, lk_cnt, rinfo, | |
6632 | &added_entry); | |
6633 | if (status) | |
6634 | break; | |
6635 | } | |
6636 | return status; | |
6637 | } | |
6638 | ||
0f9d5027 | 6639 | /** |
334cb062 | 6640 | * ice_replay_vsi_all_fltr - replay all filters stored in bookkeeping lists |
0f9d5027 | 6641 | * @hw: pointer to the hardware structure |
334cb062 | 6642 | * @vsi_handle: driver VSI handle |
0f9d5027 | 6643 | * |
334cb062 | 6644 | * Replays filters for requested VSI via vsi_handle. |
0f9d5027 | 6645 | */ |
5e24d598 | 6646 | int ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle) |
0f9d5027 AV |
6647 | { |
6648 | struct ice_switch_info *sw = hw->switch_info; | |
c36a2b97 | 6649 | int status; |
0f9d5027 AV |
6650 | u8 i; |
6651 | ||
c36a2b97 | 6652 | for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) { |
334cb062 | 6653 | struct list_head *head; |
0f9d5027 | 6654 | |
334cb062 | 6655 | head = &sw->recp_list[i].filt_replay_rules; |
c36a2b97 VR |
6656 | if (!sw->recp_list[i].adv_rule) |
6657 | status = ice_replay_vsi_fltr(hw, vsi_handle, i, head); | |
6658 | else | |
6659 | status = ice_replay_vsi_adv_rule(hw, vsi_handle, head); | |
0f9d5027 AV |
6660 | if (status) |
6661 | return status; | |
6662 | } | |
6663 | return status; | |
6664 | } | |
334cb062 AV |
6665 | |
6666 | /** | |
6667 | * ice_rm_all_sw_replay_rule_info - deletes filter replay rules | |
f9867df6 | 6668 | * @hw: pointer to the HW struct |
334cb062 AV |
6669 | * |
6670 | * Deletes the filter replay rules. | |
6671 | */ | |
6672 | void ice_rm_all_sw_replay_rule_info(struct ice_hw *hw) | |
6673 | { | |
6674 | struct ice_switch_info *sw = hw->switch_info; | |
6675 | u8 i; | |
6676 | ||
6677 | if (!sw) | |
6678 | return; | |
6679 | ||
8b8ef05b | 6680 | for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) { |
334cb062 AV |
6681 | if (!list_empty(&sw->recp_list[i].filt_replay_rules)) { |
6682 | struct list_head *l_head; | |
6683 | ||
6684 | l_head = &sw->recp_list[i].filt_replay_rules; | |
8b8ef05b VR |
6685 | if (!sw->recp_list[i].adv_rule) |
6686 | ice_rem_sw_rule_info(hw, l_head); | |
6687 | else | |
6688 | ice_rem_adv_rule_info(hw, l_head); | |
334cb062 AV |
6689 | } |
6690 | } | |
6691 | } |