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