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