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