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