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