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