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