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