1 /* SPDX-License-Identifier: BSD-3-Clause
3 * Copyright (c) 2007-2018 Solarflare Communications Inc.
15 static __checkReturn efx_rc_t
23 static __checkReturn efx_rc_t
27 static __checkReturn efx_rc_t
30 __inout efx_filter_spec_t *spec,
31 __in boolean_t may_replace);
33 static __checkReturn efx_rc_t
36 __inout efx_filter_spec_t *spec);
38 static __checkReturn efx_rc_t
39 siena_filter_supported_filters(
41 __out_ecount(buffer_length) uint32_t *buffer,
42 __in size_t buffer_length,
43 __out size_t *list_lengthp);
45 #endif /* EFSYS_OPT_SIENA */
48 static const efx_filter_ops_t __efx_filter_siena_ops = {
49 siena_filter_init, /* efo_init */
50 siena_filter_fini, /* efo_fini */
51 siena_filter_restore, /* efo_restore */
52 siena_filter_add, /* efo_add */
53 siena_filter_delete, /* efo_delete */
54 siena_filter_supported_filters, /* efo_supported_filters */
55 NULL, /* efo_reconfigure */
57 #endif /* EFSYS_OPT_SIENA */
59 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
60 static const efx_filter_ops_t __efx_filter_ef10_ops = {
61 ef10_filter_init, /* efo_init */
62 ef10_filter_fini, /* efo_fini */
63 ef10_filter_restore, /* efo_restore */
64 ef10_filter_add, /* efo_add */
65 ef10_filter_delete, /* efo_delete */
66 ef10_filter_supported_filters, /* efo_supported_filters */
67 ef10_filter_reconfigure, /* efo_reconfigure */
69 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
71 __checkReturn efx_rc_t
74 __inout efx_filter_spec_t *spec)
76 const efx_filter_ops_t *efop = enp->en_efop;
78 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
79 EFSYS_ASSERT3P(spec, !=, NULL);
80 EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
82 return (efop->efo_add(enp, spec, B_FALSE));
85 __checkReturn efx_rc_t
88 __inout efx_filter_spec_t *spec)
90 const efx_filter_ops_t *efop = enp->en_efop;
92 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
93 EFSYS_ASSERT3P(spec, !=, NULL);
94 EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
96 return (efop->efo_delete(enp, spec));
99 __checkReturn efx_rc_t
105 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
107 if ((rc = enp->en_efop->efo_restore(enp)) != 0)
113 EFSYS_PROBE1(fail1, efx_rc_t, rc);
118 __checkReturn efx_rc_t
122 const efx_filter_ops_t *efop;
125 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
126 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
127 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER));
129 switch (enp->en_family) {
131 case EFX_FAMILY_SIENA:
132 efop = &__efx_filter_siena_ops;
134 #endif /* EFSYS_OPT_SIENA */
136 #if EFSYS_OPT_HUNTINGTON
137 case EFX_FAMILY_HUNTINGTON:
138 efop = &__efx_filter_ef10_ops;
140 #endif /* EFSYS_OPT_HUNTINGTON */
142 #if EFSYS_OPT_MEDFORD
143 case EFX_FAMILY_MEDFORD:
144 efop = &__efx_filter_ef10_ops;
146 #endif /* EFSYS_OPT_MEDFORD */
154 if ((rc = efop->efo_init(enp)) != 0)
158 enp->en_mod_flags |= EFX_MOD_FILTER;
164 EFSYS_PROBE1(fail1, efx_rc_t, rc);
167 enp->en_mod_flags &= ~EFX_MOD_FILTER;
175 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
176 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
177 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
179 enp->en_efop->efo_fini(enp);
182 enp->en_mod_flags &= ~EFX_MOD_FILTER;
186 * Query the possible combinations of match flags which can be filtered on.
187 * These are returned as a list, of which each 32 bit element is a bitmask
188 * formed of EFX_FILTER_MATCH flags.
190 * The combinations are ordered in priority from highest to lowest.
192 * If the provided buffer is too short to hold the list, the call with fail with
193 * ENOSPC and *list_lengthp will be set to the buffer length required.
195 __checkReturn efx_rc_t
196 efx_filter_supported_filters(
198 __out_ecount(buffer_length) uint32_t *buffer,
199 __in size_t buffer_length,
200 __out size_t *list_lengthp)
204 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
205 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
206 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
207 EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL);
209 if (buffer == NULL) {
214 rc = enp->en_efop->efo_supported_filters(enp, buffer, buffer_length,
224 EFSYS_PROBE1(fail1, efx_rc_t, rc);
229 __checkReturn efx_rc_t
230 efx_filter_reconfigure(
232 __in_ecount(6) uint8_t const *mac_addr,
233 __in boolean_t all_unicst,
234 __in boolean_t mulcst,
235 __in boolean_t all_mulcst,
236 __in boolean_t brdcst,
237 __in_ecount(6*count) uint8_t const *addrs,
242 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
243 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
244 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
246 if (enp->en_efop->efo_reconfigure != NULL) {
247 if ((rc = enp->en_efop->efo_reconfigure(enp, mac_addr,
257 EFSYS_PROBE1(fail1, efx_rc_t, rc);
263 efx_filter_spec_init_rx(
264 __out efx_filter_spec_t *spec,
265 __in efx_filter_priority_t priority,
266 __in efx_filter_flags_t flags,
269 EFSYS_ASSERT3P(spec, !=, NULL);
270 EFSYS_ASSERT3P(erp, !=, NULL);
271 EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
272 EFX_FILTER_FLAG_RX_SCATTER)) == 0);
274 memset(spec, 0, sizeof (*spec));
275 spec->efs_priority = priority;
276 spec->efs_flags = EFX_FILTER_FLAG_RX | flags;
277 spec->efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
278 spec->efs_dmaq_id = (uint16_t)erp->er_index;
282 efx_filter_spec_init_tx(
283 __out efx_filter_spec_t *spec,
286 EFSYS_ASSERT3P(spec, !=, NULL);
287 EFSYS_ASSERT3P(etp, !=, NULL);
289 memset(spec, 0, sizeof (*spec));
290 spec->efs_priority = EFX_FILTER_PRI_REQUIRED;
291 spec->efs_flags = EFX_FILTER_FLAG_TX;
292 spec->efs_dmaq_id = (uint16_t)etp->et_index;
297 * Specify IPv4 host, transport protocol and port in a filter specification
299 __checkReturn efx_rc_t
300 efx_filter_spec_set_ipv4_local(
301 __inout efx_filter_spec_t *spec,
306 EFSYS_ASSERT3P(spec, !=, NULL);
308 spec->efs_match_flags |=
309 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
310 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
311 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
312 spec->efs_ip_proto = proto;
313 spec->efs_loc_host.eo_u32[0] = host;
314 spec->efs_loc_port = port;
319 * Specify IPv4 hosts, transport protocol and ports in a filter specification
321 __checkReturn efx_rc_t
322 efx_filter_spec_set_ipv4_full(
323 __inout efx_filter_spec_t *spec,
330 EFSYS_ASSERT3P(spec, !=, NULL);
332 spec->efs_match_flags |=
333 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
334 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
335 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
336 spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
337 spec->efs_ip_proto = proto;
338 spec->efs_loc_host.eo_u32[0] = lhost;
339 spec->efs_loc_port = lport;
340 spec->efs_rem_host.eo_u32[0] = rhost;
341 spec->efs_rem_port = rport;
346 * Specify local Ethernet address and/or VID in filter specification
348 __checkReturn efx_rc_t
349 efx_filter_spec_set_eth_local(
350 __inout efx_filter_spec_t *spec,
352 __in const uint8_t *addr)
354 EFSYS_ASSERT3P(spec, !=, NULL);
355 EFSYS_ASSERT3P(addr, !=, NULL);
357 if (vid == EFX_FILTER_SPEC_VID_UNSPEC && addr == NULL)
360 if (vid != EFX_FILTER_SPEC_VID_UNSPEC) {
361 spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID;
362 spec->efs_outer_vid = vid;
365 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
366 memcpy(spec->efs_loc_mac, addr, EFX_MAC_ADDR_LEN);
372 efx_filter_spec_set_ether_type(
373 __inout efx_filter_spec_t *spec,
374 __in uint16_t ether_type)
376 EFSYS_ASSERT3P(spec, !=, NULL);
378 spec->efs_ether_type = ether_type;
379 spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
383 * Specify matching otherwise-unmatched unicast in a filter specification
385 __checkReturn efx_rc_t
386 efx_filter_spec_set_uc_def(
387 __inout efx_filter_spec_t *spec)
389 EFSYS_ASSERT3P(spec, !=, NULL);
391 spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_UCAST_DST;
396 * Specify matching otherwise-unmatched multicast in a filter specification
398 __checkReturn efx_rc_t
399 efx_filter_spec_set_mc_def(
400 __inout efx_filter_spec_t *spec)
402 EFSYS_ASSERT3P(spec, !=, NULL);
404 spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
409 __checkReturn efx_rc_t
410 efx_filter_spec_set_encap_type(
411 __inout efx_filter_spec_t *spec,
412 __in efx_tunnel_protocol_t encap_type,
413 __in efx_filter_inner_frame_match_t inner_frame_match)
415 uint32_t match_flags = 0;
419 EFSYS_ASSERT3P(spec, !=, NULL);
421 switch (encap_type) {
422 case EFX_TUNNEL_PROTOCOL_VXLAN:
423 case EFX_TUNNEL_PROTOCOL_GENEVE:
424 ip_proto = EFX_IPPROTO_UDP;
426 case EFX_TUNNEL_PROTOCOL_NVGRE:
427 ip_proto = EFX_IPPROTO_GRE;
435 switch (inner_frame_match) {
436 case EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_MCAST_DST:
437 match_flags |= EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST;
439 case EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_UCAST_DST:
440 match_flags |= EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST;
442 case EFX_FILTER_INNER_FRAME_MATCH_OTHER:
443 /* This is for when specific inner frames are to be matched. */
451 spec->efs_encap_type = encap_type;
452 spec->efs_ip_proto = ip_proto;
453 spec->efs_match_flags |= (match_flags | EFX_FILTER_MATCH_IP_PROTO);
460 EFSYS_PROBE1(fail1, efx_rc_t, rc);
465 #if EFSYS_OPT_RX_SCALE
466 __checkReturn efx_rc_t
467 efx_filter_spec_set_rss_context(
468 __inout efx_filter_spec_t *spec,
469 __in uint32_t rss_context)
473 EFSYS_ASSERT3P(spec, !=, NULL);
475 /* The filter must have been created with EFX_FILTER_FLAG_RX_RSS. */
476 if ((spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) == 0) {
481 spec->efs_rss_context = rss_context;
486 EFSYS_PROBE1(fail1, efx_rc_t, rc);
495 * "Fudge factors" - difference between programmed value and actual depth.
496 * Due to pipelined implementation we need to program H/W with a value that
497 * is larger than the hop limit we want.
499 #define FILTER_CTL_SRCH_FUDGE_WILD 3
500 #define FILTER_CTL_SRCH_FUDGE_FULL 1
503 * Hard maximum hop limit. Hardware will time-out beyond 200-something.
504 * We also need to avoid infinite loops in efx_filter_search() when the
507 #define FILTER_CTL_SRCH_MAX 200
509 static __checkReturn efx_rc_t
510 siena_filter_spec_from_gen_spec(
511 __out siena_filter_spec_t *sf_spec,
512 __in efx_filter_spec_t *gen_spec)
515 boolean_t is_full = B_FALSE;
517 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX)
518 EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX);
520 EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX);
522 /* Siena only has one RSS context */
523 if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
524 gen_spec->efs_rss_context != EFX_RSS_CONTEXT_DEFAULT) {
529 sf_spec->sfs_flags = gen_spec->efs_flags;
530 sf_spec->sfs_dmaq_id = gen_spec->efs_dmaq_id;
532 switch (gen_spec->efs_match_flags) {
533 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
534 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
535 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT:
538 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
539 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: {
540 uint32_t rhost, host1, host2;
541 uint16_t rport, port1, port2;
543 if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) {
547 if (gen_spec->efs_loc_port == 0 ||
548 (is_full && gen_spec->efs_rem_port == 0)) {
552 switch (gen_spec->efs_ip_proto) {
553 case EFX_IPPROTO_TCP:
554 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
555 sf_spec->sfs_type = (is_full ?
556 EFX_SIENA_FILTER_TX_TCP_FULL :
557 EFX_SIENA_FILTER_TX_TCP_WILD);
559 sf_spec->sfs_type = (is_full ?
560 EFX_SIENA_FILTER_RX_TCP_FULL :
561 EFX_SIENA_FILTER_RX_TCP_WILD);
564 case EFX_IPPROTO_UDP:
565 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
566 sf_spec->sfs_type = (is_full ?
567 EFX_SIENA_FILTER_TX_UDP_FULL :
568 EFX_SIENA_FILTER_TX_UDP_WILD);
570 sf_spec->sfs_type = (is_full ?
571 EFX_SIENA_FILTER_RX_UDP_FULL :
572 EFX_SIENA_FILTER_RX_UDP_WILD);
580 * The filter is constructed in terms of source and destination,
581 * with the odd wrinkle that the ports are swapped in a UDP
582 * wildcard filter. We need to convert from local and remote
583 * addresses (zero for a wildcard).
585 rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0;
586 rport = is_full ? gen_spec->efs_rem_port : 0;
587 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
588 host1 = gen_spec->efs_loc_host.eo_u32[0];
592 host2 = gen_spec->efs_loc_host.eo_u32[0];
594 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
595 if (sf_spec->sfs_type ==
596 EFX_SIENA_FILTER_TX_UDP_WILD) {
598 port2 = gen_spec->efs_loc_port;
600 port1 = gen_spec->efs_loc_port;
604 if (sf_spec->sfs_type ==
605 EFX_SIENA_FILTER_RX_UDP_WILD) {
606 port1 = gen_spec->efs_loc_port;
610 port2 = gen_spec->efs_loc_port;
613 sf_spec->sfs_dword[0] = (host1 << 16) | port1;
614 sf_spec->sfs_dword[1] = (port2 << 16) | (host1 >> 16);
615 sf_spec->sfs_dword[2] = host2;
619 case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID:
622 case EFX_FILTER_MATCH_LOC_MAC:
623 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
624 sf_spec->sfs_type = (is_full ?
625 EFX_SIENA_FILTER_TX_MAC_FULL :
626 EFX_SIENA_FILTER_TX_MAC_WILD);
628 sf_spec->sfs_type = (is_full ?
629 EFX_SIENA_FILTER_RX_MAC_FULL :
630 EFX_SIENA_FILTER_RX_MAC_WILD);
632 sf_spec->sfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0;
633 sf_spec->sfs_dword[1] =
634 gen_spec->efs_loc_mac[2] << 24 |
635 gen_spec->efs_loc_mac[3] << 16 |
636 gen_spec->efs_loc_mac[4] << 8 |
637 gen_spec->efs_loc_mac[5];
638 sf_spec->sfs_dword[2] =
639 gen_spec->efs_loc_mac[0] << 8 |
640 gen_spec->efs_loc_mac[1];
644 EFSYS_ASSERT(B_FALSE);
660 EFSYS_PROBE1(fail1, efx_rc_t, rc);
666 * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
667 * key derived from the n-tuple.
670 siena_filter_tbl_hash(
675 /* First 16 rounds */
676 tmp = 0x1fff ^ (uint16_t)(key >> 16);
677 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
678 tmp = tmp ^ tmp >> 9;
681 tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff);
682 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
683 tmp = tmp ^ tmp >> 9;
689 * To allow for hash collisions, filter search continues at these
690 * increments from the first possible entry selected by the hash.
693 siena_filter_tbl_increment(
696 return ((uint16_t)(key * 2 - 1));
699 static __checkReturn boolean_t
700 siena_filter_test_used(
701 __in siena_filter_tbl_t *sftp,
702 __in unsigned int index)
704 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
705 return ((sftp->sft_bitmap[index / 32] & (1 << (index % 32))) != 0);
709 siena_filter_set_used(
710 __in siena_filter_tbl_t *sftp,
711 __in unsigned int index)
713 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
714 sftp->sft_bitmap[index / 32] |= (1 << (index % 32));
719 siena_filter_clear_used(
720 __in siena_filter_tbl_t *sftp,
721 __in unsigned int index)
723 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
724 sftp->sft_bitmap[index / 32] &= ~(1 << (index % 32));
727 EFSYS_ASSERT3U(sftp->sft_used, >=, 0);
731 static siena_filter_tbl_id_t
733 __in siena_filter_type_t type)
735 siena_filter_tbl_id_t tbl_id;
738 case EFX_SIENA_FILTER_RX_TCP_FULL:
739 case EFX_SIENA_FILTER_RX_TCP_WILD:
740 case EFX_SIENA_FILTER_RX_UDP_FULL:
741 case EFX_SIENA_FILTER_RX_UDP_WILD:
742 tbl_id = EFX_SIENA_FILTER_TBL_RX_IP;
745 case EFX_SIENA_FILTER_RX_MAC_FULL:
746 case EFX_SIENA_FILTER_RX_MAC_WILD:
747 tbl_id = EFX_SIENA_FILTER_TBL_RX_MAC;
750 case EFX_SIENA_FILTER_TX_TCP_FULL:
751 case EFX_SIENA_FILTER_TX_TCP_WILD:
752 case EFX_SIENA_FILTER_TX_UDP_FULL:
753 case EFX_SIENA_FILTER_TX_UDP_WILD:
754 tbl_id = EFX_SIENA_FILTER_TBL_TX_IP;
757 case EFX_SIENA_FILTER_TX_MAC_FULL:
758 case EFX_SIENA_FILTER_TX_MAC_WILD:
759 tbl_id = EFX_SIENA_FILTER_TBL_TX_MAC;
763 EFSYS_ASSERT(B_FALSE);
764 tbl_id = EFX_SIENA_FILTER_NTBLS;
771 siena_filter_reset_search_depth(
772 __inout siena_filter_t *sfp,
773 __in siena_filter_tbl_id_t tbl_id)
776 case EFX_SIENA_FILTER_TBL_RX_IP:
777 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] = 0;
778 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] = 0;
779 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] = 0;
780 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] = 0;
783 case EFX_SIENA_FILTER_TBL_RX_MAC:
784 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] = 0;
785 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] = 0;
788 case EFX_SIENA_FILTER_TBL_TX_IP:
789 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] = 0;
790 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] = 0;
791 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] = 0;
792 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] = 0;
795 case EFX_SIENA_FILTER_TBL_TX_MAC:
796 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] = 0;
797 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] = 0;
801 EFSYS_ASSERT(B_FALSE);
807 siena_filter_push_rx_limits(
810 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
813 EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
815 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT,
816 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] +
817 FILTER_CTL_SRCH_FUDGE_FULL);
818 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT,
819 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] +
820 FILTER_CTL_SRCH_FUDGE_WILD);
821 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT,
822 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] +
823 FILTER_CTL_SRCH_FUDGE_FULL);
824 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT,
825 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] +
826 FILTER_CTL_SRCH_FUDGE_WILD);
828 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC].sft_size) {
829 EFX_SET_OWORD_FIELD(oword,
830 FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
831 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] +
832 FILTER_CTL_SRCH_FUDGE_FULL);
833 EFX_SET_OWORD_FIELD(oword,
834 FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
835 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] +
836 FILTER_CTL_SRCH_FUDGE_WILD);
839 EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
843 siena_filter_push_tx_limits(
846 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
849 EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
851 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP].sft_size != 0) {
852 EFX_SET_OWORD_FIELD(oword,
853 FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE,
854 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] +
855 FILTER_CTL_SRCH_FUDGE_FULL);
856 EFX_SET_OWORD_FIELD(oword,
857 FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE,
858 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] +
859 FILTER_CTL_SRCH_FUDGE_WILD);
860 EFX_SET_OWORD_FIELD(oword,
861 FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE,
862 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] +
863 FILTER_CTL_SRCH_FUDGE_FULL);
864 EFX_SET_OWORD_FIELD(oword,
865 FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE,
866 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] +
867 FILTER_CTL_SRCH_FUDGE_WILD);
870 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC].sft_size != 0) {
872 oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
873 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] +
874 FILTER_CTL_SRCH_FUDGE_FULL);
876 oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
877 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] +
878 FILTER_CTL_SRCH_FUDGE_WILD);
881 EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
884 /* Build a filter entry and return its n-tuple key. */
885 static __checkReturn uint32_t
887 __out efx_oword_t *filter,
888 __in siena_filter_spec_t *spec)
892 uint8_t type = spec->sfs_type;
893 uint32_t flags = spec->sfs_flags;
895 switch (siena_filter_tbl_id(type)) {
896 case EFX_SIENA_FILTER_TBL_RX_IP: {
897 boolean_t is_udp = (type == EFX_SIENA_FILTER_RX_UDP_FULL ||
898 type == EFX_SIENA_FILTER_RX_UDP_WILD);
899 EFX_POPULATE_OWORD_7(*filter,
901 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
903 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
904 FRF_AZ_TCP_UDP, is_udp,
905 FRF_AZ_RXQ_ID, spec->sfs_dmaq_id,
906 EFX_DWORD_2, spec->sfs_dword[2],
907 EFX_DWORD_1, spec->sfs_dword[1],
908 EFX_DWORD_0, spec->sfs_dword[0]);
913 case EFX_SIENA_FILTER_TBL_RX_MAC: {
914 boolean_t is_wild = (type == EFX_SIENA_FILTER_RX_MAC_WILD);
915 EFX_POPULATE_OWORD_7(*filter,
917 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
918 FRF_CZ_RMFT_SCATTER_EN,
919 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
920 FRF_CZ_RMFT_RXQ_ID, spec->sfs_dmaq_id,
921 FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
922 FRF_CZ_RMFT_DEST_MAC_DW1, spec->sfs_dword[2],
923 FRF_CZ_RMFT_DEST_MAC_DW0, spec->sfs_dword[1],
924 FRF_CZ_RMFT_VLAN_ID, spec->sfs_dword[0]);
929 case EFX_SIENA_FILTER_TBL_TX_IP: {
930 boolean_t is_udp = (type == EFX_SIENA_FILTER_TX_UDP_FULL ||
931 type == EFX_SIENA_FILTER_TX_UDP_WILD);
932 EFX_POPULATE_OWORD_5(*filter,
933 FRF_CZ_TIFT_TCP_UDP, is_udp,
934 FRF_CZ_TIFT_TXQ_ID, spec->sfs_dmaq_id,
935 EFX_DWORD_2, spec->sfs_dword[2],
936 EFX_DWORD_1, spec->sfs_dword[1],
937 EFX_DWORD_0, spec->sfs_dword[0]);
938 dword3 = is_udp | spec->sfs_dmaq_id << 1;
942 case EFX_SIENA_FILTER_TBL_TX_MAC: {
943 boolean_t is_wild = (type == EFX_SIENA_FILTER_TX_MAC_WILD);
944 EFX_POPULATE_OWORD_5(*filter,
945 FRF_CZ_TMFT_TXQ_ID, spec->sfs_dmaq_id,
946 FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
947 FRF_CZ_TMFT_SRC_MAC_DW1, spec->sfs_dword[2],
948 FRF_CZ_TMFT_SRC_MAC_DW0, spec->sfs_dword[1],
949 FRF_CZ_TMFT_VLAN_ID, spec->sfs_dword[0]);
950 dword3 = is_wild | spec->sfs_dmaq_id << 1;
955 EFSYS_ASSERT(B_FALSE);
968 static __checkReturn efx_rc_t
969 siena_filter_push_entry(
970 __inout efx_nic_t *enp,
971 __in siena_filter_type_t type,
973 __in efx_oword_t *eop)
978 case EFX_SIENA_FILTER_RX_TCP_FULL:
979 case EFX_SIENA_FILTER_RX_TCP_WILD:
980 case EFX_SIENA_FILTER_RX_UDP_FULL:
981 case EFX_SIENA_FILTER_RX_UDP_WILD:
982 EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index,
986 case EFX_SIENA_FILTER_RX_MAC_FULL:
987 case EFX_SIENA_FILTER_RX_MAC_WILD:
988 EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index,
992 case EFX_SIENA_FILTER_TX_TCP_FULL:
993 case EFX_SIENA_FILTER_TX_TCP_WILD:
994 case EFX_SIENA_FILTER_TX_UDP_FULL:
995 case EFX_SIENA_FILTER_TX_UDP_WILD:
996 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index,
1000 case EFX_SIENA_FILTER_TX_MAC_FULL:
1001 case EFX_SIENA_FILTER_TX_MAC_WILD:
1002 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index,
1007 EFSYS_ASSERT(B_FALSE);
1018 static __checkReturn boolean_t
1020 __in const siena_filter_spec_t *left,
1021 __in const siena_filter_spec_t *right)
1023 siena_filter_tbl_id_t tbl_id;
1025 tbl_id = siena_filter_tbl_id(left->sfs_type);
1028 if (left->sfs_type != right->sfs_type)
1031 if (memcmp(left->sfs_dword, right->sfs_dword,
1032 sizeof (left->sfs_dword)))
1035 if ((tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1036 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) &&
1037 left->sfs_dmaq_id != right->sfs_dmaq_id)
1043 static __checkReturn efx_rc_t
1044 siena_filter_search(
1045 __in siena_filter_tbl_t *sftp,
1046 __in siena_filter_spec_t *spec,
1048 __in boolean_t for_insert,
1049 __out int *filter_index,
1050 __out unsigned int *depth_required)
1052 unsigned int hash, incr, filter_idx, depth;
1054 hash = siena_filter_tbl_hash(key);
1055 incr = siena_filter_tbl_increment(key);
1057 filter_idx = hash & (sftp->sft_size - 1);
1062 * Return success if entry is used and matches this spec
1063 * or entry is unused and we are trying to insert.
1065 if (siena_filter_test_used(sftp, filter_idx) ?
1066 siena_filter_equal(spec,
1067 &sftp->sft_spec[filter_idx]) :
1069 *filter_index = filter_idx;
1070 *depth_required = depth;
1074 /* Return failure if we reached the maximum search depth */
1075 if (depth == FILTER_CTL_SRCH_MAX)
1076 return (for_insert ? EBUSY : ENOENT);
1078 filter_idx = (filter_idx + incr) & (sftp->sft_size - 1);
1084 siena_filter_clear_entry(
1085 __in efx_nic_t *enp,
1086 __in siena_filter_tbl_t *sftp,
1091 if (siena_filter_test_used(sftp, index)) {
1092 siena_filter_clear_used(sftp, index);
1094 EFX_ZERO_OWORD(filter);
1095 siena_filter_push_entry(enp,
1096 sftp->sft_spec[index].sfs_type,
1099 memset(&sftp->sft_spec[index],
1100 0, sizeof (sftp->sft_spec[0]));
1105 siena_filter_tbl_clear(
1106 __in efx_nic_t *enp,
1107 __in siena_filter_tbl_id_t tbl_id)
1109 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1110 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1112 efsys_lock_state_t state;
1114 EFSYS_LOCK(enp->en_eslp, state);
1116 for (index = 0; index < sftp->sft_size; ++index) {
1117 siena_filter_clear_entry(enp, sftp, index);
1120 if (sftp->sft_used == 0)
1121 siena_filter_reset_search_depth(sfp, tbl_id);
1123 EFSYS_UNLOCK(enp->en_eslp, state);
1126 static __checkReturn efx_rc_t
1128 __in efx_nic_t *enp)
1130 siena_filter_t *sfp;
1131 siena_filter_tbl_t *sftp;
1135 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (siena_filter_t), sfp);
1142 enp->en_filter.ef_siena_filter = sfp;
1144 switch (enp->en_family) {
1145 case EFX_FAMILY_SIENA:
1146 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_IP];
1147 sftp->sft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
1149 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC];
1150 sftp->sft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
1152 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP];
1153 sftp->sft_size = FR_CZ_TX_FILTER_TBL0_ROWS;
1155 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC];
1156 sftp->sft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
1164 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1165 unsigned int bitmap_size;
1167 sftp = &sfp->sf_tbl[tbl_id];
1168 if (sftp->sft_size == 0)
1171 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1174 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1176 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, sftp->sft_bitmap);
1177 if (!sftp->sft_bitmap) {
1182 EFSYS_KMEM_ALLOC(enp->en_esip,
1183 sftp->sft_size * sizeof (*sftp->sft_spec),
1185 if (!sftp->sft_spec) {
1189 memset(sftp->sft_spec, 0,
1190 sftp->sft_size * sizeof (*sftp->sft_spec));
1203 siena_filter_fini(enp);
1206 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1212 __in efx_nic_t *enp)
1214 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1215 siena_filter_tbl_id_t tbl_id;
1217 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1218 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1223 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1224 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1225 unsigned int bitmap_size;
1227 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1230 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1232 if (sftp->sft_bitmap != NULL) {
1233 EFSYS_KMEM_FREE(enp->en_esip, bitmap_size,
1235 sftp->sft_bitmap = NULL;
1238 if (sftp->sft_spec != NULL) {
1239 EFSYS_KMEM_FREE(enp->en_esip, sftp->sft_size *
1240 sizeof (*sftp->sft_spec), sftp->sft_spec);
1241 sftp->sft_spec = NULL;
1245 EFSYS_KMEM_FREE(enp->en_esip, sizeof (siena_filter_t),
1246 enp->en_filter.ef_siena_filter);
1249 /* Restore filter state after a reset */
1250 static __checkReturn efx_rc_t
1251 siena_filter_restore(
1252 __in efx_nic_t *enp)
1254 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1255 siena_filter_tbl_id_t tbl_id;
1256 siena_filter_tbl_t *sftp;
1257 siena_filter_spec_t *spec;
1260 efsys_lock_state_t state;
1264 EFSYS_LOCK(enp->en_eslp, state);
1266 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1267 sftp = &sfp->sf_tbl[tbl_id];
1268 for (filter_idx = 0;
1269 filter_idx < sftp->sft_size;
1271 if (!siena_filter_test_used(sftp, filter_idx))
1274 spec = &sftp->sft_spec[filter_idx];
1275 if ((key = siena_filter_build(&filter, spec)) == 0) {
1279 if ((rc = siena_filter_push_entry(enp,
1280 spec->sfs_type, filter_idx, &filter)) != 0)
1285 siena_filter_push_rx_limits(enp);
1286 siena_filter_push_tx_limits(enp);
1288 EFSYS_UNLOCK(enp->en_eslp, state);
1296 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1298 EFSYS_UNLOCK(enp->en_eslp, state);
1303 static __checkReturn efx_rc_t
1305 __in efx_nic_t *enp,
1306 __inout efx_filter_spec_t *spec,
1307 __in boolean_t may_replace)
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;
1314 siena_filter_spec_t *saved_sf_spec;
1318 efsys_lock_state_t state;
1322 EFSYS_ASSERT3P(spec, !=, NULL);
1324 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1327 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1328 sftp = &sfp->sf_tbl[tbl_id];
1330 if (sftp->sft_size == 0) {
1335 key = siena_filter_build(&filter, &sf_spec);
1337 EFSYS_LOCK(enp->en_eslp, state);
1339 rc = siena_filter_search(sftp, &sf_spec, key, B_TRUE,
1340 &filter_idx, &depth);
1344 EFSYS_ASSERT3U(filter_idx, <, sftp->sft_size);
1345 saved_sf_spec = &sftp->sft_spec[filter_idx];
1347 if (siena_filter_test_used(sftp, filter_idx)) {
1348 if (may_replace == B_FALSE) {
1353 siena_filter_set_used(sftp, filter_idx);
1354 *saved_sf_spec = sf_spec;
1356 if (sfp->sf_depth[sf_spec.sfs_type] < depth) {
1357 sfp->sf_depth[sf_spec.sfs_type] = depth;
1358 if (tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1359 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC)
1360 siena_filter_push_tx_limits(enp);
1362 siena_filter_push_rx_limits(enp);
1365 siena_filter_push_entry(enp, sf_spec.sfs_type,
1366 filter_idx, &filter);
1368 EFSYS_UNLOCK(enp->en_eslp, state);
1375 EFSYS_UNLOCK(enp->en_eslp, state);
1382 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1386 static __checkReturn efx_rc_t
1387 siena_filter_delete(
1388 __in efx_nic_t *enp,
1389 __inout efx_filter_spec_t *spec)
1392 siena_filter_spec_t sf_spec;
1393 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1394 siena_filter_tbl_id_t tbl_id;
1395 siena_filter_tbl_t *sftp;
1399 efsys_lock_state_t state;
1402 EFSYS_ASSERT3P(spec, !=, NULL);
1404 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1407 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1408 sftp = &sfp->sf_tbl[tbl_id];
1410 key = siena_filter_build(&filter, &sf_spec);
1412 EFSYS_LOCK(enp->en_eslp, state);
1414 rc = siena_filter_search(sftp, &sf_spec, key, B_FALSE,
1415 &filter_idx, &depth);
1419 siena_filter_clear_entry(enp, sftp, filter_idx);
1420 if (sftp->sft_used == 0)
1421 siena_filter_reset_search_depth(sfp, tbl_id);
1423 EFSYS_UNLOCK(enp->en_eslp, state);
1427 EFSYS_UNLOCK(enp->en_eslp, state);
1431 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1435 #define SIENA_MAX_SUPPORTED_MATCHES 4
1437 static __checkReturn efx_rc_t
1438 siena_filter_supported_filters(
1439 __in efx_nic_t *enp,
1440 __out_ecount(buffer_length) uint32_t *buffer,
1441 __in size_t buffer_length,
1442 __out size_t *list_lengthp)
1445 uint32_t rx_matches[SIENA_MAX_SUPPORTED_MATCHES];
1449 rx_matches[index++] =
1450 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1451 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
1452 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
1454 rx_matches[index++] =
1455 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1456 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
1458 if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) {
1459 rx_matches[index++] =
1460 EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC;
1462 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC;
1465 EFSYS_ASSERT3U(index, <=, SIENA_MAX_SUPPORTED_MATCHES);
1466 list_length = index;
1468 *list_lengthp = list_length;
1470 if (buffer_length < list_length) {
1475 memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0]));
1480 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1485 #undef MAX_SUPPORTED
1487 #endif /* EFSYS_OPT_SIENA */
1489 #endif /* EFSYS_OPT_FILTER */