2 * Copyright (c) 2007-2016 Solarflare Communications Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * The views and conclusions contained in the software and documentation are
27 * those of the authors and should not be interpreted as representing official
28 * policies, either expressed or implied, of the FreeBSD Project.
39 static __checkReturn efx_rc_t
47 static __checkReturn efx_rc_t
51 static __checkReturn efx_rc_t
54 __inout efx_filter_spec_t *spec,
55 __in boolean_t may_replace);
57 static __checkReturn efx_rc_t
60 __inout efx_filter_spec_t *spec);
62 static __checkReturn efx_rc_t
63 siena_filter_supported_filters(
65 __out_ecount(buffer_length) uint32_t *buffer,
66 __in size_t buffer_length,
67 __out size_t *list_lengthp);
69 #endif /* EFSYS_OPT_SIENA */
72 static const efx_filter_ops_t __efx_filter_siena_ops = {
73 siena_filter_init, /* efo_init */
74 siena_filter_fini, /* efo_fini */
75 siena_filter_restore, /* efo_restore */
76 siena_filter_add, /* efo_add */
77 siena_filter_delete, /* efo_delete */
78 siena_filter_supported_filters, /* efo_supported_filters */
79 NULL, /* efo_reconfigure */
81 #endif /* EFSYS_OPT_SIENA */
83 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
84 static const efx_filter_ops_t __efx_filter_ef10_ops = {
85 ef10_filter_init, /* efo_init */
86 ef10_filter_fini, /* efo_fini */
87 ef10_filter_restore, /* efo_restore */
88 ef10_filter_add, /* efo_add */
89 ef10_filter_delete, /* efo_delete */
90 ef10_filter_supported_filters, /* efo_supported_filters */
91 ef10_filter_reconfigure, /* efo_reconfigure */
93 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
95 __checkReturn efx_rc_t
98 __inout efx_filter_spec_t *spec)
100 const efx_filter_ops_t *efop = enp->en_efop;
102 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
103 EFSYS_ASSERT3P(spec, !=, NULL);
104 EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
106 return (efop->efo_add(enp, spec, B_FALSE));
109 __checkReturn efx_rc_t
112 __inout efx_filter_spec_t *spec)
114 const efx_filter_ops_t *efop = enp->en_efop;
116 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
117 EFSYS_ASSERT3P(spec, !=, NULL);
118 EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
120 return (efop->efo_delete(enp, spec));
123 __checkReturn efx_rc_t
129 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
131 if ((rc = enp->en_efop->efo_restore(enp)) != 0)
137 EFSYS_PROBE1(fail1, efx_rc_t, rc);
142 __checkReturn efx_rc_t
146 const efx_filter_ops_t *efop;
149 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
150 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
151 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER));
153 switch (enp->en_family) {
155 case EFX_FAMILY_SIENA:
156 efop = &__efx_filter_siena_ops;
158 #endif /* EFSYS_OPT_SIENA */
160 #if EFSYS_OPT_HUNTINGTON
161 case EFX_FAMILY_HUNTINGTON:
162 efop = &__efx_filter_ef10_ops;
164 #endif /* EFSYS_OPT_HUNTINGTON */
166 #if EFSYS_OPT_MEDFORD
167 case EFX_FAMILY_MEDFORD:
168 efop = &__efx_filter_ef10_ops;
170 #endif /* EFSYS_OPT_MEDFORD */
178 if ((rc = efop->efo_init(enp)) != 0)
182 enp->en_mod_flags |= EFX_MOD_FILTER;
188 EFSYS_PROBE1(fail1, efx_rc_t, rc);
191 enp->en_mod_flags &= ~EFX_MOD_FILTER;
199 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
200 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
201 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
203 enp->en_efop->efo_fini(enp);
206 enp->en_mod_flags &= ~EFX_MOD_FILTER;
210 * Query the possible combinations of match flags which can be filtered on.
211 * These are returned as a list, of which each 32 bit element is a bitmask
212 * formed of EFX_FILTER_MATCH flags.
214 * The combinations are ordered in priority from highest to lowest.
216 * If the provided buffer is too short to hold the list, the call with fail with
217 * ENOSPC and *list_lengthp will be set to the buffer length required.
219 __checkReturn efx_rc_t
220 efx_filter_supported_filters(
222 __out_ecount(buffer_length) uint32_t *buffer,
223 __in size_t buffer_length,
224 __out size_t *list_lengthp)
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 EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL);
233 if (buffer == NULL) {
238 rc = enp->en_efop->efo_supported_filters(enp, buffer, buffer_length,
248 EFSYS_PROBE1(fail1, efx_rc_t, rc);
253 __checkReturn efx_rc_t
254 efx_filter_reconfigure(
256 __in_ecount(6) uint8_t const *mac_addr,
257 __in boolean_t all_unicst,
258 __in boolean_t mulcst,
259 __in boolean_t all_mulcst,
260 __in boolean_t brdcst,
261 __in_ecount(6*count) uint8_t const *addrs,
266 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
267 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
268 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
270 if (enp->en_efop->efo_reconfigure != NULL) {
271 if ((rc = enp->en_efop->efo_reconfigure(enp, mac_addr,
281 EFSYS_PROBE1(fail1, efx_rc_t, rc);
287 efx_filter_spec_init_rx(
288 __out efx_filter_spec_t *spec,
289 __in efx_filter_priority_t priority,
290 __in efx_filter_flags_t flags,
293 EFSYS_ASSERT3P(spec, !=, NULL);
294 EFSYS_ASSERT3P(erp, !=, NULL);
295 EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
296 EFX_FILTER_FLAG_RX_SCATTER)) == 0);
298 memset(spec, 0, sizeof (*spec));
299 spec->efs_priority = priority;
300 spec->efs_flags = EFX_FILTER_FLAG_RX | flags;
301 spec->efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
302 spec->efs_dmaq_id = (uint16_t)erp->er_index;
306 efx_filter_spec_init_tx(
307 __out efx_filter_spec_t *spec,
310 EFSYS_ASSERT3P(spec, !=, NULL);
311 EFSYS_ASSERT3P(etp, !=, NULL);
313 memset(spec, 0, sizeof (*spec));
314 spec->efs_priority = EFX_FILTER_PRI_REQUIRED;
315 spec->efs_flags = EFX_FILTER_FLAG_TX;
316 spec->efs_dmaq_id = (uint16_t)etp->et_index;
321 * Specify IPv4 host, transport protocol and port in a filter specification
323 __checkReturn efx_rc_t
324 efx_filter_spec_set_ipv4_local(
325 __inout efx_filter_spec_t *spec,
330 EFSYS_ASSERT3P(spec, !=, NULL);
332 spec->efs_match_flags |=
333 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
334 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
335 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
336 spec->efs_ip_proto = proto;
337 spec->efs_loc_host.eo_u32[0] = host;
338 spec->efs_loc_port = port;
343 * Specify IPv4 hosts, transport protocol and ports in a filter specification
345 __checkReturn efx_rc_t
346 efx_filter_spec_set_ipv4_full(
347 __inout efx_filter_spec_t *spec,
354 EFSYS_ASSERT3P(spec, !=, NULL);
356 spec->efs_match_flags |=
357 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
358 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
359 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
360 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
361 spec->efs_ip_proto = proto;
362 spec->efs_loc_host.eo_u32[0] = lhost;
363 spec->efs_loc_port = lport;
364 spec->efs_rem_host.eo_u32[0] = rhost;
365 spec->efs_rem_port = rport;
370 * Specify local Ethernet address and/or VID in filter specification
372 __checkReturn efx_rc_t
373 efx_filter_spec_set_eth_local(
374 __inout efx_filter_spec_t *spec,
376 __in const uint8_t *addr)
378 EFSYS_ASSERT3P(spec, !=, NULL);
379 EFSYS_ASSERT3P(addr, !=, NULL);
381 if (vid == EFX_FILTER_SPEC_VID_UNSPEC && addr == NULL)
384 if (vid != EFX_FILTER_SPEC_VID_UNSPEC) {
385 spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID;
386 spec->efs_outer_vid = vid;
389 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
390 memcpy(spec->efs_loc_mac, addr, EFX_MAC_ADDR_LEN);
396 efx_filter_spec_set_ether_type(
397 __inout efx_filter_spec_t *spec,
398 __in uint16_t ether_type)
400 EFSYS_ASSERT3P(spec, !=, NULL);
402 spec->efs_ether_type = ether_type;
403 spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
407 * Specify matching otherwise-unmatched unicast in a filter specification
409 __checkReturn efx_rc_t
410 efx_filter_spec_set_uc_def(
411 __inout efx_filter_spec_t *spec)
413 EFSYS_ASSERT3P(spec, !=, NULL);
415 spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_UCAST_DST;
420 * Specify matching otherwise-unmatched multicast in a filter specification
422 __checkReturn efx_rc_t
423 efx_filter_spec_set_mc_def(
424 __inout efx_filter_spec_t *spec)
426 EFSYS_ASSERT3P(spec, !=, NULL);
428 spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
433 __checkReturn efx_rc_t
434 efx_filter_spec_set_encap_type(
435 __inout efx_filter_spec_t *spec,
436 __in efx_tunnel_protocol_t encap_type,
437 __in efx_filter_inner_frame_match_t inner_frame_match)
439 uint32_t match_flags = 0;
443 EFSYS_ASSERT3P(spec, !=, NULL);
445 switch (encap_type) {
446 case EFX_TUNNEL_PROTOCOL_VXLAN:
447 case EFX_TUNNEL_PROTOCOL_GENEVE:
448 ip_proto = EFX_IPPROTO_UDP;
450 case EFX_TUNNEL_PROTOCOL_NVGRE:
451 ip_proto = EFX_IPPROTO_GRE;
459 switch (inner_frame_match) {
460 case EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_MCAST_DST:
461 match_flags |= EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST;
463 case EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_UCAST_DST:
464 match_flags |= EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST;
466 case EFX_FILTER_INNER_FRAME_MATCH_OTHER:
467 /* This is for when specific inner frames are to be matched. */
475 spec->efs_encap_type = encap_type;
476 spec->efs_ip_proto = ip_proto;
477 spec->efs_match_flags |= (match_flags | EFX_FILTER_MATCH_IP_PROTO);
484 EFSYS_PROBE1(fail1, efx_rc_t, rc);
489 #if EFSYS_OPT_RX_SCALE
490 __checkReturn efx_rc_t
491 efx_filter_spec_set_rss_context(
492 __inout efx_filter_spec_t *spec,
493 __in uint32_t rss_context)
497 EFSYS_ASSERT3P(spec, !=, NULL);
499 /* The filter must have been created with EFX_FILTER_FLAG_RX_RSS. */
500 if ((spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) == 0) {
505 spec->efs_rss_context = rss_context;
510 EFSYS_PROBE1(fail1, efx_rc_t, rc);
519 * "Fudge factors" - difference between programmed value and actual depth.
520 * Due to pipelined implementation we need to program H/W with a value that
521 * is larger than the hop limit we want.
523 #define FILTER_CTL_SRCH_FUDGE_WILD 3
524 #define FILTER_CTL_SRCH_FUDGE_FULL 1
527 * Hard maximum hop limit. Hardware will time-out beyond 200-something.
528 * We also need to avoid infinite loops in efx_filter_search() when the
531 #define FILTER_CTL_SRCH_MAX 200
533 static __checkReturn efx_rc_t
534 siena_filter_spec_from_gen_spec(
535 __out siena_filter_spec_t *sf_spec,
536 __in efx_filter_spec_t *gen_spec)
539 boolean_t is_full = B_FALSE;
541 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX)
542 EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX);
544 EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX);
546 /* Siena only has one RSS context */
547 if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
548 gen_spec->efs_rss_context != EFX_RSS_CONTEXT_DEFAULT) {
553 sf_spec->sfs_flags = gen_spec->efs_flags;
554 sf_spec->sfs_dmaq_id = gen_spec->efs_dmaq_id;
556 switch (gen_spec->efs_match_flags) {
557 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
558 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
559 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT:
562 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
563 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: {
564 uint32_t rhost, host1, host2;
565 uint16_t rport, port1, port2;
567 if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) {
571 if (gen_spec->efs_loc_port == 0 ||
572 (is_full && gen_spec->efs_rem_port == 0)) {
576 switch (gen_spec->efs_ip_proto) {
577 case EFX_IPPROTO_TCP:
578 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
579 sf_spec->sfs_type = (is_full ?
580 EFX_SIENA_FILTER_TX_TCP_FULL :
581 EFX_SIENA_FILTER_TX_TCP_WILD);
583 sf_spec->sfs_type = (is_full ?
584 EFX_SIENA_FILTER_RX_TCP_FULL :
585 EFX_SIENA_FILTER_RX_TCP_WILD);
588 case EFX_IPPROTO_UDP:
589 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
590 sf_spec->sfs_type = (is_full ?
591 EFX_SIENA_FILTER_TX_UDP_FULL :
592 EFX_SIENA_FILTER_TX_UDP_WILD);
594 sf_spec->sfs_type = (is_full ?
595 EFX_SIENA_FILTER_RX_UDP_FULL :
596 EFX_SIENA_FILTER_RX_UDP_WILD);
604 * The filter is constructed in terms of source and destination,
605 * with the odd wrinkle that the ports are swapped in a UDP
606 * wildcard filter. We need to convert from local and remote
607 * addresses (zero for a wildcard).
609 rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0;
610 rport = is_full ? gen_spec->efs_rem_port : 0;
611 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
612 host1 = gen_spec->efs_loc_host.eo_u32[0];
616 host2 = gen_spec->efs_loc_host.eo_u32[0];
618 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
619 if (sf_spec->sfs_type ==
620 EFX_SIENA_FILTER_TX_UDP_WILD) {
622 port2 = gen_spec->efs_loc_port;
624 port1 = gen_spec->efs_loc_port;
628 if (sf_spec->sfs_type ==
629 EFX_SIENA_FILTER_RX_UDP_WILD) {
630 port1 = gen_spec->efs_loc_port;
634 port2 = gen_spec->efs_loc_port;
637 sf_spec->sfs_dword[0] = (host1 << 16) | port1;
638 sf_spec->sfs_dword[1] = (port2 << 16) | (host1 >> 16);
639 sf_spec->sfs_dword[2] = host2;
643 case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID:
646 case EFX_FILTER_MATCH_LOC_MAC:
647 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
648 sf_spec->sfs_type = (is_full ?
649 EFX_SIENA_FILTER_TX_MAC_FULL :
650 EFX_SIENA_FILTER_TX_MAC_WILD);
652 sf_spec->sfs_type = (is_full ?
653 EFX_SIENA_FILTER_RX_MAC_FULL :
654 EFX_SIENA_FILTER_RX_MAC_WILD);
656 sf_spec->sfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0;
657 sf_spec->sfs_dword[1] =
658 gen_spec->efs_loc_mac[2] << 24 |
659 gen_spec->efs_loc_mac[3] << 16 |
660 gen_spec->efs_loc_mac[4] << 8 |
661 gen_spec->efs_loc_mac[5];
662 sf_spec->sfs_dword[2] =
663 gen_spec->efs_loc_mac[0] << 8 |
664 gen_spec->efs_loc_mac[1];
668 EFSYS_ASSERT(B_FALSE);
684 EFSYS_PROBE1(fail1, efx_rc_t, rc);
690 * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
691 * key derived from the n-tuple.
694 siena_filter_tbl_hash(
699 /* First 16 rounds */
700 tmp = 0x1fff ^ (uint16_t)(key >> 16);
701 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
702 tmp = tmp ^ tmp >> 9;
705 tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff);
706 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
707 tmp = tmp ^ tmp >> 9;
713 * To allow for hash collisions, filter search continues at these
714 * increments from the first possible entry selected by the hash.
717 siena_filter_tbl_increment(
720 return ((uint16_t)(key * 2 - 1));
723 static __checkReturn boolean_t
724 siena_filter_test_used(
725 __in siena_filter_tbl_t *sftp,
726 __in unsigned int index)
728 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
729 return ((sftp->sft_bitmap[index / 32] & (1 << (index % 32))) != 0);
733 siena_filter_set_used(
734 __in siena_filter_tbl_t *sftp,
735 __in unsigned int index)
737 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
738 sftp->sft_bitmap[index / 32] |= (1 << (index % 32));
743 siena_filter_clear_used(
744 __in siena_filter_tbl_t *sftp,
745 __in unsigned int index)
747 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
748 sftp->sft_bitmap[index / 32] &= ~(1 << (index % 32));
751 EFSYS_ASSERT3U(sftp->sft_used, >=, 0);
755 static siena_filter_tbl_id_t
757 __in siena_filter_type_t type)
759 siena_filter_tbl_id_t tbl_id;
762 case EFX_SIENA_FILTER_RX_TCP_FULL:
763 case EFX_SIENA_FILTER_RX_TCP_WILD:
764 case EFX_SIENA_FILTER_RX_UDP_FULL:
765 case EFX_SIENA_FILTER_RX_UDP_WILD:
766 tbl_id = EFX_SIENA_FILTER_TBL_RX_IP;
769 case EFX_SIENA_FILTER_RX_MAC_FULL:
770 case EFX_SIENA_FILTER_RX_MAC_WILD:
771 tbl_id = EFX_SIENA_FILTER_TBL_RX_MAC;
774 case EFX_SIENA_FILTER_TX_TCP_FULL:
775 case EFX_SIENA_FILTER_TX_TCP_WILD:
776 case EFX_SIENA_FILTER_TX_UDP_FULL:
777 case EFX_SIENA_FILTER_TX_UDP_WILD:
778 tbl_id = EFX_SIENA_FILTER_TBL_TX_IP;
781 case EFX_SIENA_FILTER_TX_MAC_FULL:
782 case EFX_SIENA_FILTER_TX_MAC_WILD:
783 tbl_id = EFX_SIENA_FILTER_TBL_TX_MAC;
787 EFSYS_ASSERT(B_FALSE);
788 tbl_id = EFX_SIENA_FILTER_NTBLS;
795 siena_filter_reset_search_depth(
796 __inout siena_filter_t *sfp,
797 __in siena_filter_tbl_id_t tbl_id)
800 case EFX_SIENA_FILTER_TBL_RX_IP:
801 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] = 0;
802 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] = 0;
803 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] = 0;
804 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] = 0;
807 case EFX_SIENA_FILTER_TBL_RX_MAC:
808 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] = 0;
809 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] = 0;
812 case EFX_SIENA_FILTER_TBL_TX_IP:
813 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] = 0;
814 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] = 0;
815 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] = 0;
816 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] = 0;
819 case EFX_SIENA_FILTER_TBL_TX_MAC:
820 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] = 0;
821 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] = 0;
825 EFSYS_ASSERT(B_FALSE);
831 siena_filter_push_rx_limits(
834 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
837 EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
839 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT,
840 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] +
841 FILTER_CTL_SRCH_FUDGE_FULL);
842 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT,
843 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] +
844 FILTER_CTL_SRCH_FUDGE_WILD);
845 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT,
846 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] +
847 FILTER_CTL_SRCH_FUDGE_FULL);
848 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT,
849 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] +
850 FILTER_CTL_SRCH_FUDGE_WILD);
852 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC].sft_size) {
853 EFX_SET_OWORD_FIELD(oword,
854 FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
855 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] +
856 FILTER_CTL_SRCH_FUDGE_FULL);
857 EFX_SET_OWORD_FIELD(oword,
858 FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
859 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] +
860 FILTER_CTL_SRCH_FUDGE_WILD);
863 EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
867 siena_filter_push_tx_limits(
870 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
873 EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
875 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP].sft_size != 0) {
876 EFX_SET_OWORD_FIELD(oword,
877 FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE,
878 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] +
879 FILTER_CTL_SRCH_FUDGE_FULL);
880 EFX_SET_OWORD_FIELD(oword,
881 FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE,
882 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] +
883 FILTER_CTL_SRCH_FUDGE_WILD);
884 EFX_SET_OWORD_FIELD(oword,
885 FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE,
886 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] +
887 FILTER_CTL_SRCH_FUDGE_FULL);
888 EFX_SET_OWORD_FIELD(oword,
889 FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE,
890 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] +
891 FILTER_CTL_SRCH_FUDGE_WILD);
894 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC].sft_size != 0) {
896 oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
897 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] +
898 FILTER_CTL_SRCH_FUDGE_FULL);
900 oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
901 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] +
902 FILTER_CTL_SRCH_FUDGE_WILD);
905 EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
908 /* Build a filter entry and return its n-tuple key. */
909 static __checkReturn uint32_t
911 __out efx_oword_t *filter,
912 __in siena_filter_spec_t *spec)
916 uint8_t type = spec->sfs_type;
917 uint32_t flags = spec->sfs_flags;
919 switch (siena_filter_tbl_id(type)) {
920 case EFX_SIENA_FILTER_TBL_RX_IP: {
921 boolean_t is_udp = (type == EFX_SIENA_FILTER_RX_UDP_FULL ||
922 type == EFX_SIENA_FILTER_RX_UDP_WILD);
923 EFX_POPULATE_OWORD_7(*filter,
925 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
927 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
928 FRF_AZ_TCP_UDP, is_udp,
929 FRF_AZ_RXQ_ID, spec->sfs_dmaq_id,
930 EFX_DWORD_2, spec->sfs_dword[2],
931 EFX_DWORD_1, spec->sfs_dword[1],
932 EFX_DWORD_0, spec->sfs_dword[0]);
937 case EFX_SIENA_FILTER_TBL_RX_MAC: {
938 boolean_t is_wild = (type == EFX_SIENA_FILTER_RX_MAC_WILD);
939 EFX_POPULATE_OWORD_7(*filter,
941 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
942 FRF_CZ_RMFT_SCATTER_EN,
943 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
944 FRF_CZ_RMFT_RXQ_ID, spec->sfs_dmaq_id,
945 FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
946 FRF_CZ_RMFT_DEST_MAC_DW1, spec->sfs_dword[2],
947 FRF_CZ_RMFT_DEST_MAC_DW0, spec->sfs_dword[1],
948 FRF_CZ_RMFT_VLAN_ID, spec->sfs_dword[0]);
953 case EFX_SIENA_FILTER_TBL_TX_IP: {
954 boolean_t is_udp = (type == EFX_SIENA_FILTER_TX_UDP_FULL ||
955 type == EFX_SIENA_FILTER_TX_UDP_WILD);
956 EFX_POPULATE_OWORD_5(*filter,
957 FRF_CZ_TIFT_TCP_UDP, is_udp,
958 FRF_CZ_TIFT_TXQ_ID, spec->sfs_dmaq_id,
959 EFX_DWORD_2, spec->sfs_dword[2],
960 EFX_DWORD_1, spec->sfs_dword[1],
961 EFX_DWORD_0, spec->sfs_dword[0]);
962 dword3 = is_udp | spec->sfs_dmaq_id << 1;
966 case EFX_SIENA_FILTER_TBL_TX_MAC: {
967 boolean_t is_wild = (type == EFX_SIENA_FILTER_TX_MAC_WILD);
968 EFX_POPULATE_OWORD_5(*filter,
969 FRF_CZ_TMFT_TXQ_ID, spec->sfs_dmaq_id,
970 FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
971 FRF_CZ_TMFT_SRC_MAC_DW1, spec->sfs_dword[2],
972 FRF_CZ_TMFT_SRC_MAC_DW0, spec->sfs_dword[1],
973 FRF_CZ_TMFT_VLAN_ID, spec->sfs_dword[0]);
974 dword3 = is_wild | spec->sfs_dmaq_id << 1;
979 EFSYS_ASSERT(B_FALSE);
992 static __checkReturn efx_rc_t
993 siena_filter_push_entry(
994 __inout efx_nic_t *enp,
995 __in siena_filter_type_t type,
997 __in efx_oword_t *eop)
1002 case EFX_SIENA_FILTER_RX_TCP_FULL:
1003 case EFX_SIENA_FILTER_RX_TCP_WILD:
1004 case EFX_SIENA_FILTER_RX_UDP_FULL:
1005 case EFX_SIENA_FILTER_RX_UDP_WILD:
1006 EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index,
1010 case EFX_SIENA_FILTER_RX_MAC_FULL:
1011 case EFX_SIENA_FILTER_RX_MAC_WILD:
1012 EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index,
1016 case EFX_SIENA_FILTER_TX_TCP_FULL:
1017 case EFX_SIENA_FILTER_TX_TCP_WILD:
1018 case EFX_SIENA_FILTER_TX_UDP_FULL:
1019 case EFX_SIENA_FILTER_TX_UDP_WILD:
1020 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index,
1024 case EFX_SIENA_FILTER_TX_MAC_FULL:
1025 case EFX_SIENA_FILTER_TX_MAC_WILD:
1026 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index,
1031 EFSYS_ASSERT(B_FALSE);
1042 static __checkReturn boolean_t
1044 __in const siena_filter_spec_t *left,
1045 __in const siena_filter_spec_t *right)
1047 siena_filter_tbl_id_t tbl_id;
1049 tbl_id = siena_filter_tbl_id(left->sfs_type);
1052 if (left->sfs_type != right->sfs_type)
1055 if (memcmp(left->sfs_dword, right->sfs_dword,
1056 sizeof (left->sfs_dword)))
1059 if ((tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1060 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) &&
1061 left->sfs_dmaq_id != right->sfs_dmaq_id)
1067 static __checkReturn efx_rc_t
1068 siena_filter_search(
1069 __in siena_filter_tbl_t *sftp,
1070 __in siena_filter_spec_t *spec,
1072 __in boolean_t for_insert,
1073 __out int *filter_index,
1074 __out unsigned int *depth_required)
1076 unsigned int hash, incr, filter_idx, depth;
1078 hash = siena_filter_tbl_hash(key);
1079 incr = siena_filter_tbl_increment(key);
1081 filter_idx = hash & (sftp->sft_size - 1);
1086 * Return success if entry is used and matches this spec
1087 * or entry is unused and we are trying to insert.
1089 if (siena_filter_test_used(sftp, filter_idx) ?
1090 siena_filter_equal(spec,
1091 &sftp->sft_spec[filter_idx]) :
1093 *filter_index = filter_idx;
1094 *depth_required = depth;
1098 /* Return failure if we reached the maximum search depth */
1099 if (depth == FILTER_CTL_SRCH_MAX)
1100 return (for_insert ? EBUSY : ENOENT);
1102 filter_idx = (filter_idx + incr) & (sftp->sft_size - 1);
1108 siena_filter_clear_entry(
1109 __in efx_nic_t *enp,
1110 __in siena_filter_tbl_t *sftp,
1115 if (siena_filter_test_used(sftp, index)) {
1116 siena_filter_clear_used(sftp, index);
1118 EFX_ZERO_OWORD(filter);
1119 siena_filter_push_entry(enp,
1120 sftp->sft_spec[index].sfs_type,
1123 memset(&sftp->sft_spec[index],
1124 0, sizeof (sftp->sft_spec[0]));
1129 siena_filter_tbl_clear(
1130 __in efx_nic_t *enp,
1131 __in siena_filter_tbl_id_t tbl_id)
1133 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1134 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1136 efsys_lock_state_t state;
1138 EFSYS_LOCK(enp->en_eslp, state);
1140 for (index = 0; index < sftp->sft_size; ++index) {
1141 siena_filter_clear_entry(enp, sftp, index);
1144 if (sftp->sft_used == 0)
1145 siena_filter_reset_search_depth(sfp, tbl_id);
1147 EFSYS_UNLOCK(enp->en_eslp, state);
1150 static __checkReturn efx_rc_t
1152 __in efx_nic_t *enp)
1154 siena_filter_t *sfp;
1155 siena_filter_tbl_t *sftp;
1159 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (siena_filter_t), sfp);
1166 enp->en_filter.ef_siena_filter = sfp;
1168 switch (enp->en_family) {
1169 case EFX_FAMILY_SIENA:
1170 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_IP];
1171 sftp->sft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
1173 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC];
1174 sftp->sft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
1176 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP];
1177 sftp->sft_size = FR_CZ_TX_FILTER_TBL0_ROWS;
1179 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC];
1180 sftp->sft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
1188 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1189 unsigned int bitmap_size;
1191 sftp = &sfp->sf_tbl[tbl_id];
1192 if (sftp->sft_size == 0)
1195 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1198 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1200 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, sftp->sft_bitmap);
1201 if (!sftp->sft_bitmap) {
1206 EFSYS_KMEM_ALLOC(enp->en_esip,
1207 sftp->sft_size * sizeof (*sftp->sft_spec),
1209 if (!sftp->sft_spec) {
1213 memset(sftp->sft_spec, 0,
1214 sftp->sft_size * sizeof (*sftp->sft_spec));
1227 siena_filter_fini(enp);
1230 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1236 __in efx_nic_t *enp)
1238 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1239 siena_filter_tbl_id_t tbl_id;
1241 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1242 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1247 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1248 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1249 unsigned int bitmap_size;
1251 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1254 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1256 if (sftp->sft_bitmap != NULL) {
1257 EFSYS_KMEM_FREE(enp->en_esip, bitmap_size,
1259 sftp->sft_bitmap = NULL;
1262 if (sftp->sft_spec != NULL) {
1263 EFSYS_KMEM_FREE(enp->en_esip, sftp->sft_size *
1264 sizeof (*sftp->sft_spec), sftp->sft_spec);
1265 sftp->sft_spec = NULL;
1269 EFSYS_KMEM_FREE(enp->en_esip, sizeof (siena_filter_t),
1270 enp->en_filter.ef_siena_filter);
1273 /* Restore filter state after a reset */
1274 static __checkReturn efx_rc_t
1275 siena_filter_restore(
1276 __in efx_nic_t *enp)
1278 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1279 siena_filter_tbl_id_t tbl_id;
1280 siena_filter_tbl_t *sftp;
1281 siena_filter_spec_t *spec;
1284 efsys_lock_state_t state;
1288 EFSYS_LOCK(enp->en_eslp, state);
1290 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1291 sftp = &sfp->sf_tbl[tbl_id];
1292 for (filter_idx = 0;
1293 filter_idx < sftp->sft_size;
1295 if (!siena_filter_test_used(sftp, filter_idx))
1298 spec = &sftp->sft_spec[filter_idx];
1299 if ((key = siena_filter_build(&filter, spec)) == 0) {
1303 if ((rc = siena_filter_push_entry(enp,
1304 spec->sfs_type, filter_idx, &filter)) != 0)
1309 siena_filter_push_rx_limits(enp);
1310 siena_filter_push_tx_limits(enp);
1312 EFSYS_UNLOCK(enp->en_eslp, state);
1320 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1322 EFSYS_UNLOCK(enp->en_eslp, state);
1327 static __checkReturn efx_rc_t
1329 __in efx_nic_t *enp,
1330 __inout efx_filter_spec_t *spec,
1331 __in boolean_t may_replace)
1334 siena_filter_spec_t sf_spec;
1335 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1336 siena_filter_tbl_id_t tbl_id;
1337 siena_filter_tbl_t *sftp;
1338 siena_filter_spec_t *saved_sf_spec;
1342 efsys_lock_state_t state;
1346 EFSYS_ASSERT3P(spec, !=, NULL);
1348 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1351 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1352 sftp = &sfp->sf_tbl[tbl_id];
1354 if (sftp->sft_size == 0) {
1359 key = siena_filter_build(&filter, &sf_spec);
1361 EFSYS_LOCK(enp->en_eslp, state);
1363 rc = siena_filter_search(sftp, &sf_spec, key, B_TRUE,
1364 &filter_idx, &depth);
1368 EFSYS_ASSERT3U(filter_idx, <, sftp->sft_size);
1369 saved_sf_spec = &sftp->sft_spec[filter_idx];
1371 if (siena_filter_test_used(sftp, filter_idx)) {
1372 if (may_replace == B_FALSE) {
1377 siena_filter_set_used(sftp, filter_idx);
1378 *saved_sf_spec = sf_spec;
1380 if (sfp->sf_depth[sf_spec.sfs_type] < depth) {
1381 sfp->sf_depth[sf_spec.sfs_type] = depth;
1382 if (tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1383 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC)
1384 siena_filter_push_tx_limits(enp);
1386 siena_filter_push_rx_limits(enp);
1389 siena_filter_push_entry(enp, sf_spec.sfs_type,
1390 filter_idx, &filter);
1392 EFSYS_UNLOCK(enp->en_eslp, state);
1399 EFSYS_UNLOCK(enp->en_eslp, state);
1406 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1410 static __checkReturn efx_rc_t
1411 siena_filter_delete(
1412 __in efx_nic_t *enp,
1413 __inout efx_filter_spec_t *spec)
1416 siena_filter_spec_t sf_spec;
1417 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1418 siena_filter_tbl_id_t tbl_id;
1419 siena_filter_tbl_t *sftp;
1423 efsys_lock_state_t state;
1426 EFSYS_ASSERT3P(spec, !=, NULL);
1428 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1431 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1432 sftp = &sfp->sf_tbl[tbl_id];
1434 key = siena_filter_build(&filter, &sf_spec);
1436 EFSYS_LOCK(enp->en_eslp, state);
1438 rc = siena_filter_search(sftp, &sf_spec, key, B_FALSE,
1439 &filter_idx, &depth);
1443 siena_filter_clear_entry(enp, sftp, filter_idx);
1444 if (sftp->sft_used == 0)
1445 siena_filter_reset_search_depth(sfp, tbl_id);
1447 EFSYS_UNLOCK(enp->en_eslp, state);
1451 EFSYS_UNLOCK(enp->en_eslp, state);
1455 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1459 #define SIENA_MAX_SUPPORTED_MATCHES 4
1461 static __checkReturn efx_rc_t
1462 siena_filter_supported_filters(
1463 __in efx_nic_t *enp,
1464 __out_ecount(buffer_length) uint32_t *buffer,
1465 __in size_t buffer_length,
1466 __out size_t *list_lengthp)
1469 uint32_t rx_matches[SIENA_MAX_SUPPORTED_MATCHES];
1473 rx_matches[index++] =
1474 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1475 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
1476 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
1478 rx_matches[index++] =
1479 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1480 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
1482 if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) {
1483 rx_matches[index++] =
1484 EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC;
1486 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC;
1489 EFSYS_ASSERT3U(index, <=, SIENA_MAX_SUPPORTED_MATCHES);
1490 list_length = index;
1492 *list_lengthp = list_length;
1494 if (buffer_length < list_length) {
1499 memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0]));
1504 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1509 #undef MAX_SUPPORTED
1511 #endif /* EFSYS_OPT_SIENA */
1513 #endif /* EFSYS_OPT_FILTER */