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.
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
42 static __checkReturn efx_rc_t
50 static __checkReturn efx_rc_t
54 static __checkReturn efx_rc_t
57 __inout efx_filter_spec_t *spec,
58 __in boolean_t may_replace);
60 static __checkReturn efx_rc_t
63 __inout efx_filter_spec_t *spec);
65 static __checkReturn efx_rc_t
66 siena_filter_supported_filters(
68 __out_ecount(buffer_length) uint32_t *buffer,
69 __in size_t buffer_length,
70 __out size_t *list_lengthp);
72 #endif /* EFSYS_OPT_SIENA */
75 static const efx_filter_ops_t __efx_filter_siena_ops = {
76 siena_filter_init, /* efo_init */
77 siena_filter_fini, /* efo_fini */
78 siena_filter_restore, /* efo_restore */
79 siena_filter_add, /* efo_add */
80 siena_filter_delete, /* efo_delete */
81 siena_filter_supported_filters, /* efo_supported_filters */
82 NULL, /* efo_reconfigure */
84 #endif /* EFSYS_OPT_SIENA */
86 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
87 static const efx_filter_ops_t __efx_filter_ef10_ops = {
88 ef10_filter_init, /* efo_init */
89 ef10_filter_fini, /* efo_fini */
90 ef10_filter_restore, /* efo_restore */
91 ef10_filter_add, /* efo_add */
92 ef10_filter_delete, /* efo_delete */
93 ef10_filter_supported_filters, /* efo_supported_filters */
94 ef10_filter_reconfigure, /* efo_reconfigure */
96 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
98 __checkReturn efx_rc_t
101 __inout efx_filter_spec_t *spec)
103 const efx_filter_ops_t *efop = enp->en_efop;
105 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
106 EFSYS_ASSERT3P(spec, !=, NULL);
107 EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
109 return (efop->efo_add(enp, spec, B_FALSE));
112 __checkReturn efx_rc_t
115 __inout efx_filter_spec_t *spec)
117 const efx_filter_ops_t *efop = enp->en_efop;
119 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
120 EFSYS_ASSERT3P(spec, !=, NULL);
121 EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
123 #if EFSYS_OPT_RX_SCALE
124 spec->efs_rss_context = enp->en_rss_context;
127 return (efop->efo_delete(enp, spec));
130 __checkReturn efx_rc_t
136 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
138 if ((rc = enp->en_efop->efo_restore(enp)) != 0)
144 EFSYS_PROBE1(fail1, efx_rc_t, rc);
149 __checkReturn efx_rc_t
153 const efx_filter_ops_t *efop;
156 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
157 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
158 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER));
160 switch (enp->en_family) {
162 case EFX_FAMILY_SIENA:
163 efop = &__efx_filter_siena_ops;
165 #endif /* EFSYS_OPT_SIENA */
167 #if EFSYS_OPT_HUNTINGTON
168 case EFX_FAMILY_HUNTINGTON:
169 efop = &__efx_filter_ef10_ops;
171 #endif /* EFSYS_OPT_HUNTINGTON */
173 #if EFSYS_OPT_MEDFORD
174 case EFX_FAMILY_MEDFORD:
175 efop = &__efx_filter_ef10_ops;
177 #endif /* EFSYS_OPT_MEDFORD */
185 if ((rc = efop->efo_init(enp)) != 0)
189 enp->en_mod_flags |= EFX_MOD_FILTER;
195 EFSYS_PROBE1(fail1, efx_rc_t, rc);
198 enp->en_mod_flags &= ~EFX_MOD_FILTER;
206 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
207 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
208 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
210 enp->en_efop->efo_fini(enp);
213 enp->en_mod_flags &= ~EFX_MOD_FILTER;
217 * Query the possible combinations of match flags which can be filtered on.
218 * These are returned as a list, of which each 32 bit element is a bitmask
219 * formed of EFX_FILTER_MATCH flags.
221 * The combinations are ordered in priority from highest to lowest.
223 * If the provided buffer is too short to hold the list, the call with fail with
224 * ENOSPC and *list_lengthp will be set to the buffer length required.
226 __checkReturn efx_rc_t
227 efx_filter_supported_filters(
229 __out_ecount(buffer_length) uint32_t *buffer,
230 __in size_t buffer_length,
231 __out size_t *list_lengthp)
235 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
236 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
237 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
238 EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL);
240 if (buffer == NULL) {
245 rc = enp->en_efop->efo_supported_filters(enp, buffer, buffer_length,
255 EFSYS_PROBE1(fail1, efx_rc_t, rc);
260 __checkReturn efx_rc_t
261 efx_filter_reconfigure(
263 __in_ecount(6) uint8_t const *mac_addr,
264 __in boolean_t all_unicst,
265 __in boolean_t mulcst,
266 __in boolean_t all_mulcst,
267 __in boolean_t brdcst,
268 __in_ecount(6*count) uint8_t const *addrs,
273 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
274 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
275 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
277 if (enp->en_efop->efo_reconfigure != NULL) {
278 if ((rc = enp->en_efop->efo_reconfigure(enp, mac_addr,
288 EFSYS_PROBE1(fail1, efx_rc_t, rc);
294 efx_filter_spec_init_rx(
295 __out efx_filter_spec_t *spec,
296 __in efx_filter_priority_t priority,
297 __in efx_filter_flags_t flags,
300 EFSYS_ASSERT3P(spec, !=, NULL);
301 EFSYS_ASSERT3P(erp, !=, NULL);
302 EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
303 EFX_FILTER_FLAG_RX_SCATTER)) == 0);
305 memset(spec, 0, sizeof (*spec));
306 spec->efs_priority = priority;
307 spec->efs_flags = EFX_FILTER_FLAG_RX | flags;
308 spec->efs_rss_context = EFX_FILTER_SPEC_RSS_CONTEXT_DEFAULT;
309 spec->efs_dmaq_id = (uint16_t)erp->er_index;
313 efx_filter_spec_init_tx(
314 __out efx_filter_spec_t *spec,
317 EFSYS_ASSERT3P(spec, !=, NULL);
318 EFSYS_ASSERT3P(etp, !=, NULL);
320 memset(spec, 0, sizeof (*spec));
321 spec->efs_priority = EFX_FILTER_PRI_REQUIRED;
322 spec->efs_flags = EFX_FILTER_FLAG_TX;
323 spec->efs_dmaq_id = (uint16_t)etp->et_index;
328 * Specify IPv4 host, transport protocol and port in a filter specification
330 __checkReturn efx_rc_t
331 efx_filter_spec_set_ipv4_local(
332 __inout efx_filter_spec_t *spec,
337 EFSYS_ASSERT3P(spec, !=, NULL);
339 spec->efs_match_flags |=
340 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
341 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
342 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
343 spec->efs_ip_proto = proto;
344 spec->efs_loc_host.eo_u32[0] = host;
345 spec->efs_loc_port = port;
350 * Specify IPv4 hosts, transport protocol and ports in a filter specification
352 __checkReturn efx_rc_t
353 efx_filter_spec_set_ipv4_full(
354 __inout efx_filter_spec_t *spec,
361 EFSYS_ASSERT3P(spec, !=, NULL);
363 spec->efs_match_flags |=
364 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
365 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
366 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
367 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
368 spec->efs_ip_proto = proto;
369 spec->efs_loc_host.eo_u32[0] = lhost;
370 spec->efs_loc_port = lport;
371 spec->efs_rem_host.eo_u32[0] = rhost;
372 spec->efs_rem_port = rport;
377 * Specify local Ethernet address and/or VID in filter specification
379 __checkReturn efx_rc_t
380 efx_filter_spec_set_eth_local(
381 __inout efx_filter_spec_t *spec,
383 __in const uint8_t *addr)
385 EFSYS_ASSERT3P(spec, !=, NULL);
386 EFSYS_ASSERT3P(addr, !=, NULL);
388 if (vid == EFX_FILTER_SPEC_VID_UNSPEC && addr == NULL)
391 if (vid != EFX_FILTER_SPEC_VID_UNSPEC) {
392 spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID;
393 spec->efs_outer_vid = vid;
396 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
397 memcpy(spec->efs_loc_mac, addr, EFX_MAC_ADDR_LEN);
403 * Specify matching otherwise-unmatched unicast in a filter specification
405 __checkReturn efx_rc_t
406 efx_filter_spec_set_uc_def(
407 __inout efx_filter_spec_t *spec)
409 EFSYS_ASSERT3P(spec, !=, NULL);
411 spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_UCAST_DST;
416 * Specify matching otherwise-unmatched multicast in a filter specification
418 __checkReturn efx_rc_t
419 efx_filter_spec_set_mc_def(
420 __inout efx_filter_spec_t *spec)
422 EFSYS_ASSERT3P(spec, !=, NULL);
424 spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
433 * "Fudge factors" - difference between programmed value and actual depth.
434 * Due to pipelined implementation we need to program H/W with a value that
435 * is larger than the hop limit we want.
437 #define FILTER_CTL_SRCH_FUDGE_WILD 3
438 #define FILTER_CTL_SRCH_FUDGE_FULL 1
441 * Hard maximum hop limit. Hardware will time-out beyond 200-something.
442 * We also need to avoid infinite loops in efx_filter_search() when the
445 #define FILTER_CTL_SRCH_MAX 200
447 static __checkReturn efx_rc_t
448 siena_filter_spec_from_gen_spec(
449 __out siena_filter_spec_t *sf_spec,
450 __in efx_filter_spec_t *gen_spec)
453 boolean_t is_full = B_FALSE;
455 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX)
456 EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX);
458 EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX);
460 /* Falconsiena only has one RSS context */
461 if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
462 gen_spec->efs_rss_context != 0) {
467 sf_spec->sfs_flags = gen_spec->efs_flags;
468 sf_spec->sfs_dmaq_id = gen_spec->efs_dmaq_id;
470 switch (gen_spec->efs_match_flags) {
471 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
472 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
473 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT:
476 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
477 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: {
478 uint32_t rhost, host1, host2;
479 uint16_t rport, port1, port2;
481 if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) {
485 if (gen_spec->efs_loc_port == 0 ||
486 (is_full && gen_spec->efs_rem_port == 0)) {
490 switch (gen_spec->efs_ip_proto) {
491 case EFX_IPPROTO_TCP:
492 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
493 sf_spec->sfs_type = (is_full ?
494 EFX_SIENA_FILTER_TX_TCP_FULL :
495 EFX_SIENA_FILTER_TX_TCP_WILD);
497 sf_spec->sfs_type = (is_full ?
498 EFX_SIENA_FILTER_RX_TCP_FULL :
499 EFX_SIENA_FILTER_RX_TCP_WILD);
502 case EFX_IPPROTO_UDP:
503 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
504 sf_spec->sfs_type = (is_full ?
505 EFX_SIENA_FILTER_TX_UDP_FULL :
506 EFX_SIENA_FILTER_TX_UDP_WILD);
508 sf_spec->sfs_type = (is_full ?
509 EFX_SIENA_FILTER_RX_UDP_FULL :
510 EFX_SIENA_FILTER_RX_UDP_WILD);
518 * The filter is constructed in terms of source and destination,
519 * with the odd wrinkle that the ports are swapped in a UDP
520 * wildcard filter. We need to convert from local and remote
521 * addresses (zero for a wildcard).
523 rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0;
524 rport = is_full ? gen_spec->efs_rem_port : 0;
525 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
526 host1 = gen_spec->efs_loc_host.eo_u32[0];
530 host2 = gen_spec->efs_loc_host.eo_u32[0];
532 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
533 if (sf_spec->sfs_type ==
534 EFX_SIENA_FILTER_TX_UDP_WILD) {
536 port2 = gen_spec->efs_loc_port;
538 port1 = gen_spec->efs_loc_port;
542 if (sf_spec->sfs_type ==
543 EFX_SIENA_FILTER_RX_UDP_WILD) {
544 port1 = gen_spec->efs_loc_port;
548 port2 = gen_spec->efs_loc_port;
551 sf_spec->sfs_dword[0] = (host1 << 16) | port1;
552 sf_spec->sfs_dword[1] = (port2 << 16) | (host1 >> 16);
553 sf_spec->sfs_dword[2] = host2;
557 case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID:
560 case EFX_FILTER_MATCH_LOC_MAC:
561 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
562 sf_spec->sfs_type = (is_full ?
563 EFX_SIENA_FILTER_TX_MAC_FULL :
564 EFX_SIENA_FILTER_TX_MAC_WILD);
566 sf_spec->sfs_type = (is_full ?
567 EFX_SIENA_FILTER_RX_MAC_FULL :
568 EFX_SIENA_FILTER_RX_MAC_WILD);
570 sf_spec->sfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0;
571 sf_spec->sfs_dword[1] =
572 gen_spec->efs_loc_mac[2] << 24 |
573 gen_spec->efs_loc_mac[3] << 16 |
574 gen_spec->efs_loc_mac[4] << 8 |
575 gen_spec->efs_loc_mac[5];
576 sf_spec->sfs_dword[2] =
577 gen_spec->efs_loc_mac[0] << 8 |
578 gen_spec->efs_loc_mac[1];
582 EFSYS_ASSERT(B_FALSE);
598 EFSYS_PROBE1(fail1, efx_rc_t, rc);
604 * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
605 * key derived from the n-tuple.
608 siena_filter_tbl_hash(
613 /* First 16 rounds */
614 tmp = 0x1fff ^ (uint16_t)(key >> 16);
615 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
616 tmp = tmp ^ tmp >> 9;
619 tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff);
620 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
621 tmp = tmp ^ tmp >> 9;
627 * To allow for hash collisions, filter search continues at these
628 * increments from the first possible entry selected by the hash.
631 siena_filter_tbl_increment(
634 return ((uint16_t)(key * 2 - 1));
637 static __checkReturn boolean_t
638 siena_filter_test_used(
639 __in siena_filter_tbl_t *sftp,
640 __in unsigned int index)
642 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
643 return ((sftp->sft_bitmap[index / 32] & (1 << (index % 32))) != 0);
647 siena_filter_set_used(
648 __in siena_filter_tbl_t *sftp,
649 __in unsigned int index)
651 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
652 sftp->sft_bitmap[index / 32] |= (1 << (index % 32));
657 siena_filter_clear_used(
658 __in siena_filter_tbl_t *sftp,
659 __in unsigned int index)
661 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
662 sftp->sft_bitmap[index / 32] &= ~(1 << (index % 32));
665 EFSYS_ASSERT3U(sftp->sft_used, >=, 0);
669 static siena_filter_tbl_id_t
671 __in siena_filter_type_t type)
673 siena_filter_tbl_id_t tbl_id;
676 case EFX_SIENA_FILTER_RX_TCP_FULL:
677 case EFX_SIENA_FILTER_RX_TCP_WILD:
678 case EFX_SIENA_FILTER_RX_UDP_FULL:
679 case EFX_SIENA_FILTER_RX_UDP_WILD:
680 tbl_id = EFX_SIENA_FILTER_TBL_RX_IP;
683 case EFX_SIENA_FILTER_RX_MAC_FULL:
684 case EFX_SIENA_FILTER_RX_MAC_WILD:
685 tbl_id = EFX_SIENA_FILTER_TBL_RX_MAC;
688 case EFX_SIENA_FILTER_TX_TCP_FULL:
689 case EFX_SIENA_FILTER_TX_TCP_WILD:
690 case EFX_SIENA_FILTER_TX_UDP_FULL:
691 case EFX_SIENA_FILTER_TX_UDP_WILD:
692 tbl_id = EFX_SIENA_FILTER_TBL_TX_IP;
695 case EFX_SIENA_FILTER_TX_MAC_FULL:
696 case EFX_SIENA_FILTER_TX_MAC_WILD:
697 tbl_id = EFX_SIENA_FILTER_TBL_TX_MAC;
701 EFSYS_ASSERT(B_FALSE);
702 tbl_id = EFX_SIENA_FILTER_NTBLS;
709 siena_filter_reset_search_depth(
710 __inout siena_filter_t *sfp,
711 __in siena_filter_tbl_id_t tbl_id)
714 case EFX_SIENA_FILTER_TBL_RX_IP:
715 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] = 0;
716 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] = 0;
717 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] = 0;
718 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] = 0;
721 case EFX_SIENA_FILTER_TBL_RX_MAC:
722 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] = 0;
723 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] = 0;
726 case EFX_SIENA_FILTER_TBL_TX_IP:
727 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] = 0;
728 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] = 0;
729 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] = 0;
730 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] = 0;
733 case EFX_SIENA_FILTER_TBL_TX_MAC:
734 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] = 0;
735 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] = 0;
739 EFSYS_ASSERT(B_FALSE);
745 siena_filter_push_rx_limits(
748 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
751 EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
753 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT,
754 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] +
755 FILTER_CTL_SRCH_FUDGE_FULL);
756 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT,
757 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] +
758 FILTER_CTL_SRCH_FUDGE_WILD);
759 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT,
760 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] +
761 FILTER_CTL_SRCH_FUDGE_FULL);
762 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT,
763 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] +
764 FILTER_CTL_SRCH_FUDGE_WILD);
766 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC].sft_size) {
767 EFX_SET_OWORD_FIELD(oword,
768 FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
769 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] +
770 FILTER_CTL_SRCH_FUDGE_FULL);
771 EFX_SET_OWORD_FIELD(oword,
772 FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
773 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] +
774 FILTER_CTL_SRCH_FUDGE_WILD);
777 EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
781 siena_filter_push_tx_limits(
784 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
787 EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
789 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP].sft_size != 0) {
790 EFX_SET_OWORD_FIELD(oword,
791 FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE,
792 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] +
793 FILTER_CTL_SRCH_FUDGE_FULL);
794 EFX_SET_OWORD_FIELD(oword,
795 FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE,
796 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] +
797 FILTER_CTL_SRCH_FUDGE_WILD);
798 EFX_SET_OWORD_FIELD(oword,
799 FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE,
800 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] +
801 FILTER_CTL_SRCH_FUDGE_FULL);
802 EFX_SET_OWORD_FIELD(oword,
803 FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE,
804 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] +
805 FILTER_CTL_SRCH_FUDGE_WILD);
808 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC].sft_size != 0) {
810 oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
811 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] +
812 FILTER_CTL_SRCH_FUDGE_FULL);
814 oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
815 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] +
816 FILTER_CTL_SRCH_FUDGE_WILD);
819 EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
822 /* Build a filter entry and return its n-tuple key. */
823 static __checkReturn uint32_t
825 __out efx_oword_t *filter,
826 __in siena_filter_spec_t *spec)
830 uint8_t type = spec->sfs_type;
831 uint32_t flags = spec->sfs_flags;
833 switch (siena_filter_tbl_id(type)) {
834 case EFX_SIENA_FILTER_TBL_RX_IP: {
835 boolean_t is_udp = (type == EFX_SIENA_FILTER_RX_UDP_FULL ||
836 type == EFX_SIENA_FILTER_RX_UDP_WILD);
837 EFX_POPULATE_OWORD_7(*filter,
839 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
841 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
842 FRF_AZ_TCP_UDP, is_udp,
843 FRF_AZ_RXQ_ID, spec->sfs_dmaq_id,
844 EFX_DWORD_2, spec->sfs_dword[2],
845 EFX_DWORD_1, spec->sfs_dword[1],
846 EFX_DWORD_0, spec->sfs_dword[0]);
851 case EFX_SIENA_FILTER_TBL_RX_MAC: {
852 boolean_t is_wild = (type == EFX_SIENA_FILTER_RX_MAC_WILD);
853 EFX_POPULATE_OWORD_7(*filter,
855 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
856 FRF_CZ_RMFT_SCATTER_EN,
857 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
858 FRF_CZ_RMFT_RXQ_ID, spec->sfs_dmaq_id,
859 FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
860 FRF_CZ_RMFT_DEST_MAC_DW1, spec->sfs_dword[2],
861 FRF_CZ_RMFT_DEST_MAC_DW0, spec->sfs_dword[1],
862 FRF_CZ_RMFT_VLAN_ID, spec->sfs_dword[0]);
867 case EFX_SIENA_FILTER_TBL_TX_IP: {
868 boolean_t is_udp = (type == EFX_SIENA_FILTER_TX_UDP_FULL ||
869 type == EFX_SIENA_FILTER_TX_UDP_WILD);
870 EFX_POPULATE_OWORD_5(*filter,
871 FRF_CZ_TIFT_TCP_UDP, is_udp,
872 FRF_CZ_TIFT_TXQ_ID, spec->sfs_dmaq_id,
873 EFX_DWORD_2, spec->sfs_dword[2],
874 EFX_DWORD_1, spec->sfs_dword[1],
875 EFX_DWORD_0, spec->sfs_dword[0]);
876 dword3 = is_udp | spec->sfs_dmaq_id << 1;
880 case EFX_SIENA_FILTER_TBL_TX_MAC: {
881 boolean_t is_wild = (type == EFX_SIENA_FILTER_TX_MAC_WILD);
882 EFX_POPULATE_OWORD_5(*filter,
883 FRF_CZ_TMFT_TXQ_ID, spec->sfs_dmaq_id,
884 FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
885 FRF_CZ_TMFT_SRC_MAC_DW1, spec->sfs_dword[2],
886 FRF_CZ_TMFT_SRC_MAC_DW0, spec->sfs_dword[1],
887 FRF_CZ_TMFT_VLAN_ID, spec->sfs_dword[0]);
888 dword3 = is_wild | spec->sfs_dmaq_id << 1;
893 EFSYS_ASSERT(B_FALSE);
906 static __checkReturn efx_rc_t
907 siena_filter_push_entry(
908 __inout efx_nic_t *enp,
909 __in siena_filter_type_t type,
911 __in efx_oword_t *eop)
916 case EFX_SIENA_FILTER_RX_TCP_FULL:
917 case EFX_SIENA_FILTER_RX_TCP_WILD:
918 case EFX_SIENA_FILTER_RX_UDP_FULL:
919 case EFX_SIENA_FILTER_RX_UDP_WILD:
920 EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index,
924 case EFX_SIENA_FILTER_RX_MAC_FULL:
925 case EFX_SIENA_FILTER_RX_MAC_WILD:
926 EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index,
930 case EFX_SIENA_FILTER_TX_TCP_FULL:
931 case EFX_SIENA_FILTER_TX_TCP_WILD:
932 case EFX_SIENA_FILTER_TX_UDP_FULL:
933 case EFX_SIENA_FILTER_TX_UDP_WILD:
934 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index,
938 case EFX_SIENA_FILTER_TX_MAC_FULL:
939 case EFX_SIENA_FILTER_TX_MAC_WILD:
940 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index,
945 EFSYS_ASSERT(B_FALSE);
956 static __checkReturn boolean_t
958 __in const siena_filter_spec_t *left,
959 __in const siena_filter_spec_t *right)
961 siena_filter_tbl_id_t tbl_id;
963 tbl_id = siena_filter_tbl_id(left->sfs_type);
966 if (left->sfs_type != right->sfs_type)
969 if (memcmp(left->sfs_dword, right->sfs_dword,
970 sizeof (left->sfs_dword)))
973 if ((tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
974 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) &&
975 left->sfs_dmaq_id != right->sfs_dmaq_id)
981 static __checkReturn efx_rc_t
983 __in siena_filter_tbl_t *sftp,
984 __in siena_filter_spec_t *spec,
986 __in boolean_t for_insert,
987 __out int *filter_index,
988 __out unsigned int *depth_required)
990 unsigned int hash, incr, filter_idx, depth;
992 hash = siena_filter_tbl_hash(key);
993 incr = siena_filter_tbl_increment(key);
995 filter_idx = hash & (sftp->sft_size - 1);
1000 * Return success if entry is used and matches this spec
1001 * or entry is unused and we are trying to insert.
1003 if (siena_filter_test_used(sftp, filter_idx) ?
1004 siena_filter_equal(spec,
1005 &sftp->sft_spec[filter_idx]) :
1007 *filter_index = filter_idx;
1008 *depth_required = depth;
1012 /* Return failure if we reached the maximum search depth */
1013 if (depth == FILTER_CTL_SRCH_MAX)
1014 return (for_insert ? EBUSY : ENOENT);
1016 filter_idx = (filter_idx + incr) & (sftp->sft_size - 1);
1022 siena_filter_clear_entry(
1023 __in efx_nic_t *enp,
1024 __in siena_filter_tbl_t *sftp,
1029 if (siena_filter_test_used(sftp, index)) {
1030 siena_filter_clear_used(sftp, index);
1032 EFX_ZERO_OWORD(filter);
1033 siena_filter_push_entry(enp,
1034 sftp->sft_spec[index].sfs_type,
1037 memset(&sftp->sft_spec[index],
1038 0, sizeof (sftp->sft_spec[0]));
1043 siena_filter_tbl_clear(
1044 __in efx_nic_t *enp,
1045 __in siena_filter_tbl_id_t tbl_id)
1047 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1048 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1050 efsys_lock_state_t state;
1052 EFSYS_LOCK(enp->en_eslp, state);
1054 for (index = 0; index < sftp->sft_size; ++index) {
1055 siena_filter_clear_entry(enp, sftp, index);
1058 if (sftp->sft_used == 0)
1059 siena_filter_reset_search_depth(sfp, tbl_id);
1061 EFSYS_UNLOCK(enp->en_eslp, state);
1064 static __checkReturn efx_rc_t
1066 __in efx_nic_t *enp)
1068 siena_filter_t *sfp;
1069 siena_filter_tbl_t *sftp;
1073 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (siena_filter_t), sfp);
1080 enp->en_filter.ef_siena_filter = sfp;
1082 switch (enp->en_family) {
1083 case EFX_FAMILY_SIENA:
1084 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_IP];
1085 sftp->sft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
1087 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC];
1088 sftp->sft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
1090 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP];
1091 sftp->sft_size = FR_CZ_TX_FILTER_TBL0_ROWS;
1093 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC];
1094 sftp->sft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
1102 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1103 unsigned int bitmap_size;
1105 sftp = &sfp->sf_tbl[tbl_id];
1106 if (sftp->sft_size == 0)
1109 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1112 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1114 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, sftp->sft_bitmap);
1115 if (!sftp->sft_bitmap) {
1120 EFSYS_KMEM_ALLOC(enp->en_esip,
1121 sftp->sft_size * sizeof (*sftp->sft_spec),
1123 if (!sftp->sft_spec) {
1127 memset(sftp->sft_spec, 0,
1128 sftp->sft_size * sizeof (*sftp->sft_spec));
1141 siena_filter_fini(enp);
1144 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1150 __in efx_nic_t *enp)
1152 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1153 siena_filter_tbl_id_t tbl_id;
1155 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1156 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1161 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1162 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1163 unsigned int bitmap_size;
1165 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1168 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1170 if (sftp->sft_bitmap != NULL) {
1171 EFSYS_KMEM_FREE(enp->en_esip, bitmap_size,
1173 sftp->sft_bitmap = NULL;
1176 if (sftp->sft_spec != NULL) {
1177 EFSYS_KMEM_FREE(enp->en_esip, sftp->sft_size *
1178 sizeof (*sftp->sft_spec), sftp->sft_spec);
1179 sftp->sft_spec = NULL;
1183 EFSYS_KMEM_FREE(enp->en_esip, sizeof (siena_filter_t),
1184 enp->en_filter.ef_siena_filter);
1187 /* Restore filter state after a reset */
1188 static __checkReturn efx_rc_t
1189 siena_filter_restore(
1190 __in efx_nic_t *enp)
1192 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1193 siena_filter_tbl_id_t tbl_id;
1194 siena_filter_tbl_t *sftp;
1195 siena_filter_spec_t *spec;
1198 efsys_lock_state_t state;
1202 EFSYS_LOCK(enp->en_eslp, state);
1204 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1205 sftp = &sfp->sf_tbl[tbl_id];
1206 for (filter_idx = 0;
1207 filter_idx < sftp->sft_size;
1209 if (!siena_filter_test_used(sftp, filter_idx))
1212 spec = &sftp->sft_spec[filter_idx];
1213 if ((key = siena_filter_build(&filter, spec)) == 0) {
1217 if ((rc = siena_filter_push_entry(enp,
1218 spec->sfs_type, filter_idx, &filter)) != 0)
1223 siena_filter_push_rx_limits(enp);
1224 siena_filter_push_tx_limits(enp);
1226 EFSYS_UNLOCK(enp->en_eslp, state);
1234 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1236 EFSYS_UNLOCK(enp->en_eslp, state);
1241 static __checkReturn efx_rc_t
1243 __in efx_nic_t *enp,
1244 __inout efx_filter_spec_t *spec,
1245 __in boolean_t may_replace)
1248 siena_filter_spec_t sf_spec;
1249 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1250 siena_filter_tbl_id_t tbl_id;
1251 siena_filter_tbl_t *sftp;
1252 siena_filter_spec_t *saved_sf_spec;
1256 efsys_lock_state_t state;
1260 EFSYS_ASSERT3P(spec, !=, NULL);
1262 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1265 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1266 sftp = &sfp->sf_tbl[tbl_id];
1268 if (sftp->sft_size == 0) {
1273 key = siena_filter_build(&filter, &sf_spec);
1275 EFSYS_LOCK(enp->en_eslp, state);
1277 rc = siena_filter_search(sftp, &sf_spec, key, B_TRUE,
1278 &filter_idx, &depth);
1282 EFSYS_ASSERT3U(filter_idx, <, sftp->sft_size);
1283 saved_sf_spec = &sftp->sft_spec[filter_idx];
1285 if (siena_filter_test_used(sftp, filter_idx)) {
1286 if (may_replace == B_FALSE) {
1291 siena_filter_set_used(sftp, filter_idx);
1292 *saved_sf_spec = sf_spec;
1294 if (sfp->sf_depth[sf_spec.sfs_type] < depth) {
1295 sfp->sf_depth[sf_spec.sfs_type] = depth;
1296 if (tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1297 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC)
1298 siena_filter_push_tx_limits(enp);
1300 siena_filter_push_rx_limits(enp);
1303 siena_filter_push_entry(enp, sf_spec.sfs_type,
1304 filter_idx, &filter);
1306 EFSYS_UNLOCK(enp->en_eslp, state);
1313 EFSYS_UNLOCK(enp->en_eslp, state);
1320 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1324 static __checkReturn efx_rc_t
1325 siena_filter_delete(
1326 __in efx_nic_t *enp,
1327 __inout efx_filter_spec_t *spec)
1330 siena_filter_spec_t sf_spec;
1331 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1332 siena_filter_tbl_id_t tbl_id;
1333 siena_filter_tbl_t *sftp;
1337 efsys_lock_state_t state;
1340 EFSYS_ASSERT3P(spec, !=, NULL);
1342 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1345 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1346 sftp = &sfp->sf_tbl[tbl_id];
1348 key = siena_filter_build(&filter, &sf_spec);
1350 EFSYS_LOCK(enp->en_eslp, state);
1352 rc = siena_filter_search(sftp, &sf_spec, key, B_FALSE,
1353 &filter_idx, &depth);
1357 siena_filter_clear_entry(enp, sftp, filter_idx);
1358 if (sftp->sft_used == 0)
1359 siena_filter_reset_search_depth(sfp, tbl_id);
1361 EFSYS_UNLOCK(enp->en_eslp, state);
1365 EFSYS_UNLOCK(enp->en_eslp, state);
1369 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1373 #define SIENA_MAX_SUPPORTED_MATCHES 4
1375 static __checkReturn efx_rc_t
1376 siena_filter_supported_filters(
1377 __in efx_nic_t *enp,
1378 __out_ecount(buffer_length) uint32_t *buffer,
1379 __in size_t buffer_length,
1380 __out size_t *list_lengthp)
1383 uint32_t rx_matches[SIENA_MAX_SUPPORTED_MATCHES];
1387 rx_matches[index++] =
1388 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1389 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
1390 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
1392 rx_matches[index++] =
1393 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1394 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
1396 if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) {
1397 rx_matches[index++] =
1398 EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC;
1400 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC;
1403 EFSYS_ASSERT3U(index, <=, SIENA_MAX_SUPPORTED_MATCHES);
1404 list_length = index;
1406 *list_lengthp = list_length;
1408 if (buffer_length < list_length) {
1413 memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0]));
1418 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1423 #undef MAX_SUPPORTED
1425 #endif /* EFSYS_OPT_SIENA */
1427 #endif /* EFSYS_OPT_FILTER */