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 __checkReturn efx_rc_t
85 __inout efx_filter_spec_t *spec)
87 const efx_filter_ops_t *efop = enp->en_efop;
89 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
90 EFSYS_ASSERT3P(spec, !=, NULL);
91 EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
93 return (efop->efo_add(enp, spec, B_FALSE));
96 __checkReturn efx_rc_t
99 __inout efx_filter_spec_t *spec)
101 const efx_filter_ops_t *efop = enp->en_efop;
103 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
104 EFSYS_ASSERT3P(spec, !=, NULL);
105 EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
107 return (efop->efo_delete(enp, spec));
110 __checkReturn efx_rc_t
116 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
118 if ((rc = enp->en_efop->efo_restore(enp)) != 0)
124 EFSYS_PROBE1(fail1, efx_rc_t, rc);
129 __checkReturn efx_rc_t
133 const efx_filter_ops_t *efop;
136 /* Check that efx_filter_spec_t is 64 bytes. */
137 EFX_STATIC_ASSERT(sizeof (efx_filter_spec_t) == 64);
139 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
140 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
141 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER));
143 switch (enp->en_family) {
145 case EFX_FAMILY_SIENA:
146 efop = &__efx_filter_siena_ops;
148 #endif /* EFSYS_OPT_SIENA */
156 if ((rc = efop->efo_init(enp)) != 0)
160 enp->en_mod_flags |= EFX_MOD_FILTER;
166 EFSYS_PROBE1(fail1, efx_rc_t, rc);
169 enp->en_mod_flags &= ~EFX_MOD_FILTER;
177 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
178 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
179 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
181 enp->en_efop->efo_fini(enp);
184 enp->en_mod_flags &= ~EFX_MOD_FILTER;
187 __checkReturn efx_rc_t
188 efx_filter_supported_filters(
190 __out uint32_t *list,
191 __out size_t *length)
195 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
196 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
197 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
198 EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL);
200 if ((rc = enp->en_efop->efo_supported_filters(enp, list, length)) != 0)
206 EFSYS_PROBE1(fail1, efx_rc_t, rc);
211 __checkReturn efx_rc_t
212 efx_filter_reconfigure(
214 __in_ecount(6) uint8_t const *mac_addr,
215 __in boolean_t all_unicst,
216 __in boolean_t mulcst,
217 __in boolean_t all_mulcst,
218 __in boolean_t brdcst,
219 __in_ecount(6*count) uint8_t const *addrs,
224 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
225 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
226 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
228 if (enp->en_efop->efo_reconfigure != NULL) {
229 if ((rc = enp->en_efop->efo_reconfigure(enp, mac_addr,
239 EFSYS_PROBE1(fail1, efx_rc_t, rc);
245 efx_filter_spec_init_rx(
246 __out efx_filter_spec_t *spec,
247 __in efx_filter_priority_t priority,
248 __in efx_filter_flags_t flags,
251 EFSYS_ASSERT3P(spec, !=, NULL);
252 EFSYS_ASSERT3P(erp, !=, NULL);
253 EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
254 EFX_FILTER_FLAG_RX_SCATTER)) == 0);
256 memset(spec, 0, sizeof (*spec));
257 spec->efs_priority = priority;
258 spec->efs_flags = EFX_FILTER_FLAG_RX | flags;
259 spec->efs_rss_context = EFX_FILTER_SPEC_RSS_CONTEXT_DEFAULT;
260 spec->efs_dmaq_id = (uint16_t)erp->er_index;
264 efx_filter_spec_init_tx(
265 __out efx_filter_spec_t *spec,
268 EFSYS_ASSERT3P(spec, !=, NULL);
269 EFSYS_ASSERT3P(etp, !=, NULL);
271 memset(spec, 0, sizeof (*spec));
272 spec->efs_priority = EFX_FILTER_PRI_REQUIRED;
273 spec->efs_flags = EFX_FILTER_FLAG_TX;
274 spec->efs_dmaq_id = (uint16_t)etp->et_index;
279 * Specify IPv4 host, transport protocol and port in a filter specification
281 __checkReturn efx_rc_t
282 efx_filter_spec_set_ipv4_local(
283 __inout efx_filter_spec_t *spec,
288 EFSYS_ASSERT3P(spec, !=, NULL);
290 spec->efs_match_flags |=
291 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
292 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
293 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
294 spec->efs_ip_proto = proto;
295 spec->efs_loc_host.eo_u32[0] = host;
296 spec->efs_loc_port = port;
301 * Specify IPv4 hosts, transport protocol and ports in a filter specification
303 __checkReturn efx_rc_t
304 efx_filter_spec_set_ipv4_full(
305 __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 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
318 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
319 spec->efs_ip_proto = proto;
320 spec->efs_loc_host.eo_u32[0] = lhost;
321 spec->efs_loc_port = lport;
322 spec->efs_rem_host.eo_u32[0] = rhost;
323 spec->efs_rem_port = rport;
328 * Specify local Ethernet address and/or VID in filter specification
330 __checkReturn efx_rc_t
331 efx_filter_spec_set_eth_local(
332 __inout efx_filter_spec_t *spec,
334 __in const uint8_t *addr)
336 EFSYS_ASSERT3P(spec, !=, NULL);
337 EFSYS_ASSERT3P(addr, !=, NULL);
339 if (vid == EFX_FILTER_SPEC_VID_UNSPEC && addr == NULL)
342 if (vid != EFX_FILTER_SPEC_VID_UNSPEC) {
343 spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID;
344 spec->efs_outer_vid = vid;
347 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
348 memcpy(spec->efs_loc_mac, addr, EFX_MAC_ADDR_LEN);
354 * Specify matching otherwise-unmatched unicast in a filter specification
356 __checkReturn efx_rc_t
357 efx_filter_spec_set_uc_def(
358 __inout efx_filter_spec_t *spec)
360 EFSYS_ASSERT3P(spec, !=, NULL);
362 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
367 * Specify matching otherwise-unmatched multicast in a filter specification
369 __checkReturn efx_rc_t
370 efx_filter_spec_set_mc_def(
371 __inout efx_filter_spec_t *spec)
373 EFSYS_ASSERT3P(spec, !=, NULL);
375 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
376 spec->efs_loc_mac[0] = 1;
385 * "Fudge factors" - difference between programmed value and actual depth.
386 * Due to pipelined implementation we need to program H/W with a value that
387 * is larger than the hop limit we want.
389 #define FILTER_CTL_SRCH_FUDGE_WILD 3
390 #define FILTER_CTL_SRCH_FUDGE_FULL 1
393 * Hard maximum hop limit. Hardware will time-out beyond 200-something.
394 * We also need to avoid infinite loops in efx_filter_search() when the
397 #define FILTER_CTL_SRCH_MAX 200
399 static __checkReturn efx_rc_t
400 siena_filter_spec_from_gen_spec(
401 __out siena_filter_spec_t *sf_spec,
402 __in efx_filter_spec_t *gen_spec)
405 boolean_t is_full = B_FALSE;
407 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX)
408 EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX);
410 EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX);
412 /* Falconsiena only has one RSS context */
413 if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
414 gen_spec->efs_rss_context != 0) {
419 sf_spec->sfs_flags = gen_spec->efs_flags;
420 sf_spec->sfs_dmaq_id = gen_spec->efs_dmaq_id;
422 switch (gen_spec->efs_match_flags) {
423 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
424 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
425 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT:
428 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
429 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: {
430 uint32_t rhost, host1, host2;
431 uint16_t rport, port1, port2;
433 if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) {
437 if (gen_spec->efs_loc_port == 0 ||
438 (is_full && gen_spec->efs_rem_port == 0)) {
442 switch (gen_spec->efs_ip_proto) {
443 case EFX_IPPROTO_TCP:
444 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
445 sf_spec->sfs_type = (is_full ?
446 EFX_SIENA_FILTER_TX_TCP_FULL :
447 EFX_SIENA_FILTER_TX_TCP_WILD);
449 sf_spec->sfs_type = (is_full ?
450 EFX_SIENA_FILTER_RX_TCP_FULL :
451 EFX_SIENA_FILTER_RX_TCP_WILD);
454 case EFX_IPPROTO_UDP:
455 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
456 sf_spec->sfs_type = (is_full ?
457 EFX_SIENA_FILTER_TX_UDP_FULL :
458 EFX_SIENA_FILTER_TX_UDP_WILD);
460 sf_spec->sfs_type = (is_full ?
461 EFX_SIENA_FILTER_RX_UDP_FULL :
462 EFX_SIENA_FILTER_RX_UDP_WILD);
470 * The filter is constructed in terms of source and destination,
471 * with the odd wrinkle that the ports are swapped in a UDP
472 * wildcard filter. We need to convert from local and remote
473 * addresses (zero for a wildcard).
475 rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0;
476 rport = is_full ? gen_spec->efs_rem_port : 0;
477 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
478 host1 = gen_spec->efs_loc_host.eo_u32[0];
482 host2 = gen_spec->efs_loc_host.eo_u32[0];
484 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
485 if (sf_spec->sfs_type ==
486 EFX_SIENA_FILTER_TX_UDP_WILD) {
488 port2 = gen_spec->efs_loc_port;
490 port1 = gen_spec->efs_loc_port;
494 if (sf_spec->sfs_type ==
495 EFX_SIENA_FILTER_RX_UDP_WILD) {
496 port1 = gen_spec->efs_loc_port;
500 port2 = gen_spec->efs_loc_port;
503 sf_spec->sfs_dword[0] = (host1 << 16) | port1;
504 sf_spec->sfs_dword[1] = (port2 << 16) | (host1 >> 16);
505 sf_spec->sfs_dword[2] = host2;
509 case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID:
512 case EFX_FILTER_MATCH_LOC_MAC:
513 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
514 sf_spec->sfs_type = (is_full ?
515 EFX_SIENA_FILTER_TX_MAC_FULL :
516 EFX_SIENA_FILTER_TX_MAC_WILD);
518 sf_spec->sfs_type = (is_full ?
519 EFX_SIENA_FILTER_RX_MAC_FULL :
520 EFX_SIENA_FILTER_RX_MAC_WILD);
522 sf_spec->sfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0;
523 sf_spec->sfs_dword[1] =
524 gen_spec->efs_loc_mac[2] << 24 |
525 gen_spec->efs_loc_mac[3] << 16 |
526 gen_spec->efs_loc_mac[4] << 8 |
527 gen_spec->efs_loc_mac[5];
528 sf_spec->sfs_dword[2] =
529 gen_spec->efs_loc_mac[0] << 8 |
530 gen_spec->efs_loc_mac[1];
534 EFSYS_ASSERT(B_FALSE);
550 EFSYS_PROBE1(fail1, efx_rc_t, rc);
556 * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
557 * key derived from the n-tuple.
560 siena_filter_tbl_hash(
565 /* First 16 rounds */
566 tmp = 0x1fff ^ (uint16_t)(key >> 16);
567 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
568 tmp = tmp ^ tmp >> 9;
571 tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff);
572 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
573 tmp = tmp ^ tmp >> 9;
579 * To allow for hash collisions, filter search continues at these
580 * increments from the first possible entry selected by the hash.
583 siena_filter_tbl_increment(
586 return ((uint16_t)(key * 2 - 1));
589 static __checkReturn boolean_t
590 siena_filter_test_used(
591 __in siena_filter_tbl_t *sftp,
592 __in unsigned int index)
594 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
595 return ((sftp->sft_bitmap[index / 32] & (1 << (index % 32))) != 0);
599 siena_filter_set_used(
600 __in siena_filter_tbl_t *sftp,
601 __in unsigned int index)
603 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
604 sftp->sft_bitmap[index / 32] |= (1 << (index % 32));
609 siena_filter_clear_used(
610 __in siena_filter_tbl_t *sftp,
611 __in unsigned int index)
613 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
614 sftp->sft_bitmap[index / 32] &= ~(1 << (index % 32));
617 EFSYS_ASSERT3U(sftp->sft_used, >=, 0);
621 static siena_filter_tbl_id_t
623 __in siena_filter_type_t type)
625 siena_filter_tbl_id_t tbl_id;
628 case EFX_SIENA_FILTER_RX_TCP_FULL:
629 case EFX_SIENA_FILTER_RX_TCP_WILD:
630 case EFX_SIENA_FILTER_RX_UDP_FULL:
631 case EFX_SIENA_FILTER_RX_UDP_WILD:
632 tbl_id = EFX_SIENA_FILTER_TBL_RX_IP;
635 case EFX_SIENA_FILTER_RX_MAC_FULL:
636 case EFX_SIENA_FILTER_RX_MAC_WILD:
637 tbl_id = EFX_SIENA_FILTER_TBL_RX_MAC;
640 case EFX_SIENA_FILTER_TX_TCP_FULL:
641 case EFX_SIENA_FILTER_TX_TCP_WILD:
642 case EFX_SIENA_FILTER_TX_UDP_FULL:
643 case EFX_SIENA_FILTER_TX_UDP_WILD:
644 tbl_id = EFX_SIENA_FILTER_TBL_TX_IP;
647 case EFX_SIENA_FILTER_TX_MAC_FULL:
648 case EFX_SIENA_FILTER_TX_MAC_WILD:
649 tbl_id = EFX_SIENA_FILTER_TBL_TX_MAC;
653 EFSYS_ASSERT(B_FALSE);
654 tbl_id = EFX_SIENA_FILTER_NTBLS;
661 siena_filter_reset_search_depth(
662 __inout siena_filter_t *sfp,
663 __in siena_filter_tbl_id_t tbl_id)
666 case EFX_SIENA_FILTER_TBL_RX_IP:
667 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] = 0;
668 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] = 0;
669 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] = 0;
670 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] = 0;
673 case EFX_SIENA_FILTER_TBL_RX_MAC:
674 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] = 0;
675 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] = 0;
678 case EFX_SIENA_FILTER_TBL_TX_IP:
679 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] = 0;
680 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] = 0;
681 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] = 0;
682 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] = 0;
685 case EFX_SIENA_FILTER_TBL_TX_MAC:
686 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] = 0;
687 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] = 0;
691 EFSYS_ASSERT(B_FALSE);
697 siena_filter_push_rx_limits(
700 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
703 EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
705 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT,
706 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] +
707 FILTER_CTL_SRCH_FUDGE_FULL);
708 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT,
709 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] +
710 FILTER_CTL_SRCH_FUDGE_WILD);
711 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT,
712 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] +
713 FILTER_CTL_SRCH_FUDGE_FULL);
714 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT,
715 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] +
716 FILTER_CTL_SRCH_FUDGE_WILD);
718 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC].sft_size) {
719 EFX_SET_OWORD_FIELD(oword,
720 FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
721 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] +
722 FILTER_CTL_SRCH_FUDGE_FULL);
723 EFX_SET_OWORD_FIELD(oword,
724 FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
725 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] +
726 FILTER_CTL_SRCH_FUDGE_WILD);
729 EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
733 siena_filter_push_tx_limits(
736 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
739 EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
741 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP].sft_size != 0) {
742 EFX_SET_OWORD_FIELD(oword,
743 FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE,
744 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] +
745 FILTER_CTL_SRCH_FUDGE_FULL);
746 EFX_SET_OWORD_FIELD(oword,
747 FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE,
748 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] +
749 FILTER_CTL_SRCH_FUDGE_WILD);
750 EFX_SET_OWORD_FIELD(oword,
751 FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE,
752 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] +
753 FILTER_CTL_SRCH_FUDGE_FULL);
754 EFX_SET_OWORD_FIELD(oword,
755 FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE,
756 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] +
757 FILTER_CTL_SRCH_FUDGE_WILD);
760 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC].sft_size != 0) {
762 oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
763 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] +
764 FILTER_CTL_SRCH_FUDGE_FULL);
766 oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
767 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] +
768 FILTER_CTL_SRCH_FUDGE_WILD);
771 EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
774 /* Build a filter entry and return its n-tuple key. */
775 static __checkReturn uint32_t
777 __out efx_oword_t *filter,
778 __in siena_filter_spec_t *spec)
782 uint8_t type = spec->sfs_type;
783 uint32_t flags = spec->sfs_flags;
785 switch (siena_filter_tbl_id(type)) {
786 case EFX_SIENA_FILTER_TBL_RX_IP: {
787 boolean_t is_udp = (type == EFX_SIENA_FILTER_RX_UDP_FULL ||
788 type == EFX_SIENA_FILTER_RX_UDP_WILD);
789 EFX_POPULATE_OWORD_7(*filter,
791 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
793 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
794 FRF_AZ_TCP_UDP, is_udp,
795 FRF_AZ_RXQ_ID, spec->sfs_dmaq_id,
796 EFX_DWORD_2, spec->sfs_dword[2],
797 EFX_DWORD_1, spec->sfs_dword[1],
798 EFX_DWORD_0, spec->sfs_dword[0]);
803 case EFX_SIENA_FILTER_TBL_RX_MAC: {
804 boolean_t is_wild = (type == EFX_SIENA_FILTER_RX_MAC_WILD);
805 EFX_POPULATE_OWORD_7(*filter,
807 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
808 FRF_CZ_RMFT_SCATTER_EN,
809 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
810 FRF_CZ_RMFT_RXQ_ID, spec->sfs_dmaq_id,
811 FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
812 FRF_CZ_RMFT_DEST_MAC_DW1, spec->sfs_dword[2],
813 FRF_CZ_RMFT_DEST_MAC_DW0, spec->sfs_dword[1],
814 FRF_CZ_RMFT_VLAN_ID, spec->sfs_dword[0]);
819 case EFX_SIENA_FILTER_TBL_TX_IP: {
820 boolean_t is_udp = (type == EFX_SIENA_FILTER_TX_UDP_FULL ||
821 type == EFX_SIENA_FILTER_TX_UDP_WILD);
822 EFX_POPULATE_OWORD_5(*filter,
823 FRF_CZ_TIFT_TCP_UDP, is_udp,
824 FRF_CZ_TIFT_TXQ_ID, spec->sfs_dmaq_id,
825 EFX_DWORD_2, spec->sfs_dword[2],
826 EFX_DWORD_1, spec->sfs_dword[1],
827 EFX_DWORD_0, spec->sfs_dword[0]);
828 dword3 = is_udp | spec->sfs_dmaq_id << 1;
832 case EFX_SIENA_FILTER_TBL_TX_MAC: {
833 boolean_t is_wild = (type == EFX_SIENA_FILTER_TX_MAC_WILD);
834 EFX_POPULATE_OWORD_5(*filter,
835 FRF_CZ_TMFT_TXQ_ID, spec->sfs_dmaq_id,
836 FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
837 FRF_CZ_TMFT_SRC_MAC_DW1, spec->sfs_dword[2],
838 FRF_CZ_TMFT_SRC_MAC_DW0, spec->sfs_dword[1],
839 FRF_CZ_TMFT_VLAN_ID, spec->sfs_dword[0]);
840 dword3 = is_wild | spec->sfs_dmaq_id << 1;
845 EFSYS_ASSERT(B_FALSE);
858 static __checkReturn efx_rc_t
859 siena_filter_push_entry(
860 __inout efx_nic_t *enp,
861 __in siena_filter_type_t type,
863 __in efx_oword_t *eop)
868 case EFX_SIENA_FILTER_RX_TCP_FULL:
869 case EFX_SIENA_FILTER_RX_TCP_WILD:
870 case EFX_SIENA_FILTER_RX_UDP_FULL:
871 case EFX_SIENA_FILTER_RX_UDP_WILD:
872 EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index,
876 case EFX_SIENA_FILTER_RX_MAC_FULL:
877 case EFX_SIENA_FILTER_RX_MAC_WILD:
878 EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index,
882 case EFX_SIENA_FILTER_TX_TCP_FULL:
883 case EFX_SIENA_FILTER_TX_TCP_WILD:
884 case EFX_SIENA_FILTER_TX_UDP_FULL:
885 case EFX_SIENA_FILTER_TX_UDP_WILD:
886 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index,
890 case EFX_SIENA_FILTER_TX_MAC_FULL:
891 case EFX_SIENA_FILTER_TX_MAC_WILD:
892 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index,
897 EFSYS_ASSERT(B_FALSE);
908 static __checkReturn boolean_t
910 __in const siena_filter_spec_t *left,
911 __in const siena_filter_spec_t *right)
913 siena_filter_tbl_id_t tbl_id;
915 tbl_id = siena_filter_tbl_id(left->sfs_type);
918 if (left->sfs_type != right->sfs_type)
921 if (memcmp(left->sfs_dword, right->sfs_dword,
922 sizeof (left->sfs_dword)))
925 if ((tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
926 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) &&
927 left->sfs_dmaq_id != right->sfs_dmaq_id)
933 static __checkReturn efx_rc_t
935 __in siena_filter_tbl_t *sftp,
936 __in siena_filter_spec_t *spec,
938 __in boolean_t for_insert,
939 __out int *filter_index,
940 __out unsigned int *depth_required)
942 unsigned int hash, incr, filter_idx, depth;
944 hash = siena_filter_tbl_hash(key);
945 incr = siena_filter_tbl_increment(key);
947 filter_idx = hash & (sftp->sft_size - 1);
952 * Return success if entry is used and matches this spec
953 * or entry is unused and we are trying to insert.
955 if (siena_filter_test_used(sftp, filter_idx) ?
956 siena_filter_equal(spec,
957 &sftp->sft_spec[filter_idx]) :
959 *filter_index = filter_idx;
960 *depth_required = depth;
964 /* Return failure if we reached the maximum search depth */
965 if (depth == FILTER_CTL_SRCH_MAX)
966 return (for_insert ? EBUSY : ENOENT);
968 filter_idx = (filter_idx + incr) & (sftp->sft_size - 1);
974 siena_filter_clear_entry(
976 __in siena_filter_tbl_t *sftp,
981 if (siena_filter_test_used(sftp, index)) {
982 siena_filter_clear_used(sftp, index);
984 EFX_ZERO_OWORD(filter);
985 siena_filter_push_entry(enp,
986 sftp->sft_spec[index].sfs_type,
989 memset(&sftp->sft_spec[index],
990 0, sizeof (sftp->sft_spec[0]));
995 siena_filter_tbl_clear(
997 __in siena_filter_tbl_id_t tbl_id)
999 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1000 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1002 efsys_lock_state_t state;
1004 EFSYS_LOCK(enp->en_eslp, state);
1006 for (index = 0; index < sftp->sft_size; ++index) {
1007 siena_filter_clear_entry(enp, sftp, index);
1010 if (sftp->sft_used == 0)
1011 siena_filter_reset_search_depth(sfp, tbl_id);
1013 EFSYS_UNLOCK(enp->en_eslp, state);
1016 static __checkReturn efx_rc_t
1018 __in efx_nic_t *enp)
1020 siena_filter_t *sfp;
1021 siena_filter_tbl_t *sftp;
1025 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (siena_filter_t), sfp);
1032 enp->en_filter.ef_siena_filter = sfp;
1034 switch (enp->en_family) {
1035 case EFX_FAMILY_SIENA:
1036 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_IP];
1037 sftp->sft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
1039 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC];
1040 sftp->sft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
1042 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP];
1043 sftp->sft_size = FR_CZ_TX_FILTER_TBL0_ROWS;
1045 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC];
1046 sftp->sft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
1054 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1055 unsigned int bitmap_size;
1057 sftp = &sfp->sf_tbl[tbl_id];
1058 if (sftp->sft_size == 0)
1061 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1064 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1066 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, sftp->sft_bitmap);
1067 if (!sftp->sft_bitmap) {
1072 EFSYS_KMEM_ALLOC(enp->en_esip,
1073 sftp->sft_size * sizeof (*sftp->sft_spec),
1075 if (!sftp->sft_spec) {
1079 memset(sftp->sft_spec, 0,
1080 sftp->sft_size * sizeof (*sftp->sft_spec));
1093 siena_filter_fini(enp);
1096 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1102 __in efx_nic_t *enp)
1104 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1105 siena_filter_tbl_id_t tbl_id;
1107 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1108 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1113 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1114 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1115 unsigned int bitmap_size;
1117 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1120 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1122 if (sftp->sft_bitmap != NULL) {
1123 EFSYS_KMEM_FREE(enp->en_esip, bitmap_size,
1125 sftp->sft_bitmap = NULL;
1128 if (sftp->sft_spec != NULL) {
1129 EFSYS_KMEM_FREE(enp->en_esip, sftp->sft_size *
1130 sizeof (*sftp->sft_spec), sftp->sft_spec);
1131 sftp->sft_spec = NULL;
1135 EFSYS_KMEM_FREE(enp->en_esip, sizeof (siena_filter_t),
1136 enp->en_filter.ef_siena_filter);
1139 /* Restore filter state after a reset */
1140 static __checkReturn efx_rc_t
1141 siena_filter_restore(
1142 __in efx_nic_t *enp)
1144 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1145 siena_filter_tbl_id_t tbl_id;
1146 siena_filter_tbl_t *sftp;
1147 siena_filter_spec_t *spec;
1150 efsys_lock_state_t state;
1154 EFSYS_LOCK(enp->en_eslp, state);
1156 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1157 sftp = &sfp->sf_tbl[tbl_id];
1158 for (filter_idx = 0;
1159 filter_idx < sftp->sft_size;
1161 if (!siena_filter_test_used(sftp, filter_idx))
1164 spec = &sftp->sft_spec[filter_idx];
1165 if ((key = siena_filter_build(&filter, spec)) == 0) {
1169 if ((rc = siena_filter_push_entry(enp,
1170 spec->sfs_type, filter_idx, &filter)) != 0)
1175 siena_filter_push_rx_limits(enp);
1176 siena_filter_push_tx_limits(enp);
1178 EFSYS_UNLOCK(enp->en_eslp, state);
1186 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1188 EFSYS_UNLOCK(enp->en_eslp, state);
1193 static __checkReturn efx_rc_t
1195 __in efx_nic_t *enp,
1196 __inout efx_filter_spec_t *spec,
1197 __in boolean_t may_replace)
1200 siena_filter_spec_t sf_spec;
1201 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1202 siena_filter_tbl_id_t tbl_id;
1203 siena_filter_tbl_t *sftp;
1204 siena_filter_spec_t *saved_sf_spec;
1208 efsys_lock_state_t state;
1212 EFSYS_ASSERT3P(spec, !=, NULL);
1214 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1217 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1218 sftp = &sfp->sf_tbl[tbl_id];
1220 if (sftp->sft_size == 0) {
1225 key = siena_filter_build(&filter, &sf_spec);
1227 EFSYS_LOCK(enp->en_eslp, state);
1229 rc = siena_filter_search(sftp, &sf_spec, key, B_TRUE,
1230 &filter_idx, &depth);
1234 EFSYS_ASSERT3U(filter_idx, <, sftp->sft_size);
1235 saved_sf_spec = &sftp->sft_spec[filter_idx];
1237 if (siena_filter_test_used(sftp, filter_idx)) {
1238 if (may_replace == B_FALSE) {
1243 siena_filter_set_used(sftp, filter_idx);
1244 *saved_sf_spec = sf_spec;
1246 if (sfp->sf_depth[sf_spec.sfs_type] < depth) {
1247 sfp->sf_depth[sf_spec.sfs_type] = depth;
1248 if (tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1249 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC)
1250 siena_filter_push_tx_limits(enp);
1252 siena_filter_push_rx_limits(enp);
1255 siena_filter_push_entry(enp, sf_spec.sfs_type,
1256 filter_idx, &filter);
1258 EFSYS_UNLOCK(enp->en_eslp, state);
1265 EFSYS_UNLOCK(enp->en_eslp, state);
1272 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1276 static __checkReturn efx_rc_t
1277 siena_filter_delete(
1278 __in efx_nic_t *enp,
1279 __inout efx_filter_spec_t *spec)
1282 siena_filter_spec_t sf_spec;
1283 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1284 siena_filter_tbl_id_t tbl_id;
1285 siena_filter_tbl_t *sftp;
1289 efsys_lock_state_t state;
1292 EFSYS_ASSERT3P(spec, !=, NULL);
1294 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1297 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1298 sftp = &sfp->sf_tbl[tbl_id];
1300 key = siena_filter_build(&filter, &sf_spec);
1302 EFSYS_LOCK(enp->en_eslp, state);
1304 rc = siena_filter_search(sftp, &sf_spec, key, B_FALSE,
1305 &filter_idx, &depth);
1309 siena_filter_clear_entry(enp, sftp, filter_idx);
1310 if (sftp->sft_used == 0)
1311 siena_filter_reset_search_depth(sfp, tbl_id);
1313 EFSYS_UNLOCK(enp->en_eslp, state);
1317 EFSYS_UNLOCK(enp->en_eslp, state);
1321 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1325 #define MAX_SUPPORTED 4
1327 static __checkReturn efx_rc_t
1328 siena_filter_supported_filters(
1329 __in efx_nic_t *enp,
1330 __out uint32_t *list,
1331 __out size_t *length)
1334 uint32_t rx_matches[MAX_SUPPORTED];
1342 rx_matches[index++] =
1343 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1344 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
1345 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
1347 rx_matches[index++] =
1348 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1349 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
1351 if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) {
1352 rx_matches[index++] =
1353 EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC;
1355 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC;
1358 EFSYS_ASSERT3U(index, <=, MAX_SUPPORTED);
1361 memcpy(list, rx_matches, *length);
1370 #undef MAX_SUPPORTED
1372 #endif /* EFSYS_OPT_SIENA */
1374 #endif /* EFSYS_OPT_FILTER */