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