1 /*-
2 * Copyright (c) 2007-2016 Solarflare Communications Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * The views and conclusions contained in the software and documentation are
27 * those of the authors and should not be interpreted as representing official
28 * policies, either expressed or implied, of the FreeBSD Project.
29 */
30
31 #include <sys/cdefs.h>
32 #include "efx.h"
33 #include "efx_impl.h"
34
35 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
36
37 #if EFSYS_OPT_FILTER
38
39 #define EFE_SPEC(eftp, index) ((eftp)->eft_entry[(index)].efe_spec)
40
41 static efx_filter_spec_t *
ef10_filter_entry_spec(__in const ef10_filter_table_t * eftp,__in unsigned int index)42 ef10_filter_entry_spec(
43 __in const ef10_filter_table_t *eftp,
44 __in unsigned int index)
45 {
46 return ((efx_filter_spec_t *)(EFE_SPEC(eftp, index) &
47 ~(uintptr_t)EFX_EF10_FILTER_FLAGS));
48 }
49
50 static boolean_t
ef10_filter_entry_is_busy(__in const ef10_filter_table_t * eftp,__in unsigned int index)51 ef10_filter_entry_is_busy(
52 __in const ef10_filter_table_t *eftp,
53 __in unsigned int index)
54 {
55 if (EFE_SPEC(eftp, index) & EFX_EF10_FILTER_FLAG_BUSY)
56 return (B_TRUE);
57 else
58 return (B_FALSE);
59 }
60
61 static boolean_t
ef10_filter_entry_is_auto_old(__in const ef10_filter_table_t * eftp,__in unsigned int index)62 ef10_filter_entry_is_auto_old(
63 __in const ef10_filter_table_t *eftp,
64 __in unsigned int index)
65 {
66 if (EFE_SPEC(eftp, index) & EFX_EF10_FILTER_FLAG_AUTO_OLD)
67 return (B_TRUE);
68 else
69 return (B_FALSE);
70 }
71
72 static void
ef10_filter_set_entry(__inout ef10_filter_table_t * eftp,__in unsigned int index,__in_opt const efx_filter_spec_t * efsp)73 ef10_filter_set_entry(
74 __inout ef10_filter_table_t *eftp,
75 __in unsigned int index,
76 __in_opt const efx_filter_spec_t *efsp)
77 {
78 EFE_SPEC(eftp, index) = (uintptr_t)efsp;
79 }
80
81 static void
ef10_filter_set_entry_busy(__inout ef10_filter_table_t * eftp,__in unsigned int index)82 ef10_filter_set_entry_busy(
83 __inout ef10_filter_table_t *eftp,
84 __in unsigned int index)
85 {
86 EFE_SPEC(eftp, index) |= (uintptr_t)EFX_EF10_FILTER_FLAG_BUSY;
87 }
88
89 static void
ef10_filter_set_entry_not_busy(__inout ef10_filter_table_t * eftp,__in unsigned int index)90 ef10_filter_set_entry_not_busy(
91 __inout ef10_filter_table_t *eftp,
92 __in unsigned int index)
93 {
94 EFE_SPEC(eftp, index) &= ~(uintptr_t)EFX_EF10_FILTER_FLAG_BUSY;
95 }
96
97 static void
ef10_filter_set_entry_auto_old(__inout ef10_filter_table_t * eftp,__in unsigned int index)98 ef10_filter_set_entry_auto_old(
99 __inout ef10_filter_table_t *eftp,
100 __in unsigned int index)
101 {
102 EFSYS_ASSERT(ef10_filter_entry_spec(eftp, index) != NULL);
103 EFE_SPEC(eftp, index) |= (uintptr_t)EFX_EF10_FILTER_FLAG_AUTO_OLD;
104 }
105
106 static void
ef10_filter_set_entry_not_auto_old(__inout ef10_filter_table_t * eftp,__in unsigned int index)107 ef10_filter_set_entry_not_auto_old(
108 __inout ef10_filter_table_t *eftp,
109 __in unsigned int index)
110 {
111 EFE_SPEC(eftp, index) &= ~(uintptr_t)EFX_EF10_FILTER_FLAG_AUTO_OLD;
112 EFSYS_ASSERT(ef10_filter_entry_spec(eftp, index) != NULL);
113 }
114
115 __checkReturn efx_rc_t
ef10_filter_init(__in efx_nic_t * enp)116 ef10_filter_init(
117 __in efx_nic_t *enp)
118 {
119 efx_rc_t rc;
120 ef10_filter_table_t *eftp;
121
122 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
123 enp->en_family == EFX_FAMILY_MEDFORD ||
124 enp->en_family == EFX_FAMILY_MEDFORD2);
125
126 #define MATCH_MASK(match) (EFX_MASK32(match) << EFX_LOW_BIT(match))
127 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_HOST ==
128 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_IP));
129 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_HOST ==
130 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_IP));
131 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_MAC ==
132 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_MAC));
133 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_PORT ==
134 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_PORT));
135 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_MAC ==
136 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_MAC));
137 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_PORT ==
138 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_PORT));
139 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_ETHER_TYPE ==
140 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_ETHER_TYPE));
141 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_INNER_VID ==
142 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_INNER_VLAN));
143 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_OUTER_VID ==
144 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_OUTER_VLAN));
145 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IP_PROTO ==
146 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IP_PROTO));
147 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_VNI_OR_VSID ==
148 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_VNI_OR_VSID));
149 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_LOC_MAC ==
150 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_DST_MAC));
151 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST ==
152 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_MCAST_DST));
153 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST ==
154 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_UCAST_DST));
155 EFX_STATIC_ASSERT(EFX_FILTER_MATCH_UNKNOWN_MCAST_DST ==
156 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_MCAST_DST));
157 EFX_STATIC_ASSERT((uint32_t)EFX_FILTER_MATCH_UNKNOWN_UCAST_DST ==
158 MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_UCAST_DST));
159 #undef MATCH_MASK
160
161 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (ef10_filter_table_t), eftp);
162
163 if (!eftp) {
164 rc = ENOMEM;
165 goto fail1;
166 }
167
168 enp->en_filter.ef_ef10_filter_table = eftp;
169
170 return (0);
171
172 fail1:
173 EFSYS_PROBE1(fail1, efx_rc_t, rc);
174
175 return (rc);
176 }
177
178 void
ef10_filter_fini(__in efx_nic_t * enp)179 ef10_filter_fini(
180 __in efx_nic_t *enp)
181 {
182 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
183 enp->en_family == EFX_FAMILY_MEDFORD ||
184 enp->en_family == EFX_FAMILY_MEDFORD2);
185
186 if (enp->en_filter.ef_ef10_filter_table != NULL) {
187 EFSYS_KMEM_FREE(enp->en_esip, sizeof (ef10_filter_table_t),
188 enp->en_filter.ef_ef10_filter_table);
189 }
190 }
191
192 static __checkReturn efx_rc_t
efx_mcdi_filter_op_add(__in efx_nic_t * enp,__in efx_filter_spec_t * spec,__in unsigned int filter_op,__inout ef10_filter_handle_t * handle)193 efx_mcdi_filter_op_add(
194 __in efx_nic_t *enp,
195 __in efx_filter_spec_t *spec,
196 __in unsigned int filter_op,
197 __inout ef10_filter_handle_t *handle)
198 {
199 efx_mcdi_req_t req;
200 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FILTER_OP_V3_IN_LEN,
201 MC_CMD_FILTER_OP_EXT_OUT_LEN);
202 efx_filter_match_flags_t match_flags;
203 efx_rc_t rc;
204
205 req.emr_cmd = MC_CMD_FILTER_OP;
206 req.emr_in_buf = payload;
207 req.emr_in_length = MC_CMD_FILTER_OP_V3_IN_LEN;
208 req.emr_out_buf = payload;
209 req.emr_out_length = MC_CMD_FILTER_OP_EXT_OUT_LEN;
210
211 /*
212 * Remove match flag for encapsulated filters that does not correspond
213 * to the MCDI match flags
214 */
215 match_flags = spec->efs_match_flags & ~EFX_FILTER_MATCH_ENCAP_TYPE;
216
217 switch (filter_op) {
218 case MC_CMD_FILTER_OP_IN_OP_REPLACE:
219 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_LO,
220 handle->efh_lo);
221 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_HI,
222 handle->efh_hi);
223 /* Fall through */
224 case MC_CMD_FILTER_OP_IN_OP_INSERT:
225 case MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE:
226 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_OP, filter_op);
227 break;
228 default:
229 EFSYS_ASSERT(0);
230 rc = EINVAL;
231 goto fail1;
232 }
233
234 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_PORT_ID,
235 EVB_PORT_ID_ASSIGNED);
236 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_MATCH_FIELDS,
237 match_flags);
238 if (spec->efs_dmaq_id == EFX_FILTER_SPEC_RX_DMAQ_ID_DROP) {
239 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_DEST,
240 MC_CMD_FILTER_OP_EXT_IN_RX_DEST_DROP);
241 } else {
242 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_DEST,
243 MC_CMD_FILTER_OP_EXT_IN_RX_DEST_HOST);
244 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_QUEUE,
245 spec->efs_dmaq_id);
246 }
247
248 #if EFSYS_OPT_RX_SCALE
249 if (spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) {
250 uint32_t rss_context;
251
252 if (spec->efs_rss_context == EFX_RSS_CONTEXT_DEFAULT)
253 rss_context = enp->en_rss_context;
254 else
255 rss_context = spec->efs_rss_context;
256 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_CONTEXT,
257 rss_context);
258 }
259 #endif
260
261 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_MODE,
262 spec->efs_flags & EFX_FILTER_FLAG_RX_RSS ?
263 MC_CMD_FILTER_OP_EXT_IN_RX_MODE_RSS :
264 MC_CMD_FILTER_OP_EXT_IN_RX_MODE_SIMPLE);
265 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_TX_DEST,
266 MC_CMD_FILTER_OP_EXT_IN_TX_DEST_DEFAULT);
267
268 if (filter_op != MC_CMD_FILTER_OP_IN_OP_REPLACE) {
269 /*
270 * NOTE: Unlike most MCDI requests, the filter fields
271 * are presented in network (big endian) byte order.
272 */
273 memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_SRC_MAC),
274 spec->efs_rem_mac, EFX_MAC_ADDR_LEN);
275 memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_DST_MAC),
276 spec->efs_loc_mac, EFX_MAC_ADDR_LEN);
277
278 MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_SRC_PORT,
279 __CPU_TO_BE_16(spec->efs_rem_port));
280 MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_DST_PORT,
281 __CPU_TO_BE_16(spec->efs_loc_port));
282
283 MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_ETHER_TYPE,
284 __CPU_TO_BE_16(spec->efs_ether_type));
285
286 MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_INNER_VLAN,
287 __CPU_TO_BE_16(spec->efs_inner_vid));
288 MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_OUTER_VLAN,
289 __CPU_TO_BE_16(spec->efs_outer_vid));
290
291 /* IP protocol (in low byte, high byte is zero) */
292 MCDI_IN_SET_BYTE(req, FILTER_OP_EXT_IN_IP_PROTO,
293 spec->efs_ip_proto);
294
295 EFX_STATIC_ASSERT(sizeof (spec->efs_rem_host) ==
296 MC_CMD_FILTER_OP_EXT_IN_SRC_IP_LEN);
297 EFX_STATIC_ASSERT(sizeof (spec->efs_loc_host) ==
298 MC_CMD_FILTER_OP_EXT_IN_DST_IP_LEN);
299
300 memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_SRC_IP),
301 &spec->efs_rem_host.eo_byte[0],
302 MC_CMD_FILTER_OP_EXT_IN_SRC_IP_LEN);
303 memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_DST_IP),
304 &spec->efs_loc_host.eo_byte[0],
305 MC_CMD_FILTER_OP_EXT_IN_DST_IP_LEN);
306
307 /*
308 * On Medford, filters for encapsulated packets match based on
309 * the ether type and IP protocol in the outer frame. In
310 * addition we need to fill in the VNI or VSID type field.
311 */
312 switch (spec->efs_encap_type) {
313 case EFX_TUNNEL_PROTOCOL_NONE:
314 break;
315 case EFX_TUNNEL_PROTOCOL_VXLAN:
316 case EFX_TUNNEL_PROTOCOL_GENEVE:
317 MCDI_IN_POPULATE_DWORD_1(req,
318 FILTER_OP_EXT_IN_VNI_OR_VSID,
319 FILTER_OP_EXT_IN_VNI_TYPE,
320 spec->efs_encap_type == EFX_TUNNEL_PROTOCOL_VXLAN ?
321 MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_VXLAN :
322 MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_GENEVE);
323 break;
324 case EFX_TUNNEL_PROTOCOL_NVGRE:
325 MCDI_IN_POPULATE_DWORD_1(req,
326 FILTER_OP_EXT_IN_VNI_OR_VSID,
327 FILTER_OP_EXT_IN_VSID_TYPE,
328 MC_CMD_FILTER_OP_EXT_IN_VSID_TYPE_NVGRE);
329 break;
330 default:
331 EFSYS_ASSERT(0);
332 rc = EINVAL;
333 goto fail2;
334 }
335
336 memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_VNI_OR_VSID),
337 spec->efs_vni_or_vsid, EFX_VNI_OR_VSID_LEN);
338
339 memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_IFRM_DST_MAC),
340 spec->efs_ifrm_loc_mac, EFX_MAC_ADDR_LEN);
341 }
342
343 /*
344 * Set the "MARK" or "FLAG" action for all packets matching this filter
345 * if necessary (only useful with equal stride packed stream Rx mode
346 * which provide the information in pseudo-header).
347 * These actions require MC_CMD_FILTER_OP_V3_IN msgrequest.
348 */
349 if ((spec->efs_flags & EFX_FILTER_FLAG_ACTION_MARK) &&
350 (spec->efs_flags & EFX_FILTER_FLAG_ACTION_FLAG)) {
351 rc = EINVAL;
352 goto fail3;
353 }
354 if (spec->efs_flags & EFX_FILTER_FLAG_ACTION_MARK) {
355 MCDI_IN_SET_DWORD(req, FILTER_OP_V3_IN_MATCH_ACTION,
356 MC_CMD_FILTER_OP_V3_IN_MATCH_ACTION_MARK);
357 MCDI_IN_SET_DWORD(req, FILTER_OP_V3_IN_MATCH_MARK_VALUE,
358 spec->efs_mark);
359 } else if (spec->efs_flags & EFX_FILTER_FLAG_ACTION_FLAG) {
360 MCDI_IN_SET_DWORD(req, FILTER_OP_V3_IN_MATCH_ACTION,
361 MC_CMD_FILTER_OP_V3_IN_MATCH_ACTION_FLAG);
362 }
363
364 efx_mcdi_execute(enp, &req);
365
366 if (req.emr_rc != 0) {
367 rc = req.emr_rc;
368 goto fail4;
369 }
370
371 if (req.emr_out_length_used < MC_CMD_FILTER_OP_EXT_OUT_LEN) {
372 rc = EMSGSIZE;
373 goto fail5;
374 }
375
376 handle->efh_lo = MCDI_OUT_DWORD(req, FILTER_OP_EXT_OUT_HANDLE_LO);
377 handle->efh_hi = MCDI_OUT_DWORD(req, FILTER_OP_EXT_OUT_HANDLE_HI);
378
379 return (0);
380
381 fail5:
382 EFSYS_PROBE(fail5);
383 fail4:
384 EFSYS_PROBE(fail4);
385 fail3:
386 EFSYS_PROBE(fail3);
387 fail2:
388 EFSYS_PROBE(fail2);
389 fail1:
390 EFSYS_PROBE1(fail1, efx_rc_t, rc);
391
392 return (rc);
393
394 }
395
396 static __checkReturn efx_rc_t
efx_mcdi_filter_op_delete(__in efx_nic_t * enp,__in unsigned int filter_op,__inout ef10_filter_handle_t * handle)397 efx_mcdi_filter_op_delete(
398 __in efx_nic_t *enp,
399 __in unsigned int filter_op,
400 __inout ef10_filter_handle_t *handle)
401 {
402 efx_mcdi_req_t req;
403 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FILTER_OP_EXT_IN_LEN,
404 MC_CMD_FILTER_OP_EXT_OUT_LEN);
405 efx_rc_t rc;
406
407 req.emr_cmd = MC_CMD_FILTER_OP;
408 req.emr_in_buf = payload;
409 req.emr_in_length = MC_CMD_FILTER_OP_EXT_IN_LEN;
410 req.emr_out_buf = payload;
411 req.emr_out_length = MC_CMD_FILTER_OP_EXT_OUT_LEN;
412
413 switch (filter_op) {
414 case MC_CMD_FILTER_OP_IN_OP_REMOVE:
415 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_OP,
416 MC_CMD_FILTER_OP_IN_OP_REMOVE);
417 break;
418 case MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE:
419 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_OP,
420 MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE);
421 break;
422 default:
423 EFSYS_ASSERT(0);
424 rc = EINVAL;
425 goto fail1;
426 }
427
428 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_LO, handle->efh_lo);
429 MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_HI, handle->efh_hi);
430
431 efx_mcdi_execute_quiet(enp, &req);
432
433 if (req.emr_rc != 0) {
434 rc = req.emr_rc;
435 goto fail2;
436 }
437
438 if (req.emr_out_length_used < MC_CMD_FILTER_OP_EXT_OUT_LEN) {
439 rc = EMSGSIZE;
440 goto fail3;
441 }
442
443 return (0);
444
445 fail3:
446 EFSYS_PROBE(fail3);
447
448 fail2:
449 EFSYS_PROBE(fail2);
450 fail1:
451 EFSYS_PROBE1(fail1, efx_rc_t, rc);
452
453 return (rc);
454 }
455
456 static __checkReturn boolean_t
ef10_filter_equal(__in const efx_filter_spec_t * left,__in const efx_filter_spec_t * right)457 ef10_filter_equal(
458 __in const efx_filter_spec_t *left,
459 __in const efx_filter_spec_t *right)
460 {
461 /* FIXME: Consider rx vs tx filters (look at efs_flags) */
462 if (left->efs_match_flags != right->efs_match_flags)
463 return (B_FALSE);
464 if (!EFX_OWORD_IS_EQUAL(left->efs_rem_host, right->efs_rem_host))
465 return (B_FALSE);
466 if (!EFX_OWORD_IS_EQUAL(left->efs_loc_host, right->efs_loc_host))
467 return (B_FALSE);
468 if (memcmp(left->efs_rem_mac, right->efs_rem_mac, EFX_MAC_ADDR_LEN))
469 return (B_FALSE);
470 if (memcmp(left->efs_loc_mac, right->efs_loc_mac, EFX_MAC_ADDR_LEN))
471 return (B_FALSE);
472 if (left->efs_rem_port != right->efs_rem_port)
473 return (B_FALSE);
474 if (left->efs_loc_port != right->efs_loc_port)
475 return (B_FALSE);
476 if (left->efs_inner_vid != right->efs_inner_vid)
477 return (B_FALSE);
478 if (left->efs_outer_vid != right->efs_outer_vid)
479 return (B_FALSE);
480 if (left->efs_ether_type != right->efs_ether_type)
481 return (B_FALSE);
482 if (left->efs_ip_proto != right->efs_ip_proto)
483 return (B_FALSE);
484 if (left->efs_encap_type != right->efs_encap_type)
485 return (B_FALSE);
486 if (memcmp(left->efs_vni_or_vsid, right->efs_vni_or_vsid,
487 EFX_VNI_OR_VSID_LEN))
488 return (B_FALSE);
489 if (memcmp(left->efs_ifrm_loc_mac, right->efs_ifrm_loc_mac,
490 EFX_MAC_ADDR_LEN))
491 return (B_FALSE);
492
493 return (B_TRUE);
494
495 }
496
497 static __checkReturn boolean_t
ef10_filter_same_dest(__in const efx_filter_spec_t * left,__in const efx_filter_spec_t * right)498 ef10_filter_same_dest(
499 __in const efx_filter_spec_t *left,
500 __in const efx_filter_spec_t *right)
501 {
502 if ((left->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
503 (right->efs_flags & EFX_FILTER_FLAG_RX_RSS)) {
504 if (left->efs_rss_context == right->efs_rss_context)
505 return (B_TRUE);
506 } else if ((~(left->efs_flags) & EFX_FILTER_FLAG_RX_RSS) &&
507 (~(right->efs_flags) & EFX_FILTER_FLAG_RX_RSS)) {
508 if (left->efs_dmaq_id == right->efs_dmaq_id)
509 return (B_TRUE);
510 }
511 return (B_FALSE);
512 }
513
514 static __checkReturn uint32_t
ef10_filter_hash(__in efx_filter_spec_t * spec)515 ef10_filter_hash(
516 __in efx_filter_spec_t *spec)
517 {
518 EFX_STATIC_ASSERT((sizeof (efx_filter_spec_t) % sizeof (uint32_t))
519 == 0);
520 EFX_STATIC_ASSERT((EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid) %
521 sizeof (uint32_t)) == 0);
522
523 /*
524 * As the area of the efx_filter_spec_t we need to hash is DWORD
525 * aligned and an exact number of DWORDs in size we can use the
526 * optimised efx_hash_dwords() rather than efx_hash_bytes()
527 */
528 return (efx_hash_dwords((const uint32_t *)&spec->efs_outer_vid,
529 (sizeof (efx_filter_spec_t) -
530 EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid)) /
531 sizeof (uint32_t), 0));
532 }
533
534 /*
535 * Decide whether a filter should be exclusive or else should allow
536 * delivery to additional recipients. Currently we decide that
537 * filters for specific local unicast MAC and IP addresses are
538 * exclusive.
539 */
540 static __checkReturn boolean_t
ef10_filter_is_exclusive(__in efx_filter_spec_t * spec)541 ef10_filter_is_exclusive(
542 __in efx_filter_spec_t *spec)
543 {
544 if ((spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC) &&
545 !EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac))
546 return (B_TRUE);
547
548 if ((spec->efs_match_flags &
549 (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) ==
550 (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) {
551 if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV4) &&
552 ((spec->efs_loc_host.eo_u8[0] & 0xf) != 0xe))
553 return (B_TRUE);
554 if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV6) &&
555 (spec->efs_loc_host.eo_u8[0] != 0xff))
556 return (B_TRUE);
557 }
558
559 return (B_FALSE);
560 }
561
562 __checkReturn efx_rc_t
ef10_filter_restore(__in efx_nic_t * enp)563 ef10_filter_restore(
564 __in efx_nic_t *enp)
565 {
566 int tbl_id;
567 efx_filter_spec_t *spec;
568 ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
569 boolean_t restoring;
570 efsys_lock_state_t state;
571 efx_rc_t rc;
572
573 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
574 enp->en_family == EFX_FAMILY_MEDFORD ||
575 enp->en_family == EFX_FAMILY_MEDFORD2);
576
577 for (tbl_id = 0; tbl_id < EFX_EF10_FILTER_TBL_ROWS; tbl_id++) {
578 EFSYS_LOCK(enp->en_eslp, state);
579
580 spec = ef10_filter_entry_spec(eftp, tbl_id);
581 if (spec == NULL) {
582 restoring = B_FALSE;
583 } else if (ef10_filter_entry_is_busy(eftp, tbl_id)) {
584 /* Ignore busy entries. */
585 restoring = B_FALSE;
586 } else {
587 ef10_filter_set_entry_busy(eftp, tbl_id);
588 restoring = B_TRUE;
589 }
590
591 EFSYS_UNLOCK(enp->en_eslp, state);
592
593 if (restoring == B_FALSE)
594 continue;
595
596 if (ef10_filter_is_exclusive(spec)) {
597 rc = efx_mcdi_filter_op_add(enp, spec,
598 MC_CMD_FILTER_OP_IN_OP_INSERT,
599 &eftp->eft_entry[tbl_id].efe_handle);
600 } else {
601 rc = efx_mcdi_filter_op_add(enp, spec,
602 MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE,
603 &eftp->eft_entry[tbl_id].efe_handle);
604 }
605
606 if (rc != 0)
607 goto fail1;
608
609 EFSYS_LOCK(enp->en_eslp, state);
610
611 ef10_filter_set_entry_not_busy(eftp, tbl_id);
612
613 EFSYS_UNLOCK(enp->en_eslp, state);
614 }
615
616 return (0);
617
618 fail1:
619 EFSYS_PROBE1(fail1, efx_rc_t, rc);
620
621 return (rc);
622 }
623
624 /*
625 * An arbitrary search limit for the software hash table. As per the linux net
626 * driver.
627 */
628 #define EF10_FILTER_SEARCH_LIMIT 200
629
630 static __checkReturn efx_rc_t
ef10_filter_add_internal(__in efx_nic_t * enp,__inout efx_filter_spec_t * spec,__in boolean_t may_replace,__out_opt uint32_t * filter_id)631 ef10_filter_add_internal(
632 __in efx_nic_t *enp,
633 __inout efx_filter_spec_t *spec,
634 __in boolean_t may_replace,
635 __out_opt uint32_t *filter_id)
636 {
637 efx_rc_t rc;
638 ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
639 efx_filter_spec_t *saved_spec;
640 uint32_t hash;
641 unsigned int depth;
642 int ins_index;
643 boolean_t replacing = B_FALSE;
644 unsigned int i;
645 efsys_lock_state_t state;
646 boolean_t locked = B_FALSE;
647
648 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
649 enp->en_family == EFX_FAMILY_MEDFORD ||
650 enp->en_family == EFX_FAMILY_MEDFORD2);
651
652 hash = ef10_filter_hash(spec);
653
654 /*
655 * FIXME: Add support for inserting filters of different priorities
656 * and removing lower priority multicast filters (bug 42378)
657 */
658
659 /*
660 * Find any existing filters with the same match tuple or
661 * else a free slot to insert at. If any of them are busy,
662 * we have to wait and retry.
663 */
664 for (;;) {
665 ins_index = -1;
666 depth = 1;
667 EFSYS_LOCK(enp->en_eslp, state);
668 locked = B_TRUE;
669
670 for (;;) {
671 i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1);
672 saved_spec = ef10_filter_entry_spec(eftp, i);
673
674 if (!saved_spec) {
675 if (ins_index < 0) {
676 ins_index = i;
677 }
678 } else if (ef10_filter_equal(spec, saved_spec)) {
679 if (ef10_filter_entry_is_busy(eftp, i))
680 break;
681 if (saved_spec->efs_priority
682 == EFX_FILTER_PRI_AUTO) {
683 ins_index = i;
684 goto found;
685 } else if (ef10_filter_is_exclusive(spec)) {
686 if (may_replace) {
687 ins_index = i;
688 goto found;
689 } else {
690 rc = EEXIST;
691 goto fail1;
692 }
693 }
694
695 /* Leave existing */
696 }
697
698 /*
699 * Once we reach the maximum search depth, use
700 * the first suitable slot or return EBUSY if
701 * there was none.
702 */
703 if (depth == EF10_FILTER_SEARCH_LIMIT) {
704 if (ins_index < 0) {
705 rc = EBUSY;
706 goto fail2;
707 }
708 goto found;
709 }
710 depth++;
711 }
712 EFSYS_UNLOCK(enp->en_eslp, state);
713 locked = B_FALSE;
714 }
715
716 found:
717 /*
718 * Create a software table entry if necessary, and mark it
719 * busy. We might yet fail to insert, but any attempt to
720 * insert a conflicting filter while we're waiting for the
721 * firmware must find the busy entry.
722 */
723 saved_spec = ef10_filter_entry_spec(eftp, ins_index);
724 if (saved_spec) {
725 if (saved_spec->efs_priority == EFX_FILTER_PRI_AUTO) {
726 /* This is a filter we are refreshing */
727 ef10_filter_set_entry_not_auto_old(eftp, ins_index);
728 goto out_unlock;
729 }
730 replacing = B_TRUE;
731 } else {
732 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), saved_spec);
733 if (!saved_spec) {
734 rc = ENOMEM;
735 goto fail3;
736 }
737 *saved_spec = *spec;
738 ef10_filter_set_entry(eftp, ins_index, saved_spec);
739 }
740 ef10_filter_set_entry_busy(eftp, ins_index);
741
742 EFSYS_UNLOCK(enp->en_eslp, state);
743 locked = B_FALSE;
744
745 /*
746 * On replacing the filter handle may change after after a successful
747 * replace operation.
748 */
749 if (replacing) {
750 rc = efx_mcdi_filter_op_add(enp, spec,
751 MC_CMD_FILTER_OP_IN_OP_REPLACE,
752 &eftp->eft_entry[ins_index].efe_handle);
753 } else if (ef10_filter_is_exclusive(spec)) {
754 rc = efx_mcdi_filter_op_add(enp, spec,
755 MC_CMD_FILTER_OP_IN_OP_INSERT,
756 &eftp->eft_entry[ins_index].efe_handle);
757 } else {
758 rc = efx_mcdi_filter_op_add(enp, spec,
759 MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE,
760 &eftp->eft_entry[ins_index].efe_handle);
761 }
762
763 if (rc != 0)
764 goto fail4;
765
766 EFSYS_LOCK(enp->en_eslp, state);
767 locked = B_TRUE;
768
769 if (replacing) {
770 /* Update the fields that may differ */
771 saved_spec->efs_priority = spec->efs_priority;
772 saved_spec->efs_flags = spec->efs_flags;
773 saved_spec->efs_rss_context = spec->efs_rss_context;
774 saved_spec->efs_dmaq_id = spec->efs_dmaq_id;
775 }
776
777 ef10_filter_set_entry_not_busy(eftp, ins_index);
778
779 out_unlock:
780
781 EFSYS_UNLOCK(enp->en_eslp, state);
782 locked = B_FALSE;
783
784 if (filter_id)
785 *filter_id = ins_index;
786
787 return (0);
788
789 fail4:
790 EFSYS_PROBE(fail4);
791
792 if (!replacing) {
793 EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), saved_spec);
794 saved_spec = NULL;
795 }
796 ef10_filter_set_entry_not_busy(eftp, ins_index);
797 ef10_filter_set_entry(eftp, ins_index, NULL);
798
799 fail3:
800 EFSYS_PROBE(fail3);
801
802 fail2:
803 EFSYS_PROBE(fail2);
804
805 fail1:
806 EFSYS_PROBE1(fail1, efx_rc_t, rc);
807
808 if (locked)
809 EFSYS_UNLOCK(enp->en_eslp, state);
810
811 return (rc);
812 }
813
814 __checkReturn efx_rc_t
ef10_filter_add(__in efx_nic_t * enp,__inout efx_filter_spec_t * spec,__in boolean_t may_replace)815 ef10_filter_add(
816 __in efx_nic_t *enp,
817 __inout efx_filter_spec_t *spec,
818 __in boolean_t may_replace)
819 {
820 efx_rc_t rc;
821
822 rc = ef10_filter_add_internal(enp, spec, may_replace, NULL);
823 if (rc != 0)
824 goto fail1;
825
826 return (0);
827
828 fail1:
829 EFSYS_PROBE1(fail1, efx_rc_t, rc);
830
831 return (rc);
832 }
833
834 static __checkReturn efx_rc_t
ef10_filter_delete_internal(__in efx_nic_t * enp,__in uint32_t filter_id)835 ef10_filter_delete_internal(
836 __in efx_nic_t *enp,
837 __in uint32_t filter_id)
838 {
839 efx_rc_t rc;
840 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
841 efx_filter_spec_t *spec;
842 efsys_lock_state_t state;
843 uint32_t filter_idx = filter_id % EFX_EF10_FILTER_TBL_ROWS;
844
845 /*
846 * Find the software table entry and mark it busy. Don't
847 * remove it yet; any attempt to update while we're waiting
848 * for the firmware must find the busy entry.
849 *
850 * FIXME: What if the busy flag is never cleared?
851 */
852 EFSYS_LOCK(enp->en_eslp, state);
853 while (ef10_filter_entry_is_busy(table, filter_idx)) {
854 EFSYS_UNLOCK(enp->en_eslp, state);
855 EFSYS_SPIN(1);
856 EFSYS_LOCK(enp->en_eslp, state);
857 }
858 if ((spec = ef10_filter_entry_spec(table, filter_idx)) != NULL) {
859 ef10_filter_set_entry_busy(table, filter_idx);
860 }
861 EFSYS_UNLOCK(enp->en_eslp, state);
862
863 if (spec == NULL) {
864 rc = ENOENT;
865 goto fail1;
866 }
867
868 /*
869 * Try to remove the hardware filter. This may fail if the MC has
870 * rebooted (which frees all hardware filter resources).
871 */
872 if (ef10_filter_is_exclusive(spec)) {
873 rc = efx_mcdi_filter_op_delete(enp,
874 MC_CMD_FILTER_OP_IN_OP_REMOVE,
875 &table->eft_entry[filter_idx].efe_handle);
876 } else {
877 rc = efx_mcdi_filter_op_delete(enp,
878 MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE,
879 &table->eft_entry[filter_idx].efe_handle);
880 }
881
882 /* Free the software table entry */
883 EFSYS_LOCK(enp->en_eslp, state);
884 ef10_filter_set_entry_not_busy(table, filter_idx);
885 ef10_filter_set_entry(table, filter_idx, NULL);
886 EFSYS_UNLOCK(enp->en_eslp, state);
887
888 EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
889
890 /* Check result of hardware filter removal */
891 if (rc != 0)
892 goto fail2;
893
894 return (0);
895
896 fail2:
897 EFSYS_PROBE(fail2);
898
899 fail1:
900 EFSYS_PROBE1(fail1, efx_rc_t, rc);
901
902 return (rc);
903 }
904
905 __checkReturn efx_rc_t
ef10_filter_delete(__in efx_nic_t * enp,__inout efx_filter_spec_t * spec)906 ef10_filter_delete(
907 __in efx_nic_t *enp,
908 __inout efx_filter_spec_t *spec)
909 {
910 efx_rc_t rc;
911 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
912 efx_filter_spec_t *saved_spec;
913 unsigned int hash;
914 unsigned int depth;
915 unsigned int i;
916 efsys_lock_state_t state;
917 boolean_t locked = B_FALSE;
918
919 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
920 enp->en_family == EFX_FAMILY_MEDFORD ||
921 enp->en_family == EFX_FAMILY_MEDFORD2);
922
923 hash = ef10_filter_hash(spec);
924
925 EFSYS_LOCK(enp->en_eslp, state);
926 locked = B_TRUE;
927
928 depth = 1;
929 for (;;) {
930 i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1);
931 saved_spec = ef10_filter_entry_spec(table, i);
932 if (saved_spec && ef10_filter_equal(spec, saved_spec) &&
933 ef10_filter_same_dest(spec, saved_spec)) {
934 break;
935 }
936 if (depth == EF10_FILTER_SEARCH_LIMIT) {
937 rc = ENOENT;
938 goto fail1;
939 }
940 depth++;
941 }
942
943 EFSYS_UNLOCK(enp->en_eslp, state);
944 locked = B_FALSE;
945
946 rc = ef10_filter_delete_internal(enp, i);
947 if (rc != 0)
948 goto fail2;
949
950 return (0);
951
952 fail2:
953 EFSYS_PROBE(fail2);
954
955 fail1:
956 EFSYS_PROBE1(fail1, efx_rc_t, rc);
957
958 if (locked)
959 EFSYS_UNLOCK(enp->en_eslp, state);
960
961 return (rc);
962 }
963
964 static __checkReturn efx_rc_t
efx_mcdi_get_parser_disp_info(__in efx_nic_t * enp,__out_ecount (buffer_length)uint32_t * buffer,__in size_t buffer_length,__in boolean_t encap,__out size_t * list_lengthp)965 efx_mcdi_get_parser_disp_info(
966 __in efx_nic_t *enp,
967 __out_ecount(buffer_length) uint32_t *buffer,
968 __in size_t buffer_length,
969 __in boolean_t encap,
970 __out size_t *list_lengthp)
971 {
972 efx_mcdi_req_t req;
973 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PARSER_DISP_INFO_IN_LEN,
974 MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX);
975 size_t matches_count;
976 size_t list_size;
977 efx_rc_t rc;
978
979 req.emr_cmd = MC_CMD_GET_PARSER_DISP_INFO;
980 req.emr_in_buf = payload;
981 req.emr_in_length = MC_CMD_GET_PARSER_DISP_INFO_IN_LEN;
982 req.emr_out_buf = payload;
983 req.emr_out_length = MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX;
984
985 MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP, encap ?
986 MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_ENCAP_RX_MATCHES :
987 MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES);
988
989 efx_mcdi_execute(enp, &req);
990
991 if (req.emr_rc != 0) {
992 rc = req.emr_rc;
993 goto fail1;
994 }
995
996 matches_count = MCDI_OUT_DWORD(req,
997 GET_PARSER_DISP_INFO_OUT_NUM_SUPPORTED_MATCHES);
998
999 if (req.emr_out_length_used <
1000 MC_CMD_GET_PARSER_DISP_INFO_OUT_LEN(matches_count)) {
1001 rc = EMSGSIZE;
1002 goto fail2;
1003 }
1004
1005 *list_lengthp = matches_count;
1006
1007 if (buffer_length < matches_count) {
1008 rc = ENOSPC;
1009 goto fail3;
1010 }
1011
1012 /*
1013 * Check that the elements in the list in the MCDI response are the size
1014 * we expect, so we can just copy them directly. Any conversion of the
1015 * flags is handled by the caller.
1016 */
1017 EFX_STATIC_ASSERT(sizeof (uint32_t) ==
1018 MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN);
1019
1020 list_size = matches_count *
1021 MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN;
1022 memcpy(buffer,
1023 MCDI_OUT2(req, uint32_t,
1024 GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES),
1025 list_size);
1026
1027 return (0);
1028
1029 fail3:
1030 EFSYS_PROBE(fail3);
1031 fail2:
1032 EFSYS_PROBE(fail2);
1033 fail1:
1034 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1035
1036 return (rc);
1037 }
1038
1039 __checkReturn efx_rc_t
ef10_filter_supported_filters(__in efx_nic_t * enp,__out_ecount (buffer_length)uint32_t * buffer,__in size_t buffer_length,__out size_t * list_lengthp)1040 ef10_filter_supported_filters(
1041 __in efx_nic_t *enp,
1042 __out_ecount(buffer_length) uint32_t *buffer,
1043 __in size_t buffer_length,
1044 __out size_t *list_lengthp)
1045 {
1046 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1047 size_t mcdi_list_length;
1048 size_t mcdi_encap_list_length;
1049 size_t list_length;
1050 uint32_t i;
1051 uint32_t next_buf_idx;
1052 size_t next_buf_length;
1053 efx_rc_t rc;
1054 boolean_t no_space = B_FALSE;
1055 efx_filter_match_flags_t all_filter_flags =
1056 (EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_LOC_HOST |
1057 EFX_FILTER_MATCH_REM_MAC | EFX_FILTER_MATCH_REM_PORT |
1058 EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_PORT |
1059 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_INNER_VID |
1060 EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_IP_PROTO |
1061 EFX_FILTER_MATCH_VNI_OR_VSID |
1062 EFX_FILTER_MATCH_IFRM_LOC_MAC |
1063 EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST |
1064 EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST |
1065 EFX_FILTER_MATCH_ENCAP_TYPE |
1066 EFX_FILTER_MATCH_UNKNOWN_MCAST_DST |
1067 EFX_FILTER_MATCH_UNKNOWN_UCAST_DST);
1068
1069 /*
1070 * Two calls to MC_CMD_GET_PARSER_DISP_INFO are needed: one to get the
1071 * list of supported filters for ordinary packets, and then another to
1072 * get the list of supported filters for encapsulated packets. To
1073 * distinguish the second list from the first, the
1074 * EFX_FILTER_MATCH_ENCAP_TYPE flag is added to each filter for
1075 * encapsulated packets.
1076 */
1077 rc = efx_mcdi_get_parser_disp_info(enp, buffer, buffer_length, B_FALSE,
1078 &mcdi_list_length);
1079 if (rc != 0) {
1080 if (rc == ENOSPC)
1081 no_space = B_TRUE;
1082 else
1083 goto fail1;
1084 }
1085
1086 if (no_space) {
1087 next_buf_idx = 0;
1088 next_buf_length = 0;
1089 } else {
1090 EFSYS_ASSERT(mcdi_list_length <= buffer_length);
1091 next_buf_idx = mcdi_list_length;
1092 next_buf_length = buffer_length - mcdi_list_length;
1093 }
1094
1095 if (encp->enc_tunnel_encapsulations_supported != 0) {
1096 rc = efx_mcdi_get_parser_disp_info(enp, &buffer[next_buf_idx],
1097 next_buf_length, B_TRUE, &mcdi_encap_list_length);
1098 if (rc != 0) {
1099 if (rc == ENOSPC)
1100 no_space = B_TRUE;
1101 else
1102 goto fail2;
1103 } else {
1104 for (i = next_buf_idx;
1105 i < next_buf_idx + mcdi_encap_list_length; i++)
1106 buffer[i] |= EFX_FILTER_MATCH_ENCAP_TYPE;
1107 }
1108 } else {
1109 mcdi_encap_list_length = 0;
1110 }
1111
1112 if (no_space) {
1113 *list_lengthp = mcdi_list_length + mcdi_encap_list_length;
1114 rc = ENOSPC;
1115 goto fail3;
1116 }
1117
1118 /*
1119 * The static assertions in ef10_filter_init() ensure that the values of
1120 * the EFX_FILTER_MATCH flags match those used by MCDI, so they don't
1121 * need to be converted.
1122 *
1123 * In case support is added to MCDI for additional flags, remove any
1124 * matches from the list which include flags we don't support. The order
1125 * of the matches is preserved as they are ordered from highest to
1126 * lowest priority.
1127 */
1128 EFSYS_ASSERT(mcdi_list_length + mcdi_encap_list_length <=
1129 buffer_length);
1130 list_length = 0;
1131 for (i = 0; i < mcdi_list_length + mcdi_encap_list_length; i++) {
1132 if ((buffer[i] & ~all_filter_flags) == 0) {
1133 buffer[list_length] = buffer[i];
1134 list_length++;
1135 }
1136 }
1137
1138 *list_lengthp = list_length;
1139
1140 return (0);
1141
1142 fail3:
1143 EFSYS_PROBE(fail3);
1144 fail2:
1145 EFSYS_PROBE(fail2);
1146 fail1:
1147 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1148
1149 return (rc);
1150 }
1151
1152 static __checkReturn efx_rc_t
1153 ef10_filter_insert_unicast(
1154 __in efx_nic_t *enp,
1155 __in_ecount(6) uint8_t const *addr,
1156 __in efx_filter_flags_t filter_flags)
1157 {
1158 ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
1159 efx_filter_spec_t spec;
1160 efx_rc_t rc;
1161
1162 /* Insert the filter for the local station address */
1163 efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1164 filter_flags,
1165 eftp->eft_default_rxq);
1166 rc = efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC,
1167 addr);
1168 if (rc != 0)
1169 goto fail1;
1170
1171 rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1172 &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]);
1173 if (rc != 0)
1174 goto fail2;
1175
1176 eftp->eft_unicst_filter_count++;
1177 EFSYS_ASSERT(eftp->eft_unicst_filter_count <=
1178 EFX_EF10_FILTER_UNICAST_FILTERS_MAX);
1179
1180 return (0);
1181
1182 fail2:
1183 EFSYS_PROBE(fail2);
1184 fail1:
1185 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1186 return (rc);
1187 }
1188
1189 static __checkReturn efx_rc_t
ef10_filter_insert_all_unicast(__in efx_nic_t * enp,__in efx_filter_flags_t filter_flags)1190 ef10_filter_insert_all_unicast(
1191 __in efx_nic_t *enp,
1192 __in efx_filter_flags_t filter_flags)
1193 {
1194 ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
1195 efx_filter_spec_t spec;
1196 efx_rc_t rc;
1197
1198 /* Insert the unknown unicast filter */
1199 efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1200 filter_flags,
1201 eftp->eft_default_rxq);
1202 rc = efx_filter_spec_set_uc_def(&spec);
1203 if (rc != 0)
1204 goto fail1;
1205 rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1206 &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]);
1207 if (rc != 0)
1208 goto fail2;
1209
1210 eftp->eft_unicst_filter_count++;
1211 EFSYS_ASSERT(eftp->eft_unicst_filter_count <=
1212 EFX_EF10_FILTER_UNICAST_FILTERS_MAX);
1213
1214 return (0);
1215
1216 fail2:
1217 EFSYS_PROBE(fail2);
1218 fail1:
1219 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1220 return (rc);
1221 }
1222
1223 static __checkReturn efx_rc_t
1224 ef10_filter_insert_multicast_list(
1225 __in efx_nic_t *enp,
1226 __in boolean_t mulcst,
1227 __in boolean_t brdcst,
1228 __in_ecount(6*count) uint8_t const *addrs,
1229 __in uint32_t count,
1230 __in efx_filter_flags_t filter_flags,
1231 __in boolean_t rollback)
1232 {
1233 ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
1234 efx_filter_spec_t spec;
1235 uint8_t addr[6];
1236 uint32_t i;
1237 uint32_t filter_index;
1238 uint32_t filter_count;
1239 efx_rc_t rc;
1240
1241 if (mulcst == B_FALSE)
1242 count = 0;
1243
1244 if (count + (brdcst ? 1 : 0) >
1245 EFX_ARRAY_SIZE(eftp->eft_mulcst_filter_indexes)) {
1246 /* Too many MAC addresses */
1247 rc = EINVAL;
1248 goto fail1;
1249 }
1250
1251 /* Insert/renew multicast address list filters */
1252 filter_count = 0;
1253 for (i = 0; i < count; i++) {
1254 efx_filter_spec_init_rx(&spec,
1255 EFX_FILTER_PRI_AUTO,
1256 filter_flags,
1257 eftp->eft_default_rxq);
1258
1259 rc = efx_filter_spec_set_eth_local(&spec,
1260 EFX_FILTER_SPEC_VID_UNSPEC,
1261 &addrs[i * EFX_MAC_ADDR_LEN]);
1262 if (rc != 0) {
1263 if (rollback == B_TRUE) {
1264 /* Only stop upon failure if told to rollback */
1265 goto rollback;
1266 } else {
1267 /*
1268 * Don't try to add a filter with a corrupt
1269 * specification.
1270 */
1271 continue;
1272 }
1273 }
1274
1275 rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1276 &filter_index);
1277
1278 if (rc == 0) {
1279 eftp->eft_mulcst_filter_indexes[filter_count] =
1280 filter_index;
1281 filter_count++;
1282 } else if (rollback == B_TRUE) {
1283 /* Only stop upon failure if told to rollback */
1284 goto rollback;
1285 }
1286 }
1287
1288 if (brdcst == B_TRUE) {
1289 /* Insert/renew broadcast address filter */
1290 efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1291 filter_flags,
1292 eftp->eft_default_rxq);
1293
1294 EFX_MAC_BROADCAST_ADDR_SET(addr);
1295 rc = efx_filter_spec_set_eth_local(&spec,
1296 EFX_FILTER_SPEC_VID_UNSPEC, addr);
1297 if ((rc != 0) && (rollback == B_TRUE)) {
1298 /* Only stop upon failure if told to rollback */
1299 goto rollback;
1300 }
1301
1302 rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1303 &filter_index);
1304
1305 if (rc == 0) {
1306 eftp->eft_mulcst_filter_indexes[filter_count] =
1307 filter_index;
1308 filter_count++;
1309 } else if (rollback == B_TRUE) {
1310 /* Only stop upon failure if told to rollback */
1311 goto rollback;
1312 }
1313 }
1314
1315 eftp->eft_mulcst_filter_count = filter_count;
1316 eftp->eft_using_all_mulcst = B_FALSE;
1317
1318 return (0);
1319
1320 rollback:
1321 /* Remove any filters we have inserted */
1322 i = filter_count;
1323 while (i--) {
1324 (void) ef10_filter_delete_internal(enp,
1325 eftp->eft_mulcst_filter_indexes[i]);
1326 }
1327 eftp->eft_mulcst_filter_count = 0;
1328
1329 fail1:
1330 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1331
1332 return (rc);
1333 }
1334
1335 static __checkReturn efx_rc_t
ef10_filter_insert_all_multicast(__in efx_nic_t * enp,__in efx_filter_flags_t filter_flags)1336 ef10_filter_insert_all_multicast(
1337 __in efx_nic_t *enp,
1338 __in efx_filter_flags_t filter_flags)
1339 {
1340 ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
1341 efx_filter_spec_t spec;
1342 efx_rc_t rc;
1343
1344 /* Insert the unknown multicast filter */
1345 efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1346 filter_flags,
1347 eftp->eft_default_rxq);
1348 rc = efx_filter_spec_set_mc_def(&spec);
1349 if (rc != 0)
1350 goto fail1;
1351
1352 rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1353 &eftp->eft_mulcst_filter_indexes[0]);
1354 if (rc != 0)
1355 goto fail2;
1356
1357 eftp->eft_mulcst_filter_count = 1;
1358 eftp->eft_using_all_mulcst = B_TRUE;
1359
1360 /*
1361 * FIXME: If brdcst == B_FALSE, add a filter to drop broadcast traffic.
1362 */
1363
1364 return (0);
1365
1366 fail2:
1367 EFSYS_PROBE(fail2);
1368 fail1:
1369 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1370
1371 return (rc);
1372 }
1373
1374 typedef struct ef10_filter_encap_entry_s {
1375 uint16_t ether_type;
1376 efx_tunnel_protocol_t encap_type;
1377 uint32_t inner_frame_match;
1378 } ef10_filter_encap_entry_t;
1379
1380 #define EF10_ENCAP_FILTER_ENTRY(ipv, encap_type, inner_frame_match) \
1381 { EFX_ETHER_TYPE_##ipv, EFX_TUNNEL_PROTOCOL_##encap_type, \
1382 EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_##inner_frame_match }
1383
1384 static ef10_filter_encap_entry_t ef10_filter_encap_list[] = {
1385 EF10_ENCAP_FILTER_ENTRY(IPV4, VXLAN, UCAST_DST),
1386 EF10_ENCAP_FILTER_ENTRY(IPV4, VXLAN, MCAST_DST),
1387 EF10_ENCAP_FILTER_ENTRY(IPV6, VXLAN, UCAST_DST),
1388 EF10_ENCAP_FILTER_ENTRY(IPV6, VXLAN, MCAST_DST),
1389
1390 EF10_ENCAP_FILTER_ENTRY(IPV4, GENEVE, UCAST_DST),
1391 EF10_ENCAP_FILTER_ENTRY(IPV4, GENEVE, MCAST_DST),
1392 EF10_ENCAP_FILTER_ENTRY(IPV6, GENEVE, UCAST_DST),
1393 EF10_ENCAP_FILTER_ENTRY(IPV6, GENEVE, MCAST_DST),
1394
1395 EF10_ENCAP_FILTER_ENTRY(IPV4, NVGRE, UCAST_DST),
1396 EF10_ENCAP_FILTER_ENTRY(IPV4, NVGRE, MCAST_DST),
1397 EF10_ENCAP_FILTER_ENTRY(IPV6, NVGRE, UCAST_DST),
1398 EF10_ENCAP_FILTER_ENTRY(IPV6, NVGRE, MCAST_DST),
1399 };
1400
1401 #undef EF10_ENCAP_FILTER_ENTRY
1402
1403 static __checkReturn efx_rc_t
ef10_filter_insert_encap_filters(__in efx_nic_t * enp,__in boolean_t mulcst,__in efx_filter_flags_t filter_flags)1404 ef10_filter_insert_encap_filters(
1405 __in efx_nic_t *enp,
1406 __in boolean_t mulcst,
1407 __in efx_filter_flags_t filter_flags)
1408 {
1409 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1410 uint32_t i;
1411 efx_rc_t rc;
1412
1413 EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(ef10_filter_encap_list) <=
1414 EFX_ARRAY_SIZE(table->eft_encap_filter_indexes));
1415
1416 /*
1417 * On Medford, full-featured firmware can identify packets as being
1418 * tunnel encapsulated, even if no encapsulated packet offloads are in
1419 * use. When packets are identified as such, ordinary filters are not
1420 * applied, only ones specific to encapsulated packets. Hence we need to
1421 * insert filters for encapsulated packets in order to receive them.
1422 *
1423 * Separate filters need to be inserted for each ether type,
1424 * encapsulation type, and inner frame type (unicast or multicast). To
1425 * keep things simple and reduce the number of filters needed, catch-all
1426 * filters for all combinations of types are inserted, even if
1427 * all_unicst or all_mulcst have not been set. (These catch-all filters
1428 * may well, however, fail to insert on unprivileged functions.)
1429 */
1430 table->eft_encap_filter_count = 0;
1431 for (i = 0; i < EFX_ARRAY_SIZE(ef10_filter_encap_list); i++) {
1432 efx_filter_spec_t spec;
1433 ef10_filter_encap_entry_t *encap_filter =
1434 &ef10_filter_encap_list[i];
1435
1436 /*
1437 * Skip multicast filters if we've not been asked for
1438 * any multicast traffic.
1439 */
1440 if ((mulcst == B_FALSE) &&
1441 (encap_filter->inner_frame_match ==
1442 EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_MCAST_DST))
1443 continue;
1444
1445 efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1446 filter_flags,
1447 table->eft_default_rxq);
1448 efx_filter_spec_set_ether_type(&spec, encap_filter->ether_type);
1449 rc = efx_filter_spec_set_encap_type(&spec,
1450 encap_filter->encap_type,
1451 encap_filter->inner_frame_match);
1452 if (rc != 0)
1453 goto fail1;
1454
1455 rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1456 &table->eft_encap_filter_indexes[
1457 table->eft_encap_filter_count]);
1458 if (rc != 0) {
1459 if (rc != EACCES)
1460 goto fail2;
1461 } else {
1462 table->eft_encap_filter_count++;
1463 }
1464 }
1465
1466 return (0);
1467
1468 fail2:
1469 EFSYS_PROBE(fail2);
1470 fail1:
1471 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1472
1473 return (rc);
1474 }
1475
1476 static void
ef10_filter_remove_old(__in efx_nic_t * enp)1477 ef10_filter_remove_old(
1478 __in efx_nic_t *enp)
1479 {
1480 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1481 uint32_t i;
1482
1483 for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) {
1484 if (ef10_filter_entry_is_auto_old(table, i)) {
1485 (void) ef10_filter_delete_internal(enp, i);
1486 }
1487 }
1488 }
1489
1490 static __checkReturn efx_rc_t
ef10_filter_get_workarounds(__in efx_nic_t * enp)1491 ef10_filter_get_workarounds(
1492 __in efx_nic_t *enp)
1493 {
1494 efx_nic_cfg_t *encp = &enp->en_nic_cfg;
1495 uint32_t implemented = 0;
1496 uint32_t enabled = 0;
1497 efx_rc_t rc;
1498
1499 rc = efx_mcdi_get_workarounds(enp, &implemented, &enabled);
1500 if (rc == 0) {
1501 /* Check if chained multicast filter support is enabled */
1502 if (implemented & enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807)
1503 encp->enc_bug26807_workaround = B_TRUE;
1504 else
1505 encp->enc_bug26807_workaround = B_FALSE;
1506 } else if (rc == ENOTSUP) {
1507 /*
1508 * Firmware is too old to support GET_WORKAROUNDS, and support
1509 * for this workaround was implemented later.
1510 */
1511 encp->enc_bug26807_workaround = B_FALSE;
1512 } else {
1513 goto fail1;
1514 }
1515
1516 return (0);
1517
1518 fail1:
1519 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1520
1521 return (rc);
1522
1523 }
1524
1525 /*
1526 * Reconfigure all filters.
1527 * If all_unicst and/or all mulcst filters cannot be applied then
1528 * return ENOTSUP (Note the filters for the specified addresses are
1529 * still applied in this case).
1530 */
1531 __checkReturn efx_rc_t
1532 ef10_filter_reconfigure(
1533 __in efx_nic_t *enp,
1534 __in_ecount(6) uint8_t const *mac_addr,
1535 __in boolean_t all_unicst,
1536 __in boolean_t mulcst,
1537 __in boolean_t all_mulcst,
1538 __in boolean_t brdcst,
1539 __in_ecount(6*count) uint8_t const *addrs,
1540 __in uint32_t count)
1541 {
1542 efx_nic_cfg_t *encp = &enp->en_nic_cfg;
1543 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1544 efx_filter_flags_t filter_flags;
1545 unsigned int i;
1546 efx_rc_t all_unicst_rc = 0;
1547 efx_rc_t all_mulcst_rc = 0;
1548 efx_rc_t rc;
1549
1550 if (table->eft_default_rxq == NULL) {
1551 /*
1552 * Filters direct traffic to the default RXQ, and so cannot be
1553 * inserted until it is available. Any currently configured
1554 * filters must be removed (ignore errors in case the MC
1555 * has rebooted, which removes hardware filters).
1556 */
1557 for (i = 0; i < table->eft_unicst_filter_count; i++) {
1558 (void) ef10_filter_delete_internal(enp,
1559 table->eft_unicst_filter_indexes[i]);
1560 }
1561 table->eft_unicst_filter_count = 0;
1562
1563 for (i = 0; i < table->eft_mulcst_filter_count; i++) {
1564 (void) ef10_filter_delete_internal(enp,
1565 table->eft_mulcst_filter_indexes[i]);
1566 }
1567 table->eft_mulcst_filter_count = 0;
1568
1569 for (i = 0; i < table->eft_encap_filter_count; i++) {
1570 (void) ef10_filter_delete_internal(enp,
1571 table->eft_encap_filter_indexes[i]);
1572 }
1573 table->eft_encap_filter_count = 0;
1574
1575 return (0);
1576 }
1577
1578 if (table->eft_using_rss)
1579 filter_flags = EFX_FILTER_FLAG_RX_RSS;
1580 else
1581 filter_flags = 0;
1582
1583 /* Mark old filters which may need to be removed */
1584 for (i = 0; i < table->eft_unicst_filter_count; i++) {
1585 ef10_filter_set_entry_auto_old(table,
1586 table->eft_unicst_filter_indexes[i]);
1587 }
1588 for (i = 0; i < table->eft_mulcst_filter_count; i++) {
1589 ef10_filter_set_entry_auto_old(table,
1590 table->eft_mulcst_filter_indexes[i]);
1591 }
1592 for (i = 0; i < table->eft_encap_filter_count; i++) {
1593 ef10_filter_set_entry_auto_old(table,
1594 table->eft_encap_filter_indexes[i]);
1595 }
1596
1597 /*
1598 * Insert or renew unicast filters.
1599 *
1600 * Firmware does not perform chaining on unicast filters. As traffic is
1601 * therefore only delivered to the first matching filter, we should
1602 * always insert the specific filter for our MAC address, to try and
1603 * ensure we get that traffic.
1604 *
1605 * (If the filter for our MAC address has already been inserted by
1606 * another function, we won't receive traffic sent to us, even if we
1607 * insert a unicast mismatch filter. To prevent traffic stealing, this
1608 * therefore relies on the privilege model only allowing functions to
1609 * insert filters for their own MAC address unless explicitly given
1610 * additional privileges by the user. This also means that, even on a
1611 * priviliged function, inserting a unicast mismatch filter may not
1612 * catch all traffic in multi PCI function scenarios.)
1613 */
1614 table->eft_unicst_filter_count = 0;
1615 rc = ef10_filter_insert_unicast(enp, mac_addr, filter_flags);
1616 if (all_unicst || (rc != 0)) {
1617 all_unicst_rc = ef10_filter_insert_all_unicast(enp,
1618 filter_flags);
1619 if ((rc != 0) && (all_unicst_rc != 0))
1620 goto fail1;
1621 }
1622
1623 /*
1624 * WORKAROUND_BUG26807 controls firmware support for chained multicast
1625 * filters, and can only be enabled or disabled when the hardware filter
1626 * table is empty.
1627 *
1628 * Chained multicast filters require support from the datapath firmware,
1629 * and may not be available (e.g. low-latency variants or old Huntington
1630 * firmware).
1631 *
1632 * Firmware will reset (FLR) functions which have inserted filters in
1633 * the hardware filter table when the workaround is enabled/disabled.
1634 * Functions without any hardware filters are not reset.
1635 *
1636 * Re-check if the workaround is enabled after adding unicast hardware
1637 * filters. This ensures that encp->enc_bug26807_workaround matches the
1638 * firmware state, and that later changes to enable/disable the
1639 * workaround will result in this function seeing a reset (FLR).
1640 *
1641 * In common-code drivers, we only support multiple PCI function
1642 * scenarios with firmware that supports multicast chaining, so we can
1643 * assume it is enabled for such cases and hence simplify the filter
1644 * insertion logic. Firmware that does not support multicast chaining
1645 * does not support multiple PCI function configurations either, so
1646 * filter insertion is much simpler and the same strategies can still be
1647 * used.
1648 */
1649 if ((rc = ef10_filter_get_workarounds(enp)) != 0)
1650 goto fail2;
1651
1652 if ((table->eft_using_all_mulcst != all_mulcst) &&
1653 (encp->enc_bug26807_workaround == B_TRUE)) {
1654 /*
1655 * Multicast filter chaining is enabled, so traffic that matches
1656 * more than one multicast filter will be replicated and
1657 * delivered to multiple recipients. To avoid this duplicate
1658 * delivery, remove old multicast filters before inserting new
1659 * multicast filters.
1660 */
1661 ef10_filter_remove_old(enp);
1662 }
1663
1664 /* Insert or renew multicast filters */
1665 if (all_mulcst == B_TRUE) {
1666 /*
1667 * Insert the all multicast filter. If that fails, try to insert
1668 * all of our multicast filters (but without rollback on
1669 * failure).
1670 */
1671 all_mulcst_rc = ef10_filter_insert_all_multicast(enp,
1672 filter_flags);
1673 if (all_mulcst_rc != 0) {
1674 rc = ef10_filter_insert_multicast_list(enp, B_TRUE,
1675 brdcst, addrs, count, filter_flags, B_FALSE);
1676 if (rc != 0)
1677 goto fail3;
1678 }
1679 } else {
1680 /*
1681 * Insert filters for multicast addresses.
1682 * If any insertion fails, then rollback and try to insert the
1683 * all multicast filter instead.
1684 * If that also fails, try to insert all of the multicast
1685 * filters (but without rollback on failure).
1686 */
1687 rc = ef10_filter_insert_multicast_list(enp, mulcst, brdcst,
1688 addrs, count, filter_flags, B_TRUE);
1689 if (rc != 0) {
1690 if ((table->eft_using_all_mulcst == B_FALSE) &&
1691 (encp->enc_bug26807_workaround == B_TRUE)) {
1692 /*
1693 * Multicast filter chaining is on, so remove
1694 * old filters before inserting the multicast
1695 * all filter to avoid duplicate delivery caused
1696 * by packets matching multiple filters.
1697 */
1698 ef10_filter_remove_old(enp);
1699 }
1700
1701 rc = ef10_filter_insert_all_multicast(enp,
1702 filter_flags);
1703 if (rc != 0) {
1704 rc = ef10_filter_insert_multicast_list(enp,
1705 mulcst, brdcst,
1706 addrs, count, filter_flags, B_FALSE);
1707 if (rc != 0)
1708 goto fail4;
1709 }
1710 }
1711 }
1712
1713 if (encp->enc_tunnel_encapsulations_supported != 0) {
1714 /* Try to insert filters for encapsulated packets. */
1715 (void) ef10_filter_insert_encap_filters(enp,
1716 mulcst || all_mulcst || brdcst,
1717 filter_flags);
1718 }
1719
1720 /* Remove old filters which were not renewed */
1721 ef10_filter_remove_old(enp);
1722
1723 /* report if any optional flags were rejected */
1724 if (((all_unicst != B_FALSE) && (all_unicst_rc != 0)) ||
1725 ((all_mulcst != B_FALSE) && (all_mulcst_rc != 0))) {
1726 rc = ENOTSUP;
1727 }
1728
1729 return (rc);
1730
1731 fail4:
1732 EFSYS_PROBE(fail4);
1733 fail3:
1734 EFSYS_PROBE(fail3);
1735 fail2:
1736 EFSYS_PROBE(fail2);
1737 fail1:
1738 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1739
1740 /* Clear auto old flags */
1741 for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) {
1742 if (ef10_filter_entry_is_auto_old(table, i)) {
1743 ef10_filter_set_entry_not_auto_old(table, i);
1744 }
1745 }
1746
1747 return (rc);
1748 }
1749
1750 void
ef10_filter_get_default_rxq(__in efx_nic_t * enp,__out efx_rxq_t ** erpp,__out boolean_t * using_rss)1751 ef10_filter_get_default_rxq(
1752 __in efx_nic_t *enp,
1753 __out efx_rxq_t **erpp,
1754 __out boolean_t *using_rss)
1755 {
1756 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1757
1758 *erpp = table->eft_default_rxq;
1759 *using_rss = table->eft_using_rss;
1760 }
1761
1762 void
ef10_filter_default_rxq_set(__in efx_nic_t * enp,__in efx_rxq_t * erp,__in boolean_t using_rss)1763 ef10_filter_default_rxq_set(
1764 __in efx_nic_t *enp,
1765 __in efx_rxq_t *erp,
1766 __in boolean_t using_rss)
1767 {
1768 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1769
1770 #if EFSYS_OPT_RX_SCALE
1771 EFSYS_ASSERT((using_rss == B_FALSE) ||
1772 (enp->en_rss_context != EF10_RSS_CONTEXT_INVALID));
1773 table->eft_using_rss = using_rss;
1774 #else
1775 EFSYS_ASSERT(using_rss == B_FALSE);
1776 table->eft_using_rss = B_FALSE;
1777 #endif
1778 table->eft_default_rxq = erp;
1779 }
1780
1781 void
ef10_filter_default_rxq_clear(__in efx_nic_t * enp)1782 ef10_filter_default_rxq_clear(
1783 __in efx_nic_t *enp)
1784 {
1785 ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1786
1787 table->eft_default_rxq = NULL;
1788 table->eft_using_rss = B_FALSE;
1789 }
1790
1791 #endif /* EFSYS_OPT_FILTER */
1792
1793 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
1794