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