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