]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/sfxge/common/efx_filter.c
THIS BRANCH IS OBSOLETE, PLEASE READ:
[FreeBSD/FreeBSD.git] / sys / dev / sfxge / common / efx_filter.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2007-2016 Solarflare Communications Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice,
11  *    this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * The views and conclusions contained in the software and documentation are
29  * those of the authors and should not be interpreted as representing official
30  * policies, either expressed or implied, of the FreeBSD Project.
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include "efx.h"
37 #include "efx_impl.h"
38
39 #if EFSYS_OPT_FILTER
40
41 #if EFSYS_OPT_SIENA
42
43 static  __checkReturn   efx_rc_t
44 siena_filter_init(
45         __in            efx_nic_t *enp);
46
47 static                  void
48 siena_filter_fini(
49         __in            efx_nic_t *enp);
50
51 static  __checkReturn   efx_rc_t
52 siena_filter_restore(
53         __in            efx_nic_t *enp);
54
55 static  __checkReturn   efx_rc_t
56 siena_filter_add(
57         __in            efx_nic_t *enp,
58         __inout         efx_filter_spec_t *spec,
59         __in            boolean_t may_replace);
60
61 static  __checkReturn   efx_rc_t
62 siena_filter_delete(
63         __in            efx_nic_t *enp,
64         __inout         efx_filter_spec_t *spec);
65
66 static  __checkReturn   efx_rc_t
67 siena_filter_supported_filters(
68         __in                            efx_nic_t *enp,
69         __out_ecount(buffer_length)     uint32_t *buffer,
70         __in                            size_t buffer_length,
71         __out                           size_t *list_lengthp);
72
73 #endif /* EFSYS_OPT_SIENA */
74
75 #if EFSYS_OPT_SIENA
76 static const efx_filter_ops_t   __efx_filter_siena_ops = {
77         siena_filter_init,              /* efo_init */
78         siena_filter_fini,              /* efo_fini */
79         siena_filter_restore,           /* efo_restore */
80         siena_filter_add,               /* efo_add */
81         siena_filter_delete,            /* efo_delete */
82         siena_filter_supported_filters, /* efo_supported_filters */
83         NULL,                           /* efo_reconfigure */
84 };
85 #endif /* EFSYS_OPT_SIENA */
86
87 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
88 static const efx_filter_ops_t   __efx_filter_ef10_ops = {
89         ef10_filter_init,               /* efo_init */
90         ef10_filter_fini,               /* efo_fini */
91         ef10_filter_restore,            /* efo_restore */
92         ef10_filter_add,                /* efo_add */
93         ef10_filter_delete,             /* efo_delete */
94         ef10_filter_supported_filters,  /* efo_supported_filters */
95         ef10_filter_reconfigure,        /* efo_reconfigure */
96 };
97 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
98
99         __checkReturn   efx_rc_t
100 efx_filter_insert(
101         __in            efx_nic_t *enp,
102         __inout         efx_filter_spec_t *spec)
103 {
104         const efx_filter_ops_t *efop = enp->en_efop;
105         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
106         efx_rc_t rc;
107
108         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
109         EFSYS_ASSERT3P(spec, !=, NULL);
110         EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
111
112         if ((spec->efs_flags & EFX_FILTER_FLAG_ACTION_MARK) &&
113             !encp->enc_filter_action_mark_supported) {
114                 rc = ENOTSUP;
115                 goto fail1;
116         }
117
118         if ((spec->efs_flags & EFX_FILTER_FLAG_ACTION_FLAG) &&
119             !encp->enc_filter_action_flag_supported) {
120                 rc = ENOTSUP;
121                 goto fail2;
122         }
123
124         return (efop->efo_add(enp, spec, B_FALSE));
125
126 fail2:
127         EFSYS_PROBE(fail2);
128 fail1:
129         EFSYS_PROBE1(fail1, efx_rc_t, rc);
130
131         return (rc);
132 }
133
134         __checkReturn   efx_rc_t
135 efx_filter_remove(
136         __in            efx_nic_t *enp,
137         __inout         efx_filter_spec_t *spec)
138 {
139         const efx_filter_ops_t *efop = enp->en_efop;
140
141         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
142         EFSYS_ASSERT3P(spec, !=, NULL);
143         EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
144
145         return (efop->efo_delete(enp, spec));
146 }
147
148         __checkReturn   efx_rc_t
149 efx_filter_restore(
150         __in            efx_nic_t *enp)
151 {
152         efx_rc_t rc;
153
154         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
155
156         if ((rc = enp->en_efop->efo_restore(enp)) != 0)
157                 goto fail1;
158
159         return (0);
160
161 fail1:
162         EFSYS_PROBE1(fail1, efx_rc_t, rc);
163
164         return (rc);
165 }
166
167         __checkReturn   efx_rc_t
168 efx_filter_init(
169         __in            efx_nic_t *enp)
170 {
171         const efx_filter_ops_t *efop;
172         efx_rc_t rc;
173
174         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
175         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
176         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER));
177
178         switch (enp->en_family) {
179 #if EFSYS_OPT_SIENA
180         case EFX_FAMILY_SIENA:
181                 efop = &__efx_filter_siena_ops;
182                 break;
183 #endif /* EFSYS_OPT_SIENA */
184
185 #if EFSYS_OPT_HUNTINGTON
186         case EFX_FAMILY_HUNTINGTON:
187                 efop = &__efx_filter_ef10_ops;
188                 break;
189 #endif /* EFSYS_OPT_HUNTINGTON */
190
191 #if EFSYS_OPT_MEDFORD
192         case EFX_FAMILY_MEDFORD:
193                 efop = &__efx_filter_ef10_ops;
194                 break;
195 #endif /* EFSYS_OPT_MEDFORD */
196
197 #if EFSYS_OPT_MEDFORD2
198         case EFX_FAMILY_MEDFORD2:
199                 efop = &__efx_filter_ef10_ops;
200                 break;
201 #endif /* EFSYS_OPT_MEDFORD2 */
202
203         default:
204                 EFSYS_ASSERT(0);
205                 rc = ENOTSUP;
206                 goto fail1;
207         }
208
209         if ((rc = efop->efo_init(enp)) != 0)
210                 goto fail2;
211
212         enp->en_efop = efop;
213         enp->en_mod_flags |= EFX_MOD_FILTER;
214         return (0);
215
216 fail2:
217         EFSYS_PROBE(fail2);
218 fail1:
219         EFSYS_PROBE1(fail1, efx_rc_t, rc);
220
221         enp->en_efop = NULL;
222         enp->en_mod_flags &= ~EFX_MOD_FILTER;
223         return (rc);
224 }
225
226                         void
227 efx_filter_fini(
228         __in            efx_nic_t *enp)
229 {
230         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
231         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
232         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
233
234         enp->en_efop->efo_fini(enp);
235
236         enp->en_efop = NULL;
237         enp->en_mod_flags &= ~EFX_MOD_FILTER;
238 }
239
240 /*
241  * Query the possible combinations of match flags which can be filtered on.
242  * These are returned as a list, of which each 32 bit element is a bitmask
243  * formed of EFX_FILTER_MATCH flags.
244  *
245  * The combinations are ordered in priority from highest to lowest.
246  *
247  * If the provided buffer is too short to hold the list, the call with fail with
248  * ENOSPC and *list_lengthp will be set to the buffer length required.
249  */
250         __checkReturn   efx_rc_t
251 efx_filter_supported_filters(
252         __in                            efx_nic_t *enp,
253         __out_ecount(buffer_length)     uint32_t *buffer,
254         __in                            size_t buffer_length,
255         __out                           size_t *list_lengthp)
256 {
257         efx_rc_t rc;
258
259         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
260         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
261         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
262         EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL);
263
264         if (buffer == NULL) {
265                 rc = EINVAL;
266                 goto fail1;
267         }
268
269         rc = enp->en_efop->efo_supported_filters(enp, buffer, buffer_length,
270                                                     list_lengthp);
271         if (rc != 0)
272                 goto fail2;
273
274         return (0);
275
276 fail2:
277         EFSYS_PROBE(fail2);
278 fail1:
279         EFSYS_PROBE1(fail1, efx_rc_t, rc);
280
281         return (rc);
282 }
283
284         __checkReturn   efx_rc_t
285 efx_filter_reconfigure(
286         __in                            efx_nic_t *enp,
287         __in_ecount(6)                  uint8_t const *mac_addr,
288         __in                            boolean_t all_unicst,
289         __in                            boolean_t mulcst,
290         __in                            boolean_t all_mulcst,
291         __in                            boolean_t brdcst,
292         __in_ecount(6*count)            uint8_t const *addrs,
293         __in                            uint32_t count)
294 {
295         efx_rc_t rc;
296
297         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
298         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
299         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
300
301         if (enp->en_efop->efo_reconfigure != NULL) {
302                 if ((rc = enp->en_efop->efo_reconfigure(enp, mac_addr,
303                                                         all_unicst, mulcst,
304                                                         all_mulcst, brdcst,
305                                                         addrs, count)) != 0)
306                         goto fail1;
307         }
308
309         return (0);
310
311 fail1:
312         EFSYS_PROBE1(fail1, efx_rc_t, rc);
313
314         return (rc);
315 }
316
317                 void
318 efx_filter_spec_init_rx(
319         __out           efx_filter_spec_t *spec,
320         __in            efx_filter_priority_t priority,
321         __in            efx_filter_flags_t flags,
322         __in            efx_rxq_t *erp)
323 {
324         EFSYS_ASSERT3P(spec, !=, NULL);
325         EFSYS_ASSERT3P(erp, !=, NULL);
326         EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
327                                 EFX_FILTER_FLAG_RX_SCATTER)) == 0);
328
329         memset(spec, 0, sizeof (*spec));
330         spec->efs_priority = priority;
331         spec->efs_flags = EFX_FILTER_FLAG_RX | flags;
332         spec->efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
333         spec->efs_dmaq_id = (uint16_t)erp->er_index;
334 }
335
336                 void
337 efx_filter_spec_init_tx(
338         __out           efx_filter_spec_t *spec,
339         __in            efx_txq_t *etp)
340 {
341         EFSYS_ASSERT3P(spec, !=, NULL);
342         EFSYS_ASSERT3P(etp, !=, NULL);
343
344         memset(spec, 0, sizeof (*spec));
345         spec->efs_priority = EFX_FILTER_PRI_REQUIRED;
346         spec->efs_flags = EFX_FILTER_FLAG_TX;
347         spec->efs_dmaq_id = (uint16_t)etp->et_index;
348 }
349
350 /*
351  *  Specify IPv4 host, transport protocol and port in a filter specification
352  */
353 __checkReturn           efx_rc_t
354 efx_filter_spec_set_ipv4_local(
355         __inout         efx_filter_spec_t *spec,
356         __in            uint8_t proto,
357         __in            uint32_t host,
358         __in            uint16_t port)
359 {
360         EFSYS_ASSERT3P(spec, !=, NULL);
361
362         spec->efs_match_flags |=
363                 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
364                 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
365         spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
366         spec->efs_ip_proto = proto;
367         spec->efs_loc_host.eo_u32[0] = host;
368         spec->efs_loc_port = port;
369         return (0);
370 }
371
372 /*
373  * Specify IPv4 hosts, transport protocol and ports in a filter specification
374  */
375 __checkReturn           efx_rc_t
376 efx_filter_spec_set_ipv4_full(
377         __inout         efx_filter_spec_t *spec,
378         __in            uint8_t proto,
379         __in            uint32_t lhost,
380         __in            uint16_t lport,
381         __in            uint32_t rhost,
382         __in            uint16_t rport)
383 {
384         EFSYS_ASSERT3P(spec, !=, NULL);
385
386         spec->efs_match_flags |=
387                 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
388                 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
389                 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
390         spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
391         spec->efs_ip_proto = proto;
392         spec->efs_loc_host.eo_u32[0] = lhost;
393         spec->efs_loc_port = lport;
394         spec->efs_rem_host.eo_u32[0] = rhost;
395         spec->efs_rem_port = rport;
396         return (0);
397 }
398
399 /*
400  * Specify local Ethernet address and/or VID in filter specification
401  */
402 __checkReturn           efx_rc_t
403 efx_filter_spec_set_eth_local(
404         __inout         efx_filter_spec_t *spec,
405         __in            uint16_t vid,
406         __in            const uint8_t *addr)
407 {
408         EFSYS_ASSERT3P(spec, !=, NULL);
409         EFSYS_ASSERT3P(addr, !=, NULL);
410
411         if (vid == EFX_FILTER_SPEC_VID_UNSPEC && addr == NULL)
412                 return (EINVAL);
413
414         if (vid != EFX_FILTER_SPEC_VID_UNSPEC) {
415                 spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID;
416                 spec->efs_outer_vid = vid;
417         }
418         if (addr != NULL) {
419                 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
420                 memcpy(spec->efs_loc_mac, addr, EFX_MAC_ADDR_LEN);
421         }
422         return (0);
423 }
424
425                         void
426 efx_filter_spec_set_ether_type(
427         __inout         efx_filter_spec_t *spec,
428         __in            uint16_t ether_type)
429 {
430         EFSYS_ASSERT3P(spec, !=, NULL);
431
432         spec->efs_ether_type = ether_type;
433         spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
434 }
435
436 /*
437  * Specify matching otherwise-unmatched unicast in a filter specification
438  */
439 __checkReturn           efx_rc_t
440 efx_filter_spec_set_uc_def(
441         __inout         efx_filter_spec_t *spec)
442 {
443         EFSYS_ASSERT3P(spec, !=, NULL);
444
445         spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_UCAST_DST;
446         return (0);
447 }
448
449 /*
450  * Specify matching otherwise-unmatched multicast in a filter specification
451  */
452 __checkReturn           efx_rc_t
453 efx_filter_spec_set_mc_def(
454         __inout         efx_filter_spec_t *spec)
455 {
456         EFSYS_ASSERT3P(spec, !=, NULL);
457
458         spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
459         return (0);
460 }
461
462 __checkReturn           efx_rc_t
463 efx_filter_spec_set_encap_type(
464         __inout         efx_filter_spec_t *spec,
465         __in            efx_tunnel_protocol_t encap_type,
466         __in            efx_filter_inner_frame_match_t inner_frame_match)
467 {
468         uint32_t match_flags = EFX_FILTER_MATCH_ENCAP_TYPE;
469         uint8_t ip_proto;
470         efx_rc_t rc;
471
472         EFSYS_ASSERT3P(spec, !=, NULL);
473
474         switch (encap_type) {
475         case EFX_TUNNEL_PROTOCOL_VXLAN:
476         case EFX_TUNNEL_PROTOCOL_GENEVE:
477                 ip_proto = EFX_IPPROTO_UDP;
478                 break;
479         case EFX_TUNNEL_PROTOCOL_NVGRE:
480                 ip_proto = EFX_IPPROTO_GRE;
481                 break;
482         default:
483                 EFSYS_ASSERT(0);
484                 rc = EINVAL;
485                 goto fail1;
486         }
487
488         switch (inner_frame_match) {
489         case EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_MCAST_DST:
490                 match_flags |= EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST;
491                 break;
492         case EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_UCAST_DST:
493                 match_flags |= EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST;
494                 break;
495         case EFX_FILTER_INNER_FRAME_MATCH_OTHER:
496                 /* This is for when specific inner frames are to be matched. */
497                 break;
498         default:
499                 EFSYS_ASSERT(0);
500                 rc = EINVAL;
501                 goto fail2;
502         }
503
504         spec->efs_encap_type = encap_type;
505         spec->efs_ip_proto = ip_proto;
506         spec->efs_match_flags |= (match_flags | EFX_FILTER_MATCH_IP_PROTO);
507
508         return (0);
509
510 fail2:
511         EFSYS_PROBE(fail2);
512 fail1:
513         EFSYS_PROBE1(fail1, efx_rc_t, rc);
514
515         return (rc);
516 }
517
518 /*
519  * Specify inner and outer Ethernet address and VNI or VSID in tunnel filter
520  * specification.
521  */
522 static  __checkReturn   efx_rc_t
523 efx_filter_spec_set_tunnel(
524         __inout efx_filter_spec_t *spec,
525         __in            efx_tunnel_protocol_t encap_type,
526         __in            const uint8_t *vni_or_vsid,
527         __in            const uint8_t *inner_addr,
528         __in            const uint8_t *outer_addr)
529 {
530         efx_rc_t rc;
531
532         EFSYS_ASSERT3P(spec, !=, NULL);
533         EFSYS_ASSERT3P(vni_or_vsid, !=, NULL);
534         EFSYS_ASSERT3P(inner_addr, !=, NULL);
535         EFSYS_ASSERT3P(outer_addr, !=, NULL);
536
537         switch (encap_type) {
538         case EFX_TUNNEL_PROTOCOL_VXLAN:
539         case EFX_TUNNEL_PROTOCOL_GENEVE:
540         case EFX_TUNNEL_PROTOCOL_NVGRE:
541                 break;
542         default:
543                 rc = EINVAL;
544                 goto fail1;
545         }
546
547         if ((inner_addr == NULL) && (outer_addr == NULL)) {
548                 rc = EINVAL;
549                 goto fail2;
550         }
551
552         if (vni_or_vsid != NULL) {
553                 spec->efs_match_flags |= EFX_FILTER_MATCH_VNI_OR_VSID;
554                 memcpy(spec->efs_vni_or_vsid, vni_or_vsid, EFX_VNI_OR_VSID_LEN);
555         }
556         if (outer_addr != NULL) {
557                 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
558                 memcpy(spec->efs_loc_mac, outer_addr, EFX_MAC_ADDR_LEN);
559         }
560         if (inner_addr != NULL) {
561                 spec->efs_match_flags |= EFX_FILTER_MATCH_IFRM_LOC_MAC;
562                 memcpy(spec->efs_ifrm_loc_mac, inner_addr, EFX_MAC_ADDR_LEN);
563         }
564
565         spec->efs_match_flags |= EFX_FILTER_MATCH_ENCAP_TYPE;
566         spec->efs_encap_type = encap_type;
567
568         return (0);
569
570 fail2:
571         EFSYS_PROBE(fail2);
572 fail1:
573         EFSYS_PROBE1(fail1, efx_rc_t, rc);
574
575         return (rc);
576 }
577
578 /*
579  * Specify inner and outer Ethernet address and VNI in VXLAN filter
580  * specification.
581  */
582 __checkReturn           efx_rc_t
583 efx_filter_spec_set_vxlan(
584         __inout         efx_filter_spec_t *spec,
585         __in            const uint8_t *vni,
586         __in            const uint8_t *inner_addr,
587         __in            const uint8_t *outer_addr)
588 {
589         return efx_filter_spec_set_tunnel(spec, EFX_TUNNEL_PROTOCOL_VXLAN,
590             vni, inner_addr, outer_addr);
591 }
592
593 /*
594  * Specify inner and outer Ethernet address and VNI in Geneve filter
595  * specification.
596  */
597 __checkReturn           efx_rc_t
598 efx_filter_spec_set_geneve(
599         __inout         efx_filter_spec_t *spec,
600         __in            const uint8_t *vni,
601         __in            const uint8_t *inner_addr,
602         __in            const uint8_t *outer_addr)
603 {
604         return efx_filter_spec_set_tunnel(spec, EFX_TUNNEL_PROTOCOL_GENEVE,
605             vni, inner_addr, outer_addr);
606 }
607
608 /*
609  * Specify inner and outer Ethernet address and vsid in NVGRE filter
610  * specification.
611  */
612 __checkReturn           efx_rc_t
613 efx_filter_spec_set_nvgre(
614         __inout         efx_filter_spec_t *spec,
615         __in            const uint8_t *vsid,
616         __in            const uint8_t *inner_addr,
617         __in            const uint8_t *outer_addr)
618 {
619         return efx_filter_spec_set_tunnel(spec, EFX_TUNNEL_PROTOCOL_NVGRE,
620             vsid, inner_addr, outer_addr);
621 }
622
623 #if EFSYS_OPT_RX_SCALE
624         __checkReturn   efx_rc_t
625 efx_filter_spec_set_rss_context(
626         __inout         efx_filter_spec_t *spec,
627         __in            uint32_t rss_context)
628 {
629         efx_rc_t rc;
630
631         EFSYS_ASSERT3P(spec, !=, NULL);
632
633         /* The filter must have been created with EFX_FILTER_FLAG_RX_RSS. */
634         if ((spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) == 0) {
635                 rc = EINVAL;
636                 goto fail1;
637         }
638
639         spec->efs_rss_context = rss_context;
640
641         return (0);
642
643 fail1:
644         EFSYS_PROBE1(fail1, efx_rc_t, rc);
645
646         return (rc);
647 }
648 #endif
649
650 #if EFSYS_OPT_SIENA
651
652 /*
653  * "Fudge factors" - difference between programmed value and actual depth.
654  * Due to pipelined implementation we need to program H/W with a value that
655  * is larger than the hop limit we want.
656  */
657 #define FILTER_CTL_SRCH_FUDGE_WILD 3
658 #define FILTER_CTL_SRCH_FUDGE_FULL 1
659
660 /*
661  * Hard maximum hop limit.  Hardware will time-out beyond 200-something.
662  * We also need to avoid infinite loops in efx_filter_search() when the
663  * table is full.
664  */
665 #define FILTER_CTL_SRCH_MAX 200
666
667 static  __checkReturn   efx_rc_t
668 siena_filter_spec_from_gen_spec(
669         __out           siena_filter_spec_t *sf_spec,
670         __in            efx_filter_spec_t *gen_spec)
671 {
672         efx_rc_t rc;
673         boolean_t is_full = B_FALSE;
674
675         if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX)
676                 EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX);
677         else
678                 EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX);
679
680         /* Siena only has one RSS context */
681         if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
682             gen_spec->efs_rss_context != EFX_RSS_CONTEXT_DEFAULT) {
683                 rc = EINVAL;
684                 goto fail1;
685         }
686
687         sf_spec->sfs_flags = gen_spec->efs_flags;
688         sf_spec->sfs_dmaq_id = gen_spec->efs_dmaq_id;
689
690         switch (gen_spec->efs_match_flags) {
691         case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
692             EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
693             EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT:
694                 is_full = B_TRUE;
695                 /* Fall through */
696         case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
697             EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: {
698                 uint32_t rhost, host1, host2;
699                 uint16_t rport, port1, port2;
700
701                 if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) {
702                         rc = ENOTSUP;
703                         goto fail2;
704                 }
705                 if (gen_spec->efs_loc_port == 0 ||
706                     (is_full && gen_spec->efs_rem_port == 0)) {
707                         rc = EINVAL;
708                         goto fail3;
709                 }
710                 switch (gen_spec->efs_ip_proto) {
711                 case EFX_IPPROTO_TCP:
712                         if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
713                                 sf_spec->sfs_type = (is_full ?
714                                     EFX_SIENA_FILTER_TX_TCP_FULL :
715                                     EFX_SIENA_FILTER_TX_TCP_WILD);
716                         } else {
717                                 sf_spec->sfs_type = (is_full ?
718                                     EFX_SIENA_FILTER_RX_TCP_FULL :
719                                     EFX_SIENA_FILTER_RX_TCP_WILD);
720                         }
721                         break;
722                 case EFX_IPPROTO_UDP:
723                         if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
724                                 sf_spec->sfs_type = (is_full ?
725                                     EFX_SIENA_FILTER_TX_UDP_FULL :
726                                     EFX_SIENA_FILTER_TX_UDP_WILD);
727                         } else {
728                                 sf_spec->sfs_type = (is_full ?
729                                     EFX_SIENA_FILTER_RX_UDP_FULL :
730                                     EFX_SIENA_FILTER_RX_UDP_WILD);
731                         }
732                         break;
733                 default:
734                         rc = ENOTSUP;
735                         goto fail4;
736                 }
737                 /*
738                  * The filter is constructed in terms of source and destination,
739                  * with the odd wrinkle that the ports are swapped in a UDP
740                  * wildcard filter. We need to convert from local and remote
741                  * addresses (zero for a wildcard).
742                  */
743                 rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0;
744                 rport = is_full ? gen_spec->efs_rem_port : 0;
745                 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
746                         host1 = gen_spec->efs_loc_host.eo_u32[0];
747                         host2 = rhost;
748                 } else {
749                         host1 = rhost;
750                         host2 = gen_spec->efs_loc_host.eo_u32[0];
751                 }
752                 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
753                         if (sf_spec->sfs_type ==
754                             EFX_SIENA_FILTER_TX_UDP_WILD) {
755                                 port1 = rport;
756                                 port2 = gen_spec->efs_loc_port;
757                         } else {
758                                 port1 = gen_spec->efs_loc_port;
759                                 port2 = rport;
760                         }
761                 } else {
762                         if (sf_spec->sfs_type ==
763                             EFX_SIENA_FILTER_RX_UDP_WILD) {
764                                 port1 = gen_spec->efs_loc_port;
765                                 port2 = rport;
766                         } else {
767                                 port1 = rport;
768                                 port2 = gen_spec->efs_loc_port;
769                         }
770                 }
771                 sf_spec->sfs_dword[0] = (host1 << 16) | port1;
772                 sf_spec->sfs_dword[1] = (port2 << 16) | (host1 >> 16);
773                 sf_spec->sfs_dword[2] = host2;
774                 break;
775         }
776
777         case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID:
778                 is_full = B_TRUE;
779                 /* Fall through */
780         case EFX_FILTER_MATCH_LOC_MAC:
781                 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
782                         sf_spec->sfs_type = (is_full ?
783                             EFX_SIENA_FILTER_TX_MAC_FULL :
784                             EFX_SIENA_FILTER_TX_MAC_WILD);
785                 } else {
786                         sf_spec->sfs_type = (is_full ?
787                             EFX_SIENA_FILTER_RX_MAC_FULL :
788                             EFX_SIENA_FILTER_RX_MAC_WILD);
789                 }
790                 sf_spec->sfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0;
791                 sf_spec->sfs_dword[1] =
792                     gen_spec->efs_loc_mac[2] << 24 |
793                     gen_spec->efs_loc_mac[3] << 16 |
794                     gen_spec->efs_loc_mac[4] <<  8 |
795                     gen_spec->efs_loc_mac[5];
796                 sf_spec->sfs_dword[2] =
797                     gen_spec->efs_loc_mac[0] << 8 |
798                     gen_spec->efs_loc_mac[1];
799                 break;
800
801         default:
802                 EFSYS_ASSERT(B_FALSE);
803                 rc = ENOTSUP;
804                 goto fail5;
805         }
806
807         return (0);
808
809 fail5:
810         EFSYS_PROBE(fail5);
811 fail4:
812         EFSYS_PROBE(fail4);
813 fail3:
814         EFSYS_PROBE(fail3);
815 fail2:
816         EFSYS_PROBE(fail2);
817 fail1:
818         EFSYS_PROBE1(fail1, efx_rc_t, rc);
819
820         return (rc);
821 }
822
823 /*
824  * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
825  * key derived from the n-tuple.
826  */
827 static                  uint16_t
828 siena_filter_tbl_hash(
829         __in            uint32_t key)
830 {
831         uint16_t tmp;
832
833         /* First 16 rounds */
834         tmp = 0x1fff ^ (uint16_t)(key >> 16);
835         tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
836         tmp = tmp ^ tmp >> 9;
837
838         /* Last 16 rounds */
839         tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff);
840         tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
841         tmp = tmp ^ tmp >> 9;
842
843         return (tmp);
844 }
845
846 /*
847  * To allow for hash collisions, filter search continues at these
848  * increments from the first possible entry selected by the hash.
849  */
850 static                  uint16_t
851 siena_filter_tbl_increment(
852         __in            uint32_t key)
853 {
854         return ((uint16_t)(key * 2 - 1));
855 }
856
857 static  __checkReturn   boolean_t
858 siena_filter_test_used(
859         __in            siena_filter_tbl_t *sftp,
860         __in            unsigned int index)
861 {
862         EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
863         return ((sftp->sft_bitmap[index / 32] & (1 << (index % 32))) != 0);
864 }
865
866 static                  void
867 siena_filter_set_used(
868         __in            siena_filter_tbl_t *sftp,
869         __in            unsigned int index)
870 {
871         EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
872         sftp->sft_bitmap[index / 32] |= (1 << (index % 32));
873         ++sftp->sft_used;
874 }
875
876 static                  void
877 siena_filter_clear_used(
878         __in            siena_filter_tbl_t *sftp,
879         __in            unsigned int index)
880 {
881         EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
882         sftp->sft_bitmap[index / 32] &= ~(1 << (index % 32));
883
884         --sftp->sft_used;
885         EFSYS_ASSERT3U(sftp->sft_used, >=, 0);
886 }
887
888 static                  siena_filter_tbl_id_t
889 siena_filter_tbl_id(
890         __in            siena_filter_type_t type)
891 {
892         siena_filter_tbl_id_t tbl_id;
893
894         switch (type) {
895         case EFX_SIENA_FILTER_RX_TCP_FULL:
896         case EFX_SIENA_FILTER_RX_TCP_WILD:
897         case EFX_SIENA_FILTER_RX_UDP_FULL:
898         case EFX_SIENA_FILTER_RX_UDP_WILD:
899                 tbl_id = EFX_SIENA_FILTER_TBL_RX_IP;
900                 break;
901
902         case EFX_SIENA_FILTER_RX_MAC_FULL:
903         case EFX_SIENA_FILTER_RX_MAC_WILD:
904                 tbl_id = EFX_SIENA_FILTER_TBL_RX_MAC;
905                 break;
906
907         case EFX_SIENA_FILTER_TX_TCP_FULL:
908         case EFX_SIENA_FILTER_TX_TCP_WILD:
909         case EFX_SIENA_FILTER_TX_UDP_FULL:
910         case EFX_SIENA_FILTER_TX_UDP_WILD:
911                 tbl_id = EFX_SIENA_FILTER_TBL_TX_IP;
912                 break;
913
914         case EFX_SIENA_FILTER_TX_MAC_FULL:
915         case EFX_SIENA_FILTER_TX_MAC_WILD:
916                 tbl_id = EFX_SIENA_FILTER_TBL_TX_MAC;
917                 break;
918
919         default:
920                 EFSYS_ASSERT(B_FALSE);
921                 tbl_id = EFX_SIENA_FILTER_NTBLS;
922                 break;
923         }
924         return (tbl_id);
925 }
926
927 static                  void
928 siena_filter_reset_search_depth(
929         __inout         siena_filter_t *sfp,
930         __in            siena_filter_tbl_id_t tbl_id)
931 {
932         switch (tbl_id) {
933         case EFX_SIENA_FILTER_TBL_RX_IP:
934                 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] = 0;
935                 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] = 0;
936                 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] = 0;
937                 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] = 0;
938                 break;
939
940         case EFX_SIENA_FILTER_TBL_RX_MAC:
941                 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] = 0;
942                 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] = 0;
943                 break;
944
945         case EFX_SIENA_FILTER_TBL_TX_IP:
946                 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] = 0;
947                 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] = 0;
948                 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] = 0;
949                 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] = 0;
950                 break;
951
952         case EFX_SIENA_FILTER_TBL_TX_MAC:
953                 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] = 0;
954                 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] = 0;
955                 break;
956
957         default:
958                 EFSYS_ASSERT(B_FALSE);
959                 break;
960         }
961 }
962
963 static                  void
964 siena_filter_push_rx_limits(
965         __in            efx_nic_t *enp)
966 {
967         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
968         efx_oword_t oword;
969
970         EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
971
972         EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT,
973             sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] +
974             FILTER_CTL_SRCH_FUDGE_FULL);
975         EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT,
976             sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] +
977             FILTER_CTL_SRCH_FUDGE_WILD);
978         EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT,
979             sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] +
980             FILTER_CTL_SRCH_FUDGE_FULL);
981         EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT,
982             sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] +
983             FILTER_CTL_SRCH_FUDGE_WILD);
984
985         if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC].sft_size) {
986                 EFX_SET_OWORD_FIELD(oword,
987                     FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
988                     sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] +
989                     FILTER_CTL_SRCH_FUDGE_FULL);
990                 EFX_SET_OWORD_FIELD(oword,
991                     FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
992                     sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] +
993                     FILTER_CTL_SRCH_FUDGE_WILD);
994         }
995
996         EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
997 }
998
999 static                  void
1000 siena_filter_push_tx_limits(
1001         __in            efx_nic_t *enp)
1002 {
1003         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1004         efx_oword_t oword;
1005
1006         EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
1007
1008         if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP].sft_size != 0) {
1009                 EFX_SET_OWORD_FIELD(oword,
1010                     FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE,
1011                     sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] +
1012                     FILTER_CTL_SRCH_FUDGE_FULL);
1013                 EFX_SET_OWORD_FIELD(oword,
1014                     FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE,
1015                     sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] +
1016                     FILTER_CTL_SRCH_FUDGE_WILD);
1017                 EFX_SET_OWORD_FIELD(oword,
1018                     FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE,
1019                     sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] +
1020                     FILTER_CTL_SRCH_FUDGE_FULL);
1021                 EFX_SET_OWORD_FIELD(oword,
1022                     FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE,
1023                     sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] +
1024                     FILTER_CTL_SRCH_FUDGE_WILD);
1025         }
1026
1027         if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC].sft_size != 0) {
1028                 EFX_SET_OWORD_FIELD(
1029                         oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
1030                         sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] +
1031                         FILTER_CTL_SRCH_FUDGE_FULL);
1032                 EFX_SET_OWORD_FIELD(
1033                         oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
1034                         sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] +
1035                         FILTER_CTL_SRCH_FUDGE_WILD);
1036         }
1037
1038         EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
1039 }
1040
1041 /* Build a filter entry and return its n-tuple key. */
1042 static  __checkReturn   uint32_t
1043 siena_filter_build(
1044         __out           efx_oword_t *filter,
1045         __in            siena_filter_spec_t *spec)
1046 {
1047         uint32_t dword3;
1048         uint32_t key;
1049         uint8_t  type  = spec->sfs_type;
1050         uint32_t flags = spec->sfs_flags;
1051
1052         switch (siena_filter_tbl_id(type)) {
1053         case EFX_SIENA_FILTER_TBL_RX_IP: {
1054                 boolean_t is_udp = (type == EFX_SIENA_FILTER_RX_UDP_FULL ||
1055                     type == EFX_SIENA_FILTER_RX_UDP_WILD);
1056                 EFX_POPULATE_OWORD_7(*filter,
1057                     FRF_BZ_RSS_EN,
1058                     (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
1059                     FRF_BZ_SCATTER_EN,
1060                     (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
1061                     FRF_AZ_TCP_UDP, is_udp,
1062                     FRF_AZ_RXQ_ID, spec->sfs_dmaq_id,
1063                     EFX_DWORD_2, spec->sfs_dword[2],
1064                     EFX_DWORD_1, spec->sfs_dword[1],
1065                     EFX_DWORD_0, spec->sfs_dword[0]);
1066                 dword3 = is_udp;
1067                 break;
1068         }
1069
1070         case EFX_SIENA_FILTER_TBL_RX_MAC: {
1071                 boolean_t is_wild = (type == EFX_SIENA_FILTER_RX_MAC_WILD);
1072                 EFX_POPULATE_OWORD_7(*filter,
1073                     FRF_CZ_RMFT_RSS_EN,
1074                     (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
1075                     FRF_CZ_RMFT_SCATTER_EN,
1076                     (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
1077                     FRF_CZ_RMFT_RXQ_ID, spec->sfs_dmaq_id,
1078                     FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
1079                     FRF_CZ_RMFT_DEST_MAC_DW1, spec->sfs_dword[2],
1080                     FRF_CZ_RMFT_DEST_MAC_DW0, spec->sfs_dword[1],
1081                     FRF_CZ_RMFT_VLAN_ID, spec->sfs_dword[0]);
1082                 dword3 = is_wild;
1083                 break;
1084         }
1085
1086         case EFX_SIENA_FILTER_TBL_TX_IP: {
1087                 boolean_t is_udp = (type == EFX_SIENA_FILTER_TX_UDP_FULL ||
1088                     type == EFX_SIENA_FILTER_TX_UDP_WILD);
1089                 EFX_POPULATE_OWORD_5(*filter,
1090                     FRF_CZ_TIFT_TCP_UDP, is_udp,
1091                     FRF_CZ_TIFT_TXQ_ID, spec->sfs_dmaq_id,
1092                     EFX_DWORD_2, spec->sfs_dword[2],
1093                     EFX_DWORD_1, spec->sfs_dword[1],
1094                     EFX_DWORD_0, spec->sfs_dword[0]);
1095                 dword3 = is_udp | spec->sfs_dmaq_id << 1;
1096                 break;
1097         }
1098
1099         case EFX_SIENA_FILTER_TBL_TX_MAC: {
1100                 boolean_t is_wild = (type == EFX_SIENA_FILTER_TX_MAC_WILD);
1101                 EFX_POPULATE_OWORD_5(*filter,
1102                     FRF_CZ_TMFT_TXQ_ID, spec->sfs_dmaq_id,
1103                     FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
1104                     FRF_CZ_TMFT_SRC_MAC_DW1, spec->sfs_dword[2],
1105                     FRF_CZ_TMFT_SRC_MAC_DW0, spec->sfs_dword[1],
1106                     FRF_CZ_TMFT_VLAN_ID, spec->sfs_dword[0]);
1107                 dword3 = is_wild | spec->sfs_dmaq_id << 1;
1108                 break;
1109         }
1110
1111         default:
1112                 EFSYS_ASSERT(B_FALSE);
1113                 EFX_ZERO_OWORD(*filter);
1114                 return (0);
1115         }
1116
1117         key =
1118             spec->sfs_dword[0] ^
1119             spec->sfs_dword[1] ^
1120             spec->sfs_dword[2] ^
1121             dword3;
1122
1123         return (key);
1124 }
1125
1126 static  __checkReturn           efx_rc_t
1127 siena_filter_push_entry(
1128         __inout                 efx_nic_t *enp,
1129         __in                    siena_filter_type_t type,
1130         __in                    int index,
1131         __in                    efx_oword_t *eop)
1132 {
1133         efx_rc_t rc;
1134
1135         switch (type) {
1136         case EFX_SIENA_FILTER_RX_TCP_FULL:
1137         case EFX_SIENA_FILTER_RX_TCP_WILD:
1138         case EFX_SIENA_FILTER_RX_UDP_FULL:
1139         case EFX_SIENA_FILTER_RX_UDP_WILD:
1140                 EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index,
1141                     eop, B_TRUE);
1142                 break;
1143
1144         case EFX_SIENA_FILTER_RX_MAC_FULL:
1145         case EFX_SIENA_FILTER_RX_MAC_WILD:
1146                 EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index,
1147                     eop, B_TRUE);
1148                 break;
1149
1150         case EFX_SIENA_FILTER_TX_TCP_FULL:
1151         case EFX_SIENA_FILTER_TX_TCP_WILD:
1152         case EFX_SIENA_FILTER_TX_UDP_FULL:
1153         case EFX_SIENA_FILTER_TX_UDP_WILD:
1154                 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index,
1155                     eop, B_TRUE);
1156                 break;
1157
1158         case EFX_SIENA_FILTER_TX_MAC_FULL:
1159         case EFX_SIENA_FILTER_TX_MAC_WILD:
1160                 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index,
1161                     eop, B_TRUE);
1162                 break;
1163
1164         default:
1165                 EFSYS_ASSERT(B_FALSE);
1166                 rc = ENOTSUP;
1167                 goto fail1;
1168         }
1169         return (0);
1170
1171 fail1:
1172         return (rc);
1173 }
1174
1175 static  __checkReturn   boolean_t
1176 siena_filter_equal(
1177         __in            const siena_filter_spec_t *left,
1178         __in            const siena_filter_spec_t *right)
1179 {
1180         siena_filter_tbl_id_t tbl_id;
1181
1182         tbl_id = siena_filter_tbl_id(left->sfs_type);
1183
1184         if (left->sfs_type != right->sfs_type)
1185                 return (B_FALSE);
1186
1187         if (memcmp(left->sfs_dword, right->sfs_dword,
1188                 sizeof (left->sfs_dword)))
1189                 return (B_FALSE);
1190
1191         if ((tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1192                 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) &&
1193             left->sfs_dmaq_id != right->sfs_dmaq_id)
1194                 return (B_FALSE);
1195
1196         return (B_TRUE);
1197 }
1198
1199 static  __checkReturn   efx_rc_t
1200 siena_filter_search(
1201         __in            siena_filter_tbl_t *sftp,
1202         __in            siena_filter_spec_t *spec,
1203         __in            uint32_t key,
1204         __in            boolean_t for_insert,
1205         __out           int *filter_index,
1206         __out           unsigned int *depth_required)
1207 {
1208         unsigned int hash, incr, filter_idx, depth;
1209
1210         hash = siena_filter_tbl_hash(key);
1211         incr = siena_filter_tbl_increment(key);
1212
1213         filter_idx = hash & (sftp->sft_size - 1);
1214         depth = 1;
1215
1216         for (;;) {
1217                 /*
1218                  * Return success if entry is used and matches this spec
1219                  * or entry is unused and we are trying to insert.
1220                  */
1221                 if (siena_filter_test_used(sftp, filter_idx) ?
1222                     siena_filter_equal(spec,
1223                     &sftp->sft_spec[filter_idx]) :
1224                     for_insert) {
1225                         *filter_index = filter_idx;
1226                         *depth_required = depth;
1227                         return (0);
1228                 }
1229
1230                 /* Return failure if we reached the maximum search depth */
1231                 if (depth == FILTER_CTL_SRCH_MAX)
1232                         return (for_insert ? EBUSY : ENOENT);
1233
1234                 filter_idx = (filter_idx + incr) & (sftp->sft_size - 1);
1235                 ++depth;
1236         }
1237 }
1238
1239 static                  void
1240 siena_filter_clear_entry(
1241         __in            efx_nic_t *enp,
1242         __in            siena_filter_tbl_t *sftp,
1243         __in            int index)
1244 {
1245         efx_oword_t filter;
1246
1247         if (siena_filter_test_used(sftp, index)) {
1248                 siena_filter_clear_used(sftp, index);
1249
1250                 EFX_ZERO_OWORD(filter);
1251                 siena_filter_push_entry(enp,
1252                     sftp->sft_spec[index].sfs_type,
1253                     index, &filter);
1254
1255                 memset(&sftp->sft_spec[index],
1256                     0, sizeof (sftp->sft_spec[0]));
1257         }
1258 }
1259
1260                         void
1261 siena_filter_tbl_clear(
1262         __in            efx_nic_t *enp,
1263         __in            siena_filter_tbl_id_t tbl_id)
1264 {
1265         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1266         siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1267         int index;
1268         efsys_lock_state_t state;
1269
1270         EFSYS_LOCK(enp->en_eslp, state);
1271
1272         for (index = 0; index < sftp->sft_size; ++index) {
1273                 siena_filter_clear_entry(enp, sftp, index);
1274         }
1275
1276         if (sftp->sft_used == 0)
1277                 siena_filter_reset_search_depth(sfp, tbl_id);
1278
1279         EFSYS_UNLOCK(enp->en_eslp, state);
1280 }
1281
1282 static  __checkReturn   efx_rc_t
1283 siena_filter_init(
1284         __in            efx_nic_t *enp)
1285 {
1286         siena_filter_t *sfp;
1287         siena_filter_tbl_t *sftp;
1288         int tbl_id;
1289         efx_rc_t rc;
1290
1291         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (siena_filter_t), sfp);
1292
1293         if (!sfp) {
1294                 rc = ENOMEM;
1295                 goto fail1;
1296         }
1297
1298         enp->en_filter.ef_siena_filter = sfp;
1299
1300         switch (enp->en_family) {
1301         case EFX_FAMILY_SIENA:
1302                 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_IP];
1303                 sftp->sft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
1304
1305                 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC];
1306                 sftp->sft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
1307
1308                 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP];
1309                 sftp->sft_size = FR_CZ_TX_FILTER_TBL0_ROWS;
1310
1311                 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC];
1312                 sftp->sft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
1313                 break;
1314
1315         default:
1316                 rc = ENOTSUP;
1317                 goto fail2;
1318         }
1319
1320         for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1321                 unsigned int bitmap_size;
1322
1323                 sftp = &sfp->sf_tbl[tbl_id];
1324                 if (sftp->sft_size == 0)
1325                         continue;
1326
1327                 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1328                     sizeof (uint32_t));
1329                 bitmap_size =
1330                     (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1331
1332                 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, sftp->sft_bitmap);
1333                 if (!sftp->sft_bitmap) {
1334                         rc = ENOMEM;
1335                         goto fail3;
1336                 }
1337
1338                 EFSYS_KMEM_ALLOC(enp->en_esip,
1339                     sftp->sft_size * sizeof (*sftp->sft_spec),
1340                     sftp->sft_spec);
1341                 if (!sftp->sft_spec) {
1342                         rc = ENOMEM;
1343                         goto fail4;
1344                 }
1345                 memset(sftp->sft_spec, 0,
1346                     sftp->sft_size * sizeof (*sftp->sft_spec));
1347         }
1348
1349         return (0);
1350
1351 fail4:
1352         EFSYS_PROBE(fail4);
1353
1354 fail3:
1355         EFSYS_PROBE(fail3);
1356
1357 fail2:
1358         EFSYS_PROBE(fail2);
1359         siena_filter_fini(enp);
1360
1361 fail1:
1362         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1363         return (rc);
1364 }
1365
1366 static                  void
1367 siena_filter_fini(
1368         __in            efx_nic_t *enp)
1369 {
1370         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1371         siena_filter_tbl_id_t tbl_id;
1372
1373         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1374         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1375
1376         if (sfp == NULL)
1377                 return;
1378
1379         for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1380                 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1381                 unsigned int bitmap_size;
1382
1383                 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1384                     sizeof (uint32_t));
1385                 bitmap_size =
1386                     (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1387
1388                 if (sftp->sft_bitmap != NULL) {
1389                         EFSYS_KMEM_FREE(enp->en_esip, bitmap_size,
1390                             sftp->sft_bitmap);
1391                         sftp->sft_bitmap = NULL;
1392                 }
1393
1394                 if (sftp->sft_spec != NULL) {
1395                         EFSYS_KMEM_FREE(enp->en_esip, sftp->sft_size *
1396                             sizeof (*sftp->sft_spec), sftp->sft_spec);
1397                         sftp->sft_spec = NULL;
1398                 }
1399         }
1400
1401         EFSYS_KMEM_FREE(enp->en_esip, sizeof (siena_filter_t),
1402             enp->en_filter.ef_siena_filter);
1403 }
1404
1405 /* Restore filter state after a reset */
1406 static  __checkReturn   efx_rc_t
1407 siena_filter_restore(
1408         __in            efx_nic_t *enp)
1409 {
1410         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1411         siena_filter_tbl_id_t tbl_id;
1412         siena_filter_tbl_t *sftp;
1413         siena_filter_spec_t *spec;
1414         efx_oword_t filter;
1415         int filter_idx;
1416         efsys_lock_state_t state;
1417         uint32_t key;
1418         efx_rc_t rc;
1419
1420         EFSYS_LOCK(enp->en_eslp, state);
1421
1422         for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1423                 sftp = &sfp->sf_tbl[tbl_id];
1424                 for (filter_idx = 0;
1425                         filter_idx < sftp->sft_size;
1426                         filter_idx++) {
1427                         if (!siena_filter_test_used(sftp, filter_idx))
1428                                 continue;
1429
1430                         spec = &sftp->sft_spec[filter_idx];
1431                         if ((key = siena_filter_build(&filter, spec)) == 0) {
1432                                 rc = EINVAL;
1433                                 goto fail1;
1434                         }
1435                         if ((rc = siena_filter_push_entry(enp,
1436                                     spec->sfs_type, filter_idx, &filter)) != 0)
1437                                 goto fail2;
1438                 }
1439         }
1440
1441         siena_filter_push_rx_limits(enp);
1442         siena_filter_push_tx_limits(enp);
1443
1444         EFSYS_UNLOCK(enp->en_eslp, state);
1445
1446         return (0);
1447
1448 fail2:
1449         EFSYS_PROBE(fail2);
1450
1451 fail1:
1452         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1453
1454         EFSYS_UNLOCK(enp->en_eslp, state);
1455
1456         return (rc);
1457 }
1458
1459 static   __checkReturn  efx_rc_t
1460 siena_filter_add(
1461         __in            efx_nic_t *enp,
1462         __inout         efx_filter_spec_t *spec,
1463         __in            boolean_t may_replace)
1464 {
1465         efx_rc_t rc;
1466         siena_filter_spec_t sf_spec;
1467         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1468         siena_filter_tbl_id_t tbl_id;
1469         siena_filter_tbl_t *sftp;
1470         siena_filter_spec_t *saved_sf_spec;
1471         efx_oword_t filter;
1472         int filter_idx;
1473         unsigned int depth;
1474         efsys_lock_state_t state;
1475         uint32_t key;
1476
1477         EFSYS_ASSERT3P(spec, !=, NULL);
1478
1479         if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1480                 goto fail1;
1481
1482         tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1483         sftp = &sfp->sf_tbl[tbl_id];
1484
1485         if (sftp->sft_size == 0) {
1486                 rc = EINVAL;
1487                 goto fail2;
1488         }
1489
1490         key = siena_filter_build(&filter, &sf_spec);
1491
1492         EFSYS_LOCK(enp->en_eslp, state);
1493
1494         rc = siena_filter_search(sftp, &sf_spec, key, B_TRUE,
1495             &filter_idx, &depth);
1496         if (rc != 0)
1497                 goto fail3;
1498
1499         EFSYS_ASSERT3U(filter_idx, <, sftp->sft_size);
1500         saved_sf_spec = &sftp->sft_spec[filter_idx];
1501
1502         if (siena_filter_test_used(sftp, filter_idx)) {
1503                 if (may_replace == B_FALSE) {
1504                         rc = EEXIST;
1505                         goto fail4;
1506                 }
1507         }
1508         siena_filter_set_used(sftp, filter_idx);
1509         *saved_sf_spec = sf_spec;
1510
1511         if (sfp->sf_depth[sf_spec.sfs_type] < depth) {
1512                 sfp->sf_depth[sf_spec.sfs_type] = depth;
1513                 if (tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1514                     tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC)
1515                         siena_filter_push_tx_limits(enp);
1516                 else
1517                         siena_filter_push_rx_limits(enp);
1518         }
1519
1520         siena_filter_push_entry(enp, sf_spec.sfs_type,
1521             filter_idx, &filter);
1522
1523         EFSYS_UNLOCK(enp->en_eslp, state);
1524         return (0);
1525
1526 fail4:
1527         EFSYS_PROBE(fail4);
1528
1529 fail3:
1530         EFSYS_UNLOCK(enp->en_eslp, state);
1531         EFSYS_PROBE(fail3);
1532
1533 fail2:
1534         EFSYS_PROBE(fail2);
1535
1536 fail1:
1537         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1538         return (rc);
1539 }
1540
1541 static   __checkReturn  efx_rc_t
1542 siena_filter_delete(
1543         __in            efx_nic_t *enp,
1544         __inout         efx_filter_spec_t *spec)
1545 {
1546         efx_rc_t rc;
1547         siena_filter_spec_t sf_spec;
1548         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1549         siena_filter_tbl_id_t tbl_id;
1550         siena_filter_tbl_t *sftp;
1551         efx_oword_t filter;
1552         int filter_idx;
1553         unsigned int depth;
1554         efsys_lock_state_t state;
1555         uint32_t key;
1556
1557         EFSYS_ASSERT3P(spec, !=, NULL);
1558
1559         if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1560                 goto fail1;
1561
1562         tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1563         sftp = &sfp->sf_tbl[tbl_id];
1564
1565         key = siena_filter_build(&filter, &sf_spec);
1566
1567         EFSYS_LOCK(enp->en_eslp, state);
1568
1569         rc = siena_filter_search(sftp, &sf_spec, key, B_FALSE,
1570             &filter_idx, &depth);
1571         if (rc != 0)
1572                 goto fail2;
1573
1574         siena_filter_clear_entry(enp, sftp, filter_idx);
1575         if (sftp->sft_used == 0)
1576                 siena_filter_reset_search_depth(sfp, tbl_id);
1577
1578         EFSYS_UNLOCK(enp->en_eslp, state);
1579         return (0);
1580
1581 fail2:
1582         EFSYS_UNLOCK(enp->en_eslp, state);
1583         EFSYS_PROBE(fail2);
1584
1585 fail1:
1586         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1587         return (rc);
1588 }
1589
1590 #define SIENA_MAX_SUPPORTED_MATCHES 4
1591
1592 static  __checkReturn   efx_rc_t
1593 siena_filter_supported_filters(
1594         __in                            efx_nic_t *enp,
1595         __out_ecount(buffer_length)     uint32_t *buffer,
1596         __in                            size_t buffer_length,
1597         __out                           size_t *list_lengthp)
1598 {
1599         uint32_t index = 0;
1600         uint32_t rx_matches[SIENA_MAX_SUPPORTED_MATCHES];
1601         size_t list_length;
1602         efx_rc_t rc;
1603
1604         rx_matches[index++] =
1605             EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1606             EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
1607             EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
1608
1609         rx_matches[index++] =
1610             EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1611             EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
1612
1613         if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) {
1614                 rx_matches[index++] =
1615                     EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC;
1616
1617                 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC;
1618         }
1619
1620         EFSYS_ASSERT3U(index, <=, SIENA_MAX_SUPPORTED_MATCHES);
1621         list_length = index;
1622
1623         *list_lengthp = list_length;
1624
1625         if (buffer_length < list_length) {
1626                 rc = ENOSPC;
1627                 goto fail1;
1628         }
1629
1630         memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0]));
1631
1632         return (0);
1633
1634 fail1:
1635         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1636
1637         return (rc);
1638 }
1639
1640 #undef MAX_SUPPORTED
1641
1642 #endif /* EFSYS_OPT_SIENA */
1643
1644 #endif /* EFSYS_OPT_FILTER */