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