]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/dpdk/drivers/net/sfc/base/efx_filter.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / seastar / dpdk / drivers / net / sfc / base / efx_filter.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2 *
3 * Copyright (c) 2007-2018 Solarflare Communications Inc.
4 * All rights reserved.
5 */
6
7 #include "efx.h"
8 #include "efx_impl.h"
9
10
11 #if EFSYS_OPT_FILTER
12
13 #if EFSYS_OPT_SIENA
14
15 static __checkReturn efx_rc_t
16 siena_filter_init(
17 __in efx_nic_t *enp);
18
19 static void
20 siena_filter_fini(
21 __in efx_nic_t *enp);
22
23 static __checkReturn efx_rc_t
24 siena_filter_restore(
25 __in efx_nic_t *enp);
26
27 static __checkReturn efx_rc_t
28 siena_filter_add(
29 __in efx_nic_t *enp,
30 __inout efx_filter_spec_t *spec,
31 __in boolean_t may_replace);
32
33 static __checkReturn efx_rc_t
34 siena_filter_delete(
35 __in efx_nic_t *enp,
36 __inout efx_filter_spec_t *spec);
37
38 static __checkReturn efx_rc_t
39 siena_filter_supported_filters(
40 __in efx_nic_t *enp,
41 __out_ecount(buffer_length) uint32_t *buffer,
42 __in size_t buffer_length,
43 __out size_t *list_lengthp);
44
45 #endif /* EFSYS_OPT_SIENA */
46
47 #if EFSYS_OPT_SIENA
48 static const efx_filter_ops_t __efx_filter_siena_ops = {
49 siena_filter_init, /* efo_init */
50 siena_filter_fini, /* efo_fini */
51 siena_filter_restore, /* efo_restore */
52 siena_filter_add, /* efo_add */
53 siena_filter_delete, /* efo_delete */
54 siena_filter_supported_filters, /* efo_supported_filters */
55 NULL, /* efo_reconfigure */
56 };
57 #endif /* EFSYS_OPT_SIENA */
58
59 #if EFX_OPTS_EF10()
60 static const efx_filter_ops_t __efx_filter_ef10_ops = {
61 ef10_filter_init, /* efo_init */
62 ef10_filter_fini, /* efo_fini */
63 ef10_filter_restore, /* efo_restore */
64 ef10_filter_add, /* efo_add */
65 ef10_filter_delete, /* efo_delete */
66 ef10_filter_supported_filters, /* efo_supported_filters */
67 ef10_filter_reconfigure, /* efo_reconfigure */
68 };
69 #endif /* EFX_OPTS_EF10() */
70
71 __checkReturn efx_rc_t
72 efx_filter_insert(
73 __in efx_nic_t *enp,
74 __inout efx_filter_spec_t *spec)
75 {
76 const efx_filter_ops_t *efop = enp->en_efop;
77 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
78 efx_rc_t rc;
79
80 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
81 EFSYS_ASSERT3P(spec, !=, NULL);
82 EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
83
84 if ((spec->efs_flags & EFX_FILTER_FLAG_ACTION_MARK) &&
85 !encp->enc_filter_action_mark_supported) {
86 rc = ENOTSUP;
87 goto fail1;
88 }
89
90 if ((spec->efs_flags & EFX_FILTER_FLAG_ACTION_FLAG) &&
91 !encp->enc_filter_action_flag_supported) {
92 rc = ENOTSUP;
93 goto fail2;
94 }
95
96 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 VNI or VSID in tunnel filter
494 * specification.
495 */
496 static __checkReturn efx_rc_t
497 efx_filter_spec_set_tunnel(
498 __inout efx_filter_spec_t *spec,
499 __in efx_tunnel_protocol_t encap_type,
500 __in const uint8_t *vni_or_vsid,
501 __in const uint8_t *inner_addr,
502 __in const uint8_t *outer_addr)
503 {
504 efx_rc_t rc;
505
506 EFSYS_ASSERT3P(spec, !=, NULL);
507 EFSYS_ASSERT3P(vni_or_vsid, !=, NULL);
508 EFSYS_ASSERT3P(inner_addr, !=, NULL);
509 EFSYS_ASSERT3P(outer_addr, !=, NULL);
510
511 switch (encap_type) {
512 case EFX_TUNNEL_PROTOCOL_VXLAN:
513 case EFX_TUNNEL_PROTOCOL_GENEVE:
514 case EFX_TUNNEL_PROTOCOL_NVGRE:
515 break;
516 default:
517 rc = EINVAL;
518 goto fail1;
519 }
520
521 if ((inner_addr == NULL) && (outer_addr == NULL)) {
522 rc = EINVAL;
523 goto fail2;
524 }
525
526 if (vni_or_vsid != NULL) {
527 spec->efs_match_flags |= EFX_FILTER_MATCH_VNI_OR_VSID;
528 memcpy(spec->efs_vni_or_vsid, vni_or_vsid, EFX_VNI_OR_VSID_LEN);
529 }
530 if (outer_addr != NULL) {
531 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
532 memcpy(spec->efs_loc_mac, outer_addr, EFX_MAC_ADDR_LEN);
533 }
534 if (inner_addr != NULL) {
535 spec->efs_match_flags |= EFX_FILTER_MATCH_IFRM_LOC_MAC;
536 memcpy(spec->efs_ifrm_loc_mac, inner_addr, EFX_MAC_ADDR_LEN);
537 }
538
539 spec->efs_match_flags |= EFX_FILTER_MATCH_ENCAP_TYPE;
540 spec->efs_encap_type = encap_type;
541
542 return (0);
543
544 fail2:
545 EFSYS_PROBE(fail2);
546 fail1:
547 EFSYS_PROBE1(fail1, efx_rc_t, rc);
548
549 return (rc);
550 }
551
552 /*
553 * Specify inner and outer Ethernet address and VNI in VXLAN filter
554 * specification.
555 */
556 __checkReturn efx_rc_t
557 efx_filter_spec_set_vxlan(
558 __inout efx_filter_spec_t *spec,
559 __in const uint8_t *vni,
560 __in const uint8_t *inner_addr,
561 __in const uint8_t *outer_addr)
562 {
563 return efx_filter_spec_set_tunnel(spec, EFX_TUNNEL_PROTOCOL_VXLAN,
564 vni, inner_addr, outer_addr);
565 }
566
567 /*
568 * Specify inner and outer Ethernet address and VNI in Geneve filter
569 * specification.
570 */
571 __checkReturn efx_rc_t
572 efx_filter_spec_set_geneve(
573 __inout efx_filter_spec_t *spec,
574 __in const uint8_t *vni,
575 __in const uint8_t *inner_addr,
576 __in const uint8_t *outer_addr)
577 {
578 return efx_filter_spec_set_tunnel(spec, EFX_TUNNEL_PROTOCOL_GENEVE,
579 vni, inner_addr, outer_addr);
580 }
581
582 /*
583 * Specify inner and outer Ethernet address and vsid in NVGRE filter
584 * specification.
585 */
586 __checkReturn efx_rc_t
587 efx_filter_spec_set_nvgre(
588 __inout efx_filter_spec_t *spec,
589 __in const uint8_t *vsid,
590 __in const uint8_t *inner_addr,
591 __in const uint8_t *outer_addr)
592 {
593 return efx_filter_spec_set_tunnel(spec, EFX_TUNNEL_PROTOCOL_NVGRE,
594 vsid, inner_addr, outer_addr);
595 }
596
597 #if EFSYS_OPT_RX_SCALE
598 __checkReturn efx_rc_t
599 efx_filter_spec_set_rss_context(
600 __inout efx_filter_spec_t *spec,
601 __in uint32_t rss_context)
602 {
603 efx_rc_t rc;
604
605 EFSYS_ASSERT3P(spec, !=, NULL);
606
607 /* The filter must have been created with EFX_FILTER_FLAG_RX_RSS. */
608 if ((spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) == 0) {
609 rc = EINVAL;
610 goto fail1;
611 }
612
613 spec->efs_rss_context = rss_context;
614
615 return (0);
616
617 fail1:
618 EFSYS_PROBE1(fail1, efx_rc_t, rc);
619
620 return (rc);
621 }
622 #endif
623
624 #if EFSYS_OPT_SIENA
625
626 /*
627 * "Fudge factors" - difference between programmed value and actual depth.
628 * Due to pipelined implementation we need to program H/W with a value that
629 * is larger than the hop limit we want.
630 */
631 #define FILTER_CTL_SRCH_FUDGE_WILD 3
632 #define FILTER_CTL_SRCH_FUDGE_FULL 1
633
634 /*
635 * Hard maximum hop limit. Hardware will time-out beyond 200-something.
636 * We also need to avoid infinite loops in efx_filter_search() when the
637 * table is full.
638 */
639 #define FILTER_CTL_SRCH_MAX 200
640
641 static __checkReturn efx_rc_t
642 siena_filter_spec_from_gen_spec(
643 __out siena_filter_spec_t *sf_spec,
644 __in efx_filter_spec_t *gen_spec)
645 {
646 efx_rc_t rc;
647 boolean_t is_full = B_FALSE;
648
649 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX)
650 EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX);
651 else
652 EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX);
653
654 /* Siena only has one RSS context */
655 if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
656 gen_spec->efs_rss_context != EFX_RSS_CONTEXT_DEFAULT) {
657 rc = EINVAL;
658 goto fail1;
659 }
660
661 sf_spec->sfs_flags = gen_spec->efs_flags;
662 sf_spec->sfs_dmaq_id = gen_spec->efs_dmaq_id;
663
664 switch (gen_spec->efs_match_flags) {
665 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
666 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
667 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT:
668 is_full = B_TRUE;
669 /* Fall through */
670 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
671 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: {
672 uint32_t rhost, host1, host2;
673 uint16_t rport, port1, port2;
674
675 if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) {
676 rc = ENOTSUP;
677 goto fail2;
678 }
679 if (gen_spec->efs_loc_port == 0 ||
680 (is_full && gen_spec->efs_rem_port == 0)) {
681 rc = EINVAL;
682 goto fail3;
683 }
684 switch (gen_spec->efs_ip_proto) {
685 case EFX_IPPROTO_TCP:
686 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
687 sf_spec->sfs_type = (is_full ?
688 EFX_SIENA_FILTER_TX_TCP_FULL :
689 EFX_SIENA_FILTER_TX_TCP_WILD);
690 } else {
691 sf_spec->sfs_type = (is_full ?
692 EFX_SIENA_FILTER_RX_TCP_FULL :
693 EFX_SIENA_FILTER_RX_TCP_WILD);
694 }
695 break;
696 case EFX_IPPROTO_UDP:
697 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
698 sf_spec->sfs_type = (is_full ?
699 EFX_SIENA_FILTER_TX_UDP_FULL :
700 EFX_SIENA_FILTER_TX_UDP_WILD);
701 } else {
702 sf_spec->sfs_type = (is_full ?
703 EFX_SIENA_FILTER_RX_UDP_FULL :
704 EFX_SIENA_FILTER_RX_UDP_WILD);
705 }
706 break;
707 default:
708 rc = ENOTSUP;
709 goto fail4;
710 }
711 /*
712 * The filter is constructed in terms of source and destination,
713 * with the odd wrinkle that the ports are swapped in a UDP
714 * wildcard filter. We need to convert from local and remote
715 * addresses (zero for a wildcard).
716 */
717 rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0;
718 rport = is_full ? gen_spec->efs_rem_port : 0;
719 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
720 host1 = gen_spec->efs_loc_host.eo_u32[0];
721 host2 = rhost;
722 } else {
723 host1 = rhost;
724 host2 = gen_spec->efs_loc_host.eo_u32[0];
725 }
726 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
727 if (sf_spec->sfs_type ==
728 EFX_SIENA_FILTER_TX_UDP_WILD) {
729 port1 = rport;
730 port2 = gen_spec->efs_loc_port;
731 } else {
732 port1 = gen_spec->efs_loc_port;
733 port2 = rport;
734 }
735 } else {
736 if (sf_spec->sfs_type ==
737 EFX_SIENA_FILTER_RX_UDP_WILD) {
738 port1 = gen_spec->efs_loc_port;
739 port2 = rport;
740 } else {
741 port1 = rport;
742 port2 = gen_spec->efs_loc_port;
743 }
744 }
745 sf_spec->sfs_dword[0] = (host1 << 16) | port1;
746 sf_spec->sfs_dword[1] = (port2 << 16) | (host1 >> 16);
747 sf_spec->sfs_dword[2] = host2;
748 break;
749 }
750
751 case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID:
752 is_full = B_TRUE;
753 /* Fall through */
754 case EFX_FILTER_MATCH_LOC_MAC:
755 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
756 sf_spec->sfs_type = (is_full ?
757 EFX_SIENA_FILTER_TX_MAC_FULL :
758 EFX_SIENA_FILTER_TX_MAC_WILD);
759 } else {
760 sf_spec->sfs_type = (is_full ?
761 EFX_SIENA_FILTER_RX_MAC_FULL :
762 EFX_SIENA_FILTER_RX_MAC_WILD);
763 }
764 sf_spec->sfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0;
765 sf_spec->sfs_dword[1] =
766 gen_spec->efs_loc_mac[2] << 24 |
767 gen_spec->efs_loc_mac[3] << 16 |
768 gen_spec->efs_loc_mac[4] << 8 |
769 gen_spec->efs_loc_mac[5];
770 sf_spec->sfs_dword[2] =
771 gen_spec->efs_loc_mac[0] << 8 |
772 gen_spec->efs_loc_mac[1];
773 break;
774
775 default:
776 EFSYS_ASSERT(B_FALSE);
777 rc = ENOTSUP;
778 goto fail5;
779 }
780
781 return (0);
782
783 fail5:
784 EFSYS_PROBE(fail5);
785 fail4:
786 EFSYS_PROBE(fail4);
787 fail3:
788 EFSYS_PROBE(fail3);
789 fail2:
790 EFSYS_PROBE(fail2);
791 fail1:
792 EFSYS_PROBE1(fail1, efx_rc_t, rc);
793
794 return (rc);
795 }
796
797 /*
798 * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
799 * key derived from the n-tuple.
800 */
801 static uint16_t
802 siena_filter_tbl_hash(
803 __in uint32_t key)
804 {
805 uint16_t tmp;
806
807 /* First 16 rounds */
808 tmp = 0x1fff ^ (uint16_t)(key >> 16);
809 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
810 tmp = tmp ^ tmp >> 9;
811
812 /* Last 16 rounds */
813 tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff);
814 tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
815 tmp = tmp ^ tmp >> 9;
816
817 return (tmp);
818 }
819
820 /*
821 * To allow for hash collisions, filter search continues at these
822 * increments from the first possible entry selected by the hash.
823 */
824 static uint16_t
825 siena_filter_tbl_increment(
826 __in uint32_t key)
827 {
828 return ((uint16_t)(key * 2 - 1));
829 }
830
831 static __checkReturn boolean_t
832 siena_filter_test_used(
833 __in siena_filter_tbl_t *sftp,
834 __in unsigned int index)
835 {
836 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
837 return ((sftp->sft_bitmap[index / 32] & (1 << (index % 32))) != 0);
838 }
839
840 static void
841 siena_filter_set_used(
842 __in siena_filter_tbl_t *sftp,
843 __in unsigned int index)
844 {
845 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
846 sftp->sft_bitmap[index / 32] |= (1 << (index % 32));
847 ++sftp->sft_used;
848 }
849
850 static void
851 siena_filter_clear_used(
852 __in siena_filter_tbl_t *sftp,
853 __in unsigned int index)
854 {
855 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
856 sftp->sft_bitmap[index / 32] &= ~(1 << (index % 32));
857
858 --sftp->sft_used;
859 EFSYS_ASSERT3U(sftp->sft_used, >=, 0);
860 }
861
862
863 static siena_filter_tbl_id_t
864 siena_filter_tbl_id(
865 __in siena_filter_type_t type)
866 {
867 siena_filter_tbl_id_t tbl_id;
868
869 switch (type) {
870 case EFX_SIENA_FILTER_RX_TCP_FULL:
871 case EFX_SIENA_FILTER_RX_TCP_WILD:
872 case EFX_SIENA_FILTER_RX_UDP_FULL:
873 case EFX_SIENA_FILTER_RX_UDP_WILD:
874 tbl_id = EFX_SIENA_FILTER_TBL_RX_IP;
875 break;
876
877 case EFX_SIENA_FILTER_RX_MAC_FULL:
878 case EFX_SIENA_FILTER_RX_MAC_WILD:
879 tbl_id = EFX_SIENA_FILTER_TBL_RX_MAC;
880 break;
881
882 case EFX_SIENA_FILTER_TX_TCP_FULL:
883 case EFX_SIENA_FILTER_TX_TCP_WILD:
884 case EFX_SIENA_FILTER_TX_UDP_FULL:
885 case EFX_SIENA_FILTER_TX_UDP_WILD:
886 tbl_id = EFX_SIENA_FILTER_TBL_TX_IP;
887 break;
888
889 case EFX_SIENA_FILTER_TX_MAC_FULL:
890 case EFX_SIENA_FILTER_TX_MAC_WILD:
891 tbl_id = EFX_SIENA_FILTER_TBL_TX_MAC;
892 break;
893
894 default:
895 EFSYS_ASSERT(B_FALSE);
896 tbl_id = EFX_SIENA_FILTER_NTBLS;
897 break;
898 }
899 return (tbl_id);
900 }
901
902 static void
903 siena_filter_reset_search_depth(
904 __inout siena_filter_t *sfp,
905 __in siena_filter_tbl_id_t tbl_id)
906 {
907 switch (tbl_id) {
908 case EFX_SIENA_FILTER_TBL_RX_IP:
909 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] = 0;
910 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] = 0;
911 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] = 0;
912 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] = 0;
913 break;
914
915 case EFX_SIENA_FILTER_TBL_RX_MAC:
916 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] = 0;
917 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] = 0;
918 break;
919
920 case EFX_SIENA_FILTER_TBL_TX_IP:
921 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] = 0;
922 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] = 0;
923 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] = 0;
924 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] = 0;
925 break;
926
927 case EFX_SIENA_FILTER_TBL_TX_MAC:
928 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] = 0;
929 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] = 0;
930 break;
931
932 default:
933 EFSYS_ASSERT(B_FALSE);
934 break;
935 }
936 }
937
938 static void
939 siena_filter_push_rx_limits(
940 __in efx_nic_t *enp)
941 {
942 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
943 efx_oword_t oword;
944
945 EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
946
947 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT,
948 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] +
949 FILTER_CTL_SRCH_FUDGE_FULL);
950 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT,
951 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] +
952 FILTER_CTL_SRCH_FUDGE_WILD);
953 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT,
954 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] +
955 FILTER_CTL_SRCH_FUDGE_FULL);
956 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT,
957 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] +
958 FILTER_CTL_SRCH_FUDGE_WILD);
959
960 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC].sft_size) {
961 EFX_SET_OWORD_FIELD(oword,
962 FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
963 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] +
964 FILTER_CTL_SRCH_FUDGE_FULL);
965 EFX_SET_OWORD_FIELD(oword,
966 FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
967 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] +
968 FILTER_CTL_SRCH_FUDGE_WILD);
969 }
970
971 EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
972 }
973
974 static void
975 siena_filter_push_tx_limits(
976 __in efx_nic_t *enp)
977 {
978 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
979 efx_oword_t oword;
980
981 EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
982
983 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP].sft_size != 0) {
984 EFX_SET_OWORD_FIELD(oword,
985 FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE,
986 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] +
987 FILTER_CTL_SRCH_FUDGE_FULL);
988 EFX_SET_OWORD_FIELD(oword,
989 FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE,
990 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] +
991 FILTER_CTL_SRCH_FUDGE_WILD);
992 EFX_SET_OWORD_FIELD(oword,
993 FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE,
994 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] +
995 FILTER_CTL_SRCH_FUDGE_FULL);
996 EFX_SET_OWORD_FIELD(oword,
997 FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE,
998 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] +
999 FILTER_CTL_SRCH_FUDGE_WILD);
1000 }
1001
1002 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC].sft_size != 0) {
1003 EFX_SET_OWORD_FIELD(
1004 oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
1005 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] +
1006 FILTER_CTL_SRCH_FUDGE_FULL);
1007 EFX_SET_OWORD_FIELD(
1008 oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
1009 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] +
1010 FILTER_CTL_SRCH_FUDGE_WILD);
1011 }
1012
1013 EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
1014 }
1015
1016 /* Build a filter entry and return its n-tuple key. */
1017 static __checkReturn uint32_t
1018 siena_filter_build(
1019 __out efx_oword_t *filter,
1020 __in siena_filter_spec_t *spec)
1021 {
1022 uint32_t dword3;
1023 uint32_t key;
1024 uint8_t type = spec->sfs_type;
1025 uint32_t flags = spec->sfs_flags;
1026
1027 switch (siena_filter_tbl_id(type)) {
1028 case EFX_SIENA_FILTER_TBL_RX_IP: {
1029 boolean_t is_udp = (type == EFX_SIENA_FILTER_RX_UDP_FULL ||
1030 type == EFX_SIENA_FILTER_RX_UDP_WILD);
1031 EFX_POPULATE_OWORD_7(*filter,
1032 FRF_BZ_RSS_EN,
1033 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
1034 FRF_BZ_SCATTER_EN,
1035 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
1036 FRF_AZ_TCP_UDP, is_udp,
1037 FRF_AZ_RXQ_ID, spec->sfs_dmaq_id,
1038 EFX_DWORD_2, spec->sfs_dword[2],
1039 EFX_DWORD_1, spec->sfs_dword[1],
1040 EFX_DWORD_0, spec->sfs_dword[0]);
1041 dword3 = is_udp;
1042 break;
1043 }
1044
1045 case EFX_SIENA_FILTER_TBL_RX_MAC: {
1046 boolean_t is_wild = (type == EFX_SIENA_FILTER_RX_MAC_WILD);
1047 EFX_POPULATE_OWORD_7(*filter,
1048 FRF_CZ_RMFT_RSS_EN,
1049 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
1050 FRF_CZ_RMFT_SCATTER_EN,
1051 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
1052 FRF_CZ_RMFT_RXQ_ID, spec->sfs_dmaq_id,
1053 FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
1054 FRF_CZ_RMFT_DEST_MAC_DW1, spec->sfs_dword[2],
1055 FRF_CZ_RMFT_DEST_MAC_DW0, spec->sfs_dword[1],
1056 FRF_CZ_RMFT_VLAN_ID, spec->sfs_dword[0]);
1057 dword3 = is_wild;
1058 break;
1059 }
1060
1061 case EFX_SIENA_FILTER_TBL_TX_IP: {
1062 boolean_t is_udp = (type == EFX_SIENA_FILTER_TX_UDP_FULL ||
1063 type == EFX_SIENA_FILTER_TX_UDP_WILD);
1064 EFX_POPULATE_OWORD_5(*filter,
1065 FRF_CZ_TIFT_TCP_UDP, is_udp,
1066 FRF_CZ_TIFT_TXQ_ID, spec->sfs_dmaq_id,
1067 EFX_DWORD_2, spec->sfs_dword[2],
1068 EFX_DWORD_1, spec->sfs_dword[1],
1069 EFX_DWORD_0, spec->sfs_dword[0]);
1070 dword3 = is_udp | spec->sfs_dmaq_id << 1;
1071 break;
1072 }
1073
1074 case EFX_SIENA_FILTER_TBL_TX_MAC: {
1075 boolean_t is_wild = (type == EFX_SIENA_FILTER_TX_MAC_WILD);
1076 EFX_POPULATE_OWORD_5(*filter,
1077 FRF_CZ_TMFT_TXQ_ID, spec->sfs_dmaq_id,
1078 FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
1079 FRF_CZ_TMFT_SRC_MAC_DW1, spec->sfs_dword[2],
1080 FRF_CZ_TMFT_SRC_MAC_DW0, spec->sfs_dword[1],
1081 FRF_CZ_TMFT_VLAN_ID, spec->sfs_dword[0]);
1082 dword3 = is_wild | spec->sfs_dmaq_id << 1;
1083 break;
1084 }
1085
1086 default:
1087 EFSYS_ASSERT(B_FALSE);
1088 EFX_ZERO_OWORD(*filter);
1089 return (0);
1090 }
1091
1092 key =
1093 spec->sfs_dword[0] ^
1094 spec->sfs_dword[1] ^
1095 spec->sfs_dword[2] ^
1096 dword3;
1097
1098 return (key);
1099 }
1100
1101 static __checkReturn efx_rc_t
1102 siena_filter_push_entry(
1103 __inout efx_nic_t *enp,
1104 __in siena_filter_type_t type,
1105 __in int index,
1106 __in efx_oword_t *eop)
1107 {
1108 efx_rc_t rc;
1109
1110 switch (type) {
1111 case EFX_SIENA_FILTER_RX_TCP_FULL:
1112 case EFX_SIENA_FILTER_RX_TCP_WILD:
1113 case EFX_SIENA_FILTER_RX_UDP_FULL:
1114 case EFX_SIENA_FILTER_RX_UDP_WILD:
1115 EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index,
1116 eop, B_TRUE);
1117 break;
1118
1119 case EFX_SIENA_FILTER_RX_MAC_FULL:
1120 case EFX_SIENA_FILTER_RX_MAC_WILD:
1121 EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index,
1122 eop, B_TRUE);
1123 break;
1124
1125 case EFX_SIENA_FILTER_TX_TCP_FULL:
1126 case EFX_SIENA_FILTER_TX_TCP_WILD:
1127 case EFX_SIENA_FILTER_TX_UDP_FULL:
1128 case EFX_SIENA_FILTER_TX_UDP_WILD:
1129 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index,
1130 eop, B_TRUE);
1131 break;
1132
1133 case EFX_SIENA_FILTER_TX_MAC_FULL:
1134 case EFX_SIENA_FILTER_TX_MAC_WILD:
1135 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index,
1136 eop, B_TRUE);
1137 break;
1138
1139 default:
1140 EFSYS_ASSERT(B_FALSE);
1141 rc = ENOTSUP;
1142 goto fail1;
1143 }
1144 return (0);
1145
1146 fail1:
1147 return (rc);
1148 }
1149
1150
1151 static __checkReturn boolean_t
1152 siena_filter_equal(
1153 __in const siena_filter_spec_t *left,
1154 __in const siena_filter_spec_t *right)
1155 {
1156 siena_filter_tbl_id_t tbl_id;
1157
1158 tbl_id = siena_filter_tbl_id(left->sfs_type);
1159
1160
1161 if (left->sfs_type != right->sfs_type)
1162 return (B_FALSE);
1163
1164 if (memcmp(left->sfs_dword, right->sfs_dword,
1165 sizeof (left->sfs_dword)))
1166 return (B_FALSE);
1167
1168 if ((tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1169 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) &&
1170 left->sfs_dmaq_id != right->sfs_dmaq_id)
1171 return (B_FALSE);
1172
1173 return (B_TRUE);
1174 }
1175
1176 static __checkReturn efx_rc_t
1177 siena_filter_search(
1178 __in siena_filter_tbl_t *sftp,
1179 __in siena_filter_spec_t *spec,
1180 __in uint32_t key,
1181 __in boolean_t for_insert,
1182 __out int *filter_index,
1183 __out unsigned int *depth_required)
1184 {
1185 unsigned int hash, incr, filter_idx, depth;
1186
1187 hash = siena_filter_tbl_hash(key);
1188 incr = siena_filter_tbl_increment(key);
1189
1190 filter_idx = hash & (sftp->sft_size - 1);
1191 depth = 1;
1192
1193 for (;;) {
1194 /*
1195 * Return success if entry is used and matches this spec
1196 * or entry is unused and we are trying to insert.
1197 */
1198 if (siena_filter_test_used(sftp, filter_idx) ?
1199 siena_filter_equal(spec,
1200 &sftp->sft_spec[filter_idx]) :
1201 for_insert) {
1202 *filter_index = filter_idx;
1203 *depth_required = depth;
1204 return (0);
1205 }
1206
1207 /* Return failure if we reached the maximum search depth */
1208 if (depth == FILTER_CTL_SRCH_MAX)
1209 return (for_insert ? EBUSY : ENOENT);
1210
1211 filter_idx = (filter_idx + incr) & (sftp->sft_size - 1);
1212 ++depth;
1213 }
1214 }
1215
1216 static void
1217 siena_filter_clear_entry(
1218 __in efx_nic_t *enp,
1219 __in siena_filter_tbl_t *sftp,
1220 __in int index)
1221 {
1222 efx_oword_t filter;
1223
1224 if (siena_filter_test_used(sftp, index)) {
1225 siena_filter_clear_used(sftp, index);
1226
1227 EFX_ZERO_OWORD(filter);
1228 siena_filter_push_entry(enp,
1229 sftp->sft_spec[index].sfs_type,
1230 index, &filter);
1231
1232 memset(&sftp->sft_spec[index],
1233 0, sizeof (sftp->sft_spec[0]));
1234 }
1235 }
1236
1237 void
1238 siena_filter_tbl_clear(
1239 __in efx_nic_t *enp,
1240 __in siena_filter_tbl_id_t tbl_id)
1241 {
1242 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1243 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1244 int index;
1245 efsys_lock_state_t state;
1246
1247 EFSYS_LOCK(enp->en_eslp, state);
1248
1249 for (index = 0; index < sftp->sft_size; ++index) {
1250 siena_filter_clear_entry(enp, sftp, index);
1251 }
1252
1253 if (sftp->sft_used == 0)
1254 siena_filter_reset_search_depth(sfp, tbl_id);
1255
1256 EFSYS_UNLOCK(enp->en_eslp, state);
1257 }
1258
1259 static __checkReturn efx_rc_t
1260 siena_filter_init(
1261 __in efx_nic_t *enp)
1262 {
1263 siena_filter_t *sfp;
1264 siena_filter_tbl_t *sftp;
1265 int tbl_id;
1266 efx_rc_t rc;
1267
1268 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (siena_filter_t), sfp);
1269
1270 if (!sfp) {
1271 rc = ENOMEM;
1272 goto fail1;
1273 }
1274
1275 enp->en_filter.ef_siena_filter = sfp;
1276
1277 switch (enp->en_family) {
1278 case EFX_FAMILY_SIENA:
1279 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_IP];
1280 sftp->sft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
1281
1282 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC];
1283 sftp->sft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
1284
1285 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP];
1286 sftp->sft_size = FR_CZ_TX_FILTER_TBL0_ROWS;
1287
1288 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC];
1289 sftp->sft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
1290 break;
1291
1292 default:
1293 rc = ENOTSUP;
1294 goto fail2;
1295 }
1296
1297 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1298 unsigned int bitmap_size;
1299
1300 sftp = &sfp->sf_tbl[tbl_id];
1301 if (sftp->sft_size == 0)
1302 continue;
1303
1304 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1305 sizeof (uint32_t));
1306 bitmap_size =
1307 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1308
1309 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, sftp->sft_bitmap);
1310 if (!sftp->sft_bitmap) {
1311 rc = ENOMEM;
1312 goto fail3;
1313 }
1314
1315 EFSYS_KMEM_ALLOC(enp->en_esip,
1316 sftp->sft_size * sizeof (*sftp->sft_spec),
1317 sftp->sft_spec);
1318 if (!sftp->sft_spec) {
1319 rc = ENOMEM;
1320 goto fail4;
1321 }
1322 memset(sftp->sft_spec, 0,
1323 sftp->sft_size * sizeof (*sftp->sft_spec));
1324 }
1325
1326 return (0);
1327
1328 fail4:
1329 EFSYS_PROBE(fail4);
1330
1331 fail3:
1332 EFSYS_PROBE(fail3);
1333
1334 fail2:
1335 EFSYS_PROBE(fail2);
1336 siena_filter_fini(enp);
1337
1338 fail1:
1339 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1340 return (rc);
1341 }
1342
1343 static void
1344 siena_filter_fini(
1345 __in efx_nic_t *enp)
1346 {
1347 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1348 siena_filter_tbl_id_t tbl_id;
1349
1350 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1351 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1352
1353 if (sfp == NULL)
1354 return;
1355
1356 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1357 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1358 unsigned int bitmap_size;
1359
1360 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1361 sizeof (uint32_t));
1362 bitmap_size =
1363 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1364
1365 if (sftp->sft_bitmap != NULL) {
1366 EFSYS_KMEM_FREE(enp->en_esip, bitmap_size,
1367 sftp->sft_bitmap);
1368 sftp->sft_bitmap = NULL;
1369 }
1370
1371 if (sftp->sft_spec != NULL) {
1372 EFSYS_KMEM_FREE(enp->en_esip, sftp->sft_size *
1373 sizeof (*sftp->sft_spec), sftp->sft_spec);
1374 sftp->sft_spec = NULL;
1375 }
1376 }
1377
1378 EFSYS_KMEM_FREE(enp->en_esip, sizeof (siena_filter_t),
1379 enp->en_filter.ef_siena_filter);
1380 }
1381
1382 /* Restore filter state after a reset */
1383 static __checkReturn efx_rc_t
1384 siena_filter_restore(
1385 __in efx_nic_t *enp)
1386 {
1387 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1388 siena_filter_tbl_id_t tbl_id;
1389 siena_filter_tbl_t *sftp;
1390 siena_filter_spec_t *spec;
1391 efx_oword_t filter;
1392 int filter_idx;
1393 efsys_lock_state_t state;
1394 uint32_t key;
1395 efx_rc_t rc;
1396
1397 EFSYS_LOCK(enp->en_eslp, state);
1398
1399 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1400 sftp = &sfp->sf_tbl[tbl_id];
1401 for (filter_idx = 0;
1402 filter_idx < sftp->sft_size;
1403 filter_idx++) {
1404 if (!siena_filter_test_used(sftp, filter_idx))
1405 continue;
1406
1407 spec = &sftp->sft_spec[filter_idx];
1408 if ((key = siena_filter_build(&filter, spec)) == 0) {
1409 rc = EINVAL;
1410 goto fail1;
1411 }
1412 if ((rc = siena_filter_push_entry(enp,
1413 spec->sfs_type, filter_idx, &filter)) != 0)
1414 goto fail2;
1415 }
1416 }
1417
1418 siena_filter_push_rx_limits(enp);
1419 siena_filter_push_tx_limits(enp);
1420
1421 EFSYS_UNLOCK(enp->en_eslp, state);
1422
1423 return (0);
1424
1425 fail2:
1426 EFSYS_PROBE(fail2);
1427
1428 fail1:
1429 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1430
1431 EFSYS_UNLOCK(enp->en_eslp, state);
1432
1433 return (rc);
1434 }
1435
1436 static __checkReturn efx_rc_t
1437 siena_filter_add(
1438 __in efx_nic_t *enp,
1439 __inout efx_filter_spec_t *spec,
1440 __in boolean_t may_replace)
1441 {
1442 efx_rc_t rc;
1443 siena_filter_spec_t sf_spec;
1444 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1445 siena_filter_tbl_id_t tbl_id;
1446 siena_filter_tbl_t *sftp;
1447 siena_filter_spec_t *saved_sf_spec;
1448 efx_oword_t filter;
1449 int filter_idx;
1450 unsigned int depth;
1451 efsys_lock_state_t state;
1452 uint32_t key;
1453
1454
1455 EFSYS_ASSERT3P(spec, !=, NULL);
1456
1457 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1458 goto fail1;
1459
1460 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1461 sftp = &sfp->sf_tbl[tbl_id];
1462
1463 if (sftp->sft_size == 0) {
1464 rc = EINVAL;
1465 goto fail2;
1466 }
1467
1468 key = siena_filter_build(&filter, &sf_spec);
1469
1470 EFSYS_LOCK(enp->en_eslp, state);
1471
1472 rc = siena_filter_search(sftp, &sf_spec, key, B_TRUE,
1473 &filter_idx, &depth);
1474 if (rc != 0)
1475 goto fail3;
1476
1477 EFSYS_ASSERT3U(filter_idx, <, sftp->sft_size);
1478 saved_sf_spec = &sftp->sft_spec[filter_idx];
1479
1480 if (siena_filter_test_used(sftp, filter_idx)) {
1481 if (may_replace == B_FALSE) {
1482 rc = EEXIST;
1483 goto fail4;
1484 }
1485 }
1486 siena_filter_set_used(sftp, filter_idx);
1487 *saved_sf_spec = sf_spec;
1488
1489 if (sfp->sf_depth[sf_spec.sfs_type] < depth) {
1490 sfp->sf_depth[sf_spec.sfs_type] = depth;
1491 if (tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1492 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC)
1493 siena_filter_push_tx_limits(enp);
1494 else
1495 siena_filter_push_rx_limits(enp);
1496 }
1497
1498 siena_filter_push_entry(enp, sf_spec.sfs_type,
1499 filter_idx, &filter);
1500
1501 EFSYS_UNLOCK(enp->en_eslp, state);
1502 return (0);
1503
1504 fail4:
1505 EFSYS_PROBE(fail4);
1506
1507 fail3:
1508 EFSYS_UNLOCK(enp->en_eslp, state);
1509 EFSYS_PROBE(fail3);
1510
1511 fail2:
1512 EFSYS_PROBE(fail2);
1513
1514 fail1:
1515 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1516 return (rc);
1517 }
1518
1519 static __checkReturn efx_rc_t
1520 siena_filter_delete(
1521 __in efx_nic_t *enp,
1522 __inout efx_filter_spec_t *spec)
1523 {
1524 efx_rc_t rc;
1525 siena_filter_spec_t sf_spec;
1526 siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1527 siena_filter_tbl_id_t tbl_id;
1528 siena_filter_tbl_t *sftp;
1529 efx_oword_t filter;
1530 int filter_idx;
1531 unsigned int depth;
1532 efsys_lock_state_t state;
1533 uint32_t key;
1534
1535 EFSYS_ASSERT3P(spec, !=, NULL);
1536
1537 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1538 goto fail1;
1539
1540 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1541 sftp = &sfp->sf_tbl[tbl_id];
1542
1543 key = siena_filter_build(&filter, &sf_spec);
1544
1545 EFSYS_LOCK(enp->en_eslp, state);
1546
1547 rc = siena_filter_search(sftp, &sf_spec, key, B_FALSE,
1548 &filter_idx, &depth);
1549 if (rc != 0)
1550 goto fail2;
1551
1552 siena_filter_clear_entry(enp, sftp, filter_idx);
1553 if (sftp->sft_used == 0)
1554 siena_filter_reset_search_depth(sfp, tbl_id);
1555
1556 EFSYS_UNLOCK(enp->en_eslp, state);
1557 return (0);
1558
1559 fail2:
1560 EFSYS_UNLOCK(enp->en_eslp, state);
1561 EFSYS_PROBE(fail2);
1562
1563 fail1:
1564 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1565 return (rc);
1566 }
1567
1568 #define SIENA_MAX_SUPPORTED_MATCHES 4
1569
1570 static __checkReturn efx_rc_t
1571 siena_filter_supported_filters(
1572 __in efx_nic_t *enp,
1573 __out_ecount(buffer_length) uint32_t *buffer,
1574 __in size_t buffer_length,
1575 __out size_t *list_lengthp)
1576 {
1577 uint32_t index = 0;
1578 uint32_t rx_matches[SIENA_MAX_SUPPORTED_MATCHES];
1579 size_t list_length;
1580 efx_rc_t rc;
1581
1582 rx_matches[index++] =
1583 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1584 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
1585 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
1586
1587 rx_matches[index++] =
1588 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1589 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
1590
1591 if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) {
1592 rx_matches[index++] =
1593 EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC;
1594
1595 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC;
1596 }
1597
1598 EFSYS_ASSERT3U(index, <=, SIENA_MAX_SUPPORTED_MATCHES);
1599 list_length = index;
1600
1601 *list_lengthp = list_length;
1602
1603 if (buffer_length < list_length) {
1604 rc = ENOSPC;
1605 goto fail1;
1606 }
1607
1608 memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0]));
1609
1610 return (0);
1611
1612 fail1:
1613 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1614
1615 return (rc);
1616 }
1617
1618 #undef MAX_SUPPORTED
1619
1620 #endif /* EFSYS_OPT_SIENA */
1621
1622 #endif /* EFSYS_OPT_FILTER */