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