2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2007-2016 Solarflare Communications Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * The views and conclusions contained in the software and documentation are
29 * those of the authors and should not be interpreted as representing official
30 * policies, either expressed or implied, of the FreeBSD Project.
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
44 static __checkReturn efx_rc_t
52 static __checkReturn efx_rc_t
56 static __checkReturn efx_rc_t
59 __inout efx_filter_spec_t *spec,
60 __in boolean_t may_replace);
62 static __checkReturn efx_rc_t
65 __inout efx_filter_spec_t *spec);
67 static __checkReturn efx_rc_t
68 siena_filter_supported_filters(
70 __out_ecount(buffer_length) uint32_t *buffer,
71 __in size_t buffer_length,
72 __out size_t *list_lengthp);
74 #endif /* EFSYS_OPT_SIENA */
77 static const efx_filter_ops_t __efx_filter_siena_ops = {
78 siena_filter_init, /* efo_init */
79 siena_filter_fini, /* efo_fini */
80 siena_filter_restore, /* efo_restore */
81 siena_filter_add, /* efo_add */
82 siena_filter_delete, /* efo_delete */
83 siena_filter_supported_filters, /* efo_supported_filters */
84 NULL, /* efo_reconfigure */
86 #endif /* EFSYS_OPT_SIENA */
88 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
89 static const efx_filter_ops_t __efx_filter_ef10_ops = {
90 ef10_filter_init, /* efo_init */
91 ef10_filter_fini, /* efo_fini */
92 ef10_filter_restore, /* efo_restore */
93 ef10_filter_add, /* efo_add */
94 ef10_filter_delete, /* efo_delete */
95 ef10_filter_supported_filters, /* efo_supported_filters */
96 ef10_filter_reconfigure, /* efo_reconfigure */
98 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
100 __checkReturn efx_rc_t
103 __inout efx_filter_spec_t *spec)
105 const efx_filter_ops_t *efop = enp->en_efop;
107 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
108 EFSYS_ASSERT3P(spec, !=, NULL);
109 EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
111 return (efop->efo_add(enp, spec, B_FALSE));
114 __checkReturn efx_rc_t
117 __inout efx_filter_spec_t *spec)
119 const efx_filter_ops_t *efop = enp->en_efop;
121 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
122 EFSYS_ASSERT3P(spec, !=, NULL);
123 EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
125 #if EFSYS_OPT_RX_SCALE
126 spec->efs_rss_context = enp->en_rss_context;
129 return (efop->efo_delete(enp, spec));
132 __checkReturn efx_rc_t
138 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
140 if ((rc = enp->en_efop->efo_restore(enp)) != 0)
146 EFSYS_PROBE1(fail1, efx_rc_t, rc);
151 __checkReturn efx_rc_t
155 const efx_filter_ops_t *efop;
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;
219 * Query the possible combinations of match flags which can be filtered on.
220 * These are returned as a list, of which each 32 bit element is a bitmask
221 * formed of EFX_FILTER_MATCH flags.
223 * The combinations are ordered in priority from highest to lowest.
225 * If the provided buffer is too short to hold the list, the call with fail with
226 * ENOSPC and *list_lengthp will be set to the buffer length required.
228 __checkReturn efx_rc_t
229 efx_filter_supported_filters(
231 __out_ecount(buffer_length) uint32_t *buffer,
232 __in size_t buffer_length,
233 __out size_t *list_lengthp)
237 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
238 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
239 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
240 EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL);
242 if (buffer == NULL) {
247 rc = enp->en_efop->efo_supported_filters(enp, buffer, buffer_length,
257 EFSYS_PROBE1(fail1, efx_rc_t, rc);
262 __checkReturn efx_rc_t
263 efx_filter_reconfigure(
265 __in_ecount(6) uint8_t const *mac_addr,
266 __in boolean_t all_unicst,
267 __in boolean_t mulcst,
268 __in boolean_t all_mulcst,
269 __in boolean_t brdcst,
270 __in_ecount(6*count) uint8_t const *addrs,
275 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
276 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
277 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
279 if (enp->en_efop->efo_reconfigure != NULL) {
280 if ((rc = enp->en_efop->efo_reconfigure(enp, mac_addr,
290 EFSYS_PROBE1(fail1, efx_rc_t, rc);
296 efx_filter_spec_init_rx(
297 __out efx_filter_spec_t *spec,
298 __in efx_filter_priority_t priority,
299 __in efx_filter_flags_t flags,
302 EFSYS_ASSERT3P(spec, !=, NULL);
303 EFSYS_ASSERT3P(erp, !=, NULL);
304 EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
305 EFX_FILTER_FLAG_RX_SCATTER)) == 0);
307 memset(spec, 0, sizeof (*spec));
308 spec->efs_priority = priority;
309 spec->efs_flags = EFX_FILTER_FLAG_RX | flags;
310 spec->efs_rss_context = EFX_FILTER_SPEC_RSS_CONTEXT_DEFAULT;
311 spec->efs_dmaq_id = (uint16_t)erp->er_index;
315 efx_filter_spec_init_tx(
316 __out efx_filter_spec_t *spec,
319 EFSYS_ASSERT3P(spec, !=, NULL);
320 EFSYS_ASSERT3P(etp, !=, NULL);
322 memset(spec, 0, sizeof (*spec));
323 spec->efs_priority = EFX_FILTER_PRI_REQUIRED;
324 spec->efs_flags = EFX_FILTER_FLAG_TX;
325 spec->efs_dmaq_id = (uint16_t)etp->et_index;
330 * Specify IPv4 host, transport protocol and port in a filter specification
332 __checkReturn efx_rc_t
333 efx_filter_spec_set_ipv4_local(
334 __inout efx_filter_spec_t *spec,
339 EFSYS_ASSERT3P(spec, !=, NULL);
341 spec->efs_match_flags |=
342 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
343 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
344 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
345 spec->efs_ip_proto = proto;
346 spec->efs_loc_host.eo_u32[0] = host;
347 spec->efs_loc_port = port;
352 * Specify IPv4 hosts, transport protocol and ports in a filter specification
354 __checkReturn efx_rc_t
355 efx_filter_spec_set_ipv4_full(
356 __inout efx_filter_spec_t *spec,
363 EFSYS_ASSERT3P(spec, !=, NULL);
365 spec->efs_match_flags |=
366 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
367 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
368 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
369 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
370 spec->efs_ip_proto = proto;
371 spec->efs_loc_host.eo_u32[0] = lhost;
372 spec->efs_loc_port = lport;
373 spec->efs_rem_host.eo_u32[0] = rhost;
374 spec->efs_rem_port = rport;
379 * Specify local Ethernet address and/or VID in filter specification
381 __checkReturn efx_rc_t
382 efx_filter_spec_set_eth_local(
383 __inout efx_filter_spec_t *spec,
385 __in const uint8_t *addr)
387 EFSYS_ASSERT3P(spec, !=, NULL);
388 EFSYS_ASSERT3P(addr, !=, NULL);
390 if (vid == EFX_FILTER_SPEC_VID_UNSPEC && addr == NULL)
393 if (vid != EFX_FILTER_SPEC_VID_UNSPEC) {
394 spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID;
395 spec->efs_outer_vid = vid;
398 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
399 memcpy(spec->efs_loc_mac, addr, EFX_MAC_ADDR_LEN);
405 * Specify matching otherwise-unmatched unicast in a filter specification
407 __checkReturn efx_rc_t
408 efx_filter_spec_set_uc_def(
409 __inout efx_filter_spec_t *spec)
411 EFSYS_ASSERT3P(spec, !=, NULL);
413 spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_UCAST_DST;
418 * Specify matching otherwise-unmatched multicast in a filter specification
420 __checkReturn efx_rc_t
421 efx_filter_spec_set_mc_def(
422 __inout efx_filter_spec_t *spec)
424 EFSYS_ASSERT3P(spec, !=, NULL);
426 spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
435 * "Fudge factors" - difference between programmed value and actual depth.
436 * Due to pipelined implementation we need to program H/W with a value that
437 * is larger than the hop limit we want.
439 #define FILTER_CTL_SRCH_FUDGE_WILD 3
440 #define FILTER_CTL_SRCH_FUDGE_FULL 1
443 * Hard maximum hop limit. Hardware will time-out beyond 200-something.
444 * We also need to avoid infinite loops in efx_filter_search() when the
447 #define FILTER_CTL_SRCH_MAX 200
449 static __checkReturn efx_rc_t
450 siena_filter_spec_from_gen_spec(
451 __out siena_filter_spec_t *sf_spec,
452 __in efx_filter_spec_t *gen_spec)
455 boolean_t is_full = B_FALSE;
457 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX)
458 EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX);
460 EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX);
462 /* Falconsiena only has one RSS context */
463 if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
464 gen_spec->efs_rss_context != 0) {
469 sf_spec->sfs_flags = gen_spec->efs_flags;
470 sf_spec->sfs_dmaq_id = gen_spec->efs_dmaq_id;
472 switch (gen_spec->efs_match_flags) {
473 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
474 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
475 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT:
478 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
479 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: {
480 uint32_t rhost, host1, host2;
481 uint16_t rport, port1, port2;
483 if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) {
487 if (gen_spec->efs_loc_port == 0 ||
488 (is_full && gen_spec->efs_rem_port == 0)) {
492 switch (gen_spec->efs_ip_proto) {
493 case EFX_IPPROTO_TCP:
494 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
495 sf_spec->sfs_type = (is_full ?
496 EFX_SIENA_FILTER_TX_TCP_FULL :
497 EFX_SIENA_FILTER_TX_TCP_WILD);
499 sf_spec->sfs_type = (is_full ?
500 EFX_SIENA_FILTER_RX_TCP_FULL :
501 EFX_SIENA_FILTER_RX_TCP_WILD);
504 case EFX_IPPROTO_UDP:
505 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
506 sf_spec->sfs_type = (is_full ?
507 EFX_SIENA_FILTER_TX_UDP_FULL :
508 EFX_SIENA_FILTER_TX_UDP_WILD);
510 sf_spec->sfs_type = (is_full ?
511 EFX_SIENA_FILTER_RX_UDP_FULL :
512 EFX_SIENA_FILTER_RX_UDP_WILD);
520 * The filter is constructed in terms of source and destination,
521 * with the odd wrinkle that the ports are swapped in a UDP
522 * wildcard filter. We need to convert from local and remote
523 * addresses (zero for a wildcard).
525 rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0;
526 rport = is_full ? gen_spec->efs_rem_port : 0;
527 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
528 host1 = gen_spec->efs_loc_host.eo_u32[0];
532 host2 = gen_spec->efs_loc_host.eo_u32[0];
534 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
535 if (sf_spec->sfs_type ==
536 EFX_SIENA_FILTER_TX_UDP_WILD) {
538 port2 = gen_spec->efs_loc_port;
540 port1 = gen_spec->efs_loc_port;
544 if (sf_spec->sfs_type ==
545 EFX_SIENA_FILTER_RX_UDP_WILD) {
546 port1 = gen_spec->efs_loc_port;
550 port2 = gen_spec->efs_loc_port;
553 sf_spec->sfs_dword[0] = (host1 << 16) | port1;
554 sf_spec->sfs_dword[1] = (port2 << 16) | (host1 >> 16);
555 sf_spec->sfs_dword[2] = host2;
559 case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID:
562 case EFX_FILTER_MATCH_LOC_MAC:
563 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
564 sf_spec->sfs_type = (is_full ?
565 EFX_SIENA_FILTER_TX_MAC_FULL :
566 EFX_SIENA_FILTER_TX_MAC_WILD);
568 sf_spec->sfs_type = (is_full ?
569 EFX_SIENA_FILTER_RX_MAC_FULL :
570 EFX_SIENA_FILTER_RX_MAC_WILD);
572 sf_spec->sfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0;
573 sf_spec->sfs_dword[1] =
574 gen_spec->efs_loc_mac[2] << 24 |
575 gen_spec->efs_loc_mac[3] << 16 |
576 gen_spec->efs_loc_mac[4] << 8 |
577 gen_spec->efs_loc_mac[5];
578 sf_spec->sfs_dword[2] =
579 gen_spec->efs_loc_mac[0] << 8 |
580 gen_spec->efs_loc_mac[1];
584 EFSYS_ASSERT(B_FALSE);
600 EFSYS_PROBE1(fail1, efx_rc_t, rc);
606 * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
607 * key derived from the n-tuple.
610 siena_filter_tbl_hash(
615 /* First 16 rounds */
616 tmp = 0x1fff ^ (uint16_t)(key >> 16);
617 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
618 tmp = tmp ^ tmp >> 9;
621 tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff);
622 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
623 tmp = tmp ^ tmp >> 9;
629 * To allow for hash collisions, filter search continues at these
630 * increments from the first possible entry selected by the hash.
633 siena_filter_tbl_increment(
636 return ((uint16_t)(key * 2 - 1));
639 static __checkReturn boolean_t
640 siena_filter_test_used(
641 __in siena_filter_tbl_t *sftp,
642 __in unsigned int index)
644 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
645 return ((sftp->sft_bitmap[index / 32] & (1 << (index % 32))) != 0);
649 siena_filter_set_used(
650 __in siena_filter_tbl_t *sftp,
651 __in unsigned int index)
653 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
654 sftp->sft_bitmap[index / 32] |= (1 << (index % 32));
659 siena_filter_clear_used(
660 __in siena_filter_tbl_t *sftp,
661 __in unsigned int index)
663 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
664 sftp->sft_bitmap[index / 32] &= ~(1 << (index % 32));
667 EFSYS_ASSERT3U(sftp->sft_used, >=, 0);
671 static siena_filter_tbl_id_t
673 __in siena_filter_type_t type)
675 siena_filter_tbl_id_t tbl_id;
678 case EFX_SIENA_FILTER_RX_TCP_FULL:
679 case EFX_SIENA_FILTER_RX_TCP_WILD:
680 case EFX_SIENA_FILTER_RX_UDP_FULL:
681 case EFX_SIENA_FILTER_RX_UDP_WILD:
682 tbl_id = EFX_SIENA_FILTER_TBL_RX_IP;
685 case EFX_SIENA_FILTER_RX_MAC_FULL:
686 case EFX_SIENA_FILTER_RX_MAC_WILD:
687 tbl_id = EFX_SIENA_FILTER_TBL_RX_MAC;
690 case EFX_SIENA_FILTER_TX_TCP_FULL:
691 case EFX_SIENA_FILTER_TX_TCP_WILD:
692 case EFX_SIENA_FILTER_TX_UDP_FULL:
693 case EFX_SIENA_FILTER_TX_UDP_WILD:
694 tbl_id = EFX_SIENA_FILTER_TBL_TX_IP;
697 case EFX_SIENA_FILTER_TX_MAC_FULL:
698 case EFX_SIENA_FILTER_TX_MAC_WILD:
699 tbl_id = EFX_SIENA_FILTER_TBL_TX_MAC;
703 EFSYS_ASSERT(B_FALSE);
704 tbl_id = EFX_SIENA_FILTER_NTBLS;
711 siena_filter_reset_search_depth(
712 __inout siena_filter_t *sfp,
713 __in siena_filter_tbl_id_t tbl_id)
716 case EFX_SIENA_FILTER_TBL_RX_IP:
717 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] = 0;
718 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] = 0;
719 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] = 0;
720 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] = 0;
723 case EFX_SIENA_FILTER_TBL_RX_MAC:
724 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] = 0;
725 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] = 0;
728 case EFX_SIENA_FILTER_TBL_TX_IP:
729 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] = 0;
730 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] = 0;
731 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] = 0;
732 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] = 0;
735 case EFX_SIENA_FILTER_TBL_TX_MAC:
736 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] = 0;
737 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] = 0;
741 EFSYS_ASSERT(B_FALSE);
747 siena_filter_push_rx_limits(
750 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
753 EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
755 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT,
756 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] +
757 FILTER_CTL_SRCH_FUDGE_FULL);
758 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT,
759 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] +
760 FILTER_CTL_SRCH_FUDGE_WILD);
761 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT,
762 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] +
763 FILTER_CTL_SRCH_FUDGE_FULL);
764 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT,
765 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] +
766 FILTER_CTL_SRCH_FUDGE_WILD);
768 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC].sft_size) {
769 EFX_SET_OWORD_FIELD(oword,
770 FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
771 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] +
772 FILTER_CTL_SRCH_FUDGE_FULL);
773 EFX_SET_OWORD_FIELD(oword,
774 FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
775 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] +
776 FILTER_CTL_SRCH_FUDGE_WILD);
779 EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
783 siena_filter_push_tx_limits(
786 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
789 EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
791 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP].sft_size != 0) {
792 EFX_SET_OWORD_FIELD(oword,
793 FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE,
794 sfp->sf_depth[EFX_SIENA_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 sfp->sf_depth[EFX_SIENA_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 sfp->sf_depth[EFX_SIENA_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 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] +
807 FILTER_CTL_SRCH_FUDGE_WILD);
810 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC].sft_size != 0) {
812 oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
813 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] +
814 FILTER_CTL_SRCH_FUDGE_FULL);
816 oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
817 sfp->sf_depth[EFX_SIENA_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
827 __out efx_oword_t *filter,
828 __in siena_filter_spec_t *spec)
832 uint8_t type = spec->sfs_type;
833 uint32_t flags = spec->sfs_flags;
835 switch (siena_filter_tbl_id(type)) {
836 case EFX_SIENA_FILTER_TBL_RX_IP: {
837 boolean_t is_udp = (type == EFX_SIENA_FILTER_RX_UDP_FULL ||
838 type == EFX_SIENA_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->sfs_dmaq_id,
846 EFX_DWORD_2, spec->sfs_dword[2],
847 EFX_DWORD_1, spec->sfs_dword[1],
848 EFX_DWORD_0, spec->sfs_dword[0]);
853 case EFX_SIENA_FILTER_TBL_RX_MAC: {
854 boolean_t is_wild = (type == EFX_SIENA_FILTER_RX_MAC_WILD);
855 EFX_POPULATE_OWORD_7(*filter,
857 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
858 FRF_CZ_RMFT_SCATTER_EN,
859 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
860 FRF_CZ_RMFT_RXQ_ID, spec->sfs_dmaq_id,
861 FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
862 FRF_CZ_RMFT_DEST_MAC_DW1, spec->sfs_dword[2],
863 FRF_CZ_RMFT_DEST_MAC_DW0, spec->sfs_dword[1],
864 FRF_CZ_RMFT_VLAN_ID, spec->sfs_dword[0]);
869 case EFX_SIENA_FILTER_TBL_TX_IP: {
870 boolean_t is_udp = (type == EFX_SIENA_FILTER_TX_UDP_FULL ||
871 type == EFX_SIENA_FILTER_TX_UDP_WILD);
872 EFX_POPULATE_OWORD_5(*filter,
873 FRF_CZ_TIFT_TCP_UDP, is_udp,
874 FRF_CZ_TIFT_TXQ_ID, spec->sfs_dmaq_id,
875 EFX_DWORD_2, spec->sfs_dword[2],
876 EFX_DWORD_1, spec->sfs_dword[1],
877 EFX_DWORD_0, spec->sfs_dword[0]);
878 dword3 = is_udp | spec->sfs_dmaq_id << 1;
882 case EFX_SIENA_FILTER_TBL_TX_MAC: {
883 boolean_t is_wild = (type == EFX_SIENA_FILTER_TX_MAC_WILD);
884 EFX_POPULATE_OWORD_5(*filter,
885 FRF_CZ_TMFT_TXQ_ID, spec->sfs_dmaq_id,
886 FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
887 FRF_CZ_TMFT_SRC_MAC_DW1, spec->sfs_dword[2],
888 FRF_CZ_TMFT_SRC_MAC_DW0, spec->sfs_dword[1],
889 FRF_CZ_TMFT_VLAN_ID, spec->sfs_dword[0]);
890 dword3 = is_wild | spec->sfs_dmaq_id << 1;
895 EFSYS_ASSERT(B_FALSE);
908 static __checkReturn efx_rc_t
909 siena_filter_push_entry(
910 __inout efx_nic_t *enp,
911 __in siena_filter_type_t type,
913 __in efx_oword_t *eop)
918 case EFX_SIENA_FILTER_RX_TCP_FULL:
919 case EFX_SIENA_FILTER_RX_TCP_WILD:
920 case EFX_SIENA_FILTER_RX_UDP_FULL:
921 case EFX_SIENA_FILTER_RX_UDP_WILD:
922 EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index,
926 case EFX_SIENA_FILTER_RX_MAC_FULL:
927 case EFX_SIENA_FILTER_RX_MAC_WILD:
928 EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index,
932 case EFX_SIENA_FILTER_TX_TCP_FULL:
933 case EFX_SIENA_FILTER_TX_TCP_WILD:
934 case EFX_SIENA_FILTER_TX_UDP_FULL:
935 case EFX_SIENA_FILTER_TX_UDP_WILD:
936 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index,
940 case EFX_SIENA_FILTER_TX_MAC_FULL:
941 case EFX_SIENA_FILTER_TX_MAC_WILD:
942 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index,
947 EFSYS_ASSERT(B_FALSE);
958 static __checkReturn boolean_t
960 __in const siena_filter_spec_t *left,
961 __in const siena_filter_spec_t *right)
963 siena_filter_tbl_id_t tbl_id;
965 tbl_id = siena_filter_tbl_id(left->sfs_type);
968 if (left->sfs_type != right->sfs_type)
971 if (memcmp(left->sfs_dword, right->sfs_dword,
972 sizeof (left->sfs_dword)))
975 if ((tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
976 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) &&
977 left->sfs_dmaq_id != right->sfs_dmaq_id)
983 static __checkReturn efx_rc_t
985 __in siena_filter_tbl_t *sftp,
986 __in siena_filter_spec_t *spec,
988 __in boolean_t for_insert,
989 __out int *filter_index,
990 __out unsigned int *depth_required)
992 unsigned int hash, incr, filter_idx, depth;
994 hash = siena_filter_tbl_hash(key);
995 incr = siena_filter_tbl_increment(key);
997 filter_idx = hash & (sftp->sft_size - 1);
1002 * Return success if entry is used and matches this spec
1003 * or entry is unused and we are trying to insert.
1005 if (siena_filter_test_used(sftp, filter_idx) ?
1006 siena_filter_equal(spec,
1007 &sftp->sft_spec[filter_idx]) :
1009 *filter_index = filter_idx;
1010 *depth_required = depth;
1014 /* Return failure if we reached the maximum search depth */
1015 if (depth == FILTER_CTL_SRCH_MAX)
1016 return (for_insert ? EBUSY : ENOENT);
1018 filter_idx = (filter_idx + incr) & (sftp->sft_size - 1);
1024 siena_filter_clear_entry(
1025 __in efx_nic_t *enp,
1026 __in siena_filter_tbl_t *sftp,
1031 if (siena_filter_test_used(sftp, index)) {
1032 siena_filter_clear_used(sftp, index);
1034 EFX_ZERO_OWORD(filter);
1035 siena_filter_push_entry(enp,
1036 sftp->sft_spec[index].sfs_type,
1039 memset(&sftp->sft_spec[index],
1040 0, sizeof (sftp->sft_spec[0]));
1045 siena_filter_tbl_clear(
1046 __in efx_nic_t *enp,
1047 __in siena_filter_tbl_id_t tbl_id)
1049 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1050 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1052 efsys_lock_state_t state;
1054 EFSYS_LOCK(enp->en_eslp, state);
1056 for (index = 0; index < sftp->sft_size; ++index) {
1057 siena_filter_clear_entry(enp, sftp, index);
1060 if (sftp->sft_used == 0)
1061 siena_filter_reset_search_depth(sfp, tbl_id);
1063 EFSYS_UNLOCK(enp->en_eslp, state);
1066 static __checkReturn efx_rc_t
1068 __in efx_nic_t *enp)
1070 siena_filter_t *sfp;
1071 siena_filter_tbl_t *sftp;
1075 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (siena_filter_t), sfp);
1082 enp->en_filter.ef_siena_filter = sfp;
1084 switch (enp->en_family) {
1085 case EFX_FAMILY_SIENA:
1086 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_IP];
1087 sftp->sft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
1089 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC];
1090 sftp->sft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
1092 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP];
1093 sftp->sft_size = FR_CZ_TX_FILTER_TBL0_ROWS;
1095 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC];
1096 sftp->sft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
1104 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1105 unsigned int bitmap_size;
1107 sftp = &sfp->sf_tbl[tbl_id];
1108 if (sftp->sft_size == 0)
1111 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1114 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1116 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, sftp->sft_bitmap);
1117 if (!sftp->sft_bitmap) {
1122 EFSYS_KMEM_ALLOC(enp->en_esip,
1123 sftp->sft_size * sizeof (*sftp->sft_spec),
1125 if (!sftp->sft_spec) {
1129 memset(sftp->sft_spec, 0,
1130 sftp->sft_size * sizeof (*sftp->sft_spec));
1143 siena_filter_fini(enp);
1146 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1152 __in efx_nic_t *enp)
1154 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1155 siena_filter_tbl_id_t tbl_id;
1157 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1158 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1163 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1164 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1165 unsigned int bitmap_size;
1167 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1170 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1172 if (sftp->sft_bitmap != NULL) {
1173 EFSYS_KMEM_FREE(enp->en_esip, bitmap_size,
1175 sftp->sft_bitmap = NULL;
1178 if (sftp->sft_spec != NULL) {
1179 EFSYS_KMEM_FREE(enp->en_esip, sftp->sft_size *
1180 sizeof (*sftp->sft_spec), sftp->sft_spec);
1181 sftp->sft_spec = NULL;
1185 EFSYS_KMEM_FREE(enp->en_esip, sizeof (siena_filter_t),
1186 enp->en_filter.ef_siena_filter);
1189 /* Restore filter state after a reset */
1190 static __checkReturn efx_rc_t
1191 siena_filter_restore(
1192 __in efx_nic_t *enp)
1194 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1195 siena_filter_tbl_id_t tbl_id;
1196 siena_filter_tbl_t *sftp;
1197 siena_filter_spec_t *spec;
1200 efsys_lock_state_t state;
1204 EFSYS_LOCK(enp->en_eslp, state);
1206 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1207 sftp = &sfp->sf_tbl[tbl_id];
1208 for (filter_idx = 0;
1209 filter_idx < sftp->sft_size;
1211 if (!siena_filter_test_used(sftp, filter_idx))
1214 spec = &sftp->sft_spec[filter_idx];
1215 if ((key = siena_filter_build(&filter, spec)) == 0) {
1219 if ((rc = siena_filter_push_entry(enp,
1220 spec->sfs_type, filter_idx, &filter)) != 0)
1225 siena_filter_push_rx_limits(enp);
1226 siena_filter_push_tx_limits(enp);
1228 EFSYS_UNLOCK(enp->en_eslp, state);
1236 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1238 EFSYS_UNLOCK(enp->en_eslp, state);
1243 static __checkReturn efx_rc_t
1245 __in efx_nic_t *enp,
1246 __inout efx_filter_spec_t *spec,
1247 __in boolean_t may_replace)
1250 siena_filter_spec_t sf_spec;
1251 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1252 siena_filter_tbl_id_t tbl_id;
1253 siena_filter_tbl_t *sftp;
1254 siena_filter_spec_t *saved_sf_spec;
1258 efsys_lock_state_t state;
1262 EFSYS_ASSERT3P(spec, !=, NULL);
1264 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1267 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1268 sftp = &sfp->sf_tbl[tbl_id];
1270 if (sftp->sft_size == 0) {
1275 key = siena_filter_build(&filter, &sf_spec);
1277 EFSYS_LOCK(enp->en_eslp, state);
1279 rc = siena_filter_search(sftp, &sf_spec, key, B_TRUE,
1280 &filter_idx, &depth);
1284 EFSYS_ASSERT3U(filter_idx, <, sftp->sft_size);
1285 saved_sf_spec = &sftp->sft_spec[filter_idx];
1287 if (siena_filter_test_used(sftp, filter_idx)) {
1288 if (may_replace == B_FALSE) {
1293 siena_filter_set_used(sftp, filter_idx);
1294 *saved_sf_spec = sf_spec;
1296 if (sfp->sf_depth[sf_spec.sfs_type] < depth) {
1297 sfp->sf_depth[sf_spec.sfs_type] = depth;
1298 if (tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1299 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC)
1300 siena_filter_push_tx_limits(enp);
1302 siena_filter_push_rx_limits(enp);
1305 siena_filter_push_entry(enp, sf_spec.sfs_type,
1306 filter_idx, &filter);
1308 EFSYS_UNLOCK(enp->en_eslp, state);
1315 EFSYS_UNLOCK(enp->en_eslp, state);
1322 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1326 static __checkReturn efx_rc_t
1327 siena_filter_delete(
1328 __in efx_nic_t *enp,
1329 __inout efx_filter_spec_t *spec)
1332 siena_filter_spec_t sf_spec;
1333 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1334 siena_filter_tbl_id_t tbl_id;
1335 siena_filter_tbl_t *sftp;
1339 efsys_lock_state_t state;
1342 EFSYS_ASSERT3P(spec, !=, NULL);
1344 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1347 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1348 sftp = &sfp->sf_tbl[tbl_id];
1350 key = siena_filter_build(&filter, &sf_spec);
1352 EFSYS_LOCK(enp->en_eslp, state);
1354 rc = siena_filter_search(sftp, &sf_spec, key, B_FALSE,
1355 &filter_idx, &depth);
1359 siena_filter_clear_entry(enp, sftp, filter_idx);
1360 if (sftp->sft_used == 0)
1361 siena_filter_reset_search_depth(sfp, tbl_id);
1363 EFSYS_UNLOCK(enp->en_eslp, state);
1367 EFSYS_UNLOCK(enp->en_eslp, state);
1371 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1375 #define SIENA_MAX_SUPPORTED_MATCHES 4
1377 static __checkReturn efx_rc_t
1378 siena_filter_supported_filters(
1379 __in efx_nic_t *enp,
1380 __out_ecount(buffer_length) uint32_t *buffer,
1381 __in size_t buffer_length,
1382 __out size_t *list_lengthp)
1385 uint32_t rx_matches[SIENA_MAX_SUPPORTED_MATCHES];
1389 rx_matches[index++] =
1390 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1391 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
1392 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
1394 rx_matches[index++] =
1395 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1396 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
1398 if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) {
1399 rx_matches[index++] =
1400 EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC;
1402 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC;
1405 EFSYS_ASSERT3U(index, <=, SIENA_MAX_SUPPORTED_MATCHES);
1406 list_length = index;
1408 *list_lengthp = list_length;
1410 if (buffer_length < list_length) {
1415 memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0]));
1420 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1425 #undef MAX_SUPPORTED
1427 #endif /* EFSYS_OPT_SIENA */
1429 #endif /* EFSYS_OPT_FILTER */