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