ba310260be30c3397dbc4ca91506947bdcac01ff
[deb_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_FILTER_SPEC_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 /*
400  * Specify matching otherwise-unmatched unicast in a filter specification
401  */
402 __checkReturn           efx_rc_t
403 efx_filter_spec_set_uc_def(
404         __inout         efx_filter_spec_t *spec)
405 {
406         EFSYS_ASSERT3P(spec, !=, NULL);
407
408         spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_UCAST_DST;
409         return (0);
410 }
411
412 /*
413  * Specify matching otherwise-unmatched multicast in a filter specification
414  */
415 __checkReturn           efx_rc_t
416 efx_filter_spec_set_mc_def(
417         __inout         efx_filter_spec_t *spec)
418 {
419         EFSYS_ASSERT3P(spec, !=, NULL);
420
421         spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
422         return (0);
423 }
424
425
426
427 #if EFSYS_OPT_SIENA
428
429 /*
430  * "Fudge factors" - difference between programmed value and actual depth.
431  * Due to pipelined implementation we need to program H/W with a value that
432  * is larger than the hop limit we want.
433  */
434 #define FILTER_CTL_SRCH_FUDGE_WILD 3
435 #define FILTER_CTL_SRCH_FUDGE_FULL 1
436
437 /*
438  * Hard maximum hop limit.  Hardware will time-out beyond 200-something.
439  * We also need to avoid infinite loops in efx_filter_search() when the
440  * table is full.
441  */
442 #define FILTER_CTL_SRCH_MAX 200
443
444 static  __checkReturn   efx_rc_t
445 siena_filter_spec_from_gen_spec(
446         __out           siena_filter_spec_t *sf_spec,
447         __in            efx_filter_spec_t *gen_spec)
448 {
449         efx_rc_t rc;
450         boolean_t is_full = B_FALSE;
451
452         if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX)
453                 EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX);
454         else
455                 EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX);
456
457         /* Falconsiena only has one RSS context */
458         if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
459             gen_spec->efs_rss_context != 0) {
460                 rc = EINVAL;
461                 goto fail1;
462         }
463
464         sf_spec->sfs_flags = gen_spec->efs_flags;
465         sf_spec->sfs_dmaq_id = gen_spec->efs_dmaq_id;
466
467         switch (gen_spec->efs_match_flags) {
468         case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
469             EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
470             EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT:
471                 is_full = B_TRUE;
472                 /* Fall through */
473         case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
474             EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: {
475                 uint32_t rhost, host1, host2;
476                 uint16_t rport, port1, port2;
477
478                 if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) {
479                         rc = ENOTSUP;
480                         goto fail2;
481                 }
482                 if (gen_spec->efs_loc_port == 0 ||
483                     (is_full && gen_spec->efs_rem_port == 0)) {
484                         rc = EINVAL;
485                         goto fail3;
486                 }
487                 switch (gen_spec->efs_ip_proto) {
488                 case EFX_IPPROTO_TCP:
489                         if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
490                                 sf_spec->sfs_type = (is_full ?
491                                     EFX_SIENA_FILTER_TX_TCP_FULL :
492                                     EFX_SIENA_FILTER_TX_TCP_WILD);
493                         } else {
494                                 sf_spec->sfs_type = (is_full ?
495                                     EFX_SIENA_FILTER_RX_TCP_FULL :
496                                     EFX_SIENA_FILTER_RX_TCP_WILD);
497                         }
498                         break;
499                 case EFX_IPPROTO_UDP:
500                         if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
501                                 sf_spec->sfs_type = (is_full ?
502                                     EFX_SIENA_FILTER_TX_UDP_FULL :
503                                     EFX_SIENA_FILTER_TX_UDP_WILD);
504                         } else {
505                                 sf_spec->sfs_type = (is_full ?
506                                     EFX_SIENA_FILTER_RX_UDP_FULL :
507                                     EFX_SIENA_FILTER_RX_UDP_WILD);
508                         }
509                         break;
510                 default:
511                         rc = ENOTSUP;
512                         goto fail4;
513                 }
514                 /*
515                  * The filter is constructed in terms of source and destination,
516                  * with the odd wrinkle that the ports are swapped in a UDP
517                  * wildcard filter. We need to convert from local and remote
518                  * addresses (zero for a wildcard).
519                  */
520                 rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0;
521                 rport = is_full ? gen_spec->efs_rem_port : 0;
522                 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
523                         host1 = gen_spec->efs_loc_host.eo_u32[0];
524                         host2 = rhost;
525                 } else {
526                         host1 = rhost;
527                         host2 = gen_spec->efs_loc_host.eo_u32[0];
528                 }
529                 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
530                         if (sf_spec->sfs_type ==
531                             EFX_SIENA_FILTER_TX_UDP_WILD) {
532                                 port1 = rport;
533                                 port2 = gen_spec->efs_loc_port;
534                         } else {
535                                 port1 = gen_spec->efs_loc_port;
536                                 port2 = rport;
537                         }
538                 } else {
539                         if (sf_spec->sfs_type ==
540                             EFX_SIENA_FILTER_RX_UDP_WILD) {
541                                 port1 = gen_spec->efs_loc_port;
542                                 port2 = rport;
543                         } else {
544                                 port1 = rport;
545                                 port2 = gen_spec->efs_loc_port;
546                         }
547                 }
548                 sf_spec->sfs_dword[0] = (host1 << 16) | port1;
549                 sf_spec->sfs_dword[1] = (port2 << 16) | (host1 >> 16);
550                 sf_spec->sfs_dword[2] = host2;
551                 break;
552         }
553
554         case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID:
555                 is_full = B_TRUE;
556                 /* Fall through */
557         case EFX_FILTER_MATCH_LOC_MAC:
558                 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
559                         sf_spec->sfs_type = (is_full ?
560                             EFX_SIENA_FILTER_TX_MAC_FULL :
561                             EFX_SIENA_FILTER_TX_MAC_WILD);
562                 } else {
563                         sf_spec->sfs_type = (is_full ?
564                             EFX_SIENA_FILTER_RX_MAC_FULL :
565                             EFX_SIENA_FILTER_RX_MAC_WILD);
566                 }
567                 sf_spec->sfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0;
568                 sf_spec->sfs_dword[1] =
569                     gen_spec->efs_loc_mac[2] << 24 |
570                     gen_spec->efs_loc_mac[3] << 16 |
571                     gen_spec->efs_loc_mac[4] <<  8 |
572                     gen_spec->efs_loc_mac[5];
573                 sf_spec->sfs_dword[2] =
574                     gen_spec->efs_loc_mac[0] << 8 |
575                     gen_spec->efs_loc_mac[1];
576                 break;
577
578         default:
579                 EFSYS_ASSERT(B_FALSE);
580                 rc = ENOTSUP;
581                 goto fail5;
582         }
583
584         return (0);
585
586 fail5:
587         EFSYS_PROBE(fail5);
588 fail4:
589         EFSYS_PROBE(fail4);
590 fail3:
591         EFSYS_PROBE(fail3);
592 fail2:
593         EFSYS_PROBE(fail2);
594 fail1:
595         EFSYS_PROBE1(fail1, efx_rc_t, rc);
596
597         return (rc);
598 }
599
600 /*
601  * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
602  * key derived from the n-tuple.
603  */
604 static                  uint16_t
605 siena_filter_tbl_hash(
606         __in            uint32_t key)
607 {
608         uint16_t tmp;
609
610         /* First 16 rounds */
611         tmp = 0x1fff ^ (uint16_t)(key >> 16);
612         tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
613         tmp = tmp ^ tmp >> 9;
614
615         /* Last 16 rounds */
616         tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff);
617         tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
618         tmp = tmp ^ tmp >> 9;
619
620         return (tmp);
621 }
622
623 /*
624  * To allow for hash collisions, filter search continues at these
625  * increments from the first possible entry selected by the hash.
626  */
627 static                  uint16_t
628 siena_filter_tbl_increment(
629         __in            uint32_t key)
630 {
631         return ((uint16_t)(key * 2 - 1));
632 }
633
634 static  __checkReturn   boolean_t
635 siena_filter_test_used(
636         __in            siena_filter_tbl_t *sftp,
637         __in            unsigned int index)
638 {
639         EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
640         return ((sftp->sft_bitmap[index / 32] & (1 << (index % 32))) != 0);
641 }
642
643 static                  void
644 siena_filter_set_used(
645         __in            siena_filter_tbl_t *sftp,
646         __in            unsigned int index)
647 {
648         EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
649         sftp->sft_bitmap[index / 32] |= (1 << (index % 32));
650         ++sftp->sft_used;
651 }
652
653 static                  void
654 siena_filter_clear_used(
655         __in            siena_filter_tbl_t *sftp,
656         __in            unsigned int index)
657 {
658         EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
659         sftp->sft_bitmap[index / 32] &= ~(1 << (index % 32));
660
661         --sftp->sft_used;
662         EFSYS_ASSERT3U(sftp->sft_used, >=, 0);
663 }
664
665
666 static                  siena_filter_tbl_id_t
667 siena_filter_tbl_id(
668         __in            siena_filter_type_t type)
669 {
670         siena_filter_tbl_id_t tbl_id;
671
672         switch (type) {
673         case EFX_SIENA_FILTER_RX_TCP_FULL:
674         case EFX_SIENA_FILTER_RX_TCP_WILD:
675         case EFX_SIENA_FILTER_RX_UDP_FULL:
676         case EFX_SIENA_FILTER_RX_UDP_WILD:
677                 tbl_id = EFX_SIENA_FILTER_TBL_RX_IP;
678                 break;
679
680         case EFX_SIENA_FILTER_RX_MAC_FULL:
681         case EFX_SIENA_FILTER_RX_MAC_WILD:
682                 tbl_id = EFX_SIENA_FILTER_TBL_RX_MAC;
683                 break;
684
685         case EFX_SIENA_FILTER_TX_TCP_FULL:
686         case EFX_SIENA_FILTER_TX_TCP_WILD:
687         case EFX_SIENA_FILTER_TX_UDP_FULL:
688         case EFX_SIENA_FILTER_TX_UDP_WILD:
689                 tbl_id = EFX_SIENA_FILTER_TBL_TX_IP;
690                 break;
691
692         case EFX_SIENA_FILTER_TX_MAC_FULL:
693         case EFX_SIENA_FILTER_TX_MAC_WILD:
694                 tbl_id = EFX_SIENA_FILTER_TBL_TX_MAC;
695                 break;
696
697         default:
698                 EFSYS_ASSERT(B_FALSE);
699                 tbl_id = EFX_SIENA_FILTER_NTBLS;
700                 break;
701         }
702         return (tbl_id);
703 }
704
705 static                  void
706 siena_filter_reset_search_depth(
707         __inout         siena_filter_t *sfp,
708         __in            siena_filter_tbl_id_t tbl_id)
709 {
710         switch (tbl_id) {
711         case EFX_SIENA_FILTER_TBL_RX_IP:
712                 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] = 0;
713                 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] = 0;
714                 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] = 0;
715                 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] = 0;
716                 break;
717
718         case EFX_SIENA_FILTER_TBL_RX_MAC:
719                 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] = 0;
720                 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] = 0;
721                 break;
722
723         case EFX_SIENA_FILTER_TBL_TX_IP:
724                 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] = 0;
725                 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] = 0;
726                 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] = 0;
727                 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] = 0;
728                 break;
729
730         case EFX_SIENA_FILTER_TBL_TX_MAC:
731                 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] = 0;
732                 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] = 0;
733                 break;
734
735         default:
736                 EFSYS_ASSERT(B_FALSE);
737                 break;
738         }
739 }
740
741 static                  void
742 siena_filter_push_rx_limits(
743         __in            efx_nic_t *enp)
744 {
745         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
746         efx_oword_t oword;
747
748         EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
749
750         EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT,
751             sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] +
752             FILTER_CTL_SRCH_FUDGE_FULL);
753         EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT,
754             sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] +
755             FILTER_CTL_SRCH_FUDGE_WILD);
756         EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT,
757             sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] +
758             FILTER_CTL_SRCH_FUDGE_FULL);
759         EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT,
760             sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] +
761             FILTER_CTL_SRCH_FUDGE_WILD);
762
763         if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC].sft_size) {
764                 EFX_SET_OWORD_FIELD(oword,
765                     FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
766                     sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] +
767                     FILTER_CTL_SRCH_FUDGE_FULL);
768                 EFX_SET_OWORD_FIELD(oword,
769                     FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
770                     sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] +
771                     FILTER_CTL_SRCH_FUDGE_WILD);
772         }
773
774         EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
775 }
776
777 static                  void
778 siena_filter_push_tx_limits(
779         __in            efx_nic_t *enp)
780 {
781         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
782         efx_oword_t oword;
783
784         EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
785
786         if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP].sft_size != 0) {
787                 EFX_SET_OWORD_FIELD(oword,
788                     FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE,
789                     sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] +
790                     FILTER_CTL_SRCH_FUDGE_FULL);
791                 EFX_SET_OWORD_FIELD(oword,
792                     FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE,
793                     sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] +
794                     FILTER_CTL_SRCH_FUDGE_WILD);
795                 EFX_SET_OWORD_FIELD(oword,
796                     FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE,
797                     sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] +
798                     FILTER_CTL_SRCH_FUDGE_FULL);
799                 EFX_SET_OWORD_FIELD(oword,
800                     FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE,
801                     sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] +
802                     FILTER_CTL_SRCH_FUDGE_WILD);
803         }
804
805         if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC].sft_size != 0) {
806                 EFX_SET_OWORD_FIELD(
807                         oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
808                         sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] +
809                         FILTER_CTL_SRCH_FUDGE_FULL);
810                 EFX_SET_OWORD_FIELD(
811                         oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
812                         sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] +
813                         FILTER_CTL_SRCH_FUDGE_WILD);
814         }
815
816         EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
817 }
818
819 /* Build a filter entry and return its n-tuple key. */
820 static  __checkReturn   uint32_t
821 siena_filter_build(
822         __out           efx_oword_t *filter,
823         __in            siena_filter_spec_t *spec)
824 {
825         uint32_t dword3;
826         uint32_t key;
827         uint8_t  type  = spec->sfs_type;
828         uint32_t flags = spec->sfs_flags;
829
830         switch (siena_filter_tbl_id(type)) {
831         case EFX_SIENA_FILTER_TBL_RX_IP: {
832                 boolean_t is_udp = (type == EFX_SIENA_FILTER_RX_UDP_FULL ||
833                     type == EFX_SIENA_FILTER_RX_UDP_WILD);
834                 EFX_POPULATE_OWORD_7(*filter,
835                     FRF_BZ_RSS_EN,
836                     (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
837                     FRF_BZ_SCATTER_EN,
838                     (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
839                     FRF_AZ_TCP_UDP, is_udp,
840                     FRF_AZ_RXQ_ID, spec->sfs_dmaq_id,
841                     EFX_DWORD_2, spec->sfs_dword[2],
842                     EFX_DWORD_1, spec->sfs_dword[1],
843                     EFX_DWORD_0, spec->sfs_dword[0]);
844                 dword3 = is_udp;
845                 break;
846         }
847
848         case EFX_SIENA_FILTER_TBL_RX_MAC: {
849                 boolean_t is_wild = (type == EFX_SIENA_FILTER_RX_MAC_WILD);
850                 EFX_POPULATE_OWORD_7(*filter,
851                     FRF_CZ_RMFT_RSS_EN,
852                     (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
853                     FRF_CZ_RMFT_SCATTER_EN,
854                     (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
855                     FRF_CZ_RMFT_RXQ_ID, spec->sfs_dmaq_id,
856                     FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
857                     FRF_CZ_RMFT_DEST_MAC_DW1, spec->sfs_dword[2],
858                     FRF_CZ_RMFT_DEST_MAC_DW0, spec->sfs_dword[1],
859                     FRF_CZ_RMFT_VLAN_ID, spec->sfs_dword[0]);
860                 dword3 = is_wild;
861                 break;
862         }
863
864         case EFX_SIENA_FILTER_TBL_TX_IP: {
865                 boolean_t is_udp = (type == EFX_SIENA_FILTER_TX_UDP_FULL ||
866                     type == EFX_SIENA_FILTER_TX_UDP_WILD);
867                 EFX_POPULATE_OWORD_5(*filter,
868                     FRF_CZ_TIFT_TCP_UDP, is_udp,
869                     FRF_CZ_TIFT_TXQ_ID, spec->sfs_dmaq_id,
870                     EFX_DWORD_2, spec->sfs_dword[2],
871                     EFX_DWORD_1, spec->sfs_dword[1],
872                     EFX_DWORD_0, spec->sfs_dword[0]);
873                 dword3 = is_udp | spec->sfs_dmaq_id << 1;
874                 break;
875         }
876
877         case EFX_SIENA_FILTER_TBL_TX_MAC: {
878                 boolean_t is_wild = (type == EFX_SIENA_FILTER_TX_MAC_WILD);
879                 EFX_POPULATE_OWORD_5(*filter,
880                     FRF_CZ_TMFT_TXQ_ID, spec->sfs_dmaq_id,
881                     FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
882                     FRF_CZ_TMFT_SRC_MAC_DW1, spec->sfs_dword[2],
883                     FRF_CZ_TMFT_SRC_MAC_DW0, spec->sfs_dword[1],
884                     FRF_CZ_TMFT_VLAN_ID, spec->sfs_dword[0]);
885                 dword3 = is_wild | spec->sfs_dmaq_id << 1;
886                 break;
887         }
888
889         default:
890                 EFSYS_ASSERT(B_FALSE);
891                 return (0);
892         }
893
894         key =
895             spec->sfs_dword[0] ^
896             spec->sfs_dword[1] ^
897             spec->sfs_dword[2] ^
898             dword3;
899
900         return (key);
901 }
902
903 static  __checkReturn           efx_rc_t
904 siena_filter_push_entry(
905         __inout                 efx_nic_t *enp,
906         __in                    siena_filter_type_t type,
907         __in                    int index,
908         __in                    efx_oword_t *eop)
909 {
910         efx_rc_t rc;
911
912         switch (type) {
913         case EFX_SIENA_FILTER_RX_TCP_FULL:
914         case EFX_SIENA_FILTER_RX_TCP_WILD:
915         case EFX_SIENA_FILTER_RX_UDP_FULL:
916         case EFX_SIENA_FILTER_RX_UDP_WILD:
917                 EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index,
918                     eop, B_TRUE);
919                 break;
920
921         case EFX_SIENA_FILTER_RX_MAC_FULL:
922         case EFX_SIENA_FILTER_RX_MAC_WILD:
923                 EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index,
924                     eop, B_TRUE);
925                 break;
926
927         case EFX_SIENA_FILTER_TX_TCP_FULL:
928         case EFX_SIENA_FILTER_TX_TCP_WILD:
929         case EFX_SIENA_FILTER_TX_UDP_FULL:
930         case EFX_SIENA_FILTER_TX_UDP_WILD:
931                 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index,
932                     eop, B_TRUE);
933                 break;
934
935         case EFX_SIENA_FILTER_TX_MAC_FULL:
936         case EFX_SIENA_FILTER_TX_MAC_WILD:
937                 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index,
938                     eop, B_TRUE);
939                 break;
940
941         default:
942                 EFSYS_ASSERT(B_FALSE);
943                 rc = ENOTSUP;
944                 goto fail1;
945         }
946         return (0);
947
948 fail1:
949         return (rc);
950 }
951
952
953 static  __checkReturn   boolean_t
954 siena_filter_equal(
955         __in            const siena_filter_spec_t *left,
956         __in            const siena_filter_spec_t *right)
957 {
958         siena_filter_tbl_id_t tbl_id;
959
960         tbl_id = siena_filter_tbl_id(left->sfs_type);
961
962
963         if (left->sfs_type != right->sfs_type)
964                 return (B_FALSE);
965
966         if (memcmp(left->sfs_dword, right->sfs_dword,
967                 sizeof (left->sfs_dword)))
968                 return (B_FALSE);
969
970         if ((tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
971                 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) &&
972             left->sfs_dmaq_id != right->sfs_dmaq_id)
973                 return (B_FALSE);
974
975         return (B_TRUE);
976 }
977
978 static  __checkReturn   efx_rc_t
979 siena_filter_search(
980         __in            siena_filter_tbl_t *sftp,
981         __in            siena_filter_spec_t *spec,
982         __in            uint32_t key,
983         __in            boolean_t for_insert,
984         __out           int *filter_index,
985         __out           unsigned int *depth_required)
986 {
987         unsigned int hash, incr, filter_idx, depth;
988
989         hash = siena_filter_tbl_hash(key);
990         incr = siena_filter_tbl_increment(key);
991
992         filter_idx = hash & (sftp->sft_size - 1);
993         depth = 1;
994
995         for (;;) {
996                 /*
997                  * Return success if entry is used and matches this spec
998                  * or entry is unused and we are trying to insert.
999                  */
1000                 if (siena_filter_test_used(sftp, filter_idx) ?
1001                     siena_filter_equal(spec,
1002                     &sftp->sft_spec[filter_idx]) :
1003                     for_insert) {
1004                         *filter_index = filter_idx;
1005                         *depth_required = depth;
1006                         return (0);
1007                 }
1008
1009                 /* Return failure if we reached the maximum search depth */
1010                 if (depth == FILTER_CTL_SRCH_MAX)
1011                         return (for_insert ? EBUSY : ENOENT);
1012
1013                 filter_idx = (filter_idx + incr) & (sftp->sft_size - 1);
1014                 ++depth;
1015         }
1016 }
1017
1018 static                  void
1019 siena_filter_clear_entry(
1020         __in            efx_nic_t *enp,
1021         __in            siena_filter_tbl_t *sftp,
1022         __in            int index)
1023 {
1024         efx_oword_t filter;
1025
1026         if (siena_filter_test_used(sftp, index)) {
1027                 siena_filter_clear_used(sftp, index);
1028
1029                 EFX_ZERO_OWORD(filter);
1030                 siena_filter_push_entry(enp,
1031                     sftp->sft_spec[index].sfs_type,
1032                     index, &filter);
1033
1034                 memset(&sftp->sft_spec[index],
1035                     0, sizeof (sftp->sft_spec[0]));
1036         }
1037 }
1038
1039                         void
1040 siena_filter_tbl_clear(
1041         __in            efx_nic_t *enp,
1042         __in            siena_filter_tbl_id_t tbl_id)
1043 {
1044         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1045         siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1046         int index;
1047         efsys_lock_state_t state;
1048
1049         EFSYS_LOCK(enp->en_eslp, state);
1050
1051         for (index = 0; index < sftp->sft_size; ++index) {
1052                 siena_filter_clear_entry(enp, sftp, index);
1053         }
1054
1055         if (sftp->sft_used == 0)
1056                 siena_filter_reset_search_depth(sfp, tbl_id);
1057
1058         EFSYS_UNLOCK(enp->en_eslp, state);
1059 }
1060
1061 static  __checkReturn   efx_rc_t
1062 siena_filter_init(
1063         __in            efx_nic_t *enp)
1064 {
1065         siena_filter_t *sfp;
1066         siena_filter_tbl_t *sftp;
1067         int tbl_id;
1068         efx_rc_t rc;
1069
1070         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (siena_filter_t), sfp);
1071
1072         if (!sfp) {
1073                 rc = ENOMEM;
1074                 goto fail1;
1075         }
1076
1077         enp->en_filter.ef_siena_filter = sfp;
1078
1079         switch (enp->en_family) {
1080         case EFX_FAMILY_SIENA:
1081                 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_IP];
1082                 sftp->sft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
1083
1084                 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC];
1085                 sftp->sft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
1086
1087                 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP];
1088                 sftp->sft_size = FR_CZ_TX_FILTER_TBL0_ROWS;
1089
1090                 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC];
1091                 sftp->sft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
1092                 break;
1093
1094         default:
1095                 rc = ENOTSUP;
1096                 goto fail2;
1097         }
1098
1099         for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1100                 unsigned int bitmap_size;
1101
1102                 sftp = &sfp->sf_tbl[tbl_id];
1103                 if (sftp->sft_size == 0)
1104                         continue;
1105
1106                 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1107                     sizeof (uint32_t));
1108                 bitmap_size =
1109                     (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1110
1111                 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, sftp->sft_bitmap);
1112                 if (!sftp->sft_bitmap) {
1113                         rc = ENOMEM;
1114                         goto fail3;
1115                 }
1116
1117                 EFSYS_KMEM_ALLOC(enp->en_esip,
1118                     sftp->sft_size * sizeof (*sftp->sft_spec),
1119                     sftp->sft_spec);
1120                 if (!sftp->sft_spec) {
1121                         rc = ENOMEM;
1122                         goto fail4;
1123                 }
1124                 memset(sftp->sft_spec, 0,
1125                     sftp->sft_size * sizeof (*sftp->sft_spec));
1126         }
1127
1128         return (0);
1129
1130 fail4:
1131         EFSYS_PROBE(fail4);
1132
1133 fail3:
1134         EFSYS_PROBE(fail3);
1135
1136 fail2:
1137         EFSYS_PROBE(fail2);
1138         siena_filter_fini(enp);
1139
1140 fail1:
1141         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1142         return (rc);
1143 }
1144
1145 static                  void
1146 siena_filter_fini(
1147         __in            efx_nic_t *enp)
1148 {
1149         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1150         siena_filter_tbl_id_t tbl_id;
1151
1152         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1153         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1154
1155         if (sfp == NULL)
1156                 return;
1157
1158         for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1159                 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1160                 unsigned int bitmap_size;
1161
1162                 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1163                     sizeof (uint32_t));
1164                 bitmap_size =
1165                     (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1166
1167                 if (sftp->sft_bitmap != NULL) {
1168                         EFSYS_KMEM_FREE(enp->en_esip, bitmap_size,
1169                             sftp->sft_bitmap);
1170                         sftp->sft_bitmap = NULL;
1171                 }
1172
1173                 if (sftp->sft_spec != NULL) {
1174                         EFSYS_KMEM_FREE(enp->en_esip, sftp->sft_size *
1175                             sizeof (*sftp->sft_spec), sftp->sft_spec);
1176                         sftp->sft_spec = NULL;
1177                 }
1178         }
1179
1180         EFSYS_KMEM_FREE(enp->en_esip, sizeof (siena_filter_t),
1181             enp->en_filter.ef_siena_filter);
1182 }
1183
1184 /* Restore filter state after a reset */
1185 static  __checkReturn   efx_rc_t
1186 siena_filter_restore(
1187         __in            efx_nic_t *enp)
1188 {
1189         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1190         siena_filter_tbl_id_t tbl_id;
1191         siena_filter_tbl_t *sftp;
1192         siena_filter_spec_t *spec;
1193         efx_oword_t filter;
1194         int filter_idx;
1195         efsys_lock_state_t state;
1196         uint32_t key;
1197         efx_rc_t rc;
1198
1199         EFSYS_LOCK(enp->en_eslp, state);
1200
1201         for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1202                 sftp = &sfp->sf_tbl[tbl_id];
1203                 for (filter_idx = 0;
1204                         filter_idx < sftp->sft_size;
1205                         filter_idx++) {
1206                         if (!siena_filter_test_used(sftp, filter_idx))
1207                                 continue;
1208
1209                         spec = &sftp->sft_spec[filter_idx];
1210                         if ((key = siena_filter_build(&filter, spec)) == 0) {
1211                                 rc = EINVAL;
1212                                 goto fail1;
1213                         }
1214                         if ((rc = siena_filter_push_entry(enp,
1215                                     spec->sfs_type, filter_idx, &filter)) != 0)
1216                                 goto fail2;
1217                 }
1218         }
1219
1220         siena_filter_push_rx_limits(enp);
1221         siena_filter_push_tx_limits(enp);
1222
1223         EFSYS_UNLOCK(enp->en_eslp, state);
1224
1225         return (0);
1226
1227 fail2:
1228         EFSYS_PROBE(fail2);
1229
1230 fail1:
1231         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1232
1233         EFSYS_UNLOCK(enp->en_eslp, state);
1234
1235         return (rc);
1236 }
1237
1238 static   __checkReturn  efx_rc_t
1239 siena_filter_add(
1240         __in            efx_nic_t *enp,
1241         __inout         efx_filter_spec_t *spec,
1242         __in            boolean_t may_replace)
1243 {
1244         efx_rc_t rc;
1245         siena_filter_spec_t sf_spec;
1246         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1247         siena_filter_tbl_id_t tbl_id;
1248         siena_filter_tbl_t *sftp;
1249         siena_filter_spec_t *saved_sf_spec;
1250         efx_oword_t filter;
1251         int filter_idx;
1252         unsigned int depth;
1253         efsys_lock_state_t state;
1254         uint32_t key;
1255
1256
1257         EFSYS_ASSERT3P(spec, !=, NULL);
1258
1259         if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1260                 goto fail1;
1261
1262         tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1263         sftp = &sfp->sf_tbl[tbl_id];
1264
1265         if (sftp->sft_size == 0) {
1266                 rc = EINVAL;
1267                 goto fail2;
1268         }
1269
1270         key = siena_filter_build(&filter, &sf_spec);
1271
1272         EFSYS_LOCK(enp->en_eslp, state);
1273
1274         rc = siena_filter_search(sftp, &sf_spec, key, B_TRUE,
1275             &filter_idx, &depth);
1276         if (rc != 0)
1277                 goto fail3;
1278
1279         EFSYS_ASSERT3U(filter_idx, <, sftp->sft_size);
1280         saved_sf_spec = &sftp->sft_spec[filter_idx];
1281
1282         if (siena_filter_test_used(sftp, filter_idx)) {
1283                 if (may_replace == B_FALSE) {
1284                         rc = EEXIST;
1285                         goto fail4;
1286                 }
1287         }
1288         siena_filter_set_used(sftp, filter_idx);
1289         *saved_sf_spec = sf_spec;
1290
1291         if (sfp->sf_depth[sf_spec.sfs_type] < depth) {
1292                 sfp->sf_depth[sf_spec.sfs_type] = depth;
1293                 if (tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1294                     tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC)
1295                         siena_filter_push_tx_limits(enp);
1296                 else
1297                         siena_filter_push_rx_limits(enp);
1298         }
1299
1300         siena_filter_push_entry(enp, sf_spec.sfs_type,
1301             filter_idx, &filter);
1302
1303         EFSYS_UNLOCK(enp->en_eslp, state);
1304         return (0);
1305
1306 fail4:
1307         EFSYS_PROBE(fail4);
1308
1309 fail3:
1310         EFSYS_UNLOCK(enp->en_eslp, state);
1311         EFSYS_PROBE(fail3);
1312
1313 fail2:
1314         EFSYS_PROBE(fail2);
1315
1316 fail1:
1317         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1318         return (rc);
1319 }
1320
1321 static   __checkReturn  efx_rc_t
1322 siena_filter_delete(
1323         __in            efx_nic_t *enp,
1324         __inout         efx_filter_spec_t *spec)
1325 {
1326         efx_rc_t rc;
1327         siena_filter_spec_t sf_spec;
1328         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1329         siena_filter_tbl_id_t tbl_id;
1330         siena_filter_tbl_t *sftp;
1331         efx_oword_t filter;
1332         int filter_idx;
1333         unsigned int depth;
1334         efsys_lock_state_t state;
1335         uint32_t key;
1336
1337         EFSYS_ASSERT3P(spec, !=, NULL);
1338
1339         if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1340                 goto fail1;
1341
1342         tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1343         sftp = &sfp->sf_tbl[tbl_id];
1344
1345         key = siena_filter_build(&filter, &sf_spec);
1346
1347         EFSYS_LOCK(enp->en_eslp, state);
1348
1349         rc = siena_filter_search(sftp, &sf_spec, key, B_FALSE,
1350             &filter_idx, &depth);
1351         if (rc != 0)
1352                 goto fail2;
1353
1354         siena_filter_clear_entry(enp, sftp, filter_idx);
1355         if (sftp->sft_used == 0)
1356                 siena_filter_reset_search_depth(sfp, tbl_id);
1357
1358         EFSYS_UNLOCK(enp->en_eslp, state);
1359         return (0);
1360
1361 fail2:
1362         EFSYS_UNLOCK(enp->en_eslp, state);
1363         EFSYS_PROBE(fail2);
1364
1365 fail1:
1366         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1367         return (rc);
1368 }
1369
1370 #define SIENA_MAX_SUPPORTED_MATCHES 4
1371
1372 static  __checkReturn   efx_rc_t
1373 siena_filter_supported_filters(
1374         __in                            efx_nic_t *enp,
1375         __out_ecount(buffer_length)     uint32_t *buffer,
1376         __in                            size_t buffer_length,
1377         __out                           size_t *list_lengthp)
1378 {
1379         uint32_t index = 0;
1380         uint32_t rx_matches[SIENA_MAX_SUPPORTED_MATCHES];
1381         size_t list_length;
1382         efx_rc_t rc;
1383
1384         rx_matches[index++] =
1385             EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1386             EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
1387             EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
1388
1389         rx_matches[index++] =
1390             EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1391             EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
1392
1393         if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) {
1394                 rx_matches[index++] =
1395                     EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC;
1396
1397                 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC;
1398         }
1399
1400         EFSYS_ASSERT3U(index, <=, SIENA_MAX_SUPPORTED_MATCHES);
1401         list_length = index;
1402
1403         *list_lengthp = list_length;
1404
1405         if (buffer_length < list_length) {
1406                 rc = ENOSPC;
1407                 goto fail1;
1408         }
1409
1410         memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0]));
1411
1412         return (0);
1413
1414 fail1:
1415         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1416
1417         return (rc);
1418 }
1419
1420 #undef MAX_SUPPORTED
1421
1422 #endif /* EFSYS_OPT_SIENA */
1423
1424 #endif /* EFSYS_OPT_FILTER */