1 /* SPDX-License-Identifier: BSD-3-Clause
2 *
3 * Copyright(c) 2019-2021 Xilinx, Inc.
4 */
5
6 #include "efx.h"
7 #include "efx_impl.h"
8
9
10 #if EFSYS_OPT_MAE
11
12 static __checkReturn efx_rc_t
efx_mae_get_capabilities(__in efx_nic_t * enp)13 efx_mae_get_capabilities(
14 __in efx_nic_t *enp)
15 {
16 efx_mcdi_req_t req;
17 EFX_MCDI_DECLARE_BUF(payload,
18 MC_CMD_MAE_GET_CAPS_IN_LEN,
19 MC_CMD_MAE_GET_CAPS_OUT_LEN);
20 struct efx_mae_s *maep = enp->en_maep;
21 efx_rc_t rc;
22
23 req.emr_cmd = MC_CMD_MAE_GET_CAPS;
24 req.emr_in_buf = payload;
25 req.emr_in_length = MC_CMD_MAE_GET_CAPS_IN_LEN;
26 req.emr_out_buf = payload;
27 req.emr_out_length = MC_CMD_MAE_GET_CAPS_OUT_LEN;
28
29 efx_mcdi_execute(enp, &req);
30
31 if (req.emr_rc != 0) {
32 rc = req.emr_rc;
33 goto fail1;
34 }
35
36 if (req.emr_out_length_used < MC_CMD_MAE_GET_CAPS_OUT_LEN) {
37 rc = EMSGSIZE;
38 goto fail2;
39 }
40
41 maep->em_max_n_outer_prios =
42 MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_OUTER_PRIOS);
43
44 maep->em_max_n_action_prios =
45 MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ACTION_PRIOS);
46
47 maep->em_encap_types_supported = 0;
48
49 if (MCDI_OUT_DWORD_FIELD(req, MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED,
50 MAE_GET_CAPS_OUT_ENCAP_TYPE_VXLAN) != 0) {
51 maep->em_encap_types_supported |=
52 (1U << EFX_TUNNEL_PROTOCOL_VXLAN);
53 }
54
55 if (MCDI_OUT_DWORD_FIELD(req, MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED,
56 MAE_GET_CAPS_OUT_ENCAP_TYPE_GENEVE) != 0) {
57 maep->em_encap_types_supported |=
58 (1U << EFX_TUNNEL_PROTOCOL_GENEVE);
59 }
60
61 if (MCDI_OUT_DWORD_FIELD(req, MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED,
62 MAE_GET_CAPS_OUT_ENCAP_TYPE_NVGRE) != 0) {
63 maep->em_encap_types_supported |=
64 (1U << EFX_TUNNEL_PROTOCOL_NVGRE);
65 }
66
67 maep->em_max_nfields =
68 MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT);
69
70 maep->em_max_ncounters =
71 MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_COUNTERS);
72
73 return (0);
74
75 fail2:
76 EFSYS_PROBE(fail2);
77 fail1:
78 EFSYS_PROBE1(fail1, efx_rc_t, rc);
79 return (rc);
80 }
81
82 static __checkReturn efx_rc_t
efx_mae_get_outer_rule_caps(__in efx_nic_t * enp,__in unsigned int field_ncaps,__out_ecount (field_ncaps)efx_mae_field_cap_t * field_caps)83 efx_mae_get_outer_rule_caps(
84 __in efx_nic_t *enp,
85 __in unsigned int field_ncaps,
86 __out_ecount(field_ncaps) efx_mae_field_cap_t *field_caps)
87 {
88 efx_mcdi_req_t req;
89 EFX_MCDI_DECLARE_BUF(payload,
90 MC_CMD_MAE_GET_OR_CAPS_IN_LEN,
91 MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2);
92 unsigned int mcdi_field_ncaps;
93 unsigned int i;
94 efx_rc_t rc;
95
96 if (MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps) >
97 MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2) {
98 rc = EINVAL;
99 goto fail1;
100 }
101
102 req.emr_cmd = MC_CMD_MAE_GET_OR_CAPS;
103 req.emr_in_buf = payload;
104 req.emr_in_length = MC_CMD_MAE_GET_OR_CAPS_IN_LEN;
105 req.emr_out_buf = payload;
106 req.emr_out_length = MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps);
107
108 efx_mcdi_execute(enp, &req);
109
110 if (req.emr_rc != 0) {
111 rc = req.emr_rc;
112 goto fail2;
113 }
114
115 if (req.emr_out_length_used < MC_CMD_MAE_GET_OR_CAPS_OUT_LENMIN) {
116 rc = EMSGSIZE;
117 goto fail3;
118 }
119
120 mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_OR_CAPS_OUT_COUNT);
121
122 if (req.emr_out_length_used <
123 MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(mcdi_field_ncaps)) {
124 rc = EMSGSIZE;
125 goto fail4;
126 }
127
128 if (mcdi_field_ncaps > field_ncaps) {
129 rc = EMSGSIZE;
130 goto fail5;
131 }
132
133 for (i = 0; i < mcdi_field_ncaps; ++i) {
134 uint32_t match_flag;
135 uint32_t mask_flag;
136
137 field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req,
138 MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
139 MAE_FIELD_FLAGS_SUPPORT_STATUS);
140
141 match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
142 MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
143 MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS);
144
145 field_caps[i].emfc_match_affects_class =
146 (match_flag != 0) ? B_TRUE : B_FALSE;
147
148 mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
149 MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
150 MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS);
151
152 field_caps[i].emfc_mask_affects_class =
153 (mask_flag != 0) ? B_TRUE : B_FALSE;
154 }
155
156 return (0);
157
158 fail5:
159 EFSYS_PROBE(fail5);
160 fail4:
161 EFSYS_PROBE(fail4);
162 fail3:
163 EFSYS_PROBE(fail3);
164 fail2:
165 EFSYS_PROBE(fail2);
166 fail1:
167 EFSYS_PROBE1(fail1, efx_rc_t, rc);
168 return (rc);
169 }
170
171 static __checkReturn efx_rc_t
efx_mae_get_action_rule_caps(__in efx_nic_t * enp,__in unsigned int field_ncaps,__out_ecount (field_ncaps)efx_mae_field_cap_t * field_caps)172 efx_mae_get_action_rule_caps(
173 __in efx_nic_t *enp,
174 __in unsigned int field_ncaps,
175 __out_ecount(field_ncaps) efx_mae_field_cap_t *field_caps)
176 {
177 efx_mcdi_req_t req;
178 EFX_MCDI_DECLARE_BUF(payload,
179 MC_CMD_MAE_GET_AR_CAPS_IN_LEN,
180 MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2);
181 unsigned int mcdi_field_ncaps;
182 unsigned int i;
183 efx_rc_t rc;
184
185 if (MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps) >
186 MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2) {
187 rc = EINVAL;
188 goto fail1;
189 }
190
191 req.emr_cmd = MC_CMD_MAE_GET_AR_CAPS;
192 req.emr_in_buf = payload;
193 req.emr_in_length = MC_CMD_MAE_GET_AR_CAPS_IN_LEN;
194 req.emr_out_buf = payload;
195 req.emr_out_length = MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps);
196
197 efx_mcdi_execute(enp, &req);
198
199 if (req.emr_rc != 0) {
200 rc = req.emr_rc;
201 goto fail2;
202 }
203
204 if (req.emr_out_length_used < MC_CMD_MAE_GET_AR_CAPS_OUT_LENMIN) {
205 rc = EMSGSIZE;
206 goto fail3;
207 }
208
209 mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_AR_CAPS_OUT_COUNT);
210
211 if (req.emr_out_length_used <
212 MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(mcdi_field_ncaps)) {
213 rc = EMSGSIZE;
214 goto fail4;
215 }
216
217 if (mcdi_field_ncaps > field_ncaps) {
218 rc = EMSGSIZE;
219 goto fail5;
220 }
221
222 for (i = 0; i < mcdi_field_ncaps; ++i) {
223 uint32_t match_flag;
224 uint32_t mask_flag;
225
226 field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req,
227 MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
228 MAE_FIELD_FLAGS_SUPPORT_STATUS);
229
230 match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
231 MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
232 MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS);
233
234 field_caps[i].emfc_match_affects_class =
235 (match_flag != 0) ? B_TRUE : B_FALSE;
236
237 mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
238 MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
239 MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS);
240
241 field_caps[i].emfc_mask_affects_class =
242 (mask_flag != 0) ? B_TRUE : B_FALSE;
243 }
244
245 return (0);
246
247 fail5:
248 EFSYS_PROBE(fail5);
249 fail4:
250 EFSYS_PROBE(fail4);
251 fail3:
252 EFSYS_PROBE(fail3);
253 fail2:
254 EFSYS_PROBE(fail2);
255 fail1:
256 EFSYS_PROBE1(fail1, efx_rc_t, rc);
257 return (rc);
258 }
259
260 __checkReturn efx_rc_t
efx_mae_init(__in efx_nic_t * enp)261 efx_mae_init(
262 __in efx_nic_t *enp)
263 {
264 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
265 efx_mae_field_cap_t *or_fcaps;
266 size_t or_fcaps_size;
267 efx_mae_field_cap_t *ar_fcaps;
268 size_t ar_fcaps_size;
269 efx_mae_t *maep;
270 efx_rc_t rc;
271
272 if (encp->enc_mae_supported == B_FALSE) {
273 rc = ENOTSUP;
274 goto fail1;
275 }
276
277 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*maep), maep);
278 if (maep == NULL) {
279 rc = ENOMEM;
280 goto fail2;
281 }
282
283 enp->en_maep = maep;
284
285 rc = efx_mae_get_capabilities(enp);
286 if (rc != 0)
287 goto fail3;
288
289 or_fcaps_size = maep->em_max_nfields * sizeof (*or_fcaps);
290 EFSYS_KMEM_ALLOC(enp->en_esip, or_fcaps_size, or_fcaps);
291 if (or_fcaps == NULL) {
292 rc = ENOMEM;
293 goto fail4;
294 }
295
296 maep->em_outer_rule_field_caps_size = or_fcaps_size;
297 maep->em_outer_rule_field_caps = or_fcaps;
298
299 rc = efx_mae_get_outer_rule_caps(enp, maep->em_max_nfields, or_fcaps);
300 if (rc != 0)
301 goto fail5;
302
303 ar_fcaps_size = maep->em_max_nfields * sizeof (*ar_fcaps);
304 EFSYS_KMEM_ALLOC(enp->en_esip, ar_fcaps_size, ar_fcaps);
305 if (ar_fcaps == NULL) {
306 rc = ENOMEM;
307 goto fail6;
308 }
309
310 maep->em_action_rule_field_caps_size = ar_fcaps_size;
311 maep->em_action_rule_field_caps = ar_fcaps;
312
313 rc = efx_mae_get_action_rule_caps(enp, maep->em_max_nfields, ar_fcaps);
314 if (rc != 0)
315 goto fail7;
316
317 return (0);
318
319 fail7:
320 EFSYS_PROBE(fail5);
321 EFSYS_KMEM_FREE(enp->en_esip, ar_fcaps_size, ar_fcaps);
322 fail6:
323 EFSYS_PROBE(fail4);
324 fail5:
325 EFSYS_PROBE(fail5);
326 EFSYS_KMEM_FREE(enp->en_esip, or_fcaps_size, or_fcaps);
327 fail4:
328 EFSYS_PROBE(fail4);
329 fail3:
330 EFSYS_PROBE(fail3);
331 EFSYS_KMEM_FREE(enp->en_esip, sizeof (struct efx_mae_s), enp->en_maep);
332 enp->en_maep = NULL;
333 fail2:
334 EFSYS_PROBE(fail2);
335 fail1:
336 EFSYS_PROBE1(fail1, efx_rc_t, rc);
337 return (rc);
338 }
339
340 void
efx_mae_fini(__in efx_nic_t * enp)341 efx_mae_fini(
342 __in efx_nic_t *enp)
343 {
344 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
345 efx_mae_t *maep = enp->en_maep;
346
347 if (encp->enc_mae_supported == B_FALSE)
348 return;
349
350 EFSYS_KMEM_FREE(enp->en_esip, maep->em_action_rule_field_caps_size,
351 maep->em_action_rule_field_caps);
352 EFSYS_KMEM_FREE(enp->en_esip, maep->em_outer_rule_field_caps_size,
353 maep->em_outer_rule_field_caps);
354 EFSYS_KMEM_FREE(enp->en_esip, sizeof (*maep), maep);
355 enp->en_maep = NULL;
356 }
357
358 __checkReturn efx_rc_t
efx_mae_get_limits(__in efx_nic_t * enp,__out efx_mae_limits_t * emlp)359 efx_mae_get_limits(
360 __in efx_nic_t *enp,
361 __out efx_mae_limits_t *emlp)
362 {
363 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
364 struct efx_mae_s *maep = enp->en_maep;
365 efx_rc_t rc;
366
367 if (encp->enc_mae_supported == B_FALSE) {
368 rc = ENOTSUP;
369 goto fail1;
370 }
371
372 emlp->eml_max_n_outer_prios = maep->em_max_n_outer_prios;
373 emlp->eml_max_n_action_prios = maep->em_max_n_action_prios;
374 emlp->eml_encap_types_supported = maep->em_encap_types_supported;
375 emlp->eml_encap_header_size_limit =
376 MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2;
377 emlp->eml_max_n_counters = maep->em_max_ncounters;
378
379 return (0);
380
381 fail1:
382 EFSYS_PROBE1(fail1, efx_rc_t, rc);
383 return (rc);
384 }
385
386 __checkReturn efx_rc_t
efx_mae_match_spec_init(__in efx_nic_t * enp,__in efx_mae_rule_type_t type,__in uint32_t prio,__out efx_mae_match_spec_t ** specp)387 efx_mae_match_spec_init(
388 __in efx_nic_t *enp,
389 __in efx_mae_rule_type_t type,
390 __in uint32_t prio,
391 __out efx_mae_match_spec_t **specp)
392 {
393 efx_mae_match_spec_t *spec;
394 efx_rc_t rc;
395
396 switch (type) {
397 case EFX_MAE_RULE_OUTER:
398 break;
399 case EFX_MAE_RULE_ACTION:
400 break;
401 default:
402 rc = ENOTSUP;
403 goto fail1;
404 }
405
406 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
407 if (spec == NULL) {
408 rc = ENOMEM;
409 goto fail2;
410 }
411
412 spec->emms_type = type;
413 spec->emms_prio = prio;
414
415 *specp = spec;
416
417 return (0);
418
419 fail2:
420 EFSYS_PROBE(fail2);
421 fail1:
422 EFSYS_PROBE1(fail1, efx_rc_t, rc);
423 return (rc);
424 }
425
426 void
efx_mae_match_spec_fini(__in efx_nic_t * enp,__in efx_mae_match_spec_t * spec)427 efx_mae_match_spec_fini(
428 __in efx_nic_t *enp,
429 __in efx_mae_match_spec_t *spec)
430 {
431 EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
432 }
433
434 /* Named identifiers which are valid indices to efx_mae_field_cap_t */
435 typedef enum efx_mae_field_cap_id_e {
436 EFX_MAE_FIELD_ID_INGRESS_MPORT_SELECTOR = MAE_FIELD_INGRESS_PORT,
437 EFX_MAE_FIELD_ID_ETHER_TYPE_BE = MAE_FIELD_ETHER_TYPE,
438 EFX_MAE_FIELD_ID_ETH_SADDR_BE = MAE_FIELD_ETH_SADDR,
439 EFX_MAE_FIELD_ID_ETH_DADDR_BE = MAE_FIELD_ETH_DADDR,
440 EFX_MAE_FIELD_ID_VLAN0_TCI_BE = MAE_FIELD_VLAN0_TCI,
441 EFX_MAE_FIELD_ID_VLAN0_PROTO_BE = MAE_FIELD_VLAN0_PROTO,
442 EFX_MAE_FIELD_ID_VLAN1_TCI_BE = MAE_FIELD_VLAN1_TCI,
443 EFX_MAE_FIELD_ID_VLAN1_PROTO_BE = MAE_FIELD_VLAN1_PROTO,
444 EFX_MAE_FIELD_ID_SRC_IP4_BE = MAE_FIELD_SRC_IP4,
445 EFX_MAE_FIELD_ID_DST_IP4_BE = MAE_FIELD_DST_IP4,
446 EFX_MAE_FIELD_ID_IP_PROTO = MAE_FIELD_IP_PROTO,
447 EFX_MAE_FIELD_ID_IP_TOS = MAE_FIELD_IP_TOS,
448 EFX_MAE_FIELD_ID_IP_TTL = MAE_FIELD_IP_TTL,
449 EFX_MAE_FIELD_ID_SRC_IP6_BE = MAE_FIELD_SRC_IP6,
450 EFX_MAE_FIELD_ID_DST_IP6_BE = MAE_FIELD_DST_IP6,
451 EFX_MAE_FIELD_ID_L4_SPORT_BE = MAE_FIELD_L4_SPORT,
452 EFX_MAE_FIELD_ID_L4_DPORT_BE = MAE_FIELD_L4_DPORT,
453 EFX_MAE_FIELD_ID_TCP_FLAGS_BE = MAE_FIELD_TCP_FLAGS,
454 EFX_MAE_FIELD_ID_ENC_ETHER_TYPE_BE = MAE_FIELD_ENC_ETHER_TYPE,
455 EFX_MAE_FIELD_ID_ENC_ETH_SADDR_BE = MAE_FIELD_ENC_ETH_SADDR,
456 EFX_MAE_FIELD_ID_ENC_ETH_DADDR_BE = MAE_FIELD_ENC_ETH_DADDR,
457 EFX_MAE_FIELD_ID_ENC_VLAN0_TCI_BE = MAE_FIELD_ENC_VLAN0_TCI,
458 EFX_MAE_FIELD_ID_ENC_VLAN0_PROTO_BE = MAE_FIELD_ENC_VLAN0_PROTO,
459 EFX_MAE_FIELD_ID_ENC_VLAN1_TCI_BE = MAE_FIELD_ENC_VLAN1_TCI,
460 EFX_MAE_FIELD_ID_ENC_VLAN1_PROTO_BE = MAE_FIELD_ENC_VLAN1_PROTO,
461 EFX_MAE_FIELD_ID_ENC_SRC_IP4_BE = MAE_FIELD_ENC_SRC_IP4,
462 EFX_MAE_FIELD_ID_ENC_DST_IP4_BE = MAE_FIELD_ENC_DST_IP4,
463 EFX_MAE_FIELD_ID_ENC_IP_PROTO = MAE_FIELD_ENC_IP_PROTO,
464 EFX_MAE_FIELD_ID_ENC_IP_TOS = MAE_FIELD_ENC_IP_TOS,
465 EFX_MAE_FIELD_ID_ENC_IP_TTL = MAE_FIELD_ENC_IP_TTL,
466 EFX_MAE_FIELD_ID_ENC_SRC_IP6_BE = MAE_FIELD_ENC_SRC_IP6,
467 EFX_MAE_FIELD_ID_ENC_DST_IP6_BE = MAE_FIELD_ENC_DST_IP6,
468 EFX_MAE_FIELD_ID_ENC_L4_SPORT_BE = MAE_FIELD_ENC_L4_SPORT,
469 EFX_MAE_FIELD_ID_ENC_L4_DPORT_BE = MAE_FIELD_ENC_L4_DPORT,
470 EFX_MAE_FIELD_ID_ENC_VNET_ID_BE = MAE_FIELD_ENC_VNET_ID,
471 EFX_MAE_FIELD_ID_OUTER_RULE_ID = MAE_FIELD_OUTER_RULE_ID,
472 EFX_MAE_FIELD_ID_HAS_OVLAN = MAE_FIELD_HAS_OVLAN,
473 EFX_MAE_FIELD_ID_HAS_IVLAN = MAE_FIELD_HAS_IVLAN,
474 EFX_MAE_FIELD_ID_ENC_HAS_OVLAN = MAE_FIELD_ENC_HAS_OVLAN,
475 EFX_MAE_FIELD_ID_ENC_HAS_IVLAN = MAE_FIELD_ENC_HAS_IVLAN,
476 EFX_MAE_FIELD_ID_RECIRC_ID = MAE_FIELD_RECIRC_ID,
477
478 EFX_MAE_FIELD_CAP_NIDS
479 } efx_mae_field_cap_id_t;
480
481 typedef enum efx_mae_field_endianness_e {
482 EFX_MAE_FIELD_LE = 0,
483 EFX_MAE_FIELD_BE,
484
485 EFX_MAE_FIELD_ENDIANNESS_NTYPES
486 } efx_mae_field_endianness_t;
487
488 /*
489 * The following structure is a means to describe an MAE field.
490 * The information in it is meant to be used internally by
491 * APIs for addressing a given field in a mask-value pairs
492 * structure and for validation purposes.
493 *
494 * A field may have an alternative one. This structure
495 * has additional members to reference the alternative
496 * field's mask. See efx_mae_match_spec_is_valid().
497 */
498 typedef struct efx_mae_mv_desc_s {
499 efx_mae_field_cap_id_t emmd_field_cap_id;
500
501 size_t emmd_value_size;
502 size_t emmd_value_offset;
503 size_t emmd_mask_size;
504 size_t emmd_mask_offset;
505
506 /*
507 * Having the alternative field's mask size set to 0
508 * means that there's no alternative field specified.
509 */
510 size_t emmd_alt_mask_size;
511 size_t emmd_alt_mask_offset;
512
513 /* Primary field and the alternative one are of the same endianness. */
514 efx_mae_field_endianness_t emmd_endianness;
515 } efx_mae_mv_desc_t;
516
517 /* Indices to this array are provided by efx_mae_field_id_t */
518 static const efx_mae_mv_desc_t __efx_mae_action_rule_mv_desc_set[] = {
519 #define EFX_MAE_MV_DESC(_name, _endianness) \
520 [EFX_MAE_FIELD_##_name] = \
521 { \
522 EFX_MAE_FIELD_ID_##_name, \
523 MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LEN, \
524 MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_OFST, \
525 MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_MASK_LEN, \
526 MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_MASK_OFST, \
527 0, 0 /* no alternative field */, \
528 _endianness \
529 }
530
531 EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
532 EFX_MAE_MV_DESC(ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
533 EFX_MAE_MV_DESC(ETH_SADDR_BE, EFX_MAE_FIELD_BE),
534 EFX_MAE_MV_DESC(ETH_DADDR_BE, EFX_MAE_FIELD_BE),
535 EFX_MAE_MV_DESC(VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
536 EFX_MAE_MV_DESC(VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
537 EFX_MAE_MV_DESC(VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
538 EFX_MAE_MV_DESC(VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
539 EFX_MAE_MV_DESC(SRC_IP4_BE, EFX_MAE_FIELD_BE),
540 EFX_MAE_MV_DESC(DST_IP4_BE, EFX_MAE_FIELD_BE),
541 EFX_MAE_MV_DESC(IP_PROTO, EFX_MAE_FIELD_BE),
542 EFX_MAE_MV_DESC(IP_TOS, EFX_MAE_FIELD_BE),
543 EFX_MAE_MV_DESC(IP_TTL, EFX_MAE_FIELD_BE),
544 EFX_MAE_MV_DESC(SRC_IP6_BE, EFX_MAE_FIELD_BE),
545 EFX_MAE_MV_DESC(DST_IP6_BE, EFX_MAE_FIELD_BE),
546 EFX_MAE_MV_DESC(L4_SPORT_BE, EFX_MAE_FIELD_BE),
547 EFX_MAE_MV_DESC(L4_DPORT_BE, EFX_MAE_FIELD_BE),
548 EFX_MAE_MV_DESC(TCP_FLAGS_BE, EFX_MAE_FIELD_BE),
549 EFX_MAE_MV_DESC(ENC_VNET_ID_BE, EFX_MAE_FIELD_BE),
550 EFX_MAE_MV_DESC(OUTER_RULE_ID, EFX_MAE_FIELD_LE),
551 EFX_MAE_MV_DESC(RECIRC_ID, EFX_MAE_FIELD_LE),
552
553 #undef EFX_MAE_MV_DESC
554 };
555
556 /* Indices to this array are provided by efx_mae_field_id_t */
557 static const efx_mae_mv_desc_t __efx_mae_outer_rule_mv_desc_set[] = {
558 #define EFX_MAE_MV_DESC(_name, _endianness) \
559 [EFX_MAE_FIELD_##_name] = \
560 { \
561 EFX_MAE_FIELD_ID_##_name, \
562 MAE_ENC_FIELD_PAIRS_##_name##_LEN, \
563 MAE_ENC_FIELD_PAIRS_##_name##_OFST, \
564 MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN, \
565 MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST, \
566 0, 0 /* no alternative field */, \
567 _endianness \
568 }
569
570 /* Same as EFX_MAE_MV_DESC(), but also indicates an alternative field. */
571 #define EFX_MAE_MV_DESC_ALT(_name, _alt_name, _endianness) \
572 [EFX_MAE_FIELD_##_name] = \
573 { \
574 EFX_MAE_FIELD_ID_##_name, \
575 MAE_ENC_FIELD_PAIRS_##_name##_LEN, \
576 MAE_ENC_FIELD_PAIRS_##_name##_OFST, \
577 MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN, \
578 MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST, \
579 MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_LEN, \
580 MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_OFST, \
581 _endianness \
582 }
583
584 EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
585 EFX_MAE_MV_DESC(ENC_ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
586 EFX_MAE_MV_DESC(ENC_ETH_SADDR_BE, EFX_MAE_FIELD_BE),
587 EFX_MAE_MV_DESC(ENC_ETH_DADDR_BE, EFX_MAE_FIELD_BE),
588 EFX_MAE_MV_DESC(ENC_VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
589 EFX_MAE_MV_DESC(ENC_VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
590 EFX_MAE_MV_DESC(ENC_VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
591 EFX_MAE_MV_DESC(ENC_VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
592 EFX_MAE_MV_DESC_ALT(ENC_SRC_IP4_BE, ENC_SRC_IP6_BE, EFX_MAE_FIELD_BE),
593 EFX_MAE_MV_DESC_ALT(ENC_DST_IP4_BE, ENC_DST_IP6_BE, EFX_MAE_FIELD_BE),
594 EFX_MAE_MV_DESC(ENC_IP_PROTO, EFX_MAE_FIELD_BE),
595 EFX_MAE_MV_DESC(ENC_IP_TOS, EFX_MAE_FIELD_BE),
596 EFX_MAE_MV_DESC(ENC_IP_TTL, EFX_MAE_FIELD_BE),
597 EFX_MAE_MV_DESC_ALT(ENC_SRC_IP6_BE, ENC_SRC_IP4_BE, EFX_MAE_FIELD_BE),
598 EFX_MAE_MV_DESC_ALT(ENC_DST_IP6_BE, ENC_DST_IP4_BE, EFX_MAE_FIELD_BE),
599 EFX_MAE_MV_DESC(ENC_L4_SPORT_BE, EFX_MAE_FIELD_BE),
600 EFX_MAE_MV_DESC(ENC_L4_DPORT_BE, EFX_MAE_FIELD_BE),
601
602 #undef EFX_MAE_MV_DESC_ALT
603 #undef EFX_MAE_MV_DESC
604 };
605
606 /*
607 * The following structure is a means to describe an MAE bit.
608 * The information in it is meant to be used internally by
609 * APIs for addressing a given flag in a mask-value pairs
610 * structure and for validation purposes.
611 */
612 typedef struct efx_mae_mv_bit_desc_s {
613 /*
614 * Arrays using this struct are indexed by field IDs.
615 * Fields which aren't meant to be referenced by these
616 * arrays comprise gaps (invalid entries). Below field
617 * helps to identify such entries.
618 */
619 boolean_t emmbd_entry_is_valid;
620 efx_mae_field_cap_id_t emmbd_bit_cap_id;
621 size_t emmbd_value_ofst;
622 unsigned int emmbd_value_lbn;
623 size_t emmbd_mask_ofst;
624 unsigned int emmbd_mask_lbn;
625 } efx_mae_mv_bit_desc_t;
626
627 static const efx_mae_mv_bit_desc_t __efx_mae_outer_rule_mv_bit_desc_set[] = {
628 #define EFX_MAE_MV_BIT_DESC(_name) \
629 [EFX_MAE_FIELD_##_name] = \
630 { \
631 B_TRUE, \
632 EFX_MAE_FIELD_ID_##_name, \
633 MAE_ENC_FIELD_PAIRS_##_name##_OFST, \
634 MAE_ENC_FIELD_PAIRS_##_name##_LBN, \
635 MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST, \
636 MAE_ENC_FIELD_PAIRS_##_name##_MASK_LBN, \
637 }
638
639 EFX_MAE_MV_BIT_DESC(ENC_HAS_OVLAN),
640 EFX_MAE_MV_BIT_DESC(ENC_HAS_IVLAN),
641
642 #undef EFX_MAE_MV_BIT_DESC
643 };
644
645 static const efx_mae_mv_bit_desc_t __efx_mae_action_rule_mv_bit_desc_set[] = {
646 #define EFX_MAE_MV_BIT_DESC(_name) \
647 [EFX_MAE_FIELD_##_name] = \
648 { \
649 B_TRUE, \
650 EFX_MAE_FIELD_ID_##_name, \
651 MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_OFST, \
652 MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LBN, \
653 MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK_OFST, \
654 MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LBN, \
655 }
656
657 EFX_MAE_MV_BIT_DESC(HAS_OVLAN),
658 EFX_MAE_MV_BIT_DESC(HAS_IVLAN),
659 EFX_MAE_MV_BIT_DESC(ENC_HAS_OVLAN),
660 EFX_MAE_MV_BIT_DESC(ENC_HAS_IVLAN),
661
662 #undef EFX_MAE_MV_BIT_DESC
663 };
664
665 __checkReturn efx_rc_t
efx_mae_mport_invalid(__out efx_mport_sel_t * mportp)666 efx_mae_mport_invalid(
667 __out efx_mport_sel_t *mportp)
668 {
669 efx_dword_t dword;
670 efx_rc_t rc;
671
672 if (mportp == NULL) {
673 rc = EINVAL;
674 goto fail1;
675 }
676
677 EFX_POPULATE_DWORD_1(dword,
678 MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_INVALID);
679
680 memset(mportp, 0, sizeof (*mportp));
681 mportp->sel = dword.ed_u32[0];
682
683 return (0);
684
685 fail1:
686 EFSYS_PROBE1(fail1, efx_rc_t, rc);
687 return (rc);
688 }
689
690 __checkReturn efx_rc_t
efx_mae_mport_by_phy_port(__in uint32_t phy_port,__out efx_mport_sel_t * mportp)691 efx_mae_mport_by_phy_port(
692 __in uint32_t phy_port,
693 __out efx_mport_sel_t *mportp)
694 {
695 efx_dword_t dword;
696 efx_rc_t rc;
697
698 if (phy_port > EFX_MASK32(MAE_MPORT_SELECTOR_PPORT_ID)) {
699 rc = EINVAL;
700 goto fail1;
701 }
702
703 EFX_POPULATE_DWORD_2(dword,
704 MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT,
705 MAE_MPORT_SELECTOR_PPORT_ID, phy_port);
706
707 memset(mportp, 0, sizeof (*mportp));
708 /*
709 * The constructed DWORD is little-endian,
710 * but the resulting value is meant to be
711 * passed to MCDIs, where it will undergo
712 * host-order to little endian conversion.
713 */
714 mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
715
716 return (0);
717
718 fail1:
719 EFSYS_PROBE1(fail1, efx_rc_t, rc);
720 return (rc);
721 }
722
723 __checkReturn efx_rc_t
efx_mae_mport_by_pcie_function(__in uint32_t pf,__in uint32_t vf,__out efx_mport_sel_t * mportp)724 efx_mae_mport_by_pcie_function(
725 __in uint32_t pf,
726 __in uint32_t vf,
727 __out efx_mport_sel_t *mportp)
728 {
729 efx_dword_t dword;
730 efx_rc_t rc;
731
732 rc = efx_mae_mport_by_pcie_mh_function(EFX_PCIE_INTERFACE_CALLER,
733 pf, vf, mportp);
734 if (rc != 0)
735 goto fail1;
736
737 return (0);
738
739 fail1:
740 EFSYS_PROBE1(fail1, efx_rc_t, rc);
741 return (rc);
742 }
743
744 static __checkReturn efx_rc_t
efx_mae_intf_to_selector(__in efx_pcie_interface_t intf,__out uint32_t * selector_intfp)745 efx_mae_intf_to_selector(
746 __in efx_pcie_interface_t intf,
747 __out uint32_t *selector_intfp)
748 {
749 efx_rc_t rc;
750
751 switch (intf) {
752 case EFX_PCIE_INTERFACE_HOST_PRIMARY:
753 EFX_STATIC_ASSERT(MAE_MPORT_SELECTOR_HOST_PRIMARY <=
754 EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_INTF_ID));
755 *selector_intfp = MAE_MPORT_SELECTOR_HOST_PRIMARY;
756 break;
757 case EFX_PCIE_INTERFACE_NIC_EMBEDDED:
758 EFX_STATIC_ASSERT(MAE_MPORT_SELECTOR_NIC_EMBEDDED <=
759 EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_INTF_ID));
760 *selector_intfp = MAE_MPORT_SELECTOR_NIC_EMBEDDED;
761 break;
762 case EFX_PCIE_INTERFACE_CALLER:
763 EFX_STATIC_ASSERT(MAE_MPORT_SELECTOR_CALLER_INTF <=
764 EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_INTF_ID));
765 *selector_intfp = MAE_MPORT_SELECTOR_CALLER_INTF;
766 break;
767 default:
768 rc = EINVAL;
769 goto fail1;
770 }
771
772 return (0);
773
774 fail1:
775 EFSYS_PROBE1(fail1, efx_rc_t, rc);
776 return (rc);
777 }
778
779 __checkReturn efx_rc_t
efx_mae_mport_by_pcie_mh_function(__in efx_pcie_interface_t intf,__in uint32_t pf,__in uint32_t vf,__out efx_mport_sel_t * mportp)780 efx_mae_mport_by_pcie_mh_function(
781 __in efx_pcie_interface_t intf,
782 __in uint32_t pf,
783 __in uint32_t vf,
784 __out efx_mport_sel_t *mportp)
785 {
786 uint32_t selector_intf;
787 efx_dword_t dword;
788 efx_rc_t rc;
789
790 EFX_STATIC_ASSERT(EFX_PCI_VF_INVALID ==
791 MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL);
792
793 rc = efx_mae_intf_to_selector(intf, &selector_intf);
794 if (rc != 0)
795 goto fail1;
796
797 if (pf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_MH_PF_ID)) {
798 rc = EINVAL;
799 goto fail2;
800 }
801
802 if (vf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_VF_ID)) {
803 rc = EINVAL;
804 goto fail3;
805 }
806
807
808 EFX_POPULATE_DWORD_4(dword,
809 MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_MH_FUNC,
810 MAE_MPORT_SELECTOR_FUNC_INTF_ID, selector_intf,
811 MAE_MPORT_SELECTOR_FUNC_MH_PF_ID, pf,
812 MAE_MPORT_SELECTOR_FUNC_VF_ID, vf);
813
814 memset(mportp, 0, sizeof (*mportp));
815 mportp->sel = dword.ed_u32[0];
816
817 return (0);
818
819 fail3:
820 EFSYS_PROBE(fail3);
821 fail2:
822 EFSYS_PROBE(fail2);
823 fail1:
824 EFSYS_PROBE1(fail1, efx_rc_t, rc);
825 return (rc);
826 }
827
828 static __checkReturn efx_rc_t
efx_mcdi_mae_mport_lookup(__in efx_nic_t * enp,__in const efx_mport_sel_t * mport_selectorp,__out efx_mport_id_t * mport_idp)829 efx_mcdi_mae_mport_lookup(
830 __in efx_nic_t *enp,
831 __in const efx_mport_sel_t *mport_selectorp,
832 __out efx_mport_id_t *mport_idp)
833 {
834 efx_mcdi_req_t req;
835 EFX_MCDI_DECLARE_BUF(payload,
836 MC_CMD_MAE_MPORT_LOOKUP_IN_LEN,
837 MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN);
838 efx_rc_t rc;
839
840 req.emr_cmd = MC_CMD_MAE_MPORT_LOOKUP;
841 req.emr_in_buf = payload;
842 req.emr_in_length = MC_CMD_MAE_MPORT_LOOKUP_IN_LEN;
843 req.emr_out_buf = payload;
844 req.emr_out_length = MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN;
845
846 MCDI_IN_SET_DWORD(req, MAE_MPORT_LOOKUP_IN_MPORT_SELECTOR,
847 mport_selectorp->sel);
848
849 efx_mcdi_execute(enp, &req);
850
851 if (req.emr_rc != 0) {
852 rc = req.emr_rc;
853 goto fail1;
854 }
855
856 mport_idp->id = MCDI_OUT_DWORD(req, MAE_MPORT_LOOKUP_OUT_MPORT_ID);
857
858 return (0);
859
860 fail1:
861 EFSYS_PROBE1(fail1, efx_rc_t, rc);
862 return (rc);
863 }
864
865 __checkReturn efx_rc_t
efx_mae_mport_id_by_selector(__in efx_nic_t * enp,__in const efx_mport_sel_t * mport_selectorp,__out efx_mport_id_t * mport_idp)866 efx_mae_mport_id_by_selector(
867 __in efx_nic_t *enp,
868 __in const efx_mport_sel_t *mport_selectorp,
869 __out efx_mport_id_t *mport_idp)
870 {
871 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
872 efx_rc_t rc;
873
874 if (encp->enc_mae_supported == B_FALSE) {
875 rc = ENOTSUP;
876 goto fail1;
877 }
878
879 rc = efx_mcdi_mae_mport_lookup(enp, mport_selectorp, mport_idp);
880 if (rc != 0)
881 goto fail2;
882
883 return (0);
884
885 fail2:
886 EFSYS_PROBE(fail2);
887 fail1:
888 EFSYS_PROBE1(fail1, efx_rc_t, rc);
889 return (rc);
890 }
891
892 __checkReturn efx_rc_t
efx_mae_match_spec_recirc_id_set(__in efx_mae_match_spec_t * spec,__in uint8_t recirc_id)893 efx_mae_match_spec_recirc_id_set(
894 __in efx_mae_match_spec_t *spec,
895 __in uint8_t recirc_id)
896 {
897 uint8_t full_mask = UINT8_MAX;
898 const uint8_t *vp;
899 const uint8_t *mp;
900 efx_rc_t rc;
901
902 vp = (const uint8_t *)&recirc_id;
903 mp = (const uint8_t *)&full_mask;
904
905 rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_RECIRC_ID,
906 sizeof (recirc_id), vp,
907 sizeof (full_mask), mp);
908 if (rc != 0)
909 goto fail1;
910
911 return (0);
912
913 fail1:
914 EFSYS_PROBE1(fail1, efx_rc_t, rc);
915 return (rc);
916 }
917
918 __checkReturn efx_rc_t
efx_mae_mport_by_id(__in const efx_mport_id_t * mport_idp,__out efx_mport_sel_t * mportp)919 efx_mae_mport_by_id(
920 __in const efx_mport_id_t *mport_idp,
921 __out efx_mport_sel_t *mportp)
922 {
923 efx_dword_t dword;
924
925 EFX_POPULATE_DWORD_2(dword,
926 MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_MPORT_ID,
927 MAE_MPORT_SELECTOR_MPORT_ID, mport_idp->id);
928
929 memset(mportp, 0, sizeof (*mportp));
930 mportp->sel = __LE_TO_CPU_32(dword.ed_u32[0]);
931
932 return (0);
933 }
934
935 __checkReturn efx_rc_t
efx_mae_match_spec_field_set(__in efx_mae_match_spec_t * spec,__in efx_mae_field_id_t field_id,__in size_t value_size,__in_bcount (value_size)const uint8_t * value,__in size_t mask_size,__in_bcount (mask_size)const uint8_t * mask)936 efx_mae_match_spec_field_set(
937 __in efx_mae_match_spec_t *spec,
938 __in efx_mae_field_id_t field_id,
939 __in size_t value_size,
940 __in_bcount(value_size) const uint8_t *value,
941 __in size_t mask_size,
942 __in_bcount(mask_size) const uint8_t *mask)
943 {
944 const efx_mae_mv_desc_t *descp;
945 unsigned int desc_set_nentries;
946 uint8_t *mvp;
947 efx_rc_t rc;
948
949 switch (spec->emms_type) {
950 case EFX_MAE_RULE_OUTER:
951 desc_set_nentries =
952 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
953 descp = &__efx_mae_outer_rule_mv_desc_set[field_id];
954 mvp = spec->emms_mask_value_pairs.outer;
955 break;
956 case EFX_MAE_RULE_ACTION:
957 desc_set_nentries =
958 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
959 descp = &__efx_mae_action_rule_mv_desc_set[field_id];
960 mvp = spec->emms_mask_value_pairs.action;
961 break;
962 default:
963 rc = ENOTSUP;
964 goto fail1;
965 }
966
967 if ((unsigned int)field_id >= desc_set_nentries) {
968 rc = EINVAL;
969 goto fail2;
970 }
971
972 if (descp->emmd_mask_size == 0) {
973 /* The ID points to a gap in the array of field descriptors. */
974 rc = EINVAL;
975 goto fail3;
976 }
977
978 if (value_size != descp->emmd_value_size) {
979 rc = EINVAL;
980 goto fail4;
981 }
982
983 if (mask_size != descp->emmd_mask_size) {
984 rc = EINVAL;
985 goto fail5;
986 }
987
988 if (descp->emmd_endianness == EFX_MAE_FIELD_BE) {
989 unsigned int i;
990
991 /*
992 * The mask/value are in network (big endian) order.
993 * The MCDI request field is also big endian.
994 */
995
996 EFSYS_ASSERT3U(value_size, ==, mask_size);
997
998 for (i = 0; i < value_size; ++i) {
999 uint8_t *v_bytep = mvp + descp->emmd_value_offset + i;
1000 uint8_t *m_bytep = mvp + descp->emmd_mask_offset + i;
1001
1002 /*
1003 * Apply the mask (which may be all-zeros) to the value.
1004 *
1005 * If this API is provided with some value to set for a
1006 * given field in one specification and with some other
1007 * value to set for this field in another specification,
1008 * then, if the two masks are all-zeros, the field will
1009 * avoid being counted as a mismatch when comparing the
1010 * specifications using efx_mae_match_specs_equal() API.
1011 */
1012 *v_bytep = value[i] & mask[i];
1013 *m_bytep = mask[i];
1014 }
1015 } else {
1016 efx_dword_t dword;
1017
1018 /*
1019 * The mask/value are in host byte order.
1020 * The MCDI request field is little endian.
1021 */
1022 switch (value_size) {
1023 case 4:
1024 EFX_POPULATE_DWORD_1(dword,
1025 EFX_DWORD_0, *(const uint32_t *)value);
1026
1027 memcpy(mvp + descp->emmd_value_offset,
1028 &dword, sizeof (dword));
1029 break;
1030 case 1:
1031 memcpy(mvp + descp->emmd_value_offset,
1032 value, 1);
1033 break;
1034 default:
1035 EFSYS_ASSERT(B_FALSE);
1036 }
1037
1038 switch (mask_size) {
1039 case 4:
1040 EFX_POPULATE_DWORD_1(dword,
1041 EFX_DWORD_0, *(const uint32_t *)mask);
1042
1043 memcpy(mvp + descp->emmd_mask_offset,
1044 &dword, sizeof (dword));
1045 break;
1046 case 1:
1047 memcpy(mvp + descp->emmd_mask_offset,
1048 mask, 1);
1049 break;
1050 default:
1051 EFSYS_ASSERT(B_FALSE);
1052 }
1053 }
1054
1055 return (0);
1056
1057 fail5:
1058 EFSYS_PROBE(fail5);
1059 fail4:
1060 EFSYS_PROBE(fail4);
1061 fail3:
1062 EFSYS_PROBE(fail3);
1063 fail2:
1064 EFSYS_PROBE(fail2);
1065 fail1:
1066 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1067 return (rc);
1068 }
1069
1070 __checkReturn efx_rc_t
efx_mae_match_spec_bit_set(__in efx_mae_match_spec_t * spec,__in efx_mae_field_id_t field_id,__in boolean_t value)1071 efx_mae_match_spec_bit_set(
1072 __in efx_mae_match_spec_t *spec,
1073 __in efx_mae_field_id_t field_id,
1074 __in boolean_t value)
1075 {
1076 const efx_mae_mv_bit_desc_t *bit_descp;
1077 unsigned int bit_desc_set_nentries;
1078 unsigned int byte_idx;
1079 unsigned int bit_idx;
1080 uint8_t *mvp;
1081 efx_rc_t rc;
1082
1083 switch (spec->emms_type) {
1084 case EFX_MAE_RULE_OUTER:
1085 bit_desc_set_nentries =
1086 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
1087 bit_descp = &__efx_mae_outer_rule_mv_bit_desc_set[field_id];
1088 mvp = spec->emms_mask_value_pairs.outer;
1089 break;
1090 case EFX_MAE_RULE_ACTION:
1091 bit_desc_set_nentries =
1092 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
1093 bit_descp = &__efx_mae_action_rule_mv_bit_desc_set[field_id];
1094 mvp = spec->emms_mask_value_pairs.action;
1095 break;
1096 default:
1097 rc = ENOTSUP;
1098 goto fail1;
1099 }
1100
1101 if ((unsigned int)field_id >= bit_desc_set_nentries) {
1102 rc = EINVAL;
1103 goto fail2;
1104 }
1105
1106 if (bit_descp->emmbd_entry_is_valid == B_FALSE) {
1107 rc = EINVAL;
1108 goto fail3;
1109 }
1110
1111 byte_idx = bit_descp->emmbd_value_ofst + bit_descp->emmbd_value_lbn / 8;
1112 bit_idx = bit_descp->emmbd_value_lbn % 8;
1113
1114 if (value != B_FALSE)
1115 mvp[byte_idx] |= (1U << bit_idx);
1116 else
1117 mvp[byte_idx] &= ~(1U << bit_idx);
1118
1119 byte_idx = bit_descp->emmbd_mask_ofst + bit_descp->emmbd_mask_lbn / 8;
1120 bit_idx = bit_descp->emmbd_mask_lbn % 8;
1121 mvp[byte_idx] |= (1U << bit_idx);
1122
1123 return (0);
1124
1125 fail3:
1126 EFSYS_PROBE(fail3);
1127 fail2:
1128 EFSYS_PROBE(fail2);
1129 fail1:
1130 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1131 return (rc);
1132 }
1133
1134 __checkReturn efx_rc_t
efx_mae_match_spec_mport_set(__in efx_mae_match_spec_t * spec,__in const efx_mport_sel_t * valuep,__in_opt const efx_mport_sel_t * maskp)1135 efx_mae_match_spec_mport_set(
1136 __in efx_mae_match_spec_t *spec,
1137 __in const efx_mport_sel_t *valuep,
1138 __in_opt const efx_mport_sel_t *maskp)
1139 {
1140 uint32_t full_mask = UINT32_MAX;
1141 const uint8_t *vp;
1142 const uint8_t *mp;
1143 efx_rc_t rc;
1144
1145 if (valuep == NULL) {
1146 rc = EINVAL;
1147 goto fail1;
1148 }
1149
1150 vp = (const uint8_t *)&valuep->sel;
1151 if (maskp != NULL)
1152 mp = (const uint8_t *)&maskp->sel;
1153 else
1154 mp = (const uint8_t *)&full_mask;
1155
1156 rc = efx_mae_match_spec_field_set(spec,
1157 EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR,
1158 sizeof (valuep->sel), vp, sizeof (maskp->sel), mp);
1159 if (rc != 0)
1160 goto fail2;
1161
1162 return (0);
1163
1164 fail2:
1165 EFSYS_PROBE(fail2);
1166 fail1:
1167 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1168 return (rc);
1169 }
1170
1171 __checkReturn boolean_t
efx_mae_match_specs_equal(__in const efx_mae_match_spec_t * left,__in const efx_mae_match_spec_t * right)1172 efx_mae_match_specs_equal(
1173 __in const efx_mae_match_spec_t *left,
1174 __in const efx_mae_match_spec_t *right)
1175 {
1176 return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
1177 }
1178
1179 #define EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit) \
1180 ((_mask)[(_bit) / (_mask_page_nbits)] & \
1181 (1ULL << ((_bit) & ((_mask_page_nbits) - 1))))
1182
1183 static boolean_t
efx_mask_is_prefix(__in size_t mask_nbytes,__in_bcount (mask_nbytes)const uint8_t * maskp)1184 efx_mask_is_prefix(
1185 __in size_t mask_nbytes,
1186 __in_bcount(mask_nbytes) const uint8_t *maskp)
1187 {
1188 boolean_t prev_bit_is_set = B_TRUE;
1189 unsigned int i;
1190
1191 for (i = 0; i < 8 * mask_nbytes; ++i) {
1192 boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i);
1193
1194 if (!prev_bit_is_set && bit_is_set)
1195 return B_FALSE;
1196
1197 prev_bit_is_set = bit_is_set;
1198 }
1199
1200 return B_TRUE;
1201 }
1202
1203 static boolean_t
efx_mask_is_all_ones(__in size_t mask_nbytes,__in_bcount (mask_nbytes)const uint8_t * maskp)1204 efx_mask_is_all_ones(
1205 __in size_t mask_nbytes,
1206 __in_bcount(mask_nbytes) const uint8_t *maskp)
1207 {
1208 unsigned int i;
1209 uint8_t t = ~0;
1210
1211 for (i = 0; i < mask_nbytes; ++i)
1212 t &= maskp[i];
1213
1214 return (t == (uint8_t)(~0));
1215 }
1216
1217 static boolean_t
efx_mask_is_all_zeros(__in size_t mask_nbytes,__in_bcount (mask_nbytes)const uint8_t * maskp)1218 efx_mask_is_all_zeros(
1219 __in size_t mask_nbytes,
1220 __in_bcount(mask_nbytes) const uint8_t *maskp)
1221 {
1222 unsigned int i;
1223 uint8_t t = 0;
1224
1225 for (i = 0; i < mask_nbytes; ++i)
1226 t |= maskp[i];
1227
1228 return (t == 0);
1229 }
1230
1231 __checkReturn boolean_t
efx_mae_match_spec_is_valid(__in efx_nic_t * enp,__in const efx_mae_match_spec_t * spec)1232 efx_mae_match_spec_is_valid(
1233 __in efx_nic_t *enp,
1234 __in const efx_mae_match_spec_t *spec)
1235 {
1236 efx_mae_t *maep = enp->en_maep;
1237 unsigned int field_ncaps = maep->em_max_nfields;
1238 const efx_mae_field_cap_t *field_caps;
1239 const efx_mae_mv_desc_t *desc_setp;
1240 unsigned int desc_set_nentries;
1241 const efx_mae_mv_bit_desc_t *bit_desc_setp;
1242 unsigned int bit_desc_set_nentries;
1243 boolean_t is_valid = B_TRUE;
1244 efx_mae_field_id_t field_id;
1245 const uint8_t *mvp;
1246
1247 switch (spec->emms_type) {
1248 case EFX_MAE_RULE_OUTER:
1249 field_caps = maep->em_outer_rule_field_caps;
1250 desc_setp = __efx_mae_outer_rule_mv_desc_set;
1251 desc_set_nentries =
1252 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1253 bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
1254 bit_desc_set_nentries =
1255 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
1256 mvp = spec->emms_mask_value_pairs.outer;
1257 break;
1258 case EFX_MAE_RULE_ACTION:
1259 field_caps = maep->em_action_rule_field_caps;
1260 desc_setp = __efx_mae_action_rule_mv_desc_set;
1261 desc_set_nentries =
1262 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1263 bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
1264 bit_desc_set_nentries =
1265 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
1266 mvp = spec->emms_mask_value_pairs.action;
1267 break;
1268 default:
1269 return (B_FALSE);
1270 }
1271
1272 if (field_caps == NULL)
1273 return (B_FALSE);
1274
1275 for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1276 ++field_id) {
1277 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1278 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1279 const uint8_t *alt_m_buf = mvp + descp->emmd_alt_mask_offset;
1280 const uint8_t *m_buf = mvp + descp->emmd_mask_offset;
1281 size_t alt_m_size = descp->emmd_alt_mask_size;
1282 size_t m_size = descp->emmd_mask_size;
1283
1284 if (m_size == 0)
1285 continue; /* Skip array gap */
1286
1287 if ((unsigned int)field_cap_id >= field_ncaps) {
1288 /*
1289 * The FW has not reported capability status for
1290 * this field. Make sure that its mask is zeroed.
1291 */
1292 is_valid = efx_mask_is_all_zeros(m_size, m_buf);
1293 if (is_valid != B_FALSE)
1294 continue;
1295 else
1296 break;
1297 }
1298
1299 switch (field_caps[field_cap_id].emfc_support) {
1300 case MAE_FIELD_SUPPORTED_MATCH_MASK:
1301 is_valid = B_TRUE;
1302 break;
1303 case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
1304 is_valid = efx_mask_is_prefix(m_size, m_buf);
1305 break;
1306 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
1307 is_valid = (efx_mask_is_all_ones(m_size, m_buf) ||
1308 efx_mask_is_all_zeros(m_size, m_buf));
1309 break;
1310 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
1311 is_valid = efx_mask_is_all_ones(m_size, m_buf);
1312
1313 if ((is_valid == B_FALSE) && (alt_m_size != 0)) {
1314 /*
1315 * This field has an alternative one. The FW
1316 * reports ALWAYS for both implying that one
1317 * of them is required to have all-ones mask.
1318 *
1319 * The primary field's mask is incorrect; go
1320 * on to check that of the alternative field.
1321 */
1322 is_valid = efx_mask_is_all_ones(alt_m_size,
1323 alt_m_buf);
1324 }
1325 break;
1326 case MAE_FIELD_SUPPORTED_MATCH_NEVER:
1327 case MAE_FIELD_UNSUPPORTED:
1328 default:
1329 is_valid = efx_mask_is_all_zeros(m_size, m_buf);
1330 break;
1331 }
1332
1333 if (is_valid == B_FALSE)
1334 return (B_FALSE);
1335 }
1336
1337 for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
1338 ++field_id) {
1339 const efx_mae_mv_bit_desc_t *bit_descp =
1340 &bit_desc_setp[field_id];
1341 unsigned int byte_idx =
1342 bit_descp->emmbd_mask_ofst +
1343 bit_descp->emmbd_mask_lbn / 8;
1344 unsigned int bit_idx =
1345 bit_descp->emmbd_mask_lbn % 8;
1346 efx_mae_field_cap_id_t bit_cap_id =
1347 bit_descp->emmbd_bit_cap_id;
1348
1349 if (bit_descp->emmbd_entry_is_valid == B_FALSE)
1350 continue; /* Skip array gap */
1351
1352 if ((unsigned int)bit_cap_id >= field_ncaps) {
1353 /* No capability for this bit = unsupported. */
1354 is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0);
1355 if (is_valid == B_FALSE)
1356 break;
1357 else
1358 continue;
1359 }
1360
1361 switch (field_caps[bit_cap_id].emfc_support) {
1362 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
1363 is_valid = B_TRUE;
1364 break;
1365 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
1366 is_valid = ((mvp[byte_idx] & (1U << bit_idx)) != 0);
1367 break;
1368 case MAE_FIELD_SUPPORTED_MATCH_NEVER:
1369 case MAE_FIELD_UNSUPPORTED:
1370 default:
1371 is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0);
1372 break;
1373 }
1374
1375 if (is_valid == B_FALSE)
1376 break;
1377 }
1378
1379 return (is_valid);
1380 }
1381
1382 __checkReturn efx_rc_t
efx_mae_action_set_spec_init(__in efx_nic_t * enp,__out efx_mae_actions_t ** specp)1383 efx_mae_action_set_spec_init(
1384 __in efx_nic_t *enp,
1385 __out efx_mae_actions_t **specp)
1386 {
1387 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1388 efx_mae_actions_t *spec;
1389 efx_rc_t rc;
1390
1391 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
1392 if (spec == NULL) {
1393 rc = ENOMEM;
1394 goto fail1;
1395 }
1396
1397 spec->ema_rsrc.emar_dst_mac_id.id = EFX_MAE_RSRC_ID_INVALID;
1398 spec->ema_rsrc.emar_src_mac_id.id = EFX_MAE_RSRC_ID_INVALID;
1399 spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
1400 spec->ema_rsrc.emar_counter_id.id = EFX_MAE_RSRC_ID_INVALID;
1401
1402 /*
1403 * Helpers which populate v2 actions must reject them when v2 is not
1404 * supported. As they have no EFX NIC argument, save v2 status here.
1405 */
1406 spec->ema_v2_is_supported = encp->enc_mae_aset_v2_supported;
1407
1408 *specp = spec;
1409
1410 return (0);
1411
1412 fail1:
1413 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1414 return (rc);
1415 }
1416
1417 void
efx_mae_action_set_spec_fini(__in efx_nic_t * enp,__in efx_mae_actions_t * spec)1418 efx_mae_action_set_spec_fini(
1419 __in efx_nic_t *enp,
1420 __in efx_mae_actions_t *spec)
1421 {
1422 EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
1423 }
1424
1425 static __checkReturn efx_rc_t
efx_mae_action_set_no_op(__in efx_mae_actions_t * spec,__in size_t arg_size,__in_bcount (arg_size)const uint8_t * arg)1426 efx_mae_action_set_no_op(
1427 __in efx_mae_actions_t *spec,
1428 __in size_t arg_size,
1429 __in_bcount(arg_size) const uint8_t *arg)
1430 {
1431 efx_rc_t rc;
1432
1433 _NOTE(ARGUNUSED(spec))
1434
1435 if (arg_size != 0) {
1436 rc = EINVAL;
1437 goto fail1;
1438 }
1439
1440 if (arg != NULL) {
1441 rc = EINVAL;
1442 goto fail2;
1443 }
1444
1445 /* This action does not have any arguments, so do nothing here. */
1446
1447 return (0);
1448
1449 fail2:
1450 EFSYS_PROBE(fail2);
1451 fail1:
1452 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1453 return (rc);
1454 }
1455
1456 static __checkReturn efx_rc_t
efx_mae_action_set_add_vlan_pop(__in efx_mae_actions_t * spec,__in size_t arg_size,__in_bcount (arg_size)const uint8_t * arg)1457 efx_mae_action_set_add_vlan_pop(
1458 __in efx_mae_actions_t *spec,
1459 __in size_t arg_size,
1460 __in_bcount(arg_size) const uint8_t *arg)
1461 {
1462 efx_rc_t rc;
1463
1464 if (arg_size != 0) {
1465 rc = EINVAL;
1466 goto fail1;
1467 }
1468
1469 if (arg != NULL) {
1470 rc = EINVAL;
1471 goto fail2;
1472 }
1473
1474 if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) {
1475 rc = ENOTSUP;
1476 goto fail3;
1477 }
1478
1479 ++spec->ema_n_vlan_tags_to_pop;
1480
1481 return (0);
1482
1483 fail3:
1484 EFSYS_PROBE(fail3);
1485 fail2:
1486 EFSYS_PROBE(fail2);
1487 fail1:
1488 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1489 return (rc);
1490 }
1491
1492 static __checkReturn efx_rc_t
efx_mae_action_set_add_vlan_push(__in efx_mae_actions_t * spec,__in size_t arg_size,__in_bcount (arg_size)const uint8_t * arg)1493 efx_mae_action_set_add_vlan_push(
1494 __in efx_mae_actions_t *spec,
1495 __in size_t arg_size,
1496 __in_bcount(arg_size) const uint8_t *arg)
1497 {
1498 unsigned int n_tags = spec->ema_n_vlan_tags_to_push;
1499 efx_rc_t rc;
1500
1501 if (arg_size != sizeof (*spec->ema_vlan_push_descs)) {
1502 rc = EINVAL;
1503 goto fail1;
1504 }
1505
1506 if (arg == NULL) {
1507 rc = EINVAL;
1508 goto fail2;
1509 }
1510
1511 if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1512 rc = ENOTSUP;
1513 goto fail3;
1514 }
1515
1516 memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size);
1517 ++(spec->ema_n_vlan_tags_to_push);
1518
1519 return (0);
1520
1521 fail3:
1522 EFSYS_PROBE(fail3);
1523 fail2:
1524 EFSYS_PROBE(fail2);
1525 fail1:
1526 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1527 return (rc);
1528 }
1529
1530 static __checkReturn efx_rc_t
efx_mae_action_set_add_count(__in efx_mae_actions_t * spec,__in size_t arg_size,__in_bcount (arg_size)const uint8_t * arg)1531 efx_mae_action_set_add_count(
1532 __in efx_mae_actions_t *spec,
1533 __in size_t arg_size,
1534 __in_bcount(arg_size) const uint8_t *arg)
1535 {
1536 efx_rc_t rc;
1537
1538 EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1539 MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL);
1540
1541 /*
1542 * Preparing an action set spec to update a counter requires
1543 * two steps: first add this action to the action spec, and then
1544 * add the counter ID to the spec. This allows validity checking
1545 * and resource allocation to be done separately.
1546 *
1547 * In order to fill in the counter ID, the caller is supposed to invoke
1548 * efx_mae_action_set_fill_in_counter_id(). If they do not do that,
1549 * efx_mae_action_set_alloc() invocation will throw an error.
1550 *
1551 * For now, no arguments are supposed to be handled.
1552 */
1553
1554 if (arg_size != 0) {
1555 rc = EINVAL;
1556 goto fail1;
1557 }
1558
1559 if (arg != NULL) {
1560 rc = EINVAL;
1561 goto fail2;
1562 }
1563
1564 ++(spec->ema_n_count_actions);
1565
1566 return (0);
1567
1568 fail2:
1569 EFSYS_PROBE(fail2);
1570 fail1:
1571 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1572 return (rc);
1573 }
1574
1575 static __checkReturn efx_rc_t
efx_mae_action_set_add_mark(__in efx_mae_actions_t * spec,__in size_t arg_size,__in_bcount (arg_size)const uint8_t * arg)1576 efx_mae_action_set_add_mark(
1577 __in efx_mae_actions_t *spec,
1578 __in size_t arg_size,
1579 __in_bcount(arg_size) const uint8_t *arg)
1580 {
1581 efx_rc_t rc;
1582
1583 if (arg_size != sizeof (spec->ema_mark_value)) {
1584 rc = EINVAL;
1585 goto fail1;
1586 }
1587
1588 if (arg == NULL) {
1589 rc = EINVAL;
1590 goto fail2;
1591 }
1592
1593 memcpy(&spec->ema_mark_value, arg, arg_size);
1594
1595 return (0);
1596
1597 fail2:
1598 EFSYS_PROBE(fail2);
1599 fail1:
1600 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1601 return (rc);
1602 }
1603
1604 static __checkReturn efx_rc_t
efx_mae_action_set_add_deliver(__in efx_mae_actions_t * spec,__in size_t arg_size,__in_bcount (arg_size)const uint8_t * arg)1605 efx_mae_action_set_add_deliver(
1606 __in efx_mae_actions_t *spec,
1607 __in size_t arg_size,
1608 __in_bcount(arg_size) const uint8_t *arg)
1609 {
1610 efx_rc_t rc;
1611
1612 if (arg_size != sizeof (spec->ema_deliver_mport)) {
1613 rc = EINVAL;
1614 goto fail1;
1615 }
1616
1617 if (arg == NULL) {
1618 rc = EINVAL;
1619 goto fail2;
1620 }
1621
1622 memcpy(&spec->ema_deliver_mport, arg, arg_size);
1623
1624 return (0);
1625
1626 fail2:
1627 EFSYS_PROBE(fail2);
1628 fail1:
1629 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1630 return (rc);
1631 }
1632
1633 typedef struct efx_mae_action_desc_s {
1634 /* Action specific handler */
1635 efx_rc_t (*emad_add)(efx_mae_actions_t *,
1636 size_t, const uint8_t *);
1637 } efx_mae_action_desc_t;
1638
1639 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
1640 [EFX_MAE_ACTION_DECAP] = {
1641 .emad_add = efx_mae_action_set_no_op
1642 },
1643 [EFX_MAE_ACTION_VLAN_POP] = {
1644 .emad_add = efx_mae_action_set_add_vlan_pop
1645 },
1646 [EFX_MAE_ACTION_SET_DST_MAC] = {
1647 .emad_add = efx_mae_action_set_no_op
1648 },
1649 [EFX_MAE_ACTION_SET_SRC_MAC] = {
1650 .emad_add = efx_mae_action_set_no_op
1651 },
1652 [EFX_MAE_ACTION_DECR_IP_TTL] = {
1653 .emad_add = efx_mae_action_set_no_op
1654 },
1655 [EFX_MAE_ACTION_VLAN_PUSH] = {
1656 .emad_add = efx_mae_action_set_add_vlan_push
1657 },
1658 [EFX_MAE_ACTION_ENCAP] = {
1659 .emad_add = efx_mae_action_set_no_op
1660 },
1661 [EFX_MAE_ACTION_COUNT] = {
1662 .emad_add = efx_mae_action_set_add_count
1663 },
1664 [EFX_MAE_ACTION_FLAG] = {
1665 .emad_add = efx_mae_action_set_no_op
1666 },
1667 [EFX_MAE_ACTION_MARK] = {
1668 .emad_add = efx_mae_action_set_add_mark
1669 },
1670 [EFX_MAE_ACTION_DELIVER] = {
1671 .emad_add = efx_mae_action_set_add_deliver
1672 }
1673 };
1674
1675 static const uint32_t efx_mae_action_ordered_map =
1676 (1U << EFX_MAE_ACTION_DECAP) |
1677 (1U << EFX_MAE_ACTION_VLAN_POP) |
1678 (1U << EFX_MAE_ACTION_SET_DST_MAC) |
1679 (1U << EFX_MAE_ACTION_SET_SRC_MAC) |
1680 (1U << EFX_MAE_ACTION_DECR_IP_TTL) |
1681 (1U << EFX_MAE_ACTION_VLAN_PUSH) |
1682 /*
1683 * HW will conduct action COUNT after
1684 * the matching packet has been modified by
1685 * length-affecting actions except for ENCAP.
1686 */
1687 (1U << EFX_MAE_ACTION_COUNT) |
1688 (1U << EFX_MAE_ACTION_ENCAP) |
1689 (1U << EFX_MAE_ACTION_FLAG) |
1690 (1U << EFX_MAE_ACTION_MARK) |
1691 (1U << EFX_MAE_ACTION_DELIVER);
1692
1693 /*
1694 * These actions must not be added after DELIVER, but
1695 * they can have any place among the rest of
1696 * strictly ordered actions.
1697 */
1698 static const uint32_t efx_mae_action_nonstrict_map =
1699 (1U << EFX_MAE_ACTION_COUNT) |
1700 (1U << EFX_MAE_ACTION_FLAG) |
1701 (1U << EFX_MAE_ACTION_MARK);
1702
1703 static const uint32_t efx_mae_action_repeat_map =
1704 (1U << EFX_MAE_ACTION_VLAN_POP) |
1705 (1U << EFX_MAE_ACTION_VLAN_PUSH) |
1706 (1U << EFX_MAE_ACTION_COUNT);
1707
1708 /*
1709 * Add an action to an action set.
1710 *
1711 * This has to be invoked in the desired action order.
1712 * An out-of-order action request will be turned down.
1713 */
1714 static __checkReturn efx_rc_t
efx_mae_action_set_spec_populate(__in efx_mae_actions_t * spec,__in efx_mae_action_t type,__in size_t arg_size,__in_bcount (arg_size)const uint8_t * arg)1715 efx_mae_action_set_spec_populate(
1716 __in efx_mae_actions_t *spec,
1717 __in efx_mae_action_t type,
1718 __in size_t arg_size,
1719 __in_bcount(arg_size) const uint8_t *arg)
1720 {
1721 uint32_t action_mask;
1722 efx_rc_t rc;
1723
1724 EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1725 (sizeof (efx_mae_action_ordered_map) * 8));
1726 EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1727 (sizeof (efx_mae_action_repeat_map) * 8));
1728
1729 EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
1730 EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK);
1731 EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER);
1732
1733 if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
1734 rc = EINVAL;
1735 goto fail1;
1736 }
1737
1738 action_mask = (1U << type);
1739
1740 if ((spec->ema_actions & action_mask) != 0) {
1741 /* The action set already contains this action. */
1742 if ((efx_mae_action_repeat_map & action_mask) == 0) {
1743 /* Cannot add another non-repeatable action. */
1744 rc = ENOTSUP;
1745 goto fail2;
1746 }
1747 }
1748
1749 if ((efx_mae_action_ordered_map & action_mask) != 0) {
1750 uint32_t strict_ordered_map =
1751 efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map;
1752 uint32_t later_actions_mask =
1753 strict_ordered_map & ~(action_mask | (action_mask - 1));
1754
1755 if ((spec->ema_actions & later_actions_mask) != 0) {
1756 /* Cannot add an action after later ordered actions. */
1757 rc = ENOTSUP;
1758 goto fail3;
1759 }
1760 }
1761
1762 if (efx_mae_actions[type].emad_add != NULL) {
1763 rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
1764 if (rc != 0)
1765 goto fail4;
1766 }
1767
1768 spec->ema_actions |= action_mask;
1769
1770 return (0);
1771
1772 fail4:
1773 EFSYS_PROBE(fail4);
1774 fail3:
1775 EFSYS_PROBE(fail3);
1776 fail2:
1777 EFSYS_PROBE(fail2);
1778 fail1:
1779 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1780 return (rc);
1781 }
1782
1783 __checkReturn efx_rc_t
efx_mae_action_set_populate_decap(__in efx_mae_actions_t * spec)1784 efx_mae_action_set_populate_decap(
1785 __in efx_mae_actions_t *spec)
1786 {
1787 return (efx_mae_action_set_spec_populate(spec,
1788 EFX_MAE_ACTION_DECAP, 0, NULL));
1789 }
1790
1791 __checkReturn efx_rc_t
efx_mae_action_set_populate_vlan_pop(__in efx_mae_actions_t * spec)1792 efx_mae_action_set_populate_vlan_pop(
1793 __in efx_mae_actions_t *spec)
1794 {
1795 return (efx_mae_action_set_spec_populate(spec,
1796 EFX_MAE_ACTION_VLAN_POP, 0, NULL));
1797 }
1798
1799 __checkReturn efx_rc_t
efx_mae_action_set_populate_set_dst_mac(__in efx_mae_actions_t * spec)1800 efx_mae_action_set_populate_set_dst_mac(
1801 __in efx_mae_actions_t *spec)
1802 {
1803 efx_rc_t rc;
1804
1805 if (spec->ema_v2_is_supported == B_FALSE) {
1806 rc = ENOTSUP;
1807 goto fail1;
1808 }
1809
1810 return (efx_mae_action_set_spec_populate(spec,
1811 EFX_MAE_ACTION_SET_DST_MAC, 0, NULL));
1812
1813 fail1:
1814 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1815 return (rc);
1816 }
1817
1818 __checkReturn efx_rc_t
efx_mae_action_set_populate_set_src_mac(__in efx_mae_actions_t * spec)1819 efx_mae_action_set_populate_set_src_mac(
1820 __in efx_mae_actions_t *spec)
1821 {
1822 efx_rc_t rc;
1823
1824 if (spec->ema_v2_is_supported == B_FALSE) {
1825 rc = ENOTSUP;
1826 goto fail1;
1827 }
1828
1829 return (efx_mae_action_set_spec_populate(spec,
1830 EFX_MAE_ACTION_SET_SRC_MAC, 0, NULL));
1831
1832 fail1:
1833 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1834 return (rc);
1835 }
1836
1837 __checkReturn efx_rc_t
efx_mae_action_set_populate_decr_ip_ttl(__in efx_mae_actions_t * spec)1838 efx_mae_action_set_populate_decr_ip_ttl(
1839 __in efx_mae_actions_t *spec)
1840 {
1841 efx_rc_t rc;
1842
1843 if (spec->ema_v2_is_supported == B_FALSE) {
1844 rc = ENOTSUP;
1845 goto fail1;
1846 }
1847
1848 return (efx_mae_action_set_spec_populate(spec,
1849 EFX_MAE_ACTION_DECR_IP_TTL, 0, NULL));
1850
1851 fail1:
1852 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1853 return (rc);
1854 }
1855
1856 __checkReturn efx_rc_t
efx_mae_action_set_populate_vlan_push(__in efx_mae_actions_t * spec,__in uint16_t tpid_be,__in uint16_t tci_be)1857 efx_mae_action_set_populate_vlan_push(
1858 __in efx_mae_actions_t *spec,
1859 __in uint16_t tpid_be,
1860 __in uint16_t tci_be)
1861 {
1862 efx_mae_action_vlan_push_t action;
1863 const uint8_t *arg = (const uint8_t *)&action;
1864
1865 action.emavp_tpid_be = tpid_be;
1866 action.emavp_tci_be = tci_be;
1867
1868 return (efx_mae_action_set_spec_populate(spec,
1869 EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg));
1870 }
1871
1872 __checkReturn efx_rc_t
efx_mae_action_set_populate_encap(__in efx_mae_actions_t * spec)1873 efx_mae_action_set_populate_encap(
1874 __in efx_mae_actions_t *spec)
1875 {
1876 /*
1877 * There is no argument to pass encap. header ID, thus, one does not
1878 * need to allocate an encap. header while parsing application input.
1879 * This is useful since building an action set may be done simply to
1880 * validate a rule, whilst resource allocation usually consumes time.
1881 */
1882 return (efx_mae_action_set_spec_populate(spec,
1883 EFX_MAE_ACTION_ENCAP, 0, NULL));
1884 }
1885
1886 __checkReturn efx_rc_t
efx_mae_action_set_populate_count(__in efx_mae_actions_t * spec)1887 efx_mae_action_set_populate_count(
1888 __in efx_mae_actions_t *spec)
1889 {
1890 /*
1891 * There is no argument to pass counter ID, thus, one does not
1892 * need to allocate a counter while parsing application input.
1893 * This is useful since building an action set may be done simply to
1894 * validate a rule, whilst resource allocation usually consumes time.
1895 */
1896 return (efx_mae_action_set_spec_populate(spec,
1897 EFX_MAE_ACTION_COUNT, 0, NULL));
1898 }
1899
1900 __checkReturn efx_rc_t
efx_mae_action_set_populate_flag(__in efx_mae_actions_t * spec)1901 efx_mae_action_set_populate_flag(
1902 __in efx_mae_actions_t *spec)
1903 {
1904 return (efx_mae_action_set_spec_populate(spec,
1905 EFX_MAE_ACTION_FLAG, 0, NULL));
1906 }
1907
1908 __checkReturn efx_rc_t
efx_mae_action_set_populate_mark(__in efx_mae_actions_t * spec,__in uint32_t mark_value)1909 efx_mae_action_set_populate_mark(
1910 __in efx_mae_actions_t *spec,
1911 __in uint32_t mark_value)
1912 {
1913 const uint8_t *arg = (const uint8_t *)&mark_value;
1914
1915 return (efx_mae_action_set_spec_populate(spec,
1916 EFX_MAE_ACTION_MARK, sizeof (mark_value), arg));
1917 }
1918
1919 __checkReturn efx_rc_t
efx_mae_action_set_populate_deliver(__in efx_mae_actions_t * spec,__in const efx_mport_sel_t * mportp)1920 efx_mae_action_set_populate_deliver(
1921 __in efx_mae_actions_t *spec,
1922 __in const efx_mport_sel_t *mportp)
1923 {
1924 const uint8_t *arg;
1925 efx_rc_t rc;
1926
1927 if (mportp == NULL) {
1928 rc = EINVAL;
1929 goto fail1;
1930 }
1931
1932 arg = (const uint8_t *)&mportp->sel;
1933
1934 return (efx_mae_action_set_spec_populate(spec,
1935 EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
1936
1937 fail1:
1938 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1939 return (rc);
1940 }
1941
1942 __checkReturn efx_rc_t
efx_mae_action_set_populate_drop(__in efx_mae_actions_t * spec)1943 efx_mae_action_set_populate_drop(
1944 __in efx_mae_actions_t *spec)
1945 {
1946 efx_mport_sel_t mport;
1947 const uint8_t *arg;
1948 efx_dword_t dword;
1949
1950 EFX_POPULATE_DWORD_1(dword,
1951 MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL);
1952
1953 /*
1954 * The constructed DWORD is little-endian,
1955 * but the resulting value is meant to be
1956 * passed to MCDIs, where it will undergo
1957 * host-order to little endian conversion.
1958 */
1959 mport.sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
1960
1961 arg = (const uint8_t *)&mport.sel;
1962
1963 return (efx_mae_action_set_spec_populate(spec,
1964 EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg));
1965 }
1966
1967 __checkReturn boolean_t
efx_mae_action_set_specs_equal(__in const efx_mae_actions_t * left,__in const efx_mae_actions_t * right)1968 efx_mae_action_set_specs_equal(
1969 __in const efx_mae_actions_t *left,
1970 __in const efx_mae_actions_t *right)
1971 {
1972 size_t cmp_size = EFX_FIELD_OFFSET(efx_mae_actions_t, ema_rsrc);
1973
1974 /*
1975 * An action set specification consists of two parts. The first part
1976 * indicates what actions are included in the action set, as well as
1977 * extra quantitative values (in example, the number of VLAN tags to
1978 * push). The second part comprises resource IDs used by the actions.
1979 *
1980 * A resource, in example, a counter, is allocated from the hardware
1981 * by the client, and it's the client who is responsible for keeping
1982 * track of allocated resources and comparing resource IDs if needed.
1983 *
1984 * In this API, don't compare resource IDs in the two specifications.
1985 */
1986
1987 return ((memcmp(left, right, cmp_size) == 0) ? B_TRUE : B_FALSE);
1988 }
1989
1990 __checkReturn efx_rc_t
efx_mae_match_specs_class_cmp(__in efx_nic_t * enp,__in const efx_mae_match_spec_t * left,__in const efx_mae_match_spec_t * right,__out boolean_t * have_same_classp)1991 efx_mae_match_specs_class_cmp(
1992 __in efx_nic_t *enp,
1993 __in const efx_mae_match_spec_t *left,
1994 __in const efx_mae_match_spec_t *right,
1995 __out boolean_t *have_same_classp)
1996 {
1997 efx_mae_t *maep = enp->en_maep;
1998 unsigned int field_ncaps = maep->em_max_nfields;
1999 const efx_mae_field_cap_t *field_caps;
2000 const efx_mae_mv_desc_t *desc_setp;
2001 unsigned int desc_set_nentries;
2002 const efx_mae_mv_bit_desc_t *bit_desc_setp;
2003 unsigned int bit_desc_set_nentries;
2004 boolean_t have_same_class = B_TRUE;
2005 efx_mae_field_id_t field_id;
2006 const uint8_t *mvpl;
2007 const uint8_t *mvpr;
2008 efx_rc_t rc;
2009
2010 switch (left->emms_type) {
2011 case EFX_MAE_RULE_OUTER:
2012 field_caps = maep->em_outer_rule_field_caps;
2013 desc_setp = __efx_mae_outer_rule_mv_desc_set;
2014 desc_set_nentries =
2015 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
2016 bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
2017 bit_desc_set_nentries =
2018 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
2019 mvpl = left->emms_mask_value_pairs.outer;
2020 mvpr = right->emms_mask_value_pairs.outer;
2021 break;
2022 case EFX_MAE_RULE_ACTION:
2023 field_caps = maep->em_action_rule_field_caps;
2024 desc_setp = __efx_mae_action_rule_mv_desc_set;
2025 desc_set_nentries =
2026 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
2027 bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
2028 bit_desc_set_nentries =
2029 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
2030 mvpl = left->emms_mask_value_pairs.action;
2031 mvpr = right->emms_mask_value_pairs.action;
2032 break;
2033 default:
2034 rc = ENOTSUP;
2035 goto fail1;
2036 }
2037
2038 if (field_caps == NULL) {
2039 rc = EAGAIN;
2040 goto fail2;
2041 }
2042
2043 if (left->emms_type != right->emms_type ||
2044 left->emms_prio != right->emms_prio) {
2045 /*
2046 * Rules of different types can never map to the same class.
2047 *
2048 * The FW can support some set of match criteria for one
2049 * priority and not support the very same set for
2050 * another priority. Thus, two rules which have
2051 * different priorities can never map to
2052 * the same class.
2053 */
2054 *have_same_classp = B_FALSE;
2055 return (0);
2056 }
2057
2058 for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
2059 ++field_id) {
2060 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
2061 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
2062 const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
2063 const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
2064 size_t mask_size = descp->emmd_mask_size;
2065 const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
2066 const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
2067 size_t value_size = descp->emmd_value_size;
2068
2069 if (mask_size == 0)
2070 continue; /* Skip array gap */
2071
2072 if ((unsigned int)field_cap_id >= field_ncaps) {
2073 /*
2074 * The FW has not reported capability status for this
2075 * field. It's unknown whether any difference between
2076 * the two masks / values affects the class. The only
2077 * case when the class must be the same is when these
2078 * mask-value pairs match. Otherwise, report mismatch.
2079 */
2080 if ((memcmp(lmaskp, rmaskp, mask_size) == 0) &&
2081 (memcmp(lvalp, rvalp, value_size) == 0))
2082 continue;
2083 else
2084 break;
2085 }
2086
2087 if (field_caps[field_cap_id].emfc_mask_affects_class) {
2088 if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
2089 have_same_class = B_FALSE;
2090 break;
2091 }
2092 }
2093
2094 if (field_caps[field_cap_id].emfc_match_affects_class) {
2095 if (memcmp(lvalp, rvalp, value_size) != 0) {
2096 have_same_class = B_FALSE;
2097 break;
2098 }
2099 }
2100 }
2101
2102 if (have_same_class == B_FALSE)
2103 goto done;
2104
2105 for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
2106 ++field_id) {
2107 const efx_mae_mv_bit_desc_t *bit_descp =
2108 &bit_desc_setp[field_id];
2109 efx_mae_field_cap_id_t bit_cap_id =
2110 bit_descp->emmbd_bit_cap_id;
2111 unsigned int byte_idx;
2112 unsigned int bit_idx;
2113
2114 if (bit_descp->emmbd_entry_is_valid == B_FALSE)
2115 continue; /* Skip array gap */
2116
2117 if ((unsigned int)bit_cap_id >= field_ncaps)
2118 break;
2119
2120 byte_idx =
2121 bit_descp->emmbd_mask_ofst +
2122 bit_descp->emmbd_mask_lbn / 8;
2123 bit_idx =
2124 bit_descp->emmbd_mask_lbn % 8;
2125
2126 if (field_caps[bit_cap_id].emfc_mask_affects_class &&
2127 (mvpl[byte_idx] & (1U << bit_idx)) !=
2128 (mvpr[byte_idx] & (1U << bit_idx))) {
2129 have_same_class = B_FALSE;
2130 break;
2131 }
2132
2133 byte_idx =
2134 bit_descp->emmbd_value_ofst +
2135 bit_descp->emmbd_value_lbn / 8;
2136 bit_idx =
2137 bit_descp->emmbd_value_lbn % 8;
2138
2139 if (field_caps[bit_cap_id].emfc_match_affects_class &&
2140 (mvpl[byte_idx] & (1U << bit_idx)) !=
2141 (mvpr[byte_idx] & (1U << bit_idx))) {
2142 have_same_class = B_FALSE;
2143 break;
2144 }
2145 }
2146
2147 done:
2148 *have_same_classp = have_same_class;
2149
2150 return (0);
2151
2152 fail2:
2153 EFSYS_PROBE(fail2);
2154 fail1:
2155 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2156 return (rc);
2157 }
2158
2159 __checkReturn efx_rc_t
efx_mae_outer_rule_recirc_id_set(__in efx_mae_match_spec_t * spec,__in uint8_t recirc_id)2160 efx_mae_outer_rule_recirc_id_set(
2161 __in efx_mae_match_spec_t *spec,
2162 __in uint8_t recirc_id)
2163 {
2164 efx_rc_t rc;
2165
2166 if (spec->emms_type != EFX_MAE_RULE_OUTER) {
2167 rc = EINVAL;
2168 goto fail1;
2169 }
2170
2171 spec->emms_outer_rule_recirc_id = recirc_id;
2172
2173 return (0);
2174
2175 fail1:
2176 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2177 return (rc);
2178 }
2179
2180 __checkReturn efx_rc_t
efx_mae_outer_rule_insert(__in efx_nic_t * enp,__in const efx_mae_match_spec_t * spec,__in efx_tunnel_protocol_t encap_type,__out efx_mae_rule_id_t * or_idp)2181 efx_mae_outer_rule_insert(
2182 __in efx_nic_t *enp,
2183 __in const efx_mae_match_spec_t *spec,
2184 __in efx_tunnel_protocol_t encap_type,
2185 __out efx_mae_rule_id_t *or_idp)
2186 {
2187 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2188 efx_mcdi_req_t req;
2189 EFX_MCDI_DECLARE_BUF(payload,
2190 MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2,
2191 MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
2192 uint32_t encap_type_mcdi;
2193 efx_mae_rule_id_t or_id;
2194 size_t offset;
2195 efx_rc_t rc;
2196
2197 EFX_STATIC_ASSERT(sizeof (or_idp->id) ==
2198 MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN);
2199
2200 EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2201 MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL);
2202
2203 if (encp->enc_mae_supported == B_FALSE) {
2204 rc = ENOTSUP;
2205 goto fail1;
2206 }
2207
2208 if (spec->emms_type != EFX_MAE_RULE_OUTER) {
2209 rc = EINVAL;
2210 goto fail2;
2211 }
2212
2213 switch (encap_type) {
2214 case EFX_TUNNEL_PROTOCOL_NONE:
2215 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
2216 break;
2217 case EFX_TUNNEL_PROTOCOL_VXLAN:
2218 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
2219 break;
2220 case EFX_TUNNEL_PROTOCOL_GENEVE:
2221 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
2222 break;
2223 case EFX_TUNNEL_PROTOCOL_NVGRE:
2224 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
2225 break;
2226 default:
2227 rc = ENOTSUP;
2228 goto fail3;
2229 }
2230
2231 req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT;
2232 req.emr_in_buf = payload;
2233 req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2;
2234 req.emr_out_buf = payload;
2235 req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN;
2236
2237 MCDI_IN_SET_DWORD(req,
2238 MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi);
2239
2240 MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio);
2241
2242 /*
2243 * Mask-value pairs have been stored in the byte order needed for the
2244 * MCDI request and are thus safe to be copied directly to the buffer.
2245 * The library cares about byte order in efx_mae_match_spec_field_set().
2246 */
2247 EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >=
2248 MAE_ENC_FIELD_PAIRS_LEN);
2249 offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST;
2250 memcpy(payload + offset, spec->emms_mask_value_pairs.outer,
2251 MAE_ENC_FIELD_PAIRS_LEN);
2252
2253 MCDI_IN_SET_DWORD_FIELD(req, MAE_OUTER_RULE_INSERT_IN_LOOKUP_CONTROL,
2254 MAE_OUTER_RULE_INSERT_IN_RECIRC_ID,
2255 spec->emms_outer_rule_recirc_id);
2256
2257 efx_mcdi_execute(enp, &req);
2258
2259 if (req.emr_rc != 0) {
2260 rc = req.emr_rc;
2261 goto fail4;
2262 }
2263
2264 if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) {
2265 rc = EMSGSIZE;
2266 goto fail5;
2267 }
2268
2269 or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
2270 if (or_id.id == EFX_MAE_RSRC_ID_INVALID) {
2271 rc = ENOENT;
2272 goto fail6;
2273 }
2274
2275 or_idp->id = or_id.id;
2276
2277 return (0);
2278
2279 fail6:
2280 EFSYS_PROBE(fail6);
2281 fail5:
2282 EFSYS_PROBE(fail5);
2283 fail4:
2284 EFSYS_PROBE(fail4);
2285 fail3:
2286 EFSYS_PROBE(fail3);
2287 fail2:
2288 EFSYS_PROBE(fail2);
2289 fail1:
2290 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2291 return (rc);
2292 }
2293
2294 __checkReturn efx_rc_t
efx_mae_outer_rule_remove(__in efx_nic_t * enp,__in const efx_mae_rule_id_t * or_idp)2295 efx_mae_outer_rule_remove(
2296 __in efx_nic_t *enp,
2297 __in const efx_mae_rule_id_t *or_idp)
2298 {
2299 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2300 efx_mcdi_req_t req;
2301 EFX_MCDI_DECLARE_BUF(payload,
2302 MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1),
2303 MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
2304 efx_rc_t rc;
2305
2306 if (encp->enc_mae_supported == B_FALSE) {
2307 rc = ENOTSUP;
2308 goto fail1;
2309 }
2310
2311 req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE;
2312 req.emr_in_buf = payload;
2313 req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1);
2314 req.emr_out_buf = payload;
2315 req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1);
2316
2317 MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id);
2318
2319 efx_mcdi_execute(enp, &req);
2320
2321 if (req.emr_rc != 0) {
2322 rc = req.emr_rc;
2323 goto fail2;
2324 }
2325
2326 if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LENMIN) {
2327 rc = EMSGSIZE;
2328 goto fail3;
2329 }
2330
2331 if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) !=
2332 or_idp->id) {
2333 /* Firmware failed to remove the outer rule. */
2334 rc = EAGAIN;
2335 goto fail4;
2336 }
2337
2338 return (0);
2339
2340 fail4:
2341 EFSYS_PROBE(fail4);
2342 fail3:
2343 EFSYS_PROBE(fail3);
2344 fail2:
2345 EFSYS_PROBE(fail2);
2346 fail1:
2347 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2348 return (rc);
2349 }
2350
2351 __checkReturn efx_rc_t
efx_mae_match_spec_outer_rule_id_set(__in efx_mae_match_spec_t * spec,__in const efx_mae_rule_id_t * or_idp)2352 efx_mae_match_spec_outer_rule_id_set(
2353 __in efx_mae_match_spec_t *spec,
2354 __in const efx_mae_rule_id_t *or_idp)
2355 {
2356 uint32_t full_mask = UINT32_MAX;
2357 efx_rc_t rc;
2358
2359 if (spec->emms_type != EFX_MAE_RULE_ACTION) {
2360 rc = EINVAL;
2361 goto fail1;
2362 }
2363
2364 if (or_idp == NULL) {
2365 rc = EINVAL;
2366 goto fail2;
2367 }
2368
2369 rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID,
2370 sizeof (or_idp->id), (const uint8_t *)&or_idp->id,
2371 sizeof (full_mask), (const uint8_t *)&full_mask);
2372 if (rc != 0)
2373 goto fail3;
2374
2375 return (0);
2376
2377 fail3:
2378 EFSYS_PROBE(fail3);
2379 fail2:
2380 EFSYS_PROBE(fail2);
2381 fail1:
2382 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2383 return (rc);
2384 }
2385
2386 __checkReturn efx_rc_t
efx_mae_mac_addr_alloc(__in efx_nic_t * enp,__in uint8_t addr_bytes[EFX_MAC_ADDR_LEN],__out efx_mae_mac_id_t * mac_idp)2387 efx_mae_mac_addr_alloc(
2388 __in efx_nic_t *enp,
2389 __in uint8_t addr_bytes[EFX_MAC_ADDR_LEN],
2390 __out efx_mae_mac_id_t *mac_idp)
2391 {
2392 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2393 efx_mcdi_req_t req;
2394 EFX_MCDI_DECLARE_BUF(payload,
2395 MC_CMD_MAE_MAC_ADDR_ALLOC_IN_LEN,
2396 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN);
2397 efx_mae_mac_id_t mac_id;
2398 efx_rc_t rc;
2399
2400 EFX_STATIC_ASSERT(sizeof (mac_idp->id) ==
2401 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_LEN);
2402
2403 EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2404 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2405
2406 if (encp->enc_mae_supported == B_FALSE) {
2407 rc = ENOTSUP;
2408 goto fail1;
2409 }
2410
2411 if (encp->enc_mae_aset_v2_supported == B_FALSE) {
2412 rc = ENOTSUP;
2413 goto fail2;
2414 }
2415
2416 req.emr_cmd = MC_CMD_MAE_MAC_ADDR_ALLOC;
2417 req.emr_in_buf = payload;
2418 req.emr_in_length = MC_CMD_MAE_MAC_ADDR_ALLOC_IN_LEN;
2419 req.emr_out_buf = payload;
2420 req.emr_out_length = MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN;
2421
2422 memcpy(payload + MC_CMD_MAE_MAC_ADDR_ALLOC_IN_MAC_ADDR_OFST,
2423 addr_bytes, EFX_MAC_ADDR_LEN);
2424
2425 efx_mcdi_execute(enp, &req);
2426
2427 if (req.emr_rc != 0) {
2428 rc = req.emr_rc;
2429 goto fail3;
2430 }
2431
2432 if (req.emr_out_length_used < MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN) {
2433 rc = EMSGSIZE;
2434 goto fail4;
2435 }
2436
2437 mac_id.id = MCDI_OUT_DWORD(req, MAE_MAC_ADDR_ALLOC_OUT_MAC_ID);
2438 if (mac_id.id == EFX_MAE_RSRC_ID_INVALID) {
2439 rc = ENOENT;
2440 goto fail5;
2441 }
2442
2443 mac_idp->id = mac_id.id;
2444
2445 return (0);
2446
2447 fail5:
2448 EFSYS_PROBE(fail5);
2449 fail4:
2450 EFSYS_PROBE(fail4);
2451 fail3:
2452 EFSYS_PROBE(fail3);
2453 fail2:
2454 EFSYS_PROBE(fail2);
2455 fail1:
2456 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2457 return (rc);
2458 }
2459
2460 __checkReturn efx_rc_t
efx_mae_mac_addr_free(__in efx_nic_t * enp,__in const efx_mae_mac_id_t * mac_idp)2461 efx_mae_mac_addr_free(
2462 __in efx_nic_t *enp,
2463 __in const efx_mae_mac_id_t *mac_idp)
2464 {
2465 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2466 efx_mcdi_req_t req;
2467 EFX_MCDI_DECLARE_BUF(payload,
2468 MC_CMD_MAE_MAC_ADDR_FREE_IN_LEN(1),
2469 MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1));
2470 efx_rc_t rc;
2471
2472 if (encp->enc_mae_supported == B_FALSE) {
2473 rc = ENOTSUP;
2474 goto fail1;
2475 }
2476
2477 if (encp->enc_mae_aset_v2_supported == B_FALSE) {
2478 rc = ENOTSUP;
2479 goto fail2;
2480 }
2481
2482 req.emr_cmd = MC_CMD_MAE_MAC_ADDR_FREE;
2483 req.emr_in_buf = payload;
2484 req.emr_in_length = MC_CMD_MAE_MAC_ADDR_FREE_IN_LEN(1);
2485 req.emr_out_buf = payload;
2486 req.emr_out_length = MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1);
2487
2488 MCDI_IN_SET_DWORD(req, MAE_MAC_ADDR_FREE_IN_MAC_ID, mac_idp->id);
2489
2490 efx_mcdi_execute(enp, &req);
2491
2492 if (req.emr_rc != 0) {
2493 rc = req.emr_rc;
2494 goto fail3;
2495 }
2496
2497 if (req.emr_out_length_used < MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1)) {
2498 rc = EMSGSIZE;
2499 goto fail4;
2500 }
2501
2502 if (MCDI_OUT_DWORD(req, MAE_MAC_ADDR_FREE_OUT_FREED_MAC_ID) !=
2503 mac_idp->id) {
2504 /* Firmware failed to remove the MAC address entry. */
2505 rc = EAGAIN;
2506 goto fail5;
2507 }
2508
2509 return (0);
2510
2511 fail5:
2512 EFSYS_PROBE(fail5);
2513 fail4:
2514 EFSYS_PROBE(fail4);
2515 fail3:
2516 EFSYS_PROBE(fail3);
2517 fail2:
2518 EFSYS_PROBE(fail2);
2519 fail1:
2520 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2521 return (rc);
2522 }
2523
2524 __checkReturn efx_rc_t
efx_mae_action_set_fill_in_dst_mac_id(__in efx_mae_actions_t * spec,__in const efx_mae_mac_id_t * mac_idp)2525 efx_mae_action_set_fill_in_dst_mac_id(
2526 __in efx_mae_actions_t *spec,
2527 __in const efx_mae_mac_id_t *mac_idp)
2528 {
2529 efx_rc_t rc;
2530
2531 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_DST_MAC)) == 0) {
2532 /*
2533 * The caller has not intended to have this action originally,
2534 * hence, they cannot indicate the MAC address entry ID.
2535 */
2536 rc = EINVAL;
2537 goto fail1;
2538 }
2539
2540 if (spec->ema_rsrc.emar_dst_mac_id.id != EFX_MAE_RSRC_ID_INVALID) {
2541 /* An attempt to indicate the MAC address entry ID twice. */
2542 rc = EINVAL;
2543 goto fail2;
2544 }
2545
2546 if (mac_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2547 rc = EINVAL;
2548 goto fail3;
2549 }
2550
2551 spec->ema_rsrc.emar_dst_mac_id.id = mac_idp->id;
2552
2553 return (0);
2554
2555 fail3:
2556 EFSYS_PROBE(fail3);
2557 fail2:
2558 EFSYS_PROBE(fail2);
2559 fail1:
2560 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2561 return (rc);
2562 }
2563
2564 __checkReturn efx_rc_t
efx_mae_action_set_fill_in_src_mac_id(__in efx_mae_actions_t * spec,__in const efx_mae_mac_id_t * mac_idp)2565 efx_mae_action_set_fill_in_src_mac_id(
2566 __in efx_mae_actions_t *spec,
2567 __in const efx_mae_mac_id_t *mac_idp)
2568 {
2569 efx_rc_t rc;
2570
2571 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_SRC_MAC)) == 0) {
2572 /*
2573 * The caller has not intended to have this action originally,
2574 * hence, they cannot indicate the MAC address entry ID.
2575 */
2576 rc = EINVAL;
2577 goto fail1;
2578 }
2579
2580 if (spec->ema_rsrc.emar_src_mac_id.id != EFX_MAE_RSRC_ID_INVALID) {
2581 /* An attempt to indicate the MAC address entry ID twice. */
2582 rc = EINVAL;
2583 goto fail2;
2584 }
2585
2586 if (mac_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2587 rc = EINVAL;
2588 goto fail3;
2589 }
2590
2591 spec->ema_rsrc.emar_src_mac_id.id = mac_idp->id;
2592
2593 return (0);
2594
2595 fail3:
2596 EFSYS_PROBE(fail3);
2597 fail2:
2598 EFSYS_PROBE(fail2);
2599 fail1:
2600 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2601 return (rc);
2602 }
2603
2604 __checkReturn efx_rc_t
efx_mae_encap_header_alloc(__in efx_nic_t * enp,__in efx_tunnel_protocol_t encap_type,__in_bcount (header_size)uint8_t * header_data,__in size_t header_size,__out efx_mae_eh_id_t * eh_idp)2605 efx_mae_encap_header_alloc(
2606 __in efx_nic_t *enp,
2607 __in efx_tunnel_protocol_t encap_type,
2608 __in_bcount(header_size) uint8_t *header_data,
2609 __in size_t header_size,
2610 __out efx_mae_eh_id_t *eh_idp)
2611 {
2612 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2613 efx_mcdi_req_t req;
2614 EFX_MCDI_DECLARE_BUF(payload,
2615 MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LENMAX_MCDI2,
2616 MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN);
2617 uint32_t encap_type_mcdi;
2618 efx_mae_eh_id_t eh_id;
2619 efx_rc_t rc;
2620
2621 EFX_STATIC_ASSERT(sizeof (eh_idp->id) ==
2622 MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_LEN);
2623
2624 EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2625 MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
2626
2627 if (encp->enc_mae_supported == B_FALSE) {
2628 rc = ENOTSUP;
2629 goto fail1;
2630 }
2631
2632 switch (encap_type) {
2633 case EFX_TUNNEL_PROTOCOL_NONE:
2634 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
2635 break;
2636 case EFX_TUNNEL_PROTOCOL_VXLAN:
2637 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
2638 break;
2639 case EFX_TUNNEL_PROTOCOL_GENEVE:
2640 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
2641 break;
2642 case EFX_TUNNEL_PROTOCOL_NVGRE:
2643 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
2644 break;
2645 default:
2646 rc = ENOTSUP;
2647 goto fail2;
2648 }
2649
2650 if (header_size >
2651 MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2) {
2652 rc = EINVAL;
2653 goto fail3;
2654 }
2655
2656 req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_ALLOC;
2657 req.emr_in_buf = payload;
2658 req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(header_size);
2659 req.emr_out_buf = payload;
2660 req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN;
2661
2662 MCDI_IN_SET_DWORD(req,
2663 MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, encap_type_mcdi);
2664
2665 memcpy(payload + MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_OFST,
2666 header_data, header_size);
2667
2668 efx_mcdi_execute(enp, &req);
2669
2670 if (req.emr_rc != 0) {
2671 rc = req.emr_rc;
2672 goto fail4;
2673 }
2674
2675 if (req.emr_out_length_used < MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN) {
2676 rc = EMSGSIZE;
2677 goto fail5;
2678 }
2679
2680 eh_id.id = MCDI_OUT_DWORD(req,
2681 MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID);
2682
2683 if (eh_id.id == EFX_MAE_RSRC_ID_INVALID) {
2684 rc = ENOENT;
2685 goto fail6;
2686 }
2687
2688 eh_idp->id = eh_id.id;
2689
2690 return (0);
2691
2692 fail6:
2693 EFSYS_PROBE(fail6);
2694 fail5:
2695 EFSYS_PROBE(fail5);
2696 fail4:
2697 EFSYS_PROBE(fail4);
2698 fail3:
2699 EFSYS_PROBE(fail3);
2700 fail2:
2701 EFSYS_PROBE(fail2);
2702 fail1:
2703 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2704 return (rc);
2705 }
2706
2707 __checkReturn efx_rc_t
efx_mae_encap_header_free(__in efx_nic_t * enp,__in const efx_mae_eh_id_t * eh_idp)2708 efx_mae_encap_header_free(
2709 __in efx_nic_t *enp,
2710 __in const efx_mae_eh_id_t *eh_idp)
2711 {
2712 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2713 efx_mcdi_req_t req;
2714 EFX_MCDI_DECLARE_BUF(payload,
2715 MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1),
2716 MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1));
2717 efx_rc_t rc;
2718
2719 if (encp->enc_mae_supported == B_FALSE) {
2720 rc = ENOTSUP;
2721 goto fail1;
2722 }
2723
2724 req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_FREE;
2725 req.emr_in_buf = payload;
2726 req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1);
2727 req.emr_out_buf = payload;
2728 req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1);
2729
2730 MCDI_IN_SET_DWORD(req, MAE_ENCAP_HEADER_FREE_IN_EH_ID, eh_idp->id);
2731
2732 efx_mcdi_execute(enp, &req);
2733
2734 if (req.emr_rc != 0) {
2735 rc = req.emr_rc;
2736 goto fail2;
2737 }
2738
2739 if (MCDI_OUT_DWORD(req, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) !=
2740 eh_idp->id) {
2741 /* Firmware failed to remove the encap. header. */
2742 rc = EAGAIN;
2743 goto fail3;
2744 }
2745
2746 return (0);
2747
2748 fail3:
2749 EFSYS_PROBE(fail3);
2750 fail2:
2751 EFSYS_PROBE(fail2);
2752 fail1:
2753 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2754 return (rc);
2755 }
2756
2757 __checkReturn efx_rc_t
efx_mae_action_set_fill_in_eh_id(__in efx_mae_actions_t * spec,__in const efx_mae_eh_id_t * eh_idp)2758 efx_mae_action_set_fill_in_eh_id(
2759 __in efx_mae_actions_t *spec,
2760 __in const efx_mae_eh_id_t *eh_idp)
2761 {
2762 efx_rc_t rc;
2763
2764 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) == 0) {
2765 /*
2766 * The caller has not intended to have action ENCAP originally,
2767 * hence, this attempt to indicate encap. header ID is invalid.
2768 */
2769 rc = EINVAL;
2770 goto fail1;
2771 }
2772
2773 if (spec->ema_rsrc.emar_eh_id.id != EFX_MAE_RSRC_ID_INVALID) {
2774 /* The caller attempts to indicate encap. header ID twice. */
2775 rc = EINVAL;
2776 goto fail2;
2777 }
2778
2779 if (eh_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2780 rc = EINVAL;
2781 goto fail3;
2782 }
2783
2784 spec->ema_rsrc.emar_eh_id.id = eh_idp->id;
2785
2786 return (0);
2787
2788 fail3:
2789 EFSYS_PROBE(fail3);
2790 fail2:
2791 EFSYS_PROBE(fail2);
2792 fail1:
2793 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2794 return (rc);
2795 }
2796
2797 __checkReturn efx_rc_t
efx_mae_action_set_alloc(__in efx_nic_t * enp,__in const efx_mae_actions_t * spec,__out efx_mae_aset_id_t * aset_idp)2798 efx_mae_action_set_alloc(
2799 __in efx_nic_t *enp,
2800 __in const efx_mae_actions_t *spec,
2801 __out efx_mae_aset_id_t *aset_idp)
2802 {
2803 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2804 efx_mcdi_req_t req;
2805 EFX_MCDI_DECLARE_BUF(payload,
2806 MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
2807 MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
2808 efx_mae_aset_id_t aset_id;
2809 efx_rc_t rc;
2810
2811 if (encp->enc_mae_supported == B_FALSE) {
2812 rc = ENOTSUP;
2813 goto fail1;
2814 }
2815
2816 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_DST_MAC)) != 0 &&
2817 spec->ema_rsrc.emar_dst_mac_id.id == EFX_MAE_RSRC_ID_INVALID) {
2818 rc = EINVAL;
2819 goto fail2;
2820 }
2821
2822 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_SRC_MAC)) != 0 &&
2823 spec->ema_rsrc.emar_src_mac_id.id == EFX_MAE_RSRC_ID_INVALID) {
2824 rc = EINVAL;
2825 goto fail3;
2826 }
2827
2828 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) != 0 &&
2829 spec->ema_rsrc.emar_eh_id.id == EFX_MAE_RSRC_ID_INVALID) {
2830 rc = EINVAL;
2831 goto fail4;
2832 }
2833
2834 if (spec->ema_n_count_actions == 1 &&
2835 spec->ema_rsrc.emar_counter_id.id == EFX_MAE_RSRC_ID_INVALID) {
2836 rc = EINVAL;
2837 goto fail5;
2838 }
2839
2840 req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
2841 req.emr_in_buf = payload;
2842 req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
2843 req.emr_out_buf = payload;
2844 req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
2845
2846 /*
2847 * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
2848 * corresponding resource types are supported by the implementation.
2849 * Use proper resource ID assignments instead.
2850 */
2851 MCDI_IN_SET_DWORD(req,
2852 MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
2853
2854 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECAP)) != 0) {
2855 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2856 MAE_ACTION_SET_ALLOC_IN_DECAP, 1);
2857 }
2858
2859 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2860 MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
2861
2862 MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
2863 spec->ema_rsrc.emar_dst_mac_id.id);
2864
2865 MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
2866 spec->ema_rsrc.emar_src_mac_id.id);
2867
2868 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECR_IP_TTL)) != 0) {
2869 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2870 MAE_ACTION_SET_ALLOC_IN_DO_DECR_IP_TTL, 1);
2871 }
2872
2873 if (spec->ema_n_vlan_tags_to_push > 0) {
2874 unsigned int outer_tag_idx;
2875
2876 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2877 MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
2878 spec->ema_n_vlan_tags_to_push);
2879
2880 if (spec->ema_n_vlan_tags_to_push ==
2881 EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
2882 MCDI_IN_SET_WORD(req,
2883 MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
2884 spec->ema_vlan_push_descs[0].emavp_tpid_be);
2885 MCDI_IN_SET_WORD(req,
2886 MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
2887 spec->ema_vlan_push_descs[0].emavp_tci_be);
2888 }
2889
2890 outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
2891
2892 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
2893 spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
2894 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
2895 spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
2896 }
2897
2898 MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
2899 spec->ema_rsrc.emar_eh_id.id);
2900 MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
2901 spec->ema_rsrc.emar_counter_id.id);
2902
2903 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
2904 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2905 MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
2906 }
2907
2908 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
2909 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2910 MAE_ACTION_SET_ALLOC_IN_MARK, 1);
2911
2912 MCDI_IN_SET_DWORD(req,
2913 MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
2914 }
2915
2916 MCDI_IN_SET_DWORD(req,
2917 MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
2918
2919 efx_mcdi_execute(enp, &req);
2920
2921 if (req.emr_rc != 0) {
2922 rc = req.emr_rc;
2923 goto fail6;
2924 }
2925
2926 if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
2927 rc = EMSGSIZE;
2928 goto fail7;
2929 }
2930
2931 aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
2932 if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
2933 rc = ENOENT;
2934 goto fail8;
2935 }
2936
2937 aset_idp->id = aset_id.id;
2938
2939 return (0);
2940
2941 fail8:
2942 EFSYS_PROBE(fail8);
2943 fail7:
2944 EFSYS_PROBE(fail7);
2945 fail6:
2946 EFSYS_PROBE(fail6);
2947 fail5:
2948 EFSYS_PROBE(fail5);
2949 fail4:
2950 EFSYS_PROBE(fail4);
2951 fail3:
2952 EFSYS_PROBE(fail3);
2953 fail2:
2954 EFSYS_PROBE(fail2);
2955 fail1:
2956 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2957 return (rc);
2958 }
2959
2960 __checkReturn unsigned int
efx_mae_action_set_get_nb_count(__in const efx_mae_actions_t * spec)2961 efx_mae_action_set_get_nb_count(
2962 __in const efx_mae_actions_t *spec)
2963 {
2964 return (spec->ema_n_count_actions);
2965 }
2966
2967 __checkReturn efx_rc_t
efx_mae_action_set_fill_in_counter_id(__in efx_mae_actions_t * spec,__in const efx_counter_t * counter_idp)2968 efx_mae_action_set_fill_in_counter_id(
2969 __in efx_mae_actions_t *spec,
2970 __in const efx_counter_t *counter_idp)
2971 {
2972 efx_rc_t rc;
2973
2974 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_COUNT)) == 0) {
2975 /*
2976 * Invalid to add counter ID if spec does not have COUNT action.
2977 */
2978 rc = EINVAL;
2979 goto fail1;
2980 }
2981
2982 if (spec->ema_n_count_actions != 1) {
2983 /*
2984 * Having multiple COUNT actions in the spec requires a counter
2985 * list to be used. This API must only be used for a single
2986 * counter per spec. Turn down the request as inappropriate.
2987 */
2988 rc = EINVAL;
2989 goto fail2;
2990 }
2991
2992 if (spec->ema_rsrc.emar_counter_id.id != EFX_MAE_RSRC_ID_INVALID) {
2993 /* The caller attempts to indicate counter ID twice. */
2994 rc = EALREADY;
2995 goto fail3;
2996 }
2997
2998 if (counter_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2999 rc = EINVAL;
3000 goto fail4;
3001 }
3002
3003 spec->ema_rsrc.emar_counter_id.id = counter_idp->id;
3004
3005 return (0);
3006
3007 fail4:
3008 EFSYS_PROBE(fail4);
3009 fail3:
3010 EFSYS_PROBE(fail3);
3011 fail2:
3012 EFSYS_PROBE(fail2);
3013 fail1:
3014 EFSYS_PROBE1(fail1, efx_rc_t, rc);
3015 return (rc);
3016 }
3017
3018 __checkReturn efx_rc_t
efx_mae_counters_alloc(__in efx_nic_t * enp,__in uint32_t n_counters,__out uint32_t * n_allocatedp,__out_ecount (n_counters)efx_counter_t * countersp,__out_opt uint32_t * gen_countp)3019 efx_mae_counters_alloc(
3020 __in efx_nic_t *enp,
3021 __in uint32_t n_counters,
3022 __out uint32_t *n_allocatedp,
3023 __out_ecount(n_counters) efx_counter_t *countersp,
3024 __out_opt uint32_t *gen_countp)
3025 {
3026 EFX_MCDI_DECLARE_BUF(payload,
3027 MC_CMD_MAE_COUNTER_ALLOC_IN_LEN,
3028 MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMAX_MCDI2);
3029 efx_mae_t *maep = enp->en_maep;
3030 uint32_t n_allocated;
3031 efx_mcdi_req_t req;
3032 unsigned int i;
3033 efx_rc_t rc;
3034
3035 if (n_counters > maep->em_max_ncounters ||
3036 n_counters < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM ||
3037 n_counters > MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MAXNUM_MCDI2) {
3038 rc = EINVAL;
3039 goto fail1;
3040 }
3041
3042 req.emr_cmd = MC_CMD_MAE_COUNTER_ALLOC;
3043 req.emr_in_buf = payload;
3044 req.emr_in_length = MC_CMD_MAE_COUNTER_ALLOC_IN_LEN;
3045 req.emr_out_buf = payload;
3046 req.emr_out_length = MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(n_counters);
3047
3048 MCDI_IN_SET_DWORD(req, MAE_COUNTER_ALLOC_IN_REQUESTED_COUNT,
3049 n_counters);
3050
3051 efx_mcdi_execute(enp, &req);
3052
3053 if (req.emr_rc != 0) {
3054 rc = req.emr_rc;
3055 goto fail2;
3056 }
3057
3058 if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMIN) {
3059 rc = EMSGSIZE;
3060 goto fail3;
3061 }
3062
3063 n_allocated = MCDI_OUT_DWORD(req,
3064 MAE_COUNTER_ALLOC_OUT_COUNTER_ID_COUNT);
3065 if (n_allocated < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM) {
3066 rc = EFAULT;
3067 goto fail4;
3068 }
3069
3070 for (i = 0; i < n_allocated; i++) {
3071 countersp[i].id = MCDI_OUT_INDEXED_DWORD(req,
3072 MAE_COUNTER_ALLOC_OUT_COUNTER_ID, i);
3073 }
3074
3075 if (gen_countp != NULL) {
3076 *gen_countp = MCDI_OUT_DWORD(req,
3077 MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT);
3078 }
3079
3080 *n_allocatedp = n_allocated;
3081
3082 return (0);
3083
3084 fail4:
3085 EFSYS_PROBE(fail4);
3086 fail3:
3087 EFSYS_PROBE(fail3);
3088 fail2:
3089 EFSYS_PROBE(fail2);
3090 fail1:
3091 EFSYS_PROBE1(fail1, efx_rc_t, rc);
3092
3093 return (rc);
3094 }
3095
3096 __checkReturn efx_rc_t
efx_mae_counters_free(__in efx_nic_t * enp,__in uint32_t n_counters,__out uint32_t * n_freedp,__in_ecount (n_counters)const efx_counter_t * countersp,__out_opt uint32_t * gen_countp)3097 efx_mae_counters_free(
3098 __in efx_nic_t *enp,
3099 __in uint32_t n_counters,
3100 __out uint32_t *n_freedp,
3101 __in_ecount(n_counters) const efx_counter_t *countersp,
3102 __out_opt uint32_t *gen_countp)
3103 {
3104 EFX_MCDI_DECLARE_BUF(payload,
3105 MC_CMD_MAE_COUNTER_FREE_IN_LENMAX_MCDI2,
3106 MC_CMD_MAE_COUNTER_FREE_OUT_LENMAX_MCDI2);
3107 efx_mae_t *maep = enp->en_maep;
3108 efx_mcdi_req_t req;
3109 uint32_t n_freed;
3110 unsigned int i;
3111 efx_rc_t rc;
3112
3113 if (n_counters > maep->em_max_ncounters ||
3114 n_counters < MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MINNUM ||
3115 n_counters >
3116 MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MAXNUM_MCDI2) {
3117 rc = EINVAL;
3118 goto fail1;
3119 }
3120
3121 req.emr_cmd = MC_CMD_MAE_COUNTER_FREE;
3122 req.emr_in_buf = payload;
3123 req.emr_in_length = MC_CMD_MAE_COUNTER_FREE_IN_LEN(n_counters);
3124 req.emr_out_buf = payload;
3125 req.emr_out_length = MC_CMD_MAE_COUNTER_FREE_OUT_LEN(n_counters);
3126
3127 for (i = 0; i < n_counters; i++) {
3128 MCDI_IN_SET_INDEXED_DWORD(req,
3129 MAE_COUNTER_FREE_IN_FREE_COUNTER_ID, i, countersp[i].id);
3130 }
3131 MCDI_IN_SET_DWORD(req, MAE_COUNTER_FREE_IN_COUNTER_ID_COUNT,
3132 n_counters);
3133
3134 efx_mcdi_execute(enp, &req);
3135
3136 if (req.emr_rc != 0) {
3137 rc = req.emr_rc;
3138 goto fail2;
3139 }
3140
3141 if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_FREE_OUT_LENMIN) {
3142 rc = EMSGSIZE;
3143 goto fail3;
3144 }
3145
3146 n_freed = MCDI_OUT_DWORD(req, MAE_COUNTER_FREE_OUT_COUNTER_ID_COUNT);
3147
3148 if (n_freed < MC_CMD_MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID_MINNUM) {
3149 rc = EFAULT;
3150 goto fail4;
3151 }
3152
3153 if (gen_countp != NULL) {
3154 *gen_countp = MCDI_OUT_DWORD(req,
3155 MAE_COUNTER_FREE_OUT_GENERATION_COUNT);
3156 }
3157
3158 *n_freedp = n_freed;
3159
3160 return (0);
3161
3162 fail4:
3163 EFSYS_PROBE(fail4);
3164 fail3:
3165 EFSYS_PROBE(fail3);
3166 fail2:
3167 EFSYS_PROBE(fail2);
3168 fail1:
3169 EFSYS_PROBE1(fail1, efx_rc_t, rc);
3170
3171 return (rc);
3172 }
3173
3174 __checkReturn efx_rc_t
efx_mae_counters_stream_start(__in efx_nic_t * enp,__in uint16_t rxq_id,__in uint16_t packet_size,__in uint32_t flags_in,__out uint32_t * flags_out)3175 efx_mae_counters_stream_start(
3176 __in efx_nic_t *enp,
3177 __in uint16_t rxq_id,
3178 __in uint16_t packet_size,
3179 __in uint32_t flags_in,
3180 __out uint32_t *flags_out)
3181 {
3182 efx_mcdi_req_t req;
3183 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN,
3184 MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN);
3185 efx_rc_t rc;
3186
3187 EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_IN_ZERO_SQUASH_DISABLE ==
3188 1U << MC_CMD_MAE_COUNTERS_STREAM_START_IN_ZERO_SQUASH_DISABLE_LBN);
3189
3190 EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_OUT_USES_CREDITS ==
3191 1U << MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_LBN);
3192
3193 req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_START;
3194 req.emr_in_buf = payload;
3195 req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN;
3196 req.emr_out_buf = payload;
3197 req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN;
3198
3199 MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_QID, rxq_id);
3200 MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_PACKET_SIZE,
3201 packet_size);
3202 MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_START_IN_FLAGS, flags_in);
3203
3204 efx_mcdi_execute(enp, &req);
3205
3206 if (req.emr_rc != 0) {
3207 rc = req.emr_rc;
3208 goto fail1;
3209 }
3210
3211 if (req.emr_out_length_used <
3212 MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN) {
3213 rc = EMSGSIZE;
3214 goto fail2;
3215 }
3216
3217 *flags_out = MCDI_OUT_DWORD(req, MAE_COUNTERS_STREAM_START_OUT_FLAGS);
3218
3219 return (0);
3220
3221 fail2:
3222 EFSYS_PROBE(fail2);
3223 fail1:
3224 EFSYS_PROBE1(fail1, efx_rc_t, rc);
3225
3226 return (rc);
3227 }
3228
3229 __checkReturn efx_rc_t
efx_mae_counters_stream_stop(__in efx_nic_t * enp,__in uint16_t rxq_id,__out_opt uint32_t * gen_countp)3230 efx_mae_counters_stream_stop(
3231 __in efx_nic_t *enp,
3232 __in uint16_t rxq_id,
3233 __out_opt uint32_t *gen_countp)
3234 {
3235 efx_mcdi_req_t req;
3236 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN,
3237 MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN);
3238 efx_rc_t rc;
3239
3240 req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_STOP;
3241 req.emr_in_buf = payload;
3242 req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN;
3243 req.emr_out_buf = payload;
3244 req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN;
3245
3246 MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_STOP_IN_QID, rxq_id);
3247
3248 efx_mcdi_execute(enp, &req);
3249
3250 if (req.emr_rc != 0) {
3251 rc = req.emr_rc;
3252 goto fail1;
3253 }
3254
3255 if (req.emr_out_length_used <
3256 MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN) {
3257 rc = EMSGSIZE;
3258 goto fail2;
3259 }
3260
3261 if (gen_countp != NULL) {
3262 *gen_countp = MCDI_OUT_DWORD(req,
3263 MAE_COUNTERS_STREAM_STOP_OUT_GENERATION_COUNT);
3264 }
3265
3266 return (0);
3267
3268 fail2:
3269 EFSYS_PROBE(fail2);
3270 fail1:
3271 EFSYS_PROBE1(fail1, efx_rc_t, rc);
3272
3273 return (rc);
3274 }
3275
3276 __checkReturn efx_rc_t
efx_mae_counters_stream_give_credits(__in efx_nic_t * enp,__in uint32_t n_credits)3277 efx_mae_counters_stream_give_credits(
3278 __in efx_nic_t *enp,
3279 __in uint32_t n_credits)
3280 {
3281 efx_mcdi_req_t req;
3282 EFX_MCDI_DECLARE_BUF(payload,
3283 MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN,
3284 MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN);
3285 efx_rc_t rc;
3286
3287 req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS;
3288 req.emr_in_buf = payload;
3289 req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN;
3290 req.emr_out_buf = payload;
3291 req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN;
3292
3293 MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_NUM_CREDITS,
3294 n_credits);
3295
3296 efx_mcdi_execute(enp, &req);
3297
3298 if (req.emr_rc != 0) {
3299 rc = req.emr_rc;
3300 goto fail1;
3301 }
3302
3303 return (0);
3304
3305 fail1:
3306 EFSYS_PROBE1(fail1, efx_rc_t, rc);
3307
3308 return (rc);
3309 }
3310
3311 __checkReturn efx_rc_t
efx_mae_action_set_free(__in efx_nic_t * enp,__in const efx_mae_aset_id_t * aset_idp)3312 efx_mae_action_set_free(
3313 __in efx_nic_t *enp,
3314 __in const efx_mae_aset_id_t *aset_idp)
3315 {
3316 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3317 efx_mcdi_req_t req;
3318 EFX_MCDI_DECLARE_BUF(payload,
3319 MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
3320 MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
3321 efx_rc_t rc;
3322
3323 if (encp->enc_mae_supported == B_FALSE) {
3324 rc = ENOTSUP;
3325 goto fail1;
3326 }
3327
3328 req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
3329 req.emr_in_buf = payload;
3330 req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
3331 req.emr_out_buf = payload;
3332 req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
3333
3334 MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
3335
3336 efx_mcdi_execute(enp, &req);
3337
3338 if (req.emr_rc != 0) {
3339 rc = req.emr_rc;
3340 goto fail2;
3341 }
3342
3343 if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_FREE_OUT_LENMIN) {
3344 rc = EMSGSIZE;
3345 goto fail3;
3346 }
3347
3348 if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
3349 aset_idp->id) {
3350 /* Firmware failed to free the action set. */
3351 rc = EAGAIN;
3352 goto fail4;
3353 }
3354
3355 return (0);
3356
3357 fail4:
3358 EFSYS_PROBE(fail4);
3359 fail3:
3360 EFSYS_PROBE(fail3);
3361 fail2:
3362 EFSYS_PROBE(fail2);
3363 fail1:
3364 EFSYS_PROBE1(fail1, efx_rc_t, rc);
3365 return (rc);
3366 }
3367
3368 __checkReturn efx_rc_t
efx_mae_action_rule_insert(__in efx_nic_t * enp,__in const efx_mae_match_spec_t * spec,__in const efx_mae_aset_list_id_t * asl_idp,__in const efx_mae_aset_id_t * as_idp,__out efx_mae_rule_id_t * ar_idp)3369 efx_mae_action_rule_insert(
3370 __in efx_nic_t *enp,
3371 __in const efx_mae_match_spec_t *spec,
3372 __in const efx_mae_aset_list_id_t *asl_idp,
3373 __in const efx_mae_aset_id_t *as_idp,
3374 __out efx_mae_rule_id_t *ar_idp)
3375 {
3376 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3377 efx_mcdi_req_t req;
3378 EFX_MCDI_DECLARE_BUF(payload,
3379 MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2,
3380 MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
3381 efx_oword_t *rule_response;
3382 efx_mae_rule_id_t ar_id;
3383 size_t offset;
3384 efx_rc_t rc;
3385
3386 EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
3387 MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
3388
3389 EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
3390 MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
3391
3392 if (encp->enc_mae_supported == B_FALSE) {
3393 rc = ENOTSUP;
3394 goto fail1;
3395 }
3396
3397 if (spec->emms_type != EFX_MAE_RULE_ACTION ||
3398 (asl_idp != NULL && as_idp != NULL) ||
3399 (asl_idp == NULL && as_idp == NULL)) {
3400 rc = EINVAL;
3401 goto fail2;
3402 }
3403
3404 req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
3405 req.emr_in_buf = payload;
3406 req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
3407 req.emr_out_buf = payload;
3408 req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
3409
3410 EFX_STATIC_ASSERT(sizeof (*rule_response) <=
3411 MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
3412 offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
3413 rule_response = (efx_oword_t *)(payload + offset);
3414 EFX_POPULATE_OWORD_3(*rule_response,
3415 MAE_ACTION_RULE_RESPONSE_ASL_ID,
3416 (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
3417 MAE_ACTION_RULE_RESPONSE_AS_ID,
3418 (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
3419 MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
3420
3421 MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
3422
3423 /*
3424 * Mask-value pairs have been stored in the byte order needed for the
3425 * MCDI request and are thus safe to be copied directly to the buffer.
3426 */
3427 EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
3428 MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
3429 offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
3430 memcpy(payload + offset, spec->emms_mask_value_pairs.action,
3431 MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
3432
3433 efx_mcdi_execute(enp, &req);
3434
3435 if (req.emr_rc != 0) {
3436 rc = req.emr_rc;
3437 goto fail3;
3438 }
3439
3440 if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
3441 rc = EMSGSIZE;
3442 goto fail4;
3443 }
3444
3445 ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
3446 if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
3447 rc = ENOENT;
3448 goto fail5;
3449 }
3450
3451 ar_idp->id = ar_id.id;
3452
3453 return (0);
3454
3455 fail5:
3456 EFSYS_PROBE(fail5);
3457 fail4:
3458 EFSYS_PROBE(fail4);
3459 fail3:
3460 EFSYS_PROBE(fail3);
3461 fail2:
3462 EFSYS_PROBE(fail2);
3463 fail1:
3464 EFSYS_PROBE1(fail1, efx_rc_t, rc);
3465 return (rc);
3466 }
3467
3468 __checkReturn efx_rc_t
efx_mae_action_rule_remove(__in efx_nic_t * enp,__in const efx_mae_rule_id_t * ar_idp)3469 efx_mae_action_rule_remove(
3470 __in efx_nic_t *enp,
3471 __in const efx_mae_rule_id_t *ar_idp)
3472 {
3473 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3474 efx_mcdi_req_t req;
3475 EFX_MCDI_DECLARE_BUF(payload,
3476 MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
3477 MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
3478 efx_rc_t rc;
3479
3480 if (encp->enc_mae_supported == B_FALSE) {
3481 rc = ENOTSUP;
3482 goto fail1;
3483 }
3484
3485 req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
3486 req.emr_in_buf = payload;
3487 req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
3488 req.emr_out_buf = payload;
3489 req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
3490
3491 MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
3492
3493 efx_mcdi_execute(enp, &req);
3494
3495 if (req.emr_rc != 0) {
3496 rc = req.emr_rc;
3497 goto fail2;
3498 }
3499
3500 if (req.emr_out_length_used <
3501 MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LENMIN) {
3502 rc = EMSGSIZE;
3503 goto fail3;
3504 }
3505
3506 if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
3507 ar_idp->id) {
3508 /* Firmware failed to delete the action rule. */
3509 rc = EAGAIN;
3510 goto fail4;
3511 }
3512
3513 return (0);
3514
3515 fail4:
3516 EFSYS_PROBE(fail4);
3517 fail3:
3518 EFSYS_PROBE(fail3);
3519 fail2:
3520 EFSYS_PROBE(fail2);
3521 fail1:
3522 EFSYS_PROBE1(fail1, efx_rc_t, rc);
3523 return (rc);
3524 }
3525
3526 __checkReturn efx_rc_t
efx_mcdi_mport_alloc_alias(__in efx_nic_t * enp,__out efx_mport_id_t * mportp,__out_opt uint32_t * labelp)3527 efx_mcdi_mport_alloc_alias(
3528 __in efx_nic_t *enp,
3529 __out efx_mport_id_t *mportp,
3530 __out_opt uint32_t *labelp)
3531 {
3532 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3533 efx_mcdi_req_t req;
3534 EFX_MCDI_DECLARE_BUF(payload,
3535 MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_LEN,
3536 MC_CMD_MAE_MPORT_ALLOC_ALIAS_OUT_LEN);
3537 efx_rc_t rc;
3538
3539 if (encp->enc_mae_supported == B_FALSE) {
3540 rc = ENOTSUP;
3541 goto fail1;
3542 }
3543
3544 req.emr_cmd = MC_CMD_MAE_MPORT_ALLOC;
3545 req.emr_in_buf = payload;
3546 req.emr_in_length = MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_LEN;
3547 req.emr_out_buf = payload;
3548 req.emr_out_length = MC_CMD_MAE_MPORT_ALLOC_ALIAS_OUT_LEN;
3549
3550 MCDI_IN_SET_DWORD(req, MAE_MPORT_ALLOC_IN_TYPE,
3551 MC_CMD_MAE_MPORT_ALLOC_IN_MPORT_TYPE_ALIAS);
3552 MCDI_IN_SET_DWORD(req, MAE_MPORT_ALLOC_ALIAS_IN_DELIVER_MPORT,
3553 MAE_MPORT_SELECTOR_ASSIGNED);
3554
3555 efx_mcdi_execute(enp, &req);
3556
3557 if (req.emr_rc != 0) {
3558 rc = req.emr_rc;
3559 goto fail2;
3560 }
3561
3562 mportp->id = MCDI_OUT_DWORD(req, MAE_MPORT_ALLOC_OUT_MPORT_ID);
3563 if (labelp != NULL)
3564 *labelp = MCDI_OUT_DWORD(req, MAE_MPORT_ALLOC_ALIAS_OUT_LABEL);
3565
3566 return (0);
3567
3568 fail2:
3569 EFSYS_PROBE(fail2);
3570 fail1:
3571 EFSYS_PROBE1(fail1, efx_rc_t, rc);
3572 return (rc);
3573 }
3574
3575 __checkReturn efx_rc_t
efx_mae_mport_free(__in efx_nic_t * enp,__in const efx_mport_id_t * mportp)3576 efx_mae_mport_free(
3577 __in efx_nic_t *enp,
3578 __in const efx_mport_id_t *mportp)
3579 {
3580 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3581 efx_mcdi_req_t req;
3582 EFX_MCDI_DECLARE_BUF(payload,
3583 MC_CMD_MAE_MPORT_FREE_IN_LEN,
3584 MC_CMD_MAE_MPORT_FREE_OUT_LEN);
3585 efx_rc_t rc;
3586
3587 if (encp->enc_mae_supported == B_FALSE) {
3588 rc = ENOTSUP;
3589 goto fail1;
3590 }
3591
3592 req.emr_cmd = MC_CMD_MAE_MPORT_FREE;
3593 req.emr_in_buf = payload;
3594 req.emr_in_length = MC_CMD_MAE_MPORT_FREE_IN_LEN;
3595 req.emr_out_buf = payload;
3596 req.emr_out_length = MC_CMD_MAE_MPORT_FREE_OUT_LEN;
3597
3598 MCDI_IN_SET_DWORD(req, MAE_MPORT_FREE_IN_MPORT_ID, mportp->id);
3599
3600 efx_mcdi_execute(enp, &req);
3601
3602 if (req.emr_rc != 0) {
3603 rc = req.emr_rc;
3604 goto fail2;
3605 }
3606
3607 return (0);
3608
3609 fail2:
3610 EFSYS_PROBE(fail2);
3611 fail1:
3612 EFSYS_PROBE1(fail1, efx_rc_t, rc);
3613 return (rc);
3614 }
3615
3616 static __checkReturn efx_rc_t
efx_mae_read_mport_journal_single(__in uint8_t * entry_buf,__out efx_mport_desc_t * desc)3617 efx_mae_read_mport_journal_single(
3618 __in uint8_t *entry_buf,
3619 __out efx_mport_desc_t *desc)
3620 {
3621 uint32_t pcie_intf;
3622 efx_rc_t rc;
3623
3624 memset(desc, 0, sizeof (*desc));
3625
3626 desc->emd_id.id = MCDI_STRUCT_DWORD(entry_buf,
3627 MAE_MPORT_DESC_V2_MPORT_ID);
3628
3629 desc->emd_can_receive_on = MCDI_STRUCT_DWORD_FIELD(entry_buf,
3630 MAE_MPORT_DESC_V2_FLAGS,
3631 MAE_MPORT_DESC_V2_CAN_RECEIVE_ON);
3632
3633 desc->emd_can_deliver_to = MCDI_STRUCT_DWORD_FIELD(entry_buf,
3634 MAE_MPORT_DESC_V2_FLAGS,
3635 MAE_MPORT_DESC_V2_CAN_DELIVER_TO);
3636
3637 desc->emd_can_delete = MCDI_STRUCT_DWORD_FIELD(entry_buf,
3638 MAE_MPORT_DESC_V2_FLAGS,
3639 MAE_MPORT_DESC_V2_CAN_DELETE);
3640
3641 desc->emd_zombie = MCDI_STRUCT_DWORD_FIELD(entry_buf,
3642 MAE_MPORT_DESC_V2_FLAGS,
3643 MAE_MPORT_DESC_V2_IS_ZOMBIE);
3644
3645 desc->emd_type = MCDI_STRUCT_DWORD(entry_buf,
3646 MAE_MPORT_DESC_V2_MPORT_TYPE);
3647
3648 /*
3649 * We can't check everything here. If some additional checks are
3650 * required, they should be performed by the callback function.
3651 */
3652 switch (desc->emd_type) {
3653 case EFX_MPORT_TYPE_NET_PORT:
3654 desc->emd_net_port.ep_index =
3655 MCDI_STRUCT_DWORD(entry_buf,
3656 MAE_MPORT_DESC_V2_NET_PORT_IDX);
3657 break;
3658 case EFX_MPORT_TYPE_ALIAS:
3659 desc->emd_alias.ea_target_mport_id.id =
3660 MCDI_STRUCT_DWORD(entry_buf,
3661 MAE_MPORT_DESC_V2_ALIAS_DELIVER_MPORT_ID);
3662 break;
3663 case EFX_MPORT_TYPE_VNIC:
3664 desc->emd_vnic.ev_client_type =
3665 MCDI_STRUCT_DWORD(entry_buf,
3666 MAE_MPORT_DESC_V2_VNIC_CLIENT_TYPE);
3667 if (desc->emd_vnic.ev_client_type !=
3668 EFX_MPORT_VNIC_CLIENT_FUNCTION)
3669 break;
3670
3671 pcie_intf = MCDI_STRUCT_DWORD(entry_buf,
3672 MAE_MPORT_DESC_V2_VNIC_FUNCTION_INTERFACE);
3673 rc = efx_mcdi_intf_from_pcie(pcie_intf,
3674 &desc->emd_vnic.ev_intf);
3675 if (rc != 0)
3676 goto fail1;
3677
3678 desc->emd_vnic.ev_pf = MCDI_STRUCT_WORD(entry_buf,
3679 MAE_MPORT_DESC_V2_VNIC_FUNCTION_PF_IDX);
3680 desc->emd_vnic.ev_vf = MCDI_STRUCT_WORD(entry_buf,
3681 MAE_MPORT_DESC_V2_VNIC_FUNCTION_VF_IDX);
3682 desc->emd_vnic.ev_handle = MCDI_STRUCT_DWORD(entry_buf,
3683 MAE_MPORT_DESC_V2_VNIC_CLIENT_HANDLE);
3684 break;
3685 default:
3686 rc = EINVAL;
3687 goto fail2;
3688 }
3689
3690 return (0);
3691
3692 fail2:
3693 EFSYS_PROBE(fail2);
3694 fail1:
3695 EFSYS_PROBE1(fail1, efx_rc_t, rc);
3696 return (rc);
3697 }
3698
3699 static __checkReturn efx_rc_t
efx_mae_read_mport_journal_batch(__in efx_nic_t * enp,__in efx_mae_read_mport_journal_cb * cbp,__in void * cb_datap,__out uint32_t * morep)3700 efx_mae_read_mport_journal_batch(
3701 __in efx_nic_t *enp,
3702 __in efx_mae_read_mport_journal_cb *cbp,
3703 __in void *cb_datap,
3704 __out uint32_t *morep)
3705 {
3706 efx_mcdi_req_t req;
3707 EFX_MCDI_DECLARE_BUF(payload,
3708 MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN,
3709 MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2);
3710 uint32_t n_entries;
3711 uint32_t entry_sz;
3712 uint8_t *entry_buf;
3713 unsigned int i;
3714 efx_rc_t rc;
3715
3716 EFX_STATIC_ASSERT(EFX_MPORT_TYPE_NET_PORT ==
3717 MAE_MPORT_DESC_V2_MPORT_TYPE_NET_PORT);
3718 EFX_STATIC_ASSERT(EFX_MPORT_TYPE_ALIAS ==
3719 MAE_MPORT_DESC_V2_MPORT_TYPE_ALIAS);
3720 EFX_STATIC_ASSERT(EFX_MPORT_TYPE_VNIC ==
3721 MAE_MPORT_DESC_V2_MPORT_TYPE_VNIC);
3722
3723 EFX_STATIC_ASSERT(EFX_MPORT_VNIC_CLIENT_FUNCTION ==
3724 MAE_MPORT_DESC_V2_VNIC_CLIENT_TYPE_FUNCTION);
3725 EFX_STATIC_ASSERT(EFX_MPORT_VNIC_CLIENT_PLUGIN ==
3726 MAE_MPORT_DESC_V2_VNIC_CLIENT_TYPE_PLUGIN);
3727
3728 if (cbp == NULL) {
3729 rc = EINVAL;
3730 goto fail1;
3731 }
3732
3733 req.emr_cmd = MC_CMD_MAE_MPORT_READ_JOURNAL;
3734 req.emr_in_buf = payload;
3735 req.emr_in_length = MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN;
3736 req.emr_out_buf = payload;
3737 req.emr_out_length = MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2;
3738
3739 MCDI_IN_SET_DWORD(req, MAE_MPORT_READ_JOURNAL_IN_FLAGS, 0);
3740
3741 efx_mcdi_execute(enp, &req);
3742
3743 if (req.emr_rc != 0) {
3744 rc = req.emr_rc;
3745 goto fail2;
3746 }
3747
3748 if (req.emr_out_length_used <
3749 MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMIN) {
3750 rc = EMSGSIZE;
3751 goto fail3;
3752 }
3753
3754 if (morep != NULL) {
3755 *morep = MCDI_OUT_DWORD_FIELD(req,
3756 MAE_MPORT_READ_JOURNAL_OUT_FLAGS,
3757 MAE_MPORT_READ_JOURNAL_OUT_MORE);
3758 }
3759 n_entries = MCDI_OUT_DWORD(req,
3760 MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_COUNT);
3761 entry_sz = MCDI_OUT_DWORD(req,
3762 MAE_MPORT_READ_JOURNAL_OUT_SIZEOF_MPORT_DESC);
3763 entry_buf = MCDI_OUT2(req, uint8_t,
3764 MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA);
3765
3766 if (entry_sz < MAE_MPORT_DESC_V2_VNIC_CLIENT_HANDLE_OFST +
3767 MAE_MPORT_DESC_V2_VNIC_CLIENT_HANDLE_LEN) {
3768 rc = EINVAL;
3769 goto fail4;
3770 }
3771 if (n_entries * entry_sz / entry_sz != n_entries) {
3772 rc = EINVAL;
3773 goto fail5;
3774 }
3775 if (req.emr_out_length_used !=
3776 MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMIN + n_entries * entry_sz) {
3777 rc = EINVAL;
3778 goto fail6;
3779 }
3780
3781 for (i = 0; i < n_entries; i++) {
3782 efx_mport_desc_t desc;
3783
3784 rc = efx_mae_read_mport_journal_single(entry_buf, &desc);
3785 if (rc != 0)
3786 continue;
3787
3788 (*cbp)(cb_datap, &desc, sizeof (desc));
3789 entry_buf += entry_sz;
3790 }
3791
3792 return (0);
3793
3794 fail6:
3795 EFSYS_PROBE(fail6);
3796 fail5:
3797 EFSYS_PROBE(fail5);
3798 fail4:
3799 EFSYS_PROBE(fail4);
3800 fail3:
3801 EFSYS_PROBE(fail3);
3802 fail2:
3803 EFSYS_PROBE(fail2);
3804 fail1:
3805 EFSYS_PROBE1(fail1, efx_rc_t, rc);
3806 return (rc);
3807 }
3808
3809 __checkReturn efx_rc_t
efx_mae_read_mport_journal(__in efx_nic_t * enp,__in efx_mae_read_mport_journal_cb * cbp,__in void * cb_datap)3810 efx_mae_read_mport_journal(
3811 __in efx_nic_t *enp,
3812 __in efx_mae_read_mport_journal_cb *cbp,
3813 __in void *cb_datap)
3814 {
3815 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3816 uint32_t more = 0;
3817 efx_rc_t rc;
3818
3819 if (encp->enc_mae_supported == B_FALSE) {
3820 rc = ENOTSUP;
3821 goto fail1;
3822 }
3823
3824 do {
3825 rc = efx_mae_read_mport_journal_batch(enp, cbp, cb_datap,
3826 &more);
3827 if (rc != 0)
3828 goto fail2;
3829 } while (more != 0);
3830
3831 return (0);
3832
3833 fail2:
3834 EFSYS_PROBE(fail2);
3835 fail1:
3836 EFSYS_PROBE1(fail1, efx_rc_t, rc);
3837 return (rc);
3838 }
3839
3840 #endif /* EFSYS_OPT_MAE */
3841