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