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