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