xref: /freebsd/sys/dev/sfxge/common/efx_filter.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2007-2016 Solarflare Communications Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice,
11  *    this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * The views and conclusions contained in the software and documentation are
29  * those of the authors and should not be interpreted as representing official
30  * policies, either expressed or implied, of the FreeBSD Project.
31  */
32 
33 #include <sys/cdefs.h>
34 #include "efx.h"
35 #include "efx_impl.h"
36 
37 #if EFSYS_OPT_FILTER
38 
39 #if EFSYS_OPT_SIENA
40 
41 static	__checkReturn	efx_rc_t
42 siena_filter_init(
43 	__in		efx_nic_t *enp);
44 
45 static			void
46 siena_filter_fini(
47 	__in		efx_nic_t *enp);
48 
49 static	__checkReturn	efx_rc_t
50 siena_filter_restore(
51 	__in		efx_nic_t *enp);
52 
53 static	__checkReturn	efx_rc_t
54 siena_filter_add(
55 	__in		efx_nic_t *enp,
56 	__inout		efx_filter_spec_t *spec,
57 	__in		boolean_t may_replace);
58 
59 static	__checkReturn	efx_rc_t
60 siena_filter_delete(
61 	__in		efx_nic_t *enp,
62 	__inout		efx_filter_spec_t *spec);
63 
64 static	__checkReturn	efx_rc_t
65 siena_filter_supported_filters(
66 	__in				efx_nic_t *enp,
67 	__out_ecount(buffer_length)	uint32_t *buffer,
68 	__in				size_t buffer_length,
69 	__out				size_t *list_lengthp);
70 
71 #endif /* EFSYS_OPT_SIENA */
72 
73 #if EFSYS_OPT_SIENA
74 static const efx_filter_ops_t	__efx_filter_siena_ops = {
75 	siena_filter_init,		/* efo_init */
76 	siena_filter_fini,		/* efo_fini */
77 	siena_filter_restore,		/* efo_restore */
78 	siena_filter_add,		/* efo_add */
79 	siena_filter_delete,		/* efo_delete */
80 	siena_filter_supported_filters,	/* efo_supported_filters */
81 	NULL,				/* efo_reconfigure */
82 };
83 #endif /* EFSYS_OPT_SIENA */
84 
85 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
86 static const efx_filter_ops_t	__efx_filter_ef10_ops = {
87 	ef10_filter_init,		/* efo_init */
88 	ef10_filter_fini,		/* efo_fini */
89 	ef10_filter_restore,		/* efo_restore */
90 	ef10_filter_add,		/* efo_add */
91 	ef10_filter_delete,		/* efo_delete */
92 	ef10_filter_supported_filters,	/* efo_supported_filters */
93 	ef10_filter_reconfigure,	/* efo_reconfigure */
94 };
95 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
96 
97 	__checkReturn	efx_rc_t
efx_filter_insert(__in efx_nic_t * enp,__inout efx_filter_spec_t * spec)98 efx_filter_insert(
99 	__in		efx_nic_t *enp,
100 	__inout		efx_filter_spec_t *spec)
101 {
102 	const efx_filter_ops_t *efop = enp->en_efop;
103 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
104 	efx_rc_t rc;
105 
106 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
107 	EFSYS_ASSERT3P(spec, !=, NULL);
108 	EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
109 
110 	if ((spec->efs_flags & EFX_FILTER_FLAG_ACTION_MARK) &&
111 	    !encp->enc_filter_action_mark_supported) {
112 		rc = ENOTSUP;
113 		goto fail1;
114 	}
115 
116 	if ((spec->efs_flags & EFX_FILTER_FLAG_ACTION_FLAG) &&
117 	    !encp->enc_filter_action_flag_supported) {
118 		rc = ENOTSUP;
119 		goto fail2;
120 	}
121 
122 	return (efop->efo_add(enp, spec, B_FALSE));
123 
124 fail2:
125 	EFSYS_PROBE(fail2);
126 fail1:
127 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
128 
129 	return (rc);
130 }
131 
132 	__checkReturn	efx_rc_t
efx_filter_remove(__in efx_nic_t * enp,__inout efx_filter_spec_t * spec)133 efx_filter_remove(
134 	__in		efx_nic_t *enp,
135 	__inout		efx_filter_spec_t *spec)
136 {
137 	const efx_filter_ops_t *efop = enp->en_efop;
138 
139 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
140 	EFSYS_ASSERT3P(spec, !=, NULL);
141 	EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
142 
143 	return (efop->efo_delete(enp, spec));
144 }
145 
146 	__checkReturn	efx_rc_t
efx_filter_restore(__in efx_nic_t * enp)147 efx_filter_restore(
148 	__in		efx_nic_t *enp)
149 {
150 	efx_rc_t rc;
151 
152 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
153 
154 	if ((rc = enp->en_efop->efo_restore(enp)) != 0)
155 		goto fail1;
156 
157 	return (0);
158 
159 fail1:
160 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
161 
162 	return (rc);
163 }
164 
165 	__checkReturn	efx_rc_t
efx_filter_init(__in efx_nic_t * enp)166 efx_filter_init(
167 	__in		efx_nic_t *enp)
168 {
169 	const efx_filter_ops_t *efop;
170 	efx_rc_t rc;
171 
172 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
173 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
174 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER));
175 
176 	switch (enp->en_family) {
177 #if EFSYS_OPT_SIENA
178 	case EFX_FAMILY_SIENA:
179 		efop = &__efx_filter_siena_ops;
180 		break;
181 #endif /* EFSYS_OPT_SIENA */
182 
183 #if EFSYS_OPT_HUNTINGTON
184 	case EFX_FAMILY_HUNTINGTON:
185 		efop = &__efx_filter_ef10_ops;
186 		break;
187 #endif /* EFSYS_OPT_HUNTINGTON */
188 
189 #if EFSYS_OPT_MEDFORD
190 	case EFX_FAMILY_MEDFORD:
191 		efop = &__efx_filter_ef10_ops;
192 		break;
193 #endif /* EFSYS_OPT_MEDFORD */
194 
195 #if EFSYS_OPT_MEDFORD2
196 	case EFX_FAMILY_MEDFORD2:
197 		efop = &__efx_filter_ef10_ops;
198 		break;
199 #endif /* EFSYS_OPT_MEDFORD2 */
200 
201 	default:
202 		EFSYS_ASSERT(0);
203 		rc = ENOTSUP;
204 		goto fail1;
205 	}
206 
207 	if ((rc = efop->efo_init(enp)) != 0)
208 		goto fail2;
209 
210 	enp->en_efop = efop;
211 	enp->en_mod_flags |= EFX_MOD_FILTER;
212 	return (0);
213 
214 fail2:
215 	EFSYS_PROBE(fail2);
216 fail1:
217 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
218 
219 	enp->en_efop = NULL;
220 	enp->en_mod_flags &= ~EFX_MOD_FILTER;
221 	return (rc);
222 }
223 
224 			void
efx_filter_fini(__in efx_nic_t * enp)225 efx_filter_fini(
226 	__in		efx_nic_t *enp)
227 {
228 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
229 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
230 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
231 
232 	enp->en_efop->efo_fini(enp);
233 
234 	enp->en_efop = NULL;
235 	enp->en_mod_flags &= ~EFX_MOD_FILTER;
236 }
237 
238 /*
239  * Query the possible combinations of match flags which can be filtered on.
240  * These are returned as a list, of which each 32 bit element is a bitmask
241  * formed of EFX_FILTER_MATCH flags.
242  *
243  * The combinations are ordered in priority from highest to lowest.
244  *
245  * If the provided buffer is too short to hold the list, the call with fail with
246  * ENOSPC and *list_lengthp will be set to the buffer length required.
247  */
248 	__checkReturn	efx_rc_t
efx_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)249 efx_filter_supported_filters(
250 	__in				efx_nic_t *enp,
251 	__out_ecount(buffer_length)	uint32_t *buffer,
252 	__in				size_t buffer_length,
253 	__out				size_t *list_lengthp)
254 {
255 	efx_rc_t rc;
256 
257 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
258 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
259 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
260 	EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL);
261 
262 	if (buffer == NULL) {
263 		rc = EINVAL;
264 		goto fail1;
265 	}
266 
267 	rc = enp->en_efop->efo_supported_filters(enp, buffer, buffer_length,
268 						    list_lengthp);
269 	if (rc != 0)
270 		goto fail2;
271 
272 	return (0);
273 
274 fail2:
275 	EFSYS_PROBE(fail2);
276 fail1:
277 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
278 
279 	return (rc);
280 }
281 
282 	__checkReturn	efx_rc_t
283 efx_filter_reconfigure(
284 	__in				efx_nic_t *enp,
285 	__in_ecount(6)			uint8_t const *mac_addr,
286 	__in				boolean_t all_unicst,
287 	__in				boolean_t mulcst,
288 	__in				boolean_t all_mulcst,
289 	__in				boolean_t brdcst,
290 	__in_ecount(6*count)		uint8_t const *addrs,
291 	__in				uint32_t count)
292 {
293 	efx_rc_t rc;
294 
295 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
296 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
297 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
298 
299 	if (enp->en_efop->efo_reconfigure != NULL) {
300 		if ((rc = enp->en_efop->efo_reconfigure(enp, mac_addr,
301 							all_unicst, mulcst,
302 							all_mulcst, brdcst,
303 							addrs, count)) != 0)
304 			goto fail1;
305 	}
306 
307 	return (0);
308 
309 fail1:
310 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
311 
312 	return (rc);
313 }
314 
315 		void
efx_filter_spec_init_rx(__out efx_filter_spec_t * spec,__in efx_filter_priority_t priority,__in efx_filter_flags_t flags,__in efx_rxq_t * erp)316 efx_filter_spec_init_rx(
317 	__out		efx_filter_spec_t *spec,
318 	__in		efx_filter_priority_t priority,
319 	__in		efx_filter_flags_t flags,
320 	__in		efx_rxq_t *erp)
321 {
322 	EFSYS_ASSERT3P(spec, !=, NULL);
323 	EFSYS_ASSERT3P(erp, !=, NULL);
324 	EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
325 				EFX_FILTER_FLAG_RX_SCATTER)) == 0);
326 
327 	memset(spec, 0, sizeof (*spec));
328 	spec->efs_priority = priority;
329 	spec->efs_flags = EFX_FILTER_FLAG_RX | flags;
330 	spec->efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
331 	spec->efs_dmaq_id = (uint16_t)erp->er_index;
332 }
333 
334 		void
efx_filter_spec_init_tx(__out efx_filter_spec_t * spec,__in efx_txq_t * etp)335 efx_filter_spec_init_tx(
336 	__out		efx_filter_spec_t *spec,
337 	__in		efx_txq_t *etp)
338 {
339 	EFSYS_ASSERT3P(spec, !=, NULL);
340 	EFSYS_ASSERT3P(etp, !=, NULL);
341 
342 	memset(spec, 0, sizeof (*spec));
343 	spec->efs_priority = EFX_FILTER_PRI_REQUIRED;
344 	spec->efs_flags = EFX_FILTER_FLAG_TX;
345 	spec->efs_dmaq_id = (uint16_t)etp->et_index;
346 }
347 
348 /*
349  *  Specify IPv4 host, transport protocol and port in a filter specification
350  */
351 __checkReturn		efx_rc_t
efx_filter_spec_set_ipv4_local(__inout efx_filter_spec_t * spec,__in uint8_t proto,__in uint32_t host,__in uint16_t port)352 efx_filter_spec_set_ipv4_local(
353 	__inout		efx_filter_spec_t *spec,
354 	__in		uint8_t proto,
355 	__in		uint32_t host,
356 	__in		uint16_t port)
357 {
358 	EFSYS_ASSERT3P(spec, !=, NULL);
359 
360 	spec->efs_match_flags |=
361 		EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
362 		EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
363 	spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
364 	spec->efs_ip_proto = proto;
365 	spec->efs_loc_host.eo_u32[0] = host;
366 	spec->efs_loc_port = port;
367 	return (0);
368 }
369 
370 /*
371  * Specify IPv4 hosts, transport protocol and ports in a filter specification
372  */
373 __checkReturn		efx_rc_t
efx_filter_spec_set_ipv4_full(__inout efx_filter_spec_t * spec,__in uint8_t proto,__in uint32_t lhost,__in uint16_t lport,__in uint32_t rhost,__in uint16_t rport)374 efx_filter_spec_set_ipv4_full(
375 	__inout		efx_filter_spec_t *spec,
376 	__in		uint8_t proto,
377 	__in		uint32_t lhost,
378 	__in		uint16_t lport,
379 	__in		uint32_t rhost,
380 	__in		uint16_t rport)
381 {
382 	EFSYS_ASSERT3P(spec, !=, NULL);
383 
384 	spec->efs_match_flags |=
385 		EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
386 		EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
387 		EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
388 	spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
389 	spec->efs_ip_proto = proto;
390 	spec->efs_loc_host.eo_u32[0] = lhost;
391 	spec->efs_loc_port = lport;
392 	spec->efs_rem_host.eo_u32[0] = rhost;
393 	spec->efs_rem_port = rport;
394 	return (0);
395 }
396 
397 /*
398  * Specify local Ethernet address and/or VID in filter specification
399  */
400 __checkReturn		efx_rc_t
efx_filter_spec_set_eth_local(__inout efx_filter_spec_t * spec,__in uint16_t vid,__in const uint8_t * addr)401 efx_filter_spec_set_eth_local(
402 	__inout		efx_filter_spec_t *spec,
403 	__in		uint16_t vid,
404 	__in		const uint8_t *addr)
405 {
406 	EFSYS_ASSERT3P(spec, !=, NULL);
407 	EFSYS_ASSERT3P(addr, !=, NULL);
408 
409 	if (vid == EFX_FILTER_SPEC_VID_UNSPEC && addr == NULL)
410 		return (EINVAL);
411 
412 	if (vid != EFX_FILTER_SPEC_VID_UNSPEC) {
413 		spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID;
414 		spec->efs_outer_vid = vid;
415 	}
416 	if (addr != NULL) {
417 		spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
418 		memcpy(spec->efs_loc_mac, addr, EFX_MAC_ADDR_LEN);
419 	}
420 	return (0);
421 }
422 
423 			void
efx_filter_spec_set_ether_type(__inout efx_filter_spec_t * spec,__in uint16_t ether_type)424 efx_filter_spec_set_ether_type(
425 	__inout		efx_filter_spec_t *spec,
426 	__in		uint16_t ether_type)
427 {
428 	EFSYS_ASSERT3P(spec, !=, NULL);
429 
430 	spec->efs_ether_type = ether_type;
431 	spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
432 }
433 
434 /*
435  * Specify matching otherwise-unmatched unicast in a filter specification
436  */
437 __checkReturn		efx_rc_t
efx_filter_spec_set_uc_def(__inout efx_filter_spec_t * spec)438 efx_filter_spec_set_uc_def(
439 	__inout		efx_filter_spec_t *spec)
440 {
441 	EFSYS_ASSERT3P(spec, !=, NULL);
442 
443 	spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_UCAST_DST;
444 	return (0);
445 }
446 
447 /*
448  * Specify matching otherwise-unmatched multicast in a filter specification
449  */
450 __checkReturn		efx_rc_t
efx_filter_spec_set_mc_def(__inout efx_filter_spec_t * spec)451 efx_filter_spec_set_mc_def(
452 	__inout		efx_filter_spec_t *spec)
453 {
454 	EFSYS_ASSERT3P(spec, !=, NULL);
455 
456 	spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
457 	return (0);
458 }
459 
460 __checkReturn		efx_rc_t
efx_filter_spec_set_encap_type(__inout efx_filter_spec_t * spec,__in efx_tunnel_protocol_t encap_type,__in efx_filter_inner_frame_match_t inner_frame_match)461 efx_filter_spec_set_encap_type(
462 	__inout		efx_filter_spec_t *spec,
463 	__in		efx_tunnel_protocol_t encap_type,
464 	__in		efx_filter_inner_frame_match_t inner_frame_match)
465 {
466 	uint32_t match_flags = EFX_FILTER_MATCH_ENCAP_TYPE;
467 	uint8_t ip_proto;
468 	efx_rc_t rc;
469 
470 	EFSYS_ASSERT3P(spec, !=, NULL);
471 
472 	switch (encap_type) {
473 	case EFX_TUNNEL_PROTOCOL_VXLAN:
474 	case EFX_TUNNEL_PROTOCOL_GENEVE:
475 		ip_proto = EFX_IPPROTO_UDP;
476 		break;
477 	case EFX_TUNNEL_PROTOCOL_NVGRE:
478 		ip_proto = EFX_IPPROTO_GRE;
479 		break;
480 	default:
481 		EFSYS_ASSERT(0);
482 		rc = EINVAL;
483 		goto fail1;
484 	}
485 
486 	switch (inner_frame_match) {
487 	case EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_MCAST_DST:
488 		match_flags |= EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST;
489 		break;
490 	case EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_UCAST_DST:
491 		match_flags |= EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST;
492 		break;
493 	case EFX_FILTER_INNER_FRAME_MATCH_OTHER:
494 		/* This is for when specific inner frames are to be matched. */
495 		break;
496 	default:
497 		EFSYS_ASSERT(0);
498 		rc = EINVAL;
499 		goto fail2;
500 	}
501 
502 	spec->efs_encap_type = encap_type;
503 	spec->efs_ip_proto = ip_proto;
504 	spec->efs_match_flags |= (match_flags | EFX_FILTER_MATCH_IP_PROTO);
505 
506 	return (0);
507 
508 fail2:
509 	EFSYS_PROBE(fail2);
510 fail1:
511 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
512 
513 	return (rc);
514 }
515 
516 /*
517  * Specify inner and outer Ethernet address and VNI or VSID in tunnel filter
518  * specification.
519  */
520 static	__checkReturn	efx_rc_t
efx_filter_spec_set_tunnel(__inout efx_filter_spec_t * spec,__in efx_tunnel_protocol_t encap_type,__in const uint8_t * vni_or_vsid,__in const uint8_t * inner_addr,__in const uint8_t * outer_addr)521 efx_filter_spec_set_tunnel(
522 	__inout	efx_filter_spec_t *spec,
523 	__in		efx_tunnel_protocol_t encap_type,
524 	__in		const uint8_t *vni_or_vsid,
525 	__in		const uint8_t *inner_addr,
526 	__in		const uint8_t *outer_addr)
527 {
528 	efx_rc_t rc;
529 
530 	EFSYS_ASSERT3P(spec, !=, NULL);
531 	EFSYS_ASSERT3P(vni_or_vsid, !=, NULL);
532 	EFSYS_ASSERT3P(inner_addr, !=, NULL);
533 	EFSYS_ASSERT3P(outer_addr, !=, NULL);
534 
535 	switch (encap_type) {
536 	case EFX_TUNNEL_PROTOCOL_VXLAN:
537 	case EFX_TUNNEL_PROTOCOL_GENEVE:
538 	case EFX_TUNNEL_PROTOCOL_NVGRE:
539 		break;
540 	default:
541 		rc = EINVAL;
542 		goto fail1;
543 	}
544 
545 	if ((inner_addr == NULL) && (outer_addr == NULL)) {
546 		rc = EINVAL;
547 		goto fail2;
548 	}
549 
550 	if (vni_or_vsid != NULL) {
551 		spec->efs_match_flags |= EFX_FILTER_MATCH_VNI_OR_VSID;
552 		memcpy(spec->efs_vni_or_vsid, vni_or_vsid, EFX_VNI_OR_VSID_LEN);
553 	}
554 	if (outer_addr != NULL) {
555 		spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
556 		memcpy(spec->efs_loc_mac, outer_addr, EFX_MAC_ADDR_LEN);
557 	}
558 	if (inner_addr != NULL) {
559 		spec->efs_match_flags |= EFX_FILTER_MATCH_IFRM_LOC_MAC;
560 		memcpy(spec->efs_ifrm_loc_mac, inner_addr, EFX_MAC_ADDR_LEN);
561 	}
562 
563 	spec->efs_match_flags |= EFX_FILTER_MATCH_ENCAP_TYPE;
564 	spec->efs_encap_type = encap_type;
565 
566 	return (0);
567 
568 fail2:
569 	EFSYS_PROBE(fail2);
570 fail1:
571 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
572 
573 	return (rc);
574 }
575 
576 /*
577  * Specify inner and outer Ethernet address and VNI in VXLAN filter
578  * specification.
579  */
580 __checkReturn		efx_rc_t
efx_filter_spec_set_vxlan(__inout efx_filter_spec_t * spec,__in const uint8_t * vni,__in const uint8_t * inner_addr,__in const uint8_t * outer_addr)581 efx_filter_spec_set_vxlan(
582 	__inout		efx_filter_spec_t *spec,
583 	__in		const uint8_t *vni,
584 	__in		const uint8_t *inner_addr,
585 	__in		const uint8_t *outer_addr)
586 {
587 	return efx_filter_spec_set_tunnel(spec, EFX_TUNNEL_PROTOCOL_VXLAN,
588 	    vni, inner_addr, outer_addr);
589 }
590 
591 /*
592  * Specify inner and outer Ethernet address and VNI in Geneve filter
593  * specification.
594  */
595 __checkReturn		efx_rc_t
efx_filter_spec_set_geneve(__inout efx_filter_spec_t * spec,__in const uint8_t * vni,__in const uint8_t * inner_addr,__in const uint8_t * outer_addr)596 efx_filter_spec_set_geneve(
597 	__inout		efx_filter_spec_t *spec,
598 	__in		const uint8_t *vni,
599 	__in		const uint8_t *inner_addr,
600 	__in		const uint8_t *outer_addr)
601 {
602 	return efx_filter_spec_set_tunnel(spec, EFX_TUNNEL_PROTOCOL_GENEVE,
603 	    vni, inner_addr, outer_addr);
604 }
605 
606 /*
607  * Specify inner and outer Ethernet address and vsid in NVGRE filter
608  * specification.
609  */
610 __checkReturn		efx_rc_t
efx_filter_spec_set_nvgre(__inout efx_filter_spec_t * spec,__in const uint8_t * vsid,__in const uint8_t * inner_addr,__in const uint8_t * outer_addr)611 efx_filter_spec_set_nvgre(
612 	__inout		efx_filter_spec_t *spec,
613 	__in		const uint8_t *vsid,
614 	__in		const uint8_t *inner_addr,
615 	__in		const uint8_t *outer_addr)
616 {
617 	return efx_filter_spec_set_tunnel(spec, EFX_TUNNEL_PROTOCOL_NVGRE,
618 	    vsid, inner_addr, outer_addr);
619 }
620 
621 #if EFSYS_OPT_RX_SCALE
622 	__checkReturn	efx_rc_t
efx_filter_spec_set_rss_context(__inout efx_filter_spec_t * spec,__in uint32_t rss_context)623 efx_filter_spec_set_rss_context(
624 	__inout		efx_filter_spec_t *spec,
625 	__in		uint32_t rss_context)
626 {
627 	efx_rc_t rc;
628 
629 	EFSYS_ASSERT3P(spec, !=, NULL);
630 
631 	/* The filter must have been created with EFX_FILTER_FLAG_RX_RSS. */
632 	if ((spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) == 0) {
633 		rc = EINVAL;
634 		goto fail1;
635 	}
636 
637 	spec->efs_rss_context = rss_context;
638 
639 	return (0);
640 
641 fail1:
642 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
643 
644 	return (rc);
645 }
646 #endif
647 
648 #if EFSYS_OPT_SIENA
649 
650 /*
651  * "Fudge factors" - difference between programmed value and actual depth.
652  * Due to pipelined implementation we need to program H/W with a value that
653  * is larger than the hop limit we want.
654  */
655 #define	FILTER_CTL_SRCH_FUDGE_WILD 3
656 #define	FILTER_CTL_SRCH_FUDGE_FULL 1
657 
658 /*
659  * Hard maximum hop limit.  Hardware will time-out beyond 200-something.
660  * We also need to avoid infinite loops in efx_filter_search() when the
661  * table is full.
662  */
663 #define	FILTER_CTL_SRCH_MAX 200
664 
665 static	__checkReturn	efx_rc_t
siena_filter_spec_from_gen_spec(__out siena_filter_spec_t * sf_spec,__in efx_filter_spec_t * gen_spec)666 siena_filter_spec_from_gen_spec(
667 	__out		siena_filter_spec_t *sf_spec,
668 	__in		efx_filter_spec_t *gen_spec)
669 {
670 	efx_rc_t rc;
671 	boolean_t is_full = B_FALSE;
672 
673 	if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX)
674 		EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX);
675 	else
676 		EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX);
677 
678 	/* Siena only has one RSS context */
679 	if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
680 	    gen_spec->efs_rss_context != EFX_RSS_CONTEXT_DEFAULT) {
681 		rc = EINVAL;
682 		goto fail1;
683 	}
684 
685 	sf_spec->sfs_flags = gen_spec->efs_flags;
686 	sf_spec->sfs_dmaq_id = gen_spec->efs_dmaq_id;
687 
688 	switch (gen_spec->efs_match_flags) {
689 	case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
690 	    EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
691 	    EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT:
692 		is_full = B_TRUE;
693 		/* Fall through */
694 	case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
695 	    EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: {
696 		uint32_t rhost, host1, host2;
697 		uint16_t rport, port1, port2;
698 
699 		if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) {
700 			rc = ENOTSUP;
701 			goto fail2;
702 		}
703 		if (gen_spec->efs_loc_port == 0 ||
704 		    (is_full && gen_spec->efs_rem_port == 0)) {
705 			rc = EINVAL;
706 			goto fail3;
707 		}
708 		switch (gen_spec->efs_ip_proto) {
709 		case EFX_IPPROTO_TCP:
710 			if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
711 				sf_spec->sfs_type = (is_full ?
712 				    EFX_SIENA_FILTER_TX_TCP_FULL :
713 				    EFX_SIENA_FILTER_TX_TCP_WILD);
714 			} else {
715 				sf_spec->sfs_type = (is_full ?
716 				    EFX_SIENA_FILTER_RX_TCP_FULL :
717 				    EFX_SIENA_FILTER_RX_TCP_WILD);
718 			}
719 			break;
720 		case EFX_IPPROTO_UDP:
721 			if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
722 				sf_spec->sfs_type = (is_full ?
723 				    EFX_SIENA_FILTER_TX_UDP_FULL :
724 				    EFX_SIENA_FILTER_TX_UDP_WILD);
725 			} else {
726 				sf_spec->sfs_type = (is_full ?
727 				    EFX_SIENA_FILTER_RX_UDP_FULL :
728 				    EFX_SIENA_FILTER_RX_UDP_WILD);
729 			}
730 			break;
731 		default:
732 			rc = ENOTSUP;
733 			goto fail4;
734 		}
735 		/*
736 		 * The filter is constructed in terms of source and destination,
737 		 * with the odd wrinkle that the ports are swapped in a UDP
738 		 * wildcard filter. We need to convert from local and remote
739 		 * addresses (zero for a wildcard).
740 		 */
741 		rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0;
742 		rport = is_full ? gen_spec->efs_rem_port : 0;
743 		if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
744 			host1 = gen_spec->efs_loc_host.eo_u32[0];
745 			host2 = rhost;
746 		} else {
747 			host1 = rhost;
748 			host2 = gen_spec->efs_loc_host.eo_u32[0];
749 		}
750 		if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
751 			if (sf_spec->sfs_type ==
752 			    EFX_SIENA_FILTER_TX_UDP_WILD) {
753 				port1 = rport;
754 				port2 = gen_spec->efs_loc_port;
755 			} else {
756 				port1 = gen_spec->efs_loc_port;
757 				port2 = rport;
758 			}
759 		} else {
760 			if (sf_spec->sfs_type ==
761 			    EFX_SIENA_FILTER_RX_UDP_WILD) {
762 				port1 = gen_spec->efs_loc_port;
763 				port2 = rport;
764 			} else {
765 				port1 = rport;
766 				port2 = gen_spec->efs_loc_port;
767 			}
768 		}
769 		sf_spec->sfs_dword[0] = (host1 << 16) | port1;
770 		sf_spec->sfs_dword[1] = (port2 << 16) | (host1 >> 16);
771 		sf_spec->sfs_dword[2] = host2;
772 		break;
773 	}
774 
775 	case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID:
776 		is_full = B_TRUE;
777 		/* Fall through */
778 	case EFX_FILTER_MATCH_LOC_MAC:
779 		if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
780 			sf_spec->sfs_type = (is_full ?
781 			    EFX_SIENA_FILTER_TX_MAC_FULL :
782 			    EFX_SIENA_FILTER_TX_MAC_WILD);
783 		} else {
784 			sf_spec->sfs_type = (is_full ?
785 			    EFX_SIENA_FILTER_RX_MAC_FULL :
786 			    EFX_SIENA_FILTER_RX_MAC_WILD);
787 		}
788 		sf_spec->sfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0;
789 		sf_spec->sfs_dword[1] =
790 		    gen_spec->efs_loc_mac[2] << 24 |
791 		    gen_spec->efs_loc_mac[3] << 16 |
792 		    gen_spec->efs_loc_mac[4] <<  8 |
793 		    gen_spec->efs_loc_mac[5];
794 		sf_spec->sfs_dword[2] =
795 		    gen_spec->efs_loc_mac[0] << 8 |
796 		    gen_spec->efs_loc_mac[1];
797 		break;
798 
799 	default:
800 		EFSYS_ASSERT(B_FALSE);
801 		rc = ENOTSUP;
802 		goto fail5;
803 	}
804 
805 	return (0);
806 
807 fail5:
808 	EFSYS_PROBE(fail5);
809 fail4:
810 	EFSYS_PROBE(fail4);
811 fail3:
812 	EFSYS_PROBE(fail3);
813 fail2:
814 	EFSYS_PROBE(fail2);
815 fail1:
816 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
817 
818 	return (rc);
819 }
820 
821 /*
822  * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
823  * key derived from the n-tuple.
824  */
825 static			uint16_t
siena_filter_tbl_hash(__in uint32_t key)826 siena_filter_tbl_hash(
827 	__in		uint32_t key)
828 {
829 	uint16_t tmp;
830 
831 	/* First 16 rounds */
832 	tmp = 0x1fff ^ (uint16_t)(key >> 16);
833 	tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
834 	tmp = tmp ^ tmp >> 9;
835 
836 	/* Last 16 rounds */
837 	tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff);
838 	tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
839 	tmp = tmp ^ tmp >> 9;
840 
841 	return (tmp);
842 }
843 
844 /*
845  * To allow for hash collisions, filter search continues at these
846  * increments from the first possible entry selected by the hash.
847  */
848 static			uint16_t
siena_filter_tbl_increment(__in uint32_t key)849 siena_filter_tbl_increment(
850 	__in		uint32_t key)
851 {
852 	return ((uint16_t)(key * 2 - 1));
853 }
854 
855 static	__checkReturn	boolean_t
siena_filter_test_used(__in siena_filter_tbl_t * sftp,__in unsigned int index)856 siena_filter_test_used(
857 	__in		siena_filter_tbl_t *sftp,
858 	__in		unsigned int index)
859 {
860 	EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
861 	return ((sftp->sft_bitmap[index / 32] & (1 << (index % 32))) != 0);
862 }
863 
864 static			void
siena_filter_set_used(__in siena_filter_tbl_t * sftp,__in unsigned int index)865 siena_filter_set_used(
866 	__in		siena_filter_tbl_t *sftp,
867 	__in		unsigned int index)
868 {
869 	EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
870 	sftp->sft_bitmap[index / 32] |= (1 << (index % 32));
871 	++sftp->sft_used;
872 }
873 
874 static			void
siena_filter_clear_used(__in siena_filter_tbl_t * sftp,__in unsigned int index)875 siena_filter_clear_used(
876 	__in		siena_filter_tbl_t *sftp,
877 	__in		unsigned int index)
878 {
879 	EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
880 	sftp->sft_bitmap[index / 32] &= ~(1 << (index % 32));
881 
882 	--sftp->sft_used;
883 	EFSYS_ASSERT3U(sftp->sft_used, >=, 0);
884 }
885 
886 static			siena_filter_tbl_id_t
siena_filter_tbl_id(__in siena_filter_type_t type)887 siena_filter_tbl_id(
888 	__in		siena_filter_type_t type)
889 {
890 	siena_filter_tbl_id_t tbl_id;
891 
892 	switch (type) {
893 	case EFX_SIENA_FILTER_RX_TCP_FULL:
894 	case EFX_SIENA_FILTER_RX_TCP_WILD:
895 	case EFX_SIENA_FILTER_RX_UDP_FULL:
896 	case EFX_SIENA_FILTER_RX_UDP_WILD:
897 		tbl_id = EFX_SIENA_FILTER_TBL_RX_IP;
898 		break;
899 
900 	case EFX_SIENA_FILTER_RX_MAC_FULL:
901 	case EFX_SIENA_FILTER_RX_MAC_WILD:
902 		tbl_id = EFX_SIENA_FILTER_TBL_RX_MAC;
903 		break;
904 
905 	case EFX_SIENA_FILTER_TX_TCP_FULL:
906 	case EFX_SIENA_FILTER_TX_TCP_WILD:
907 	case EFX_SIENA_FILTER_TX_UDP_FULL:
908 	case EFX_SIENA_FILTER_TX_UDP_WILD:
909 		tbl_id = EFX_SIENA_FILTER_TBL_TX_IP;
910 		break;
911 
912 	case EFX_SIENA_FILTER_TX_MAC_FULL:
913 	case EFX_SIENA_FILTER_TX_MAC_WILD:
914 		tbl_id = EFX_SIENA_FILTER_TBL_TX_MAC;
915 		break;
916 
917 	default:
918 		EFSYS_ASSERT(B_FALSE);
919 		tbl_id = EFX_SIENA_FILTER_NTBLS;
920 		break;
921 	}
922 	return (tbl_id);
923 }
924 
925 static			void
siena_filter_reset_search_depth(__inout siena_filter_t * sfp,__in siena_filter_tbl_id_t tbl_id)926 siena_filter_reset_search_depth(
927 	__inout		siena_filter_t *sfp,
928 	__in		siena_filter_tbl_id_t tbl_id)
929 {
930 	switch (tbl_id) {
931 	case EFX_SIENA_FILTER_TBL_RX_IP:
932 		sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] = 0;
933 		sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] = 0;
934 		sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] = 0;
935 		sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] = 0;
936 		break;
937 
938 	case EFX_SIENA_FILTER_TBL_RX_MAC:
939 		sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] = 0;
940 		sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] = 0;
941 		break;
942 
943 	case EFX_SIENA_FILTER_TBL_TX_IP:
944 		sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] = 0;
945 		sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] = 0;
946 		sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] = 0;
947 		sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] = 0;
948 		break;
949 
950 	case EFX_SIENA_FILTER_TBL_TX_MAC:
951 		sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] = 0;
952 		sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] = 0;
953 		break;
954 
955 	default:
956 		EFSYS_ASSERT(B_FALSE);
957 		break;
958 	}
959 }
960 
961 static			void
siena_filter_push_rx_limits(__in efx_nic_t * enp)962 siena_filter_push_rx_limits(
963 	__in		efx_nic_t *enp)
964 {
965 	siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
966 	efx_oword_t oword;
967 
968 	EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
969 
970 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT,
971 	    sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] +
972 	    FILTER_CTL_SRCH_FUDGE_FULL);
973 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT,
974 	    sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] +
975 	    FILTER_CTL_SRCH_FUDGE_WILD);
976 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT,
977 	    sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] +
978 	    FILTER_CTL_SRCH_FUDGE_FULL);
979 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT,
980 	    sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] +
981 	    FILTER_CTL_SRCH_FUDGE_WILD);
982 
983 	if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC].sft_size) {
984 		EFX_SET_OWORD_FIELD(oword,
985 		    FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
986 		    sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] +
987 		    FILTER_CTL_SRCH_FUDGE_FULL);
988 		EFX_SET_OWORD_FIELD(oword,
989 		    FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
990 		    sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] +
991 		    FILTER_CTL_SRCH_FUDGE_WILD);
992 	}
993 
994 	EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
995 }
996 
997 static			void
siena_filter_push_tx_limits(__in efx_nic_t * enp)998 siena_filter_push_tx_limits(
999 	__in		efx_nic_t *enp)
1000 {
1001 	siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1002 	efx_oword_t oword;
1003 
1004 	EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
1005 
1006 	if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP].sft_size != 0) {
1007 		EFX_SET_OWORD_FIELD(oword,
1008 		    FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE,
1009 		    sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] +
1010 		    FILTER_CTL_SRCH_FUDGE_FULL);
1011 		EFX_SET_OWORD_FIELD(oword,
1012 		    FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE,
1013 		    sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] +
1014 		    FILTER_CTL_SRCH_FUDGE_WILD);
1015 		EFX_SET_OWORD_FIELD(oword,
1016 		    FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE,
1017 		    sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] +
1018 		    FILTER_CTL_SRCH_FUDGE_FULL);
1019 		EFX_SET_OWORD_FIELD(oword,
1020 		    FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE,
1021 		    sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] +
1022 		    FILTER_CTL_SRCH_FUDGE_WILD);
1023 	}
1024 
1025 	if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC].sft_size != 0) {
1026 		EFX_SET_OWORD_FIELD(
1027 			oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
1028 			sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] +
1029 			FILTER_CTL_SRCH_FUDGE_FULL);
1030 		EFX_SET_OWORD_FIELD(
1031 			oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
1032 			sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] +
1033 			FILTER_CTL_SRCH_FUDGE_WILD);
1034 	}
1035 
1036 	EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
1037 }
1038 
1039 /* Build a filter entry and return its n-tuple key. */
1040 static	__checkReturn	uint32_t
siena_filter_build(__out efx_oword_t * filter,__in siena_filter_spec_t * spec)1041 siena_filter_build(
1042 	__out		efx_oword_t *filter,
1043 	__in		siena_filter_spec_t *spec)
1044 {
1045 	uint32_t dword3;
1046 	uint32_t key;
1047 	uint8_t  type  = spec->sfs_type;
1048 	uint32_t flags = spec->sfs_flags;
1049 
1050 	switch (siena_filter_tbl_id(type)) {
1051 	case EFX_SIENA_FILTER_TBL_RX_IP: {
1052 		boolean_t is_udp = (type == EFX_SIENA_FILTER_RX_UDP_FULL ||
1053 		    type == EFX_SIENA_FILTER_RX_UDP_WILD);
1054 		EFX_POPULATE_OWORD_7(*filter,
1055 		    FRF_BZ_RSS_EN,
1056 		    (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
1057 		    FRF_BZ_SCATTER_EN,
1058 		    (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
1059 		    FRF_AZ_TCP_UDP, is_udp,
1060 		    FRF_AZ_RXQ_ID, spec->sfs_dmaq_id,
1061 		    EFX_DWORD_2, spec->sfs_dword[2],
1062 		    EFX_DWORD_1, spec->sfs_dword[1],
1063 		    EFX_DWORD_0, spec->sfs_dword[0]);
1064 		dword3 = is_udp;
1065 		break;
1066 	}
1067 
1068 	case EFX_SIENA_FILTER_TBL_RX_MAC: {
1069 		boolean_t is_wild = (type == EFX_SIENA_FILTER_RX_MAC_WILD);
1070 		EFX_POPULATE_OWORD_7(*filter,
1071 		    FRF_CZ_RMFT_RSS_EN,
1072 		    (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
1073 		    FRF_CZ_RMFT_SCATTER_EN,
1074 		    (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
1075 		    FRF_CZ_RMFT_RXQ_ID, spec->sfs_dmaq_id,
1076 		    FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
1077 		    FRF_CZ_RMFT_DEST_MAC_DW1, spec->sfs_dword[2],
1078 		    FRF_CZ_RMFT_DEST_MAC_DW0, spec->sfs_dword[1],
1079 		    FRF_CZ_RMFT_VLAN_ID, spec->sfs_dword[0]);
1080 		dword3 = is_wild;
1081 		break;
1082 	}
1083 
1084 	case EFX_SIENA_FILTER_TBL_TX_IP: {
1085 		boolean_t is_udp = (type == EFX_SIENA_FILTER_TX_UDP_FULL ||
1086 		    type == EFX_SIENA_FILTER_TX_UDP_WILD);
1087 		EFX_POPULATE_OWORD_5(*filter,
1088 		    FRF_CZ_TIFT_TCP_UDP, is_udp,
1089 		    FRF_CZ_TIFT_TXQ_ID, spec->sfs_dmaq_id,
1090 		    EFX_DWORD_2, spec->sfs_dword[2],
1091 		    EFX_DWORD_1, spec->sfs_dword[1],
1092 		    EFX_DWORD_0, spec->sfs_dword[0]);
1093 		dword3 = is_udp | spec->sfs_dmaq_id << 1;
1094 		break;
1095 	}
1096 
1097 	case EFX_SIENA_FILTER_TBL_TX_MAC: {
1098 		boolean_t is_wild = (type == EFX_SIENA_FILTER_TX_MAC_WILD);
1099 		EFX_POPULATE_OWORD_5(*filter,
1100 		    FRF_CZ_TMFT_TXQ_ID, spec->sfs_dmaq_id,
1101 		    FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
1102 		    FRF_CZ_TMFT_SRC_MAC_DW1, spec->sfs_dword[2],
1103 		    FRF_CZ_TMFT_SRC_MAC_DW0, spec->sfs_dword[1],
1104 		    FRF_CZ_TMFT_VLAN_ID, spec->sfs_dword[0]);
1105 		dword3 = is_wild | spec->sfs_dmaq_id << 1;
1106 		break;
1107 	}
1108 
1109 	default:
1110 		EFSYS_ASSERT(B_FALSE);
1111 		EFX_ZERO_OWORD(*filter);
1112 		return (0);
1113 	}
1114 
1115 	key =
1116 	    spec->sfs_dword[0] ^
1117 	    spec->sfs_dword[1] ^
1118 	    spec->sfs_dword[2] ^
1119 	    dword3;
1120 
1121 	return (key);
1122 }
1123 
1124 static	__checkReturn		efx_rc_t
siena_filter_push_entry(__inout efx_nic_t * enp,__in siena_filter_type_t type,__in int index,__in efx_oword_t * eop)1125 siena_filter_push_entry(
1126 	__inout			efx_nic_t *enp,
1127 	__in			siena_filter_type_t type,
1128 	__in			int index,
1129 	__in			efx_oword_t *eop)
1130 {
1131 	efx_rc_t rc;
1132 
1133 	switch (type) {
1134 	case EFX_SIENA_FILTER_RX_TCP_FULL:
1135 	case EFX_SIENA_FILTER_RX_TCP_WILD:
1136 	case EFX_SIENA_FILTER_RX_UDP_FULL:
1137 	case EFX_SIENA_FILTER_RX_UDP_WILD:
1138 		EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index,
1139 		    eop, B_TRUE);
1140 		break;
1141 
1142 	case EFX_SIENA_FILTER_RX_MAC_FULL:
1143 	case EFX_SIENA_FILTER_RX_MAC_WILD:
1144 		EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index,
1145 		    eop, B_TRUE);
1146 		break;
1147 
1148 	case EFX_SIENA_FILTER_TX_TCP_FULL:
1149 	case EFX_SIENA_FILTER_TX_TCP_WILD:
1150 	case EFX_SIENA_FILTER_TX_UDP_FULL:
1151 	case EFX_SIENA_FILTER_TX_UDP_WILD:
1152 		EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index,
1153 		    eop, B_TRUE);
1154 		break;
1155 
1156 	case EFX_SIENA_FILTER_TX_MAC_FULL:
1157 	case EFX_SIENA_FILTER_TX_MAC_WILD:
1158 		EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index,
1159 		    eop, B_TRUE);
1160 		break;
1161 
1162 	default:
1163 		EFSYS_ASSERT(B_FALSE);
1164 		rc = ENOTSUP;
1165 		goto fail1;
1166 	}
1167 	return (0);
1168 
1169 fail1:
1170 	return (rc);
1171 }
1172 
1173 static	__checkReturn	boolean_t
siena_filter_equal(__in const siena_filter_spec_t * left,__in const siena_filter_spec_t * right)1174 siena_filter_equal(
1175 	__in		const siena_filter_spec_t *left,
1176 	__in		const siena_filter_spec_t *right)
1177 {
1178 	siena_filter_tbl_id_t tbl_id;
1179 
1180 	tbl_id = siena_filter_tbl_id(left->sfs_type);
1181 
1182 	if (left->sfs_type != right->sfs_type)
1183 		return (B_FALSE);
1184 
1185 	if (memcmp(left->sfs_dword, right->sfs_dword,
1186 		sizeof (left->sfs_dword)))
1187 		return (B_FALSE);
1188 
1189 	if ((tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1190 		tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) &&
1191 	    left->sfs_dmaq_id != right->sfs_dmaq_id)
1192 		return (B_FALSE);
1193 
1194 	return (B_TRUE);
1195 }
1196 
1197 static	__checkReturn	efx_rc_t
siena_filter_search(__in siena_filter_tbl_t * sftp,__in siena_filter_spec_t * spec,__in uint32_t key,__in boolean_t for_insert,__out int * filter_index,__out unsigned int * depth_required)1198 siena_filter_search(
1199 	__in		siena_filter_tbl_t *sftp,
1200 	__in		siena_filter_spec_t *spec,
1201 	__in		uint32_t key,
1202 	__in		boolean_t for_insert,
1203 	__out		int *filter_index,
1204 	__out		unsigned int *depth_required)
1205 {
1206 	unsigned int hash, incr, filter_idx, depth;
1207 
1208 	hash = siena_filter_tbl_hash(key);
1209 	incr = siena_filter_tbl_increment(key);
1210 
1211 	filter_idx = hash & (sftp->sft_size - 1);
1212 	depth = 1;
1213 
1214 	for (;;) {
1215 		/*
1216 		 * Return success if entry is used and matches this spec
1217 		 * or entry is unused and we are trying to insert.
1218 		 */
1219 		if (siena_filter_test_used(sftp, filter_idx) ?
1220 		    siena_filter_equal(spec,
1221 		    &sftp->sft_spec[filter_idx]) :
1222 		    for_insert) {
1223 			*filter_index = filter_idx;
1224 			*depth_required = depth;
1225 			return (0);
1226 		}
1227 
1228 		/* Return failure if we reached the maximum search depth */
1229 		if (depth == FILTER_CTL_SRCH_MAX)
1230 			return (for_insert ? EBUSY : ENOENT);
1231 
1232 		filter_idx = (filter_idx + incr) & (sftp->sft_size - 1);
1233 		++depth;
1234 	}
1235 }
1236 
1237 static			void
siena_filter_clear_entry(__in efx_nic_t * enp,__in siena_filter_tbl_t * sftp,__in int index)1238 siena_filter_clear_entry(
1239 	__in		efx_nic_t *enp,
1240 	__in		siena_filter_tbl_t *sftp,
1241 	__in		int index)
1242 {
1243 	efx_oword_t filter;
1244 
1245 	if (siena_filter_test_used(sftp, index)) {
1246 		siena_filter_clear_used(sftp, index);
1247 
1248 		EFX_ZERO_OWORD(filter);
1249 		siena_filter_push_entry(enp,
1250 		    sftp->sft_spec[index].sfs_type,
1251 		    index, &filter);
1252 
1253 		memset(&sftp->sft_spec[index],
1254 		    0, sizeof (sftp->sft_spec[0]));
1255 	}
1256 }
1257 
1258 			void
siena_filter_tbl_clear(__in efx_nic_t * enp,__in siena_filter_tbl_id_t tbl_id)1259 siena_filter_tbl_clear(
1260 	__in		efx_nic_t *enp,
1261 	__in		siena_filter_tbl_id_t tbl_id)
1262 {
1263 	siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1264 	siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1265 	int index;
1266 	efsys_lock_state_t state;
1267 
1268 	EFSYS_LOCK(enp->en_eslp, state);
1269 
1270 	for (index = 0; index < sftp->sft_size; ++index) {
1271 		siena_filter_clear_entry(enp, sftp, index);
1272 	}
1273 
1274 	if (sftp->sft_used == 0)
1275 		siena_filter_reset_search_depth(sfp, tbl_id);
1276 
1277 	EFSYS_UNLOCK(enp->en_eslp, state);
1278 }
1279 
1280 static	__checkReturn	efx_rc_t
siena_filter_init(__in efx_nic_t * enp)1281 siena_filter_init(
1282 	__in		efx_nic_t *enp)
1283 {
1284 	siena_filter_t *sfp;
1285 	siena_filter_tbl_t *sftp;
1286 	int tbl_id;
1287 	efx_rc_t rc;
1288 
1289 	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (siena_filter_t), sfp);
1290 
1291 	if (!sfp) {
1292 		rc = ENOMEM;
1293 		goto fail1;
1294 	}
1295 
1296 	enp->en_filter.ef_siena_filter = sfp;
1297 
1298 	switch (enp->en_family) {
1299 	case EFX_FAMILY_SIENA:
1300 		sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_IP];
1301 		sftp->sft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
1302 
1303 		sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC];
1304 		sftp->sft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
1305 
1306 		sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP];
1307 		sftp->sft_size = FR_CZ_TX_FILTER_TBL0_ROWS;
1308 
1309 		sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC];
1310 		sftp->sft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
1311 		break;
1312 
1313 	default:
1314 		rc = ENOTSUP;
1315 		goto fail2;
1316 	}
1317 
1318 	for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1319 		unsigned int bitmap_size;
1320 
1321 		sftp = &sfp->sf_tbl[tbl_id];
1322 		if (sftp->sft_size == 0)
1323 			continue;
1324 
1325 		EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1326 		    sizeof (uint32_t));
1327 		bitmap_size =
1328 		    (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1329 
1330 		EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, sftp->sft_bitmap);
1331 		if (!sftp->sft_bitmap) {
1332 			rc = ENOMEM;
1333 			goto fail3;
1334 		}
1335 
1336 		EFSYS_KMEM_ALLOC(enp->en_esip,
1337 		    sftp->sft_size * sizeof (*sftp->sft_spec),
1338 		    sftp->sft_spec);
1339 		if (!sftp->sft_spec) {
1340 			rc = ENOMEM;
1341 			goto fail4;
1342 		}
1343 		memset(sftp->sft_spec, 0,
1344 		    sftp->sft_size * sizeof (*sftp->sft_spec));
1345 	}
1346 
1347 	return (0);
1348 
1349 fail4:
1350 	EFSYS_PROBE(fail4);
1351 
1352 fail3:
1353 	EFSYS_PROBE(fail3);
1354 
1355 fail2:
1356 	EFSYS_PROBE(fail2);
1357 	siena_filter_fini(enp);
1358 
1359 fail1:
1360 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1361 	return (rc);
1362 }
1363 
1364 static			void
siena_filter_fini(__in efx_nic_t * enp)1365 siena_filter_fini(
1366 	__in		efx_nic_t *enp)
1367 {
1368 	siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1369 	siena_filter_tbl_id_t tbl_id;
1370 
1371 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1372 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1373 
1374 	if (sfp == NULL)
1375 		return;
1376 
1377 	for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1378 		siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1379 		unsigned int bitmap_size;
1380 
1381 		EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1382 		    sizeof (uint32_t));
1383 		bitmap_size =
1384 		    (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1385 
1386 		if (sftp->sft_bitmap != NULL) {
1387 			EFSYS_KMEM_FREE(enp->en_esip, bitmap_size,
1388 			    sftp->sft_bitmap);
1389 			sftp->sft_bitmap = NULL;
1390 		}
1391 
1392 		if (sftp->sft_spec != NULL) {
1393 			EFSYS_KMEM_FREE(enp->en_esip, sftp->sft_size *
1394 			    sizeof (*sftp->sft_spec), sftp->sft_spec);
1395 			sftp->sft_spec = NULL;
1396 		}
1397 	}
1398 
1399 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (siena_filter_t),
1400 	    enp->en_filter.ef_siena_filter);
1401 }
1402 
1403 /* Restore filter state after a reset */
1404 static	__checkReturn	efx_rc_t
siena_filter_restore(__in efx_nic_t * enp)1405 siena_filter_restore(
1406 	__in		efx_nic_t *enp)
1407 {
1408 	siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1409 	siena_filter_tbl_id_t tbl_id;
1410 	siena_filter_tbl_t *sftp;
1411 	siena_filter_spec_t *spec;
1412 	efx_oword_t filter;
1413 	int filter_idx;
1414 	efsys_lock_state_t state;
1415 	uint32_t key;
1416 	efx_rc_t rc;
1417 
1418 	EFSYS_LOCK(enp->en_eslp, state);
1419 
1420 	for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1421 		sftp = &sfp->sf_tbl[tbl_id];
1422 		for (filter_idx = 0;
1423 			filter_idx < sftp->sft_size;
1424 			filter_idx++) {
1425 			if (!siena_filter_test_used(sftp, filter_idx))
1426 				continue;
1427 
1428 			spec = &sftp->sft_spec[filter_idx];
1429 			if ((key = siena_filter_build(&filter, spec)) == 0) {
1430 				rc = EINVAL;
1431 				goto fail1;
1432 			}
1433 			if ((rc = siena_filter_push_entry(enp,
1434 				    spec->sfs_type, filter_idx, &filter)) != 0)
1435 				goto fail2;
1436 		}
1437 	}
1438 
1439 	siena_filter_push_rx_limits(enp);
1440 	siena_filter_push_tx_limits(enp);
1441 
1442 	EFSYS_UNLOCK(enp->en_eslp, state);
1443 
1444 	return (0);
1445 
1446 fail2:
1447 	EFSYS_PROBE(fail2);
1448 
1449 fail1:
1450 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1451 
1452 	EFSYS_UNLOCK(enp->en_eslp, state);
1453 
1454 	return (rc);
1455 }
1456 
1457 static	 __checkReturn	efx_rc_t
siena_filter_add(__in efx_nic_t * enp,__inout efx_filter_spec_t * spec,__in boolean_t may_replace)1458 siena_filter_add(
1459 	__in		efx_nic_t *enp,
1460 	__inout		efx_filter_spec_t *spec,
1461 	__in		boolean_t may_replace)
1462 {
1463 	efx_rc_t rc;
1464 	siena_filter_spec_t sf_spec;
1465 	siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1466 	siena_filter_tbl_id_t tbl_id;
1467 	siena_filter_tbl_t *sftp;
1468 	siena_filter_spec_t *saved_sf_spec;
1469 	efx_oword_t filter;
1470 	int filter_idx;
1471 	unsigned int depth;
1472 	efsys_lock_state_t state;
1473 	uint32_t key;
1474 
1475 	EFSYS_ASSERT3P(spec, !=, NULL);
1476 
1477 	if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1478 		goto fail1;
1479 
1480 	tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1481 	sftp = &sfp->sf_tbl[tbl_id];
1482 
1483 	if (sftp->sft_size == 0) {
1484 		rc = EINVAL;
1485 		goto fail2;
1486 	}
1487 
1488 	key = siena_filter_build(&filter, &sf_spec);
1489 
1490 	EFSYS_LOCK(enp->en_eslp, state);
1491 
1492 	rc = siena_filter_search(sftp, &sf_spec, key, B_TRUE,
1493 	    &filter_idx, &depth);
1494 	if (rc != 0)
1495 		goto fail3;
1496 
1497 	EFSYS_ASSERT3U(filter_idx, <, sftp->sft_size);
1498 	saved_sf_spec = &sftp->sft_spec[filter_idx];
1499 
1500 	if (siena_filter_test_used(sftp, filter_idx)) {
1501 		if (may_replace == B_FALSE) {
1502 			rc = EEXIST;
1503 			goto fail4;
1504 		}
1505 	}
1506 	siena_filter_set_used(sftp, filter_idx);
1507 	*saved_sf_spec = sf_spec;
1508 
1509 	if (sfp->sf_depth[sf_spec.sfs_type] < depth) {
1510 		sfp->sf_depth[sf_spec.sfs_type] = depth;
1511 		if (tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1512 		    tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC)
1513 			siena_filter_push_tx_limits(enp);
1514 		else
1515 			siena_filter_push_rx_limits(enp);
1516 	}
1517 
1518 	siena_filter_push_entry(enp, sf_spec.sfs_type,
1519 	    filter_idx, &filter);
1520 
1521 	EFSYS_UNLOCK(enp->en_eslp, state);
1522 	return (0);
1523 
1524 fail4:
1525 	EFSYS_PROBE(fail4);
1526 
1527 fail3:
1528 	EFSYS_UNLOCK(enp->en_eslp, state);
1529 	EFSYS_PROBE(fail3);
1530 
1531 fail2:
1532 	EFSYS_PROBE(fail2);
1533 
1534 fail1:
1535 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1536 	return (rc);
1537 }
1538 
1539 static	 __checkReturn	efx_rc_t
siena_filter_delete(__in efx_nic_t * enp,__inout efx_filter_spec_t * spec)1540 siena_filter_delete(
1541 	__in		efx_nic_t *enp,
1542 	__inout		efx_filter_spec_t *spec)
1543 {
1544 	efx_rc_t rc;
1545 	siena_filter_spec_t sf_spec;
1546 	siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1547 	siena_filter_tbl_id_t tbl_id;
1548 	siena_filter_tbl_t *sftp;
1549 	efx_oword_t filter;
1550 	int filter_idx;
1551 	unsigned int depth;
1552 	efsys_lock_state_t state;
1553 	uint32_t key;
1554 
1555 	EFSYS_ASSERT3P(spec, !=, NULL);
1556 
1557 	if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1558 		goto fail1;
1559 
1560 	tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1561 	sftp = &sfp->sf_tbl[tbl_id];
1562 
1563 	key = siena_filter_build(&filter, &sf_spec);
1564 
1565 	EFSYS_LOCK(enp->en_eslp, state);
1566 
1567 	rc = siena_filter_search(sftp, &sf_spec, key, B_FALSE,
1568 	    &filter_idx, &depth);
1569 	if (rc != 0)
1570 		goto fail2;
1571 
1572 	siena_filter_clear_entry(enp, sftp, filter_idx);
1573 	if (sftp->sft_used == 0)
1574 		siena_filter_reset_search_depth(sfp, tbl_id);
1575 
1576 	EFSYS_UNLOCK(enp->en_eslp, state);
1577 	return (0);
1578 
1579 fail2:
1580 	EFSYS_UNLOCK(enp->en_eslp, state);
1581 	EFSYS_PROBE(fail2);
1582 
1583 fail1:
1584 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1585 	return (rc);
1586 }
1587 
1588 #define	SIENA_MAX_SUPPORTED_MATCHES 4
1589 
1590 static	__checkReturn	efx_rc_t
siena_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)1591 siena_filter_supported_filters(
1592 	__in				efx_nic_t *enp,
1593 	__out_ecount(buffer_length)	uint32_t *buffer,
1594 	__in				size_t buffer_length,
1595 	__out				size_t *list_lengthp)
1596 {
1597 	uint32_t index = 0;
1598 	uint32_t rx_matches[SIENA_MAX_SUPPORTED_MATCHES];
1599 	size_t list_length;
1600 	efx_rc_t rc;
1601 
1602 	rx_matches[index++] =
1603 	    EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1604 	    EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
1605 	    EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
1606 
1607 	rx_matches[index++] =
1608 	    EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1609 	    EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
1610 
1611 	if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) {
1612 		rx_matches[index++] =
1613 		    EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC;
1614 
1615 		rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC;
1616 	}
1617 
1618 	EFSYS_ASSERT3U(index, <=, SIENA_MAX_SUPPORTED_MATCHES);
1619 	list_length = index;
1620 
1621 	*list_lengthp = list_length;
1622 
1623 	if (buffer_length < list_length) {
1624 		rc = ENOSPC;
1625 		goto fail1;
1626 	}
1627 
1628 	memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0]));
1629 
1630 	return (0);
1631 
1632 fail1:
1633 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1634 
1635 	return (rc);
1636 }
1637 
1638 #undef MAX_SUPPORTED
1639 
1640 #endif /* EFSYS_OPT_SIENA */
1641 
1642 #endif /* EFSYS_OPT_FILTER */
1643