2 * Copyright (c) 2007-2015 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$");
36 #include "efx_types.h"
43 #if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA
45 static __checkReturn int
46 falconsiena_filter_init(
50 falconsiena_filter_fini(
53 static __checkReturn int
54 falconsiena_filter_restore(
57 static __checkReturn int
58 falconsiena_filter_add(
60 __inout efx_filter_spec_t *spec,
61 __in boolean_t may_replace);
63 static __checkReturn int
64 falconsiena_filter_delete(
66 __inout efx_filter_spec_t *spec);
68 static __checkReturn int
69 falconsiena_filter_supported_filters(
72 __out size_t *length);
74 #endif /* EFSYS_OPT_FALCON || EFSYS_OPT_SIENA */
77 static efx_filter_ops_t __efx_filter_falcon_ops = {
78 falconsiena_filter_init, /* efo_init */
79 falconsiena_filter_fini, /* efo_fini */
80 falconsiena_filter_restore, /* efo_restore */
81 falconsiena_filter_add, /* efo_add */
82 falconsiena_filter_delete, /* efo_delete */
83 falconsiena_filter_supported_filters, /* efo_supported_filters */
84 NULL, /* efo_reconfigure */
86 #endif /* EFSYS_OPT_FALCON */
89 static efx_filter_ops_t __efx_filter_siena_ops = {
90 falconsiena_filter_init, /* efo_init */
91 falconsiena_filter_fini, /* efo_fini */
92 falconsiena_filter_restore, /* efo_restore */
93 falconsiena_filter_add, /* efo_add */
94 falconsiena_filter_delete, /* efo_delete */
95 falconsiena_filter_supported_filters, /* efo_supported_filters */
96 NULL, /* efo_reconfigure */
98 #endif /* EFSYS_OPT_SIENA */
100 #if EFSYS_OPT_HUNTINGTON
101 static efx_filter_ops_t __efx_filter_hunt_ops = {
102 hunt_filter_init, /* efo_init */
103 hunt_filter_fini, /* efo_fini */
104 hunt_filter_restore, /* efo_restore */
105 hunt_filter_add, /* efo_add */
106 hunt_filter_delete, /* efo_delete */
107 hunt_filter_supported_filters, /* efo_supported_filters */
108 hunt_filter_reconfigure, /* efo_reconfigure */
110 #endif /* EFSYS_OPT_HUNTINGTON */
115 __inout efx_filter_spec_t *spec)
117 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 return (efop->efo_add(enp, spec, B_FALSE));
129 __inout efx_filter_spec_t *spec)
131 efx_filter_ops_t *efop = enp->en_efop;
133 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
134 EFSYS_ASSERT3P(spec, !=, NULL);
135 EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
137 #if EFSYS_OPT_RX_SCALE
138 spec->efs_rss_context = enp->en_rss_context;
141 return (efop->efo_delete(enp, spec));
150 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
152 if ((rc = enp->en_efop->efo_restore(enp)) != 0)
158 EFSYS_PROBE1(fail1, int, rc);
167 efx_filter_ops_t *efop;
170 /* Check that efx_filter_spec_t is 64 bytes. */
171 EFX_STATIC_ASSERT(sizeof (efx_filter_spec_t) == 64);
173 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
174 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
175 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER));
177 switch (enp->en_family) {
179 case EFX_FAMILY_FALCON:
180 efop = (efx_filter_ops_t *)&__efx_filter_falcon_ops;
182 #endif /* EFSYS_OPT_FALCON */
185 case EFX_FAMILY_SIENA:
186 efop = (efx_filter_ops_t *)&__efx_filter_siena_ops;
188 #endif /* EFSYS_OPT_SIENA */
190 #if EFSYS_OPT_HUNTINGTON
191 case EFX_FAMILY_HUNTINGTON:
192 efop = (efx_filter_ops_t *)&__efx_filter_hunt_ops;
194 #endif /* EFSYS_OPT_HUNTINGTON */
202 if ((rc = efop->efo_init(enp)) != 0)
206 enp->en_mod_flags |= EFX_MOD_FILTER;
212 EFSYS_PROBE1(fail1, int, rc);
215 enp->en_mod_flags &= ~EFX_MOD_FILTER;
223 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
224 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
225 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
227 enp->en_efop->efo_fini(enp);
230 enp->en_mod_flags &= ~EFX_MOD_FILTER;
234 efx_filter_supported_filters(
236 __out uint32_t *list,
237 __out size_t *length)
241 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
242 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
243 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
244 EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL);
246 if ((rc = enp->en_efop->efo_supported_filters(enp, list, length)) != 0)
252 EFSYS_PROBE1(fail1, int, rc);
258 efx_filter_reconfigure(
260 __in_ecount(6) uint8_t const *mac_addr,
261 __in boolean_t all_unicst,
262 __in boolean_t mulcst,
263 __in boolean_t all_mulcst,
264 __in boolean_t brdcst,
265 __in_ecount(6*count) uint8_t const *addrs,
270 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
271 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
272 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
274 if (enp->en_efop->efo_reconfigure != NULL) {
275 if ((rc = enp->en_efop->efo_reconfigure(enp, mac_addr,
285 EFSYS_PROBE1(fail1, int, rc);
291 efx_filter_spec_init_rx(
292 __inout efx_filter_spec_t *spec,
293 __in efx_filter_priority_t priority,
294 __in efx_filter_flag_t flags,
297 EFSYS_ASSERT3P(spec, !=, NULL);
298 EFSYS_ASSERT3P(erp, !=, NULL);
299 EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
300 EFX_FILTER_FLAG_RX_SCATTER)) == 0);
302 memset(spec, 0, sizeof (*spec));
303 spec->efs_priority = priority;
304 spec->efs_flags = EFX_FILTER_FLAG_RX | flags;
305 spec->efs_rss_context = EFX_FILTER_SPEC_RSS_CONTEXT_DEFAULT;
306 spec->efs_dmaq_id = (uint16_t)erp->er_index;
310 efx_filter_spec_init_tx(
311 __inout efx_filter_spec_t *spec,
314 EFSYS_ASSERT3P(spec, !=, NULL);
315 EFSYS_ASSERT3P(etp, !=, NULL);
317 memset(spec, 0, sizeof (*spec));
318 spec->efs_priority = EFX_FILTER_PRI_REQUIRED;
319 spec->efs_flags = EFX_FILTER_FLAG_TX;
320 spec->efs_dmaq_id = (uint16_t)etp->et_index;
325 * Specify IPv4 host, transport protocol and port in a filter specification
328 efx_filter_spec_set_ipv4_local(
329 __inout efx_filter_spec_t *spec,
334 EFSYS_ASSERT3P(spec, !=, NULL);
336 spec->efs_match_flags |=
337 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
338 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
339 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
340 spec->efs_ip_proto = proto;
341 spec->efs_loc_host.eo_u32[0] = host;
342 spec->efs_loc_port = port;
347 * Specify IPv4 hosts, transport protocol and ports in a filter specification
350 efx_filter_spec_set_ipv4_full(
351 __inout efx_filter_spec_t *spec,
358 EFSYS_ASSERT3P(spec, !=, NULL);
360 spec->efs_match_flags |=
361 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
362 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
363 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
364 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
365 spec->efs_ip_proto = proto;
366 spec->efs_loc_host.eo_u32[0] = lhost;
367 spec->efs_loc_port = lport;
368 spec->efs_rem_host.eo_u32[0] = rhost;
369 spec->efs_rem_port = rport;
374 * Specify local Ethernet address and/or VID in filter specification
377 efx_filter_spec_set_eth_local(
378 __inout efx_filter_spec_t *spec,
380 __in const uint8_t *addr)
382 EFSYS_ASSERT3P(spec, !=, NULL);
383 EFSYS_ASSERT3P(addr, !=, NULL);
385 if (vid == EFX_FILTER_SPEC_VID_UNSPEC && addr == NULL)
388 if (vid != EFX_FILTER_SPEC_VID_UNSPEC) {
389 spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID;
390 spec->efs_outer_vid = vid;
393 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
394 memcpy(spec->efs_loc_mac, addr, EFX_MAC_ADDR_LEN);
400 * Specify matching otherwise-unmatched unicast in a filter specification
403 efx_filter_spec_set_uc_def(
404 __inout efx_filter_spec_t *spec)
406 EFSYS_ASSERT3P(spec, !=, NULL);
408 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
413 * Specify matching otherwise-unmatched multicast in a filter specification
416 efx_filter_spec_set_mc_def(
417 __inout efx_filter_spec_t *spec)
419 EFSYS_ASSERT3P(spec, !=, NULL);
421 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
422 spec->efs_loc_mac[0] = 1;
428 #if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA
431 * "Fudge factors" - difference between programmed value and actual depth.
432 * Due to pipelined implementation we need to program H/W with a value that
433 * is larger than the hop limit we want.
435 #define FILTER_CTL_SRCH_FUDGE_WILD 3
436 #define FILTER_CTL_SRCH_FUDGE_FULL 1
439 * Hard maximum hop limit. Hardware will time-out beyond 200-something.
440 * We also need to avoid infinite loops in efx_filter_search() when the
443 #define FILTER_CTL_SRCH_MAX 200
445 static __checkReturn int
446 falconsiena_filter_spec_from_gen_spec(
447 __out falconsiena_filter_spec_t *fs_spec,
448 __in efx_filter_spec_t *gen_spec)
451 boolean_t is_full = B_FALSE;
453 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX)
454 EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX);
456 EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX);
458 /* Falconsiena only has one RSS context */
459 if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
460 gen_spec->efs_rss_context != 0) {
465 fs_spec->fsfs_flags = gen_spec->efs_flags;
466 fs_spec->fsfs_dmaq_id = gen_spec->efs_dmaq_id;
468 switch (gen_spec->efs_match_flags) {
469 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
470 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
471 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT:
474 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
475 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: {
476 uint32_t rhost, host1, host2;
477 uint16_t rport, port1, port2;
479 if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) {
483 if (gen_spec->efs_loc_port == 0 ||
484 (is_full && gen_spec->efs_rem_port == 0)) {
488 switch (gen_spec->efs_ip_proto) {
489 case EFX_IPPROTO_TCP:
490 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
491 fs_spec->fsfs_type = (is_full ?
492 EFX_FS_FILTER_TX_TCP_FULL :
493 EFX_FS_FILTER_TX_TCP_WILD);
495 fs_spec->fsfs_type = (is_full ?
496 EFX_FS_FILTER_RX_TCP_FULL :
497 EFX_FS_FILTER_RX_TCP_WILD);
500 case EFX_IPPROTO_UDP:
501 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
502 fs_spec->fsfs_type = (is_full ?
503 EFX_FS_FILTER_TX_UDP_FULL :
504 EFX_FS_FILTER_TX_UDP_WILD);
506 fs_spec->fsfs_type = (is_full ?
507 EFX_FS_FILTER_RX_UDP_FULL :
508 EFX_FS_FILTER_RX_UDP_WILD);
516 * The filter is constructed in terms of source and destination,
517 * with the odd wrinkle that the ports are swapped in a UDP
518 * wildcard filter. We need to convert from local and remote
519 * addresses (zero for a wildcard).
521 rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0;
522 rport = is_full ? gen_spec->efs_rem_port : 0;
523 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
524 host1 = gen_spec->efs_loc_host.eo_u32[0];
528 host2 = gen_spec->efs_loc_host.eo_u32[0];
530 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
531 if (fs_spec->fsfs_type == EFX_FS_FILTER_TX_UDP_WILD) {
533 port2 = gen_spec->efs_loc_port;
535 port1 = gen_spec->efs_loc_port;
539 if (fs_spec->fsfs_type == EFX_FS_FILTER_RX_UDP_WILD) {
540 port1 = gen_spec->efs_loc_port;
544 port2 = gen_spec->efs_loc_port;
547 fs_spec->fsfs_dword[0] = (host1 << 16) | port1;
548 fs_spec->fsfs_dword[1] = (port2 << 16) | (host1 >> 16);
549 fs_spec->fsfs_dword[2] = host2;
553 case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID:
556 case EFX_FILTER_MATCH_LOC_MAC:
557 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
558 fs_spec->fsfs_type = (is_full ?
559 EFX_FS_FILTER_TX_MAC_FULL :
560 EFX_FS_FILTER_TX_MAC_WILD);
562 fs_spec->fsfs_type = (is_full ?
563 EFX_FS_FILTER_RX_MAC_FULL :
564 EFX_FS_FILTER_RX_MAC_WILD);
566 fs_spec->fsfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0;
567 fs_spec->fsfs_dword[1] =
568 gen_spec->efs_loc_mac[2] << 24 |
569 gen_spec->efs_loc_mac[3] << 16 |
570 gen_spec->efs_loc_mac[4] << 8 |
571 gen_spec->efs_loc_mac[5];
572 fs_spec->fsfs_dword[2] =
573 gen_spec->efs_loc_mac[0] << 8 |
574 gen_spec->efs_loc_mac[1];
578 EFSYS_ASSERT(B_FALSE);
594 EFSYS_PROBE1(fail1, int, rc);
600 * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
601 * key derived from the n-tuple.
604 falconsiena_filter_tbl_hash(
609 /* First 16 rounds */
610 tmp = 0x1fff ^ (uint16_t)(key >> 16);
611 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
612 tmp = tmp ^ tmp >> 9;
615 tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff);
616 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
617 tmp = tmp ^ tmp >> 9;
623 * To allow for hash collisions, filter search continues at these
624 * increments from the first possible entry selected by the hash.
627 falconsiena_filter_tbl_increment(
630 return ((uint16_t)(key * 2 - 1));
633 static __checkReturn boolean_t
634 falconsiena_filter_test_used(
635 __in falconsiena_filter_tbl_t *fsftp,
636 __in unsigned int index)
638 EFSYS_ASSERT3P(fsftp->fsft_bitmap, !=, NULL);
639 return ((fsftp->fsft_bitmap[index / 32] & (1 << (index % 32))) != 0);
643 falconsiena_filter_set_used(
644 __in falconsiena_filter_tbl_t *fsftp,
645 __in unsigned int index)
647 EFSYS_ASSERT3P(fsftp->fsft_bitmap, !=, NULL);
648 fsftp->fsft_bitmap[index / 32] |= (1 << (index % 32));
653 falconsiena_filter_clear_used(
654 __in falconsiena_filter_tbl_t *fsftp,
655 __in unsigned int index)
657 EFSYS_ASSERT3P(fsftp->fsft_bitmap, !=, NULL);
658 fsftp->fsft_bitmap[index / 32] &= ~(1 << (index % 32));
661 EFSYS_ASSERT3U(fsftp->fsft_used, >=, 0);
665 static falconsiena_filter_tbl_id_t
666 falconsiena_filter_tbl_id(
667 __in falconsiena_filter_type_t type)
669 falconsiena_filter_tbl_id_t tbl_id;
672 case EFX_FS_FILTER_RX_TCP_FULL:
673 case EFX_FS_FILTER_RX_TCP_WILD:
674 case EFX_FS_FILTER_RX_UDP_FULL:
675 case EFX_FS_FILTER_RX_UDP_WILD:
676 tbl_id = EFX_FS_FILTER_TBL_RX_IP;
680 case EFX_FS_FILTER_RX_MAC_FULL:
681 case EFX_FS_FILTER_RX_MAC_WILD:
682 tbl_id = EFX_FS_FILTER_TBL_RX_MAC;
685 case EFX_FS_FILTER_TX_TCP_FULL:
686 case EFX_FS_FILTER_TX_TCP_WILD:
687 case EFX_FS_FILTER_TX_UDP_FULL:
688 case EFX_FS_FILTER_TX_UDP_WILD:
689 tbl_id = EFX_FS_FILTER_TBL_TX_IP;
692 case EFX_FS_FILTER_TX_MAC_FULL:
693 case EFX_FS_FILTER_TX_MAC_WILD:
694 tbl_id = EFX_FS_FILTER_TBL_TX_MAC;
696 #endif /* EFSYS_OPT_SIENA */
699 EFSYS_ASSERT(B_FALSE);
700 tbl_id = EFX_FS_FILTER_NTBLS;
707 falconsiena_filter_reset_search_depth(
708 __inout falconsiena_filter_t *fsfp,
709 __in falconsiena_filter_tbl_id_t tbl_id)
712 case EFX_FS_FILTER_TBL_RX_IP:
713 fsfp->fsf_depth[EFX_FS_FILTER_RX_TCP_FULL] = 0;
714 fsfp->fsf_depth[EFX_FS_FILTER_RX_TCP_WILD] = 0;
715 fsfp->fsf_depth[EFX_FS_FILTER_RX_UDP_FULL] = 0;
716 fsfp->fsf_depth[EFX_FS_FILTER_RX_UDP_WILD] = 0;
720 case EFX_FS_FILTER_TBL_RX_MAC:
721 fsfp->fsf_depth[EFX_FS_FILTER_RX_MAC_FULL] = 0;
722 fsfp->fsf_depth[EFX_FS_FILTER_RX_MAC_WILD] = 0;
725 case EFX_FS_FILTER_TBL_TX_IP:
726 fsfp->fsf_depth[EFX_FS_FILTER_TX_TCP_FULL] = 0;
727 fsfp->fsf_depth[EFX_FS_FILTER_TX_TCP_WILD] = 0;
728 fsfp->fsf_depth[EFX_FS_FILTER_TX_UDP_FULL] = 0;
729 fsfp->fsf_depth[EFX_FS_FILTER_TX_UDP_WILD] = 0;
732 case EFX_FS_FILTER_TBL_TX_MAC:
733 fsfp->fsf_depth[EFX_FS_FILTER_TX_MAC_FULL] = 0;
734 fsfp->fsf_depth[EFX_FS_FILTER_TX_MAC_WILD] = 0;
736 #endif /* EFSYS_OPT_SIENA */
739 EFSYS_ASSERT(B_FALSE);
745 falconsiena_filter_push_rx_limits(
748 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_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 fsfp->fsf_depth[EFX_FS_FILTER_RX_TCP_FULL] +
755 FILTER_CTL_SRCH_FUDGE_FULL);
756 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT,
757 fsfp->fsf_depth[EFX_FS_FILTER_RX_TCP_WILD] +
758 FILTER_CTL_SRCH_FUDGE_WILD);
759 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT,
760 fsfp->fsf_depth[EFX_FS_FILTER_RX_UDP_FULL] +
761 FILTER_CTL_SRCH_FUDGE_FULL);
762 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT,
763 fsfp->fsf_depth[EFX_FS_FILTER_RX_UDP_WILD] +
764 FILTER_CTL_SRCH_FUDGE_WILD);
767 if (fsfp->fsf_tbl[EFX_FS_FILTER_TBL_RX_MAC].fsft_size) {
768 EFX_SET_OWORD_FIELD(oword,
769 FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
770 fsfp->fsf_depth[EFX_FS_FILTER_RX_MAC_FULL] +
771 FILTER_CTL_SRCH_FUDGE_FULL);
772 EFX_SET_OWORD_FIELD(oword,
773 FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
774 fsfp->fsf_depth[EFX_FS_FILTER_RX_MAC_WILD] +
775 FILTER_CTL_SRCH_FUDGE_WILD);
777 #endif /* EFSYS_OPT_SIENA */
779 EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
783 falconsiena_filter_push_tx_limits(
786 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter;
789 EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
791 if (fsfp->fsf_tbl[EFX_FS_FILTER_TBL_TX_IP].fsft_size != 0) {
792 EFX_SET_OWORD_FIELD(oword,
793 FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE,
794 fsfp->fsf_depth[EFX_FS_FILTER_TX_TCP_FULL] +
795 FILTER_CTL_SRCH_FUDGE_FULL);
796 EFX_SET_OWORD_FIELD(oword,
797 FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE,
798 fsfp->fsf_depth[EFX_FS_FILTER_TX_TCP_WILD] +
799 FILTER_CTL_SRCH_FUDGE_WILD);
800 EFX_SET_OWORD_FIELD(oword,
801 FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE,
802 fsfp->fsf_depth[EFX_FS_FILTER_TX_UDP_FULL] +
803 FILTER_CTL_SRCH_FUDGE_FULL);
804 EFX_SET_OWORD_FIELD(oword,
805 FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE,
806 fsfp->fsf_depth[EFX_FS_FILTER_TX_UDP_WILD] +
807 FILTER_CTL_SRCH_FUDGE_WILD);
810 if (fsfp->fsf_tbl[EFX_FS_FILTER_TBL_TX_MAC].fsft_size != 0) {
812 oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
813 fsfp->fsf_depth[EFX_FS_FILTER_TX_MAC_FULL] +
814 FILTER_CTL_SRCH_FUDGE_FULL);
816 oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
817 fsfp->fsf_depth[EFX_FS_FILTER_TX_MAC_WILD] +
818 FILTER_CTL_SRCH_FUDGE_WILD);
821 EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
824 /* Build a filter entry and return its n-tuple key. */
825 static __checkReturn uint32_t
826 falconsiena_filter_build(
827 __out efx_oword_t *filter,
828 __in falconsiena_filter_spec_t *spec)
832 uint8_t type = spec->fsfs_type;
833 uint32_t flags = spec->fsfs_flags;
835 switch (falconsiena_filter_tbl_id(type)) {
836 case EFX_FS_FILTER_TBL_RX_IP: {
837 boolean_t is_udp = (type == EFX_FS_FILTER_RX_UDP_FULL ||
838 type == EFX_FS_FILTER_RX_UDP_WILD);
839 EFX_POPULATE_OWORD_7(*filter,
841 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
843 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
844 FRF_AZ_TCP_UDP, is_udp,
845 FRF_AZ_RXQ_ID, spec->fsfs_dmaq_id,
846 EFX_DWORD_2, spec->fsfs_dword[2],
847 EFX_DWORD_1, spec->fsfs_dword[1],
848 EFX_DWORD_0, spec->fsfs_dword[0]);
854 case EFX_FS_FILTER_TBL_RX_MAC: {
855 boolean_t is_wild = (type == EFX_FS_FILTER_RX_MAC_WILD);
856 EFX_POPULATE_OWORD_7(*filter,
858 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
859 FRF_CZ_RMFT_SCATTER_EN,
860 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
861 FRF_CZ_RMFT_RXQ_ID, spec->fsfs_dmaq_id,
862 FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
863 FRF_CZ_RMFT_DEST_MAC_DW1, spec->fsfs_dword[2],
864 FRF_CZ_RMFT_DEST_MAC_DW0, spec->fsfs_dword[1],
865 FRF_CZ_RMFT_VLAN_ID, spec->fsfs_dword[0]);
869 #endif /* EFSYS_OPT_SIENA */
871 case EFX_FS_FILTER_TBL_TX_IP: {
872 boolean_t is_udp = (type == EFX_FS_FILTER_TX_UDP_FULL ||
873 type == EFX_FS_FILTER_TX_UDP_WILD);
874 EFX_POPULATE_OWORD_5(*filter,
875 FRF_CZ_TIFT_TCP_UDP, is_udp,
876 FRF_CZ_TIFT_TXQ_ID, spec->fsfs_dmaq_id,
877 EFX_DWORD_2, spec->fsfs_dword[2],
878 EFX_DWORD_1, spec->fsfs_dword[1],
879 EFX_DWORD_0, spec->fsfs_dword[0]);
880 dword3 = is_udp | spec->fsfs_dmaq_id << 1;
885 case EFX_FS_FILTER_TBL_TX_MAC: {
886 boolean_t is_wild = (type == EFX_FS_FILTER_TX_MAC_WILD);
887 EFX_POPULATE_OWORD_5(*filter,
888 FRF_CZ_TMFT_TXQ_ID, spec->fsfs_dmaq_id,
889 FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
890 FRF_CZ_TMFT_SRC_MAC_DW1, spec->fsfs_dword[2],
891 FRF_CZ_TMFT_SRC_MAC_DW0, spec->fsfs_dword[1],
892 FRF_CZ_TMFT_VLAN_ID, spec->fsfs_dword[0]);
893 dword3 = is_wild | spec->fsfs_dmaq_id << 1;
896 #endif /* EFSYS_OPT_SIENA */
899 EFSYS_ASSERT(B_FALSE);
904 spec->fsfs_dword[0] ^
905 spec->fsfs_dword[1] ^
906 spec->fsfs_dword[2] ^
912 static __checkReturn int
913 falconsiena_filter_push_entry(
914 __inout efx_nic_t *enp,
915 __in falconsiena_filter_type_t type,
917 __in efx_oword_t *eop)
922 case EFX_FS_FILTER_RX_TCP_FULL:
923 case EFX_FS_FILTER_RX_TCP_WILD:
924 case EFX_FS_FILTER_RX_UDP_FULL:
925 case EFX_FS_FILTER_RX_UDP_WILD:
926 EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index,
931 case EFX_FS_FILTER_RX_MAC_FULL:
932 case EFX_FS_FILTER_RX_MAC_WILD:
933 EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index,
937 case EFX_FS_FILTER_TX_TCP_FULL:
938 case EFX_FS_FILTER_TX_TCP_WILD:
939 case EFX_FS_FILTER_TX_UDP_FULL:
940 case EFX_FS_FILTER_TX_UDP_WILD:
941 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index,
945 case EFX_FS_FILTER_TX_MAC_FULL:
946 case EFX_FS_FILTER_TX_MAC_WILD:
947 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index,
950 #endif /* EFSYS_OPT_SIENA */
953 EFSYS_ASSERT(B_FALSE);
964 static __checkReturn boolean_t
965 falconsiena_filter_equal(
966 __in const falconsiena_filter_spec_t *left,
967 __in const falconsiena_filter_spec_t *right)
969 falconsiena_filter_tbl_id_t tbl_id;
971 tbl_id = falconsiena_filter_tbl_id(left->fsfs_type);
974 if (left->fsfs_type != right->fsfs_type)
977 if (memcmp(left->fsfs_dword, right->fsfs_dword,
978 sizeof (left->fsfs_dword)))
981 if ((tbl_id == EFX_FS_FILTER_TBL_TX_IP ||
982 tbl_id == EFX_FS_FILTER_TBL_TX_MAC) &&
983 left->fsfs_dmaq_id != right->fsfs_dmaq_id)
989 static __checkReturn int
990 falconsiena_filter_search(
991 __in falconsiena_filter_tbl_t *fsftp,
992 __in falconsiena_filter_spec_t *spec,
994 __in boolean_t for_insert,
995 __out int *filter_index,
996 __out unsigned int *depth_required)
998 unsigned hash, incr, filter_idx, depth;
1000 hash = falconsiena_filter_tbl_hash(key);
1001 incr = falconsiena_filter_tbl_increment(key);
1003 filter_idx = hash & (fsftp->fsft_size - 1);
1008 * Return success if entry is used and matches this spec
1009 * or entry is unused and we are trying to insert.
1011 if (falconsiena_filter_test_used(fsftp, filter_idx) ?
1012 falconsiena_filter_equal(spec,
1013 &fsftp->fsft_spec[filter_idx]) :
1015 *filter_index = filter_idx;
1016 *depth_required = depth;
1020 /* Return failure if we reached the maximum search depth */
1021 if (depth == FILTER_CTL_SRCH_MAX)
1022 return (for_insert ? EBUSY : ENOENT);
1024 filter_idx = (filter_idx + incr) & (fsftp->fsft_size - 1);
1030 falconsiena_filter_clear_entry(
1031 __in efx_nic_t *enp,
1032 __in falconsiena_filter_tbl_t *fsftp,
1037 if (falconsiena_filter_test_used(fsftp, index)) {
1038 falconsiena_filter_clear_used(fsftp, index);
1040 EFX_ZERO_OWORD(filter);
1041 falconsiena_filter_push_entry(enp,
1042 fsftp->fsft_spec[index].fsfs_type,
1045 memset(&fsftp->fsft_spec[index],
1046 0, sizeof (fsftp->fsft_spec[0]));
1051 falconsiena_filter_tbl_clear(
1052 __in efx_nic_t *enp,
1053 __in falconsiena_filter_tbl_id_t tbl_id)
1055 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter;
1056 falconsiena_filter_tbl_t *fsftp = &fsfp->fsf_tbl[tbl_id];
1060 EFSYS_LOCK(enp->en_eslp, state);
1062 for (index = 0; index < fsftp->fsft_size; ++index) {
1063 falconsiena_filter_clear_entry(enp, fsftp, index);
1066 if (fsftp->fsft_used == 0)
1067 falconsiena_filter_reset_search_depth(fsfp, tbl_id);
1069 EFSYS_UNLOCK(enp->en_eslp, state);
1072 static __checkReturn int
1073 falconsiena_filter_init(
1074 __in efx_nic_t *enp)
1076 falconsiena_filter_t *fsfp;
1077 falconsiena_filter_tbl_t *fsftp;
1081 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (falconsiena_filter_t), fsfp);
1088 enp->en_filter.ef_falconsiena_filter = fsfp;
1090 switch (enp->en_family) {
1091 #if EFSYS_OPT_FALCON
1092 case EFX_FAMILY_FALCON:
1093 fsftp = &fsfp->fsf_tbl[EFX_FS_FILTER_TBL_RX_IP];
1094 fsftp->fsft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
1096 #endif /* EFSYS_OPT_FALCON */
1099 case EFX_FAMILY_SIENA:
1100 fsftp = &fsfp->fsf_tbl[EFX_FS_FILTER_TBL_RX_IP];
1101 fsftp->fsft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
1103 fsftp = &fsfp->fsf_tbl[EFX_FS_FILTER_TBL_RX_MAC];
1104 fsftp->fsft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
1106 fsftp = &fsfp->fsf_tbl[EFX_FS_FILTER_TBL_TX_IP];
1107 fsftp->fsft_size = FR_CZ_TX_FILTER_TBL0_ROWS;
1109 fsftp = &fsfp->fsf_tbl[EFX_FS_FILTER_TBL_TX_MAC];
1110 fsftp->fsft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
1112 #endif /* EFSYS_OPT_SIENA */
1119 for (tbl_id = 0; tbl_id < EFX_FS_FILTER_NTBLS; tbl_id++) {
1120 unsigned int bitmap_size;
1122 fsftp = &fsfp->fsf_tbl[tbl_id];
1123 if (fsftp->fsft_size == 0)
1126 EFX_STATIC_ASSERT(sizeof (fsftp->fsft_bitmap[0]) ==
1129 (fsftp->fsft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1131 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, fsftp->fsft_bitmap);
1132 if (!fsftp->fsft_bitmap) {
1137 EFSYS_KMEM_ALLOC(enp->en_esip,
1138 fsftp->fsft_size * sizeof (*fsftp->fsft_spec),
1140 if (!fsftp->fsft_spec) {
1144 memset(fsftp->fsft_spec, 0,
1145 fsftp->fsft_size * sizeof (*fsftp->fsft_spec));
1158 falconsiena_filter_fini(enp);
1161 EFSYS_PROBE1(fail1, int, rc);
1166 falconsiena_filter_fini(
1167 __in efx_nic_t *enp)
1169 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter;
1170 falconsiena_filter_tbl_id_t tbl_id;
1172 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1173 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1178 for (tbl_id = 0; tbl_id < EFX_FS_FILTER_NTBLS; tbl_id++) {
1179 falconsiena_filter_tbl_t *fsftp = &fsfp->fsf_tbl[tbl_id];
1180 unsigned int bitmap_size;
1182 EFX_STATIC_ASSERT(sizeof (fsftp->fsft_bitmap[0]) ==
1185 (fsftp->fsft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1187 if (fsftp->fsft_bitmap != NULL) {
1188 EFSYS_KMEM_FREE(enp->en_esip, bitmap_size,
1189 fsftp->fsft_bitmap);
1190 fsftp->fsft_bitmap = NULL;
1193 if (fsftp->fsft_spec != NULL) {
1194 EFSYS_KMEM_FREE(enp->en_esip, fsftp->fsft_size *
1195 sizeof (*fsftp->fsft_spec), fsftp->fsft_spec);
1196 fsftp->fsft_spec = NULL;
1200 EFSYS_KMEM_FREE(enp->en_esip, sizeof (falconsiena_filter_t),
1201 enp->en_filter.ef_falconsiena_filter);
1204 /* Restore filter state after a reset */
1205 static __checkReturn int
1206 falconsiena_filter_restore(
1207 __in efx_nic_t *enp)
1209 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter;
1210 falconsiena_filter_tbl_id_t tbl_id;
1211 falconsiena_filter_tbl_t *fsftp;
1212 falconsiena_filter_spec_t *spec;
1218 EFSYS_LOCK(enp->en_eslp, state);
1220 for (tbl_id = 0; tbl_id < EFX_FS_FILTER_NTBLS; tbl_id++) {
1221 fsftp = &fsfp->fsf_tbl[tbl_id];
1222 for (filter_idx = 0;
1223 filter_idx < fsftp->fsft_size;
1225 if (!falconsiena_filter_test_used(fsftp, filter_idx))
1228 spec = &fsftp->fsft_spec[filter_idx];
1229 if ((rc = falconsiena_filter_build(&filter, spec)) != 0)
1231 if ((rc = falconsiena_filter_push_entry(enp,
1232 spec->fsfs_type, filter_idx, &filter)) != 0)
1237 falconsiena_filter_push_rx_limits(enp);
1238 falconsiena_filter_push_tx_limits(enp);
1240 EFSYS_UNLOCK(enp->en_eslp, state);
1248 EFSYS_PROBE1(fail1, int, rc);
1250 EFSYS_UNLOCK(enp->en_eslp, state);
1255 static __checkReturn int
1256 falconsiena_filter_add(
1257 __in efx_nic_t *enp,
1258 __inout efx_filter_spec_t *spec,
1259 __in boolean_t may_replace)
1262 falconsiena_filter_spec_t fs_spec;
1263 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter;
1264 falconsiena_filter_tbl_id_t tbl_id;
1265 falconsiena_filter_tbl_t *fsftp;
1266 falconsiena_filter_spec_t *saved_fs_spec;
1274 EFSYS_ASSERT3P(spec, !=, NULL);
1276 if ((rc = falconsiena_filter_spec_from_gen_spec(&fs_spec, spec)) != 0)
1279 tbl_id = falconsiena_filter_tbl_id(fs_spec.fsfs_type);
1280 fsftp = &fsfp->fsf_tbl[tbl_id];
1282 if (fsftp->fsft_size == 0) {
1287 key = falconsiena_filter_build(&filter, &fs_spec);
1289 EFSYS_LOCK(enp->en_eslp, state);
1291 rc = falconsiena_filter_search(fsftp, &fs_spec, key, B_TRUE,
1292 &filter_idx, &depth);
1296 EFSYS_ASSERT3U(filter_idx, <, fsftp->fsft_size);
1297 saved_fs_spec = &fsftp->fsft_spec[filter_idx];
1299 if (falconsiena_filter_test_used(fsftp, filter_idx)) {
1300 if (may_replace == B_FALSE) {
1305 falconsiena_filter_set_used(fsftp, filter_idx);
1306 *saved_fs_spec = fs_spec;
1308 if (fsfp->fsf_depth[fs_spec.fsfs_type] < depth) {
1309 fsfp->fsf_depth[fs_spec.fsfs_type] = depth;
1310 if (tbl_id == EFX_FS_FILTER_TBL_TX_IP ||
1311 tbl_id == EFX_FS_FILTER_TBL_TX_MAC)
1312 falconsiena_filter_push_tx_limits(enp);
1314 falconsiena_filter_push_rx_limits(enp);
1317 falconsiena_filter_push_entry(enp, fs_spec.fsfs_type,
1318 filter_idx, &filter);
1320 EFSYS_UNLOCK(enp->en_eslp, state);
1327 EFSYS_UNLOCK(enp->en_eslp, state);
1334 EFSYS_PROBE1(fail1, int, rc);
1338 static __checkReturn int
1339 falconsiena_filter_delete(
1340 __in efx_nic_t *enp,
1341 __inout efx_filter_spec_t *spec)
1344 falconsiena_filter_spec_t fs_spec;
1345 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter;
1346 falconsiena_filter_tbl_id_t tbl_id;
1347 falconsiena_filter_tbl_t *fsftp;
1348 falconsiena_filter_spec_t *saved_spec;
1355 EFSYS_ASSERT3P(spec, !=, NULL);
1357 if ((rc = falconsiena_filter_spec_from_gen_spec(&fs_spec, spec)) != 0)
1360 tbl_id = falconsiena_filter_tbl_id(fs_spec.fsfs_type);
1361 fsftp = &fsfp->fsf_tbl[tbl_id];
1363 key = falconsiena_filter_build(&filter, &fs_spec);
1365 EFSYS_LOCK(enp->en_eslp, state);
1367 rc = falconsiena_filter_search(fsftp, &fs_spec, key, B_FALSE,
1368 &filter_idx, &depth);
1372 saved_spec = &fsftp->fsft_spec[filter_idx];
1374 falconsiena_filter_clear_entry(enp, fsftp, filter_idx);
1375 if (fsftp->fsft_used == 0)
1376 falconsiena_filter_reset_search_depth(fsfp, tbl_id);
1378 EFSYS_UNLOCK(enp->en_eslp, state);
1382 EFSYS_UNLOCK(enp->en_eslp, state);
1386 EFSYS_PROBE1(fail1, int, rc);
1390 #define MAX_SUPPORTED 4
1392 static __checkReturn int
1393 falconsiena_filter_supported_filters(
1394 __in efx_nic_t *enp,
1395 __out uint32_t *list,
1396 __out size_t *length)
1399 uint32_t rx_matches[MAX_SUPPORTED];
1407 rx_matches[index++] =
1408 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1409 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
1410 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
1412 rx_matches[index++] =
1413 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1414 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
1416 if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) {
1417 rx_matches[index++] =
1418 EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC;
1420 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC;
1423 EFSYS_ASSERT3U(index, <=, MAX_SUPPORTED);
1426 memcpy(list, rx_matches, *length);
1435 #undef MAX_SUPPORTED
1437 #endif /* EFSYS_OPT_FALCON || EFSYS_OPT_SIENA */
1439 #endif /* EFSYS_OPT_FILTER */