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$");
42 static __checkReturn efx_rc_t
43 falconsiena_filter_init(
47 falconsiena_filter_fini(
50 static __checkReturn efx_rc_t
51 falconsiena_filter_restore(
54 static __checkReturn efx_rc_t
55 falconsiena_filter_add(
57 __inout efx_filter_spec_t *spec,
58 __in boolean_t may_replace);
60 static __checkReturn efx_rc_t
61 falconsiena_filter_delete(
63 __inout efx_filter_spec_t *spec);
65 static __checkReturn efx_rc_t
66 falconsiena_filter_supported_filters(
69 __out size_t *length);
71 #endif /* EFSYS_OPT_SIENA */
74 static efx_filter_ops_t __efx_filter_siena_ops = {
75 falconsiena_filter_init, /* efo_init */
76 falconsiena_filter_fini, /* efo_fini */
77 falconsiena_filter_restore, /* efo_restore */
78 falconsiena_filter_add, /* efo_add */
79 falconsiena_filter_delete, /* efo_delete */
80 falconsiena_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 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 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 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 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_ops_t *)&__efx_filter_siena_ops;
167 #endif /* EFSYS_OPT_SIENA */
169 #if EFSYS_OPT_HUNTINGTON
170 case EFX_FAMILY_HUNTINGTON:
171 efop = (efx_filter_ops_t *)&__efx_filter_ef10_ops;
173 #endif /* EFSYS_OPT_HUNTINGTON */
175 #if EFSYS_OPT_MEDFORD
176 case EFX_FAMILY_MEDFORD:
177 efop = (efx_filter_ops_t *)&__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 falconsiena_filter_spec_from_gen_spec(
432 __out falconsiena_filter_spec_t *fs_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 fs_spec->fsfs_flags = gen_spec->efs_flags;
451 fs_spec->fsfs_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 fs_spec->fsfs_type = (is_full ?
477 EFX_FS_FILTER_TX_TCP_FULL :
478 EFX_FS_FILTER_TX_TCP_WILD);
480 fs_spec->fsfs_type = (is_full ?
481 EFX_FS_FILTER_RX_TCP_FULL :
482 EFX_FS_FILTER_RX_TCP_WILD);
485 case EFX_IPPROTO_UDP:
486 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
487 fs_spec->fsfs_type = (is_full ?
488 EFX_FS_FILTER_TX_UDP_FULL :
489 EFX_FS_FILTER_TX_UDP_WILD);
491 fs_spec->fsfs_type = (is_full ?
492 EFX_FS_FILTER_RX_UDP_FULL :
493 EFX_FS_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 (fs_spec->fsfs_type == EFX_FS_FILTER_TX_UDP_WILD) {
518 port2 = gen_spec->efs_loc_port;
520 port1 = gen_spec->efs_loc_port;
524 if (fs_spec->fsfs_type == EFX_FS_FILTER_RX_UDP_WILD) {
525 port1 = gen_spec->efs_loc_port;
529 port2 = gen_spec->efs_loc_port;
532 fs_spec->fsfs_dword[0] = (host1 << 16) | port1;
533 fs_spec->fsfs_dword[1] = (port2 << 16) | (host1 >> 16);
534 fs_spec->fsfs_dword[2] = host2;
538 case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID:
541 case EFX_FILTER_MATCH_LOC_MAC:
542 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
543 fs_spec->fsfs_type = (is_full ?
544 EFX_FS_FILTER_TX_MAC_FULL :
545 EFX_FS_FILTER_TX_MAC_WILD);
547 fs_spec->fsfs_type = (is_full ?
548 EFX_FS_FILTER_RX_MAC_FULL :
549 EFX_FS_FILTER_RX_MAC_WILD);
551 fs_spec->fsfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0;
552 fs_spec->fsfs_dword[1] =
553 gen_spec->efs_loc_mac[2] << 24 |
554 gen_spec->efs_loc_mac[3] << 16 |
555 gen_spec->efs_loc_mac[4] << 8 |
556 gen_spec->efs_loc_mac[5];
557 fs_spec->fsfs_dword[2] =
558 gen_spec->efs_loc_mac[0] << 8 |
559 gen_spec->efs_loc_mac[1];
563 EFSYS_ASSERT(B_FALSE);
579 EFSYS_PROBE1(fail1, efx_rc_t, rc);
585 * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
586 * key derived from the n-tuple.
589 falconsiena_filter_tbl_hash(
594 /* First 16 rounds */
595 tmp = 0x1fff ^ (uint16_t)(key >> 16);
596 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
597 tmp = tmp ^ tmp >> 9;
600 tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff);
601 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
602 tmp = tmp ^ tmp >> 9;
608 * To allow for hash collisions, filter search continues at these
609 * increments from the first possible entry selected by the hash.
612 falconsiena_filter_tbl_increment(
615 return ((uint16_t)(key * 2 - 1));
618 static __checkReturn boolean_t
619 falconsiena_filter_test_used(
620 __in falconsiena_filter_tbl_t *fsftp,
621 __in unsigned int index)
623 EFSYS_ASSERT3P(fsftp->fsft_bitmap, !=, NULL);
624 return ((fsftp->fsft_bitmap[index / 32] & (1 << (index % 32))) != 0);
628 falconsiena_filter_set_used(
629 __in falconsiena_filter_tbl_t *fsftp,
630 __in unsigned int index)
632 EFSYS_ASSERT3P(fsftp->fsft_bitmap, !=, NULL);
633 fsftp->fsft_bitmap[index / 32] |= (1 << (index % 32));
638 falconsiena_filter_clear_used(
639 __in falconsiena_filter_tbl_t *fsftp,
640 __in unsigned int index)
642 EFSYS_ASSERT3P(fsftp->fsft_bitmap, !=, NULL);
643 fsftp->fsft_bitmap[index / 32] &= ~(1 << (index % 32));
646 EFSYS_ASSERT3U(fsftp->fsft_used, >=, 0);
650 static falconsiena_filter_tbl_id_t
651 falconsiena_filter_tbl_id(
652 __in falconsiena_filter_type_t type)
654 falconsiena_filter_tbl_id_t tbl_id;
657 case EFX_FS_FILTER_RX_TCP_FULL:
658 case EFX_FS_FILTER_RX_TCP_WILD:
659 case EFX_FS_FILTER_RX_UDP_FULL:
660 case EFX_FS_FILTER_RX_UDP_WILD:
661 tbl_id = EFX_FS_FILTER_TBL_RX_IP;
665 case EFX_FS_FILTER_RX_MAC_FULL:
666 case EFX_FS_FILTER_RX_MAC_WILD:
667 tbl_id = EFX_FS_FILTER_TBL_RX_MAC;
670 case EFX_FS_FILTER_TX_TCP_FULL:
671 case EFX_FS_FILTER_TX_TCP_WILD:
672 case EFX_FS_FILTER_TX_UDP_FULL:
673 case EFX_FS_FILTER_TX_UDP_WILD:
674 tbl_id = EFX_FS_FILTER_TBL_TX_IP;
677 case EFX_FS_FILTER_TX_MAC_FULL:
678 case EFX_FS_FILTER_TX_MAC_WILD:
679 tbl_id = EFX_FS_FILTER_TBL_TX_MAC;
681 #endif /* EFSYS_OPT_SIENA */
684 EFSYS_ASSERT(B_FALSE);
685 tbl_id = EFX_FS_FILTER_NTBLS;
692 falconsiena_filter_reset_search_depth(
693 __inout falconsiena_filter_t *fsfp,
694 __in falconsiena_filter_tbl_id_t tbl_id)
697 case EFX_FS_FILTER_TBL_RX_IP:
698 fsfp->fsf_depth[EFX_FS_FILTER_RX_TCP_FULL] = 0;
699 fsfp->fsf_depth[EFX_FS_FILTER_RX_TCP_WILD] = 0;
700 fsfp->fsf_depth[EFX_FS_FILTER_RX_UDP_FULL] = 0;
701 fsfp->fsf_depth[EFX_FS_FILTER_RX_UDP_WILD] = 0;
705 case EFX_FS_FILTER_TBL_RX_MAC:
706 fsfp->fsf_depth[EFX_FS_FILTER_RX_MAC_FULL] = 0;
707 fsfp->fsf_depth[EFX_FS_FILTER_RX_MAC_WILD] = 0;
710 case EFX_FS_FILTER_TBL_TX_IP:
711 fsfp->fsf_depth[EFX_FS_FILTER_TX_TCP_FULL] = 0;
712 fsfp->fsf_depth[EFX_FS_FILTER_TX_TCP_WILD] = 0;
713 fsfp->fsf_depth[EFX_FS_FILTER_TX_UDP_FULL] = 0;
714 fsfp->fsf_depth[EFX_FS_FILTER_TX_UDP_WILD] = 0;
717 case EFX_FS_FILTER_TBL_TX_MAC:
718 fsfp->fsf_depth[EFX_FS_FILTER_TX_MAC_FULL] = 0;
719 fsfp->fsf_depth[EFX_FS_FILTER_TX_MAC_WILD] = 0;
721 #endif /* EFSYS_OPT_SIENA */
724 EFSYS_ASSERT(B_FALSE);
730 falconsiena_filter_push_rx_limits(
733 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter;
736 EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
738 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT,
739 fsfp->fsf_depth[EFX_FS_FILTER_RX_TCP_FULL] +
740 FILTER_CTL_SRCH_FUDGE_FULL);
741 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT,
742 fsfp->fsf_depth[EFX_FS_FILTER_RX_TCP_WILD] +
743 FILTER_CTL_SRCH_FUDGE_WILD);
744 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT,
745 fsfp->fsf_depth[EFX_FS_FILTER_RX_UDP_FULL] +
746 FILTER_CTL_SRCH_FUDGE_FULL);
747 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT,
748 fsfp->fsf_depth[EFX_FS_FILTER_RX_UDP_WILD] +
749 FILTER_CTL_SRCH_FUDGE_WILD);
752 if (fsfp->fsf_tbl[EFX_FS_FILTER_TBL_RX_MAC].fsft_size) {
753 EFX_SET_OWORD_FIELD(oword,
754 FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
755 fsfp->fsf_depth[EFX_FS_FILTER_RX_MAC_FULL] +
756 FILTER_CTL_SRCH_FUDGE_FULL);
757 EFX_SET_OWORD_FIELD(oword,
758 FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
759 fsfp->fsf_depth[EFX_FS_FILTER_RX_MAC_WILD] +
760 FILTER_CTL_SRCH_FUDGE_WILD);
762 #endif /* EFSYS_OPT_SIENA */
764 EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
768 falconsiena_filter_push_tx_limits(
771 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter;
774 EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
776 if (fsfp->fsf_tbl[EFX_FS_FILTER_TBL_TX_IP].fsft_size != 0) {
777 EFX_SET_OWORD_FIELD(oword,
778 FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE,
779 fsfp->fsf_depth[EFX_FS_FILTER_TX_TCP_FULL] +
780 FILTER_CTL_SRCH_FUDGE_FULL);
781 EFX_SET_OWORD_FIELD(oword,
782 FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE,
783 fsfp->fsf_depth[EFX_FS_FILTER_TX_TCP_WILD] +
784 FILTER_CTL_SRCH_FUDGE_WILD);
785 EFX_SET_OWORD_FIELD(oword,
786 FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE,
787 fsfp->fsf_depth[EFX_FS_FILTER_TX_UDP_FULL] +
788 FILTER_CTL_SRCH_FUDGE_FULL);
789 EFX_SET_OWORD_FIELD(oword,
790 FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE,
791 fsfp->fsf_depth[EFX_FS_FILTER_TX_UDP_WILD] +
792 FILTER_CTL_SRCH_FUDGE_WILD);
795 if (fsfp->fsf_tbl[EFX_FS_FILTER_TBL_TX_MAC].fsft_size != 0) {
797 oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
798 fsfp->fsf_depth[EFX_FS_FILTER_TX_MAC_FULL] +
799 FILTER_CTL_SRCH_FUDGE_FULL);
801 oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
802 fsfp->fsf_depth[EFX_FS_FILTER_TX_MAC_WILD] +
803 FILTER_CTL_SRCH_FUDGE_WILD);
806 EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
809 /* Build a filter entry and return its n-tuple key. */
810 static __checkReturn uint32_t
811 falconsiena_filter_build(
812 __out efx_oword_t *filter,
813 __in falconsiena_filter_spec_t *spec)
817 uint8_t type = spec->fsfs_type;
818 uint32_t flags = spec->fsfs_flags;
820 switch (falconsiena_filter_tbl_id(type)) {
821 case EFX_FS_FILTER_TBL_RX_IP: {
822 boolean_t is_udp = (type == EFX_FS_FILTER_RX_UDP_FULL ||
823 type == EFX_FS_FILTER_RX_UDP_WILD);
824 EFX_POPULATE_OWORD_7(*filter,
826 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
828 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
829 FRF_AZ_TCP_UDP, is_udp,
830 FRF_AZ_RXQ_ID, spec->fsfs_dmaq_id,
831 EFX_DWORD_2, spec->fsfs_dword[2],
832 EFX_DWORD_1, spec->fsfs_dword[1],
833 EFX_DWORD_0, spec->fsfs_dword[0]);
839 case EFX_FS_FILTER_TBL_RX_MAC: {
840 boolean_t is_wild = (type == EFX_FS_FILTER_RX_MAC_WILD);
841 EFX_POPULATE_OWORD_7(*filter,
843 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
844 FRF_CZ_RMFT_SCATTER_EN,
845 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
846 FRF_CZ_RMFT_RXQ_ID, spec->fsfs_dmaq_id,
847 FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
848 FRF_CZ_RMFT_DEST_MAC_DW1, spec->fsfs_dword[2],
849 FRF_CZ_RMFT_DEST_MAC_DW0, spec->fsfs_dword[1],
850 FRF_CZ_RMFT_VLAN_ID, spec->fsfs_dword[0]);
854 #endif /* EFSYS_OPT_SIENA */
856 case EFX_FS_FILTER_TBL_TX_IP: {
857 boolean_t is_udp = (type == EFX_FS_FILTER_TX_UDP_FULL ||
858 type == EFX_FS_FILTER_TX_UDP_WILD);
859 EFX_POPULATE_OWORD_5(*filter,
860 FRF_CZ_TIFT_TCP_UDP, is_udp,
861 FRF_CZ_TIFT_TXQ_ID, spec->fsfs_dmaq_id,
862 EFX_DWORD_2, spec->fsfs_dword[2],
863 EFX_DWORD_1, spec->fsfs_dword[1],
864 EFX_DWORD_0, spec->fsfs_dword[0]);
865 dword3 = is_udp | spec->fsfs_dmaq_id << 1;
870 case EFX_FS_FILTER_TBL_TX_MAC: {
871 boolean_t is_wild = (type == EFX_FS_FILTER_TX_MAC_WILD);
872 EFX_POPULATE_OWORD_5(*filter,
873 FRF_CZ_TMFT_TXQ_ID, spec->fsfs_dmaq_id,
874 FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
875 FRF_CZ_TMFT_SRC_MAC_DW1, spec->fsfs_dword[2],
876 FRF_CZ_TMFT_SRC_MAC_DW0, spec->fsfs_dword[1],
877 FRF_CZ_TMFT_VLAN_ID, spec->fsfs_dword[0]);
878 dword3 = is_wild | spec->fsfs_dmaq_id << 1;
881 #endif /* EFSYS_OPT_SIENA */
884 EFSYS_ASSERT(B_FALSE);
889 spec->fsfs_dword[0] ^
890 spec->fsfs_dword[1] ^
891 spec->fsfs_dword[2] ^
897 static __checkReturn efx_rc_t
898 falconsiena_filter_push_entry(
899 __inout efx_nic_t *enp,
900 __in falconsiena_filter_type_t type,
902 __in efx_oword_t *eop)
907 case EFX_FS_FILTER_RX_TCP_FULL:
908 case EFX_FS_FILTER_RX_TCP_WILD:
909 case EFX_FS_FILTER_RX_UDP_FULL:
910 case EFX_FS_FILTER_RX_UDP_WILD:
911 EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index,
916 case EFX_FS_FILTER_RX_MAC_FULL:
917 case EFX_FS_FILTER_RX_MAC_WILD:
918 EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index,
922 case EFX_FS_FILTER_TX_TCP_FULL:
923 case EFX_FS_FILTER_TX_TCP_WILD:
924 case EFX_FS_FILTER_TX_UDP_FULL:
925 case EFX_FS_FILTER_TX_UDP_WILD:
926 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index,
930 case EFX_FS_FILTER_TX_MAC_FULL:
931 case EFX_FS_FILTER_TX_MAC_WILD:
932 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index,
935 #endif /* EFSYS_OPT_SIENA */
938 EFSYS_ASSERT(B_FALSE);
949 static __checkReturn boolean_t
950 falconsiena_filter_equal(
951 __in const falconsiena_filter_spec_t *left,
952 __in const falconsiena_filter_spec_t *right)
954 falconsiena_filter_tbl_id_t tbl_id;
956 tbl_id = falconsiena_filter_tbl_id(left->fsfs_type);
959 if (left->fsfs_type != right->fsfs_type)
962 if (memcmp(left->fsfs_dword, right->fsfs_dword,
963 sizeof (left->fsfs_dword)))
966 if ((tbl_id == EFX_FS_FILTER_TBL_TX_IP ||
967 tbl_id == EFX_FS_FILTER_TBL_TX_MAC) &&
968 left->fsfs_dmaq_id != right->fsfs_dmaq_id)
974 static __checkReturn efx_rc_t
975 falconsiena_filter_search(
976 __in falconsiena_filter_tbl_t *fsftp,
977 __in falconsiena_filter_spec_t *spec,
979 __in boolean_t for_insert,
980 __out int *filter_index,
981 __out unsigned int *depth_required)
983 unsigned hash, incr, filter_idx, depth;
985 hash = falconsiena_filter_tbl_hash(key);
986 incr = falconsiena_filter_tbl_increment(key);
988 filter_idx = hash & (fsftp->fsft_size - 1);
993 * Return success if entry is used and matches this spec
994 * or entry is unused and we are trying to insert.
996 if (falconsiena_filter_test_used(fsftp, filter_idx) ?
997 falconsiena_filter_equal(spec,
998 &fsftp->fsft_spec[filter_idx]) :
1000 *filter_index = filter_idx;
1001 *depth_required = depth;
1005 /* Return failure if we reached the maximum search depth */
1006 if (depth == FILTER_CTL_SRCH_MAX)
1007 return (for_insert ? EBUSY : ENOENT);
1009 filter_idx = (filter_idx + incr) & (fsftp->fsft_size - 1);
1015 falconsiena_filter_clear_entry(
1016 __in efx_nic_t *enp,
1017 __in falconsiena_filter_tbl_t *fsftp,
1022 if (falconsiena_filter_test_used(fsftp, index)) {
1023 falconsiena_filter_clear_used(fsftp, index);
1025 EFX_ZERO_OWORD(filter);
1026 falconsiena_filter_push_entry(enp,
1027 fsftp->fsft_spec[index].fsfs_type,
1030 memset(&fsftp->fsft_spec[index],
1031 0, sizeof (fsftp->fsft_spec[0]));
1036 falconsiena_filter_tbl_clear(
1037 __in efx_nic_t *enp,
1038 __in falconsiena_filter_tbl_id_t tbl_id)
1040 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter;
1041 falconsiena_filter_tbl_t *fsftp = &fsfp->fsf_tbl[tbl_id];
1045 EFSYS_LOCK(enp->en_eslp, state);
1047 for (index = 0; index < fsftp->fsft_size; ++index) {
1048 falconsiena_filter_clear_entry(enp, fsftp, index);
1051 if (fsftp->fsft_used == 0)
1052 falconsiena_filter_reset_search_depth(fsfp, tbl_id);
1054 EFSYS_UNLOCK(enp->en_eslp, state);
1057 static __checkReturn efx_rc_t
1058 falconsiena_filter_init(
1059 __in efx_nic_t *enp)
1061 falconsiena_filter_t *fsfp;
1062 falconsiena_filter_tbl_t *fsftp;
1066 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (falconsiena_filter_t), fsfp);
1073 enp->en_filter.ef_falconsiena_filter = fsfp;
1075 switch (enp->en_family) {
1077 case EFX_FAMILY_SIENA:
1078 fsftp = &fsfp->fsf_tbl[EFX_FS_FILTER_TBL_RX_IP];
1079 fsftp->fsft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
1081 fsftp = &fsfp->fsf_tbl[EFX_FS_FILTER_TBL_RX_MAC];
1082 fsftp->fsft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
1084 fsftp = &fsfp->fsf_tbl[EFX_FS_FILTER_TBL_TX_IP];
1085 fsftp->fsft_size = FR_CZ_TX_FILTER_TBL0_ROWS;
1087 fsftp = &fsfp->fsf_tbl[EFX_FS_FILTER_TBL_TX_MAC];
1088 fsftp->fsft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
1090 #endif /* EFSYS_OPT_SIENA */
1097 for (tbl_id = 0; tbl_id < EFX_FS_FILTER_NTBLS; tbl_id++) {
1098 unsigned int bitmap_size;
1100 fsftp = &fsfp->fsf_tbl[tbl_id];
1101 if (fsftp->fsft_size == 0)
1104 EFX_STATIC_ASSERT(sizeof (fsftp->fsft_bitmap[0]) ==
1107 (fsftp->fsft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1109 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, fsftp->fsft_bitmap);
1110 if (!fsftp->fsft_bitmap) {
1115 EFSYS_KMEM_ALLOC(enp->en_esip,
1116 fsftp->fsft_size * sizeof (*fsftp->fsft_spec),
1118 if (!fsftp->fsft_spec) {
1122 memset(fsftp->fsft_spec, 0,
1123 fsftp->fsft_size * sizeof (*fsftp->fsft_spec));
1136 falconsiena_filter_fini(enp);
1139 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1144 falconsiena_filter_fini(
1145 __in efx_nic_t *enp)
1147 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter;
1148 falconsiena_filter_tbl_id_t tbl_id;
1150 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1151 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1156 for (tbl_id = 0; tbl_id < EFX_FS_FILTER_NTBLS; tbl_id++) {
1157 falconsiena_filter_tbl_t *fsftp = &fsfp->fsf_tbl[tbl_id];
1158 unsigned int bitmap_size;
1160 EFX_STATIC_ASSERT(sizeof (fsftp->fsft_bitmap[0]) ==
1163 (fsftp->fsft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1165 if (fsftp->fsft_bitmap != NULL) {
1166 EFSYS_KMEM_FREE(enp->en_esip, bitmap_size,
1167 fsftp->fsft_bitmap);
1168 fsftp->fsft_bitmap = NULL;
1171 if (fsftp->fsft_spec != NULL) {
1172 EFSYS_KMEM_FREE(enp->en_esip, fsftp->fsft_size *
1173 sizeof (*fsftp->fsft_spec), fsftp->fsft_spec);
1174 fsftp->fsft_spec = NULL;
1178 EFSYS_KMEM_FREE(enp->en_esip, sizeof (falconsiena_filter_t),
1179 enp->en_filter.ef_falconsiena_filter);
1182 /* Restore filter state after a reset */
1183 static __checkReturn efx_rc_t
1184 falconsiena_filter_restore(
1185 __in efx_nic_t *enp)
1187 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter;
1188 falconsiena_filter_tbl_id_t tbl_id;
1189 falconsiena_filter_tbl_t *fsftp;
1190 falconsiena_filter_spec_t *spec;
1196 EFSYS_LOCK(enp->en_eslp, state);
1198 for (tbl_id = 0; tbl_id < EFX_FS_FILTER_NTBLS; tbl_id++) {
1199 fsftp = &fsfp->fsf_tbl[tbl_id];
1200 for (filter_idx = 0;
1201 filter_idx < fsftp->fsft_size;
1203 if (!falconsiena_filter_test_used(fsftp, filter_idx))
1206 spec = &fsftp->fsft_spec[filter_idx];
1207 if ((rc = falconsiena_filter_build(&filter, spec)) != 0)
1209 if ((rc = falconsiena_filter_push_entry(enp,
1210 spec->fsfs_type, filter_idx, &filter)) != 0)
1215 falconsiena_filter_push_rx_limits(enp);
1216 falconsiena_filter_push_tx_limits(enp);
1218 EFSYS_UNLOCK(enp->en_eslp, state);
1226 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1228 EFSYS_UNLOCK(enp->en_eslp, state);
1233 static __checkReturn efx_rc_t
1234 falconsiena_filter_add(
1235 __in efx_nic_t *enp,
1236 __inout efx_filter_spec_t *spec,
1237 __in boolean_t may_replace)
1240 falconsiena_filter_spec_t fs_spec;
1241 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter;
1242 falconsiena_filter_tbl_id_t tbl_id;
1243 falconsiena_filter_tbl_t *fsftp;
1244 falconsiena_filter_spec_t *saved_fs_spec;
1252 EFSYS_ASSERT3P(spec, !=, NULL);
1254 if ((rc = falconsiena_filter_spec_from_gen_spec(&fs_spec, spec)) != 0)
1257 tbl_id = falconsiena_filter_tbl_id(fs_spec.fsfs_type);
1258 fsftp = &fsfp->fsf_tbl[tbl_id];
1260 if (fsftp->fsft_size == 0) {
1265 key = falconsiena_filter_build(&filter, &fs_spec);
1267 EFSYS_LOCK(enp->en_eslp, state);
1269 rc = falconsiena_filter_search(fsftp, &fs_spec, key, B_TRUE,
1270 &filter_idx, &depth);
1274 EFSYS_ASSERT3U(filter_idx, <, fsftp->fsft_size);
1275 saved_fs_spec = &fsftp->fsft_spec[filter_idx];
1277 if (falconsiena_filter_test_used(fsftp, filter_idx)) {
1278 if (may_replace == B_FALSE) {
1283 falconsiena_filter_set_used(fsftp, filter_idx);
1284 *saved_fs_spec = fs_spec;
1286 if (fsfp->fsf_depth[fs_spec.fsfs_type] < depth) {
1287 fsfp->fsf_depth[fs_spec.fsfs_type] = depth;
1288 if (tbl_id == EFX_FS_FILTER_TBL_TX_IP ||
1289 tbl_id == EFX_FS_FILTER_TBL_TX_MAC)
1290 falconsiena_filter_push_tx_limits(enp);
1292 falconsiena_filter_push_rx_limits(enp);
1295 falconsiena_filter_push_entry(enp, fs_spec.fsfs_type,
1296 filter_idx, &filter);
1298 EFSYS_UNLOCK(enp->en_eslp, state);
1305 EFSYS_UNLOCK(enp->en_eslp, state);
1312 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1316 static __checkReturn efx_rc_t
1317 falconsiena_filter_delete(
1318 __in efx_nic_t *enp,
1319 __inout efx_filter_spec_t *spec)
1322 falconsiena_filter_spec_t fs_spec;
1323 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter;
1324 falconsiena_filter_tbl_id_t tbl_id;
1325 falconsiena_filter_tbl_t *fsftp;
1332 EFSYS_ASSERT3P(spec, !=, NULL);
1334 if ((rc = falconsiena_filter_spec_from_gen_spec(&fs_spec, spec)) != 0)
1337 tbl_id = falconsiena_filter_tbl_id(fs_spec.fsfs_type);
1338 fsftp = &fsfp->fsf_tbl[tbl_id];
1340 key = falconsiena_filter_build(&filter, &fs_spec);
1342 EFSYS_LOCK(enp->en_eslp, state);
1344 rc = falconsiena_filter_search(fsftp, &fs_spec, key, B_FALSE,
1345 &filter_idx, &depth);
1349 falconsiena_filter_clear_entry(enp, fsftp, filter_idx);
1350 if (fsftp->fsft_used == 0)
1351 falconsiena_filter_reset_search_depth(fsfp, tbl_id);
1353 EFSYS_UNLOCK(enp->en_eslp, state);
1357 EFSYS_UNLOCK(enp->en_eslp, state);
1361 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1365 #define MAX_SUPPORTED 4
1367 static __checkReturn efx_rc_t
1368 falconsiena_filter_supported_filters(
1369 __in efx_nic_t *enp,
1370 __out uint32_t *list,
1371 __out size_t *length)
1374 uint32_t rx_matches[MAX_SUPPORTED];
1382 rx_matches[index++] =
1383 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1384 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
1385 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
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;
1391 if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) {
1392 rx_matches[index++] =
1393 EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC;
1395 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC;
1398 EFSYS_ASSERT3U(index, <=, MAX_SUPPORTED);
1401 memcpy(list, rx_matches, *length);
1410 #undef MAX_SUPPORTED
1412 #endif /* EFSYS_OPT_SIENA */
1414 #endif /* EFSYS_OPT_FILTER */