2 * Copyright (c) 2007-2016 Solarflare Communications Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * The views and conclusions contained in the software and documentation are
27 * those of the authors and should not be interpreted as representing official
28 * policies, either expressed or implied, of the FreeBSD Project.
39 static __checkReturn efx_rc_t
47 static __checkReturn efx_rc_t
51 static __checkReturn efx_rc_t
54 __inout efx_filter_spec_t *spec,
55 __in boolean_t may_replace);
57 static __checkReturn efx_rc_t
60 __inout efx_filter_spec_t *spec);
62 static __checkReturn efx_rc_t
63 siena_filter_supported_filters(
66 __out size_t *length);
68 #endif /* EFSYS_OPT_SIENA */
71 static const efx_filter_ops_t __efx_filter_siena_ops = {
72 siena_filter_init, /* efo_init */
73 siena_filter_fini, /* efo_fini */
74 siena_filter_restore, /* efo_restore */
75 siena_filter_add, /* efo_add */
76 siena_filter_delete, /* efo_delete */
77 siena_filter_supported_filters, /* efo_supported_filters */
78 NULL, /* efo_reconfigure */
80 #endif /* EFSYS_OPT_SIENA */
82 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
83 static const efx_filter_ops_t __efx_filter_ef10_ops = {
84 ef10_filter_init, /* efo_init */
85 ef10_filter_fini, /* efo_fini */
86 ef10_filter_restore, /* efo_restore */
87 ef10_filter_add, /* efo_add */
88 ef10_filter_delete, /* efo_delete */
89 ef10_filter_supported_filters, /* efo_supported_filters */
90 ef10_filter_reconfigure, /* efo_reconfigure */
92 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
94 __checkReturn efx_rc_t
97 __inout efx_filter_spec_t *spec)
99 const efx_filter_ops_t *efop = enp->en_efop;
101 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
102 EFSYS_ASSERT3P(spec, !=, NULL);
103 EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
105 return (efop->efo_add(enp, spec, B_FALSE));
108 __checkReturn efx_rc_t
111 __inout efx_filter_spec_t *spec)
113 const efx_filter_ops_t *efop = enp->en_efop;
115 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
116 EFSYS_ASSERT3P(spec, !=, NULL);
117 EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
119 return (efop->efo_delete(enp, spec));
122 __checkReturn efx_rc_t
128 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
130 if ((rc = enp->en_efop->efo_restore(enp)) != 0)
136 EFSYS_PROBE1(fail1, efx_rc_t, rc);
141 __checkReturn efx_rc_t
145 const efx_filter_ops_t *efop;
148 /* Check that efx_filter_spec_t is 64 bytes. */
149 EFX_STATIC_ASSERT(sizeof (efx_filter_spec_t) == 64);
151 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
152 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
153 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER));
155 switch (enp->en_family) {
157 case EFX_FAMILY_SIENA:
158 efop = &__efx_filter_siena_ops;
160 #endif /* EFSYS_OPT_SIENA */
162 #if EFSYS_OPT_HUNTINGTON
163 case EFX_FAMILY_HUNTINGTON:
164 efop = &__efx_filter_ef10_ops;
166 #endif /* EFSYS_OPT_HUNTINGTON */
168 #if EFSYS_OPT_MEDFORD
169 case EFX_FAMILY_MEDFORD:
170 efop = &__efx_filter_ef10_ops;
172 #endif /* EFSYS_OPT_MEDFORD */
180 if ((rc = efop->efo_init(enp)) != 0)
184 enp->en_mod_flags |= EFX_MOD_FILTER;
190 EFSYS_PROBE1(fail1, efx_rc_t, rc);
193 enp->en_mod_flags &= ~EFX_MOD_FILTER;
201 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
202 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
203 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
205 enp->en_efop->efo_fini(enp);
208 enp->en_mod_flags &= ~EFX_MOD_FILTER;
211 __checkReturn efx_rc_t
212 efx_filter_supported_filters(
214 __out uint32_t *list,
215 __out size_t *length)
219 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
220 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
221 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
222 EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL);
224 if ((rc = enp->en_efop->efo_supported_filters(enp, list, length)) != 0)
230 EFSYS_PROBE1(fail1, efx_rc_t, rc);
235 __checkReturn efx_rc_t
236 efx_filter_reconfigure(
238 __in_ecount(6) uint8_t const *mac_addr,
239 __in boolean_t all_unicst,
240 __in boolean_t mulcst,
241 __in boolean_t all_mulcst,
242 __in boolean_t brdcst,
243 __in_ecount(6*count) uint8_t const *addrs,
248 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
249 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
250 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
252 if (enp->en_efop->efo_reconfigure != NULL) {
253 if ((rc = enp->en_efop->efo_reconfigure(enp, mac_addr,
263 EFSYS_PROBE1(fail1, efx_rc_t, rc);
269 efx_filter_spec_init_rx(
270 __out efx_filter_spec_t *spec,
271 __in efx_filter_priority_t priority,
272 __in efx_filter_flags_t flags,
275 EFSYS_ASSERT3P(spec, !=, NULL);
276 EFSYS_ASSERT3P(erp, !=, NULL);
277 EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
278 EFX_FILTER_FLAG_RX_SCATTER)) == 0);
280 memset(spec, 0, sizeof (*spec));
281 spec->efs_priority = priority;
282 spec->efs_flags = EFX_FILTER_FLAG_RX | flags;
283 spec->efs_rss_context = EFX_FILTER_SPEC_RSS_CONTEXT_DEFAULT;
284 spec->efs_dmaq_id = (uint16_t)erp->er_index;
288 efx_filter_spec_init_tx(
289 __out efx_filter_spec_t *spec,
292 EFSYS_ASSERT3P(spec, !=, NULL);
293 EFSYS_ASSERT3P(etp, !=, NULL);
295 memset(spec, 0, sizeof (*spec));
296 spec->efs_priority = EFX_FILTER_PRI_REQUIRED;
297 spec->efs_flags = EFX_FILTER_FLAG_TX;
298 spec->efs_dmaq_id = (uint16_t)etp->et_index;
303 * Specify IPv4 host, transport protocol and port in a filter specification
305 __checkReturn efx_rc_t
306 efx_filter_spec_set_ipv4_local(
307 __inout efx_filter_spec_t *spec,
312 EFSYS_ASSERT3P(spec, !=, NULL);
314 spec->efs_match_flags |=
315 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
316 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
317 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
318 spec->efs_ip_proto = proto;
319 spec->efs_loc_host.eo_u32[0] = host;
320 spec->efs_loc_port = port;
325 * Specify IPv4 hosts, transport protocol and ports in a filter specification
327 __checkReturn efx_rc_t
328 efx_filter_spec_set_ipv4_full(
329 __inout efx_filter_spec_t *spec,
336 EFSYS_ASSERT3P(spec, !=, NULL);
338 spec->efs_match_flags |=
339 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
340 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
341 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
342 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
343 spec->efs_ip_proto = proto;
344 spec->efs_loc_host.eo_u32[0] = lhost;
345 spec->efs_loc_port = lport;
346 spec->efs_rem_host.eo_u32[0] = rhost;
347 spec->efs_rem_port = rport;
352 * Specify local Ethernet address and/or VID in filter specification
354 __checkReturn efx_rc_t
355 efx_filter_spec_set_eth_local(
356 __inout efx_filter_spec_t *spec,
358 __in const uint8_t *addr)
360 EFSYS_ASSERT3P(spec, !=, NULL);
361 EFSYS_ASSERT3P(addr, !=, NULL);
363 if (vid == EFX_FILTER_SPEC_VID_UNSPEC && addr == NULL)
366 if (vid != EFX_FILTER_SPEC_VID_UNSPEC) {
367 spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID;
368 spec->efs_outer_vid = vid;
371 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
372 memcpy(spec->efs_loc_mac, addr, EFX_MAC_ADDR_LEN);
378 * Specify matching otherwise-unmatched unicast in a filter specification
380 __checkReturn efx_rc_t
381 efx_filter_spec_set_uc_def(
382 __inout efx_filter_spec_t *spec)
384 EFSYS_ASSERT3P(spec, !=, NULL);
386 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
391 * Specify matching otherwise-unmatched multicast in a filter specification
393 __checkReturn efx_rc_t
394 efx_filter_spec_set_mc_def(
395 __inout efx_filter_spec_t *spec)
397 EFSYS_ASSERT3P(spec, !=, NULL);
399 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
400 spec->efs_loc_mac[0] = 1;
409 * "Fudge factors" - difference between programmed value and actual depth.
410 * Due to pipelined implementation we need to program H/W with a value that
411 * is larger than the hop limit we want.
413 #define FILTER_CTL_SRCH_FUDGE_WILD 3
414 #define FILTER_CTL_SRCH_FUDGE_FULL 1
417 * Hard maximum hop limit. Hardware will time-out beyond 200-something.
418 * We also need to avoid infinite loops in efx_filter_search() when the
421 #define FILTER_CTL_SRCH_MAX 200
423 static __checkReturn efx_rc_t
424 siena_filter_spec_from_gen_spec(
425 __out siena_filter_spec_t *sf_spec,
426 __in efx_filter_spec_t *gen_spec)
429 boolean_t is_full = B_FALSE;
431 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX)
432 EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX);
434 EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX);
436 /* Falconsiena only has one RSS context */
437 if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
438 gen_spec->efs_rss_context != 0) {
443 sf_spec->sfs_flags = gen_spec->efs_flags;
444 sf_spec->sfs_dmaq_id = gen_spec->efs_dmaq_id;
446 switch (gen_spec->efs_match_flags) {
447 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
448 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
449 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT:
452 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
453 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: {
454 uint32_t rhost, host1, host2;
455 uint16_t rport, port1, port2;
457 if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) {
461 if (gen_spec->efs_loc_port == 0 ||
462 (is_full && gen_spec->efs_rem_port == 0)) {
466 switch (gen_spec->efs_ip_proto) {
467 case EFX_IPPROTO_TCP:
468 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
469 sf_spec->sfs_type = (is_full ?
470 EFX_SIENA_FILTER_TX_TCP_FULL :
471 EFX_SIENA_FILTER_TX_TCP_WILD);
473 sf_spec->sfs_type = (is_full ?
474 EFX_SIENA_FILTER_RX_TCP_FULL :
475 EFX_SIENA_FILTER_RX_TCP_WILD);
478 case EFX_IPPROTO_UDP:
479 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
480 sf_spec->sfs_type = (is_full ?
481 EFX_SIENA_FILTER_TX_UDP_FULL :
482 EFX_SIENA_FILTER_TX_UDP_WILD);
484 sf_spec->sfs_type = (is_full ?
485 EFX_SIENA_FILTER_RX_UDP_FULL :
486 EFX_SIENA_FILTER_RX_UDP_WILD);
494 * The filter is constructed in terms of source and destination,
495 * with the odd wrinkle that the ports are swapped in a UDP
496 * wildcard filter. We need to convert from local and remote
497 * addresses (zero for a wildcard).
499 rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0;
500 rport = is_full ? gen_spec->efs_rem_port : 0;
501 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
502 host1 = gen_spec->efs_loc_host.eo_u32[0];
506 host2 = gen_spec->efs_loc_host.eo_u32[0];
508 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
509 if (sf_spec->sfs_type ==
510 EFX_SIENA_FILTER_TX_UDP_WILD) {
512 port2 = gen_spec->efs_loc_port;
514 port1 = gen_spec->efs_loc_port;
518 if (sf_spec->sfs_type ==
519 EFX_SIENA_FILTER_RX_UDP_WILD) {
520 port1 = gen_spec->efs_loc_port;
524 port2 = gen_spec->efs_loc_port;
527 sf_spec->sfs_dword[0] = (host1 << 16) | port1;
528 sf_spec->sfs_dword[1] = (port2 << 16) | (host1 >> 16);
529 sf_spec->sfs_dword[2] = host2;
533 case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID:
536 case EFX_FILTER_MATCH_LOC_MAC:
537 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
538 sf_spec->sfs_type = (is_full ?
539 EFX_SIENA_FILTER_TX_MAC_FULL :
540 EFX_SIENA_FILTER_TX_MAC_WILD);
542 sf_spec->sfs_type = (is_full ?
543 EFX_SIENA_FILTER_RX_MAC_FULL :
544 EFX_SIENA_FILTER_RX_MAC_WILD);
546 sf_spec->sfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0;
547 sf_spec->sfs_dword[1] =
548 gen_spec->efs_loc_mac[2] << 24 |
549 gen_spec->efs_loc_mac[3] << 16 |
550 gen_spec->efs_loc_mac[4] << 8 |
551 gen_spec->efs_loc_mac[5];
552 sf_spec->sfs_dword[2] =
553 gen_spec->efs_loc_mac[0] << 8 |
554 gen_spec->efs_loc_mac[1];
558 EFSYS_ASSERT(B_FALSE);
574 EFSYS_PROBE1(fail1, efx_rc_t, rc);
580 * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
581 * key derived from the n-tuple.
584 siena_filter_tbl_hash(
589 /* First 16 rounds */
590 tmp = 0x1fff ^ (uint16_t)(key >> 16);
591 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
592 tmp = tmp ^ tmp >> 9;
595 tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff);
596 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
597 tmp = tmp ^ tmp >> 9;
603 * To allow for hash collisions, filter search continues at these
604 * increments from the first possible entry selected by the hash.
607 siena_filter_tbl_increment(
610 return ((uint16_t)(key * 2 - 1));
613 static __checkReturn boolean_t
614 siena_filter_test_used(
615 __in siena_filter_tbl_t *sftp,
616 __in unsigned int index)
618 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
619 return ((sftp->sft_bitmap[index / 32] & (1 << (index % 32))) != 0);
623 siena_filter_set_used(
624 __in siena_filter_tbl_t *sftp,
625 __in unsigned int index)
627 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
628 sftp->sft_bitmap[index / 32] |= (1 << (index % 32));
633 siena_filter_clear_used(
634 __in siena_filter_tbl_t *sftp,
635 __in unsigned int index)
637 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
638 sftp->sft_bitmap[index / 32] &= ~(1 << (index % 32));
641 EFSYS_ASSERT3U(sftp->sft_used, >=, 0);
645 static siena_filter_tbl_id_t
647 __in siena_filter_type_t type)
649 siena_filter_tbl_id_t tbl_id;
652 case EFX_SIENA_FILTER_RX_TCP_FULL:
653 case EFX_SIENA_FILTER_RX_TCP_WILD:
654 case EFX_SIENA_FILTER_RX_UDP_FULL:
655 case EFX_SIENA_FILTER_RX_UDP_WILD:
656 tbl_id = EFX_SIENA_FILTER_TBL_RX_IP;
659 case EFX_SIENA_FILTER_RX_MAC_FULL:
660 case EFX_SIENA_FILTER_RX_MAC_WILD:
661 tbl_id = EFX_SIENA_FILTER_TBL_RX_MAC;
664 case EFX_SIENA_FILTER_TX_TCP_FULL:
665 case EFX_SIENA_FILTER_TX_TCP_WILD:
666 case EFX_SIENA_FILTER_TX_UDP_FULL:
667 case EFX_SIENA_FILTER_TX_UDP_WILD:
668 tbl_id = EFX_SIENA_FILTER_TBL_TX_IP;
671 case EFX_SIENA_FILTER_TX_MAC_FULL:
672 case EFX_SIENA_FILTER_TX_MAC_WILD:
673 tbl_id = EFX_SIENA_FILTER_TBL_TX_MAC;
677 EFSYS_ASSERT(B_FALSE);
678 tbl_id = EFX_SIENA_FILTER_NTBLS;
685 siena_filter_reset_search_depth(
686 __inout siena_filter_t *sfp,
687 __in siena_filter_tbl_id_t tbl_id)
690 case EFX_SIENA_FILTER_TBL_RX_IP:
691 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] = 0;
692 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] = 0;
693 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] = 0;
694 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] = 0;
697 case EFX_SIENA_FILTER_TBL_RX_MAC:
698 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] = 0;
699 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] = 0;
702 case EFX_SIENA_FILTER_TBL_TX_IP:
703 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] = 0;
704 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] = 0;
705 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] = 0;
706 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] = 0;
709 case EFX_SIENA_FILTER_TBL_TX_MAC:
710 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] = 0;
711 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] = 0;
715 EFSYS_ASSERT(B_FALSE);
721 siena_filter_push_rx_limits(
724 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
727 EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
729 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT,
730 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] +
731 FILTER_CTL_SRCH_FUDGE_FULL);
732 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT,
733 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] +
734 FILTER_CTL_SRCH_FUDGE_WILD);
735 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT,
736 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] +
737 FILTER_CTL_SRCH_FUDGE_FULL);
738 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT,
739 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] +
740 FILTER_CTL_SRCH_FUDGE_WILD);
742 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC].sft_size) {
743 EFX_SET_OWORD_FIELD(oword,
744 FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
745 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] +
746 FILTER_CTL_SRCH_FUDGE_FULL);
747 EFX_SET_OWORD_FIELD(oword,
748 FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
749 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] +
750 FILTER_CTL_SRCH_FUDGE_WILD);
753 EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
757 siena_filter_push_tx_limits(
760 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
763 EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
765 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP].sft_size != 0) {
766 EFX_SET_OWORD_FIELD(oword,
767 FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE,
768 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] +
769 FILTER_CTL_SRCH_FUDGE_FULL);
770 EFX_SET_OWORD_FIELD(oword,
771 FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE,
772 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] +
773 FILTER_CTL_SRCH_FUDGE_WILD);
774 EFX_SET_OWORD_FIELD(oword,
775 FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE,
776 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] +
777 FILTER_CTL_SRCH_FUDGE_FULL);
778 EFX_SET_OWORD_FIELD(oword,
779 FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE,
780 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] +
781 FILTER_CTL_SRCH_FUDGE_WILD);
784 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC].sft_size != 0) {
786 oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
787 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] +
788 FILTER_CTL_SRCH_FUDGE_FULL);
790 oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
791 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] +
792 FILTER_CTL_SRCH_FUDGE_WILD);
795 EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
798 /* Build a filter entry and return its n-tuple key. */
799 static __checkReturn uint32_t
801 __out efx_oword_t *filter,
802 __in siena_filter_spec_t *spec)
806 uint8_t type = spec->sfs_type;
807 uint32_t flags = spec->sfs_flags;
809 switch (siena_filter_tbl_id(type)) {
810 case EFX_SIENA_FILTER_TBL_RX_IP: {
811 boolean_t is_udp = (type == EFX_SIENA_FILTER_RX_UDP_FULL ||
812 type == EFX_SIENA_FILTER_RX_UDP_WILD);
813 EFX_POPULATE_OWORD_7(*filter,
815 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
817 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
818 FRF_AZ_TCP_UDP, is_udp,
819 FRF_AZ_RXQ_ID, spec->sfs_dmaq_id,
820 EFX_DWORD_2, spec->sfs_dword[2],
821 EFX_DWORD_1, spec->sfs_dword[1],
822 EFX_DWORD_0, spec->sfs_dword[0]);
827 case EFX_SIENA_FILTER_TBL_RX_MAC: {
828 boolean_t is_wild = (type == EFX_SIENA_FILTER_RX_MAC_WILD);
829 EFX_POPULATE_OWORD_7(*filter,
831 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
832 FRF_CZ_RMFT_SCATTER_EN,
833 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
834 FRF_CZ_RMFT_RXQ_ID, spec->sfs_dmaq_id,
835 FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
836 FRF_CZ_RMFT_DEST_MAC_DW1, spec->sfs_dword[2],
837 FRF_CZ_RMFT_DEST_MAC_DW0, spec->sfs_dword[1],
838 FRF_CZ_RMFT_VLAN_ID, spec->sfs_dword[0]);
843 case EFX_SIENA_FILTER_TBL_TX_IP: {
844 boolean_t is_udp = (type == EFX_SIENA_FILTER_TX_UDP_FULL ||
845 type == EFX_SIENA_FILTER_TX_UDP_WILD);
846 EFX_POPULATE_OWORD_5(*filter,
847 FRF_CZ_TIFT_TCP_UDP, is_udp,
848 FRF_CZ_TIFT_TXQ_ID, spec->sfs_dmaq_id,
849 EFX_DWORD_2, spec->sfs_dword[2],
850 EFX_DWORD_1, spec->sfs_dword[1],
851 EFX_DWORD_0, spec->sfs_dword[0]);
852 dword3 = is_udp | spec->sfs_dmaq_id << 1;
856 case EFX_SIENA_FILTER_TBL_TX_MAC: {
857 boolean_t is_wild = (type == EFX_SIENA_FILTER_TX_MAC_WILD);
858 EFX_POPULATE_OWORD_5(*filter,
859 FRF_CZ_TMFT_TXQ_ID, spec->sfs_dmaq_id,
860 FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
861 FRF_CZ_TMFT_SRC_MAC_DW1, spec->sfs_dword[2],
862 FRF_CZ_TMFT_SRC_MAC_DW0, spec->sfs_dword[1],
863 FRF_CZ_TMFT_VLAN_ID, spec->sfs_dword[0]);
864 dword3 = is_wild | spec->sfs_dmaq_id << 1;
869 EFSYS_ASSERT(B_FALSE);
882 static __checkReturn efx_rc_t
883 siena_filter_push_entry(
884 __inout efx_nic_t *enp,
885 __in siena_filter_type_t type,
887 __in efx_oword_t *eop)
892 case EFX_SIENA_FILTER_RX_TCP_FULL:
893 case EFX_SIENA_FILTER_RX_TCP_WILD:
894 case EFX_SIENA_FILTER_RX_UDP_FULL:
895 case EFX_SIENA_FILTER_RX_UDP_WILD:
896 EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index,
900 case EFX_SIENA_FILTER_RX_MAC_FULL:
901 case EFX_SIENA_FILTER_RX_MAC_WILD:
902 EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index,
906 case EFX_SIENA_FILTER_TX_TCP_FULL:
907 case EFX_SIENA_FILTER_TX_TCP_WILD:
908 case EFX_SIENA_FILTER_TX_UDP_FULL:
909 case EFX_SIENA_FILTER_TX_UDP_WILD:
910 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index,
914 case EFX_SIENA_FILTER_TX_MAC_FULL:
915 case EFX_SIENA_FILTER_TX_MAC_WILD:
916 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index,
921 EFSYS_ASSERT(B_FALSE);
932 static __checkReturn boolean_t
934 __in const siena_filter_spec_t *left,
935 __in const siena_filter_spec_t *right)
937 siena_filter_tbl_id_t tbl_id;
939 tbl_id = siena_filter_tbl_id(left->sfs_type);
942 if (left->sfs_type != right->sfs_type)
945 if (memcmp(left->sfs_dword, right->sfs_dword,
946 sizeof (left->sfs_dword)))
949 if ((tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
950 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) &&
951 left->sfs_dmaq_id != right->sfs_dmaq_id)
957 static __checkReturn efx_rc_t
959 __in siena_filter_tbl_t *sftp,
960 __in siena_filter_spec_t *spec,
962 __in boolean_t for_insert,
963 __out int *filter_index,
964 __out unsigned int *depth_required)
966 unsigned int hash, incr, filter_idx, depth;
968 hash = siena_filter_tbl_hash(key);
969 incr = siena_filter_tbl_increment(key);
971 filter_idx = hash & (sftp->sft_size - 1);
976 * Return success if entry is used and matches this spec
977 * or entry is unused and we are trying to insert.
979 if (siena_filter_test_used(sftp, filter_idx) ?
980 siena_filter_equal(spec,
981 &sftp->sft_spec[filter_idx]) :
983 *filter_index = filter_idx;
984 *depth_required = depth;
988 /* Return failure if we reached the maximum search depth */
989 if (depth == FILTER_CTL_SRCH_MAX)
990 return (for_insert ? EBUSY : ENOENT);
992 filter_idx = (filter_idx + incr) & (sftp->sft_size - 1);
998 siena_filter_clear_entry(
1000 __in siena_filter_tbl_t *sftp,
1005 if (siena_filter_test_used(sftp, index)) {
1006 siena_filter_clear_used(sftp, index);
1008 EFX_ZERO_OWORD(filter);
1009 siena_filter_push_entry(enp,
1010 sftp->sft_spec[index].sfs_type,
1013 memset(&sftp->sft_spec[index],
1014 0, sizeof (sftp->sft_spec[0]));
1019 siena_filter_tbl_clear(
1020 __in efx_nic_t *enp,
1021 __in siena_filter_tbl_id_t tbl_id)
1023 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1024 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1026 efsys_lock_state_t state;
1028 EFSYS_LOCK(enp->en_eslp, state);
1030 for (index = 0; index < sftp->sft_size; ++index) {
1031 siena_filter_clear_entry(enp, sftp, index);
1034 if (sftp->sft_used == 0)
1035 siena_filter_reset_search_depth(sfp, tbl_id);
1037 EFSYS_UNLOCK(enp->en_eslp, state);
1040 static __checkReturn efx_rc_t
1042 __in efx_nic_t *enp)
1044 siena_filter_t *sfp;
1045 siena_filter_tbl_t *sftp;
1049 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (siena_filter_t), sfp);
1056 enp->en_filter.ef_siena_filter = sfp;
1058 switch (enp->en_family) {
1059 case EFX_FAMILY_SIENA:
1060 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_IP];
1061 sftp->sft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
1063 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC];
1064 sftp->sft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
1066 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP];
1067 sftp->sft_size = FR_CZ_TX_FILTER_TBL0_ROWS;
1069 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC];
1070 sftp->sft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
1078 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1079 unsigned int bitmap_size;
1081 sftp = &sfp->sf_tbl[tbl_id];
1082 if (sftp->sft_size == 0)
1085 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1088 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1090 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, sftp->sft_bitmap);
1091 if (!sftp->sft_bitmap) {
1096 EFSYS_KMEM_ALLOC(enp->en_esip,
1097 sftp->sft_size * sizeof (*sftp->sft_spec),
1099 if (!sftp->sft_spec) {
1103 memset(sftp->sft_spec, 0,
1104 sftp->sft_size * sizeof (*sftp->sft_spec));
1117 siena_filter_fini(enp);
1120 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1126 __in efx_nic_t *enp)
1128 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1129 siena_filter_tbl_id_t tbl_id;
1131 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1132 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1137 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1138 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1139 unsigned int bitmap_size;
1141 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1144 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1146 if (sftp->sft_bitmap != NULL) {
1147 EFSYS_KMEM_FREE(enp->en_esip, bitmap_size,
1149 sftp->sft_bitmap = NULL;
1152 if (sftp->sft_spec != NULL) {
1153 EFSYS_KMEM_FREE(enp->en_esip, sftp->sft_size *
1154 sizeof (*sftp->sft_spec), sftp->sft_spec);
1155 sftp->sft_spec = NULL;
1159 EFSYS_KMEM_FREE(enp->en_esip, sizeof (siena_filter_t),
1160 enp->en_filter.ef_siena_filter);
1163 /* Restore filter state after a reset */
1164 static __checkReturn efx_rc_t
1165 siena_filter_restore(
1166 __in efx_nic_t *enp)
1168 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1169 siena_filter_tbl_id_t tbl_id;
1170 siena_filter_tbl_t *sftp;
1171 siena_filter_spec_t *spec;
1174 efsys_lock_state_t state;
1178 EFSYS_LOCK(enp->en_eslp, state);
1180 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1181 sftp = &sfp->sf_tbl[tbl_id];
1182 for (filter_idx = 0;
1183 filter_idx < sftp->sft_size;
1185 if (!siena_filter_test_used(sftp, filter_idx))
1188 spec = &sftp->sft_spec[filter_idx];
1189 if ((key = siena_filter_build(&filter, spec)) == 0) {
1193 if ((rc = siena_filter_push_entry(enp,
1194 spec->sfs_type, filter_idx, &filter)) != 0)
1199 siena_filter_push_rx_limits(enp);
1200 siena_filter_push_tx_limits(enp);
1202 EFSYS_UNLOCK(enp->en_eslp, state);
1210 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1212 EFSYS_UNLOCK(enp->en_eslp, state);
1217 static __checkReturn efx_rc_t
1219 __in efx_nic_t *enp,
1220 __inout efx_filter_spec_t *spec,
1221 __in boolean_t may_replace)
1224 siena_filter_spec_t sf_spec;
1225 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1226 siena_filter_tbl_id_t tbl_id;
1227 siena_filter_tbl_t *sftp;
1228 siena_filter_spec_t *saved_sf_spec;
1232 efsys_lock_state_t state;
1236 EFSYS_ASSERT3P(spec, !=, NULL);
1238 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1241 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1242 sftp = &sfp->sf_tbl[tbl_id];
1244 if (sftp->sft_size == 0) {
1249 key = siena_filter_build(&filter, &sf_spec);
1251 EFSYS_LOCK(enp->en_eslp, state);
1253 rc = siena_filter_search(sftp, &sf_spec, key, B_TRUE,
1254 &filter_idx, &depth);
1258 EFSYS_ASSERT3U(filter_idx, <, sftp->sft_size);
1259 saved_sf_spec = &sftp->sft_spec[filter_idx];
1261 if (siena_filter_test_used(sftp, filter_idx)) {
1262 if (may_replace == B_FALSE) {
1267 siena_filter_set_used(sftp, filter_idx);
1268 *saved_sf_spec = sf_spec;
1270 if (sfp->sf_depth[sf_spec.sfs_type] < depth) {
1271 sfp->sf_depth[sf_spec.sfs_type] = depth;
1272 if (tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1273 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC)
1274 siena_filter_push_tx_limits(enp);
1276 siena_filter_push_rx_limits(enp);
1279 siena_filter_push_entry(enp, sf_spec.sfs_type,
1280 filter_idx, &filter);
1282 EFSYS_UNLOCK(enp->en_eslp, state);
1289 EFSYS_UNLOCK(enp->en_eslp, state);
1296 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1300 static __checkReturn efx_rc_t
1301 siena_filter_delete(
1302 __in efx_nic_t *enp,
1303 __inout efx_filter_spec_t *spec)
1306 siena_filter_spec_t sf_spec;
1307 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1308 siena_filter_tbl_id_t tbl_id;
1309 siena_filter_tbl_t *sftp;
1313 efsys_lock_state_t state;
1316 EFSYS_ASSERT3P(spec, !=, NULL);
1318 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1321 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1322 sftp = &sfp->sf_tbl[tbl_id];
1324 key = siena_filter_build(&filter, &sf_spec);
1326 EFSYS_LOCK(enp->en_eslp, state);
1328 rc = siena_filter_search(sftp, &sf_spec, key, B_FALSE,
1329 &filter_idx, &depth);
1333 siena_filter_clear_entry(enp, sftp, filter_idx);
1334 if (sftp->sft_used == 0)
1335 siena_filter_reset_search_depth(sfp, tbl_id);
1337 EFSYS_UNLOCK(enp->en_eslp, state);
1341 EFSYS_UNLOCK(enp->en_eslp, state);
1345 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1349 #define MAX_SUPPORTED 4
1351 static __checkReturn efx_rc_t
1352 siena_filter_supported_filters(
1353 __in efx_nic_t *enp,
1354 __out uint32_t *list,
1355 __out size_t *length)
1358 uint32_t rx_matches[MAX_SUPPORTED];
1366 rx_matches[index++] =
1367 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1368 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
1369 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
1371 rx_matches[index++] =
1372 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1373 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
1375 if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) {
1376 rx_matches[index++] =
1377 EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC;
1379 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC;
1382 EFSYS_ASSERT3U(index, <=, MAX_SUPPORTED);
1385 memcpy(list, rx_matches, *length);
1394 #undef MAX_SUPPORTED
1396 #endif /* EFSYS_OPT_SIENA */
1398 #endif /* EFSYS_OPT_FILTER */