2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2007-2016 Solarflare Communications Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * The views and conclusions contained in the software and documentation are
29 * those of the authors and should not be interpreted as representing official
30 * policies, either expressed or implied, of the FreeBSD Project.
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
44 static __checkReturn efx_rc_t
52 static __checkReturn efx_rc_t
56 static __checkReturn efx_rc_t
59 __inout efx_filter_spec_t *spec,
60 __in boolean_t may_replace);
62 static __checkReturn efx_rc_t
65 __inout efx_filter_spec_t *spec);
67 static __checkReturn efx_rc_t
68 siena_filter_supported_filters(
70 __out_ecount(buffer_length) uint32_t *buffer,
71 __in size_t buffer_length,
72 __out size_t *list_lengthp);
74 #endif /* EFSYS_OPT_SIENA */
77 static const efx_filter_ops_t __efx_filter_siena_ops = {
78 siena_filter_init, /* efo_init */
79 siena_filter_fini, /* efo_fini */
80 siena_filter_restore, /* efo_restore */
81 siena_filter_add, /* efo_add */
82 siena_filter_delete, /* efo_delete */
83 siena_filter_supported_filters, /* efo_supported_filters */
84 NULL, /* efo_reconfigure */
86 #endif /* EFSYS_OPT_SIENA */
88 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
89 static const efx_filter_ops_t __efx_filter_ef10_ops = {
90 ef10_filter_init, /* efo_init */
91 ef10_filter_fini, /* efo_fini */
92 ef10_filter_restore, /* efo_restore */
93 ef10_filter_add, /* efo_add */
94 ef10_filter_delete, /* efo_delete */
95 ef10_filter_supported_filters, /* efo_supported_filters */
96 ef10_filter_reconfigure, /* efo_reconfigure */
98 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
100 __checkReturn efx_rc_t
103 __inout efx_filter_spec_t *spec)
105 const efx_filter_ops_t *efop = enp->en_efop;
106 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
109 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
110 EFSYS_ASSERT3P(spec, !=, NULL);
111 EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
113 if ((spec->efs_flags & EFX_FILTER_FLAG_ACTION_MARK) &&
114 !encp->enc_filter_action_mark_supported) {
119 if ((spec->efs_flags & EFX_FILTER_FLAG_ACTION_FLAG) &&
120 !encp->enc_filter_action_flag_supported) {
125 return (efop->efo_add(enp, spec, B_FALSE));
130 EFSYS_PROBE1(fail1, efx_rc_t, rc);
135 __checkReturn efx_rc_t
138 __inout efx_filter_spec_t *spec)
140 const efx_filter_ops_t *efop = enp->en_efop;
142 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
143 EFSYS_ASSERT3P(spec, !=, NULL);
144 EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
146 return (efop->efo_delete(enp, spec));
149 __checkReturn efx_rc_t
155 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
157 if ((rc = enp->en_efop->efo_restore(enp)) != 0)
163 EFSYS_PROBE1(fail1, efx_rc_t, rc);
168 __checkReturn efx_rc_t
172 const efx_filter_ops_t *efop;
175 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
176 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
177 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER));
179 switch (enp->en_family) {
181 case EFX_FAMILY_SIENA:
182 efop = &__efx_filter_siena_ops;
184 #endif /* EFSYS_OPT_SIENA */
186 #if EFSYS_OPT_HUNTINGTON
187 case EFX_FAMILY_HUNTINGTON:
188 efop = &__efx_filter_ef10_ops;
190 #endif /* EFSYS_OPT_HUNTINGTON */
192 #if EFSYS_OPT_MEDFORD
193 case EFX_FAMILY_MEDFORD:
194 efop = &__efx_filter_ef10_ops;
196 #endif /* EFSYS_OPT_MEDFORD */
198 #if EFSYS_OPT_MEDFORD2
199 case EFX_FAMILY_MEDFORD2:
200 efop = &__efx_filter_ef10_ops;
202 #endif /* EFSYS_OPT_MEDFORD2 */
210 if ((rc = efop->efo_init(enp)) != 0)
214 enp->en_mod_flags |= EFX_MOD_FILTER;
220 EFSYS_PROBE1(fail1, efx_rc_t, rc);
223 enp->en_mod_flags &= ~EFX_MOD_FILTER;
231 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
232 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
233 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
235 enp->en_efop->efo_fini(enp);
238 enp->en_mod_flags &= ~EFX_MOD_FILTER;
242 * Query the possible combinations of match flags which can be filtered on.
243 * These are returned as a list, of which each 32 bit element is a bitmask
244 * formed of EFX_FILTER_MATCH flags.
246 * The combinations are ordered in priority from highest to lowest.
248 * If the provided buffer is too short to hold the list, the call with fail with
249 * ENOSPC and *list_lengthp will be set to the buffer length required.
251 __checkReturn efx_rc_t
252 efx_filter_supported_filters(
254 __out_ecount(buffer_length) uint32_t *buffer,
255 __in size_t buffer_length,
256 __out size_t *list_lengthp)
260 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
261 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
262 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
263 EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL);
265 if (buffer == NULL) {
270 rc = enp->en_efop->efo_supported_filters(enp, buffer, buffer_length,
280 EFSYS_PROBE1(fail1, efx_rc_t, rc);
285 __checkReturn efx_rc_t
286 efx_filter_reconfigure(
288 __in_ecount(6) uint8_t const *mac_addr,
289 __in boolean_t all_unicst,
290 __in boolean_t mulcst,
291 __in boolean_t all_mulcst,
292 __in boolean_t brdcst,
293 __in_ecount(6*count) uint8_t const *addrs,
298 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
299 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
300 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
302 if (enp->en_efop->efo_reconfigure != NULL) {
303 if ((rc = enp->en_efop->efo_reconfigure(enp, mac_addr,
313 EFSYS_PROBE1(fail1, efx_rc_t, rc);
319 efx_filter_spec_init_rx(
320 __out efx_filter_spec_t *spec,
321 __in efx_filter_priority_t priority,
322 __in efx_filter_flags_t flags,
325 EFSYS_ASSERT3P(spec, !=, NULL);
326 EFSYS_ASSERT3P(erp, !=, NULL);
327 EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
328 EFX_FILTER_FLAG_RX_SCATTER)) == 0);
330 memset(spec, 0, sizeof (*spec));
331 spec->efs_priority = priority;
332 spec->efs_flags = EFX_FILTER_FLAG_RX | flags;
333 spec->efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
334 spec->efs_dmaq_id = (uint16_t)erp->er_index;
338 efx_filter_spec_init_tx(
339 __out efx_filter_spec_t *spec,
342 EFSYS_ASSERT3P(spec, !=, NULL);
343 EFSYS_ASSERT3P(etp, !=, NULL);
345 memset(spec, 0, sizeof (*spec));
346 spec->efs_priority = EFX_FILTER_PRI_REQUIRED;
347 spec->efs_flags = EFX_FILTER_FLAG_TX;
348 spec->efs_dmaq_id = (uint16_t)etp->et_index;
353 * Specify IPv4 host, transport protocol and port in a filter specification
355 __checkReturn efx_rc_t
356 efx_filter_spec_set_ipv4_local(
357 __inout efx_filter_spec_t *spec,
362 EFSYS_ASSERT3P(spec, !=, NULL);
364 spec->efs_match_flags |=
365 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
366 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
367 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
368 spec->efs_ip_proto = proto;
369 spec->efs_loc_host.eo_u32[0] = host;
370 spec->efs_loc_port = port;
375 * Specify IPv4 hosts, transport protocol and ports in a filter specification
377 __checkReturn efx_rc_t
378 efx_filter_spec_set_ipv4_full(
379 __inout efx_filter_spec_t *spec,
386 EFSYS_ASSERT3P(spec, !=, NULL);
388 spec->efs_match_flags |=
389 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
390 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
391 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
392 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
393 spec->efs_ip_proto = proto;
394 spec->efs_loc_host.eo_u32[0] = lhost;
395 spec->efs_loc_port = lport;
396 spec->efs_rem_host.eo_u32[0] = rhost;
397 spec->efs_rem_port = rport;
402 * Specify local Ethernet address and/or VID in filter specification
404 __checkReturn efx_rc_t
405 efx_filter_spec_set_eth_local(
406 __inout efx_filter_spec_t *spec,
408 __in const uint8_t *addr)
410 EFSYS_ASSERT3P(spec, !=, NULL);
411 EFSYS_ASSERT3P(addr, !=, NULL);
413 if (vid == EFX_FILTER_SPEC_VID_UNSPEC && addr == NULL)
416 if (vid != EFX_FILTER_SPEC_VID_UNSPEC) {
417 spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID;
418 spec->efs_outer_vid = vid;
421 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
422 memcpy(spec->efs_loc_mac, addr, EFX_MAC_ADDR_LEN);
428 efx_filter_spec_set_ether_type(
429 __inout efx_filter_spec_t *spec,
430 __in uint16_t ether_type)
432 EFSYS_ASSERT3P(spec, !=, NULL);
434 spec->efs_ether_type = ether_type;
435 spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
439 * Specify matching otherwise-unmatched unicast in a filter specification
441 __checkReturn efx_rc_t
442 efx_filter_spec_set_uc_def(
443 __inout efx_filter_spec_t *spec)
445 EFSYS_ASSERT3P(spec, !=, NULL);
447 spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_UCAST_DST;
452 * Specify matching otherwise-unmatched multicast in a filter specification
454 __checkReturn efx_rc_t
455 efx_filter_spec_set_mc_def(
456 __inout efx_filter_spec_t *spec)
458 EFSYS_ASSERT3P(spec, !=, NULL);
460 spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
465 __checkReturn efx_rc_t
466 efx_filter_spec_set_encap_type(
467 __inout efx_filter_spec_t *spec,
468 __in efx_tunnel_protocol_t encap_type,
469 __in efx_filter_inner_frame_match_t inner_frame_match)
471 uint32_t match_flags = EFX_FILTER_MATCH_ENCAP_TYPE;
475 EFSYS_ASSERT3P(spec, !=, NULL);
477 switch (encap_type) {
478 case EFX_TUNNEL_PROTOCOL_VXLAN:
479 case EFX_TUNNEL_PROTOCOL_GENEVE:
480 ip_proto = EFX_IPPROTO_UDP;
482 case EFX_TUNNEL_PROTOCOL_NVGRE:
483 ip_proto = EFX_IPPROTO_GRE;
491 switch (inner_frame_match) {
492 case EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_MCAST_DST:
493 match_flags |= EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST;
495 case EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_UCAST_DST:
496 match_flags |= EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST;
498 case EFX_FILTER_INNER_FRAME_MATCH_OTHER:
499 /* This is for when specific inner frames are to be matched. */
507 spec->efs_encap_type = encap_type;
508 spec->efs_ip_proto = ip_proto;
509 spec->efs_match_flags |= (match_flags | EFX_FILTER_MATCH_IP_PROTO);
516 EFSYS_PROBE1(fail1, efx_rc_t, rc);
522 * Specify inner and outer Ethernet address and VNI or VSID in tunnel filter
525 static __checkReturn efx_rc_t
526 efx_filter_spec_set_tunnel(
527 __inout efx_filter_spec_t *spec,
528 __in efx_tunnel_protocol_t encap_type,
529 __in const uint8_t *vni_or_vsid,
530 __in const uint8_t *inner_addr,
531 __in const uint8_t *outer_addr)
535 EFSYS_ASSERT3P(spec, !=, NULL);
536 EFSYS_ASSERT3P(vni_or_vsid, !=, NULL);
537 EFSYS_ASSERT3P(inner_addr, !=, NULL);
538 EFSYS_ASSERT3P(outer_addr, !=, NULL);
540 switch (encap_type) {
541 case EFX_TUNNEL_PROTOCOL_VXLAN:
542 case EFX_TUNNEL_PROTOCOL_GENEVE:
543 case EFX_TUNNEL_PROTOCOL_NVGRE:
550 if ((inner_addr == NULL) && (outer_addr == NULL)) {
555 if (vni_or_vsid != NULL) {
556 spec->efs_match_flags |= EFX_FILTER_MATCH_VNI_OR_VSID;
557 memcpy(spec->efs_vni_or_vsid, vni_or_vsid, EFX_VNI_OR_VSID_LEN);
559 if (outer_addr != NULL) {
560 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
561 memcpy(spec->efs_loc_mac, outer_addr, EFX_MAC_ADDR_LEN);
563 if (inner_addr != NULL) {
564 spec->efs_match_flags |= EFX_FILTER_MATCH_IFRM_LOC_MAC;
565 memcpy(spec->efs_ifrm_loc_mac, inner_addr, EFX_MAC_ADDR_LEN);
568 spec->efs_match_flags |= EFX_FILTER_MATCH_ENCAP_TYPE;
569 spec->efs_encap_type = encap_type;
576 EFSYS_PROBE1(fail1, efx_rc_t, rc);
582 * Specify inner and outer Ethernet address and VNI in VXLAN filter
585 __checkReturn efx_rc_t
586 efx_filter_spec_set_vxlan(
587 __inout efx_filter_spec_t *spec,
588 __in const uint8_t *vni,
589 __in const uint8_t *inner_addr,
590 __in const uint8_t *outer_addr)
592 return efx_filter_spec_set_tunnel(spec, EFX_TUNNEL_PROTOCOL_VXLAN,
593 vni, inner_addr, outer_addr);
597 * Specify inner and outer Ethernet address and VNI in Geneve filter
600 __checkReturn efx_rc_t
601 efx_filter_spec_set_geneve(
602 __inout efx_filter_spec_t *spec,
603 __in const uint8_t *vni,
604 __in const uint8_t *inner_addr,
605 __in const uint8_t *outer_addr)
607 return efx_filter_spec_set_tunnel(spec, EFX_TUNNEL_PROTOCOL_GENEVE,
608 vni, inner_addr, outer_addr);
612 * Specify inner and outer Ethernet address and vsid in NVGRE filter
615 __checkReturn efx_rc_t
616 efx_filter_spec_set_nvgre(
617 __inout efx_filter_spec_t *spec,
618 __in const uint8_t *vsid,
619 __in const uint8_t *inner_addr,
620 __in const uint8_t *outer_addr)
622 return efx_filter_spec_set_tunnel(spec, EFX_TUNNEL_PROTOCOL_NVGRE,
623 vsid, inner_addr, outer_addr);
626 #if EFSYS_OPT_RX_SCALE
627 __checkReturn efx_rc_t
628 efx_filter_spec_set_rss_context(
629 __inout efx_filter_spec_t *spec,
630 __in uint32_t rss_context)
634 EFSYS_ASSERT3P(spec, !=, NULL);
636 /* The filter must have been created with EFX_FILTER_FLAG_RX_RSS. */
637 if ((spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) == 0) {
642 spec->efs_rss_context = rss_context;
647 EFSYS_PROBE1(fail1, efx_rc_t, rc);
656 * "Fudge factors" - difference between programmed value and actual depth.
657 * Due to pipelined implementation we need to program H/W with a value that
658 * is larger than the hop limit we want.
660 #define FILTER_CTL_SRCH_FUDGE_WILD 3
661 #define FILTER_CTL_SRCH_FUDGE_FULL 1
664 * Hard maximum hop limit. Hardware will time-out beyond 200-something.
665 * We also need to avoid infinite loops in efx_filter_search() when the
668 #define FILTER_CTL_SRCH_MAX 200
670 static __checkReturn efx_rc_t
671 siena_filter_spec_from_gen_spec(
672 __out siena_filter_spec_t *sf_spec,
673 __in efx_filter_spec_t *gen_spec)
676 boolean_t is_full = B_FALSE;
678 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX)
679 EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX);
681 EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX);
683 /* Siena only has one RSS context */
684 if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
685 gen_spec->efs_rss_context != EFX_RSS_CONTEXT_DEFAULT) {
690 sf_spec->sfs_flags = gen_spec->efs_flags;
691 sf_spec->sfs_dmaq_id = gen_spec->efs_dmaq_id;
693 switch (gen_spec->efs_match_flags) {
694 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
695 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
696 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT:
699 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
700 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: {
701 uint32_t rhost, host1, host2;
702 uint16_t rport, port1, port2;
704 if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) {
708 if (gen_spec->efs_loc_port == 0 ||
709 (is_full && gen_spec->efs_rem_port == 0)) {
713 switch (gen_spec->efs_ip_proto) {
714 case EFX_IPPROTO_TCP:
715 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
716 sf_spec->sfs_type = (is_full ?
717 EFX_SIENA_FILTER_TX_TCP_FULL :
718 EFX_SIENA_FILTER_TX_TCP_WILD);
720 sf_spec->sfs_type = (is_full ?
721 EFX_SIENA_FILTER_RX_TCP_FULL :
722 EFX_SIENA_FILTER_RX_TCP_WILD);
725 case EFX_IPPROTO_UDP:
726 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
727 sf_spec->sfs_type = (is_full ?
728 EFX_SIENA_FILTER_TX_UDP_FULL :
729 EFX_SIENA_FILTER_TX_UDP_WILD);
731 sf_spec->sfs_type = (is_full ?
732 EFX_SIENA_FILTER_RX_UDP_FULL :
733 EFX_SIENA_FILTER_RX_UDP_WILD);
741 * The filter is constructed in terms of source and destination,
742 * with the odd wrinkle that the ports are swapped in a UDP
743 * wildcard filter. We need to convert from local and remote
744 * addresses (zero for a wildcard).
746 rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0;
747 rport = is_full ? gen_spec->efs_rem_port : 0;
748 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
749 host1 = gen_spec->efs_loc_host.eo_u32[0];
753 host2 = gen_spec->efs_loc_host.eo_u32[0];
755 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
756 if (sf_spec->sfs_type ==
757 EFX_SIENA_FILTER_TX_UDP_WILD) {
759 port2 = gen_spec->efs_loc_port;
761 port1 = gen_spec->efs_loc_port;
765 if (sf_spec->sfs_type ==
766 EFX_SIENA_FILTER_RX_UDP_WILD) {
767 port1 = gen_spec->efs_loc_port;
771 port2 = gen_spec->efs_loc_port;
774 sf_spec->sfs_dword[0] = (host1 << 16) | port1;
775 sf_spec->sfs_dword[1] = (port2 << 16) | (host1 >> 16);
776 sf_spec->sfs_dword[2] = host2;
780 case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID:
783 case EFX_FILTER_MATCH_LOC_MAC:
784 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
785 sf_spec->sfs_type = (is_full ?
786 EFX_SIENA_FILTER_TX_MAC_FULL :
787 EFX_SIENA_FILTER_TX_MAC_WILD);
789 sf_spec->sfs_type = (is_full ?
790 EFX_SIENA_FILTER_RX_MAC_FULL :
791 EFX_SIENA_FILTER_RX_MAC_WILD);
793 sf_spec->sfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0;
794 sf_spec->sfs_dword[1] =
795 gen_spec->efs_loc_mac[2] << 24 |
796 gen_spec->efs_loc_mac[3] << 16 |
797 gen_spec->efs_loc_mac[4] << 8 |
798 gen_spec->efs_loc_mac[5];
799 sf_spec->sfs_dword[2] =
800 gen_spec->efs_loc_mac[0] << 8 |
801 gen_spec->efs_loc_mac[1];
805 EFSYS_ASSERT(B_FALSE);
821 EFSYS_PROBE1(fail1, efx_rc_t, rc);
827 * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
828 * key derived from the n-tuple.
831 siena_filter_tbl_hash(
836 /* First 16 rounds */
837 tmp = 0x1fff ^ (uint16_t)(key >> 16);
838 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
839 tmp = tmp ^ tmp >> 9;
842 tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff);
843 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
844 tmp = tmp ^ tmp >> 9;
850 * To allow for hash collisions, filter search continues at these
851 * increments from the first possible entry selected by the hash.
854 siena_filter_tbl_increment(
857 return ((uint16_t)(key * 2 - 1));
860 static __checkReturn boolean_t
861 siena_filter_test_used(
862 __in siena_filter_tbl_t *sftp,
863 __in unsigned int index)
865 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
866 return ((sftp->sft_bitmap[index / 32] & (1 << (index % 32))) != 0);
870 siena_filter_set_used(
871 __in siena_filter_tbl_t *sftp,
872 __in unsigned int index)
874 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
875 sftp->sft_bitmap[index / 32] |= (1 << (index % 32));
880 siena_filter_clear_used(
881 __in siena_filter_tbl_t *sftp,
882 __in unsigned int index)
884 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
885 sftp->sft_bitmap[index / 32] &= ~(1 << (index % 32));
888 EFSYS_ASSERT3U(sftp->sft_used, >=, 0);
892 static siena_filter_tbl_id_t
894 __in siena_filter_type_t type)
896 siena_filter_tbl_id_t tbl_id;
899 case EFX_SIENA_FILTER_RX_TCP_FULL:
900 case EFX_SIENA_FILTER_RX_TCP_WILD:
901 case EFX_SIENA_FILTER_RX_UDP_FULL:
902 case EFX_SIENA_FILTER_RX_UDP_WILD:
903 tbl_id = EFX_SIENA_FILTER_TBL_RX_IP;
906 case EFX_SIENA_FILTER_RX_MAC_FULL:
907 case EFX_SIENA_FILTER_RX_MAC_WILD:
908 tbl_id = EFX_SIENA_FILTER_TBL_RX_MAC;
911 case EFX_SIENA_FILTER_TX_TCP_FULL:
912 case EFX_SIENA_FILTER_TX_TCP_WILD:
913 case EFX_SIENA_FILTER_TX_UDP_FULL:
914 case EFX_SIENA_FILTER_TX_UDP_WILD:
915 tbl_id = EFX_SIENA_FILTER_TBL_TX_IP;
918 case EFX_SIENA_FILTER_TX_MAC_FULL:
919 case EFX_SIENA_FILTER_TX_MAC_WILD:
920 tbl_id = EFX_SIENA_FILTER_TBL_TX_MAC;
924 EFSYS_ASSERT(B_FALSE);
925 tbl_id = EFX_SIENA_FILTER_NTBLS;
932 siena_filter_reset_search_depth(
933 __inout siena_filter_t *sfp,
934 __in siena_filter_tbl_id_t tbl_id)
937 case EFX_SIENA_FILTER_TBL_RX_IP:
938 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] = 0;
939 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] = 0;
940 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] = 0;
941 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] = 0;
944 case EFX_SIENA_FILTER_TBL_RX_MAC:
945 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] = 0;
946 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] = 0;
949 case EFX_SIENA_FILTER_TBL_TX_IP:
950 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] = 0;
951 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] = 0;
952 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] = 0;
953 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] = 0;
956 case EFX_SIENA_FILTER_TBL_TX_MAC:
957 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] = 0;
958 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] = 0;
962 EFSYS_ASSERT(B_FALSE);
968 siena_filter_push_rx_limits(
971 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
974 EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
976 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT,
977 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] +
978 FILTER_CTL_SRCH_FUDGE_FULL);
979 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT,
980 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] +
981 FILTER_CTL_SRCH_FUDGE_WILD);
982 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT,
983 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] +
984 FILTER_CTL_SRCH_FUDGE_FULL);
985 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT,
986 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] +
987 FILTER_CTL_SRCH_FUDGE_WILD);
989 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC].sft_size) {
990 EFX_SET_OWORD_FIELD(oword,
991 FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
992 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] +
993 FILTER_CTL_SRCH_FUDGE_FULL);
994 EFX_SET_OWORD_FIELD(oword,
995 FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
996 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] +
997 FILTER_CTL_SRCH_FUDGE_WILD);
1000 EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
1004 siena_filter_push_tx_limits(
1005 __in efx_nic_t *enp)
1007 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1010 EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
1012 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP].sft_size != 0) {
1013 EFX_SET_OWORD_FIELD(oword,
1014 FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE,
1015 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] +
1016 FILTER_CTL_SRCH_FUDGE_FULL);
1017 EFX_SET_OWORD_FIELD(oword,
1018 FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE,
1019 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] +
1020 FILTER_CTL_SRCH_FUDGE_WILD);
1021 EFX_SET_OWORD_FIELD(oword,
1022 FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE,
1023 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] +
1024 FILTER_CTL_SRCH_FUDGE_FULL);
1025 EFX_SET_OWORD_FIELD(oword,
1026 FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE,
1027 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] +
1028 FILTER_CTL_SRCH_FUDGE_WILD);
1031 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC].sft_size != 0) {
1032 EFX_SET_OWORD_FIELD(
1033 oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
1034 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] +
1035 FILTER_CTL_SRCH_FUDGE_FULL);
1036 EFX_SET_OWORD_FIELD(
1037 oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
1038 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] +
1039 FILTER_CTL_SRCH_FUDGE_WILD);
1042 EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
1045 /* Build a filter entry and return its n-tuple key. */
1046 static __checkReturn uint32_t
1048 __out efx_oword_t *filter,
1049 __in siena_filter_spec_t *spec)
1053 uint8_t type = spec->sfs_type;
1054 uint32_t flags = spec->sfs_flags;
1056 switch (siena_filter_tbl_id(type)) {
1057 case EFX_SIENA_FILTER_TBL_RX_IP: {
1058 boolean_t is_udp = (type == EFX_SIENA_FILTER_RX_UDP_FULL ||
1059 type == EFX_SIENA_FILTER_RX_UDP_WILD);
1060 EFX_POPULATE_OWORD_7(*filter,
1062 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
1064 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
1065 FRF_AZ_TCP_UDP, is_udp,
1066 FRF_AZ_RXQ_ID, spec->sfs_dmaq_id,
1067 EFX_DWORD_2, spec->sfs_dword[2],
1068 EFX_DWORD_1, spec->sfs_dword[1],
1069 EFX_DWORD_0, spec->sfs_dword[0]);
1074 case EFX_SIENA_FILTER_TBL_RX_MAC: {
1075 boolean_t is_wild = (type == EFX_SIENA_FILTER_RX_MAC_WILD);
1076 EFX_POPULATE_OWORD_7(*filter,
1078 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
1079 FRF_CZ_RMFT_SCATTER_EN,
1080 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
1081 FRF_CZ_RMFT_RXQ_ID, spec->sfs_dmaq_id,
1082 FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
1083 FRF_CZ_RMFT_DEST_MAC_DW1, spec->sfs_dword[2],
1084 FRF_CZ_RMFT_DEST_MAC_DW0, spec->sfs_dword[1],
1085 FRF_CZ_RMFT_VLAN_ID, spec->sfs_dword[0]);
1090 case EFX_SIENA_FILTER_TBL_TX_IP: {
1091 boolean_t is_udp = (type == EFX_SIENA_FILTER_TX_UDP_FULL ||
1092 type == EFX_SIENA_FILTER_TX_UDP_WILD);
1093 EFX_POPULATE_OWORD_5(*filter,
1094 FRF_CZ_TIFT_TCP_UDP, is_udp,
1095 FRF_CZ_TIFT_TXQ_ID, spec->sfs_dmaq_id,
1096 EFX_DWORD_2, spec->sfs_dword[2],
1097 EFX_DWORD_1, spec->sfs_dword[1],
1098 EFX_DWORD_0, spec->sfs_dword[0]);
1099 dword3 = is_udp | spec->sfs_dmaq_id << 1;
1103 case EFX_SIENA_FILTER_TBL_TX_MAC: {
1104 boolean_t is_wild = (type == EFX_SIENA_FILTER_TX_MAC_WILD);
1105 EFX_POPULATE_OWORD_5(*filter,
1106 FRF_CZ_TMFT_TXQ_ID, spec->sfs_dmaq_id,
1107 FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
1108 FRF_CZ_TMFT_SRC_MAC_DW1, spec->sfs_dword[2],
1109 FRF_CZ_TMFT_SRC_MAC_DW0, spec->sfs_dword[1],
1110 FRF_CZ_TMFT_VLAN_ID, spec->sfs_dword[0]);
1111 dword3 = is_wild | spec->sfs_dmaq_id << 1;
1116 EFSYS_ASSERT(B_FALSE);
1117 EFX_ZERO_OWORD(*filter);
1122 spec->sfs_dword[0] ^
1123 spec->sfs_dword[1] ^
1124 spec->sfs_dword[2] ^
1130 static __checkReturn efx_rc_t
1131 siena_filter_push_entry(
1132 __inout efx_nic_t *enp,
1133 __in siena_filter_type_t type,
1135 __in efx_oword_t *eop)
1140 case EFX_SIENA_FILTER_RX_TCP_FULL:
1141 case EFX_SIENA_FILTER_RX_TCP_WILD:
1142 case EFX_SIENA_FILTER_RX_UDP_FULL:
1143 case EFX_SIENA_FILTER_RX_UDP_WILD:
1144 EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index,
1148 case EFX_SIENA_FILTER_RX_MAC_FULL:
1149 case EFX_SIENA_FILTER_RX_MAC_WILD:
1150 EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index,
1154 case EFX_SIENA_FILTER_TX_TCP_FULL:
1155 case EFX_SIENA_FILTER_TX_TCP_WILD:
1156 case EFX_SIENA_FILTER_TX_UDP_FULL:
1157 case EFX_SIENA_FILTER_TX_UDP_WILD:
1158 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index,
1162 case EFX_SIENA_FILTER_TX_MAC_FULL:
1163 case EFX_SIENA_FILTER_TX_MAC_WILD:
1164 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index,
1169 EFSYS_ASSERT(B_FALSE);
1180 static __checkReturn boolean_t
1182 __in const siena_filter_spec_t *left,
1183 __in const siena_filter_spec_t *right)
1185 siena_filter_tbl_id_t tbl_id;
1187 tbl_id = siena_filter_tbl_id(left->sfs_type);
1190 if (left->sfs_type != right->sfs_type)
1193 if (memcmp(left->sfs_dword, right->sfs_dword,
1194 sizeof (left->sfs_dword)))
1197 if ((tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1198 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) &&
1199 left->sfs_dmaq_id != right->sfs_dmaq_id)
1205 static __checkReturn efx_rc_t
1206 siena_filter_search(
1207 __in siena_filter_tbl_t *sftp,
1208 __in siena_filter_spec_t *spec,
1210 __in boolean_t for_insert,
1211 __out int *filter_index,
1212 __out unsigned int *depth_required)
1214 unsigned int hash, incr, filter_idx, depth;
1216 hash = siena_filter_tbl_hash(key);
1217 incr = siena_filter_tbl_increment(key);
1219 filter_idx = hash & (sftp->sft_size - 1);
1224 * Return success if entry is used and matches this spec
1225 * or entry is unused and we are trying to insert.
1227 if (siena_filter_test_used(sftp, filter_idx) ?
1228 siena_filter_equal(spec,
1229 &sftp->sft_spec[filter_idx]) :
1231 *filter_index = filter_idx;
1232 *depth_required = depth;
1236 /* Return failure if we reached the maximum search depth */
1237 if (depth == FILTER_CTL_SRCH_MAX)
1238 return (for_insert ? EBUSY : ENOENT);
1240 filter_idx = (filter_idx + incr) & (sftp->sft_size - 1);
1246 siena_filter_clear_entry(
1247 __in efx_nic_t *enp,
1248 __in siena_filter_tbl_t *sftp,
1253 if (siena_filter_test_used(sftp, index)) {
1254 siena_filter_clear_used(sftp, index);
1256 EFX_ZERO_OWORD(filter);
1257 siena_filter_push_entry(enp,
1258 sftp->sft_spec[index].sfs_type,
1261 memset(&sftp->sft_spec[index],
1262 0, sizeof (sftp->sft_spec[0]));
1267 siena_filter_tbl_clear(
1268 __in efx_nic_t *enp,
1269 __in siena_filter_tbl_id_t tbl_id)
1271 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1272 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1274 efsys_lock_state_t state;
1276 EFSYS_LOCK(enp->en_eslp, state);
1278 for (index = 0; index < sftp->sft_size; ++index) {
1279 siena_filter_clear_entry(enp, sftp, index);
1282 if (sftp->sft_used == 0)
1283 siena_filter_reset_search_depth(sfp, tbl_id);
1285 EFSYS_UNLOCK(enp->en_eslp, state);
1288 static __checkReturn efx_rc_t
1290 __in efx_nic_t *enp)
1292 siena_filter_t *sfp;
1293 siena_filter_tbl_t *sftp;
1297 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (siena_filter_t), sfp);
1304 enp->en_filter.ef_siena_filter = sfp;
1306 switch (enp->en_family) {
1307 case EFX_FAMILY_SIENA:
1308 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_IP];
1309 sftp->sft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
1311 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC];
1312 sftp->sft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
1314 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP];
1315 sftp->sft_size = FR_CZ_TX_FILTER_TBL0_ROWS;
1317 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC];
1318 sftp->sft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
1326 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1327 unsigned int bitmap_size;
1329 sftp = &sfp->sf_tbl[tbl_id];
1330 if (sftp->sft_size == 0)
1333 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1336 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1338 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, sftp->sft_bitmap);
1339 if (!sftp->sft_bitmap) {
1344 EFSYS_KMEM_ALLOC(enp->en_esip,
1345 sftp->sft_size * sizeof (*sftp->sft_spec),
1347 if (!sftp->sft_spec) {
1351 memset(sftp->sft_spec, 0,
1352 sftp->sft_size * sizeof (*sftp->sft_spec));
1365 siena_filter_fini(enp);
1368 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1374 __in efx_nic_t *enp)
1376 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1377 siena_filter_tbl_id_t tbl_id;
1379 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1380 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1385 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1386 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1387 unsigned int bitmap_size;
1389 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1392 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1394 if (sftp->sft_bitmap != NULL) {
1395 EFSYS_KMEM_FREE(enp->en_esip, bitmap_size,
1397 sftp->sft_bitmap = NULL;
1400 if (sftp->sft_spec != NULL) {
1401 EFSYS_KMEM_FREE(enp->en_esip, sftp->sft_size *
1402 sizeof (*sftp->sft_spec), sftp->sft_spec);
1403 sftp->sft_spec = NULL;
1407 EFSYS_KMEM_FREE(enp->en_esip, sizeof (siena_filter_t),
1408 enp->en_filter.ef_siena_filter);
1411 /* Restore filter state after a reset */
1412 static __checkReturn efx_rc_t
1413 siena_filter_restore(
1414 __in efx_nic_t *enp)
1416 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1417 siena_filter_tbl_id_t tbl_id;
1418 siena_filter_tbl_t *sftp;
1419 siena_filter_spec_t *spec;
1422 efsys_lock_state_t state;
1426 EFSYS_LOCK(enp->en_eslp, state);
1428 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1429 sftp = &sfp->sf_tbl[tbl_id];
1430 for (filter_idx = 0;
1431 filter_idx < sftp->sft_size;
1433 if (!siena_filter_test_used(sftp, filter_idx))
1436 spec = &sftp->sft_spec[filter_idx];
1437 if ((key = siena_filter_build(&filter, spec)) == 0) {
1441 if ((rc = siena_filter_push_entry(enp,
1442 spec->sfs_type, filter_idx, &filter)) != 0)
1447 siena_filter_push_rx_limits(enp);
1448 siena_filter_push_tx_limits(enp);
1450 EFSYS_UNLOCK(enp->en_eslp, state);
1458 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1460 EFSYS_UNLOCK(enp->en_eslp, state);
1465 static __checkReturn efx_rc_t
1467 __in efx_nic_t *enp,
1468 __inout efx_filter_spec_t *spec,
1469 __in boolean_t may_replace)
1472 siena_filter_spec_t sf_spec;
1473 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1474 siena_filter_tbl_id_t tbl_id;
1475 siena_filter_tbl_t *sftp;
1476 siena_filter_spec_t *saved_sf_spec;
1480 efsys_lock_state_t state;
1484 EFSYS_ASSERT3P(spec, !=, NULL);
1486 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1489 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1490 sftp = &sfp->sf_tbl[tbl_id];
1492 if (sftp->sft_size == 0) {
1497 key = siena_filter_build(&filter, &sf_spec);
1499 EFSYS_LOCK(enp->en_eslp, state);
1501 rc = siena_filter_search(sftp, &sf_spec, key, B_TRUE,
1502 &filter_idx, &depth);
1506 EFSYS_ASSERT3U(filter_idx, <, sftp->sft_size);
1507 saved_sf_spec = &sftp->sft_spec[filter_idx];
1509 if (siena_filter_test_used(sftp, filter_idx)) {
1510 if (may_replace == B_FALSE) {
1515 siena_filter_set_used(sftp, filter_idx);
1516 *saved_sf_spec = sf_spec;
1518 if (sfp->sf_depth[sf_spec.sfs_type] < depth) {
1519 sfp->sf_depth[sf_spec.sfs_type] = depth;
1520 if (tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1521 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC)
1522 siena_filter_push_tx_limits(enp);
1524 siena_filter_push_rx_limits(enp);
1527 siena_filter_push_entry(enp, sf_spec.sfs_type,
1528 filter_idx, &filter);
1530 EFSYS_UNLOCK(enp->en_eslp, state);
1537 EFSYS_UNLOCK(enp->en_eslp, state);
1544 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1548 static __checkReturn efx_rc_t
1549 siena_filter_delete(
1550 __in efx_nic_t *enp,
1551 __inout efx_filter_spec_t *spec)
1554 siena_filter_spec_t sf_spec;
1555 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1556 siena_filter_tbl_id_t tbl_id;
1557 siena_filter_tbl_t *sftp;
1561 efsys_lock_state_t state;
1564 EFSYS_ASSERT3P(spec, !=, NULL);
1566 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1569 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1570 sftp = &sfp->sf_tbl[tbl_id];
1572 key = siena_filter_build(&filter, &sf_spec);
1574 EFSYS_LOCK(enp->en_eslp, state);
1576 rc = siena_filter_search(sftp, &sf_spec, key, B_FALSE,
1577 &filter_idx, &depth);
1581 siena_filter_clear_entry(enp, sftp, filter_idx);
1582 if (sftp->sft_used == 0)
1583 siena_filter_reset_search_depth(sfp, tbl_id);
1585 EFSYS_UNLOCK(enp->en_eslp, state);
1589 EFSYS_UNLOCK(enp->en_eslp, state);
1593 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1597 #define SIENA_MAX_SUPPORTED_MATCHES 4
1599 static __checkReturn efx_rc_t
1600 siena_filter_supported_filters(
1601 __in efx_nic_t *enp,
1602 __out_ecount(buffer_length) uint32_t *buffer,
1603 __in size_t buffer_length,
1604 __out size_t *list_lengthp)
1607 uint32_t rx_matches[SIENA_MAX_SUPPORTED_MATCHES];
1611 rx_matches[index++] =
1612 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1613 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
1614 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
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;
1620 if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) {
1621 rx_matches[index++] =
1622 EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC;
1624 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC;
1627 EFSYS_ASSERT3U(index, <=, SIENA_MAX_SUPPORTED_MATCHES);
1628 list_length = index;
1630 *list_lengthp = list_length;
1632 if (buffer_length < list_length) {
1637 memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0]));
1642 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1647 #undef MAX_SUPPORTED
1649 #endif /* EFSYS_OPT_SIENA */
1651 #endif /* EFSYS_OPT_FILTER */