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 #if EFSYS_OPT_RX_SCALE
121 spec->efs_rss_context = enp->en_rss_context;
124 return (efop->efo_delete(enp, spec));
127 __checkReturn efx_rc_t
133 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
135 if ((rc = enp->en_efop->efo_restore(enp)) != 0)
141 EFSYS_PROBE1(fail1, efx_rc_t, rc);
146 __checkReturn efx_rc_t
150 const efx_filter_ops_t *efop;
153 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
154 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
155 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER));
157 switch (enp->en_family) {
159 case EFX_FAMILY_SIENA:
160 efop = &__efx_filter_siena_ops;
162 #endif /* EFSYS_OPT_SIENA */
164 #if EFSYS_OPT_HUNTINGTON
165 case EFX_FAMILY_HUNTINGTON:
166 efop = &__efx_filter_ef10_ops;
168 #endif /* EFSYS_OPT_HUNTINGTON */
170 #if EFSYS_OPT_MEDFORD
171 case EFX_FAMILY_MEDFORD:
172 efop = &__efx_filter_ef10_ops;
174 #endif /* EFSYS_OPT_MEDFORD */
182 if ((rc = efop->efo_init(enp)) != 0)
186 enp->en_mod_flags |= EFX_MOD_FILTER;
192 EFSYS_PROBE1(fail1, efx_rc_t, rc);
195 enp->en_mod_flags &= ~EFX_MOD_FILTER;
203 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
204 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
205 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
207 enp->en_efop->efo_fini(enp);
210 enp->en_mod_flags &= ~EFX_MOD_FILTER;
214 * Query the possible combinations of match flags which can be filtered on.
215 * These are returned as a list, of which each 32 bit element is a bitmask
216 * formed of EFX_FILTER_MATCH flags.
218 * The combinations are ordered in priority from highest to lowest.
220 * If the provided buffer is too short to hold the list, the call with fail with
221 * ENOSPC and *list_lengthp will be set to the buffer length required.
223 __checkReturn efx_rc_t
224 efx_filter_supported_filters(
226 __out_ecount(buffer_length) uint32_t *buffer,
227 __in size_t buffer_length,
228 __out size_t *list_lengthp)
232 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
233 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
234 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
235 EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL);
237 if (buffer == NULL) {
242 rc = enp->en_efop->efo_supported_filters(enp, buffer, buffer_length,
252 EFSYS_PROBE1(fail1, efx_rc_t, rc);
257 __checkReturn efx_rc_t
258 efx_filter_reconfigure(
260 __in_ecount(6) uint8_t const *mac_addr,
261 __in boolean_t all_unicst,
262 __in boolean_t mulcst,
263 __in boolean_t all_mulcst,
264 __in boolean_t brdcst,
265 __in_ecount(6*count) uint8_t const *addrs,
270 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
271 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
272 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
274 if (enp->en_efop->efo_reconfigure != NULL) {
275 if ((rc = enp->en_efop->efo_reconfigure(enp, mac_addr,
285 EFSYS_PROBE1(fail1, efx_rc_t, rc);
291 efx_filter_spec_init_rx(
292 __out efx_filter_spec_t *spec,
293 __in efx_filter_priority_t priority,
294 __in efx_filter_flags_t flags,
297 EFSYS_ASSERT3P(spec, !=, NULL);
298 EFSYS_ASSERT3P(erp, !=, NULL);
299 EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
300 EFX_FILTER_FLAG_RX_SCATTER)) == 0);
302 memset(spec, 0, sizeof (*spec));
303 spec->efs_priority = priority;
304 spec->efs_flags = EFX_FILTER_FLAG_RX | flags;
305 spec->efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
306 spec->efs_dmaq_id = (uint16_t)erp->er_index;
310 efx_filter_spec_init_tx(
311 __out efx_filter_spec_t *spec,
314 EFSYS_ASSERT3P(spec, !=, NULL);
315 EFSYS_ASSERT3P(etp, !=, NULL);
317 memset(spec, 0, sizeof (*spec));
318 spec->efs_priority = EFX_FILTER_PRI_REQUIRED;
319 spec->efs_flags = EFX_FILTER_FLAG_TX;
320 spec->efs_dmaq_id = (uint16_t)etp->et_index;
325 * Specify IPv4 host, transport protocol and port in a filter specification
327 __checkReturn efx_rc_t
328 efx_filter_spec_set_ipv4_local(
329 __inout efx_filter_spec_t *spec,
334 EFSYS_ASSERT3P(spec, !=, NULL);
336 spec->efs_match_flags |=
337 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
338 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
339 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
340 spec->efs_ip_proto = proto;
341 spec->efs_loc_host.eo_u32[0] = host;
342 spec->efs_loc_port = port;
347 * Specify IPv4 hosts, transport protocol and ports in a filter specification
349 __checkReturn efx_rc_t
350 efx_filter_spec_set_ipv4_full(
351 __inout efx_filter_spec_t *spec,
358 EFSYS_ASSERT3P(spec, !=, NULL);
360 spec->efs_match_flags |=
361 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
362 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
363 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
364 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
365 spec->efs_ip_proto = proto;
366 spec->efs_loc_host.eo_u32[0] = lhost;
367 spec->efs_loc_port = lport;
368 spec->efs_rem_host.eo_u32[0] = rhost;
369 spec->efs_rem_port = rport;
374 * Specify local Ethernet address and/or VID in filter specification
376 __checkReturn efx_rc_t
377 efx_filter_spec_set_eth_local(
378 __inout efx_filter_spec_t *spec,
380 __in const uint8_t *addr)
382 EFSYS_ASSERT3P(spec, !=, NULL);
383 EFSYS_ASSERT3P(addr, !=, NULL);
385 if (vid == EFX_FILTER_SPEC_VID_UNSPEC && addr == NULL)
388 if (vid != EFX_FILTER_SPEC_VID_UNSPEC) {
389 spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID;
390 spec->efs_outer_vid = vid;
393 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
394 memcpy(spec->efs_loc_mac, addr, EFX_MAC_ADDR_LEN);
400 efx_filter_spec_set_ether_type(
401 __inout efx_filter_spec_t *spec,
402 __in uint16_t ether_type)
404 EFSYS_ASSERT3P(spec, !=, NULL);
406 spec->efs_ether_type = ether_type;
407 spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
411 * Specify matching otherwise-unmatched unicast in a filter specification
413 __checkReturn efx_rc_t
414 efx_filter_spec_set_uc_def(
415 __inout efx_filter_spec_t *spec)
417 EFSYS_ASSERT3P(spec, !=, NULL);
419 spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_UCAST_DST;
424 * Specify matching otherwise-unmatched multicast in a filter specification
426 __checkReturn efx_rc_t
427 efx_filter_spec_set_mc_def(
428 __inout efx_filter_spec_t *spec)
430 EFSYS_ASSERT3P(spec, !=, NULL);
432 spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
437 __checkReturn efx_rc_t
438 efx_filter_spec_set_encap_type(
439 __inout efx_filter_spec_t *spec,
440 __in efx_tunnel_protocol_t encap_type,
441 __in efx_filter_inner_frame_match_t inner_frame_match)
443 uint32_t match_flags = 0;
447 EFSYS_ASSERT3P(spec, !=, NULL);
449 switch (encap_type) {
450 case EFX_TUNNEL_PROTOCOL_VXLAN:
451 case EFX_TUNNEL_PROTOCOL_GENEVE:
452 ip_proto = EFX_IPPROTO_UDP;
454 case EFX_TUNNEL_PROTOCOL_NVGRE:
455 ip_proto = EFX_IPPROTO_GRE;
463 switch (inner_frame_match) {
464 case EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_MCAST_DST:
465 match_flags |= EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST;
467 case EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_UCAST_DST:
468 match_flags |= EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST;
470 case EFX_FILTER_INNER_FRAME_MATCH_OTHER:
471 /* This is for when specific inner frames are to be matched. */
479 spec->efs_encap_type = encap_type;
480 spec->efs_ip_proto = ip_proto;
481 spec->efs_match_flags |= (match_flags | EFX_FILTER_MATCH_IP_PROTO);
488 EFSYS_PROBE1(fail1, efx_rc_t, rc);
498 * "Fudge factors" - difference between programmed value and actual depth.
499 * Due to pipelined implementation we need to program H/W with a value that
500 * is larger than the hop limit we want.
502 #define FILTER_CTL_SRCH_FUDGE_WILD 3
503 #define FILTER_CTL_SRCH_FUDGE_FULL 1
506 * Hard maximum hop limit. Hardware will time-out beyond 200-something.
507 * We also need to avoid infinite loops in efx_filter_search() when the
510 #define FILTER_CTL_SRCH_MAX 200
512 static __checkReturn efx_rc_t
513 siena_filter_spec_from_gen_spec(
514 __out siena_filter_spec_t *sf_spec,
515 __in efx_filter_spec_t *gen_spec)
518 boolean_t is_full = B_FALSE;
520 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX)
521 EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX);
523 EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX);
525 /* Siena only has one RSS context */
526 if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
527 gen_spec->efs_rss_context != EFX_RSS_CONTEXT_DEFAULT) {
532 sf_spec->sfs_flags = gen_spec->efs_flags;
533 sf_spec->sfs_dmaq_id = gen_spec->efs_dmaq_id;
535 switch (gen_spec->efs_match_flags) {
536 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
537 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
538 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT:
541 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
542 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: {
543 uint32_t rhost, host1, host2;
544 uint16_t rport, port1, port2;
546 if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) {
550 if (gen_spec->efs_loc_port == 0 ||
551 (is_full && gen_spec->efs_rem_port == 0)) {
555 switch (gen_spec->efs_ip_proto) {
556 case EFX_IPPROTO_TCP:
557 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
558 sf_spec->sfs_type = (is_full ?
559 EFX_SIENA_FILTER_TX_TCP_FULL :
560 EFX_SIENA_FILTER_TX_TCP_WILD);
562 sf_spec->sfs_type = (is_full ?
563 EFX_SIENA_FILTER_RX_TCP_FULL :
564 EFX_SIENA_FILTER_RX_TCP_WILD);
567 case EFX_IPPROTO_UDP:
568 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
569 sf_spec->sfs_type = (is_full ?
570 EFX_SIENA_FILTER_TX_UDP_FULL :
571 EFX_SIENA_FILTER_TX_UDP_WILD);
573 sf_spec->sfs_type = (is_full ?
574 EFX_SIENA_FILTER_RX_UDP_FULL :
575 EFX_SIENA_FILTER_RX_UDP_WILD);
583 * The filter is constructed in terms of source and destination,
584 * with the odd wrinkle that the ports are swapped in a UDP
585 * wildcard filter. We need to convert from local and remote
586 * addresses (zero for a wildcard).
588 rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0;
589 rport = is_full ? gen_spec->efs_rem_port : 0;
590 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
591 host1 = gen_spec->efs_loc_host.eo_u32[0];
595 host2 = gen_spec->efs_loc_host.eo_u32[0];
597 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
598 if (sf_spec->sfs_type ==
599 EFX_SIENA_FILTER_TX_UDP_WILD) {
601 port2 = gen_spec->efs_loc_port;
603 port1 = gen_spec->efs_loc_port;
607 if (sf_spec->sfs_type ==
608 EFX_SIENA_FILTER_RX_UDP_WILD) {
609 port1 = gen_spec->efs_loc_port;
613 port2 = gen_spec->efs_loc_port;
616 sf_spec->sfs_dword[0] = (host1 << 16) | port1;
617 sf_spec->sfs_dword[1] = (port2 << 16) | (host1 >> 16);
618 sf_spec->sfs_dword[2] = host2;
622 case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID:
625 case EFX_FILTER_MATCH_LOC_MAC:
626 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
627 sf_spec->sfs_type = (is_full ?
628 EFX_SIENA_FILTER_TX_MAC_FULL :
629 EFX_SIENA_FILTER_TX_MAC_WILD);
631 sf_spec->sfs_type = (is_full ?
632 EFX_SIENA_FILTER_RX_MAC_FULL :
633 EFX_SIENA_FILTER_RX_MAC_WILD);
635 sf_spec->sfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0;
636 sf_spec->sfs_dword[1] =
637 gen_spec->efs_loc_mac[2] << 24 |
638 gen_spec->efs_loc_mac[3] << 16 |
639 gen_spec->efs_loc_mac[4] << 8 |
640 gen_spec->efs_loc_mac[5];
641 sf_spec->sfs_dword[2] =
642 gen_spec->efs_loc_mac[0] << 8 |
643 gen_spec->efs_loc_mac[1];
647 EFSYS_ASSERT(B_FALSE);
663 EFSYS_PROBE1(fail1, efx_rc_t, rc);
669 * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
670 * key derived from the n-tuple.
673 siena_filter_tbl_hash(
678 /* First 16 rounds */
679 tmp = 0x1fff ^ (uint16_t)(key >> 16);
680 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
681 tmp = tmp ^ tmp >> 9;
684 tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff);
685 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
686 tmp = tmp ^ tmp >> 9;
692 * To allow for hash collisions, filter search continues at these
693 * increments from the first possible entry selected by the hash.
696 siena_filter_tbl_increment(
699 return ((uint16_t)(key * 2 - 1));
702 static __checkReturn boolean_t
703 siena_filter_test_used(
704 __in siena_filter_tbl_t *sftp,
705 __in unsigned int index)
707 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
708 return ((sftp->sft_bitmap[index / 32] & (1 << (index % 32))) != 0);
712 siena_filter_set_used(
713 __in siena_filter_tbl_t *sftp,
714 __in unsigned int index)
716 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
717 sftp->sft_bitmap[index / 32] |= (1 << (index % 32));
722 siena_filter_clear_used(
723 __in siena_filter_tbl_t *sftp,
724 __in unsigned int index)
726 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
727 sftp->sft_bitmap[index / 32] &= ~(1 << (index % 32));
730 EFSYS_ASSERT3U(sftp->sft_used, >=, 0);
734 static siena_filter_tbl_id_t
736 __in siena_filter_type_t type)
738 siena_filter_tbl_id_t tbl_id;
741 case EFX_SIENA_FILTER_RX_TCP_FULL:
742 case EFX_SIENA_FILTER_RX_TCP_WILD:
743 case EFX_SIENA_FILTER_RX_UDP_FULL:
744 case EFX_SIENA_FILTER_RX_UDP_WILD:
745 tbl_id = EFX_SIENA_FILTER_TBL_RX_IP;
748 case EFX_SIENA_FILTER_RX_MAC_FULL:
749 case EFX_SIENA_FILTER_RX_MAC_WILD:
750 tbl_id = EFX_SIENA_FILTER_TBL_RX_MAC;
753 case EFX_SIENA_FILTER_TX_TCP_FULL:
754 case EFX_SIENA_FILTER_TX_TCP_WILD:
755 case EFX_SIENA_FILTER_TX_UDP_FULL:
756 case EFX_SIENA_FILTER_TX_UDP_WILD:
757 tbl_id = EFX_SIENA_FILTER_TBL_TX_IP;
760 case EFX_SIENA_FILTER_TX_MAC_FULL:
761 case EFX_SIENA_FILTER_TX_MAC_WILD:
762 tbl_id = EFX_SIENA_FILTER_TBL_TX_MAC;
766 EFSYS_ASSERT(B_FALSE);
767 tbl_id = EFX_SIENA_FILTER_NTBLS;
774 siena_filter_reset_search_depth(
775 __inout siena_filter_t *sfp,
776 __in siena_filter_tbl_id_t tbl_id)
779 case EFX_SIENA_FILTER_TBL_RX_IP:
780 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] = 0;
781 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] = 0;
782 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] = 0;
783 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] = 0;
786 case EFX_SIENA_FILTER_TBL_RX_MAC:
787 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] = 0;
788 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] = 0;
791 case EFX_SIENA_FILTER_TBL_TX_IP:
792 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] = 0;
793 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] = 0;
794 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] = 0;
795 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] = 0;
798 case EFX_SIENA_FILTER_TBL_TX_MAC:
799 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] = 0;
800 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] = 0;
804 EFSYS_ASSERT(B_FALSE);
810 siena_filter_push_rx_limits(
813 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
816 EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
818 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT,
819 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] +
820 FILTER_CTL_SRCH_FUDGE_FULL);
821 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT,
822 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] +
823 FILTER_CTL_SRCH_FUDGE_WILD);
824 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT,
825 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] +
826 FILTER_CTL_SRCH_FUDGE_FULL);
827 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT,
828 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] +
829 FILTER_CTL_SRCH_FUDGE_WILD);
831 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC].sft_size) {
832 EFX_SET_OWORD_FIELD(oword,
833 FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
834 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] +
835 FILTER_CTL_SRCH_FUDGE_FULL);
836 EFX_SET_OWORD_FIELD(oword,
837 FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
838 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] +
839 FILTER_CTL_SRCH_FUDGE_WILD);
842 EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
846 siena_filter_push_tx_limits(
849 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
852 EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
854 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP].sft_size != 0) {
855 EFX_SET_OWORD_FIELD(oword,
856 FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE,
857 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] +
858 FILTER_CTL_SRCH_FUDGE_FULL);
859 EFX_SET_OWORD_FIELD(oword,
860 FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE,
861 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] +
862 FILTER_CTL_SRCH_FUDGE_WILD);
863 EFX_SET_OWORD_FIELD(oword,
864 FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE,
865 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] +
866 FILTER_CTL_SRCH_FUDGE_FULL);
867 EFX_SET_OWORD_FIELD(oword,
868 FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE,
869 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] +
870 FILTER_CTL_SRCH_FUDGE_WILD);
873 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC].sft_size != 0) {
875 oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
876 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] +
877 FILTER_CTL_SRCH_FUDGE_FULL);
879 oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
880 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] +
881 FILTER_CTL_SRCH_FUDGE_WILD);
884 EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
887 /* Build a filter entry and return its n-tuple key. */
888 static __checkReturn uint32_t
890 __out efx_oword_t *filter,
891 __in siena_filter_spec_t *spec)
895 uint8_t type = spec->sfs_type;
896 uint32_t flags = spec->sfs_flags;
898 switch (siena_filter_tbl_id(type)) {
899 case EFX_SIENA_FILTER_TBL_RX_IP: {
900 boolean_t is_udp = (type == EFX_SIENA_FILTER_RX_UDP_FULL ||
901 type == EFX_SIENA_FILTER_RX_UDP_WILD);
902 EFX_POPULATE_OWORD_7(*filter,
904 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
906 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
907 FRF_AZ_TCP_UDP, is_udp,
908 FRF_AZ_RXQ_ID, spec->sfs_dmaq_id,
909 EFX_DWORD_2, spec->sfs_dword[2],
910 EFX_DWORD_1, spec->sfs_dword[1],
911 EFX_DWORD_0, spec->sfs_dword[0]);
916 case EFX_SIENA_FILTER_TBL_RX_MAC: {
917 boolean_t is_wild = (type == EFX_SIENA_FILTER_RX_MAC_WILD);
918 EFX_POPULATE_OWORD_7(*filter,
920 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
921 FRF_CZ_RMFT_SCATTER_EN,
922 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
923 FRF_CZ_RMFT_RXQ_ID, spec->sfs_dmaq_id,
924 FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
925 FRF_CZ_RMFT_DEST_MAC_DW1, spec->sfs_dword[2],
926 FRF_CZ_RMFT_DEST_MAC_DW0, spec->sfs_dword[1],
927 FRF_CZ_RMFT_VLAN_ID, spec->sfs_dword[0]);
932 case EFX_SIENA_FILTER_TBL_TX_IP: {
933 boolean_t is_udp = (type == EFX_SIENA_FILTER_TX_UDP_FULL ||
934 type == EFX_SIENA_FILTER_TX_UDP_WILD);
935 EFX_POPULATE_OWORD_5(*filter,
936 FRF_CZ_TIFT_TCP_UDP, is_udp,
937 FRF_CZ_TIFT_TXQ_ID, spec->sfs_dmaq_id,
938 EFX_DWORD_2, spec->sfs_dword[2],
939 EFX_DWORD_1, spec->sfs_dword[1],
940 EFX_DWORD_0, spec->sfs_dword[0]);
941 dword3 = is_udp | spec->sfs_dmaq_id << 1;
945 case EFX_SIENA_FILTER_TBL_TX_MAC: {
946 boolean_t is_wild = (type == EFX_SIENA_FILTER_TX_MAC_WILD);
947 EFX_POPULATE_OWORD_5(*filter,
948 FRF_CZ_TMFT_TXQ_ID, spec->sfs_dmaq_id,
949 FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
950 FRF_CZ_TMFT_SRC_MAC_DW1, spec->sfs_dword[2],
951 FRF_CZ_TMFT_SRC_MAC_DW0, spec->sfs_dword[1],
952 FRF_CZ_TMFT_VLAN_ID, spec->sfs_dword[0]);
953 dword3 = is_wild | spec->sfs_dmaq_id << 1;
958 EFSYS_ASSERT(B_FALSE);
971 static __checkReturn efx_rc_t
972 siena_filter_push_entry(
973 __inout efx_nic_t *enp,
974 __in siena_filter_type_t type,
976 __in efx_oword_t *eop)
981 case EFX_SIENA_FILTER_RX_TCP_FULL:
982 case EFX_SIENA_FILTER_RX_TCP_WILD:
983 case EFX_SIENA_FILTER_RX_UDP_FULL:
984 case EFX_SIENA_FILTER_RX_UDP_WILD:
985 EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index,
989 case EFX_SIENA_FILTER_RX_MAC_FULL:
990 case EFX_SIENA_FILTER_RX_MAC_WILD:
991 EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index,
995 case EFX_SIENA_FILTER_TX_TCP_FULL:
996 case EFX_SIENA_FILTER_TX_TCP_WILD:
997 case EFX_SIENA_FILTER_TX_UDP_FULL:
998 case EFX_SIENA_FILTER_TX_UDP_WILD:
999 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index,
1003 case EFX_SIENA_FILTER_TX_MAC_FULL:
1004 case EFX_SIENA_FILTER_TX_MAC_WILD:
1005 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index,
1010 EFSYS_ASSERT(B_FALSE);
1021 static __checkReturn boolean_t
1023 __in const siena_filter_spec_t *left,
1024 __in const siena_filter_spec_t *right)
1026 siena_filter_tbl_id_t tbl_id;
1028 tbl_id = siena_filter_tbl_id(left->sfs_type);
1031 if (left->sfs_type != right->sfs_type)
1034 if (memcmp(left->sfs_dword, right->sfs_dword,
1035 sizeof (left->sfs_dword)))
1038 if ((tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1039 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) &&
1040 left->sfs_dmaq_id != right->sfs_dmaq_id)
1046 static __checkReturn efx_rc_t
1047 siena_filter_search(
1048 __in siena_filter_tbl_t *sftp,
1049 __in siena_filter_spec_t *spec,
1051 __in boolean_t for_insert,
1052 __out int *filter_index,
1053 __out unsigned int *depth_required)
1055 unsigned int hash, incr, filter_idx, depth;
1057 hash = siena_filter_tbl_hash(key);
1058 incr = siena_filter_tbl_increment(key);
1060 filter_idx = hash & (sftp->sft_size - 1);
1065 * Return success if entry is used and matches this spec
1066 * or entry is unused and we are trying to insert.
1068 if (siena_filter_test_used(sftp, filter_idx) ?
1069 siena_filter_equal(spec,
1070 &sftp->sft_spec[filter_idx]) :
1072 *filter_index = filter_idx;
1073 *depth_required = depth;
1077 /* Return failure if we reached the maximum search depth */
1078 if (depth == FILTER_CTL_SRCH_MAX)
1079 return (for_insert ? EBUSY : ENOENT);
1081 filter_idx = (filter_idx + incr) & (sftp->sft_size - 1);
1087 siena_filter_clear_entry(
1088 __in efx_nic_t *enp,
1089 __in siena_filter_tbl_t *sftp,
1094 if (siena_filter_test_used(sftp, index)) {
1095 siena_filter_clear_used(sftp, index);
1097 EFX_ZERO_OWORD(filter);
1098 siena_filter_push_entry(enp,
1099 sftp->sft_spec[index].sfs_type,
1102 memset(&sftp->sft_spec[index],
1103 0, sizeof (sftp->sft_spec[0]));
1108 siena_filter_tbl_clear(
1109 __in efx_nic_t *enp,
1110 __in siena_filter_tbl_id_t tbl_id)
1112 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1113 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1115 efsys_lock_state_t state;
1117 EFSYS_LOCK(enp->en_eslp, state);
1119 for (index = 0; index < sftp->sft_size; ++index) {
1120 siena_filter_clear_entry(enp, sftp, index);
1123 if (sftp->sft_used == 0)
1124 siena_filter_reset_search_depth(sfp, tbl_id);
1126 EFSYS_UNLOCK(enp->en_eslp, state);
1129 static __checkReturn efx_rc_t
1131 __in efx_nic_t *enp)
1133 siena_filter_t *sfp;
1134 siena_filter_tbl_t *sftp;
1138 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (siena_filter_t), sfp);
1145 enp->en_filter.ef_siena_filter = sfp;
1147 switch (enp->en_family) {
1148 case EFX_FAMILY_SIENA:
1149 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_IP];
1150 sftp->sft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
1152 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC];
1153 sftp->sft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
1155 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP];
1156 sftp->sft_size = FR_CZ_TX_FILTER_TBL0_ROWS;
1158 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC];
1159 sftp->sft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
1167 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1168 unsigned int bitmap_size;
1170 sftp = &sfp->sf_tbl[tbl_id];
1171 if (sftp->sft_size == 0)
1174 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1177 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1179 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, sftp->sft_bitmap);
1180 if (!sftp->sft_bitmap) {
1185 EFSYS_KMEM_ALLOC(enp->en_esip,
1186 sftp->sft_size * sizeof (*sftp->sft_spec),
1188 if (!sftp->sft_spec) {
1192 memset(sftp->sft_spec, 0,
1193 sftp->sft_size * sizeof (*sftp->sft_spec));
1206 siena_filter_fini(enp);
1209 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1215 __in efx_nic_t *enp)
1217 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1218 siena_filter_tbl_id_t tbl_id;
1220 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1221 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1226 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1227 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1228 unsigned int bitmap_size;
1230 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1233 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1235 if (sftp->sft_bitmap != NULL) {
1236 EFSYS_KMEM_FREE(enp->en_esip, bitmap_size,
1238 sftp->sft_bitmap = NULL;
1241 if (sftp->sft_spec != NULL) {
1242 EFSYS_KMEM_FREE(enp->en_esip, sftp->sft_size *
1243 sizeof (*sftp->sft_spec), sftp->sft_spec);
1244 sftp->sft_spec = NULL;
1248 EFSYS_KMEM_FREE(enp->en_esip, sizeof (siena_filter_t),
1249 enp->en_filter.ef_siena_filter);
1252 /* Restore filter state after a reset */
1253 static __checkReturn efx_rc_t
1254 siena_filter_restore(
1255 __in efx_nic_t *enp)
1257 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1258 siena_filter_tbl_id_t tbl_id;
1259 siena_filter_tbl_t *sftp;
1260 siena_filter_spec_t *spec;
1263 efsys_lock_state_t state;
1267 EFSYS_LOCK(enp->en_eslp, state);
1269 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1270 sftp = &sfp->sf_tbl[tbl_id];
1271 for (filter_idx = 0;
1272 filter_idx < sftp->sft_size;
1274 if (!siena_filter_test_used(sftp, filter_idx))
1277 spec = &sftp->sft_spec[filter_idx];
1278 if ((key = siena_filter_build(&filter, spec)) == 0) {
1282 if ((rc = siena_filter_push_entry(enp,
1283 spec->sfs_type, filter_idx, &filter)) != 0)
1288 siena_filter_push_rx_limits(enp);
1289 siena_filter_push_tx_limits(enp);
1291 EFSYS_UNLOCK(enp->en_eslp, state);
1299 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1301 EFSYS_UNLOCK(enp->en_eslp, state);
1306 static __checkReturn efx_rc_t
1308 __in efx_nic_t *enp,
1309 __inout efx_filter_spec_t *spec,
1310 __in boolean_t may_replace)
1313 siena_filter_spec_t sf_spec;
1314 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1315 siena_filter_tbl_id_t tbl_id;
1316 siena_filter_tbl_t *sftp;
1317 siena_filter_spec_t *saved_sf_spec;
1321 efsys_lock_state_t state;
1325 EFSYS_ASSERT3P(spec, !=, NULL);
1327 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1330 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1331 sftp = &sfp->sf_tbl[tbl_id];
1333 if (sftp->sft_size == 0) {
1338 key = siena_filter_build(&filter, &sf_spec);
1340 EFSYS_LOCK(enp->en_eslp, state);
1342 rc = siena_filter_search(sftp, &sf_spec, key, B_TRUE,
1343 &filter_idx, &depth);
1347 EFSYS_ASSERT3U(filter_idx, <, sftp->sft_size);
1348 saved_sf_spec = &sftp->sft_spec[filter_idx];
1350 if (siena_filter_test_used(sftp, filter_idx)) {
1351 if (may_replace == B_FALSE) {
1356 siena_filter_set_used(sftp, filter_idx);
1357 *saved_sf_spec = sf_spec;
1359 if (sfp->sf_depth[sf_spec.sfs_type] < depth) {
1360 sfp->sf_depth[sf_spec.sfs_type] = depth;
1361 if (tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1362 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC)
1363 siena_filter_push_tx_limits(enp);
1365 siena_filter_push_rx_limits(enp);
1368 siena_filter_push_entry(enp, sf_spec.sfs_type,
1369 filter_idx, &filter);
1371 EFSYS_UNLOCK(enp->en_eslp, state);
1378 EFSYS_UNLOCK(enp->en_eslp, state);
1385 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1389 static __checkReturn efx_rc_t
1390 siena_filter_delete(
1391 __in efx_nic_t *enp,
1392 __inout efx_filter_spec_t *spec)
1395 siena_filter_spec_t sf_spec;
1396 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1397 siena_filter_tbl_id_t tbl_id;
1398 siena_filter_tbl_t *sftp;
1402 efsys_lock_state_t state;
1405 EFSYS_ASSERT3P(spec, !=, NULL);
1407 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1410 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1411 sftp = &sfp->sf_tbl[tbl_id];
1413 key = siena_filter_build(&filter, &sf_spec);
1415 EFSYS_LOCK(enp->en_eslp, state);
1417 rc = siena_filter_search(sftp, &sf_spec, key, B_FALSE,
1418 &filter_idx, &depth);
1422 siena_filter_clear_entry(enp, sftp, filter_idx);
1423 if (sftp->sft_used == 0)
1424 siena_filter_reset_search_depth(sfp, tbl_id);
1426 EFSYS_UNLOCK(enp->en_eslp, state);
1430 EFSYS_UNLOCK(enp->en_eslp, state);
1434 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1438 #define SIENA_MAX_SUPPORTED_MATCHES 4
1440 static __checkReturn efx_rc_t
1441 siena_filter_supported_filters(
1442 __in efx_nic_t *enp,
1443 __out_ecount(buffer_length) uint32_t *buffer,
1444 __in size_t buffer_length,
1445 __out size_t *list_lengthp)
1448 uint32_t rx_matches[SIENA_MAX_SUPPORTED_MATCHES];
1452 rx_matches[index++] =
1453 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1454 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
1455 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
1457 rx_matches[index++] =
1458 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1459 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
1461 if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) {
1462 rx_matches[index++] =
1463 EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC;
1465 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC;
1468 EFSYS_ASSERT3U(index, <=, SIENA_MAX_SUPPORTED_MATCHES);
1469 list_length = index;
1471 *list_lengthp = list_length;
1473 if (buffer_length < list_length) {
1478 memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0]));
1483 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1488 #undef MAX_SUPPORTED
1490 #endif /* EFSYS_OPT_SIENA */
1492 #endif /* EFSYS_OPT_FILTER */