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