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 #if EFSYS_OPT_RX_SCALE
120 spec->efs_rss_context = enp->en_rss_context;
123 return (efop->efo_delete(enp, spec));
126 __checkReturn efx_rc_t
132 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
134 if ((rc = enp->en_efop->efo_restore(enp)) != 0)
140 EFSYS_PROBE1(fail1, efx_rc_t, rc);
145 __checkReturn efx_rc_t
149 const efx_filter_ops_t *efop;
152 /* Check that efx_filter_spec_t is 64 bytes. */
153 EFX_STATIC_ASSERT(sizeof (efx_filter_spec_t) == 64);
155 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
156 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
157 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER));
159 switch (enp->en_family) {
161 case EFX_FAMILY_SIENA:
162 efop = &__efx_filter_siena_ops;
164 #endif /* EFSYS_OPT_SIENA */
166 #if EFSYS_OPT_HUNTINGTON
167 case EFX_FAMILY_HUNTINGTON:
168 efop = &__efx_filter_ef10_ops;
170 #endif /* EFSYS_OPT_HUNTINGTON */
172 #if EFSYS_OPT_MEDFORD
173 case EFX_FAMILY_MEDFORD:
174 efop = &__efx_filter_ef10_ops;
176 #endif /* EFSYS_OPT_MEDFORD */
184 if ((rc = efop->efo_init(enp)) != 0)
188 enp->en_mod_flags |= EFX_MOD_FILTER;
194 EFSYS_PROBE1(fail1, efx_rc_t, rc);
197 enp->en_mod_flags &= ~EFX_MOD_FILTER;
205 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
206 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
207 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
209 enp->en_efop->efo_fini(enp);
212 enp->en_mod_flags &= ~EFX_MOD_FILTER;
215 __checkReturn efx_rc_t
216 efx_filter_supported_filters(
218 __out uint32_t *list,
219 __out size_t *length)
223 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
224 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
225 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
226 EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL);
228 if ((rc = enp->en_efop->efo_supported_filters(enp, list, length)) != 0)
234 EFSYS_PROBE1(fail1, efx_rc_t, rc);
239 __checkReturn efx_rc_t
240 efx_filter_reconfigure(
242 __in_ecount(6) uint8_t const *mac_addr,
243 __in boolean_t all_unicst,
244 __in boolean_t mulcst,
245 __in boolean_t all_mulcst,
246 __in boolean_t brdcst,
247 __in_ecount(6*count) uint8_t const *addrs,
252 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
253 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
254 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
256 if (enp->en_efop->efo_reconfigure != NULL) {
257 if ((rc = enp->en_efop->efo_reconfigure(enp, mac_addr,
267 EFSYS_PROBE1(fail1, efx_rc_t, rc);
273 efx_filter_spec_init_rx(
274 __out efx_filter_spec_t *spec,
275 __in efx_filter_priority_t priority,
276 __in efx_filter_flags_t flags,
279 EFSYS_ASSERT3P(spec, !=, NULL);
280 EFSYS_ASSERT3P(erp, !=, NULL);
281 EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
282 EFX_FILTER_FLAG_RX_SCATTER)) == 0);
284 memset(spec, 0, sizeof (*spec));
285 spec->efs_priority = priority;
286 spec->efs_flags = EFX_FILTER_FLAG_RX | flags;
287 spec->efs_rss_context = EFX_FILTER_SPEC_RSS_CONTEXT_DEFAULT;
288 spec->efs_dmaq_id = (uint16_t)erp->er_index;
292 efx_filter_spec_init_tx(
293 __out efx_filter_spec_t *spec,
296 EFSYS_ASSERT3P(spec, !=, NULL);
297 EFSYS_ASSERT3P(etp, !=, NULL);
299 memset(spec, 0, sizeof (*spec));
300 spec->efs_priority = EFX_FILTER_PRI_REQUIRED;
301 spec->efs_flags = EFX_FILTER_FLAG_TX;
302 spec->efs_dmaq_id = (uint16_t)etp->et_index;
307 * Specify IPv4 host, transport protocol and port in a filter specification
309 __checkReturn efx_rc_t
310 efx_filter_spec_set_ipv4_local(
311 __inout efx_filter_spec_t *spec,
316 EFSYS_ASSERT3P(spec, !=, NULL);
318 spec->efs_match_flags |=
319 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
320 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
321 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
322 spec->efs_ip_proto = proto;
323 spec->efs_loc_host.eo_u32[0] = host;
324 spec->efs_loc_port = port;
329 * Specify IPv4 hosts, transport protocol and ports in a filter specification
331 __checkReturn efx_rc_t
332 efx_filter_spec_set_ipv4_full(
333 __inout efx_filter_spec_t *spec,
340 EFSYS_ASSERT3P(spec, !=, NULL);
342 spec->efs_match_flags |=
343 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
344 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
345 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
346 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
347 spec->efs_ip_proto = proto;
348 spec->efs_loc_host.eo_u32[0] = lhost;
349 spec->efs_loc_port = lport;
350 spec->efs_rem_host.eo_u32[0] = rhost;
351 spec->efs_rem_port = rport;
356 * Specify local Ethernet address and/or VID in filter specification
358 __checkReturn efx_rc_t
359 efx_filter_spec_set_eth_local(
360 __inout efx_filter_spec_t *spec,
362 __in const uint8_t *addr)
364 EFSYS_ASSERT3P(spec, !=, NULL);
365 EFSYS_ASSERT3P(addr, !=, NULL);
367 if (vid == EFX_FILTER_SPEC_VID_UNSPEC && addr == NULL)
370 if (vid != EFX_FILTER_SPEC_VID_UNSPEC) {
371 spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID;
372 spec->efs_outer_vid = vid;
375 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
376 memcpy(spec->efs_loc_mac, addr, EFX_MAC_ADDR_LEN);
382 * Specify matching otherwise-unmatched unicast in a filter specification
384 __checkReturn efx_rc_t
385 efx_filter_spec_set_uc_def(
386 __inout efx_filter_spec_t *spec)
388 EFSYS_ASSERT3P(spec, !=, NULL);
390 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
395 * Specify matching otherwise-unmatched multicast in a filter specification
397 __checkReturn efx_rc_t
398 efx_filter_spec_set_mc_def(
399 __inout efx_filter_spec_t *spec)
401 EFSYS_ASSERT3P(spec, !=, NULL);
403 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
404 spec->efs_loc_mac[0] = 1;
413 * "Fudge factors" - difference between programmed value and actual depth.
414 * Due to pipelined implementation we need to program H/W with a value that
415 * is larger than the hop limit we want.
417 #define FILTER_CTL_SRCH_FUDGE_WILD 3
418 #define FILTER_CTL_SRCH_FUDGE_FULL 1
421 * Hard maximum hop limit. Hardware will time-out beyond 200-something.
422 * We also need to avoid infinite loops in efx_filter_search() when the
425 #define FILTER_CTL_SRCH_MAX 200
427 static __checkReturn efx_rc_t
428 siena_filter_spec_from_gen_spec(
429 __out siena_filter_spec_t *sf_spec,
430 __in efx_filter_spec_t *gen_spec)
433 boolean_t is_full = B_FALSE;
435 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX)
436 EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX);
438 EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX);
440 /* Falconsiena only has one RSS context */
441 if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
442 gen_spec->efs_rss_context != 0) {
447 sf_spec->sfs_flags = gen_spec->efs_flags;
448 sf_spec->sfs_dmaq_id = gen_spec->efs_dmaq_id;
450 switch (gen_spec->efs_match_flags) {
451 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
452 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
453 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT:
456 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
457 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: {
458 uint32_t rhost, host1, host2;
459 uint16_t rport, port1, port2;
461 if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) {
465 if (gen_spec->efs_loc_port == 0 ||
466 (is_full && gen_spec->efs_rem_port == 0)) {
470 switch (gen_spec->efs_ip_proto) {
471 case EFX_IPPROTO_TCP:
472 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
473 sf_spec->sfs_type = (is_full ?
474 EFX_SIENA_FILTER_TX_TCP_FULL :
475 EFX_SIENA_FILTER_TX_TCP_WILD);
477 sf_spec->sfs_type = (is_full ?
478 EFX_SIENA_FILTER_RX_TCP_FULL :
479 EFX_SIENA_FILTER_RX_TCP_WILD);
482 case EFX_IPPROTO_UDP:
483 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
484 sf_spec->sfs_type = (is_full ?
485 EFX_SIENA_FILTER_TX_UDP_FULL :
486 EFX_SIENA_FILTER_TX_UDP_WILD);
488 sf_spec->sfs_type = (is_full ?
489 EFX_SIENA_FILTER_RX_UDP_FULL :
490 EFX_SIENA_FILTER_RX_UDP_WILD);
498 * The filter is constructed in terms of source and destination,
499 * with the odd wrinkle that the ports are swapped in a UDP
500 * wildcard filter. We need to convert from local and remote
501 * addresses (zero for a wildcard).
503 rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0;
504 rport = is_full ? gen_spec->efs_rem_port : 0;
505 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
506 host1 = gen_spec->efs_loc_host.eo_u32[0];
510 host2 = gen_spec->efs_loc_host.eo_u32[0];
512 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
513 if (sf_spec->sfs_type ==
514 EFX_SIENA_FILTER_TX_UDP_WILD) {
516 port2 = gen_spec->efs_loc_port;
518 port1 = gen_spec->efs_loc_port;
522 if (sf_spec->sfs_type ==
523 EFX_SIENA_FILTER_RX_UDP_WILD) {
524 port1 = gen_spec->efs_loc_port;
528 port2 = gen_spec->efs_loc_port;
531 sf_spec->sfs_dword[0] = (host1 << 16) | port1;
532 sf_spec->sfs_dword[1] = (port2 << 16) | (host1 >> 16);
533 sf_spec->sfs_dword[2] = host2;
537 case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID:
540 case EFX_FILTER_MATCH_LOC_MAC:
541 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
542 sf_spec->sfs_type = (is_full ?
543 EFX_SIENA_FILTER_TX_MAC_FULL :
544 EFX_SIENA_FILTER_TX_MAC_WILD);
546 sf_spec->sfs_type = (is_full ?
547 EFX_SIENA_FILTER_RX_MAC_FULL :
548 EFX_SIENA_FILTER_RX_MAC_WILD);
550 sf_spec->sfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0;
551 sf_spec->sfs_dword[1] =
552 gen_spec->efs_loc_mac[2] << 24 |
553 gen_spec->efs_loc_mac[3] << 16 |
554 gen_spec->efs_loc_mac[4] << 8 |
555 gen_spec->efs_loc_mac[5];
556 sf_spec->sfs_dword[2] =
557 gen_spec->efs_loc_mac[0] << 8 |
558 gen_spec->efs_loc_mac[1];
562 EFSYS_ASSERT(B_FALSE);
578 EFSYS_PROBE1(fail1, efx_rc_t, rc);
584 * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
585 * key derived from the n-tuple.
588 siena_filter_tbl_hash(
593 /* First 16 rounds */
594 tmp = 0x1fff ^ (uint16_t)(key >> 16);
595 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
596 tmp = tmp ^ tmp >> 9;
599 tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff);
600 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
601 tmp = tmp ^ tmp >> 9;
607 * To allow for hash collisions, filter search continues at these
608 * increments from the first possible entry selected by the hash.
611 siena_filter_tbl_increment(
614 return ((uint16_t)(key * 2 - 1));
617 static __checkReturn boolean_t
618 siena_filter_test_used(
619 __in siena_filter_tbl_t *sftp,
620 __in unsigned int index)
622 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
623 return ((sftp->sft_bitmap[index / 32] & (1 << (index % 32))) != 0);
627 siena_filter_set_used(
628 __in siena_filter_tbl_t *sftp,
629 __in unsigned int index)
631 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
632 sftp->sft_bitmap[index / 32] |= (1 << (index % 32));
637 siena_filter_clear_used(
638 __in siena_filter_tbl_t *sftp,
639 __in unsigned int index)
641 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
642 sftp->sft_bitmap[index / 32] &= ~(1 << (index % 32));
645 EFSYS_ASSERT3U(sftp->sft_used, >=, 0);
649 static siena_filter_tbl_id_t
651 __in siena_filter_type_t type)
653 siena_filter_tbl_id_t tbl_id;
656 case EFX_SIENA_FILTER_RX_TCP_FULL:
657 case EFX_SIENA_FILTER_RX_TCP_WILD:
658 case EFX_SIENA_FILTER_RX_UDP_FULL:
659 case EFX_SIENA_FILTER_RX_UDP_WILD:
660 tbl_id = EFX_SIENA_FILTER_TBL_RX_IP;
663 case EFX_SIENA_FILTER_RX_MAC_FULL:
664 case EFX_SIENA_FILTER_RX_MAC_WILD:
665 tbl_id = EFX_SIENA_FILTER_TBL_RX_MAC;
668 case EFX_SIENA_FILTER_TX_TCP_FULL:
669 case EFX_SIENA_FILTER_TX_TCP_WILD:
670 case EFX_SIENA_FILTER_TX_UDP_FULL:
671 case EFX_SIENA_FILTER_TX_UDP_WILD:
672 tbl_id = EFX_SIENA_FILTER_TBL_TX_IP;
675 case EFX_SIENA_FILTER_TX_MAC_FULL:
676 case EFX_SIENA_FILTER_TX_MAC_WILD:
677 tbl_id = EFX_SIENA_FILTER_TBL_TX_MAC;
681 EFSYS_ASSERT(B_FALSE);
682 tbl_id = EFX_SIENA_FILTER_NTBLS;
689 siena_filter_reset_search_depth(
690 __inout siena_filter_t *sfp,
691 __in siena_filter_tbl_id_t tbl_id)
694 case EFX_SIENA_FILTER_TBL_RX_IP:
695 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] = 0;
696 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] = 0;
697 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] = 0;
698 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] = 0;
701 case EFX_SIENA_FILTER_TBL_RX_MAC:
702 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] = 0;
703 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] = 0;
706 case EFX_SIENA_FILTER_TBL_TX_IP:
707 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] = 0;
708 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] = 0;
709 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] = 0;
710 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] = 0;
713 case EFX_SIENA_FILTER_TBL_TX_MAC:
714 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] = 0;
715 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] = 0;
719 EFSYS_ASSERT(B_FALSE);
725 siena_filter_push_rx_limits(
728 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
731 EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
733 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT,
734 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] +
735 FILTER_CTL_SRCH_FUDGE_FULL);
736 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT,
737 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] +
738 FILTER_CTL_SRCH_FUDGE_WILD);
739 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT,
740 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] +
741 FILTER_CTL_SRCH_FUDGE_FULL);
742 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT,
743 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] +
744 FILTER_CTL_SRCH_FUDGE_WILD);
746 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC].sft_size) {
747 EFX_SET_OWORD_FIELD(oword,
748 FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
749 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] +
750 FILTER_CTL_SRCH_FUDGE_FULL);
751 EFX_SET_OWORD_FIELD(oword,
752 FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
753 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] +
754 FILTER_CTL_SRCH_FUDGE_WILD);
757 EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
761 siena_filter_push_tx_limits(
764 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
767 EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
769 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP].sft_size != 0) {
770 EFX_SET_OWORD_FIELD(oword,
771 FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE,
772 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] +
773 FILTER_CTL_SRCH_FUDGE_FULL);
774 EFX_SET_OWORD_FIELD(oword,
775 FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE,
776 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] +
777 FILTER_CTL_SRCH_FUDGE_WILD);
778 EFX_SET_OWORD_FIELD(oword,
779 FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE,
780 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] +
781 FILTER_CTL_SRCH_FUDGE_FULL);
782 EFX_SET_OWORD_FIELD(oword,
783 FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE,
784 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] +
785 FILTER_CTL_SRCH_FUDGE_WILD);
788 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC].sft_size != 0) {
790 oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
791 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] +
792 FILTER_CTL_SRCH_FUDGE_FULL);
794 oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
795 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] +
796 FILTER_CTL_SRCH_FUDGE_WILD);
799 EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
802 /* Build a filter entry and return its n-tuple key. */
803 static __checkReturn uint32_t
805 __out efx_oword_t *filter,
806 __in siena_filter_spec_t *spec)
810 uint8_t type = spec->sfs_type;
811 uint32_t flags = spec->sfs_flags;
813 switch (siena_filter_tbl_id(type)) {
814 case EFX_SIENA_FILTER_TBL_RX_IP: {
815 boolean_t is_udp = (type == EFX_SIENA_FILTER_RX_UDP_FULL ||
816 type == EFX_SIENA_FILTER_RX_UDP_WILD);
817 EFX_POPULATE_OWORD_7(*filter,
819 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
821 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
822 FRF_AZ_TCP_UDP, is_udp,
823 FRF_AZ_RXQ_ID, spec->sfs_dmaq_id,
824 EFX_DWORD_2, spec->sfs_dword[2],
825 EFX_DWORD_1, spec->sfs_dword[1],
826 EFX_DWORD_0, spec->sfs_dword[0]);
831 case EFX_SIENA_FILTER_TBL_RX_MAC: {
832 boolean_t is_wild = (type == EFX_SIENA_FILTER_RX_MAC_WILD);
833 EFX_POPULATE_OWORD_7(*filter,
835 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
836 FRF_CZ_RMFT_SCATTER_EN,
837 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
838 FRF_CZ_RMFT_RXQ_ID, spec->sfs_dmaq_id,
839 FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
840 FRF_CZ_RMFT_DEST_MAC_DW1, spec->sfs_dword[2],
841 FRF_CZ_RMFT_DEST_MAC_DW0, spec->sfs_dword[1],
842 FRF_CZ_RMFT_VLAN_ID, spec->sfs_dword[0]);
847 case EFX_SIENA_FILTER_TBL_TX_IP: {
848 boolean_t is_udp = (type == EFX_SIENA_FILTER_TX_UDP_FULL ||
849 type == EFX_SIENA_FILTER_TX_UDP_WILD);
850 EFX_POPULATE_OWORD_5(*filter,
851 FRF_CZ_TIFT_TCP_UDP, is_udp,
852 FRF_CZ_TIFT_TXQ_ID, spec->sfs_dmaq_id,
853 EFX_DWORD_2, spec->sfs_dword[2],
854 EFX_DWORD_1, spec->sfs_dword[1],
855 EFX_DWORD_0, spec->sfs_dword[0]);
856 dword3 = is_udp | spec->sfs_dmaq_id << 1;
860 case EFX_SIENA_FILTER_TBL_TX_MAC: {
861 boolean_t is_wild = (type == EFX_SIENA_FILTER_TX_MAC_WILD);
862 EFX_POPULATE_OWORD_5(*filter,
863 FRF_CZ_TMFT_TXQ_ID, spec->sfs_dmaq_id,
864 FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
865 FRF_CZ_TMFT_SRC_MAC_DW1, spec->sfs_dword[2],
866 FRF_CZ_TMFT_SRC_MAC_DW0, spec->sfs_dword[1],
867 FRF_CZ_TMFT_VLAN_ID, spec->sfs_dword[0]);
868 dword3 = is_wild | spec->sfs_dmaq_id << 1;
873 EFSYS_ASSERT(B_FALSE);
886 static __checkReturn efx_rc_t
887 siena_filter_push_entry(
888 __inout efx_nic_t *enp,
889 __in siena_filter_type_t type,
891 __in efx_oword_t *eop)
896 case EFX_SIENA_FILTER_RX_TCP_FULL:
897 case EFX_SIENA_FILTER_RX_TCP_WILD:
898 case EFX_SIENA_FILTER_RX_UDP_FULL:
899 case EFX_SIENA_FILTER_RX_UDP_WILD:
900 EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index,
904 case EFX_SIENA_FILTER_RX_MAC_FULL:
905 case EFX_SIENA_FILTER_RX_MAC_WILD:
906 EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index,
910 case EFX_SIENA_FILTER_TX_TCP_FULL:
911 case EFX_SIENA_FILTER_TX_TCP_WILD:
912 case EFX_SIENA_FILTER_TX_UDP_FULL:
913 case EFX_SIENA_FILTER_TX_UDP_WILD:
914 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index,
918 case EFX_SIENA_FILTER_TX_MAC_FULL:
919 case EFX_SIENA_FILTER_TX_MAC_WILD:
920 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index,
925 EFSYS_ASSERT(B_FALSE);
936 static __checkReturn boolean_t
938 __in const siena_filter_spec_t *left,
939 __in const siena_filter_spec_t *right)
941 siena_filter_tbl_id_t tbl_id;
943 tbl_id = siena_filter_tbl_id(left->sfs_type);
946 if (left->sfs_type != right->sfs_type)
949 if (memcmp(left->sfs_dword, right->sfs_dword,
950 sizeof (left->sfs_dword)))
953 if ((tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
954 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) &&
955 left->sfs_dmaq_id != right->sfs_dmaq_id)
961 static __checkReturn efx_rc_t
963 __in siena_filter_tbl_t *sftp,
964 __in siena_filter_spec_t *spec,
966 __in boolean_t for_insert,
967 __out int *filter_index,
968 __out unsigned int *depth_required)
970 unsigned int hash, incr, filter_idx, depth;
972 hash = siena_filter_tbl_hash(key);
973 incr = siena_filter_tbl_increment(key);
975 filter_idx = hash & (sftp->sft_size - 1);
980 * Return success if entry is used and matches this spec
981 * or entry is unused and we are trying to insert.
983 if (siena_filter_test_used(sftp, filter_idx) ?
984 siena_filter_equal(spec,
985 &sftp->sft_spec[filter_idx]) :
987 *filter_index = filter_idx;
988 *depth_required = depth;
992 /* Return failure if we reached the maximum search depth */
993 if (depth == FILTER_CTL_SRCH_MAX)
994 return (for_insert ? EBUSY : ENOENT);
996 filter_idx = (filter_idx + incr) & (sftp->sft_size - 1);
1002 siena_filter_clear_entry(
1003 __in efx_nic_t *enp,
1004 __in siena_filter_tbl_t *sftp,
1009 if (siena_filter_test_used(sftp, index)) {
1010 siena_filter_clear_used(sftp, index);
1012 EFX_ZERO_OWORD(filter);
1013 siena_filter_push_entry(enp,
1014 sftp->sft_spec[index].sfs_type,
1017 memset(&sftp->sft_spec[index],
1018 0, sizeof (sftp->sft_spec[0]));
1023 siena_filter_tbl_clear(
1024 __in efx_nic_t *enp,
1025 __in siena_filter_tbl_id_t tbl_id)
1027 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1028 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1030 efsys_lock_state_t state;
1032 EFSYS_LOCK(enp->en_eslp, state);
1034 for (index = 0; index < sftp->sft_size; ++index) {
1035 siena_filter_clear_entry(enp, sftp, index);
1038 if (sftp->sft_used == 0)
1039 siena_filter_reset_search_depth(sfp, tbl_id);
1041 EFSYS_UNLOCK(enp->en_eslp, state);
1044 static __checkReturn efx_rc_t
1046 __in efx_nic_t *enp)
1048 siena_filter_t *sfp;
1049 siena_filter_tbl_t *sftp;
1053 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (siena_filter_t), sfp);
1060 enp->en_filter.ef_siena_filter = sfp;
1062 switch (enp->en_family) {
1063 case EFX_FAMILY_SIENA:
1064 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_IP];
1065 sftp->sft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
1067 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC];
1068 sftp->sft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
1070 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP];
1071 sftp->sft_size = FR_CZ_TX_FILTER_TBL0_ROWS;
1073 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC];
1074 sftp->sft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
1082 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1083 unsigned int bitmap_size;
1085 sftp = &sfp->sf_tbl[tbl_id];
1086 if (sftp->sft_size == 0)
1089 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1092 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1094 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, sftp->sft_bitmap);
1095 if (!sftp->sft_bitmap) {
1100 EFSYS_KMEM_ALLOC(enp->en_esip,
1101 sftp->sft_size * sizeof (*sftp->sft_spec),
1103 if (!sftp->sft_spec) {
1107 memset(sftp->sft_spec, 0,
1108 sftp->sft_size * sizeof (*sftp->sft_spec));
1121 siena_filter_fini(enp);
1124 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1130 __in efx_nic_t *enp)
1132 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1133 siena_filter_tbl_id_t tbl_id;
1135 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1136 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1141 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1142 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1143 unsigned int bitmap_size;
1145 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1148 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1150 if (sftp->sft_bitmap != NULL) {
1151 EFSYS_KMEM_FREE(enp->en_esip, bitmap_size,
1153 sftp->sft_bitmap = NULL;
1156 if (sftp->sft_spec != NULL) {
1157 EFSYS_KMEM_FREE(enp->en_esip, sftp->sft_size *
1158 sizeof (*sftp->sft_spec), sftp->sft_spec);
1159 sftp->sft_spec = NULL;
1163 EFSYS_KMEM_FREE(enp->en_esip, sizeof (siena_filter_t),
1164 enp->en_filter.ef_siena_filter);
1167 /* Restore filter state after a reset */
1168 static __checkReturn efx_rc_t
1169 siena_filter_restore(
1170 __in efx_nic_t *enp)
1172 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1173 siena_filter_tbl_id_t tbl_id;
1174 siena_filter_tbl_t *sftp;
1175 siena_filter_spec_t *spec;
1178 efsys_lock_state_t state;
1182 EFSYS_LOCK(enp->en_eslp, state);
1184 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1185 sftp = &sfp->sf_tbl[tbl_id];
1186 for (filter_idx = 0;
1187 filter_idx < sftp->sft_size;
1189 if (!siena_filter_test_used(sftp, filter_idx))
1192 spec = &sftp->sft_spec[filter_idx];
1193 if ((key = siena_filter_build(&filter, spec)) == 0) {
1197 if ((rc = siena_filter_push_entry(enp,
1198 spec->sfs_type, filter_idx, &filter)) != 0)
1203 siena_filter_push_rx_limits(enp);
1204 siena_filter_push_tx_limits(enp);
1206 EFSYS_UNLOCK(enp->en_eslp, state);
1214 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1216 EFSYS_UNLOCK(enp->en_eslp, state);
1221 static __checkReturn efx_rc_t
1223 __in efx_nic_t *enp,
1224 __inout efx_filter_spec_t *spec,
1225 __in boolean_t may_replace)
1228 siena_filter_spec_t sf_spec;
1229 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1230 siena_filter_tbl_id_t tbl_id;
1231 siena_filter_tbl_t *sftp;
1232 siena_filter_spec_t *saved_sf_spec;
1236 efsys_lock_state_t state;
1240 EFSYS_ASSERT3P(spec, !=, NULL);
1242 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1245 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1246 sftp = &sfp->sf_tbl[tbl_id];
1248 if (sftp->sft_size == 0) {
1253 key = siena_filter_build(&filter, &sf_spec);
1255 EFSYS_LOCK(enp->en_eslp, state);
1257 rc = siena_filter_search(sftp, &sf_spec, key, B_TRUE,
1258 &filter_idx, &depth);
1262 EFSYS_ASSERT3U(filter_idx, <, sftp->sft_size);
1263 saved_sf_spec = &sftp->sft_spec[filter_idx];
1265 if (siena_filter_test_used(sftp, filter_idx)) {
1266 if (may_replace == B_FALSE) {
1271 siena_filter_set_used(sftp, filter_idx);
1272 *saved_sf_spec = sf_spec;
1274 if (sfp->sf_depth[sf_spec.sfs_type] < depth) {
1275 sfp->sf_depth[sf_spec.sfs_type] = depth;
1276 if (tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1277 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC)
1278 siena_filter_push_tx_limits(enp);
1280 siena_filter_push_rx_limits(enp);
1283 siena_filter_push_entry(enp, sf_spec.sfs_type,
1284 filter_idx, &filter);
1286 EFSYS_UNLOCK(enp->en_eslp, state);
1293 EFSYS_UNLOCK(enp->en_eslp, state);
1300 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1304 static __checkReturn efx_rc_t
1305 siena_filter_delete(
1306 __in efx_nic_t *enp,
1307 __inout efx_filter_spec_t *spec)
1310 siena_filter_spec_t sf_spec;
1311 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1312 siena_filter_tbl_id_t tbl_id;
1313 siena_filter_tbl_t *sftp;
1317 efsys_lock_state_t state;
1320 EFSYS_ASSERT3P(spec, !=, NULL);
1322 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1325 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1326 sftp = &sfp->sf_tbl[tbl_id];
1328 key = siena_filter_build(&filter, &sf_spec);
1330 EFSYS_LOCK(enp->en_eslp, state);
1332 rc = siena_filter_search(sftp, &sf_spec, key, B_FALSE,
1333 &filter_idx, &depth);
1337 siena_filter_clear_entry(enp, sftp, filter_idx);
1338 if (sftp->sft_used == 0)
1339 siena_filter_reset_search_depth(sfp, tbl_id);
1341 EFSYS_UNLOCK(enp->en_eslp, state);
1345 EFSYS_UNLOCK(enp->en_eslp, state);
1349 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1353 #define MAX_SUPPORTED 4
1355 static __checkReturn efx_rc_t
1356 siena_filter_supported_filters(
1357 __in efx_nic_t *enp,
1358 __out uint32_t *list,
1359 __out size_t *length)
1362 uint32_t rx_matches[MAX_SUPPORTED];
1370 rx_matches[index++] =
1371 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1372 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
1373 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
1375 rx_matches[index++] =
1376 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1377 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
1379 if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) {
1380 rx_matches[index++] =
1381 EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC;
1383 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC;
1386 EFSYS_ASSERT3U(index, <=, MAX_SUPPORTED);
1389 memcpy(list, rx_matches, *length);
1398 #undef MAX_SUPPORTED
1400 #endif /* EFSYS_OPT_SIENA */
1402 #endif /* EFSYS_OPT_FILTER */