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