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