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