xref: /dpdk/drivers/common/sfc_efx/base/efx_mae.c (revision 02edbfab)
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 	return (0);
71 
72 fail2:
73 	EFSYS_PROBE(fail2);
74 fail1:
75 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
76 	return (rc);
77 }
78 
79 static	__checkReturn			efx_rc_t
80 efx_mae_get_outer_rule_caps(
81 	__in				efx_nic_t *enp,
82 	__in				unsigned int field_ncaps,
83 	__out_ecount(field_ncaps)	efx_mae_field_cap_t *field_caps)
84 {
85 	efx_mcdi_req_t req;
86 	EFX_MCDI_DECLARE_BUF(payload,
87 	    MC_CMD_MAE_GET_OR_CAPS_IN_LEN,
88 	    MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2);
89 	unsigned int mcdi_field_ncaps;
90 	unsigned int i;
91 	efx_rc_t rc;
92 
93 	if (MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps) >
94 	    MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2) {
95 		rc = EINVAL;
96 		goto fail1;
97 	}
98 
99 	req.emr_cmd = MC_CMD_MAE_GET_OR_CAPS;
100 	req.emr_in_buf = payload;
101 	req.emr_in_length = MC_CMD_MAE_GET_OR_CAPS_IN_LEN;
102 	req.emr_out_buf = payload;
103 	req.emr_out_length = MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps);
104 
105 	efx_mcdi_execute(enp, &req);
106 
107 	if (req.emr_rc != 0) {
108 		rc = req.emr_rc;
109 		goto fail2;
110 	}
111 
112 	if (req.emr_out_length_used < MC_CMD_MAE_GET_OR_CAPS_OUT_LENMIN) {
113 		rc = EMSGSIZE;
114 		goto fail3;
115 	}
116 
117 	mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_OR_CAPS_OUT_COUNT);
118 
119 	if (req.emr_out_length_used <
120 	    MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(mcdi_field_ncaps)) {
121 		rc = EMSGSIZE;
122 		goto fail4;
123 	}
124 
125 	if (mcdi_field_ncaps > field_ncaps) {
126 		rc = EMSGSIZE;
127 		goto fail5;
128 	}
129 
130 	for (i = 0; i < mcdi_field_ncaps; ++i) {
131 		uint32_t match_flag;
132 		uint32_t mask_flag;
133 
134 		field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req,
135 		    MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
136 		    MAE_FIELD_FLAGS_SUPPORT_STATUS);
137 
138 		match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
139 		    MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
140 		    MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS);
141 
142 		field_caps[i].emfc_match_affects_class =
143 		    (match_flag != 0) ? B_TRUE : B_FALSE;
144 
145 		mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
146 		    MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
147 		    MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS);
148 
149 		field_caps[i].emfc_mask_affects_class =
150 		    (mask_flag != 0) ? B_TRUE : B_FALSE;
151 	}
152 
153 	return (0);
154 
155 fail5:
156 	EFSYS_PROBE(fail5);
157 fail4:
158 	EFSYS_PROBE(fail4);
159 fail3:
160 	EFSYS_PROBE(fail3);
161 fail2:
162 	EFSYS_PROBE(fail2);
163 fail1:
164 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
165 	return (rc);
166 }
167 
168 static	__checkReturn			efx_rc_t
169 efx_mae_get_action_rule_caps(
170 	__in				efx_nic_t *enp,
171 	__in				unsigned int field_ncaps,
172 	__out_ecount(field_ncaps)	efx_mae_field_cap_t *field_caps)
173 {
174 	efx_mcdi_req_t req;
175 	EFX_MCDI_DECLARE_BUF(payload,
176 	    MC_CMD_MAE_GET_AR_CAPS_IN_LEN,
177 	    MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2);
178 	unsigned int mcdi_field_ncaps;
179 	unsigned int i;
180 	efx_rc_t rc;
181 
182 	if (MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps) >
183 	    MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2) {
184 		rc = EINVAL;
185 		goto fail1;
186 	}
187 
188 	req.emr_cmd = MC_CMD_MAE_GET_AR_CAPS;
189 	req.emr_in_buf = payload;
190 	req.emr_in_length = MC_CMD_MAE_GET_AR_CAPS_IN_LEN;
191 	req.emr_out_buf = payload;
192 	req.emr_out_length = MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps);
193 
194 	efx_mcdi_execute(enp, &req);
195 
196 	if (req.emr_rc != 0) {
197 		rc = req.emr_rc;
198 		goto fail2;
199 	}
200 
201 	if (req.emr_out_length_used < MC_CMD_MAE_GET_AR_CAPS_OUT_LENMIN) {
202 		rc = EMSGSIZE;
203 		goto fail3;
204 	}
205 
206 	mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_AR_CAPS_OUT_COUNT);
207 
208 	if (req.emr_out_length_used <
209 	    MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(mcdi_field_ncaps)) {
210 		rc = EMSGSIZE;
211 		goto fail4;
212 	}
213 
214 	if (mcdi_field_ncaps > field_ncaps) {
215 		rc = EMSGSIZE;
216 		goto fail5;
217 	}
218 
219 	for (i = 0; i < mcdi_field_ncaps; ++i) {
220 		uint32_t match_flag;
221 		uint32_t mask_flag;
222 
223 		field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req,
224 		    MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
225 		    MAE_FIELD_FLAGS_SUPPORT_STATUS);
226 
227 		match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
228 		    MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
229 		    MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS);
230 
231 		field_caps[i].emfc_match_affects_class =
232 		    (match_flag != 0) ? B_TRUE : B_FALSE;
233 
234 		mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
235 		    MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
236 		    MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS);
237 
238 		field_caps[i].emfc_mask_affects_class =
239 		    (mask_flag != 0) ? B_TRUE : B_FALSE;
240 	}
241 
242 	return (0);
243 
244 fail5:
245 	EFSYS_PROBE(fail5);
246 fail4:
247 	EFSYS_PROBE(fail4);
248 fail3:
249 	EFSYS_PROBE(fail3);
250 fail2:
251 	EFSYS_PROBE(fail2);
252 fail1:
253 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
254 	return (rc);
255 }
256 
257 	__checkReturn			efx_rc_t
258 efx_mae_init(
259 	__in				efx_nic_t *enp)
260 {
261 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
262 	efx_mae_field_cap_t *or_fcaps;
263 	size_t or_fcaps_size;
264 	efx_mae_field_cap_t *ar_fcaps;
265 	size_t ar_fcaps_size;
266 	efx_mae_t *maep;
267 	efx_rc_t rc;
268 
269 	if (encp->enc_mae_supported == B_FALSE) {
270 		rc = ENOTSUP;
271 		goto fail1;
272 	}
273 
274 	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*maep), maep);
275 	if (maep == NULL) {
276 		rc = ENOMEM;
277 		goto fail2;
278 	}
279 
280 	enp->en_maep = maep;
281 
282 	rc = efx_mae_get_capabilities(enp);
283 	if (rc != 0)
284 		goto fail3;
285 
286 	or_fcaps_size = maep->em_max_nfields * sizeof (*or_fcaps);
287 	EFSYS_KMEM_ALLOC(enp->en_esip, or_fcaps_size, or_fcaps);
288 	if (or_fcaps == NULL) {
289 		rc = ENOMEM;
290 		goto fail4;
291 	}
292 
293 	maep->em_outer_rule_field_caps_size = or_fcaps_size;
294 	maep->em_outer_rule_field_caps = or_fcaps;
295 
296 	rc = efx_mae_get_outer_rule_caps(enp, maep->em_max_nfields, or_fcaps);
297 	if (rc != 0)
298 		goto fail5;
299 
300 	ar_fcaps_size = maep->em_max_nfields * sizeof (*ar_fcaps);
301 	EFSYS_KMEM_ALLOC(enp->en_esip, ar_fcaps_size, ar_fcaps);
302 	if (ar_fcaps == NULL) {
303 		rc = ENOMEM;
304 		goto fail6;
305 	}
306 
307 	maep->em_action_rule_field_caps_size = ar_fcaps_size;
308 	maep->em_action_rule_field_caps = ar_fcaps;
309 
310 	rc = efx_mae_get_action_rule_caps(enp, maep->em_max_nfields, ar_fcaps);
311 	if (rc != 0)
312 		goto fail7;
313 
314 	return (0);
315 
316 fail7:
317 	EFSYS_PROBE(fail5);
318 	EFSYS_KMEM_FREE(enp->en_esip, ar_fcaps_size, ar_fcaps);
319 fail6:
320 	EFSYS_PROBE(fail4);
321 fail5:
322 	EFSYS_PROBE(fail5);
323 	EFSYS_KMEM_FREE(enp->en_esip, or_fcaps_size, or_fcaps);
324 fail4:
325 	EFSYS_PROBE(fail4);
326 fail3:
327 	EFSYS_PROBE(fail3);
328 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (struct efx_mae_s), enp->en_maep);
329 	enp->en_maep = NULL;
330 fail2:
331 	EFSYS_PROBE(fail2);
332 fail1:
333 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
334 	return (rc);
335 }
336 
337 					void
338 efx_mae_fini(
339 	__in				efx_nic_t *enp)
340 {
341 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
342 	efx_mae_t *maep = enp->en_maep;
343 
344 	if (encp->enc_mae_supported == B_FALSE)
345 		return;
346 
347 	EFSYS_KMEM_FREE(enp->en_esip, maep->em_action_rule_field_caps_size,
348 	    maep->em_action_rule_field_caps);
349 	EFSYS_KMEM_FREE(enp->en_esip, maep->em_outer_rule_field_caps_size,
350 	    maep->em_outer_rule_field_caps);
351 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (*maep), maep);
352 	enp->en_maep = NULL;
353 }
354 
355 	__checkReturn			efx_rc_t
356 efx_mae_get_limits(
357 	__in				efx_nic_t *enp,
358 	__out				efx_mae_limits_t *emlp)
359 {
360 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
361 	struct efx_mae_s *maep = enp->en_maep;
362 	efx_rc_t rc;
363 
364 	if (encp->enc_mae_supported == B_FALSE) {
365 		rc = ENOTSUP;
366 		goto fail1;
367 	}
368 
369 	emlp->eml_max_n_outer_prios = maep->em_max_n_outer_prios;
370 	emlp->eml_max_n_action_prios = maep->em_max_n_action_prios;
371 	emlp->eml_encap_types_supported = maep->em_encap_types_supported;
372 	emlp->eml_encap_header_size_limit =
373 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2;
374 
375 	return (0);
376 
377 fail1:
378 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
379 	return (rc);
380 }
381 
382 	__checkReturn			efx_rc_t
383 efx_mae_match_spec_init(
384 	__in				efx_nic_t *enp,
385 	__in				efx_mae_rule_type_t type,
386 	__in				uint32_t prio,
387 	__out				efx_mae_match_spec_t **specp)
388 {
389 	efx_mae_match_spec_t *spec;
390 	efx_rc_t rc;
391 
392 	switch (type) {
393 	case EFX_MAE_RULE_OUTER:
394 		break;
395 	case EFX_MAE_RULE_ACTION:
396 		break;
397 	default:
398 		rc = ENOTSUP;
399 		goto fail1;
400 	}
401 
402 	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
403 	if (spec == NULL) {
404 		rc = ENOMEM;
405 		goto fail2;
406 	}
407 
408 	spec->emms_type = type;
409 	spec->emms_prio = prio;
410 
411 	*specp = spec;
412 
413 	return (0);
414 
415 fail2:
416 	EFSYS_PROBE(fail2);
417 fail1:
418 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
419 	return (rc);
420 }
421 
422 					void
423 efx_mae_match_spec_fini(
424 	__in				efx_nic_t *enp,
425 	__in				efx_mae_match_spec_t *spec)
426 {
427 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
428 }
429 
430 /* Named identifiers which are valid indices to efx_mae_field_cap_t */
431 typedef enum efx_mae_field_cap_id_e {
432 	EFX_MAE_FIELD_ID_INGRESS_MPORT_SELECTOR = MAE_FIELD_INGRESS_PORT,
433 	EFX_MAE_FIELD_ID_ETHER_TYPE_BE = MAE_FIELD_ETHER_TYPE,
434 	EFX_MAE_FIELD_ID_ETH_SADDR_BE = MAE_FIELD_ETH_SADDR,
435 	EFX_MAE_FIELD_ID_ETH_DADDR_BE = MAE_FIELD_ETH_DADDR,
436 	EFX_MAE_FIELD_ID_VLAN0_TCI_BE = MAE_FIELD_VLAN0_TCI,
437 	EFX_MAE_FIELD_ID_VLAN0_PROTO_BE = MAE_FIELD_VLAN0_PROTO,
438 	EFX_MAE_FIELD_ID_VLAN1_TCI_BE = MAE_FIELD_VLAN1_TCI,
439 	EFX_MAE_FIELD_ID_VLAN1_PROTO_BE = MAE_FIELD_VLAN1_PROTO,
440 	EFX_MAE_FIELD_ID_SRC_IP4_BE = MAE_FIELD_SRC_IP4,
441 	EFX_MAE_FIELD_ID_DST_IP4_BE = MAE_FIELD_DST_IP4,
442 	EFX_MAE_FIELD_ID_IP_PROTO = MAE_FIELD_IP_PROTO,
443 	EFX_MAE_FIELD_ID_IP_TOS = MAE_FIELD_IP_TOS,
444 	EFX_MAE_FIELD_ID_IP_TTL = MAE_FIELD_IP_TTL,
445 	EFX_MAE_FIELD_ID_SRC_IP6_BE = MAE_FIELD_SRC_IP6,
446 	EFX_MAE_FIELD_ID_DST_IP6_BE = MAE_FIELD_DST_IP6,
447 	EFX_MAE_FIELD_ID_L4_SPORT_BE = MAE_FIELD_L4_SPORT,
448 	EFX_MAE_FIELD_ID_L4_DPORT_BE = MAE_FIELD_L4_DPORT,
449 	EFX_MAE_FIELD_ID_TCP_FLAGS_BE = MAE_FIELD_TCP_FLAGS,
450 	EFX_MAE_FIELD_ID_ENC_ETHER_TYPE_BE = MAE_FIELD_ENC_ETHER_TYPE,
451 	EFX_MAE_FIELD_ID_ENC_ETH_SADDR_BE = MAE_FIELD_ENC_ETH_SADDR,
452 	EFX_MAE_FIELD_ID_ENC_ETH_DADDR_BE = MAE_FIELD_ENC_ETH_DADDR,
453 	EFX_MAE_FIELD_ID_ENC_VLAN0_TCI_BE = MAE_FIELD_ENC_VLAN0_TCI,
454 	EFX_MAE_FIELD_ID_ENC_VLAN0_PROTO_BE = MAE_FIELD_ENC_VLAN0_PROTO,
455 	EFX_MAE_FIELD_ID_ENC_VLAN1_TCI_BE = MAE_FIELD_ENC_VLAN1_TCI,
456 	EFX_MAE_FIELD_ID_ENC_VLAN1_PROTO_BE = MAE_FIELD_ENC_VLAN1_PROTO,
457 	EFX_MAE_FIELD_ID_ENC_SRC_IP4_BE = MAE_FIELD_ENC_SRC_IP4,
458 	EFX_MAE_FIELD_ID_ENC_DST_IP4_BE = MAE_FIELD_ENC_DST_IP4,
459 	EFX_MAE_FIELD_ID_ENC_IP_PROTO = MAE_FIELD_ENC_IP_PROTO,
460 	EFX_MAE_FIELD_ID_ENC_IP_TOS = MAE_FIELD_ENC_IP_TOS,
461 	EFX_MAE_FIELD_ID_ENC_IP_TTL = MAE_FIELD_ENC_IP_TTL,
462 	EFX_MAE_FIELD_ID_ENC_SRC_IP6_BE = MAE_FIELD_ENC_SRC_IP6,
463 	EFX_MAE_FIELD_ID_ENC_DST_IP6_BE = MAE_FIELD_ENC_DST_IP6,
464 	EFX_MAE_FIELD_ID_ENC_L4_SPORT_BE = MAE_FIELD_ENC_L4_SPORT,
465 	EFX_MAE_FIELD_ID_ENC_L4_DPORT_BE = MAE_FIELD_ENC_L4_DPORT,
466 	EFX_MAE_FIELD_ID_ENC_VNET_ID_BE = MAE_FIELD_ENC_VNET_ID,
467 	EFX_MAE_FIELD_ID_OUTER_RULE_ID = MAE_FIELD_OUTER_RULE_ID,
468 	EFX_MAE_FIELD_ID_HAS_OVLAN = MAE_FIELD_HAS_OVLAN,
469 	EFX_MAE_FIELD_ID_HAS_IVLAN = MAE_FIELD_HAS_IVLAN,
470 	EFX_MAE_FIELD_ID_ENC_HAS_OVLAN = MAE_FIELD_ENC_HAS_OVLAN,
471 	EFX_MAE_FIELD_ID_ENC_HAS_IVLAN = MAE_FIELD_ENC_HAS_IVLAN,
472 
473 	EFX_MAE_FIELD_CAP_NIDS
474 } efx_mae_field_cap_id_t;
475 
476 typedef enum efx_mae_field_endianness_e {
477 	EFX_MAE_FIELD_LE = 0,
478 	EFX_MAE_FIELD_BE,
479 
480 	EFX_MAE_FIELD_ENDIANNESS_NTYPES
481 } efx_mae_field_endianness_t;
482 
483 /*
484  * The following structure is a means to describe an MAE field.
485  * The information in it is meant to be used internally by
486  * APIs for addressing a given field in a mask-value pairs
487  * structure and for validation purposes.
488  *
489  * A field may have an alternative one. This structure
490  * has additional members to reference the alternative
491  * field's mask. See efx_mae_match_spec_is_valid().
492  */
493 typedef struct efx_mae_mv_desc_s {
494 	efx_mae_field_cap_id_t		emmd_field_cap_id;
495 
496 	size_t				emmd_value_size;
497 	size_t				emmd_value_offset;
498 	size_t				emmd_mask_size;
499 	size_t				emmd_mask_offset;
500 
501 	/*
502 	 * Having the alternative field's mask size set to 0
503 	 * means that there's no alternative field specified.
504 	 */
505 	size_t				emmd_alt_mask_size;
506 	size_t				emmd_alt_mask_offset;
507 
508 	/* Primary field and the alternative one are of the same endianness. */
509 	efx_mae_field_endianness_t	emmd_endianness;
510 } efx_mae_mv_desc_t;
511 
512 /* Indices to this array are provided by efx_mae_field_id_t */
513 static const efx_mae_mv_desc_t __efx_mae_action_rule_mv_desc_set[] = {
514 #define	EFX_MAE_MV_DESC(_name, _endianness)				\
515 	[EFX_MAE_FIELD_##_name] =					\
516 	{								\
517 		EFX_MAE_FIELD_ID_##_name,				\
518 		MAE_FIELD_MASK_VALUE_PAIRS_##_name##_LEN,		\
519 		MAE_FIELD_MASK_VALUE_PAIRS_##_name##_OFST,		\
520 		MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_LEN,		\
521 		MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_OFST,		\
522 		0, 0 /* no alternative field */,			\
523 		_endianness						\
524 	}
525 
526 	EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
527 	EFX_MAE_MV_DESC(ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
528 	EFX_MAE_MV_DESC(ETH_SADDR_BE, EFX_MAE_FIELD_BE),
529 	EFX_MAE_MV_DESC(ETH_DADDR_BE, EFX_MAE_FIELD_BE),
530 	EFX_MAE_MV_DESC(VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
531 	EFX_MAE_MV_DESC(VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
532 	EFX_MAE_MV_DESC(VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
533 	EFX_MAE_MV_DESC(VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
534 	EFX_MAE_MV_DESC(SRC_IP4_BE, EFX_MAE_FIELD_BE),
535 	EFX_MAE_MV_DESC(DST_IP4_BE, EFX_MAE_FIELD_BE),
536 	EFX_MAE_MV_DESC(IP_PROTO, EFX_MAE_FIELD_BE),
537 	EFX_MAE_MV_DESC(IP_TOS, EFX_MAE_FIELD_BE),
538 	EFX_MAE_MV_DESC(IP_TTL, EFX_MAE_FIELD_BE),
539 	EFX_MAE_MV_DESC(SRC_IP6_BE, EFX_MAE_FIELD_BE),
540 	EFX_MAE_MV_DESC(DST_IP6_BE, EFX_MAE_FIELD_BE),
541 	EFX_MAE_MV_DESC(L4_SPORT_BE, EFX_MAE_FIELD_BE),
542 	EFX_MAE_MV_DESC(L4_DPORT_BE, EFX_MAE_FIELD_BE),
543 	EFX_MAE_MV_DESC(TCP_FLAGS_BE, EFX_MAE_FIELD_BE),
544 	EFX_MAE_MV_DESC(ENC_VNET_ID_BE, EFX_MAE_FIELD_BE),
545 	EFX_MAE_MV_DESC(OUTER_RULE_ID, EFX_MAE_FIELD_LE),
546 
547 #undef EFX_MAE_MV_DESC
548 };
549 
550 /* Indices to this array are provided by efx_mae_field_id_t */
551 static const efx_mae_mv_desc_t __efx_mae_outer_rule_mv_desc_set[] = {
552 #define	EFX_MAE_MV_DESC(_name, _endianness)				\
553 	[EFX_MAE_FIELD_##_name] =					\
554 	{								\
555 		EFX_MAE_FIELD_ID_##_name,				\
556 		MAE_ENC_FIELD_PAIRS_##_name##_LEN,			\
557 		MAE_ENC_FIELD_PAIRS_##_name##_OFST,			\
558 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,			\
559 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,		\
560 		0, 0 /* no alternative field */,			\
561 		_endianness						\
562 	}
563 
564 /* Same as EFX_MAE_MV_DESC(), but also indicates an alternative field. */
565 #define	EFX_MAE_MV_DESC_ALT(_name, _alt_name, _endianness)		\
566 	[EFX_MAE_FIELD_##_name] =					\
567 	{								\
568 		EFX_MAE_FIELD_ID_##_name,				\
569 		MAE_ENC_FIELD_PAIRS_##_name##_LEN,			\
570 		MAE_ENC_FIELD_PAIRS_##_name##_OFST,			\
571 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,			\
572 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,		\
573 		MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_LEN,		\
574 		MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_OFST,		\
575 		_endianness						\
576 	}
577 
578 	EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
579 	EFX_MAE_MV_DESC(ENC_ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
580 	EFX_MAE_MV_DESC(ENC_ETH_SADDR_BE, EFX_MAE_FIELD_BE),
581 	EFX_MAE_MV_DESC(ENC_ETH_DADDR_BE, EFX_MAE_FIELD_BE),
582 	EFX_MAE_MV_DESC(ENC_VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
583 	EFX_MAE_MV_DESC(ENC_VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
584 	EFX_MAE_MV_DESC(ENC_VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
585 	EFX_MAE_MV_DESC(ENC_VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
586 	EFX_MAE_MV_DESC_ALT(ENC_SRC_IP4_BE, ENC_SRC_IP6_BE, EFX_MAE_FIELD_BE),
587 	EFX_MAE_MV_DESC_ALT(ENC_DST_IP4_BE, ENC_DST_IP6_BE, EFX_MAE_FIELD_BE),
588 	EFX_MAE_MV_DESC(ENC_IP_PROTO, EFX_MAE_FIELD_BE),
589 	EFX_MAE_MV_DESC(ENC_IP_TOS, EFX_MAE_FIELD_BE),
590 	EFX_MAE_MV_DESC(ENC_IP_TTL, EFX_MAE_FIELD_BE),
591 	EFX_MAE_MV_DESC_ALT(ENC_SRC_IP6_BE, ENC_SRC_IP4_BE, EFX_MAE_FIELD_BE),
592 	EFX_MAE_MV_DESC_ALT(ENC_DST_IP6_BE, ENC_DST_IP4_BE, EFX_MAE_FIELD_BE),
593 	EFX_MAE_MV_DESC(ENC_L4_SPORT_BE, EFX_MAE_FIELD_BE),
594 	EFX_MAE_MV_DESC(ENC_L4_DPORT_BE, EFX_MAE_FIELD_BE),
595 
596 #undef EFX_MAE_MV_DESC_ALT
597 #undef EFX_MAE_MV_DESC
598 };
599 
600 /*
601  * The following structure is a means to describe an MAE bit.
602  * The information in it is meant to be used internally by
603  * APIs for addressing a given flag in a mask-value pairs
604  * structure and for validation purposes.
605  */
606 typedef struct efx_mae_mv_bit_desc_s {
607 	/*
608 	 * Arrays using this struct are indexed by field IDs.
609 	 * Fields which aren't meant to be referenced by these
610 	 * arrays comprise gaps (invalid entries). Below field
611 	 * helps to identify such entries.
612 	 */
613 	boolean_t			emmbd_entry_is_valid;
614 	efx_mae_field_cap_id_t		emmbd_bit_cap_id;
615 	size_t				emmbd_value_ofst;
616 	unsigned int			emmbd_value_lbn;
617 	size_t				emmbd_mask_ofst;
618 	unsigned int			emmbd_mask_lbn;
619 } efx_mae_mv_bit_desc_t;
620 
621 static const efx_mae_mv_bit_desc_t __efx_mae_outer_rule_mv_bit_desc_set[] = {
622 #define	EFX_MAE_MV_BIT_DESC(_name)					\
623 	[EFX_MAE_FIELD_##_name] =					\
624 	{								\
625 		B_TRUE,							\
626 		EFX_MAE_FIELD_ID_##_name,				\
627 		MAE_ENC_FIELD_PAIRS_##_name##_OFST,			\
628 		MAE_ENC_FIELD_PAIRS_##_name##_LBN,			\
629 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,		\
630 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_LBN,			\
631 	}
632 
633 	EFX_MAE_MV_BIT_DESC(ENC_HAS_OVLAN),
634 	EFX_MAE_MV_BIT_DESC(ENC_HAS_IVLAN),
635 
636 #undef EFX_MAE_MV_BIT_DESC
637 };
638 
639 static const efx_mae_mv_bit_desc_t __efx_mae_action_rule_mv_bit_desc_set[] = {
640 #define	EFX_MAE_MV_BIT_DESC(_name)					\
641 	[EFX_MAE_FIELD_##_name] =					\
642 	{								\
643 		B_TRUE,							\
644 		EFX_MAE_FIELD_ID_##_name,				\
645 		MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_OFST,		\
646 		MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LBN,		\
647 		MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK_OFST,		\
648 		MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LBN,		\
649 	}
650 
651 	EFX_MAE_MV_BIT_DESC(HAS_OVLAN),
652 	EFX_MAE_MV_BIT_DESC(HAS_IVLAN),
653 	EFX_MAE_MV_BIT_DESC(ENC_HAS_OVLAN),
654 	EFX_MAE_MV_BIT_DESC(ENC_HAS_IVLAN),
655 
656 #undef EFX_MAE_MV_BIT_DESC
657 };
658 
659 	__checkReturn			efx_rc_t
660 efx_mae_mport_by_phy_port(
661 	__in				uint32_t phy_port,
662 	__out				efx_mport_sel_t *mportp)
663 {
664 	efx_dword_t dword;
665 	efx_rc_t rc;
666 
667 	if (phy_port > EFX_MASK32(MAE_MPORT_SELECTOR_PPORT_ID)) {
668 		rc = EINVAL;
669 		goto fail1;
670 	}
671 
672 	EFX_POPULATE_DWORD_2(dword,
673 	    MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT,
674 	    MAE_MPORT_SELECTOR_PPORT_ID, phy_port);
675 
676 	memset(mportp, 0, sizeof (*mportp));
677 	/*
678 	 * The constructed DWORD is little-endian,
679 	 * but the resulting value is meant to be
680 	 * passed to MCDIs, where it will undergo
681 	 * host-order to little endian conversion.
682 	 */
683 	mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
684 
685 	return (0);
686 
687 fail1:
688 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
689 	return (rc);
690 }
691 
692 	__checkReturn			efx_rc_t
693 efx_mae_mport_by_pcie_function(
694 	__in				uint32_t pf,
695 	__in				uint32_t vf,
696 	__out				efx_mport_sel_t *mportp)
697 {
698 	efx_dword_t dword;
699 	efx_rc_t rc;
700 
701 	EFX_STATIC_ASSERT(EFX_PCI_VF_INVALID ==
702 	    MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL);
703 
704 	if (pf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_PF_ID)) {
705 		rc = EINVAL;
706 		goto fail1;
707 	}
708 
709 	if (vf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_VF_ID)) {
710 		rc = EINVAL;
711 		goto fail2;
712 	}
713 
714 	EFX_POPULATE_DWORD_3(dword,
715 	    MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
716 	    MAE_MPORT_SELECTOR_FUNC_PF_ID, pf,
717 	    MAE_MPORT_SELECTOR_FUNC_VF_ID, vf);
718 
719 	memset(mportp, 0, sizeof (*mportp));
720 	/*
721 	 * The constructed DWORD is little-endian,
722 	 * but the resulting value is meant to be
723 	 * passed to MCDIs, where it will undergo
724 	 * host-order to little endian conversion.
725 	 */
726 	mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
727 
728 	return (0);
729 
730 fail2:
731 	EFSYS_PROBE(fail2);
732 fail1:
733 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
734 	return (rc);
735 }
736 
737 	__checkReturn			efx_rc_t
738 efx_mae_match_spec_field_set(
739 	__in				efx_mae_match_spec_t *spec,
740 	__in				efx_mae_field_id_t field_id,
741 	__in				size_t value_size,
742 	__in_bcount(value_size)		const uint8_t *value,
743 	__in				size_t mask_size,
744 	__in_bcount(mask_size)		const uint8_t *mask)
745 {
746 	const efx_mae_mv_desc_t *descp;
747 	unsigned int desc_set_nentries;
748 	uint8_t *mvp;
749 	efx_rc_t rc;
750 
751 	switch (spec->emms_type) {
752 	case EFX_MAE_RULE_OUTER:
753 		desc_set_nentries =
754 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
755 		descp = &__efx_mae_outer_rule_mv_desc_set[field_id];
756 		mvp = spec->emms_mask_value_pairs.outer;
757 		break;
758 	case EFX_MAE_RULE_ACTION:
759 		desc_set_nentries =
760 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
761 		descp = &__efx_mae_action_rule_mv_desc_set[field_id];
762 		mvp = spec->emms_mask_value_pairs.action;
763 		break;
764 	default:
765 		rc = ENOTSUP;
766 		goto fail1;
767 	}
768 
769 	if ((unsigned int)field_id >= desc_set_nentries) {
770 		rc = EINVAL;
771 		goto fail2;
772 	}
773 
774 	if (descp->emmd_mask_size == 0) {
775 		/* The ID points to a gap in the array of field descriptors. */
776 		rc = EINVAL;
777 		goto fail3;
778 	}
779 
780 	if (value_size != descp->emmd_value_size) {
781 		rc = EINVAL;
782 		goto fail4;
783 	}
784 
785 	if (mask_size != descp->emmd_mask_size) {
786 		rc = EINVAL;
787 		goto fail5;
788 	}
789 
790 	if (descp->emmd_endianness == EFX_MAE_FIELD_BE) {
791 		unsigned int i;
792 
793 		/*
794 		 * The mask/value are in network (big endian) order.
795 		 * The MCDI request field is also big endian.
796 		 */
797 
798 		EFSYS_ASSERT3U(value_size, ==, mask_size);
799 
800 		for (i = 0; i < value_size; ++i) {
801 			uint8_t *v_bytep = mvp + descp->emmd_value_offset + i;
802 			uint8_t *m_bytep = mvp + descp->emmd_mask_offset + i;
803 
804 			/*
805 			 * Apply the mask (which may be all-zeros) to the value.
806 			 *
807 			 * If this API is provided with some value to set for a
808 			 * given field in one specification and with some other
809 			 * value to set for this field in another specification,
810 			 * then, if the two masks are all-zeros, the field will
811 			 * avoid being counted as a mismatch when comparing the
812 			 * specifications using efx_mae_match_specs_equal() API.
813 			 */
814 			*v_bytep = value[i] & mask[i];
815 			*m_bytep = mask[i];
816 		}
817 	} else {
818 		efx_dword_t dword;
819 
820 		/*
821 		 * The mask/value are in host byte order.
822 		 * The MCDI request field is little endian.
823 		 */
824 		switch (value_size) {
825 		case 4:
826 			EFX_POPULATE_DWORD_1(dword,
827 			    EFX_DWORD_0, *(const uint32_t *)value);
828 
829 			memcpy(mvp + descp->emmd_value_offset,
830 			    &dword, sizeof (dword));
831 			break;
832 		default:
833 			EFSYS_ASSERT(B_FALSE);
834 		}
835 
836 		switch (mask_size) {
837 		case 4:
838 			EFX_POPULATE_DWORD_1(dword,
839 			    EFX_DWORD_0, *(const uint32_t *)mask);
840 
841 			memcpy(mvp + descp->emmd_mask_offset,
842 			    &dword, sizeof (dword));
843 			break;
844 		default:
845 			EFSYS_ASSERT(B_FALSE);
846 		}
847 	}
848 
849 	return (0);
850 
851 fail5:
852 	EFSYS_PROBE(fail5);
853 fail4:
854 	EFSYS_PROBE(fail4);
855 fail3:
856 	EFSYS_PROBE(fail3);
857 fail2:
858 	EFSYS_PROBE(fail2);
859 fail1:
860 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
861 	return (rc);
862 }
863 
864 	__checkReturn			efx_rc_t
865 efx_mae_match_spec_bit_set(
866 	__in				efx_mae_match_spec_t *spec,
867 	__in				efx_mae_field_id_t field_id,
868 	__in				boolean_t value)
869 {
870 	const efx_mae_mv_bit_desc_t *bit_descp;
871 	unsigned int bit_desc_set_nentries;
872 	unsigned int byte_idx;
873 	unsigned int bit_idx;
874 	uint8_t *mvp;
875 	efx_rc_t rc;
876 
877 	switch (spec->emms_type) {
878 	case EFX_MAE_RULE_OUTER:
879 		bit_desc_set_nentries =
880 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
881 		bit_descp = &__efx_mae_outer_rule_mv_bit_desc_set[field_id];
882 		mvp = spec->emms_mask_value_pairs.outer;
883 		break;
884 	case EFX_MAE_RULE_ACTION:
885 		bit_desc_set_nentries =
886 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
887 		bit_descp = &__efx_mae_action_rule_mv_bit_desc_set[field_id];
888 		mvp = spec->emms_mask_value_pairs.action;
889 		break;
890 	default:
891 		rc = ENOTSUP;
892 		goto fail1;
893 	}
894 
895 	if ((unsigned int)field_id >= bit_desc_set_nentries) {
896 		rc = EINVAL;
897 		goto fail2;
898 	}
899 
900 	if (bit_descp->emmbd_entry_is_valid == B_FALSE) {
901 		rc = EINVAL;
902 		goto fail3;
903 	}
904 
905 	byte_idx = bit_descp->emmbd_value_ofst + bit_descp->emmbd_value_lbn / 8;
906 	bit_idx = bit_descp->emmbd_value_lbn % 8;
907 
908 	if (value != B_FALSE)
909 		mvp[byte_idx] |= (1U << bit_idx);
910 	else
911 		mvp[byte_idx] &= ~(1U << bit_idx);
912 
913 	byte_idx = bit_descp->emmbd_mask_ofst + bit_descp->emmbd_mask_lbn / 8;
914 	bit_idx = bit_descp->emmbd_mask_lbn % 8;
915 	mvp[byte_idx] |= (1U << bit_idx);
916 
917 	return (0);
918 
919 fail3:
920 	EFSYS_PROBE(fail3);
921 fail2:
922 	EFSYS_PROBE(fail2);
923 fail1:
924 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
925 	return (rc);
926 }
927 
928 	__checkReturn			efx_rc_t
929 efx_mae_match_spec_mport_set(
930 	__in				efx_mae_match_spec_t *spec,
931 	__in				const efx_mport_sel_t *valuep,
932 	__in_opt			const efx_mport_sel_t *maskp)
933 {
934 	uint32_t full_mask = UINT32_MAX;
935 	const uint8_t *vp;
936 	const uint8_t *mp;
937 	efx_rc_t rc;
938 
939 	if (valuep == NULL) {
940 		rc = EINVAL;
941 		goto fail1;
942 	}
943 
944 	vp = (const uint8_t *)&valuep->sel;
945 	if (maskp != NULL)
946 		mp = (const uint8_t *)&maskp->sel;
947 	else
948 		mp = (const uint8_t *)&full_mask;
949 
950 	rc = efx_mae_match_spec_field_set(spec,
951 	    EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR,
952 	    sizeof (valuep->sel), vp, sizeof (maskp->sel), mp);
953 	if (rc != 0)
954 		goto fail2;
955 
956 	return (0);
957 
958 fail2:
959 	EFSYS_PROBE(fail2);
960 fail1:
961 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
962 	return (rc);
963 }
964 
965 	__checkReturn			boolean_t
966 efx_mae_match_specs_equal(
967 	__in				const efx_mae_match_spec_t *left,
968 	__in				const efx_mae_match_spec_t *right)
969 {
970 	return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
971 }
972 
973 #define	EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit)		\
974 	    ((_mask)[(_bit) / (_mask_page_nbits)] &			\
975 		    (1ULL << ((_bit) & ((_mask_page_nbits) - 1))))
976 
977 static					boolean_t
978 efx_mask_is_prefix(
979 	__in				size_t mask_nbytes,
980 	__in_bcount(mask_nbytes)	const uint8_t *maskp)
981 {
982 	boolean_t prev_bit_is_set = B_TRUE;
983 	unsigned int i;
984 
985 	for (i = 0; i < 8 * mask_nbytes; ++i) {
986 		boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i);
987 
988 		if (!prev_bit_is_set && bit_is_set)
989 			return B_FALSE;
990 
991 		prev_bit_is_set = bit_is_set;
992 	}
993 
994 	return B_TRUE;
995 }
996 
997 static					boolean_t
998 efx_mask_is_all_ones(
999 	__in				size_t mask_nbytes,
1000 	__in_bcount(mask_nbytes)	const uint8_t *maskp)
1001 {
1002 	unsigned int i;
1003 	uint8_t t = ~0;
1004 
1005 	for (i = 0; i < mask_nbytes; ++i)
1006 		t &= maskp[i];
1007 
1008 	return (t == (uint8_t)(~0));
1009 }
1010 
1011 static					boolean_t
1012 efx_mask_is_all_zeros(
1013 	__in				size_t mask_nbytes,
1014 	__in_bcount(mask_nbytes)	const uint8_t *maskp)
1015 {
1016 	unsigned int i;
1017 	uint8_t t = 0;
1018 
1019 	for (i = 0; i < mask_nbytes; ++i)
1020 		t |= maskp[i];
1021 
1022 	return (t == 0);
1023 }
1024 
1025 	__checkReturn			boolean_t
1026 efx_mae_match_spec_is_valid(
1027 	__in				efx_nic_t *enp,
1028 	__in				const efx_mae_match_spec_t *spec)
1029 {
1030 	efx_mae_t *maep = enp->en_maep;
1031 	unsigned int field_ncaps = maep->em_max_nfields;
1032 	const efx_mae_field_cap_t *field_caps;
1033 	const efx_mae_mv_desc_t *desc_setp;
1034 	unsigned int desc_set_nentries;
1035 	const efx_mae_mv_bit_desc_t *bit_desc_setp;
1036 	unsigned int bit_desc_set_nentries;
1037 	boolean_t is_valid = B_TRUE;
1038 	efx_mae_field_id_t field_id;
1039 	const uint8_t *mvp;
1040 
1041 	switch (spec->emms_type) {
1042 	case EFX_MAE_RULE_OUTER:
1043 		field_caps = maep->em_outer_rule_field_caps;
1044 		desc_setp = __efx_mae_outer_rule_mv_desc_set;
1045 		desc_set_nentries =
1046 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1047 		bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
1048 		bit_desc_set_nentries =
1049 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
1050 		mvp = spec->emms_mask_value_pairs.outer;
1051 		break;
1052 	case EFX_MAE_RULE_ACTION:
1053 		field_caps = maep->em_action_rule_field_caps;
1054 		desc_setp = __efx_mae_action_rule_mv_desc_set;
1055 		desc_set_nentries =
1056 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1057 		bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
1058 		bit_desc_set_nentries =
1059 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
1060 		mvp = spec->emms_mask_value_pairs.action;
1061 		break;
1062 	default:
1063 		return (B_FALSE);
1064 	}
1065 
1066 	if (field_caps == NULL)
1067 		return (B_FALSE);
1068 
1069 	for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1070 	     ++field_id) {
1071 		const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1072 		efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1073 		const uint8_t *alt_m_buf = mvp + descp->emmd_alt_mask_offset;
1074 		const uint8_t *m_buf = mvp + descp->emmd_mask_offset;
1075 		size_t alt_m_size = descp->emmd_alt_mask_size;
1076 		size_t m_size = descp->emmd_mask_size;
1077 
1078 		if (m_size == 0)
1079 			continue; /* Skip array gap */
1080 
1081 		if ((unsigned int)field_cap_id >= field_ncaps) {
1082 			/*
1083 			 * The FW has not reported capability status for
1084 			 * this field. Make sure that its mask is zeroed.
1085 			 */
1086 			is_valid = efx_mask_is_all_zeros(m_size, m_buf);
1087 			if (is_valid != B_FALSE)
1088 				continue;
1089 			else
1090 				break;
1091 		}
1092 
1093 		switch (field_caps[field_cap_id].emfc_support) {
1094 		case MAE_FIELD_SUPPORTED_MATCH_MASK:
1095 			is_valid = B_TRUE;
1096 			break;
1097 		case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
1098 			is_valid = efx_mask_is_prefix(m_size, m_buf);
1099 			break;
1100 		case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
1101 			is_valid = (efx_mask_is_all_ones(m_size, m_buf) ||
1102 			    efx_mask_is_all_zeros(m_size, m_buf));
1103 			break;
1104 		case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
1105 			is_valid = efx_mask_is_all_ones(m_size, m_buf);
1106 
1107 			if ((is_valid == B_FALSE) && (alt_m_size != 0)) {
1108 				/*
1109 				 * This field has an alternative one. The FW
1110 				 * reports ALWAYS for both implying that one
1111 				 * of them is required to have all-ones mask.
1112 				 *
1113 				 * The primary field's mask is incorrect; go
1114 				 * on to check that of the alternative field.
1115 				 */
1116 				is_valid = efx_mask_is_all_ones(alt_m_size,
1117 								alt_m_buf);
1118 			}
1119 			break;
1120 		case MAE_FIELD_SUPPORTED_MATCH_NEVER:
1121 		case MAE_FIELD_UNSUPPORTED:
1122 		default:
1123 			is_valid = efx_mask_is_all_zeros(m_size, m_buf);
1124 			break;
1125 		}
1126 
1127 		if (is_valid == B_FALSE)
1128 			return (B_FALSE);
1129 	}
1130 
1131 	for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
1132 	     ++field_id) {
1133 		const efx_mae_mv_bit_desc_t *bit_descp =
1134 		    &bit_desc_setp[field_id];
1135 		unsigned int byte_idx =
1136 		    bit_descp->emmbd_mask_ofst +
1137 		    bit_descp->emmbd_mask_lbn / 8;
1138 		unsigned int bit_idx =
1139 		    bit_descp->emmbd_mask_lbn % 8;
1140 		efx_mae_field_cap_id_t bit_cap_id =
1141 		    bit_descp->emmbd_bit_cap_id;
1142 
1143 		if (bit_descp->emmbd_entry_is_valid == B_FALSE)
1144 			continue; /* Skip array gap */
1145 
1146 		if ((unsigned int)bit_cap_id >= field_ncaps) {
1147 			/* No capability for this bit = unsupported. */
1148 			is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0);
1149 			if (is_valid == B_FALSE)
1150 				break;
1151 			else
1152 				continue;
1153 		}
1154 
1155 		switch (field_caps[bit_cap_id].emfc_support) {
1156 		case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
1157 			is_valid = B_TRUE;
1158 			break;
1159 		case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
1160 			is_valid = ((mvp[byte_idx] & (1U << bit_idx)) != 0);
1161 			break;
1162 		case MAE_FIELD_SUPPORTED_MATCH_NEVER:
1163 		case MAE_FIELD_UNSUPPORTED:
1164 		default:
1165 			is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0);
1166 			break;
1167 		}
1168 
1169 		if (is_valid == B_FALSE)
1170 			break;
1171 	}
1172 
1173 	return (is_valid);
1174 }
1175 
1176 	__checkReturn			efx_rc_t
1177 efx_mae_action_set_spec_init(
1178 	__in				efx_nic_t *enp,
1179 	__out				efx_mae_actions_t **specp)
1180 {
1181 	efx_mae_actions_t *spec;
1182 	efx_rc_t rc;
1183 
1184 	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
1185 	if (spec == NULL) {
1186 		rc = ENOMEM;
1187 		goto fail1;
1188 	}
1189 
1190 	spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
1191 
1192 	*specp = spec;
1193 
1194 	return (0);
1195 
1196 fail1:
1197 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1198 	return (rc);
1199 }
1200 
1201 					void
1202 efx_mae_action_set_spec_fini(
1203 	__in				efx_nic_t *enp,
1204 	__in				efx_mae_actions_t *spec)
1205 {
1206 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
1207 }
1208 
1209 static	__checkReturn			efx_rc_t
1210 efx_mae_action_set_add_decap(
1211 	__in				efx_mae_actions_t *spec,
1212 	__in				size_t arg_size,
1213 	__in_bcount(arg_size)		const uint8_t *arg)
1214 {
1215 	efx_rc_t rc;
1216 
1217 	_NOTE(ARGUNUSED(spec))
1218 
1219 	if (arg_size != 0) {
1220 		rc = EINVAL;
1221 		goto fail1;
1222 	}
1223 
1224 	if (arg != NULL) {
1225 		rc = EINVAL;
1226 		goto fail2;
1227 	}
1228 
1229 	/* This action does not have any arguments, so do nothing here. */
1230 
1231 	return (0);
1232 
1233 fail2:
1234 	EFSYS_PROBE(fail2);
1235 fail1:
1236 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1237 	return (rc);
1238 }
1239 
1240 static	__checkReturn			efx_rc_t
1241 efx_mae_action_set_add_vlan_pop(
1242 	__in				efx_mae_actions_t *spec,
1243 	__in				size_t arg_size,
1244 	__in_bcount(arg_size)		const uint8_t *arg)
1245 {
1246 	efx_rc_t rc;
1247 
1248 	if (arg_size != 0) {
1249 		rc = EINVAL;
1250 		goto fail1;
1251 	}
1252 
1253 	if (arg != NULL) {
1254 		rc = EINVAL;
1255 		goto fail2;
1256 	}
1257 
1258 	if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) {
1259 		rc = ENOTSUP;
1260 		goto fail3;
1261 	}
1262 
1263 	++spec->ema_n_vlan_tags_to_pop;
1264 
1265 	return (0);
1266 
1267 fail3:
1268 	EFSYS_PROBE(fail3);
1269 fail2:
1270 	EFSYS_PROBE(fail2);
1271 fail1:
1272 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1273 	return (rc);
1274 }
1275 
1276 static	__checkReturn			efx_rc_t
1277 efx_mae_action_set_add_vlan_push(
1278 	__in				efx_mae_actions_t *spec,
1279 	__in				size_t arg_size,
1280 	__in_bcount(arg_size)		const uint8_t *arg)
1281 {
1282 	unsigned int n_tags = spec->ema_n_vlan_tags_to_push;
1283 	efx_rc_t rc;
1284 
1285 	if (arg_size != sizeof (*spec->ema_vlan_push_descs)) {
1286 		rc = EINVAL;
1287 		goto fail1;
1288 	}
1289 
1290 	if (arg == NULL) {
1291 		rc = EINVAL;
1292 		goto fail2;
1293 	}
1294 
1295 	if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1296 		rc = ENOTSUP;
1297 		goto fail3;
1298 	}
1299 
1300 	memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size);
1301 	++(spec->ema_n_vlan_tags_to_push);
1302 
1303 	return (0);
1304 
1305 fail3:
1306 	EFSYS_PROBE(fail3);
1307 fail2:
1308 	EFSYS_PROBE(fail2);
1309 fail1:
1310 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1311 	return (rc);
1312 }
1313 
1314 static	__checkReturn			efx_rc_t
1315 efx_mae_action_set_add_encap(
1316 	__in				efx_mae_actions_t *spec,
1317 	__in				size_t arg_size,
1318 	__in_bcount(arg_size)		const uint8_t *arg)
1319 {
1320 	efx_rc_t rc;
1321 
1322 	/*
1323 	 * Adding this specific action to an action set spec and setting encap.
1324 	 * header ID in the spec are two individual steps. This design allows
1325 	 * the client driver to avoid encap. header allocation when it simply
1326 	 * needs to check the order of actions submitted by user ("validate"),
1327 	 * without actually allocating an action set and inserting a rule.
1328 	 *
1329 	 * For now, mark encap. header ID as invalid; the caller will invoke
1330 	 * efx_mae_action_set_fill_in_eh_id() to override the field prior
1331 	 * to action set allocation; otherwise, the allocation will fail.
1332 	 */
1333 	spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
1334 
1335 	/*
1336 	 * As explained above, there are no arguments to handle here.
1337 	 * efx_mae_action_set_fill_in_eh_id() will take care of them.
1338 	 */
1339 	if (arg_size != 0) {
1340 		rc = EINVAL;
1341 		goto fail1;
1342 	}
1343 
1344 	if (arg != NULL) {
1345 		rc = EINVAL;
1346 		goto fail2;
1347 	}
1348 
1349 	return (0);
1350 
1351 fail2:
1352 	EFSYS_PROBE(fail2);
1353 fail1:
1354 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1355 	return (rc);
1356 }
1357 
1358 static	__checkReturn			efx_rc_t
1359 efx_mae_action_set_add_flag(
1360 	__in				efx_mae_actions_t *spec,
1361 	__in				size_t arg_size,
1362 	__in_bcount(arg_size)		const uint8_t *arg)
1363 {
1364 	efx_rc_t rc;
1365 
1366 	_NOTE(ARGUNUSED(spec))
1367 
1368 	if (arg_size != 0) {
1369 		rc = EINVAL;
1370 		goto fail1;
1371 	}
1372 
1373 	if (arg != NULL) {
1374 		rc = EINVAL;
1375 		goto fail2;
1376 	}
1377 
1378 	/* This action does not have any arguments, so do nothing here. */
1379 
1380 	return (0);
1381 
1382 fail2:
1383 	EFSYS_PROBE(fail2);
1384 fail1:
1385 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1386 	return (rc);
1387 }
1388 
1389 static	__checkReturn			efx_rc_t
1390 efx_mae_action_set_add_mark(
1391 	__in				efx_mae_actions_t *spec,
1392 	__in				size_t arg_size,
1393 	__in_bcount(arg_size)		const uint8_t *arg)
1394 {
1395 	efx_rc_t rc;
1396 
1397 	if (arg_size != sizeof (spec->ema_mark_value)) {
1398 		rc = EINVAL;
1399 		goto fail1;
1400 	}
1401 
1402 	if (arg == NULL) {
1403 		rc = EINVAL;
1404 		goto fail2;
1405 	}
1406 
1407 	memcpy(&spec->ema_mark_value, arg, arg_size);
1408 
1409 	return (0);
1410 
1411 fail2:
1412 	EFSYS_PROBE(fail2);
1413 fail1:
1414 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1415 	return (rc);
1416 }
1417 
1418 static	__checkReturn			efx_rc_t
1419 efx_mae_action_set_add_deliver(
1420 	__in				efx_mae_actions_t *spec,
1421 	__in				size_t arg_size,
1422 	__in_bcount(arg_size)		const uint8_t *arg)
1423 {
1424 	efx_rc_t rc;
1425 
1426 	if (arg_size != sizeof (spec->ema_deliver_mport)) {
1427 		rc = EINVAL;
1428 		goto fail1;
1429 	}
1430 
1431 	if (arg == NULL) {
1432 		rc = EINVAL;
1433 		goto fail2;
1434 	}
1435 
1436 	memcpy(&spec->ema_deliver_mport, arg, arg_size);
1437 
1438 	return (0);
1439 
1440 fail2:
1441 	EFSYS_PROBE(fail2);
1442 fail1:
1443 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1444 	return (rc);
1445 }
1446 
1447 typedef struct efx_mae_action_desc_s {
1448 	/* Action specific handler */
1449 	efx_rc_t	(*emad_add)(efx_mae_actions_t *,
1450 				    size_t, const uint8_t *);
1451 } efx_mae_action_desc_t;
1452 
1453 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
1454 	[EFX_MAE_ACTION_DECAP] = {
1455 		.emad_add = efx_mae_action_set_add_decap
1456 	},
1457 	[EFX_MAE_ACTION_VLAN_POP] = {
1458 		.emad_add = efx_mae_action_set_add_vlan_pop
1459 	},
1460 	[EFX_MAE_ACTION_VLAN_PUSH] = {
1461 		.emad_add = efx_mae_action_set_add_vlan_push
1462 	},
1463 	[EFX_MAE_ACTION_ENCAP] = {
1464 		.emad_add = efx_mae_action_set_add_encap
1465 	},
1466 	[EFX_MAE_ACTION_FLAG] = {
1467 		.emad_add = efx_mae_action_set_add_flag
1468 	},
1469 	[EFX_MAE_ACTION_MARK] = {
1470 		.emad_add = efx_mae_action_set_add_mark
1471 	},
1472 	[EFX_MAE_ACTION_DELIVER] = {
1473 		.emad_add = efx_mae_action_set_add_deliver
1474 	}
1475 };
1476 
1477 static const uint32_t efx_mae_action_ordered_map =
1478 	(1U << EFX_MAE_ACTION_DECAP) |
1479 	(1U << EFX_MAE_ACTION_VLAN_POP) |
1480 	(1U << EFX_MAE_ACTION_VLAN_PUSH) |
1481 	(1U << EFX_MAE_ACTION_ENCAP) |
1482 	(1U << EFX_MAE_ACTION_FLAG) |
1483 	(1U << EFX_MAE_ACTION_MARK) |
1484 	(1U << EFX_MAE_ACTION_DELIVER);
1485 
1486 /*
1487  * These actions must not be added after DELIVER, but
1488  * they can have any place among the rest of
1489  * strictly ordered actions.
1490  */
1491 static const uint32_t efx_mae_action_nonstrict_map =
1492 	(1U << EFX_MAE_ACTION_FLAG) |
1493 	(1U << EFX_MAE_ACTION_MARK);
1494 
1495 static const uint32_t efx_mae_action_repeat_map =
1496 	(1U << EFX_MAE_ACTION_VLAN_POP) |
1497 	(1U << EFX_MAE_ACTION_VLAN_PUSH);
1498 
1499 /*
1500  * Add an action to an action set.
1501  *
1502  * This has to be invoked in the desired action order.
1503  * An out-of-order action request will be turned down.
1504  */
1505 static	__checkReturn			efx_rc_t
1506 efx_mae_action_set_spec_populate(
1507 	__in				efx_mae_actions_t *spec,
1508 	__in				efx_mae_action_t type,
1509 	__in				size_t arg_size,
1510 	__in_bcount(arg_size)		const uint8_t *arg)
1511 {
1512 	uint32_t action_mask;
1513 	efx_rc_t rc;
1514 
1515 	EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1516 	    (sizeof (efx_mae_action_ordered_map) * 8));
1517 	EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1518 	    (sizeof (efx_mae_action_repeat_map) * 8));
1519 
1520 	EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
1521 	EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK);
1522 	EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER);
1523 
1524 	if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
1525 		rc = EINVAL;
1526 		goto fail1;
1527 	}
1528 
1529 	action_mask = (1U << type);
1530 
1531 	if ((spec->ema_actions & action_mask) != 0) {
1532 		/* The action set already contains this action. */
1533 		if ((efx_mae_action_repeat_map & action_mask) == 0) {
1534 			/* Cannot add another non-repeatable action. */
1535 			rc = ENOTSUP;
1536 			goto fail2;
1537 		}
1538 	}
1539 
1540 	if ((efx_mae_action_ordered_map & action_mask) != 0) {
1541 		uint32_t strict_ordered_map =
1542 		    efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map;
1543 		uint32_t later_actions_mask =
1544 		    strict_ordered_map & ~(action_mask | (action_mask - 1));
1545 
1546 		if ((spec->ema_actions & later_actions_mask) != 0) {
1547 			/* Cannot add an action after later ordered actions. */
1548 			rc = ENOTSUP;
1549 			goto fail3;
1550 		}
1551 	}
1552 
1553 	if (efx_mae_actions[type].emad_add != NULL) {
1554 		rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
1555 		if (rc != 0)
1556 			goto fail4;
1557 	}
1558 
1559 	spec->ema_actions |= action_mask;
1560 
1561 	return (0);
1562 
1563 fail4:
1564 	EFSYS_PROBE(fail4);
1565 fail3:
1566 	EFSYS_PROBE(fail3);
1567 fail2:
1568 	EFSYS_PROBE(fail2);
1569 fail1:
1570 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1571 	return (rc);
1572 }
1573 
1574 	__checkReturn			efx_rc_t
1575 efx_mae_action_set_populate_decap(
1576 	__in				efx_mae_actions_t *spec)
1577 {
1578 	return (efx_mae_action_set_spec_populate(spec,
1579 	    EFX_MAE_ACTION_DECAP, 0, NULL));
1580 }
1581 
1582 	__checkReturn			efx_rc_t
1583 efx_mae_action_set_populate_vlan_pop(
1584 	__in				efx_mae_actions_t *spec)
1585 {
1586 	return (efx_mae_action_set_spec_populate(spec,
1587 	    EFX_MAE_ACTION_VLAN_POP, 0, NULL));
1588 }
1589 
1590 	__checkReturn			efx_rc_t
1591 efx_mae_action_set_populate_vlan_push(
1592 	__in				efx_mae_actions_t *spec,
1593 	__in				uint16_t tpid_be,
1594 	__in				uint16_t tci_be)
1595 {
1596 	efx_mae_action_vlan_push_t action;
1597 	const uint8_t *arg = (const uint8_t *)&action;
1598 
1599 	action.emavp_tpid_be = tpid_be;
1600 	action.emavp_tci_be = tci_be;
1601 
1602 	return (efx_mae_action_set_spec_populate(spec,
1603 	    EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg));
1604 }
1605 
1606 	__checkReturn			efx_rc_t
1607 efx_mae_action_set_populate_encap(
1608 	__in				efx_mae_actions_t *spec)
1609 {
1610 	/*
1611 	 * There is no argument to pass encap. header ID, thus, one does not
1612 	 * need to allocate an encap. header while parsing application input.
1613 	 * This is useful since building an action set may be done simply to
1614 	 * validate a rule, whilst resource allocation usually consumes time.
1615 	 */
1616 	return (efx_mae_action_set_spec_populate(spec,
1617 	    EFX_MAE_ACTION_ENCAP, 0, NULL));
1618 }
1619 
1620 	__checkReturn			efx_rc_t
1621 efx_mae_action_set_populate_flag(
1622 	__in				efx_mae_actions_t *spec)
1623 {
1624 	return (efx_mae_action_set_spec_populate(spec,
1625 	    EFX_MAE_ACTION_FLAG, 0, NULL));
1626 }
1627 
1628 	__checkReturn			efx_rc_t
1629 efx_mae_action_set_populate_mark(
1630 	__in				efx_mae_actions_t *spec,
1631 	__in				uint32_t mark_value)
1632 {
1633 	const uint8_t *arg = (const uint8_t *)&mark_value;
1634 
1635 	return (efx_mae_action_set_spec_populate(spec,
1636 	    EFX_MAE_ACTION_MARK, sizeof (mark_value), arg));
1637 }
1638 
1639 	__checkReturn			efx_rc_t
1640 efx_mae_action_set_populate_deliver(
1641 	__in				efx_mae_actions_t *spec,
1642 	__in				const efx_mport_sel_t *mportp)
1643 {
1644 	const uint8_t *arg;
1645 	efx_rc_t rc;
1646 
1647 	if (mportp == NULL) {
1648 		rc = EINVAL;
1649 		goto fail1;
1650 	}
1651 
1652 	arg = (const uint8_t *)&mportp->sel;
1653 
1654 	return (efx_mae_action_set_spec_populate(spec,
1655 	    EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
1656 
1657 fail1:
1658 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1659 	return (rc);
1660 }
1661 
1662 	__checkReturn			efx_rc_t
1663 efx_mae_action_set_populate_drop(
1664 	__in				efx_mae_actions_t *spec)
1665 {
1666 	efx_mport_sel_t mport;
1667 	const uint8_t *arg;
1668 	efx_dword_t dword;
1669 
1670 	EFX_POPULATE_DWORD_1(dword,
1671 	    MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL);
1672 
1673 	/*
1674 	 * The constructed DWORD is little-endian,
1675 	 * but the resulting value is meant to be
1676 	 * passed to MCDIs, where it will undergo
1677 	 * host-order to little endian conversion.
1678 	 */
1679 	mport.sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
1680 
1681 	arg = (const uint8_t *)&mport.sel;
1682 
1683 	return (efx_mae_action_set_spec_populate(spec,
1684 	    EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg));
1685 }
1686 
1687 	__checkReturn			boolean_t
1688 efx_mae_action_set_specs_equal(
1689 	__in				const efx_mae_actions_t *left,
1690 	__in				const efx_mae_actions_t *right)
1691 {
1692 	size_t cmp_size = EFX_FIELD_OFFSET(efx_mae_actions_t, ema_rsrc);
1693 
1694 	/*
1695 	 * An action set specification consists of two parts. The first part
1696 	 * indicates what actions are included in the action set, as well as
1697 	 * extra quantitative values (in example, the number of VLAN tags to
1698 	 * push). The second part comprises resource IDs used by the actions.
1699 	 *
1700 	 * A resource, in example, a counter, is allocated from the hardware
1701 	 * by the client, and it's the client who is responsible for keeping
1702 	 * track of allocated resources and comparing resource IDs if needed.
1703 	 *
1704 	 * In this API, don't compare resource IDs in the two specifications.
1705 	 */
1706 
1707 	return ((memcmp(left, right, cmp_size) == 0) ? B_TRUE : B_FALSE);
1708 }
1709 
1710 	__checkReturn			efx_rc_t
1711 efx_mae_match_specs_class_cmp(
1712 	__in				efx_nic_t *enp,
1713 	__in				const efx_mae_match_spec_t *left,
1714 	__in				const efx_mae_match_spec_t *right,
1715 	__out				boolean_t *have_same_classp)
1716 {
1717 	efx_mae_t *maep = enp->en_maep;
1718 	unsigned int field_ncaps = maep->em_max_nfields;
1719 	const efx_mae_field_cap_t *field_caps;
1720 	const efx_mae_mv_desc_t *desc_setp;
1721 	unsigned int desc_set_nentries;
1722 	const efx_mae_mv_bit_desc_t *bit_desc_setp;
1723 	unsigned int bit_desc_set_nentries;
1724 	boolean_t have_same_class = B_TRUE;
1725 	efx_mae_field_id_t field_id;
1726 	const uint8_t *mvpl;
1727 	const uint8_t *mvpr;
1728 	efx_rc_t rc;
1729 
1730 	switch (left->emms_type) {
1731 	case EFX_MAE_RULE_OUTER:
1732 		field_caps = maep->em_outer_rule_field_caps;
1733 		desc_setp = __efx_mae_outer_rule_mv_desc_set;
1734 		desc_set_nentries =
1735 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1736 		bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
1737 		bit_desc_set_nentries =
1738 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
1739 		mvpl = left->emms_mask_value_pairs.outer;
1740 		mvpr = right->emms_mask_value_pairs.outer;
1741 		break;
1742 	case EFX_MAE_RULE_ACTION:
1743 		field_caps = maep->em_action_rule_field_caps;
1744 		desc_setp = __efx_mae_action_rule_mv_desc_set;
1745 		desc_set_nentries =
1746 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1747 		bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
1748 		bit_desc_set_nentries =
1749 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
1750 		mvpl = left->emms_mask_value_pairs.action;
1751 		mvpr = right->emms_mask_value_pairs.action;
1752 		break;
1753 	default:
1754 		rc = ENOTSUP;
1755 		goto fail1;
1756 	}
1757 
1758 	if (field_caps == NULL) {
1759 		rc = EAGAIN;
1760 		goto fail2;
1761 	}
1762 
1763 	if (left->emms_type != right->emms_type ||
1764 	    left->emms_prio != right->emms_prio) {
1765 		/*
1766 		 * Rules of different types can never map to the same class.
1767 		 *
1768 		 * The FW can support some set of match criteria for one
1769 		 * priority and not support the very same set for
1770 		 * another priority. Thus, two rules which have
1771 		 * different priorities can never map to
1772 		 * the same class.
1773 		 */
1774 		*have_same_classp = B_FALSE;
1775 		return (0);
1776 	}
1777 
1778 	for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1779 	     ++field_id) {
1780 		const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1781 		efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1782 		const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
1783 		const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
1784 		size_t mask_size = descp->emmd_mask_size;
1785 		const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
1786 		const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
1787 		size_t value_size = descp->emmd_value_size;
1788 
1789 		if (mask_size == 0)
1790 			continue; /* Skip array gap */
1791 
1792 		if ((unsigned int)field_cap_id >= field_ncaps) {
1793 			/*
1794 			 * The FW has not reported capability status for this
1795 			 * field. It's unknown whether any difference between
1796 			 * the two masks / values affects the class. The only
1797 			 * case when the class must be the same is when these
1798 			 * mask-value pairs match. Otherwise, report mismatch.
1799 			 */
1800 			if ((memcmp(lmaskp, rmaskp, mask_size) == 0) &&
1801 			    (memcmp(lvalp, rvalp, value_size) == 0))
1802 				continue;
1803 			else
1804 				break;
1805 		}
1806 
1807 		if (field_caps[field_cap_id].emfc_mask_affects_class) {
1808 			if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
1809 				have_same_class = B_FALSE;
1810 				break;
1811 			}
1812 		}
1813 
1814 		if (field_caps[field_cap_id].emfc_match_affects_class) {
1815 			if (memcmp(lvalp, rvalp, value_size) != 0) {
1816 				have_same_class = B_FALSE;
1817 				break;
1818 			}
1819 		}
1820 	}
1821 
1822 	if (have_same_class == B_FALSE)
1823 		goto done;
1824 
1825 	for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
1826 	     ++field_id) {
1827 		const efx_mae_mv_bit_desc_t *bit_descp =
1828 		    &bit_desc_setp[field_id];
1829 		efx_mae_field_cap_id_t bit_cap_id =
1830 		    bit_descp->emmbd_bit_cap_id;
1831 		unsigned int byte_idx;
1832 		unsigned int bit_idx;
1833 
1834 		if (bit_descp->emmbd_entry_is_valid == B_FALSE)
1835 			continue; /* Skip array gap */
1836 
1837 		if ((unsigned int)bit_cap_id >= field_ncaps)
1838 			break;
1839 
1840 		byte_idx =
1841 		    bit_descp->emmbd_mask_ofst +
1842 		    bit_descp->emmbd_mask_lbn / 8;
1843 		bit_idx =
1844 		    bit_descp->emmbd_mask_lbn % 8;
1845 
1846 		if (field_caps[bit_cap_id].emfc_mask_affects_class &&
1847 		    (mvpl[byte_idx] & (1U << bit_idx)) !=
1848 		    (mvpr[byte_idx] & (1U << bit_idx))) {
1849 			have_same_class = B_FALSE;
1850 			break;
1851 		}
1852 
1853 		byte_idx =
1854 		    bit_descp->emmbd_value_ofst +
1855 		    bit_descp->emmbd_value_lbn / 8;
1856 		bit_idx =
1857 		    bit_descp->emmbd_value_lbn % 8;
1858 
1859 		if (field_caps[bit_cap_id].emfc_match_affects_class &&
1860 		    (mvpl[byte_idx] & (1U << bit_idx)) !=
1861 		    (mvpr[byte_idx] & (1U << bit_idx))) {
1862 			have_same_class = B_FALSE;
1863 			break;
1864 		}
1865 	}
1866 
1867 done:
1868 	*have_same_classp = have_same_class;
1869 
1870 	return (0);
1871 
1872 fail2:
1873 	EFSYS_PROBE(fail2);
1874 fail1:
1875 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1876 	return (rc);
1877 }
1878 
1879 	__checkReturn		efx_rc_t
1880 efx_mae_outer_rule_insert(
1881 	__in			efx_nic_t *enp,
1882 	__in			const efx_mae_match_spec_t *spec,
1883 	__in			efx_tunnel_protocol_t encap_type,
1884 	__out			efx_mae_rule_id_t *or_idp)
1885 {
1886 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1887 	efx_mcdi_req_t req;
1888 	EFX_MCDI_DECLARE_BUF(payload,
1889 	    MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2,
1890 	    MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
1891 	uint32_t encap_type_mcdi;
1892 	efx_mae_rule_id_t or_id;
1893 	size_t offset;
1894 	efx_rc_t rc;
1895 
1896 	EFX_STATIC_ASSERT(sizeof (or_idp->id) ==
1897 	    MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN);
1898 
1899 	EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1900 	    MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL);
1901 
1902 	if (encp->enc_mae_supported == B_FALSE) {
1903 		rc = ENOTSUP;
1904 		goto fail1;
1905 	}
1906 
1907 	if (spec->emms_type != EFX_MAE_RULE_OUTER) {
1908 		rc = EINVAL;
1909 		goto fail2;
1910 	}
1911 
1912 	switch (encap_type) {
1913 	case EFX_TUNNEL_PROTOCOL_NONE:
1914 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
1915 		break;
1916 	case EFX_TUNNEL_PROTOCOL_VXLAN:
1917 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
1918 		break;
1919 	case EFX_TUNNEL_PROTOCOL_GENEVE:
1920 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
1921 		break;
1922 	case EFX_TUNNEL_PROTOCOL_NVGRE:
1923 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
1924 		break;
1925 	default:
1926 		rc = ENOTSUP;
1927 		goto fail3;
1928 	}
1929 
1930 	req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT;
1931 	req.emr_in_buf = payload;
1932 	req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2;
1933 	req.emr_out_buf = payload;
1934 	req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN;
1935 
1936 	MCDI_IN_SET_DWORD(req,
1937 	    MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi);
1938 
1939 	MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio);
1940 
1941 	/*
1942 	 * Mask-value pairs have been stored in the byte order needed for the
1943 	 * MCDI request and are thus safe to be copied directly to the buffer.
1944 	 * The library cares about byte order in efx_mae_match_spec_field_set().
1945 	 */
1946 	EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >=
1947 	    MAE_ENC_FIELD_PAIRS_LEN);
1948 	offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST;
1949 	memcpy(payload + offset, spec->emms_mask_value_pairs.outer,
1950 	    MAE_ENC_FIELD_PAIRS_LEN);
1951 
1952 	efx_mcdi_execute(enp, &req);
1953 
1954 	if (req.emr_rc != 0) {
1955 		rc = req.emr_rc;
1956 		goto fail4;
1957 	}
1958 
1959 	if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) {
1960 		rc = EMSGSIZE;
1961 		goto fail5;
1962 	}
1963 
1964 	or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
1965 	if (or_id.id == EFX_MAE_RSRC_ID_INVALID) {
1966 		rc = ENOENT;
1967 		goto fail6;
1968 	}
1969 
1970 	or_idp->id = or_id.id;
1971 
1972 	return (0);
1973 
1974 fail6:
1975 	EFSYS_PROBE(fail6);
1976 fail5:
1977 	EFSYS_PROBE(fail5);
1978 fail4:
1979 	EFSYS_PROBE(fail4);
1980 fail3:
1981 	EFSYS_PROBE(fail3);
1982 fail2:
1983 	EFSYS_PROBE(fail2);
1984 fail1:
1985 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1986 	return (rc);
1987 }
1988 
1989 	__checkReturn		efx_rc_t
1990 efx_mae_outer_rule_remove(
1991 	__in			efx_nic_t *enp,
1992 	__in			const efx_mae_rule_id_t *or_idp)
1993 {
1994 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1995 	efx_mcdi_req_t req;
1996 	EFX_MCDI_DECLARE_BUF(payload,
1997 	    MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1),
1998 	    MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
1999 	efx_rc_t rc;
2000 
2001 	if (encp->enc_mae_supported == B_FALSE) {
2002 		rc = ENOTSUP;
2003 		goto fail1;
2004 	}
2005 
2006 	req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE;
2007 	req.emr_in_buf = payload;
2008 	req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1);
2009 	req.emr_out_buf = payload;
2010 	req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1);
2011 
2012 	MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id);
2013 
2014 	efx_mcdi_execute(enp, &req);
2015 
2016 	if (req.emr_rc != 0) {
2017 		rc = req.emr_rc;
2018 		goto fail2;
2019 	}
2020 
2021 	if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LENMIN) {
2022 		rc = EMSGSIZE;
2023 		goto fail3;
2024 	}
2025 
2026 	if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) !=
2027 	    or_idp->id) {
2028 		/* Firmware failed to remove the outer rule. */
2029 		rc = EAGAIN;
2030 		goto fail4;
2031 	}
2032 
2033 	return (0);
2034 
2035 fail4:
2036 	EFSYS_PROBE(fail4);
2037 fail3:
2038 	EFSYS_PROBE(fail3);
2039 fail2:
2040 	EFSYS_PROBE(fail2);
2041 fail1:
2042 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2043 	return (rc);
2044 }
2045 
2046 	__checkReturn			efx_rc_t
2047 efx_mae_match_spec_outer_rule_id_set(
2048 	__in				efx_mae_match_spec_t *spec,
2049 	__in				const efx_mae_rule_id_t *or_idp)
2050 {
2051 	uint32_t full_mask = UINT32_MAX;
2052 	efx_rc_t rc;
2053 
2054 	if (spec->emms_type != EFX_MAE_RULE_ACTION) {
2055 		rc = EINVAL;
2056 		goto fail1;
2057 	}
2058 
2059 	if (or_idp == NULL) {
2060 		rc = EINVAL;
2061 		goto fail2;
2062 	}
2063 
2064 	rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID,
2065 	    sizeof (or_idp->id), (const uint8_t *)&or_idp->id,
2066 	    sizeof (full_mask), (const uint8_t *)&full_mask);
2067 	if (rc != 0)
2068 		goto fail3;
2069 
2070 	return (0);
2071 
2072 fail3:
2073 	EFSYS_PROBE(fail3);
2074 fail2:
2075 	EFSYS_PROBE(fail2);
2076 fail1:
2077 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2078 	return (rc);
2079 }
2080 
2081 	 __checkReturn			efx_rc_t
2082 efx_mae_encap_header_alloc(
2083 	__in				efx_nic_t *enp,
2084 	__in				efx_tunnel_protocol_t encap_type,
2085 	__in_bcount(header_size)	uint8_t *header_data,
2086 	__in				size_t header_size,
2087 	__out				efx_mae_eh_id_t *eh_idp)
2088 {
2089 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2090 	efx_mcdi_req_t req;
2091 	EFX_MCDI_DECLARE_BUF(payload,
2092 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LENMAX_MCDI2,
2093 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN);
2094 	uint32_t encap_type_mcdi;
2095 	efx_mae_eh_id_t eh_id;
2096 	efx_rc_t rc;
2097 
2098 	EFX_STATIC_ASSERT(sizeof (eh_idp->id) ==
2099 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_LEN);
2100 
2101 	EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2102 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
2103 
2104 	if (encp->enc_mae_supported == B_FALSE) {
2105 		rc = ENOTSUP;
2106 		goto fail1;
2107 	}
2108 
2109 	switch (encap_type) {
2110 	case EFX_TUNNEL_PROTOCOL_NONE:
2111 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
2112 		break;
2113 	case EFX_TUNNEL_PROTOCOL_VXLAN:
2114 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
2115 		break;
2116 	case EFX_TUNNEL_PROTOCOL_GENEVE:
2117 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
2118 		break;
2119 	case EFX_TUNNEL_PROTOCOL_NVGRE:
2120 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
2121 		break;
2122 	default:
2123 		rc = ENOTSUP;
2124 		goto fail2;
2125 	}
2126 
2127 	if (header_size >
2128 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2) {
2129 		rc = EINVAL;
2130 		goto fail3;
2131 	}
2132 
2133 	req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_ALLOC;
2134 	req.emr_in_buf = payload;
2135 	req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(header_size);
2136 	req.emr_out_buf = payload;
2137 	req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN;
2138 
2139 	MCDI_IN_SET_DWORD(req,
2140 	    MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, encap_type_mcdi);
2141 
2142 	memcpy(payload + MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_OFST,
2143 	    header_data, header_size);
2144 
2145 	efx_mcdi_execute(enp, &req);
2146 
2147 	if (req.emr_rc != 0) {
2148 		rc = req.emr_rc;
2149 		goto fail4;
2150 	}
2151 
2152 	if (req.emr_out_length_used < MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN) {
2153 		rc = EMSGSIZE;
2154 		goto fail5;
2155 	}
2156 
2157 	eh_id.id = MCDI_OUT_DWORD(req,
2158 	    MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID);
2159 
2160 	if (eh_id.id == EFX_MAE_RSRC_ID_INVALID) {
2161 		rc = ENOENT;
2162 		goto fail6;
2163 	}
2164 
2165 	eh_idp->id = eh_id.id;
2166 
2167 	return (0);
2168 
2169 fail6:
2170 	EFSYS_PROBE(fail6);
2171 fail5:
2172 	EFSYS_PROBE(fail5);
2173 fail4:
2174 	EFSYS_PROBE(fail4);
2175 fail3:
2176 	EFSYS_PROBE(fail3);
2177 fail2:
2178 	EFSYS_PROBE(fail2);
2179 fail1:
2180 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2181 	return (rc);
2182 }
2183 
2184 	__checkReturn			efx_rc_t
2185 efx_mae_encap_header_free(
2186 	__in				efx_nic_t *enp,
2187 	__in				const efx_mae_eh_id_t *eh_idp)
2188 {
2189 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2190 	efx_mcdi_req_t req;
2191 	EFX_MCDI_DECLARE_BUF(payload,
2192 	    MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1),
2193 	    MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1));
2194 	efx_rc_t rc;
2195 
2196 	if (encp->enc_mae_supported == B_FALSE) {
2197 		rc = ENOTSUP;
2198 		goto fail1;
2199 	}
2200 
2201 	req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_FREE;
2202 	req.emr_in_buf = payload;
2203 	req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1);
2204 	req.emr_out_buf = payload;
2205 	req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1);
2206 
2207 	MCDI_IN_SET_DWORD(req, MAE_ENCAP_HEADER_FREE_IN_EH_ID, eh_idp->id);
2208 
2209 	efx_mcdi_execute(enp, &req);
2210 
2211 	if (req.emr_rc != 0) {
2212 		rc = req.emr_rc;
2213 		goto fail2;
2214 	}
2215 
2216 	if (MCDI_OUT_DWORD(req, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) !=
2217 	    eh_idp->id) {
2218 		/* Firmware failed to remove the encap. header. */
2219 		rc = EAGAIN;
2220 		goto fail3;
2221 	}
2222 
2223 	return (0);
2224 
2225 fail3:
2226 	EFSYS_PROBE(fail3);
2227 fail2:
2228 	EFSYS_PROBE(fail2);
2229 fail1:
2230 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2231 	return (rc);
2232 }
2233 
2234 	__checkReturn			efx_rc_t
2235 efx_mae_action_set_fill_in_eh_id(
2236 	__in				efx_mae_actions_t *spec,
2237 	__in				const efx_mae_eh_id_t *eh_idp)
2238 {
2239 	efx_rc_t rc;
2240 
2241 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) == 0) {
2242 		/*
2243 		 * The caller has not intended to have action ENCAP originally,
2244 		 * hence, this attempt to indicate encap. header ID is invalid.
2245 		 */
2246 		rc = EINVAL;
2247 		goto fail1;
2248 	}
2249 
2250 	if (spec->ema_rsrc.emar_eh_id.id != EFX_MAE_RSRC_ID_INVALID) {
2251 		/* The caller attempts to indicate encap. header ID twice. */
2252 		rc = EINVAL;
2253 		goto fail2;
2254 	}
2255 
2256 	if (eh_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2257 		rc = EINVAL;
2258 		goto fail3;
2259 	}
2260 
2261 	spec->ema_rsrc.emar_eh_id.id = eh_idp->id;
2262 
2263 	return (0);
2264 
2265 fail3:
2266 	EFSYS_PROBE(fail3);
2267 fail2:
2268 	EFSYS_PROBE(fail2);
2269 fail1:
2270 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2271 	return (rc);
2272 }
2273 
2274 	__checkReturn			efx_rc_t
2275 efx_mae_action_set_alloc(
2276 	__in				efx_nic_t *enp,
2277 	__in				const efx_mae_actions_t *spec,
2278 	__out				efx_mae_aset_id_t *aset_idp)
2279 {
2280 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2281 	efx_mcdi_req_t req;
2282 	EFX_MCDI_DECLARE_BUF(payload,
2283 	    MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
2284 	    MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
2285 	efx_mae_aset_id_t aset_id;
2286 	efx_rc_t rc;
2287 
2288 	if (encp->enc_mae_supported == B_FALSE) {
2289 		rc = ENOTSUP;
2290 		goto fail1;
2291 	}
2292 
2293 	req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
2294 	req.emr_in_buf = payload;
2295 	req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
2296 	req.emr_out_buf = payload;
2297 	req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
2298 
2299 	/*
2300 	 * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
2301 	 * corresponding resource types are supported by the implementation.
2302 	 * Use proper resource ID assignments instead.
2303 	 */
2304 	MCDI_IN_SET_DWORD(req,
2305 	    MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
2306 	MCDI_IN_SET_DWORD(req,
2307 	    MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
2308 
2309 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECAP)) != 0) {
2310 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2311 		    MAE_ACTION_SET_ALLOC_IN_DECAP, 1);
2312 	}
2313 
2314 	MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2315 	    MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
2316 
2317 	if (spec->ema_n_vlan_tags_to_push > 0) {
2318 		unsigned int outer_tag_idx;
2319 
2320 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2321 		    MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
2322 		    spec->ema_n_vlan_tags_to_push);
2323 
2324 		if (spec->ema_n_vlan_tags_to_push ==
2325 		    EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
2326 			MCDI_IN_SET_WORD(req,
2327 			    MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
2328 			    spec->ema_vlan_push_descs[0].emavp_tpid_be);
2329 			MCDI_IN_SET_WORD(req,
2330 			    MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
2331 			    spec->ema_vlan_push_descs[0].emavp_tci_be);
2332 		}
2333 
2334 		outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
2335 
2336 		MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
2337 		    spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
2338 		MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
2339 		    spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
2340 	}
2341 
2342 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
2343 	    spec->ema_rsrc.emar_eh_id.id);
2344 
2345 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
2346 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2347 		    MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
2348 	}
2349 
2350 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
2351 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2352 		    MAE_ACTION_SET_ALLOC_IN_MARK, 1);
2353 
2354 		MCDI_IN_SET_DWORD(req,
2355 		    MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
2356 	}
2357 
2358 	MCDI_IN_SET_DWORD(req,
2359 	    MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
2360 
2361 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
2362 	    MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2363 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
2364 	    MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2365 
2366 	efx_mcdi_execute(enp, &req);
2367 
2368 	if (req.emr_rc != 0) {
2369 		rc = req.emr_rc;
2370 		goto fail2;
2371 	}
2372 
2373 	if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
2374 		rc = EMSGSIZE;
2375 		goto fail3;
2376 	}
2377 
2378 	aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
2379 	if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
2380 		rc = ENOENT;
2381 		goto fail4;
2382 	}
2383 
2384 	aset_idp->id = aset_id.id;
2385 
2386 	return (0);
2387 
2388 fail4:
2389 	EFSYS_PROBE(fail4);
2390 fail3:
2391 	EFSYS_PROBE(fail3);
2392 fail2:
2393 	EFSYS_PROBE(fail2);
2394 fail1:
2395 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2396 	return (rc);
2397 }
2398 
2399 	__checkReturn			efx_rc_t
2400 efx_mae_action_set_free(
2401 	__in				efx_nic_t *enp,
2402 	__in				const efx_mae_aset_id_t *aset_idp)
2403 {
2404 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2405 	efx_mcdi_req_t req;
2406 	EFX_MCDI_DECLARE_BUF(payload,
2407 	    MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
2408 	    MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
2409 	efx_rc_t rc;
2410 
2411 	if (encp->enc_mae_supported == B_FALSE) {
2412 		rc = ENOTSUP;
2413 		goto fail1;
2414 	}
2415 
2416 	req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
2417 	req.emr_in_buf = payload;
2418 	req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
2419 	req.emr_out_buf = payload;
2420 	req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
2421 
2422 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
2423 
2424 	efx_mcdi_execute(enp, &req);
2425 
2426 	if (req.emr_rc != 0) {
2427 		rc = req.emr_rc;
2428 		goto fail2;
2429 	}
2430 
2431 	if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_FREE_OUT_LENMIN) {
2432 		rc = EMSGSIZE;
2433 		goto fail3;
2434 	}
2435 
2436 	if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
2437 	    aset_idp->id) {
2438 		/* Firmware failed to free the action set. */
2439 		rc = EAGAIN;
2440 		goto fail4;
2441 	}
2442 
2443 	return (0);
2444 
2445 fail4:
2446 	EFSYS_PROBE(fail4);
2447 fail3:
2448 	EFSYS_PROBE(fail3);
2449 fail2:
2450 	EFSYS_PROBE(fail2);
2451 fail1:
2452 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2453 	return (rc);
2454 }
2455 
2456 	__checkReturn			efx_rc_t
2457 efx_mae_action_rule_insert(
2458 	__in				efx_nic_t *enp,
2459 	__in				const efx_mae_match_spec_t *spec,
2460 	__in				const efx_mae_aset_list_id_t *asl_idp,
2461 	__in				const efx_mae_aset_id_t *as_idp,
2462 	__out				efx_mae_rule_id_t *ar_idp)
2463 {
2464 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2465 	efx_mcdi_req_t req;
2466 	EFX_MCDI_DECLARE_BUF(payload,
2467 	    MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2,
2468 	    MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
2469 	efx_oword_t *rule_response;
2470 	efx_mae_rule_id_t ar_id;
2471 	size_t offset;
2472 	efx_rc_t rc;
2473 
2474 	EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
2475 	    MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
2476 
2477 	EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2478 	    MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
2479 
2480 	if (encp->enc_mae_supported == B_FALSE) {
2481 		rc = ENOTSUP;
2482 		goto fail1;
2483 	}
2484 
2485 	if (spec->emms_type != EFX_MAE_RULE_ACTION ||
2486 	    (asl_idp != NULL && as_idp != NULL) ||
2487 	    (asl_idp == NULL && as_idp == NULL)) {
2488 		rc = EINVAL;
2489 		goto fail2;
2490 	}
2491 
2492 	req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
2493 	req.emr_in_buf = payload;
2494 	req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
2495 	req.emr_out_buf = payload;
2496 	req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
2497 
2498 	EFX_STATIC_ASSERT(sizeof (*rule_response) <=
2499 	    MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
2500 	offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
2501 	rule_response = (efx_oword_t *)(payload + offset);
2502 	EFX_POPULATE_OWORD_3(*rule_response,
2503 	    MAE_ACTION_RULE_RESPONSE_ASL_ID,
2504 	    (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
2505 	    MAE_ACTION_RULE_RESPONSE_AS_ID,
2506 	    (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
2507 	    MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
2508 
2509 	MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
2510 
2511 	/*
2512 	 * Mask-value pairs have been stored in the byte order needed for the
2513 	 * MCDI request and are thus safe to be copied directly to the buffer.
2514 	 */
2515 	EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
2516 	    MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
2517 	offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
2518 	memcpy(payload + offset, spec->emms_mask_value_pairs.action,
2519 	    MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
2520 
2521 	efx_mcdi_execute(enp, &req);
2522 
2523 	if (req.emr_rc != 0) {
2524 		rc = req.emr_rc;
2525 		goto fail3;
2526 	}
2527 
2528 	if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
2529 		rc = EMSGSIZE;
2530 		goto fail4;
2531 	}
2532 
2533 	ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
2534 	if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
2535 		rc = ENOENT;
2536 		goto fail5;
2537 	}
2538 
2539 	ar_idp->id = ar_id.id;
2540 
2541 	return (0);
2542 
2543 fail5:
2544 	EFSYS_PROBE(fail5);
2545 fail4:
2546 	EFSYS_PROBE(fail4);
2547 fail3:
2548 	EFSYS_PROBE(fail3);
2549 fail2:
2550 	EFSYS_PROBE(fail2);
2551 fail1:
2552 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2553 	return (rc);
2554 }
2555 
2556 	__checkReturn			efx_rc_t
2557 efx_mae_action_rule_remove(
2558 	__in				efx_nic_t *enp,
2559 	__in				const efx_mae_rule_id_t *ar_idp)
2560 {
2561 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2562 	efx_mcdi_req_t req;
2563 	EFX_MCDI_DECLARE_BUF(payload,
2564 	    MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
2565 	    MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
2566 	efx_rc_t rc;
2567 
2568 	if (encp->enc_mae_supported == B_FALSE) {
2569 		rc = ENOTSUP;
2570 		goto fail1;
2571 	}
2572 
2573 	req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
2574 	req.emr_in_buf = payload;
2575 	req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
2576 	req.emr_out_buf = payload;
2577 	req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
2578 
2579 	MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
2580 
2581 	efx_mcdi_execute(enp, &req);
2582 
2583 	if (req.emr_rc != 0) {
2584 		rc = req.emr_rc;
2585 		goto fail2;
2586 	}
2587 
2588 	if (req.emr_out_length_used <
2589 	    MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LENMIN) {
2590 		rc = EMSGSIZE;
2591 		goto fail3;
2592 	}
2593 
2594 	if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
2595 	    ar_idp->id) {
2596 		/* Firmware failed to delete the action rule. */
2597 		rc = EAGAIN;
2598 		goto fail4;
2599 	}
2600 
2601 	return (0);
2602 
2603 fail4:
2604 	EFSYS_PROBE(fail4);
2605 fail3:
2606 	EFSYS_PROBE(fail3);
2607 fail2:
2608 	EFSYS_PROBE(fail2);
2609 fail1:
2610 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2611 	return (rc);
2612 }
2613 
2614 #endif /* EFSYS_OPT_MAE */
2615