xref: /dpdk/drivers/common/sfc_efx/base/efx_mae.c (revision d38febb08d57fec29fed27a2d12a507fc6fcdfa1)
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
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
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
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
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
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
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
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
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 
477 	EFX_MAE_FIELD_CAP_NIDS
478 } efx_mae_field_cap_id_t;
479 
480 typedef enum efx_mae_field_endianness_e {
481 	EFX_MAE_FIELD_LE = 0,
482 	EFX_MAE_FIELD_BE,
483 
484 	EFX_MAE_FIELD_ENDIANNESS_NTYPES
485 } efx_mae_field_endianness_t;
486 
487 /*
488  * The following structure is a means to describe an MAE field.
489  * The information in it is meant to be used internally by
490  * APIs for addressing a given field in a mask-value pairs
491  * structure and for validation purposes.
492  *
493  * A field may have an alternative one. This structure
494  * has additional members to reference the alternative
495  * field's mask. See efx_mae_match_spec_is_valid().
496  */
497 typedef struct efx_mae_mv_desc_s {
498 	efx_mae_field_cap_id_t		emmd_field_cap_id;
499 
500 	size_t				emmd_value_size;
501 	size_t				emmd_value_offset;
502 	size_t				emmd_mask_size;
503 	size_t				emmd_mask_offset;
504 
505 	/*
506 	 * Having the alternative field's mask size set to 0
507 	 * means that there's no alternative field specified.
508 	 */
509 	size_t				emmd_alt_mask_size;
510 	size_t				emmd_alt_mask_offset;
511 
512 	/* Primary field and the alternative one are of the same endianness. */
513 	efx_mae_field_endianness_t	emmd_endianness;
514 } efx_mae_mv_desc_t;
515 
516 /* Indices to this array are provided by efx_mae_field_id_t */
517 static const efx_mae_mv_desc_t __efx_mae_action_rule_mv_desc_set[] = {
518 #define	EFX_MAE_MV_DESC(_name, _endianness)				\
519 	[EFX_MAE_FIELD_##_name] =					\
520 	{								\
521 		EFX_MAE_FIELD_ID_##_name,				\
522 		MAE_FIELD_MASK_VALUE_PAIRS_##_name##_LEN,		\
523 		MAE_FIELD_MASK_VALUE_PAIRS_##_name##_OFST,		\
524 		MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_LEN,		\
525 		MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_OFST,		\
526 		0, 0 /* no alternative field */,			\
527 		_endianness						\
528 	}
529 
530 	EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
531 	EFX_MAE_MV_DESC(ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
532 	EFX_MAE_MV_DESC(ETH_SADDR_BE, EFX_MAE_FIELD_BE),
533 	EFX_MAE_MV_DESC(ETH_DADDR_BE, EFX_MAE_FIELD_BE),
534 	EFX_MAE_MV_DESC(VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
535 	EFX_MAE_MV_DESC(VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
536 	EFX_MAE_MV_DESC(VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
537 	EFX_MAE_MV_DESC(VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
538 	EFX_MAE_MV_DESC(SRC_IP4_BE, EFX_MAE_FIELD_BE),
539 	EFX_MAE_MV_DESC(DST_IP4_BE, EFX_MAE_FIELD_BE),
540 	EFX_MAE_MV_DESC(IP_PROTO, EFX_MAE_FIELD_BE),
541 	EFX_MAE_MV_DESC(IP_TOS, EFX_MAE_FIELD_BE),
542 	EFX_MAE_MV_DESC(IP_TTL, EFX_MAE_FIELD_BE),
543 	EFX_MAE_MV_DESC(SRC_IP6_BE, EFX_MAE_FIELD_BE),
544 	EFX_MAE_MV_DESC(DST_IP6_BE, EFX_MAE_FIELD_BE),
545 	EFX_MAE_MV_DESC(L4_SPORT_BE, EFX_MAE_FIELD_BE),
546 	EFX_MAE_MV_DESC(L4_DPORT_BE, EFX_MAE_FIELD_BE),
547 	EFX_MAE_MV_DESC(TCP_FLAGS_BE, EFX_MAE_FIELD_BE),
548 	EFX_MAE_MV_DESC(ENC_VNET_ID_BE, EFX_MAE_FIELD_BE),
549 	EFX_MAE_MV_DESC(OUTER_RULE_ID, EFX_MAE_FIELD_LE),
550 
551 #undef EFX_MAE_MV_DESC
552 };
553 
554 /* Indices to this array are provided by efx_mae_field_id_t */
555 static const efx_mae_mv_desc_t __efx_mae_outer_rule_mv_desc_set[] = {
556 #define	EFX_MAE_MV_DESC(_name, _endianness)				\
557 	[EFX_MAE_FIELD_##_name] =					\
558 	{								\
559 		EFX_MAE_FIELD_ID_##_name,				\
560 		MAE_ENC_FIELD_PAIRS_##_name##_LEN,			\
561 		MAE_ENC_FIELD_PAIRS_##_name##_OFST,			\
562 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,			\
563 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,		\
564 		0, 0 /* no alternative field */,			\
565 		_endianness						\
566 	}
567 
568 /* Same as EFX_MAE_MV_DESC(), but also indicates an alternative field. */
569 #define	EFX_MAE_MV_DESC_ALT(_name, _alt_name, _endianness)		\
570 	[EFX_MAE_FIELD_##_name] =					\
571 	{								\
572 		EFX_MAE_FIELD_ID_##_name,				\
573 		MAE_ENC_FIELD_PAIRS_##_name##_LEN,			\
574 		MAE_ENC_FIELD_PAIRS_##_name##_OFST,			\
575 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,			\
576 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,		\
577 		MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_LEN,		\
578 		MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_OFST,		\
579 		_endianness						\
580 	}
581 
582 	EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
583 	EFX_MAE_MV_DESC(ENC_ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
584 	EFX_MAE_MV_DESC(ENC_ETH_SADDR_BE, EFX_MAE_FIELD_BE),
585 	EFX_MAE_MV_DESC(ENC_ETH_DADDR_BE, EFX_MAE_FIELD_BE),
586 	EFX_MAE_MV_DESC(ENC_VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
587 	EFX_MAE_MV_DESC(ENC_VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
588 	EFX_MAE_MV_DESC(ENC_VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
589 	EFX_MAE_MV_DESC(ENC_VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
590 	EFX_MAE_MV_DESC_ALT(ENC_SRC_IP4_BE, ENC_SRC_IP6_BE, EFX_MAE_FIELD_BE),
591 	EFX_MAE_MV_DESC_ALT(ENC_DST_IP4_BE, ENC_DST_IP6_BE, EFX_MAE_FIELD_BE),
592 	EFX_MAE_MV_DESC(ENC_IP_PROTO, EFX_MAE_FIELD_BE),
593 	EFX_MAE_MV_DESC(ENC_IP_TOS, EFX_MAE_FIELD_BE),
594 	EFX_MAE_MV_DESC(ENC_IP_TTL, EFX_MAE_FIELD_BE),
595 	EFX_MAE_MV_DESC_ALT(ENC_SRC_IP6_BE, ENC_SRC_IP4_BE, EFX_MAE_FIELD_BE),
596 	EFX_MAE_MV_DESC_ALT(ENC_DST_IP6_BE, ENC_DST_IP4_BE, EFX_MAE_FIELD_BE),
597 	EFX_MAE_MV_DESC(ENC_L4_SPORT_BE, EFX_MAE_FIELD_BE),
598 	EFX_MAE_MV_DESC(ENC_L4_DPORT_BE, EFX_MAE_FIELD_BE),
599 
600 #undef EFX_MAE_MV_DESC_ALT
601 #undef EFX_MAE_MV_DESC
602 };
603 
604 /*
605  * The following structure is a means to describe an MAE bit.
606  * The information in it is meant to be used internally by
607  * APIs for addressing a given flag in a mask-value pairs
608  * structure and for validation purposes.
609  */
610 typedef struct efx_mae_mv_bit_desc_s {
611 	/*
612 	 * Arrays using this struct are indexed by field IDs.
613 	 * Fields which aren't meant to be referenced by these
614 	 * arrays comprise gaps (invalid entries). Below field
615 	 * helps to identify such entries.
616 	 */
617 	boolean_t			emmbd_entry_is_valid;
618 	efx_mae_field_cap_id_t		emmbd_bit_cap_id;
619 	size_t				emmbd_value_ofst;
620 	unsigned int			emmbd_value_lbn;
621 	size_t				emmbd_mask_ofst;
622 	unsigned int			emmbd_mask_lbn;
623 } efx_mae_mv_bit_desc_t;
624 
625 static const efx_mae_mv_bit_desc_t __efx_mae_outer_rule_mv_bit_desc_set[] = {
626 #define	EFX_MAE_MV_BIT_DESC(_name)					\
627 	[EFX_MAE_FIELD_##_name] =					\
628 	{								\
629 		B_TRUE,							\
630 		EFX_MAE_FIELD_ID_##_name,				\
631 		MAE_ENC_FIELD_PAIRS_##_name##_OFST,			\
632 		MAE_ENC_FIELD_PAIRS_##_name##_LBN,			\
633 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,		\
634 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_LBN,			\
635 	}
636 
637 	EFX_MAE_MV_BIT_DESC(ENC_HAS_OVLAN),
638 	EFX_MAE_MV_BIT_DESC(ENC_HAS_IVLAN),
639 
640 #undef EFX_MAE_MV_BIT_DESC
641 };
642 
643 static const efx_mae_mv_bit_desc_t __efx_mae_action_rule_mv_bit_desc_set[] = {
644 #define	EFX_MAE_MV_BIT_DESC(_name)					\
645 	[EFX_MAE_FIELD_##_name] =					\
646 	{								\
647 		B_TRUE,							\
648 		EFX_MAE_FIELD_ID_##_name,				\
649 		MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_OFST,		\
650 		MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LBN,		\
651 		MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK_OFST,		\
652 		MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LBN,		\
653 	}
654 
655 	EFX_MAE_MV_BIT_DESC(HAS_OVLAN),
656 	EFX_MAE_MV_BIT_DESC(HAS_IVLAN),
657 	EFX_MAE_MV_BIT_DESC(ENC_HAS_OVLAN),
658 	EFX_MAE_MV_BIT_DESC(ENC_HAS_IVLAN),
659 
660 #undef EFX_MAE_MV_BIT_DESC
661 };
662 
663 	__checkReturn			efx_rc_t
664 efx_mae_mport_by_phy_port(
665 	__in				uint32_t phy_port,
666 	__out				efx_mport_sel_t *mportp)
667 {
668 	efx_dword_t dword;
669 	efx_rc_t rc;
670 
671 	if (phy_port > EFX_MASK32(MAE_MPORT_SELECTOR_PPORT_ID)) {
672 		rc = EINVAL;
673 		goto fail1;
674 	}
675 
676 	EFX_POPULATE_DWORD_2(dword,
677 	    MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT,
678 	    MAE_MPORT_SELECTOR_PPORT_ID, phy_port);
679 
680 	memset(mportp, 0, sizeof (*mportp));
681 	/*
682 	 * The constructed DWORD is little-endian,
683 	 * but the resulting value is meant to be
684 	 * passed to MCDIs, where it will undergo
685 	 * host-order to little endian conversion.
686 	 */
687 	mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
688 
689 	return (0);
690 
691 fail1:
692 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
693 	return (rc);
694 }
695 
696 	__checkReturn			efx_rc_t
697 efx_mae_mport_by_pcie_function(
698 	__in				uint32_t pf,
699 	__in				uint32_t vf,
700 	__out				efx_mport_sel_t *mportp)
701 {
702 	efx_dword_t dword;
703 	efx_rc_t rc;
704 
705 	EFX_STATIC_ASSERT(EFX_PCI_VF_INVALID ==
706 	    MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL);
707 
708 	if (pf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_PF_ID)) {
709 		rc = EINVAL;
710 		goto fail1;
711 	}
712 
713 	if (vf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_VF_ID)) {
714 		rc = EINVAL;
715 		goto fail2;
716 	}
717 
718 	EFX_POPULATE_DWORD_3(dword,
719 	    MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
720 	    MAE_MPORT_SELECTOR_FUNC_PF_ID, pf,
721 	    MAE_MPORT_SELECTOR_FUNC_VF_ID, vf);
722 
723 	memset(mportp, 0, sizeof (*mportp));
724 	/*
725 	 * The constructed DWORD is little-endian,
726 	 * but the resulting value is meant to be
727 	 * passed to MCDIs, where it will undergo
728 	 * host-order to little endian conversion.
729 	 */
730 	mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
731 
732 	return (0);
733 
734 fail2:
735 	EFSYS_PROBE(fail2);
736 fail1:
737 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
738 	return (rc);
739 }
740 
741 	__checkReturn			efx_rc_t
742 efx_mae_match_spec_field_set(
743 	__in				efx_mae_match_spec_t *spec,
744 	__in				efx_mae_field_id_t field_id,
745 	__in				size_t value_size,
746 	__in_bcount(value_size)		const uint8_t *value,
747 	__in				size_t mask_size,
748 	__in_bcount(mask_size)		const uint8_t *mask)
749 {
750 	const efx_mae_mv_desc_t *descp;
751 	unsigned int desc_set_nentries;
752 	uint8_t *mvp;
753 	efx_rc_t rc;
754 
755 	switch (spec->emms_type) {
756 	case EFX_MAE_RULE_OUTER:
757 		desc_set_nentries =
758 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
759 		descp = &__efx_mae_outer_rule_mv_desc_set[field_id];
760 		mvp = spec->emms_mask_value_pairs.outer;
761 		break;
762 	case EFX_MAE_RULE_ACTION:
763 		desc_set_nentries =
764 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
765 		descp = &__efx_mae_action_rule_mv_desc_set[field_id];
766 		mvp = spec->emms_mask_value_pairs.action;
767 		break;
768 	default:
769 		rc = ENOTSUP;
770 		goto fail1;
771 	}
772 
773 	if ((unsigned int)field_id >= desc_set_nentries) {
774 		rc = EINVAL;
775 		goto fail2;
776 	}
777 
778 	if (descp->emmd_mask_size == 0) {
779 		/* The ID points to a gap in the array of field descriptors. */
780 		rc = EINVAL;
781 		goto fail3;
782 	}
783 
784 	if (value_size != descp->emmd_value_size) {
785 		rc = EINVAL;
786 		goto fail4;
787 	}
788 
789 	if (mask_size != descp->emmd_mask_size) {
790 		rc = EINVAL;
791 		goto fail5;
792 	}
793 
794 	if (descp->emmd_endianness == EFX_MAE_FIELD_BE) {
795 		unsigned int i;
796 
797 		/*
798 		 * The mask/value are in network (big endian) order.
799 		 * The MCDI request field is also big endian.
800 		 */
801 
802 		EFSYS_ASSERT3U(value_size, ==, mask_size);
803 
804 		for (i = 0; i < value_size; ++i) {
805 			uint8_t *v_bytep = mvp + descp->emmd_value_offset + i;
806 			uint8_t *m_bytep = mvp + descp->emmd_mask_offset + i;
807 
808 			/*
809 			 * Apply the mask (which may be all-zeros) to the value.
810 			 *
811 			 * If this API is provided with some value to set for a
812 			 * given field in one specification and with some other
813 			 * value to set for this field in another specification,
814 			 * then, if the two masks are all-zeros, the field will
815 			 * avoid being counted as a mismatch when comparing the
816 			 * specifications using efx_mae_match_specs_equal() API.
817 			 */
818 			*v_bytep = value[i] & mask[i];
819 			*m_bytep = mask[i];
820 		}
821 	} else {
822 		efx_dword_t dword;
823 
824 		/*
825 		 * The mask/value are in host byte order.
826 		 * The MCDI request field is little endian.
827 		 */
828 		switch (value_size) {
829 		case 4:
830 			EFX_POPULATE_DWORD_1(dword,
831 			    EFX_DWORD_0, *(const uint32_t *)value);
832 
833 			memcpy(mvp + descp->emmd_value_offset,
834 			    &dword, sizeof (dword));
835 			break;
836 		default:
837 			EFSYS_ASSERT(B_FALSE);
838 		}
839 
840 		switch (mask_size) {
841 		case 4:
842 			EFX_POPULATE_DWORD_1(dword,
843 			    EFX_DWORD_0, *(const uint32_t *)mask);
844 
845 			memcpy(mvp + descp->emmd_mask_offset,
846 			    &dword, sizeof (dword));
847 			break;
848 		default:
849 			EFSYS_ASSERT(B_FALSE);
850 		}
851 	}
852 
853 	return (0);
854 
855 fail5:
856 	EFSYS_PROBE(fail5);
857 fail4:
858 	EFSYS_PROBE(fail4);
859 fail3:
860 	EFSYS_PROBE(fail3);
861 fail2:
862 	EFSYS_PROBE(fail2);
863 fail1:
864 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
865 	return (rc);
866 }
867 
868 	__checkReturn			efx_rc_t
869 efx_mae_match_spec_bit_set(
870 	__in				efx_mae_match_spec_t *spec,
871 	__in				efx_mae_field_id_t field_id,
872 	__in				boolean_t value)
873 {
874 	const efx_mae_mv_bit_desc_t *bit_descp;
875 	unsigned int bit_desc_set_nentries;
876 	unsigned int byte_idx;
877 	unsigned int bit_idx;
878 	uint8_t *mvp;
879 	efx_rc_t rc;
880 
881 	switch (spec->emms_type) {
882 	case EFX_MAE_RULE_OUTER:
883 		bit_desc_set_nentries =
884 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
885 		bit_descp = &__efx_mae_outer_rule_mv_bit_desc_set[field_id];
886 		mvp = spec->emms_mask_value_pairs.outer;
887 		break;
888 	case EFX_MAE_RULE_ACTION:
889 		bit_desc_set_nentries =
890 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
891 		bit_descp = &__efx_mae_action_rule_mv_bit_desc_set[field_id];
892 		mvp = spec->emms_mask_value_pairs.action;
893 		break;
894 	default:
895 		rc = ENOTSUP;
896 		goto fail1;
897 	}
898 
899 	if ((unsigned int)field_id >= bit_desc_set_nentries) {
900 		rc = EINVAL;
901 		goto fail2;
902 	}
903 
904 	if (bit_descp->emmbd_entry_is_valid == B_FALSE) {
905 		rc = EINVAL;
906 		goto fail3;
907 	}
908 
909 	byte_idx = bit_descp->emmbd_value_ofst + bit_descp->emmbd_value_lbn / 8;
910 	bit_idx = bit_descp->emmbd_value_lbn % 8;
911 
912 	if (value != B_FALSE)
913 		mvp[byte_idx] |= (1U << bit_idx);
914 	else
915 		mvp[byte_idx] &= ~(1U << bit_idx);
916 
917 	byte_idx = bit_descp->emmbd_mask_ofst + bit_descp->emmbd_mask_lbn / 8;
918 	bit_idx = bit_descp->emmbd_mask_lbn % 8;
919 	mvp[byte_idx] |= (1U << bit_idx);
920 
921 	return (0);
922 
923 fail3:
924 	EFSYS_PROBE(fail3);
925 fail2:
926 	EFSYS_PROBE(fail2);
927 fail1:
928 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
929 	return (rc);
930 }
931 
932 	__checkReturn			efx_rc_t
933 efx_mae_match_spec_mport_set(
934 	__in				efx_mae_match_spec_t *spec,
935 	__in				const efx_mport_sel_t *valuep,
936 	__in_opt			const efx_mport_sel_t *maskp)
937 {
938 	uint32_t full_mask = UINT32_MAX;
939 	const uint8_t *vp;
940 	const uint8_t *mp;
941 	efx_rc_t rc;
942 
943 	if (valuep == NULL) {
944 		rc = EINVAL;
945 		goto fail1;
946 	}
947 
948 	vp = (const uint8_t *)&valuep->sel;
949 	if (maskp != NULL)
950 		mp = (const uint8_t *)&maskp->sel;
951 	else
952 		mp = (const uint8_t *)&full_mask;
953 
954 	rc = efx_mae_match_spec_field_set(spec,
955 	    EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR,
956 	    sizeof (valuep->sel), vp, sizeof (maskp->sel), mp);
957 	if (rc != 0)
958 		goto fail2;
959 
960 	return (0);
961 
962 fail2:
963 	EFSYS_PROBE(fail2);
964 fail1:
965 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
966 	return (rc);
967 }
968 
969 	__checkReturn			boolean_t
970 efx_mae_match_specs_equal(
971 	__in				const efx_mae_match_spec_t *left,
972 	__in				const efx_mae_match_spec_t *right)
973 {
974 	return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
975 }
976 
977 #define	EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit)		\
978 	    ((_mask)[(_bit) / (_mask_page_nbits)] &			\
979 		    (1ULL << ((_bit) & ((_mask_page_nbits) - 1))))
980 
981 static					boolean_t
982 efx_mask_is_prefix(
983 	__in				size_t mask_nbytes,
984 	__in_bcount(mask_nbytes)	const uint8_t *maskp)
985 {
986 	boolean_t prev_bit_is_set = B_TRUE;
987 	unsigned int i;
988 
989 	for (i = 0; i < 8 * mask_nbytes; ++i) {
990 		boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i);
991 
992 		if (!prev_bit_is_set && bit_is_set)
993 			return B_FALSE;
994 
995 		prev_bit_is_set = bit_is_set;
996 	}
997 
998 	return B_TRUE;
999 }
1000 
1001 static					boolean_t
1002 efx_mask_is_all_ones(
1003 	__in				size_t mask_nbytes,
1004 	__in_bcount(mask_nbytes)	const uint8_t *maskp)
1005 {
1006 	unsigned int i;
1007 	uint8_t t = ~0;
1008 
1009 	for (i = 0; i < mask_nbytes; ++i)
1010 		t &= maskp[i];
1011 
1012 	return (t == (uint8_t)(~0));
1013 }
1014 
1015 static					boolean_t
1016 efx_mask_is_all_zeros(
1017 	__in				size_t mask_nbytes,
1018 	__in_bcount(mask_nbytes)	const uint8_t *maskp)
1019 {
1020 	unsigned int i;
1021 	uint8_t t = 0;
1022 
1023 	for (i = 0; i < mask_nbytes; ++i)
1024 		t |= maskp[i];
1025 
1026 	return (t == 0);
1027 }
1028 
1029 	__checkReturn			boolean_t
1030 efx_mae_match_spec_is_valid(
1031 	__in				efx_nic_t *enp,
1032 	__in				const efx_mae_match_spec_t *spec)
1033 {
1034 	efx_mae_t *maep = enp->en_maep;
1035 	unsigned int field_ncaps = maep->em_max_nfields;
1036 	const efx_mae_field_cap_t *field_caps;
1037 	const efx_mae_mv_desc_t *desc_setp;
1038 	unsigned int desc_set_nentries;
1039 	const efx_mae_mv_bit_desc_t *bit_desc_setp;
1040 	unsigned int bit_desc_set_nentries;
1041 	boolean_t is_valid = B_TRUE;
1042 	efx_mae_field_id_t field_id;
1043 	const uint8_t *mvp;
1044 
1045 	switch (spec->emms_type) {
1046 	case EFX_MAE_RULE_OUTER:
1047 		field_caps = maep->em_outer_rule_field_caps;
1048 		desc_setp = __efx_mae_outer_rule_mv_desc_set;
1049 		desc_set_nentries =
1050 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1051 		bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
1052 		bit_desc_set_nentries =
1053 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
1054 		mvp = spec->emms_mask_value_pairs.outer;
1055 		break;
1056 	case EFX_MAE_RULE_ACTION:
1057 		field_caps = maep->em_action_rule_field_caps;
1058 		desc_setp = __efx_mae_action_rule_mv_desc_set;
1059 		desc_set_nentries =
1060 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1061 		bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
1062 		bit_desc_set_nentries =
1063 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
1064 		mvp = spec->emms_mask_value_pairs.action;
1065 		break;
1066 	default:
1067 		return (B_FALSE);
1068 	}
1069 
1070 	if (field_caps == NULL)
1071 		return (B_FALSE);
1072 
1073 	for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1074 	     ++field_id) {
1075 		const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1076 		efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1077 		const uint8_t *alt_m_buf = mvp + descp->emmd_alt_mask_offset;
1078 		const uint8_t *m_buf = mvp + descp->emmd_mask_offset;
1079 		size_t alt_m_size = descp->emmd_alt_mask_size;
1080 		size_t m_size = descp->emmd_mask_size;
1081 
1082 		if (m_size == 0)
1083 			continue; /* Skip array gap */
1084 
1085 		if ((unsigned int)field_cap_id >= field_ncaps) {
1086 			/*
1087 			 * The FW has not reported capability status for
1088 			 * this field. Make sure that its mask is zeroed.
1089 			 */
1090 			is_valid = efx_mask_is_all_zeros(m_size, m_buf);
1091 			if (is_valid != B_FALSE)
1092 				continue;
1093 			else
1094 				break;
1095 		}
1096 
1097 		switch (field_caps[field_cap_id].emfc_support) {
1098 		case MAE_FIELD_SUPPORTED_MATCH_MASK:
1099 			is_valid = B_TRUE;
1100 			break;
1101 		case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
1102 			is_valid = efx_mask_is_prefix(m_size, m_buf);
1103 			break;
1104 		case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
1105 			is_valid = (efx_mask_is_all_ones(m_size, m_buf) ||
1106 			    efx_mask_is_all_zeros(m_size, m_buf));
1107 			break;
1108 		case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
1109 			is_valid = efx_mask_is_all_ones(m_size, m_buf);
1110 
1111 			if ((is_valid == B_FALSE) && (alt_m_size != 0)) {
1112 				/*
1113 				 * This field has an alternative one. The FW
1114 				 * reports ALWAYS for both implying that one
1115 				 * of them is required to have all-ones mask.
1116 				 *
1117 				 * The primary field's mask is incorrect; go
1118 				 * on to check that of the alternative field.
1119 				 */
1120 				is_valid = efx_mask_is_all_ones(alt_m_size,
1121 								alt_m_buf);
1122 			}
1123 			break;
1124 		case MAE_FIELD_SUPPORTED_MATCH_NEVER:
1125 		case MAE_FIELD_UNSUPPORTED:
1126 		default:
1127 			is_valid = efx_mask_is_all_zeros(m_size, m_buf);
1128 			break;
1129 		}
1130 
1131 		if (is_valid == B_FALSE)
1132 			return (B_FALSE);
1133 	}
1134 
1135 	for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
1136 	     ++field_id) {
1137 		const efx_mae_mv_bit_desc_t *bit_descp =
1138 		    &bit_desc_setp[field_id];
1139 		unsigned int byte_idx =
1140 		    bit_descp->emmbd_mask_ofst +
1141 		    bit_descp->emmbd_mask_lbn / 8;
1142 		unsigned int bit_idx =
1143 		    bit_descp->emmbd_mask_lbn % 8;
1144 		efx_mae_field_cap_id_t bit_cap_id =
1145 		    bit_descp->emmbd_bit_cap_id;
1146 
1147 		if (bit_descp->emmbd_entry_is_valid == B_FALSE)
1148 			continue; /* Skip array gap */
1149 
1150 		if ((unsigned int)bit_cap_id >= field_ncaps) {
1151 			/* No capability for this bit = unsupported. */
1152 			is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0);
1153 			if (is_valid == B_FALSE)
1154 				break;
1155 			else
1156 				continue;
1157 		}
1158 
1159 		switch (field_caps[bit_cap_id].emfc_support) {
1160 		case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
1161 			is_valid = B_TRUE;
1162 			break;
1163 		case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
1164 			is_valid = ((mvp[byte_idx] & (1U << bit_idx)) != 0);
1165 			break;
1166 		case MAE_FIELD_SUPPORTED_MATCH_NEVER:
1167 		case MAE_FIELD_UNSUPPORTED:
1168 		default:
1169 			is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0);
1170 			break;
1171 		}
1172 
1173 		if (is_valid == B_FALSE)
1174 			break;
1175 	}
1176 
1177 	return (is_valid);
1178 }
1179 
1180 	__checkReturn			efx_rc_t
1181 efx_mae_action_set_spec_init(
1182 	__in				efx_nic_t *enp,
1183 	__out				efx_mae_actions_t **specp)
1184 {
1185 	efx_mae_actions_t *spec;
1186 	efx_rc_t rc;
1187 
1188 	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
1189 	if (spec == NULL) {
1190 		rc = ENOMEM;
1191 		goto fail1;
1192 	}
1193 
1194 	spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
1195 	spec->ema_rsrc.emar_counter_id.id = EFX_MAE_RSRC_ID_INVALID;
1196 
1197 	*specp = spec;
1198 
1199 	return (0);
1200 
1201 fail1:
1202 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1203 	return (rc);
1204 }
1205 
1206 					void
1207 efx_mae_action_set_spec_fini(
1208 	__in				efx_nic_t *enp,
1209 	__in				efx_mae_actions_t *spec)
1210 {
1211 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
1212 }
1213 
1214 static	__checkReturn			efx_rc_t
1215 efx_mae_action_set_add_decap(
1216 	__in				efx_mae_actions_t *spec,
1217 	__in				size_t arg_size,
1218 	__in_bcount(arg_size)		const uint8_t *arg)
1219 {
1220 	efx_rc_t rc;
1221 
1222 	_NOTE(ARGUNUSED(spec))
1223 
1224 	if (arg_size != 0) {
1225 		rc = EINVAL;
1226 		goto fail1;
1227 	}
1228 
1229 	if (arg != NULL) {
1230 		rc = EINVAL;
1231 		goto fail2;
1232 	}
1233 
1234 	/* This action does not have any arguments, so do nothing here. */
1235 
1236 	return (0);
1237 
1238 fail2:
1239 	EFSYS_PROBE(fail2);
1240 fail1:
1241 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1242 	return (rc);
1243 }
1244 
1245 static	__checkReturn			efx_rc_t
1246 efx_mae_action_set_add_vlan_pop(
1247 	__in				efx_mae_actions_t *spec,
1248 	__in				size_t arg_size,
1249 	__in_bcount(arg_size)		const uint8_t *arg)
1250 {
1251 	efx_rc_t rc;
1252 
1253 	if (arg_size != 0) {
1254 		rc = EINVAL;
1255 		goto fail1;
1256 	}
1257 
1258 	if (arg != NULL) {
1259 		rc = EINVAL;
1260 		goto fail2;
1261 	}
1262 
1263 	if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) {
1264 		rc = ENOTSUP;
1265 		goto fail3;
1266 	}
1267 
1268 	++spec->ema_n_vlan_tags_to_pop;
1269 
1270 	return (0);
1271 
1272 fail3:
1273 	EFSYS_PROBE(fail3);
1274 fail2:
1275 	EFSYS_PROBE(fail2);
1276 fail1:
1277 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1278 	return (rc);
1279 }
1280 
1281 static	__checkReturn			efx_rc_t
1282 efx_mae_action_set_add_vlan_push(
1283 	__in				efx_mae_actions_t *spec,
1284 	__in				size_t arg_size,
1285 	__in_bcount(arg_size)		const uint8_t *arg)
1286 {
1287 	unsigned int n_tags = spec->ema_n_vlan_tags_to_push;
1288 	efx_rc_t rc;
1289 
1290 	if (arg_size != sizeof (*spec->ema_vlan_push_descs)) {
1291 		rc = EINVAL;
1292 		goto fail1;
1293 	}
1294 
1295 	if (arg == NULL) {
1296 		rc = EINVAL;
1297 		goto fail2;
1298 	}
1299 
1300 	if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1301 		rc = ENOTSUP;
1302 		goto fail3;
1303 	}
1304 
1305 	memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size);
1306 	++(spec->ema_n_vlan_tags_to_push);
1307 
1308 	return (0);
1309 
1310 fail3:
1311 	EFSYS_PROBE(fail3);
1312 fail2:
1313 	EFSYS_PROBE(fail2);
1314 fail1:
1315 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1316 	return (rc);
1317 }
1318 
1319 static	__checkReturn			efx_rc_t
1320 efx_mae_action_set_add_encap(
1321 	__in				efx_mae_actions_t *spec,
1322 	__in				size_t arg_size,
1323 	__in_bcount(arg_size)		const uint8_t *arg)
1324 {
1325 	efx_rc_t rc;
1326 
1327 	/*
1328 	 * Adding this specific action to an action set spec and setting encap.
1329 	 * header ID in the spec are two individual steps. This design allows
1330 	 * the client driver to avoid encap. header allocation when it simply
1331 	 * needs to check the order of actions submitted by user ("validate"),
1332 	 * without actually allocating an action set and inserting a rule.
1333 	 *
1334 	 * For now, mark encap. header ID as invalid; the caller will invoke
1335 	 * efx_mae_action_set_fill_in_eh_id() to override the field prior
1336 	 * to action set allocation; otherwise, the allocation will fail.
1337 	 */
1338 	spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
1339 
1340 	/*
1341 	 * As explained above, there are no arguments to handle here.
1342 	 * efx_mae_action_set_fill_in_eh_id() will take care of them.
1343 	 */
1344 	if (arg_size != 0) {
1345 		rc = EINVAL;
1346 		goto fail1;
1347 	}
1348 
1349 	if (arg != NULL) {
1350 		rc = EINVAL;
1351 		goto fail2;
1352 	}
1353 
1354 	return (0);
1355 
1356 fail2:
1357 	EFSYS_PROBE(fail2);
1358 fail1:
1359 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1360 	return (rc);
1361 }
1362 
1363 static	__checkReturn			efx_rc_t
1364 efx_mae_action_set_add_count(
1365 	__in				efx_mae_actions_t *spec,
1366 	__in				size_t arg_size,
1367 	__in_bcount(arg_size)		const uint8_t *arg)
1368 {
1369 	efx_rc_t rc;
1370 
1371 	EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1372 			  MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL);
1373 
1374 	/*
1375 	 * Preparing an action set spec to update a counter requires
1376 	 * two steps: first add this action to the action spec, and then
1377 	 * add the counter ID to the spec. This allows validity checking
1378 	 * and resource allocation to be done separately.
1379 	 * Mark the counter ID as invalid in the spec to ensure that the
1380 	 * caller must also invoke efx_mae_action_set_fill_in_counter_id()
1381 	 * before action set allocation.
1382 	 */
1383 	spec->ema_rsrc.emar_counter_id.id = EFX_MAE_RSRC_ID_INVALID;
1384 
1385 	/* Nothing else is supposed to take place over here. */
1386 	if (arg_size != 0) {
1387 		rc = EINVAL;
1388 		goto fail1;
1389 	}
1390 
1391 	if (arg != NULL) {
1392 		rc = EINVAL;
1393 		goto fail2;
1394 	}
1395 
1396 	++(spec->ema_n_count_actions);
1397 
1398 	return (0);
1399 
1400 fail2:
1401 	EFSYS_PROBE(fail2);
1402 fail1:
1403 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1404 	return (rc);
1405 }
1406 
1407 static	__checkReturn			efx_rc_t
1408 efx_mae_action_set_add_flag(
1409 	__in				efx_mae_actions_t *spec,
1410 	__in				size_t arg_size,
1411 	__in_bcount(arg_size)		const uint8_t *arg)
1412 {
1413 	efx_rc_t rc;
1414 
1415 	_NOTE(ARGUNUSED(spec))
1416 
1417 	if (arg_size != 0) {
1418 		rc = EINVAL;
1419 		goto fail1;
1420 	}
1421 
1422 	if (arg != NULL) {
1423 		rc = EINVAL;
1424 		goto fail2;
1425 	}
1426 
1427 	/* This action does not have any arguments, so do nothing here. */
1428 
1429 	return (0);
1430 
1431 fail2:
1432 	EFSYS_PROBE(fail2);
1433 fail1:
1434 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1435 	return (rc);
1436 }
1437 
1438 static	__checkReturn			efx_rc_t
1439 efx_mae_action_set_add_mark(
1440 	__in				efx_mae_actions_t *spec,
1441 	__in				size_t arg_size,
1442 	__in_bcount(arg_size)		const uint8_t *arg)
1443 {
1444 	efx_rc_t rc;
1445 
1446 	if (arg_size != sizeof (spec->ema_mark_value)) {
1447 		rc = EINVAL;
1448 		goto fail1;
1449 	}
1450 
1451 	if (arg == NULL) {
1452 		rc = EINVAL;
1453 		goto fail2;
1454 	}
1455 
1456 	memcpy(&spec->ema_mark_value, arg, arg_size);
1457 
1458 	return (0);
1459 
1460 fail2:
1461 	EFSYS_PROBE(fail2);
1462 fail1:
1463 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1464 	return (rc);
1465 }
1466 
1467 static	__checkReturn			efx_rc_t
1468 efx_mae_action_set_add_deliver(
1469 	__in				efx_mae_actions_t *spec,
1470 	__in				size_t arg_size,
1471 	__in_bcount(arg_size)		const uint8_t *arg)
1472 {
1473 	efx_rc_t rc;
1474 
1475 	if (arg_size != sizeof (spec->ema_deliver_mport)) {
1476 		rc = EINVAL;
1477 		goto fail1;
1478 	}
1479 
1480 	if (arg == NULL) {
1481 		rc = EINVAL;
1482 		goto fail2;
1483 	}
1484 
1485 	memcpy(&spec->ema_deliver_mport, arg, arg_size);
1486 
1487 	return (0);
1488 
1489 fail2:
1490 	EFSYS_PROBE(fail2);
1491 fail1:
1492 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1493 	return (rc);
1494 }
1495 
1496 typedef struct efx_mae_action_desc_s {
1497 	/* Action specific handler */
1498 	efx_rc_t	(*emad_add)(efx_mae_actions_t *,
1499 				    size_t, const uint8_t *);
1500 } efx_mae_action_desc_t;
1501 
1502 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
1503 	[EFX_MAE_ACTION_DECAP] = {
1504 		.emad_add = efx_mae_action_set_add_decap
1505 	},
1506 	[EFX_MAE_ACTION_VLAN_POP] = {
1507 		.emad_add = efx_mae_action_set_add_vlan_pop
1508 	},
1509 	[EFX_MAE_ACTION_VLAN_PUSH] = {
1510 		.emad_add = efx_mae_action_set_add_vlan_push
1511 	},
1512 	[EFX_MAE_ACTION_ENCAP] = {
1513 		.emad_add = efx_mae_action_set_add_encap
1514 	},
1515 	[EFX_MAE_ACTION_COUNT] = {
1516 		.emad_add = efx_mae_action_set_add_count
1517 	},
1518 	[EFX_MAE_ACTION_FLAG] = {
1519 		.emad_add = efx_mae_action_set_add_flag
1520 	},
1521 	[EFX_MAE_ACTION_MARK] = {
1522 		.emad_add = efx_mae_action_set_add_mark
1523 	},
1524 	[EFX_MAE_ACTION_DELIVER] = {
1525 		.emad_add = efx_mae_action_set_add_deliver
1526 	}
1527 };
1528 
1529 static const uint32_t efx_mae_action_ordered_map =
1530 	(1U << EFX_MAE_ACTION_DECAP) |
1531 	(1U << EFX_MAE_ACTION_VLAN_POP) |
1532 	(1U << EFX_MAE_ACTION_VLAN_PUSH) |
1533 	/*
1534 	 * HW will conduct action COUNT after
1535 	 * the matching packet has been modified by
1536 	 * length-affecting actions except for ENCAP.
1537 	 */
1538 	(1U << EFX_MAE_ACTION_COUNT) |
1539 	(1U << EFX_MAE_ACTION_ENCAP) |
1540 	(1U << EFX_MAE_ACTION_FLAG) |
1541 	(1U << EFX_MAE_ACTION_MARK) |
1542 	(1U << EFX_MAE_ACTION_DELIVER);
1543 
1544 /*
1545  * These actions must not be added after DELIVER, but
1546  * they can have any place among the rest of
1547  * strictly ordered actions.
1548  */
1549 static const uint32_t efx_mae_action_nonstrict_map =
1550 	(1U << EFX_MAE_ACTION_COUNT) |
1551 	(1U << EFX_MAE_ACTION_FLAG) |
1552 	(1U << EFX_MAE_ACTION_MARK);
1553 
1554 static const uint32_t efx_mae_action_repeat_map =
1555 	(1U << EFX_MAE_ACTION_VLAN_POP) |
1556 	(1U << EFX_MAE_ACTION_VLAN_PUSH) |
1557 	(1U << EFX_MAE_ACTION_COUNT);
1558 
1559 /*
1560  * Add an action to an action set.
1561  *
1562  * This has to be invoked in the desired action order.
1563  * An out-of-order action request will be turned down.
1564  */
1565 static	__checkReturn			efx_rc_t
1566 efx_mae_action_set_spec_populate(
1567 	__in				efx_mae_actions_t *spec,
1568 	__in				efx_mae_action_t type,
1569 	__in				size_t arg_size,
1570 	__in_bcount(arg_size)		const uint8_t *arg)
1571 {
1572 	uint32_t action_mask;
1573 	efx_rc_t rc;
1574 
1575 	EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1576 	    (sizeof (efx_mae_action_ordered_map) * 8));
1577 	EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1578 	    (sizeof (efx_mae_action_repeat_map) * 8));
1579 
1580 	EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
1581 	EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK);
1582 	EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER);
1583 
1584 	if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
1585 		rc = EINVAL;
1586 		goto fail1;
1587 	}
1588 
1589 	action_mask = (1U << type);
1590 
1591 	if ((spec->ema_actions & action_mask) != 0) {
1592 		/* The action set already contains this action. */
1593 		if ((efx_mae_action_repeat_map & action_mask) == 0) {
1594 			/* Cannot add another non-repeatable action. */
1595 			rc = ENOTSUP;
1596 			goto fail2;
1597 		}
1598 	}
1599 
1600 	if ((efx_mae_action_ordered_map & action_mask) != 0) {
1601 		uint32_t strict_ordered_map =
1602 		    efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map;
1603 		uint32_t later_actions_mask =
1604 		    strict_ordered_map & ~(action_mask | (action_mask - 1));
1605 
1606 		if ((spec->ema_actions & later_actions_mask) != 0) {
1607 			/* Cannot add an action after later ordered actions. */
1608 			rc = ENOTSUP;
1609 			goto fail3;
1610 		}
1611 	}
1612 
1613 	if (efx_mae_actions[type].emad_add != NULL) {
1614 		rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
1615 		if (rc != 0)
1616 			goto fail4;
1617 	}
1618 
1619 	spec->ema_actions |= action_mask;
1620 
1621 	return (0);
1622 
1623 fail4:
1624 	EFSYS_PROBE(fail4);
1625 fail3:
1626 	EFSYS_PROBE(fail3);
1627 fail2:
1628 	EFSYS_PROBE(fail2);
1629 fail1:
1630 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1631 	return (rc);
1632 }
1633 
1634 	__checkReturn			efx_rc_t
1635 efx_mae_action_set_populate_decap(
1636 	__in				efx_mae_actions_t *spec)
1637 {
1638 	return (efx_mae_action_set_spec_populate(spec,
1639 	    EFX_MAE_ACTION_DECAP, 0, NULL));
1640 }
1641 
1642 	__checkReturn			efx_rc_t
1643 efx_mae_action_set_populate_vlan_pop(
1644 	__in				efx_mae_actions_t *spec)
1645 {
1646 	return (efx_mae_action_set_spec_populate(spec,
1647 	    EFX_MAE_ACTION_VLAN_POP, 0, NULL));
1648 }
1649 
1650 	__checkReturn			efx_rc_t
1651 efx_mae_action_set_populate_vlan_push(
1652 	__in				efx_mae_actions_t *spec,
1653 	__in				uint16_t tpid_be,
1654 	__in				uint16_t tci_be)
1655 {
1656 	efx_mae_action_vlan_push_t action;
1657 	const uint8_t *arg = (const uint8_t *)&action;
1658 
1659 	action.emavp_tpid_be = tpid_be;
1660 	action.emavp_tci_be = tci_be;
1661 
1662 	return (efx_mae_action_set_spec_populate(spec,
1663 	    EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg));
1664 }
1665 
1666 	__checkReturn			efx_rc_t
1667 efx_mae_action_set_populate_encap(
1668 	__in				efx_mae_actions_t *spec)
1669 {
1670 	/*
1671 	 * There is no argument to pass encap. header ID, thus, one does not
1672 	 * need to allocate an encap. header while parsing application input.
1673 	 * This is useful since building an action set may be done simply to
1674 	 * validate a rule, whilst resource allocation usually consumes time.
1675 	 */
1676 	return (efx_mae_action_set_spec_populate(spec,
1677 	    EFX_MAE_ACTION_ENCAP, 0, NULL));
1678 }
1679 
1680 	__checkReturn			efx_rc_t
1681 efx_mae_action_set_populate_count(
1682 	__in				efx_mae_actions_t *spec)
1683 {
1684 	/*
1685 	 * There is no argument to pass counter ID, thus, one does not
1686 	 * need to allocate a counter while parsing application input.
1687 	 * This is useful since building an action set may be done simply to
1688 	 * validate a rule, whilst resource allocation usually consumes time.
1689 	 */
1690 	return (efx_mae_action_set_spec_populate(spec,
1691 	    EFX_MAE_ACTION_COUNT, 0, NULL));
1692 }
1693 
1694 	__checkReturn			efx_rc_t
1695 efx_mae_action_set_populate_flag(
1696 	__in				efx_mae_actions_t *spec)
1697 {
1698 	return (efx_mae_action_set_spec_populate(spec,
1699 	    EFX_MAE_ACTION_FLAG, 0, NULL));
1700 }
1701 
1702 	__checkReturn			efx_rc_t
1703 efx_mae_action_set_populate_mark(
1704 	__in				efx_mae_actions_t *spec,
1705 	__in				uint32_t mark_value)
1706 {
1707 	const uint8_t *arg = (const uint8_t *)&mark_value;
1708 
1709 	return (efx_mae_action_set_spec_populate(spec,
1710 	    EFX_MAE_ACTION_MARK, sizeof (mark_value), arg));
1711 }
1712 
1713 	__checkReturn			efx_rc_t
1714 efx_mae_action_set_populate_deliver(
1715 	__in				efx_mae_actions_t *spec,
1716 	__in				const efx_mport_sel_t *mportp)
1717 {
1718 	const uint8_t *arg;
1719 	efx_rc_t rc;
1720 
1721 	if (mportp == NULL) {
1722 		rc = EINVAL;
1723 		goto fail1;
1724 	}
1725 
1726 	arg = (const uint8_t *)&mportp->sel;
1727 
1728 	return (efx_mae_action_set_spec_populate(spec,
1729 	    EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
1730 
1731 fail1:
1732 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1733 	return (rc);
1734 }
1735 
1736 	__checkReturn			efx_rc_t
1737 efx_mae_action_set_populate_drop(
1738 	__in				efx_mae_actions_t *spec)
1739 {
1740 	efx_mport_sel_t mport;
1741 	const uint8_t *arg;
1742 	efx_dword_t dword;
1743 
1744 	EFX_POPULATE_DWORD_1(dword,
1745 	    MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL);
1746 
1747 	/*
1748 	 * The constructed DWORD is little-endian,
1749 	 * but the resulting value is meant to be
1750 	 * passed to MCDIs, where it will undergo
1751 	 * host-order to little endian conversion.
1752 	 */
1753 	mport.sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
1754 
1755 	arg = (const uint8_t *)&mport.sel;
1756 
1757 	return (efx_mae_action_set_spec_populate(spec,
1758 	    EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg));
1759 }
1760 
1761 	__checkReturn			boolean_t
1762 efx_mae_action_set_specs_equal(
1763 	__in				const efx_mae_actions_t *left,
1764 	__in				const efx_mae_actions_t *right)
1765 {
1766 	size_t cmp_size = EFX_FIELD_OFFSET(efx_mae_actions_t, ema_rsrc);
1767 
1768 	/*
1769 	 * An action set specification consists of two parts. The first part
1770 	 * indicates what actions are included in the action set, as well as
1771 	 * extra quantitative values (in example, the number of VLAN tags to
1772 	 * push). The second part comprises resource IDs used by the actions.
1773 	 *
1774 	 * A resource, in example, a counter, is allocated from the hardware
1775 	 * by the client, and it's the client who is responsible for keeping
1776 	 * track of allocated resources and comparing resource IDs if needed.
1777 	 *
1778 	 * In this API, don't compare resource IDs in the two specifications.
1779 	 */
1780 
1781 	return ((memcmp(left, right, cmp_size) == 0) ? B_TRUE : B_FALSE);
1782 }
1783 
1784 	__checkReturn			efx_rc_t
1785 efx_mae_match_specs_class_cmp(
1786 	__in				efx_nic_t *enp,
1787 	__in				const efx_mae_match_spec_t *left,
1788 	__in				const efx_mae_match_spec_t *right,
1789 	__out				boolean_t *have_same_classp)
1790 {
1791 	efx_mae_t *maep = enp->en_maep;
1792 	unsigned int field_ncaps = maep->em_max_nfields;
1793 	const efx_mae_field_cap_t *field_caps;
1794 	const efx_mae_mv_desc_t *desc_setp;
1795 	unsigned int desc_set_nentries;
1796 	const efx_mae_mv_bit_desc_t *bit_desc_setp;
1797 	unsigned int bit_desc_set_nentries;
1798 	boolean_t have_same_class = B_TRUE;
1799 	efx_mae_field_id_t field_id;
1800 	const uint8_t *mvpl;
1801 	const uint8_t *mvpr;
1802 	efx_rc_t rc;
1803 
1804 	switch (left->emms_type) {
1805 	case EFX_MAE_RULE_OUTER:
1806 		field_caps = maep->em_outer_rule_field_caps;
1807 		desc_setp = __efx_mae_outer_rule_mv_desc_set;
1808 		desc_set_nentries =
1809 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1810 		bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
1811 		bit_desc_set_nentries =
1812 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
1813 		mvpl = left->emms_mask_value_pairs.outer;
1814 		mvpr = right->emms_mask_value_pairs.outer;
1815 		break;
1816 	case EFX_MAE_RULE_ACTION:
1817 		field_caps = maep->em_action_rule_field_caps;
1818 		desc_setp = __efx_mae_action_rule_mv_desc_set;
1819 		desc_set_nentries =
1820 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1821 		bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
1822 		bit_desc_set_nentries =
1823 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
1824 		mvpl = left->emms_mask_value_pairs.action;
1825 		mvpr = right->emms_mask_value_pairs.action;
1826 		break;
1827 	default:
1828 		rc = ENOTSUP;
1829 		goto fail1;
1830 	}
1831 
1832 	if (field_caps == NULL) {
1833 		rc = EAGAIN;
1834 		goto fail2;
1835 	}
1836 
1837 	if (left->emms_type != right->emms_type ||
1838 	    left->emms_prio != right->emms_prio) {
1839 		/*
1840 		 * Rules of different types can never map to the same class.
1841 		 *
1842 		 * The FW can support some set of match criteria for one
1843 		 * priority and not support the very same set for
1844 		 * another priority. Thus, two rules which have
1845 		 * different priorities can never map to
1846 		 * the same class.
1847 		 */
1848 		*have_same_classp = B_FALSE;
1849 		return (0);
1850 	}
1851 
1852 	for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1853 	     ++field_id) {
1854 		const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1855 		efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1856 		const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
1857 		const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
1858 		size_t mask_size = descp->emmd_mask_size;
1859 		const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
1860 		const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
1861 		size_t value_size = descp->emmd_value_size;
1862 
1863 		if (mask_size == 0)
1864 			continue; /* Skip array gap */
1865 
1866 		if ((unsigned int)field_cap_id >= field_ncaps) {
1867 			/*
1868 			 * The FW has not reported capability status for this
1869 			 * field. It's unknown whether any difference between
1870 			 * the two masks / values affects the class. The only
1871 			 * case when the class must be the same is when these
1872 			 * mask-value pairs match. Otherwise, report mismatch.
1873 			 */
1874 			if ((memcmp(lmaskp, rmaskp, mask_size) == 0) &&
1875 			    (memcmp(lvalp, rvalp, value_size) == 0))
1876 				continue;
1877 			else
1878 				break;
1879 		}
1880 
1881 		if (field_caps[field_cap_id].emfc_mask_affects_class) {
1882 			if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
1883 				have_same_class = B_FALSE;
1884 				break;
1885 			}
1886 		}
1887 
1888 		if (field_caps[field_cap_id].emfc_match_affects_class) {
1889 			if (memcmp(lvalp, rvalp, value_size) != 0) {
1890 				have_same_class = B_FALSE;
1891 				break;
1892 			}
1893 		}
1894 	}
1895 
1896 	if (have_same_class == B_FALSE)
1897 		goto done;
1898 
1899 	for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
1900 	     ++field_id) {
1901 		const efx_mae_mv_bit_desc_t *bit_descp =
1902 		    &bit_desc_setp[field_id];
1903 		efx_mae_field_cap_id_t bit_cap_id =
1904 		    bit_descp->emmbd_bit_cap_id;
1905 		unsigned int byte_idx;
1906 		unsigned int bit_idx;
1907 
1908 		if (bit_descp->emmbd_entry_is_valid == B_FALSE)
1909 			continue; /* Skip array gap */
1910 
1911 		if ((unsigned int)bit_cap_id >= field_ncaps)
1912 			break;
1913 
1914 		byte_idx =
1915 		    bit_descp->emmbd_mask_ofst +
1916 		    bit_descp->emmbd_mask_lbn / 8;
1917 		bit_idx =
1918 		    bit_descp->emmbd_mask_lbn % 8;
1919 
1920 		if (field_caps[bit_cap_id].emfc_mask_affects_class &&
1921 		    (mvpl[byte_idx] & (1U << bit_idx)) !=
1922 		    (mvpr[byte_idx] & (1U << bit_idx))) {
1923 			have_same_class = B_FALSE;
1924 			break;
1925 		}
1926 
1927 		byte_idx =
1928 		    bit_descp->emmbd_value_ofst +
1929 		    bit_descp->emmbd_value_lbn / 8;
1930 		bit_idx =
1931 		    bit_descp->emmbd_value_lbn % 8;
1932 
1933 		if (field_caps[bit_cap_id].emfc_match_affects_class &&
1934 		    (mvpl[byte_idx] & (1U << bit_idx)) !=
1935 		    (mvpr[byte_idx] & (1U << bit_idx))) {
1936 			have_same_class = B_FALSE;
1937 			break;
1938 		}
1939 	}
1940 
1941 done:
1942 	*have_same_classp = have_same_class;
1943 
1944 	return (0);
1945 
1946 fail2:
1947 	EFSYS_PROBE(fail2);
1948 fail1:
1949 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1950 	return (rc);
1951 }
1952 
1953 	__checkReturn		efx_rc_t
1954 efx_mae_outer_rule_insert(
1955 	__in			efx_nic_t *enp,
1956 	__in			const efx_mae_match_spec_t *spec,
1957 	__in			efx_tunnel_protocol_t encap_type,
1958 	__out			efx_mae_rule_id_t *or_idp)
1959 {
1960 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1961 	efx_mcdi_req_t req;
1962 	EFX_MCDI_DECLARE_BUF(payload,
1963 	    MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2,
1964 	    MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
1965 	uint32_t encap_type_mcdi;
1966 	efx_mae_rule_id_t or_id;
1967 	size_t offset;
1968 	efx_rc_t rc;
1969 
1970 	EFX_STATIC_ASSERT(sizeof (or_idp->id) ==
1971 	    MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN);
1972 
1973 	EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1974 	    MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL);
1975 
1976 	if (encp->enc_mae_supported == B_FALSE) {
1977 		rc = ENOTSUP;
1978 		goto fail1;
1979 	}
1980 
1981 	if (spec->emms_type != EFX_MAE_RULE_OUTER) {
1982 		rc = EINVAL;
1983 		goto fail2;
1984 	}
1985 
1986 	switch (encap_type) {
1987 	case EFX_TUNNEL_PROTOCOL_NONE:
1988 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
1989 		break;
1990 	case EFX_TUNNEL_PROTOCOL_VXLAN:
1991 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
1992 		break;
1993 	case EFX_TUNNEL_PROTOCOL_GENEVE:
1994 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
1995 		break;
1996 	case EFX_TUNNEL_PROTOCOL_NVGRE:
1997 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
1998 		break;
1999 	default:
2000 		rc = ENOTSUP;
2001 		goto fail3;
2002 	}
2003 
2004 	req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT;
2005 	req.emr_in_buf = payload;
2006 	req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2;
2007 	req.emr_out_buf = payload;
2008 	req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN;
2009 
2010 	MCDI_IN_SET_DWORD(req,
2011 	    MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi);
2012 
2013 	MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio);
2014 
2015 	/*
2016 	 * Mask-value pairs have been stored in the byte order needed for the
2017 	 * MCDI request and are thus safe to be copied directly to the buffer.
2018 	 * The library cares about byte order in efx_mae_match_spec_field_set().
2019 	 */
2020 	EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >=
2021 	    MAE_ENC_FIELD_PAIRS_LEN);
2022 	offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST;
2023 	memcpy(payload + offset, spec->emms_mask_value_pairs.outer,
2024 	    MAE_ENC_FIELD_PAIRS_LEN);
2025 
2026 	efx_mcdi_execute(enp, &req);
2027 
2028 	if (req.emr_rc != 0) {
2029 		rc = req.emr_rc;
2030 		goto fail4;
2031 	}
2032 
2033 	if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) {
2034 		rc = EMSGSIZE;
2035 		goto fail5;
2036 	}
2037 
2038 	or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
2039 	if (or_id.id == EFX_MAE_RSRC_ID_INVALID) {
2040 		rc = ENOENT;
2041 		goto fail6;
2042 	}
2043 
2044 	or_idp->id = or_id.id;
2045 
2046 	return (0);
2047 
2048 fail6:
2049 	EFSYS_PROBE(fail6);
2050 fail5:
2051 	EFSYS_PROBE(fail5);
2052 fail4:
2053 	EFSYS_PROBE(fail4);
2054 fail3:
2055 	EFSYS_PROBE(fail3);
2056 fail2:
2057 	EFSYS_PROBE(fail2);
2058 fail1:
2059 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2060 	return (rc);
2061 }
2062 
2063 	__checkReturn		efx_rc_t
2064 efx_mae_outer_rule_remove(
2065 	__in			efx_nic_t *enp,
2066 	__in			const efx_mae_rule_id_t *or_idp)
2067 {
2068 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2069 	efx_mcdi_req_t req;
2070 	EFX_MCDI_DECLARE_BUF(payload,
2071 	    MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1),
2072 	    MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
2073 	efx_rc_t rc;
2074 
2075 	if (encp->enc_mae_supported == B_FALSE) {
2076 		rc = ENOTSUP;
2077 		goto fail1;
2078 	}
2079 
2080 	req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE;
2081 	req.emr_in_buf = payload;
2082 	req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1);
2083 	req.emr_out_buf = payload;
2084 	req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1);
2085 
2086 	MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id);
2087 
2088 	efx_mcdi_execute(enp, &req);
2089 
2090 	if (req.emr_rc != 0) {
2091 		rc = req.emr_rc;
2092 		goto fail2;
2093 	}
2094 
2095 	if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LENMIN) {
2096 		rc = EMSGSIZE;
2097 		goto fail3;
2098 	}
2099 
2100 	if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) !=
2101 	    or_idp->id) {
2102 		/* Firmware failed to remove the outer rule. */
2103 		rc = EAGAIN;
2104 		goto fail4;
2105 	}
2106 
2107 	return (0);
2108 
2109 fail4:
2110 	EFSYS_PROBE(fail4);
2111 fail3:
2112 	EFSYS_PROBE(fail3);
2113 fail2:
2114 	EFSYS_PROBE(fail2);
2115 fail1:
2116 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2117 	return (rc);
2118 }
2119 
2120 	__checkReturn			efx_rc_t
2121 efx_mae_match_spec_outer_rule_id_set(
2122 	__in				efx_mae_match_spec_t *spec,
2123 	__in				const efx_mae_rule_id_t *or_idp)
2124 {
2125 	uint32_t full_mask = UINT32_MAX;
2126 	efx_rc_t rc;
2127 
2128 	if (spec->emms_type != EFX_MAE_RULE_ACTION) {
2129 		rc = EINVAL;
2130 		goto fail1;
2131 	}
2132 
2133 	if (or_idp == NULL) {
2134 		rc = EINVAL;
2135 		goto fail2;
2136 	}
2137 
2138 	rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID,
2139 	    sizeof (or_idp->id), (const uint8_t *)&or_idp->id,
2140 	    sizeof (full_mask), (const uint8_t *)&full_mask);
2141 	if (rc != 0)
2142 		goto fail3;
2143 
2144 	return (0);
2145 
2146 fail3:
2147 	EFSYS_PROBE(fail3);
2148 fail2:
2149 	EFSYS_PROBE(fail2);
2150 fail1:
2151 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2152 	return (rc);
2153 }
2154 
2155 	 __checkReturn			efx_rc_t
2156 efx_mae_encap_header_alloc(
2157 	__in				efx_nic_t *enp,
2158 	__in				efx_tunnel_protocol_t encap_type,
2159 	__in_bcount(header_size)	uint8_t *header_data,
2160 	__in				size_t header_size,
2161 	__out				efx_mae_eh_id_t *eh_idp)
2162 {
2163 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2164 	efx_mcdi_req_t req;
2165 	EFX_MCDI_DECLARE_BUF(payload,
2166 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LENMAX_MCDI2,
2167 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN);
2168 	uint32_t encap_type_mcdi;
2169 	efx_mae_eh_id_t eh_id;
2170 	efx_rc_t rc;
2171 
2172 	EFX_STATIC_ASSERT(sizeof (eh_idp->id) ==
2173 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_LEN);
2174 
2175 	EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2176 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
2177 
2178 	if (encp->enc_mae_supported == B_FALSE) {
2179 		rc = ENOTSUP;
2180 		goto fail1;
2181 	}
2182 
2183 	switch (encap_type) {
2184 	case EFX_TUNNEL_PROTOCOL_NONE:
2185 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
2186 		break;
2187 	case EFX_TUNNEL_PROTOCOL_VXLAN:
2188 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
2189 		break;
2190 	case EFX_TUNNEL_PROTOCOL_GENEVE:
2191 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
2192 		break;
2193 	case EFX_TUNNEL_PROTOCOL_NVGRE:
2194 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
2195 		break;
2196 	default:
2197 		rc = ENOTSUP;
2198 		goto fail2;
2199 	}
2200 
2201 	if (header_size >
2202 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2) {
2203 		rc = EINVAL;
2204 		goto fail3;
2205 	}
2206 
2207 	req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_ALLOC;
2208 	req.emr_in_buf = payload;
2209 	req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(header_size);
2210 	req.emr_out_buf = payload;
2211 	req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN;
2212 
2213 	MCDI_IN_SET_DWORD(req,
2214 	    MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, encap_type_mcdi);
2215 
2216 	memcpy(payload + MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_OFST,
2217 	    header_data, header_size);
2218 
2219 	efx_mcdi_execute(enp, &req);
2220 
2221 	if (req.emr_rc != 0) {
2222 		rc = req.emr_rc;
2223 		goto fail4;
2224 	}
2225 
2226 	if (req.emr_out_length_used < MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN) {
2227 		rc = EMSGSIZE;
2228 		goto fail5;
2229 	}
2230 
2231 	eh_id.id = MCDI_OUT_DWORD(req,
2232 	    MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID);
2233 
2234 	if (eh_id.id == EFX_MAE_RSRC_ID_INVALID) {
2235 		rc = ENOENT;
2236 		goto fail6;
2237 	}
2238 
2239 	eh_idp->id = eh_id.id;
2240 
2241 	return (0);
2242 
2243 fail6:
2244 	EFSYS_PROBE(fail6);
2245 fail5:
2246 	EFSYS_PROBE(fail5);
2247 fail4:
2248 	EFSYS_PROBE(fail4);
2249 fail3:
2250 	EFSYS_PROBE(fail3);
2251 fail2:
2252 	EFSYS_PROBE(fail2);
2253 fail1:
2254 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2255 	return (rc);
2256 }
2257 
2258 	__checkReturn			efx_rc_t
2259 efx_mae_encap_header_free(
2260 	__in				efx_nic_t *enp,
2261 	__in				const efx_mae_eh_id_t *eh_idp)
2262 {
2263 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2264 	efx_mcdi_req_t req;
2265 	EFX_MCDI_DECLARE_BUF(payload,
2266 	    MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1),
2267 	    MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1));
2268 	efx_rc_t rc;
2269 
2270 	if (encp->enc_mae_supported == B_FALSE) {
2271 		rc = ENOTSUP;
2272 		goto fail1;
2273 	}
2274 
2275 	req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_FREE;
2276 	req.emr_in_buf = payload;
2277 	req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1);
2278 	req.emr_out_buf = payload;
2279 	req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1);
2280 
2281 	MCDI_IN_SET_DWORD(req, MAE_ENCAP_HEADER_FREE_IN_EH_ID, eh_idp->id);
2282 
2283 	efx_mcdi_execute(enp, &req);
2284 
2285 	if (req.emr_rc != 0) {
2286 		rc = req.emr_rc;
2287 		goto fail2;
2288 	}
2289 
2290 	if (MCDI_OUT_DWORD(req, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) !=
2291 	    eh_idp->id) {
2292 		/* Firmware failed to remove the encap. header. */
2293 		rc = EAGAIN;
2294 		goto fail3;
2295 	}
2296 
2297 	return (0);
2298 
2299 fail3:
2300 	EFSYS_PROBE(fail3);
2301 fail2:
2302 	EFSYS_PROBE(fail2);
2303 fail1:
2304 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2305 	return (rc);
2306 }
2307 
2308 	__checkReturn			efx_rc_t
2309 efx_mae_action_set_fill_in_eh_id(
2310 	__in				efx_mae_actions_t *spec,
2311 	__in				const efx_mae_eh_id_t *eh_idp)
2312 {
2313 	efx_rc_t rc;
2314 
2315 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) == 0) {
2316 		/*
2317 		 * The caller has not intended to have action ENCAP originally,
2318 		 * hence, this attempt to indicate encap. header ID is invalid.
2319 		 */
2320 		rc = EINVAL;
2321 		goto fail1;
2322 	}
2323 
2324 	if (spec->ema_rsrc.emar_eh_id.id != EFX_MAE_RSRC_ID_INVALID) {
2325 		/* The caller attempts to indicate encap. header ID twice. */
2326 		rc = EINVAL;
2327 		goto fail2;
2328 	}
2329 
2330 	if (eh_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2331 		rc = EINVAL;
2332 		goto fail3;
2333 	}
2334 
2335 	spec->ema_rsrc.emar_eh_id.id = eh_idp->id;
2336 
2337 	return (0);
2338 
2339 fail3:
2340 	EFSYS_PROBE(fail3);
2341 fail2:
2342 	EFSYS_PROBE(fail2);
2343 fail1:
2344 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2345 	return (rc);
2346 }
2347 
2348 	__checkReturn			efx_rc_t
2349 efx_mae_action_set_alloc(
2350 	__in				efx_nic_t *enp,
2351 	__in				const efx_mae_actions_t *spec,
2352 	__out				efx_mae_aset_id_t *aset_idp)
2353 {
2354 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2355 	efx_mcdi_req_t req;
2356 	EFX_MCDI_DECLARE_BUF(payload,
2357 	    MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
2358 	    MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
2359 	efx_mae_aset_id_t aset_id;
2360 	efx_rc_t rc;
2361 
2362 	if (encp->enc_mae_supported == B_FALSE) {
2363 		rc = ENOTSUP;
2364 		goto fail1;
2365 	}
2366 
2367 	req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
2368 	req.emr_in_buf = payload;
2369 	req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
2370 	req.emr_out_buf = payload;
2371 	req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
2372 
2373 	/*
2374 	 * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
2375 	 * corresponding resource types are supported by the implementation.
2376 	 * Use proper resource ID assignments instead.
2377 	 */
2378 	MCDI_IN_SET_DWORD(req,
2379 	    MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
2380 
2381 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECAP)) != 0) {
2382 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2383 		    MAE_ACTION_SET_ALLOC_IN_DECAP, 1);
2384 	}
2385 
2386 	MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2387 	    MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
2388 
2389 	if (spec->ema_n_vlan_tags_to_push > 0) {
2390 		unsigned int outer_tag_idx;
2391 
2392 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2393 		    MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
2394 		    spec->ema_n_vlan_tags_to_push);
2395 
2396 		if (spec->ema_n_vlan_tags_to_push ==
2397 		    EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
2398 			MCDI_IN_SET_WORD(req,
2399 			    MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
2400 			    spec->ema_vlan_push_descs[0].emavp_tpid_be);
2401 			MCDI_IN_SET_WORD(req,
2402 			    MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
2403 			    spec->ema_vlan_push_descs[0].emavp_tci_be);
2404 		}
2405 
2406 		outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
2407 
2408 		MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
2409 		    spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
2410 		MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
2411 		    spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
2412 	}
2413 
2414 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
2415 	    spec->ema_rsrc.emar_eh_id.id);
2416 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
2417 	    spec->ema_rsrc.emar_counter_id.id);
2418 
2419 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
2420 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2421 		    MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
2422 	}
2423 
2424 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
2425 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2426 		    MAE_ACTION_SET_ALLOC_IN_MARK, 1);
2427 
2428 		MCDI_IN_SET_DWORD(req,
2429 		    MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
2430 	}
2431 
2432 	MCDI_IN_SET_DWORD(req,
2433 	    MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
2434 
2435 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
2436 	    MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2437 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
2438 	    MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2439 
2440 	efx_mcdi_execute(enp, &req);
2441 
2442 	if (req.emr_rc != 0) {
2443 		rc = req.emr_rc;
2444 		goto fail2;
2445 	}
2446 
2447 	if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
2448 		rc = EMSGSIZE;
2449 		goto fail3;
2450 	}
2451 
2452 	aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
2453 	if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
2454 		rc = ENOENT;
2455 		goto fail4;
2456 	}
2457 
2458 	aset_idp->id = aset_id.id;
2459 
2460 	return (0);
2461 
2462 fail4:
2463 	EFSYS_PROBE(fail4);
2464 fail3:
2465 	EFSYS_PROBE(fail3);
2466 fail2:
2467 	EFSYS_PROBE(fail2);
2468 fail1:
2469 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2470 	return (rc);
2471 }
2472 
2473 	__checkReturn			unsigned int
2474 efx_mae_action_set_get_nb_count(
2475 	__in				const efx_mae_actions_t *spec)
2476 {
2477 	return (spec->ema_n_count_actions);
2478 }
2479 
2480 	__checkReturn			efx_rc_t
2481 efx_mae_action_set_fill_in_counter_id(
2482 	__in				efx_mae_actions_t *spec,
2483 	__in				const efx_counter_t *counter_idp)
2484 {
2485 	efx_rc_t rc;
2486 
2487 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_COUNT)) == 0) {
2488 		/*
2489 		 * Invalid to add counter ID if spec does not have COUNT action.
2490 		 */
2491 		rc = EINVAL;
2492 		goto fail1;
2493 	}
2494 
2495 	if (spec->ema_n_count_actions != 1) {
2496 		/*
2497 		 * Having multiple COUNT actions in the spec requires a counter
2498 		 * list to be used. This API must only be used for a single
2499 		 * counter per spec. Turn down the request as inappropriate.
2500 		 */
2501 		rc = EINVAL;
2502 		goto fail2;
2503 	}
2504 
2505 	if (spec->ema_rsrc.emar_counter_id.id != EFX_MAE_RSRC_ID_INVALID) {
2506 		/* The caller attempts to indicate counter ID twice. */
2507 		rc = EALREADY;
2508 		goto fail3;
2509 	}
2510 
2511 	if (counter_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2512 		rc = EINVAL;
2513 		goto fail4;
2514 	}
2515 
2516 	spec->ema_rsrc.emar_counter_id.id = counter_idp->id;
2517 
2518 	return (0);
2519 
2520 fail4:
2521 	EFSYS_PROBE(fail4);
2522 fail3:
2523 	EFSYS_PROBE(fail3);
2524 fail2:
2525 	EFSYS_PROBE(fail2);
2526 fail1:
2527 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2528 	return (rc);
2529 }
2530 
2531 	__checkReturn			efx_rc_t
2532 efx_mae_counters_alloc(
2533 	__in				efx_nic_t *enp,
2534 	__in				uint32_t n_counters,
2535 	__out				uint32_t *n_allocatedp,
2536 	__out_ecount(n_counters)	efx_counter_t *countersp,
2537 	__out_opt			uint32_t *gen_countp)
2538 {
2539 	EFX_MCDI_DECLARE_BUF(payload,
2540 	    MC_CMD_MAE_COUNTER_ALLOC_IN_LEN,
2541 	    MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMAX_MCDI2);
2542 	efx_mae_t *maep = enp->en_maep;
2543 	uint32_t n_allocated;
2544 	efx_mcdi_req_t req;
2545 	unsigned int i;
2546 	efx_rc_t rc;
2547 
2548 	if (n_counters > maep->em_max_ncounters ||
2549 	    n_counters < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM ||
2550 	    n_counters > MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MAXNUM_MCDI2) {
2551 		rc = EINVAL;
2552 		goto fail1;
2553 	}
2554 
2555 	req.emr_cmd = MC_CMD_MAE_COUNTER_ALLOC;
2556 	req.emr_in_buf = payload;
2557 	req.emr_in_length = MC_CMD_MAE_COUNTER_ALLOC_IN_LEN;
2558 	req.emr_out_buf = payload;
2559 	req.emr_out_length = MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(n_counters);
2560 
2561 	MCDI_IN_SET_DWORD(req, MAE_COUNTER_ALLOC_IN_REQUESTED_COUNT,
2562 	    n_counters);
2563 
2564 	efx_mcdi_execute(enp, &req);
2565 
2566 	if (req.emr_rc != 0) {
2567 		rc = req.emr_rc;
2568 		goto fail2;
2569 	}
2570 
2571 	if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMIN) {
2572 		rc = EMSGSIZE;
2573 		goto fail3;
2574 	}
2575 
2576 	n_allocated = MCDI_OUT_DWORD(req,
2577 	    MAE_COUNTER_ALLOC_OUT_COUNTER_ID_COUNT);
2578 	if (n_allocated < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM) {
2579 		rc = EFAULT;
2580 		goto fail4;
2581 	}
2582 
2583 	for (i = 0; i < n_allocated; i++) {
2584 		countersp[i].id = MCDI_OUT_INDEXED_DWORD(req,
2585 		    MAE_COUNTER_ALLOC_OUT_COUNTER_ID, i);
2586 	}
2587 
2588 	if (gen_countp != NULL) {
2589 		*gen_countp = MCDI_OUT_DWORD(req,
2590 				    MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT);
2591 	}
2592 
2593 	*n_allocatedp = n_allocated;
2594 
2595 	return (0);
2596 
2597 fail4:
2598 	EFSYS_PROBE(fail4);
2599 fail3:
2600 	EFSYS_PROBE(fail3);
2601 fail2:
2602 	EFSYS_PROBE(fail2);
2603 fail1:
2604 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2605 
2606 	return (rc);
2607 }
2608 
2609 	__checkReturn			efx_rc_t
2610 efx_mae_counters_free(
2611 	__in				efx_nic_t *enp,
2612 	__in				uint32_t n_counters,
2613 	__out				uint32_t *n_freedp,
2614 	__in_ecount(n_counters)		const efx_counter_t *countersp,
2615 	__out_opt			uint32_t *gen_countp)
2616 {
2617 	EFX_MCDI_DECLARE_BUF(payload,
2618 	    MC_CMD_MAE_COUNTER_FREE_IN_LENMAX_MCDI2,
2619 	    MC_CMD_MAE_COUNTER_FREE_OUT_LENMAX_MCDI2);
2620 	efx_mae_t *maep = enp->en_maep;
2621 	efx_mcdi_req_t req;
2622 	uint32_t n_freed;
2623 	unsigned int i;
2624 	efx_rc_t rc;
2625 
2626 	if (n_counters > maep->em_max_ncounters ||
2627 	    n_counters < MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MINNUM ||
2628 	    n_counters >
2629 	    MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MAXNUM_MCDI2) {
2630 		rc = EINVAL;
2631 		goto fail1;
2632 	}
2633 
2634 	req.emr_cmd = MC_CMD_MAE_COUNTER_FREE;
2635 	req.emr_in_buf = payload;
2636 	req.emr_in_length = MC_CMD_MAE_COUNTER_FREE_IN_LEN(n_counters);
2637 	req.emr_out_buf = payload;
2638 	req.emr_out_length = MC_CMD_MAE_COUNTER_FREE_OUT_LEN(n_counters);
2639 
2640 	for (i = 0; i < n_counters; i++) {
2641 		MCDI_IN_SET_INDEXED_DWORD(req,
2642 		    MAE_COUNTER_FREE_IN_FREE_COUNTER_ID, i, countersp[i].id);
2643 	}
2644 	MCDI_IN_SET_DWORD(req, MAE_COUNTER_FREE_IN_COUNTER_ID_COUNT,
2645 			  n_counters);
2646 
2647 	efx_mcdi_execute(enp, &req);
2648 
2649 	if (req.emr_rc != 0) {
2650 		rc = req.emr_rc;
2651 		goto fail2;
2652 	}
2653 
2654 	if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_FREE_OUT_LENMIN) {
2655 		rc = EMSGSIZE;
2656 		goto fail3;
2657 	}
2658 
2659 	n_freed = MCDI_OUT_DWORD(req, MAE_COUNTER_FREE_OUT_COUNTER_ID_COUNT);
2660 
2661 	if (n_freed < MC_CMD_MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID_MINNUM) {
2662 		rc = EFAULT;
2663 		goto fail4;
2664 	}
2665 
2666 	if (gen_countp != NULL) {
2667 		*gen_countp = MCDI_OUT_DWORD(req,
2668 				    MAE_COUNTER_FREE_OUT_GENERATION_COUNT);
2669 	}
2670 
2671 	*n_freedp = n_freed;
2672 
2673 	return (0);
2674 
2675 fail4:
2676 	EFSYS_PROBE(fail4);
2677 fail3:
2678 	EFSYS_PROBE(fail3);
2679 fail2:
2680 	EFSYS_PROBE(fail2);
2681 fail1:
2682 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2683 
2684 	return (rc);
2685 }
2686 
2687 	__checkReturn			efx_rc_t
2688 efx_mae_counters_stream_start(
2689 	__in				efx_nic_t *enp,
2690 	__in				uint16_t rxq_id,
2691 	__in				uint16_t packet_size,
2692 	__in				uint32_t flags_in,
2693 	__out				uint32_t *flags_out)
2694 {
2695 	efx_mcdi_req_t req;
2696 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN,
2697 			     MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN);
2698 	efx_rc_t rc;
2699 
2700 	EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_IN_ZERO_SQUASH_DISABLE ==
2701 	    1U << MC_CMD_MAE_COUNTERS_STREAM_START_IN_ZERO_SQUASH_DISABLE_LBN);
2702 
2703 	EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_OUT_USES_CREDITS ==
2704 	    1U << MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_LBN);
2705 
2706 	req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_START;
2707 	req.emr_in_buf = payload;
2708 	req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN;
2709 	req.emr_out_buf = payload;
2710 	req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN;
2711 
2712 	MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_QID, rxq_id);
2713 	MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_PACKET_SIZE,
2714 			 packet_size);
2715 	MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_START_IN_FLAGS, flags_in);
2716 
2717 	efx_mcdi_execute(enp, &req);
2718 
2719 	if (req.emr_rc != 0) {
2720 		rc = req.emr_rc;
2721 		goto fail1;
2722 	}
2723 
2724 	if (req.emr_out_length_used <
2725 	    MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN) {
2726 		rc = EMSGSIZE;
2727 		goto fail2;
2728 	}
2729 
2730 	*flags_out = MCDI_OUT_DWORD(req, MAE_COUNTERS_STREAM_START_OUT_FLAGS);
2731 
2732 	return (0);
2733 
2734 fail2:
2735 	EFSYS_PROBE(fail2);
2736 fail1:
2737 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2738 
2739 	return (rc);
2740 }
2741 
2742 	__checkReturn			efx_rc_t
2743 efx_mae_counters_stream_stop(
2744 	__in				efx_nic_t *enp,
2745 	__in				uint16_t rxq_id,
2746 	__out_opt			uint32_t *gen_countp)
2747 {
2748 	efx_mcdi_req_t req;
2749 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN,
2750 			     MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN);
2751 	efx_rc_t rc;
2752 
2753 	req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_STOP;
2754 	req.emr_in_buf = payload;
2755 	req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN;
2756 	req.emr_out_buf = payload;
2757 	req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN;
2758 
2759 	MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_STOP_IN_QID, rxq_id);
2760 
2761 	efx_mcdi_execute(enp, &req);
2762 
2763 	if (req.emr_rc != 0) {
2764 		rc = req.emr_rc;
2765 		goto fail1;
2766 	}
2767 
2768 	if (req.emr_out_length_used <
2769 	    MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN) {
2770 		rc = EMSGSIZE;
2771 		goto fail2;
2772 	}
2773 
2774 	if (gen_countp != NULL) {
2775 		*gen_countp = MCDI_OUT_DWORD(req,
2776 			    MAE_COUNTERS_STREAM_STOP_OUT_GENERATION_COUNT);
2777 	}
2778 
2779 	return (0);
2780 
2781 fail2:
2782 	EFSYS_PROBE(fail2);
2783 fail1:
2784 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2785 
2786 	return (rc);
2787 }
2788 
2789 	__checkReturn			efx_rc_t
2790 efx_mae_counters_stream_give_credits(
2791 	__in				efx_nic_t *enp,
2792 	__in				uint32_t n_credits)
2793 {
2794 	efx_mcdi_req_t req;
2795 	EFX_MCDI_DECLARE_BUF(payload,
2796 			     MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN,
2797 			     MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN);
2798 	efx_rc_t rc;
2799 
2800 	req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS;
2801 	req.emr_in_buf = payload;
2802 	req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN;
2803 	req.emr_out_buf = payload;
2804 	req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN;
2805 
2806 	MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_NUM_CREDITS,
2807 			 n_credits);
2808 
2809 	efx_mcdi_execute(enp, &req);
2810 
2811 	if (req.emr_rc != 0) {
2812 		rc = req.emr_rc;
2813 		goto fail1;
2814 	}
2815 
2816 	return (0);
2817 
2818 fail1:
2819 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2820 
2821 	return (rc);
2822 }
2823 
2824 	__checkReturn			efx_rc_t
2825 efx_mae_action_set_free(
2826 	__in				efx_nic_t *enp,
2827 	__in				const efx_mae_aset_id_t *aset_idp)
2828 {
2829 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2830 	efx_mcdi_req_t req;
2831 	EFX_MCDI_DECLARE_BUF(payload,
2832 	    MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
2833 	    MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
2834 	efx_rc_t rc;
2835 
2836 	if (encp->enc_mae_supported == B_FALSE) {
2837 		rc = ENOTSUP;
2838 		goto fail1;
2839 	}
2840 
2841 	req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
2842 	req.emr_in_buf = payload;
2843 	req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
2844 	req.emr_out_buf = payload;
2845 	req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
2846 
2847 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
2848 
2849 	efx_mcdi_execute(enp, &req);
2850 
2851 	if (req.emr_rc != 0) {
2852 		rc = req.emr_rc;
2853 		goto fail2;
2854 	}
2855 
2856 	if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_FREE_OUT_LENMIN) {
2857 		rc = EMSGSIZE;
2858 		goto fail3;
2859 	}
2860 
2861 	if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
2862 	    aset_idp->id) {
2863 		/* Firmware failed to free the action set. */
2864 		rc = EAGAIN;
2865 		goto fail4;
2866 	}
2867 
2868 	return (0);
2869 
2870 fail4:
2871 	EFSYS_PROBE(fail4);
2872 fail3:
2873 	EFSYS_PROBE(fail3);
2874 fail2:
2875 	EFSYS_PROBE(fail2);
2876 fail1:
2877 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2878 	return (rc);
2879 }
2880 
2881 	__checkReturn			efx_rc_t
2882 efx_mae_action_rule_insert(
2883 	__in				efx_nic_t *enp,
2884 	__in				const efx_mae_match_spec_t *spec,
2885 	__in				const efx_mae_aset_list_id_t *asl_idp,
2886 	__in				const efx_mae_aset_id_t *as_idp,
2887 	__out				efx_mae_rule_id_t *ar_idp)
2888 {
2889 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2890 	efx_mcdi_req_t req;
2891 	EFX_MCDI_DECLARE_BUF(payload,
2892 	    MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2,
2893 	    MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
2894 	efx_oword_t *rule_response;
2895 	efx_mae_rule_id_t ar_id;
2896 	size_t offset;
2897 	efx_rc_t rc;
2898 
2899 	EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
2900 	    MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
2901 
2902 	EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2903 	    MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
2904 
2905 	if (encp->enc_mae_supported == B_FALSE) {
2906 		rc = ENOTSUP;
2907 		goto fail1;
2908 	}
2909 
2910 	if (spec->emms_type != EFX_MAE_RULE_ACTION ||
2911 	    (asl_idp != NULL && as_idp != NULL) ||
2912 	    (asl_idp == NULL && as_idp == NULL)) {
2913 		rc = EINVAL;
2914 		goto fail2;
2915 	}
2916 
2917 	req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
2918 	req.emr_in_buf = payload;
2919 	req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
2920 	req.emr_out_buf = payload;
2921 	req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
2922 
2923 	EFX_STATIC_ASSERT(sizeof (*rule_response) <=
2924 	    MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
2925 	offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
2926 	rule_response = (efx_oword_t *)(payload + offset);
2927 	EFX_POPULATE_OWORD_3(*rule_response,
2928 	    MAE_ACTION_RULE_RESPONSE_ASL_ID,
2929 	    (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
2930 	    MAE_ACTION_RULE_RESPONSE_AS_ID,
2931 	    (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
2932 	    MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
2933 
2934 	MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
2935 
2936 	/*
2937 	 * Mask-value pairs have been stored in the byte order needed for the
2938 	 * MCDI request and are thus safe to be copied directly to the buffer.
2939 	 */
2940 	EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
2941 	    MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
2942 	offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
2943 	memcpy(payload + offset, spec->emms_mask_value_pairs.action,
2944 	    MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
2945 
2946 	efx_mcdi_execute(enp, &req);
2947 
2948 	if (req.emr_rc != 0) {
2949 		rc = req.emr_rc;
2950 		goto fail3;
2951 	}
2952 
2953 	if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
2954 		rc = EMSGSIZE;
2955 		goto fail4;
2956 	}
2957 
2958 	ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
2959 	if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
2960 		rc = ENOENT;
2961 		goto fail5;
2962 	}
2963 
2964 	ar_idp->id = ar_id.id;
2965 
2966 	return (0);
2967 
2968 fail5:
2969 	EFSYS_PROBE(fail5);
2970 fail4:
2971 	EFSYS_PROBE(fail4);
2972 fail3:
2973 	EFSYS_PROBE(fail3);
2974 fail2:
2975 	EFSYS_PROBE(fail2);
2976 fail1:
2977 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2978 	return (rc);
2979 }
2980 
2981 	__checkReturn			efx_rc_t
2982 efx_mae_action_rule_remove(
2983 	__in				efx_nic_t *enp,
2984 	__in				const efx_mae_rule_id_t *ar_idp)
2985 {
2986 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2987 	efx_mcdi_req_t req;
2988 	EFX_MCDI_DECLARE_BUF(payload,
2989 	    MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
2990 	    MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
2991 	efx_rc_t rc;
2992 
2993 	if (encp->enc_mae_supported == B_FALSE) {
2994 		rc = ENOTSUP;
2995 		goto fail1;
2996 	}
2997 
2998 	req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
2999 	req.emr_in_buf = payload;
3000 	req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
3001 	req.emr_out_buf = payload;
3002 	req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
3003 
3004 	MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
3005 
3006 	efx_mcdi_execute(enp, &req);
3007 
3008 	if (req.emr_rc != 0) {
3009 		rc = req.emr_rc;
3010 		goto fail2;
3011 	}
3012 
3013 	if (req.emr_out_length_used <
3014 	    MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LENMIN) {
3015 		rc = EMSGSIZE;
3016 		goto fail3;
3017 	}
3018 
3019 	if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
3020 	    ar_idp->id) {
3021 		/* Firmware failed to delete the action rule. */
3022 		rc = EAGAIN;
3023 		goto fail4;
3024 	}
3025 
3026 	return (0);
3027 
3028 fail4:
3029 	EFSYS_PROBE(fail4);
3030 fail3:
3031 	EFSYS_PROBE(fail3);
3032 fail2:
3033 	EFSYS_PROBE(fail2);
3034 fail1:
3035 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
3036 	return (rc);
3037 }
3038 
3039 #endif /* EFSYS_OPT_MAE */
3040