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