Branch data Line data Source code
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
87 : 0 : efx_filter_insert(
88 : : __in efx_nic_t *enp,
89 : : __inout efx_filter_spec_t *spec)
90 : : {
91 : 0 : 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 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
96 [ # # ]: 0 : EFSYS_ASSERT3P(spec, !=, NULL);
97 [ # # ]: 0 : EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
98 : :
99 [ # # ]: 0 : if ((spec->efs_flags & EFX_FILTER_FLAG_ACTION_MARK) &&
100 [ # # ]: 0 : !encp->enc_filter_action_mark_supported) {
101 : : rc = ENOTSUP;
102 : 0 : goto fail1;
103 : : }
104 : :
105 [ # # ]: 0 : if ((spec->efs_flags & EFX_FILTER_FLAG_ACTION_FLAG) &&
106 [ # # ]: 0 : !encp->enc_filter_action_flag_supported) {
107 : : rc = ENOTSUP;
108 : 0 : goto fail2;
109 : : }
110 : :
111 [ # # ]: 0 : if (spec->efs_priority == EFX_FILTER_PRI_AUTO) {
112 : : rc = EINVAL;
113 : 0 : goto fail3;
114 : : }
115 : :
116 : 0 : 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
130 : 0 : efx_filter_remove(
131 : : __in efx_nic_t *enp,
132 : : __inout efx_filter_spec_t *spec)
133 : : {
134 : 0 : const efx_filter_ops_t *efop = enp->en_efop;
135 : :
136 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
137 [ # # ]: 0 : EFSYS_ASSERT3P(spec, !=, NULL);
138 [ # # ]: 0 : EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
139 : :
140 : 0 : return (efop->efo_delete(enp, spec));
141 : : }
142 : :
143 : : __checkReturn efx_rc_t
144 : 0 : efx_filter_restore(
145 : : __in efx_nic_t *enp)
146 : : {
147 : : efx_rc_t rc;
148 : :
149 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
150 : :
151 [ # # ]: 0 : if ((rc = enp->en_efop->efo_restore(enp)) != 0)
152 : 0 : goto fail1;
153 : :
154 : : return (0);
155 : :
156 : : fail1:
157 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
158 : :
159 : 0 : return (rc);
160 : : }
161 : :
162 : : __checkReturn efx_rc_t
163 : 0 : efx_filter_init(
164 : : __in efx_nic_t *enp)
165 : : {
166 : : const efx_filter_ops_t *efop;
167 : : efx_rc_t rc;
168 : :
169 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
170 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
171 [ # # ]: 0 : EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER));
172 : :
173 [ # # # ]: 0 : 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 : 0 : case EFX_FAMILY_RIVERHEAD:
200 : : efop = &__efx_filter_rhead_ops;
201 : 0 : break;
202 : : #endif /* EFSYS_OPT_RIVERHEAD */
203 : :
204 : : default:
205 : 0 : EFSYS_ASSERT(0);
206 : : rc = ENOTSUP;
207 : : goto fail1;
208 : : }
209 : :
210 [ # # ]: 0 : if ((rc = efop->efo_init(enp)) != 0)
211 : 0 : goto fail2;
212 : :
213 : 0 : enp->en_efop = efop;
214 : 0 : enp->en_mod_flags |= EFX_MOD_FILTER;
215 : 0 : return (0);
216 : :
217 : : fail2:
218 : : EFSYS_PROBE(fail2);
219 : : fail1:
220 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
221 : :
222 : 0 : enp->en_efop = NULL;
223 : 0 : enp->en_mod_flags &= ~EFX_MOD_FILTER;
224 : 0 : return (rc);
225 : : }
226 : :
227 : : void
228 : 0 : efx_filter_fini(
229 : : __in efx_nic_t *enp)
230 : : {
231 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
232 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
233 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
234 : :
235 : 0 : enp->en_efop->efo_fini(enp);
236 : :
237 : 0 : enp->en_efop = NULL;
238 : 0 : enp->en_mod_flags &= ~EFX_MOD_FILTER;
239 : 0 : }
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
252 : 0 : 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 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
261 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
262 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
263 [ # # ]: 0 : EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL);
264 : :
265 [ # # ]: 0 : if (buffer == NULL) {
266 : : rc = EINVAL;
267 : 0 : goto fail1;
268 : : }
269 : :
270 : 0 : rc = enp->en_efop->efo_supported_filters(enp, buffer, buffer_length,
271 : : list_lengthp);
272 [ # # ]: 0 : if (rc != 0)
273 : 0 : 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 : 0 : 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 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
299 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
300 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
301 : :
302 [ # # ]: 0 : if (enp->en_efop->efo_reconfigure != NULL) {
303 [ # # ]: 0 : if ((rc = enp->en_efop->efo_reconfigure(enp, mac_addr,
304 : : all_unicst, mulcst,
305 : : all_mulcst, brdcst,
306 : : addrs, count)) != 0)
307 : 0 : goto fail1;
308 : : }
309 : :
310 : : return (0);
311 : :
312 : : fail1:
313 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
314 : :
315 : 0 : return (rc);
316 : : }
317 : :
318 : : __checkReturn efx_rc_t
319 : 0 : efx_filter_get_count(
320 : : __in efx_nic_t *enp,
321 : : __out uint32_t *countp)
322 : : {
323 : : efx_rc_t rc;
324 : :
325 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
326 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
327 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
328 : :
329 [ # # ]: 0 : if (enp->en_efop->efo_get_count == NULL) {
330 : : rc = ENOTSUP;
331 : 0 : goto fail1;
332 : : }
333 : :
334 [ # # ]: 0 : if ((rc = enp->en_efop->efo_get_count(enp, countp)) != 0)
335 : 0 : 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
348 : 0 : 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 [ # # ]: 0 : EFSYS_ASSERT3P(spec, !=, NULL);
355 [ # # ]: 0 : EFSYS_ASSERT3P(erp, !=, NULL);
356 [ # # ]: 0 : EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
357 : : EFX_FILTER_FLAG_RX_SCATTER)) == 0);
358 : :
359 : : memset(spec, 0, sizeof (*spec));
360 : 0 : spec->efs_priority = priority;
361 : 0 : spec->efs_flags = EFX_FILTER_FLAG_RX | flags;
362 : 0 : spec->efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
363 : 0 : spec->efs_dmaq_id = (uint16_t)erp->er_index;
364 : 0 : }
365 : :
366 : : void
367 : 0 : efx_filter_spec_init_tx(
368 : : __out efx_filter_spec_t *spec,
369 : : __in efx_txq_t *etp)
370 : : {
371 [ # # ]: 0 : EFSYS_ASSERT3P(spec, !=, NULL);
372 [ # # ]: 0 : EFSYS_ASSERT3P(etp, !=, NULL);
373 : :
374 : : memset(spec, 0, sizeof (*spec));
375 : 0 : spec->efs_priority = EFX_FILTER_PRI_MANUAL;
376 : 0 : spec->efs_flags = EFX_FILTER_FLAG_TX;
377 : 0 : spec->efs_dmaq_id = (uint16_t)etp->et_index;
378 : 0 : }
379 : :
380 : :
381 : : /*
382 : : * Specify IPv4 host, transport protocol and port in a filter specification
383 : : */
384 : : __checkReturn efx_rc_t
385 : 0 : 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 [ # # ]: 0 : EFSYS_ASSERT3P(spec, !=, NULL);
392 : :
393 : 0 : 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 : 0 : spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
397 : 0 : spec->efs_ip_proto = proto;
398 : 0 : spec->efs_loc_host.eo_u32[0] = host;
399 : 0 : spec->efs_loc_port = port;
400 : 0 : return (0);
401 : : }
402 : :
403 : : /*
404 : : * Specify IPv4 hosts, transport protocol and ports in a filter specification
405 : : */
406 : : __checkReturn efx_rc_t
407 : 0 : 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 [ # # ]: 0 : EFSYS_ASSERT3P(spec, !=, NULL);
416 : :
417 : 0 : 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 : 0 : spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
422 : 0 : spec->efs_ip_proto = proto;
423 : 0 : spec->efs_loc_host.eo_u32[0] = lhost;
424 : 0 : spec->efs_loc_port = lport;
425 : 0 : spec->efs_rem_host.eo_u32[0] = rhost;
426 : 0 : spec->efs_rem_port = rport;
427 : 0 : return (0);
428 : : }
429 : :
430 : : /*
431 : : * Specify local Ethernet address and/or VID in filter specification
432 : : */
433 : : __checkReturn efx_rc_t
434 : 0 : 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 [ # # ]: 0 : EFSYS_ASSERT3P(spec, !=, NULL);
440 [ # # ]: 0 : EFSYS_ASSERT3P(addr, !=, NULL);
441 : :
442 [ # # ]: 0 : if (vid == EFX_FILTER_SPEC_VID_UNSPEC && addr == NULL)
443 : : return (EINVAL);
444 : :
445 [ # # ]: 0 : if (vid != EFX_FILTER_SPEC_VID_UNSPEC) {
446 : 0 : spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID;
447 : 0 : spec->efs_outer_vid = vid;
448 : : }
449 [ # # ]: 0 : if (addr != NULL) {
450 : 0 : spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
451 : 0 : memcpy(spec->efs_loc_mac, addr, EFX_MAC_ADDR_LEN);
452 : : }
453 : : return (0);
454 : : }
455 : :
456 : : void
457 : 0 : efx_filter_spec_set_ether_type(
458 : : __inout efx_filter_spec_t *spec,
459 : : __in uint16_t ether_type)
460 : : {
461 [ # # ]: 0 : EFSYS_ASSERT3P(spec, !=, NULL);
462 : :
463 : 0 : spec->efs_ether_type = ether_type;
464 : 0 : spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
465 : 0 : }
466 : :
467 : : /*
468 : : * Specify matching otherwise-unmatched unicast in a filter specification
469 : : */
470 : : __checkReturn efx_rc_t
471 : 0 : efx_filter_spec_set_uc_def(
472 : : __inout efx_filter_spec_t *spec)
473 : : {
474 [ # # ]: 0 : EFSYS_ASSERT3P(spec, !=, NULL);
475 : :
476 : 0 : spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_UCAST_DST;
477 : 0 : return (0);
478 : : }
479 : :
480 : : /*
481 : : * Specify matching otherwise-unmatched multicast in a filter specification
482 : : */
483 : : __checkReturn efx_rc_t
484 : 0 : efx_filter_spec_set_mc_def(
485 : : __inout efx_filter_spec_t *spec)
486 : : {
487 [ # # ]: 0 : EFSYS_ASSERT3P(spec, !=, NULL);
488 : :
489 : 0 : spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
490 : 0 : return (0);
491 : : }
492 : :
493 : :
494 : : __checkReturn efx_rc_t
495 : 0 : 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 [ # # ]: 0 : EFSYS_ASSERT3P(spec, !=, NULL);
505 : :
506 [ # # # ]: 0 : switch (encap_type) {
507 : : case EFX_TUNNEL_PROTOCOL_VXLAN:
508 : : case EFX_TUNNEL_PROTOCOL_GENEVE:
509 : : ip_proto = EFX_IPPROTO_UDP;
510 : : break;
511 : 0 : case EFX_TUNNEL_PROTOCOL_NVGRE:
512 : : ip_proto = EFX_IPPROTO_GRE;
513 : 0 : break;
514 : : default:
515 : 0 : 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 : 0 : EFSYS_ASSERT(0);
532 : : rc = EINVAL;
533 : : goto fail2;
534 : : }
535 : :
536 : 0 : spec->efs_encap_type = encap_type;
537 : 0 : spec->efs_ip_proto = ip_proto;
538 : 0 : 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
555 : 0 : 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 [ # # ]: 0 : EFSYS_ASSERT3P(spec, !=, NULL);
565 [ # # ]: 0 : EFSYS_ASSERT3P(vni_or_vsid, !=, NULL);
566 [ # # ]: 0 : EFSYS_ASSERT3P(inner_addr, !=, NULL);
567 [ # # ]: 0 : EFSYS_ASSERT3P(outer_addr, !=, NULL);
568 : :
569 [ # # ]: 0 : switch (encap_type) {
570 : : case EFX_TUNNEL_PROTOCOL_VXLAN:
571 : : case EFX_TUNNEL_PROTOCOL_GENEVE:
572 : : case EFX_TUNNEL_PROTOCOL_NVGRE:
573 : : break;
574 : 0 : default:
575 : : rc = EINVAL;
576 : 0 : goto fail1;
577 : : }
578 : :
579 [ # # ]: 0 : if ((inner_addr == NULL) && (outer_addr == NULL)) {
580 : : rc = EINVAL;
581 : 0 : goto fail2;
582 : : }
583 : :
584 [ # # ]: 0 : if (vni_or_vsid != NULL) {
585 : 0 : spec->efs_match_flags |= EFX_FILTER_MATCH_VNI_OR_VSID;
586 : 0 : memcpy(spec->efs_vni_or_vsid, vni_or_vsid, EFX_VNI_OR_VSID_LEN);
587 : : }
588 [ # # ]: 0 : if (outer_addr != NULL) {
589 : 0 : spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
590 : 0 : memcpy(spec->efs_loc_mac, outer_addr, EFX_MAC_ADDR_LEN);
591 : : }
592 [ # # ]: 0 : if (inner_addr != NULL) {
593 : 0 : spec->efs_match_flags |= EFX_FILTER_MATCH_IFRM_LOC_MAC;
594 : 0 : memcpy(spec->efs_ifrm_loc_mac, inner_addr, EFX_MAC_ADDR_LEN);
595 : : }
596 : :
597 : 0 : spec->efs_match_flags |= EFX_FILTER_MATCH_ENCAP_TYPE;
598 : 0 : spec->efs_encap_type = encap_type;
599 : :
600 : 0 : return (0);
601 : :
602 : : fail2:
603 : : EFSYS_PROBE(fail2);
604 : 0 : 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
615 : 0 : 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 : 0 : 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
630 : 0 : 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 : 0 : 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
645 : 0 : 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 : 0 : 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
657 : 0 : 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 [ # # ]: 0 : EFSYS_ASSERT3P(spec, !=, NULL);
664 : :
665 : : /* The filter must have been created with EFX_FILTER_FLAG_RX_RSS. */
666 [ # # ]: 0 : if ((spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) == 0) {
667 : : rc = EINVAL;
668 : 0 : goto fail1;
669 : : }
670 : :
671 : 0 : spec->efs_rss_context = rss_context;
672 : :
673 : 0 : return (0);
674 : :
675 : : fail1:
676 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
677 : :
678 : 0 : 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 */
|