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(
69 __out size_t *length);
71 #endif /* EFSYS_OPT_SIENA */
74 static const efx_filter_ops_t __efx_filter_siena_ops = {
75 siena_filter_init, /* efo_init */
76 siena_filter_fini, /* efo_fini */
77 siena_filter_restore, /* efo_restore */
78 siena_filter_add, /* efo_add */
79 siena_filter_delete, /* efo_delete */
80 siena_filter_supported_filters, /* efo_supported_filters */
81 NULL, /* efo_reconfigure */
83 #endif /* EFSYS_OPT_SIENA */
85 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
86 static const efx_filter_ops_t __efx_filter_ef10_ops = {
87 ef10_filter_init, /* efo_init */
88 ef10_filter_fini, /* efo_fini */
89 ef10_filter_restore, /* efo_restore */
90 ef10_filter_add, /* efo_add */
91 ef10_filter_delete, /* efo_delete */
92 ef10_filter_supported_filters, /* efo_supported_filters */
93 ef10_filter_reconfigure, /* efo_reconfigure */
95 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
97 __checkReturn efx_rc_t
100 __inout efx_filter_spec_t *spec)
102 const efx_filter_ops_t *efop = enp->en_efop;
104 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
105 EFSYS_ASSERT3P(spec, !=, NULL);
106 EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
108 return (efop->efo_add(enp, spec, B_FALSE));
111 __checkReturn efx_rc_t
114 __inout efx_filter_spec_t *spec)
116 const efx_filter_ops_t *efop = enp->en_efop;
118 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
119 EFSYS_ASSERT3P(spec, !=, NULL);
120 EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
122 #if EFSYS_OPT_RX_SCALE
123 spec->efs_rss_context = enp->en_rss_context;
126 return (efop->efo_delete(enp, spec));
129 __checkReturn efx_rc_t
135 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
137 if ((rc = enp->en_efop->efo_restore(enp)) != 0)
143 EFSYS_PROBE1(fail1, efx_rc_t, rc);
148 __checkReturn efx_rc_t
152 const efx_filter_ops_t *efop;
155 /* Check that efx_filter_spec_t is 64 bytes. */
156 EFX_STATIC_ASSERT(sizeof (efx_filter_spec_t) == 64);
158 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
159 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
160 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER));
162 switch (enp->en_family) {
164 case EFX_FAMILY_SIENA:
165 efop = &__efx_filter_siena_ops;
167 #endif /* EFSYS_OPT_SIENA */
169 #if EFSYS_OPT_HUNTINGTON
170 case EFX_FAMILY_HUNTINGTON:
171 efop = &__efx_filter_ef10_ops;
173 #endif /* EFSYS_OPT_HUNTINGTON */
175 #if EFSYS_OPT_MEDFORD
176 case EFX_FAMILY_MEDFORD:
177 efop = &__efx_filter_ef10_ops;
179 #endif /* EFSYS_OPT_MEDFORD */
187 if ((rc = efop->efo_init(enp)) != 0)
191 enp->en_mod_flags |= EFX_MOD_FILTER;
197 EFSYS_PROBE1(fail1, efx_rc_t, rc);
200 enp->en_mod_flags &= ~EFX_MOD_FILTER;
208 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
209 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
210 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
212 enp->en_efop->efo_fini(enp);
215 enp->en_mod_flags &= ~EFX_MOD_FILTER;
218 __checkReturn efx_rc_t
219 efx_filter_supported_filters(
221 __out uint32_t *list,
222 __out size_t *length)
226 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
227 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
228 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
229 EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL);
231 if ((rc = enp->en_efop->efo_supported_filters(enp, list, length)) != 0)
237 EFSYS_PROBE1(fail1, efx_rc_t, rc);
242 __checkReturn efx_rc_t
243 efx_filter_reconfigure(
245 __in_ecount(6) uint8_t const *mac_addr,
246 __in boolean_t all_unicst,
247 __in boolean_t mulcst,
248 __in boolean_t all_mulcst,
249 __in boolean_t brdcst,
250 __in_ecount(6*count) uint8_t const *addrs,
255 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
256 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
257 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
259 if (enp->en_efop->efo_reconfigure != NULL) {
260 if ((rc = enp->en_efop->efo_reconfigure(enp, mac_addr,
270 EFSYS_PROBE1(fail1, efx_rc_t, rc);
276 efx_filter_spec_init_rx(
277 __out efx_filter_spec_t *spec,
278 __in efx_filter_priority_t priority,
279 __in efx_filter_flag_t flags,
282 EFSYS_ASSERT3P(spec, !=, NULL);
283 EFSYS_ASSERT3P(erp, !=, NULL);
284 EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
285 EFX_FILTER_FLAG_RX_SCATTER)) == 0);
287 memset(spec, 0, sizeof (*spec));
288 spec->efs_priority = priority;
289 spec->efs_flags = EFX_FILTER_FLAG_RX | flags;
290 spec->efs_rss_context = EFX_FILTER_SPEC_RSS_CONTEXT_DEFAULT;
291 spec->efs_dmaq_id = (uint16_t)erp->er_index;
295 efx_filter_spec_init_tx(
296 __out efx_filter_spec_t *spec,
299 EFSYS_ASSERT3P(spec, !=, NULL);
300 EFSYS_ASSERT3P(etp, !=, NULL);
302 memset(spec, 0, sizeof (*spec));
303 spec->efs_priority = EFX_FILTER_PRI_REQUIRED;
304 spec->efs_flags = EFX_FILTER_FLAG_TX;
305 spec->efs_dmaq_id = (uint16_t)etp->et_index;
310 * Specify IPv4 host, transport protocol and port in a filter specification
312 __checkReturn efx_rc_t
313 efx_filter_spec_set_ipv4_local(
314 __inout efx_filter_spec_t *spec,
319 EFSYS_ASSERT3P(spec, !=, NULL);
321 spec->efs_match_flags |=
322 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
323 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
324 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
325 spec->efs_ip_proto = proto;
326 spec->efs_loc_host.eo_u32[0] = host;
327 spec->efs_loc_port = port;
332 * Specify IPv4 hosts, transport protocol and ports in a filter specification
334 __checkReturn efx_rc_t
335 efx_filter_spec_set_ipv4_full(
336 __inout efx_filter_spec_t *spec,
343 EFSYS_ASSERT3P(spec, !=, NULL);
345 spec->efs_match_flags |=
346 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
347 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
348 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
349 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
350 spec->efs_ip_proto = proto;
351 spec->efs_loc_host.eo_u32[0] = lhost;
352 spec->efs_loc_port = lport;
353 spec->efs_rem_host.eo_u32[0] = rhost;
354 spec->efs_rem_port = rport;
359 * Specify local Ethernet address and/or VID in filter specification
361 __checkReturn efx_rc_t
362 efx_filter_spec_set_eth_local(
363 __inout efx_filter_spec_t *spec,
365 __in const uint8_t *addr)
367 EFSYS_ASSERT3P(spec, !=, NULL);
368 EFSYS_ASSERT3P(addr, !=, NULL);
370 if (vid == EFX_FILTER_SPEC_VID_UNSPEC && addr == NULL)
373 if (vid != EFX_FILTER_SPEC_VID_UNSPEC) {
374 spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID;
375 spec->efs_outer_vid = vid;
378 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
379 memcpy(spec->efs_loc_mac, addr, EFX_MAC_ADDR_LEN);
385 * Specify matching otherwise-unmatched unicast in a filter specification
387 __checkReturn efx_rc_t
388 efx_filter_spec_set_uc_def(
389 __inout efx_filter_spec_t *spec)
391 EFSYS_ASSERT3P(spec, !=, NULL);
393 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
398 * Specify matching otherwise-unmatched multicast in a filter specification
400 __checkReturn efx_rc_t
401 efx_filter_spec_set_mc_def(
402 __inout efx_filter_spec_t *spec)
404 EFSYS_ASSERT3P(spec, !=, NULL);
406 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
407 spec->efs_loc_mac[0] = 1;
416 * "Fudge factors" - difference between programmed value and actual depth.
417 * Due to pipelined implementation we need to program H/W with a value that
418 * is larger than the hop limit we want.
420 #define FILTER_CTL_SRCH_FUDGE_WILD 3
421 #define FILTER_CTL_SRCH_FUDGE_FULL 1
424 * Hard maximum hop limit. Hardware will time-out beyond 200-something.
425 * We also need to avoid infinite loops in efx_filter_search() when the
428 #define FILTER_CTL_SRCH_MAX 200
430 static __checkReturn efx_rc_t
431 siena_filter_spec_from_gen_spec(
432 __out siena_filter_spec_t *sf_spec,
433 __in efx_filter_spec_t *gen_spec)
436 boolean_t is_full = B_FALSE;
438 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX)
439 EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX);
441 EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX);
443 /* Falconsiena only has one RSS context */
444 if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
445 gen_spec->efs_rss_context != 0) {
450 sf_spec->sfs_flags = gen_spec->efs_flags;
451 sf_spec->sfs_dmaq_id = gen_spec->efs_dmaq_id;
453 switch (gen_spec->efs_match_flags) {
454 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
455 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
456 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT:
459 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
460 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: {
461 uint32_t rhost, host1, host2;
462 uint16_t rport, port1, port2;
464 if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) {
468 if (gen_spec->efs_loc_port == 0 ||
469 (is_full && gen_spec->efs_rem_port == 0)) {
473 switch (gen_spec->efs_ip_proto) {
474 case EFX_IPPROTO_TCP:
475 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
476 sf_spec->sfs_type = (is_full ?
477 EFX_SIENA_FILTER_TX_TCP_FULL :
478 EFX_SIENA_FILTER_TX_TCP_WILD);
480 sf_spec->sfs_type = (is_full ?
481 EFX_SIENA_FILTER_RX_TCP_FULL :
482 EFX_SIENA_FILTER_RX_TCP_WILD);
485 case EFX_IPPROTO_UDP:
486 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
487 sf_spec->sfs_type = (is_full ?
488 EFX_SIENA_FILTER_TX_UDP_FULL :
489 EFX_SIENA_FILTER_TX_UDP_WILD);
491 sf_spec->sfs_type = (is_full ?
492 EFX_SIENA_FILTER_RX_UDP_FULL :
493 EFX_SIENA_FILTER_RX_UDP_WILD);
501 * The filter is constructed in terms of source and destination,
502 * with the odd wrinkle that the ports are swapped in a UDP
503 * wildcard filter. We need to convert from local and remote
504 * addresses (zero for a wildcard).
506 rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0;
507 rport = is_full ? gen_spec->efs_rem_port : 0;
508 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
509 host1 = gen_spec->efs_loc_host.eo_u32[0];
513 host2 = gen_spec->efs_loc_host.eo_u32[0];
515 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
516 if (sf_spec->sfs_type ==
517 EFX_SIENA_FILTER_TX_UDP_WILD) {
519 port2 = gen_spec->efs_loc_port;
521 port1 = gen_spec->efs_loc_port;
525 if (sf_spec->sfs_type ==
526 EFX_SIENA_FILTER_RX_UDP_WILD) {
527 port1 = gen_spec->efs_loc_port;
531 port2 = gen_spec->efs_loc_port;
534 sf_spec->sfs_dword[0] = (host1 << 16) | port1;
535 sf_spec->sfs_dword[1] = (port2 << 16) | (host1 >> 16);
536 sf_spec->sfs_dword[2] = host2;
540 case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID:
543 case EFX_FILTER_MATCH_LOC_MAC:
544 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
545 sf_spec->sfs_type = (is_full ?
546 EFX_SIENA_FILTER_TX_MAC_FULL :
547 EFX_SIENA_FILTER_TX_MAC_WILD);
549 sf_spec->sfs_type = (is_full ?
550 EFX_SIENA_FILTER_RX_MAC_FULL :
551 EFX_SIENA_FILTER_RX_MAC_WILD);
553 sf_spec->sfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0;
554 sf_spec->sfs_dword[1] =
555 gen_spec->efs_loc_mac[2] << 24 |
556 gen_spec->efs_loc_mac[3] << 16 |
557 gen_spec->efs_loc_mac[4] << 8 |
558 gen_spec->efs_loc_mac[5];
559 sf_spec->sfs_dword[2] =
560 gen_spec->efs_loc_mac[0] << 8 |
561 gen_spec->efs_loc_mac[1];
565 EFSYS_ASSERT(B_FALSE);
581 EFSYS_PROBE1(fail1, efx_rc_t, rc);
587 * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
588 * key derived from the n-tuple.
591 siena_filter_tbl_hash(
596 /* First 16 rounds */
597 tmp = 0x1fff ^ (uint16_t)(key >> 16);
598 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
599 tmp = tmp ^ tmp >> 9;
602 tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff);
603 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
604 tmp = tmp ^ tmp >> 9;
610 * To allow for hash collisions, filter search continues at these
611 * increments from the first possible entry selected by the hash.
614 siena_filter_tbl_increment(
617 return ((uint16_t)(key * 2 - 1));
620 static __checkReturn boolean_t
621 siena_filter_test_used(
622 __in siena_filter_tbl_t *sftp,
623 __in unsigned int index)
625 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
626 return ((sftp->sft_bitmap[index / 32] & (1 << (index % 32))) != 0);
630 siena_filter_set_used(
631 __in siena_filter_tbl_t *sftp,
632 __in unsigned int index)
634 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
635 sftp->sft_bitmap[index / 32] |= (1 << (index % 32));
640 siena_filter_clear_used(
641 __in siena_filter_tbl_t *sftp,
642 __in unsigned int index)
644 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
645 sftp->sft_bitmap[index / 32] &= ~(1 << (index % 32));
648 EFSYS_ASSERT3U(sftp->sft_used, >=, 0);
652 static siena_filter_tbl_id_t
654 __in siena_filter_type_t type)
656 siena_filter_tbl_id_t tbl_id;
659 case EFX_SIENA_FILTER_RX_TCP_FULL:
660 case EFX_SIENA_FILTER_RX_TCP_WILD:
661 case EFX_SIENA_FILTER_RX_UDP_FULL:
662 case EFX_SIENA_FILTER_RX_UDP_WILD:
663 tbl_id = EFX_SIENA_FILTER_TBL_RX_IP;
666 case EFX_SIENA_FILTER_RX_MAC_FULL:
667 case EFX_SIENA_FILTER_RX_MAC_WILD:
668 tbl_id = EFX_SIENA_FILTER_TBL_RX_MAC;
671 case EFX_SIENA_FILTER_TX_TCP_FULL:
672 case EFX_SIENA_FILTER_TX_TCP_WILD:
673 case EFX_SIENA_FILTER_TX_UDP_FULL:
674 case EFX_SIENA_FILTER_TX_UDP_WILD:
675 tbl_id = EFX_SIENA_FILTER_TBL_TX_IP;
678 case EFX_SIENA_FILTER_TX_MAC_FULL:
679 case EFX_SIENA_FILTER_TX_MAC_WILD:
680 tbl_id = EFX_SIENA_FILTER_TBL_TX_MAC;
684 EFSYS_ASSERT(B_FALSE);
685 tbl_id = EFX_SIENA_FILTER_NTBLS;
692 siena_filter_reset_search_depth(
693 __inout siena_filter_t *sfp,
694 __in siena_filter_tbl_id_t tbl_id)
697 case EFX_SIENA_FILTER_TBL_RX_IP:
698 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] = 0;
699 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] = 0;
700 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] = 0;
701 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] = 0;
704 case EFX_SIENA_FILTER_TBL_RX_MAC:
705 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] = 0;
706 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] = 0;
709 case EFX_SIENA_FILTER_TBL_TX_IP:
710 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] = 0;
711 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] = 0;
712 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] = 0;
713 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] = 0;
716 case EFX_SIENA_FILTER_TBL_TX_MAC:
717 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] = 0;
718 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] = 0;
722 EFSYS_ASSERT(B_FALSE);
728 siena_filter_push_rx_limits(
731 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
734 EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
736 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT,
737 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] +
738 FILTER_CTL_SRCH_FUDGE_FULL);
739 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT,
740 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] +
741 FILTER_CTL_SRCH_FUDGE_WILD);
742 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT,
743 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] +
744 FILTER_CTL_SRCH_FUDGE_FULL);
745 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT,
746 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] +
747 FILTER_CTL_SRCH_FUDGE_WILD);
749 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC].sft_size) {
750 EFX_SET_OWORD_FIELD(oword,
751 FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
752 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] +
753 FILTER_CTL_SRCH_FUDGE_FULL);
754 EFX_SET_OWORD_FIELD(oword,
755 FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
756 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] +
757 FILTER_CTL_SRCH_FUDGE_WILD);
760 EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
764 siena_filter_push_tx_limits(
767 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
770 EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
772 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP].sft_size != 0) {
773 EFX_SET_OWORD_FIELD(oword,
774 FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE,
775 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] +
776 FILTER_CTL_SRCH_FUDGE_FULL);
777 EFX_SET_OWORD_FIELD(oword,
778 FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE,
779 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] +
780 FILTER_CTL_SRCH_FUDGE_WILD);
781 EFX_SET_OWORD_FIELD(oword,
782 FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE,
783 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] +
784 FILTER_CTL_SRCH_FUDGE_FULL);
785 EFX_SET_OWORD_FIELD(oword,
786 FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE,
787 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] +
788 FILTER_CTL_SRCH_FUDGE_WILD);
791 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC].sft_size != 0) {
793 oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
794 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] +
795 FILTER_CTL_SRCH_FUDGE_FULL);
797 oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
798 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] +
799 FILTER_CTL_SRCH_FUDGE_WILD);
802 EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
805 /* Build a filter entry and return its n-tuple key. */
806 static __checkReturn uint32_t
808 __out efx_oword_t *filter,
809 __in siena_filter_spec_t *spec)
813 uint8_t type = spec->sfs_type;
814 uint32_t flags = spec->sfs_flags;
816 switch (siena_filter_tbl_id(type)) {
817 case EFX_SIENA_FILTER_TBL_RX_IP: {
818 boolean_t is_udp = (type == EFX_SIENA_FILTER_RX_UDP_FULL ||
819 type == EFX_SIENA_FILTER_RX_UDP_WILD);
820 EFX_POPULATE_OWORD_7(*filter,
822 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
824 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
825 FRF_AZ_TCP_UDP, is_udp,
826 FRF_AZ_RXQ_ID, spec->sfs_dmaq_id,
827 EFX_DWORD_2, spec->sfs_dword[2],
828 EFX_DWORD_1, spec->sfs_dword[1],
829 EFX_DWORD_0, spec->sfs_dword[0]);
834 case EFX_SIENA_FILTER_TBL_RX_MAC: {
835 boolean_t is_wild = (type == EFX_SIENA_FILTER_RX_MAC_WILD);
836 EFX_POPULATE_OWORD_7(*filter,
838 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
839 FRF_CZ_RMFT_SCATTER_EN,
840 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
841 FRF_CZ_RMFT_RXQ_ID, spec->sfs_dmaq_id,
842 FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
843 FRF_CZ_RMFT_DEST_MAC_DW1, spec->sfs_dword[2],
844 FRF_CZ_RMFT_DEST_MAC_DW0, spec->sfs_dword[1],
845 FRF_CZ_RMFT_VLAN_ID, spec->sfs_dword[0]);
850 case EFX_SIENA_FILTER_TBL_TX_IP: {
851 boolean_t is_udp = (type == EFX_SIENA_FILTER_TX_UDP_FULL ||
852 type == EFX_SIENA_FILTER_TX_UDP_WILD);
853 EFX_POPULATE_OWORD_5(*filter,
854 FRF_CZ_TIFT_TCP_UDP, is_udp,
855 FRF_CZ_TIFT_TXQ_ID, spec->sfs_dmaq_id,
856 EFX_DWORD_2, spec->sfs_dword[2],
857 EFX_DWORD_1, spec->sfs_dword[1],
858 EFX_DWORD_0, spec->sfs_dword[0]);
859 dword3 = is_udp | spec->sfs_dmaq_id << 1;
863 case EFX_SIENA_FILTER_TBL_TX_MAC: {
864 boolean_t is_wild = (type == EFX_SIENA_FILTER_TX_MAC_WILD);
865 EFX_POPULATE_OWORD_5(*filter,
866 FRF_CZ_TMFT_TXQ_ID, spec->sfs_dmaq_id,
867 FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
868 FRF_CZ_TMFT_SRC_MAC_DW1, spec->sfs_dword[2],
869 FRF_CZ_TMFT_SRC_MAC_DW0, spec->sfs_dword[1],
870 FRF_CZ_TMFT_VLAN_ID, spec->sfs_dword[0]);
871 dword3 = is_wild | spec->sfs_dmaq_id << 1;
876 EFSYS_ASSERT(B_FALSE);
889 static __checkReturn efx_rc_t
890 siena_filter_push_entry(
891 __inout efx_nic_t *enp,
892 __in siena_filter_type_t type,
894 __in efx_oword_t *eop)
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 EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index,
907 case EFX_SIENA_FILTER_RX_MAC_FULL:
908 case EFX_SIENA_FILTER_RX_MAC_WILD:
909 EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index,
913 case EFX_SIENA_FILTER_TX_TCP_FULL:
914 case EFX_SIENA_FILTER_TX_TCP_WILD:
915 case EFX_SIENA_FILTER_TX_UDP_FULL:
916 case EFX_SIENA_FILTER_TX_UDP_WILD:
917 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index,
921 case EFX_SIENA_FILTER_TX_MAC_FULL:
922 case EFX_SIENA_FILTER_TX_MAC_WILD:
923 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index,
928 EFSYS_ASSERT(B_FALSE);
939 static __checkReturn boolean_t
941 __in const siena_filter_spec_t *left,
942 __in const siena_filter_spec_t *right)
944 siena_filter_tbl_id_t tbl_id;
946 tbl_id = siena_filter_tbl_id(left->sfs_type);
949 if (left->sfs_type != right->sfs_type)
952 if (memcmp(left->sfs_dword, right->sfs_dword,
953 sizeof (left->sfs_dword)))
956 if ((tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
957 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) &&
958 left->sfs_dmaq_id != right->sfs_dmaq_id)
964 static __checkReturn efx_rc_t
966 __in siena_filter_tbl_t *sftp,
967 __in siena_filter_spec_t *spec,
969 __in boolean_t for_insert,
970 __out int *filter_index,
971 __out unsigned int *depth_required)
973 unsigned hash, incr, filter_idx, depth;
975 hash = siena_filter_tbl_hash(key);
976 incr = siena_filter_tbl_increment(key);
978 filter_idx = hash & (sftp->sft_size - 1);
983 * Return success if entry is used and matches this spec
984 * or entry is unused and we are trying to insert.
986 if (siena_filter_test_used(sftp, filter_idx) ?
987 siena_filter_equal(spec,
988 &sftp->sft_spec[filter_idx]) :
990 *filter_index = filter_idx;
991 *depth_required = depth;
995 /* Return failure if we reached the maximum search depth */
996 if (depth == FILTER_CTL_SRCH_MAX)
997 return (for_insert ? EBUSY : ENOENT);
999 filter_idx = (filter_idx + incr) & (sftp->sft_size - 1);
1005 siena_filter_clear_entry(
1006 __in efx_nic_t *enp,
1007 __in siena_filter_tbl_t *sftp,
1012 if (siena_filter_test_used(sftp, index)) {
1013 siena_filter_clear_used(sftp, index);
1015 EFX_ZERO_OWORD(filter);
1016 siena_filter_push_entry(enp,
1017 sftp->sft_spec[index].sfs_type,
1020 memset(&sftp->sft_spec[index],
1021 0, sizeof (sftp->sft_spec[0]));
1026 siena_filter_tbl_clear(
1027 __in efx_nic_t *enp,
1028 __in siena_filter_tbl_id_t tbl_id)
1030 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1031 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1035 EFSYS_LOCK(enp->en_eslp, state);
1037 for (index = 0; index < sftp->sft_size; ++index) {
1038 siena_filter_clear_entry(enp, sftp, index);
1041 if (sftp->sft_used == 0)
1042 siena_filter_reset_search_depth(sfp, tbl_id);
1044 EFSYS_UNLOCK(enp->en_eslp, state);
1047 static __checkReturn efx_rc_t
1049 __in efx_nic_t *enp)
1051 siena_filter_t *sfp;
1052 siena_filter_tbl_t *sftp;
1056 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (siena_filter_t), sfp);
1063 enp->en_filter.ef_siena_filter = sfp;
1065 switch (enp->en_family) {
1066 case EFX_FAMILY_SIENA:
1067 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_IP];
1068 sftp->sft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
1070 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC];
1071 sftp->sft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
1073 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP];
1074 sftp->sft_size = FR_CZ_TX_FILTER_TBL0_ROWS;
1076 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC];
1077 sftp->sft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
1085 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1086 unsigned int bitmap_size;
1088 sftp = &sfp->sf_tbl[tbl_id];
1089 if (sftp->sft_size == 0)
1092 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1095 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1097 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, sftp->sft_bitmap);
1098 if (!sftp->sft_bitmap) {
1103 EFSYS_KMEM_ALLOC(enp->en_esip,
1104 sftp->sft_size * sizeof (*sftp->sft_spec),
1106 if (!sftp->sft_spec) {
1110 memset(sftp->sft_spec, 0,
1111 sftp->sft_size * sizeof (*sftp->sft_spec));
1124 siena_filter_fini(enp);
1127 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1133 __in efx_nic_t *enp)
1135 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1136 siena_filter_tbl_id_t tbl_id;
1138 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1139 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1144 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1145 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1146 unsigned int bitmap_size;
1148 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1151 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1153 if (sftp->sft_bitmap != NULL) {
1154 EFSYS_KMEM_FREE(enp->en_esip, bitmap_size,
1156 sftp->sft_bitmap = NULL;
1159 if (sftp->sft_spec != NULL) {
1160 EFSYS_KMEM_FREE(enp->en_esip, sftp->sft_size *
1161 sizeof (*sftp->sft_spec), sftp->sft_spec);
1162 sftp->sft_spec = NULL;
1166 EFSYS_KMEM_FREE(enp->en_esip, sizeof (siena_filter_t),
1167 enp->en_filter.ef_siena_filter);
1170 /* Restore filter state after a reset */
1171 static __checkReturn efx_rc_t
1172 siena_filter_restore(
1173 __in efx_nic_t *enp)
1175 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1176 siena_filter_tbl_id_t tbl_id;
1177 siena_filter_tbl_t *sftp;
1178 siena_filter_spec_t *spec;
1184 EFSYS_LOCK(enp->en_eslp, state);
1186 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1187 sftp = &sfp->sf_tbl[tbl_id];
1188 for (filter_idx = 0;
1189 filter_idx < sftp->sft_size;
1191 if (!siena_filter_test_used(sftp, filter_idx))
1194 spec = &sftp->sft_spec[filter_idx];
1195 if ((rc = siena_filter_build(&filter, spec)) != 0)
1197 if ((rc = siena_filter_push_entry(enp,
1198 spec->sfs_type, filter_idx, &filter)) != 0)
1203 siena_filter_push_rx_limits(enp);
1204 siena_filter_push_tx_limits(enp);
1206 EFSYS_UNLOCK(enp->en_eslp, state);
1214 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1216 EFSYS_UNLOCK(enp->en_eslp, state);
1221 static __checkReturn efx_rc_t
1223 __in efx_nic_t *enp,
1224 __inout efx_filter_spec_t *spec,
1225 __in boolean_t may_replace)
1228 siena_filter_spec_t sf_spec;
1229 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1230 siena_filter_tbl_id_t tbl_id;
1231 siena_filter_tbl_t *sftp;
1232 siena_filter_spec_t *saved_sf_spec;
1240 EFSYS_ASSERT3P(spec, !=, NULL);
1242 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1245 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1246 sftp = &sfp->sf_tbl[tbl_id];
1248 if (sftp->sft_size == 0) {
1253 key = siena_filter_build(&filter, &sf_spec);
1255 EFSYS_LOCK(enp->en_eslp, state);
1257 rc = siena_filter_search(sftp, &sf_spec, key, B_TRUE,
1258 &filter_idx, &depth);
1262 EFSYS_ASSERT3U(filter_idx, <, sftp->sft_size);
1263 saved_sf_spec = &sftp->sft_spec[filter_idx];
1265 if (siena_filter_test_used(sftp, filter_idx)) {
1266 if (may_replace == B_FALSE) {
1271 siena_filter_set_used(sftp, filter_idx);
1272 *saved_sf_spec = sf_spec;
1274 if (sfp->sf_depth[sf_spec.sfs_type] < depth) {
1275 sfp->sf_depth[sf_spec.sfs_type] = depth;
1276 if (tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1277 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC)
1278 siena_filter_push_tx_limits(enp);
1280 siena_filter_push_rx_limits(enp);
1283 siena_filter_push_entry(enp, sf_spec.sfs_type,
1284 filter_idx, &filter);
1286 EFSYS_UNLOCK(enp->en_eslp, state);
1293 EFSYS_UNLOCK(enp->en_eslp, state);
1300 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1304 static __checkReturn efx_rc_t
1305 siena_filter_delete(
1306 __in efx_nic_t *enp,
1307 __inout efx_filter_spec_t *spec)
1310 siena_filter_spec_t sf_spec;
1311 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1312 siena_filter_tbl_id_t tbl_id;
1313 siena_filter_tbl_t *sftp;
1320 EFSYS_ASSERT3P(spec, !=, NULL);
1322 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1325 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1326 sftp = &sfp->sf_tbl[tbl_id];
1328 key = siena_filter_build(&filter, &sf_spec);
1330 EFSYS_LOCK(enp->en_eslp, state);
1332 rc = siena_filter_search(sftp, &sf_spec, key, B_FALSE,
1333 &filter_idx, &depth);
1337 siena_filter_clear_entry(enp, sftp, filter_idx);
1338 if (sftp->sft_used == 0)
1339 siena_filter_reset_search_depth(sfp, tbl_id);
1341 EFSYS_UNLOCK(enp->en_eslp, state);
1345 EFSYS_UNLOCK(enp->en_eslp, state);
1349 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1353 #define MAX_SUPPORTED 4
1355 static __checkReturn efx_rc_t
1356 siena_filter_supported_filters(
1357 __in efx_nic_t *enp,
1358 __out uint32_t *list,
1359 __out size_t *length)
1362 uint32_t rx_matches[MAX_SUPPORTED];
1370 rx_matches[index++] =
1371 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1372 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
1373 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
1375 rx_matches[index++] =
1376 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1377 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
1379 if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) {
1380 rx_matches[index++] =
1381 EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC;
1383 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC;
1386 EFSYS_ASSERT3U(index, <=, MAX_SUPPORTED);
1389 memcpy(list, rx_matches, *length);
1398 #undef MAX_SUPPORTED
1400 #endif /* EFSYS_OPT_SIENA */
1402 #endif /* EFSYS_OPT_FILTER */