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