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