xref: /dpdk/drivers/common/sfc_efx/base/efx_mae.c (revision bbbe38a6d59ccdda25917712701e629d0b10af6f)
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 
469 	EFX_MAE_FIELD_CAP_NIDS
470 } efx_mae_field_cap_id_t;
471 
472 typedef enum efx_mae_field_endianness_e {
473 	EFX_MAE_FIELD_LE = 0,
474 	EFX_MAE_FIELD_BE,
475 
476 	EFX_MAE_FIELD_ENDIANNESS_NTYPES
477 } efx_mae_field_endianness_t;
478 
479 /*
480  * The following structure is a means to describe an MAE field.
481  * The information in it is meant to be used internally by
482  * APIs for addressing a given field in a mask-value pairs
483  * structure and for validation purposes.
484  *
485  * A field may have an alternative one. This structure
486  * has additional members to reference the alternative
487  * field's mask. See efx_mae_match_spec_is_valid().
488  */
489 typedef struct efx_mae_mv_desc_s {
490 	efx_mae_field_cap_id_t		emmd_field_cap_id;
491 
492 	size_t				emmd_value_size;
493 	size_t				emmd_value_offset;
494 	size_t				emmd_mask_size;
495 	size_t				emmd_mask_offset;
496 
497 	/*
498 	 * Having the alternative field's mask size set to 0
499 	 * means that there's no alternative field specified.
500 	 */
501 	size_t				emmd_alt_mask_size;
502 	size_t				emmd_alt_mask_offset;
503 
504 	/* Primary field and the alternative one are of the same endianness. */
505 	efx_mae_field_endianness_t	emmd_endianness;
506 } efx_mae_mv_desc_t;
507 
508 /* Indices to this array are provided by efx_mae_field_id_t */
509 static const efx_mae_mv_desc_t __efx_mae_action_rule_mv_desc_set[] = {
510 #define	EFX_MAE_MV_DESC(_name, _endianness)				\
511 	[EFX_MAE_FIELD_##_name] =					\
512 	{								\
513 		EFX_MAE_FIELD_ID_##_name,				\
514 		MAE_FIELD_MASK_VALUE_PAIRS_##_name##_LEN,		\
515 		MAE_FIELD_MASK_VALUE_PAIRS_##_name##_OFST,		\
516 		MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_LEN,		\
517 		MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_OFST,		\
518 		0, 0 /* no alternative field */,			\
519 		_endianness						\
520 	}
521 
522 	EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
523 	EFX_MAE_MV_DESC(ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
524 	EFX_MAE_MV_DESC(ETH_SADDR_BE, EFX_MAE_FIELD_BE),
525 	EFX_MAE_MV_DESC(ETH_DADDR_BE, EFX_MAE_FIELD_BE),
526 	EFX_MAE_MV_DESC(VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
527 	EFX_MAE_MV_DESC(VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
528 	EFX_MAE_MV_DESC(VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
529 	EFX_MAE_MV_DESC(VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
530 	EFX_MAE_MV_DESC(SRC_IP4_BE, EFX_MAE_FIELD_BE),
531 	EFX_MAE_MV_DESC(DST_IP4_BE, EFX_MAE_FIELD_BE),
532 	EFX_MAE_MV_DESC(IP_PROTO, EFX_MAE_FIELD_BE),
533 	EFX_MAE_MV_DESC(IP_TOS, EFX_MAE_FIELD_BE),
534 	EFX_MAE_MV_DESC(IP_TTL, EFX_MAE_FIELD_BE),
535 	EFX_MAE_MV_DESC(SRC_IP6_BE, EFX_MAE_FIELD_BE),
536 	EFX_MAE_MV_DESC(DST_IP6_BE, EFX_MAE_FIELD_BE),
537 	EFX_MAE_MV_DESC(L4_SPORT_BE, EFX_MAE_FIELD_BE),
538 	EFX_MAE_MV_DESC(L4_DPORT_BE, EFX_MAE_FIELD_BE),
539 	EFX_MAE_MV_DESC(TCP_FLAGS_BE, EFX_MAE_FIELD_BE),
540 	EFX_MAE_MV_DESC(ENC_VNET_ID_BE, EFX_MAE_FIELD_BE),
541 	EFX_MAE_MV_DESC(OUTER_RULE_ID, EFX_MAE_FIELD_LE),
542 
543 #undef EFX_MAE_MV_DESC
544 };
545 
546 /* Indices to this array are provided by efx_mae_field_id_t */
547 static const efx_mae_mv_desc_t __efx_mae_outer_rule_mv_desc_set[] = {
548 #define	EFX_MAE_MV_DESC(_name, _endianness)				\
549 	[EFX_MAE_FIELD_##_name] =					\
550 	{								\
551 		EFX_MAE_FIELD_ID_##_name,				\
552 		MAE_ENC_FIELD_PAIRS_##_name##_LEN,			\
553 		MAE_ENC_FIELD_PAIRS_##_name##_OFST,			\
554 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,			\
555 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,		\
556 		0, 0 /* no alternative field */,			\
557 		_endianness						\
558 	}
559 
560 /* Same as EFX_MAE_MV_DESC(), but also indicates an alternative field. */
561 #define	EFX_MAE_MV_DESC_ALT(_name, _alt_name, _endianness)		\
562 	[EFX_MAE_FIELD_##_name] =					\
563 	{								\
564 		EFX_MAE_FIELD_ID_##_name,				\
565 		MAE_ENC_FIELD_PAIRS_##_name##_LEN,			\
566 		MAE_ENC_FIELD_PAIRS_##_name##_OFST,			\
567 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,			\
568 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,		\
569 		MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_LEN,		\
570 		MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_OFST,		\
571 		_endianness						\
572 	}
573 
574 	EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
575 	EFX_MAE_MV_DESC(ENC_ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
576 	EFX_MAE_MV_DESC(ENC_ETH_SADDR_BE, EFX_MAE_FIELD_BE),
577 	EFX_MAE_MV_DESC(ENC_ETH_DADDR_BE, EFX_MAE_FIELD_BE),
578 	EFX_MAE_MV_DESC(ENC_VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
579 	EFX_MAE_MV_DESC(ENC_VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
580 	EFX_MAE_MV_DESC(ENC_VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
581 	EFX_MAE_MV_DESC(ENC_VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
582 	EFX_MAE_MV_DESC_ALT(ENC_SRC_IP4_BE, ENC_SRC_IP6_BE, EFX_MAE_FIELD_BE),
583 	EFX_MAE_MV_DESC_ALT(ENC_DST_IP4_BE, ENC_DST_IP6_BE, EFX_MAE_FIELD_BE),
584 	EFX_MAE_MV_DESC(ENC_IP_PROTO, EFX_MAE_FIELD_BE),
585 	EFX_MAE_MV_DESC(ENC_IP_TOS, EFX_MAE_FIELD_BE),
586 	EFX_MAE_MV_DESC(ENC_IP_TTL, EFX_MAE_FIELD_BE),
587 	EFX_MAE_MV_DESC_ALT(ENC_SRC_IP6_BE, ENC_SRC_IP4_BE, EFX_MAE_FIELD_BE),
588 	EFX_MAE_MV_DESC_ALT(ENC_DST_IP6_BE, ENC_DST_IP4_BE, EFX_MAE_FIELD_BE),
589 	EFX_MAE_MV_DESC(ENC_L4_SPORT_BE, EFX_MAE_FIELD_BE),
590 	EFX_MAE_MV_DESC(ENC_L4_DPORT_BE, EFX_MAE_FIELD_BE),
591 
592 #undef EFX_MAE_MV_DESC_ALT
593 #undef EFX_MAE_MV_DESC
594 };
595 
596 	__checkReturn			efx_rc_t
597 efx_mae_mport_by_phy_port(
598 	__in				uint32_t phy_port,
599 	__out				efx_mport_sel_t *mportp)
600 {
601 	efx_dword_t dword;
602 	efx_rc_t rc;
603 
604 	if (phy_port > EFX_MASK32(MAE_MPORT_SELECTOR_PPORT_ID)) {
605 		rc = EINVAL;
606 		goto fail1;
607 	}
608 
609 	EFX_POPULATE_DWORD_2(dword,
610 	    MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT,
611 	    MAE_MPORT_SELECTOR_PPORT_ID, phy_port);
612 
613 	memset(mportp, 0, sizeof (*mportp));
614 	/*
615 	 * The constructed DWORD is little-endian,
616 	 * but the resulting value is meant to be
617 	 * passed to MCDIs, where it will undergo
618 	 * host-order to little endian conversion.
619 	 */
620 	mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
621 
622 	return (0);
623 
624 fail1:
625 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
626 	return (rc);
627 }
628 
629 	__checkReturn			efx_rc_t
630 efx_mae_mport_by_pcie_function(
631 	__in				uint32_t pf,
632 	__in				uint32_t vf,
633 	__out				efx_mport_sel_t *mportp)
634 {
635 	efx_dword_t dword;
636 	efx_rc_t rc;
637 
638 	EFX_STATIC_ASSERT(EFX_PCI_VF_INVALID ==
639 	    MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL);
640 
641 	if (pf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_PF_ID)) {
642 		rc = EINVAL;
643 		goto fail1;
644 	}
645 
646 	if (vf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_VF_ID)) {
647 		rc = EINVAL;
648 		goto fail2;
649 	}
650 
651 	EFX_POPULATE_DWORD_3(dword,
652 	    MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
653 	    MAE_MPORT_SELECTOR_FUNC_PF_ID, pf,
654 	    MAE_MPORT_SELECTOR_FUNC_VF_ID, vf);
655 
656 	memset(mportp, 0, sizeof (*mportp));
657 	/*
658 	 * The constructed DWORD is little-endian,
659 	 * but the resulting value is meant to be
660 	 * passed to MCDIs, where it will undergo
661 	 * host-order to little endian conversion.
662 	 */
663 	mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
664 
665 	return (0);
666 
667 fail2:
668 	EFSYS_PROBE(fail2);
669 fail1:
670 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
671 	return (rc);
672 }
673 
674 	__checkReturn			efx_rc_t
675 efx_mae_match_spec_field_set(
676 	__in				efx_mae_match_spec_t *spec,
677 	__in				efx_mae_field_id_t field_id,
678 	__in				size_t value_size,
679 	__in_bcount(value_size)		const uint8_t *value,
680 	__in				size_t mask_size,
681 	__in_bcount(mask_size)		const uint8_t *mask)
682 {
683 	const efx_mae_mv_desc_t *descp;
684 	unsigned int desc_set_nentries;
685 	uint8_t *mvp;
686 	efx_rc_t rc;
687 
688 	switch (spec->emms_type) {
689 	case EFX_MAE_RULE_OUTER:
690 		desc_set_nentries =
691 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
692 		descp = &__efx_mae_outer_rule_mv_desc_set[field_id];
693 		mvp = spec->emms_mask_value_pairs.outer;
694 		break;
695 	case EFX_MAE_RULE_ACTION:
696 		desc_set_nentries =
697 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
698 		descp = &__efx_mae_action_rule_mv_desc_set[field_id];
699 		mvp = spec->emms_mask_value_pairs.action;
700 		break;
701 	default:
702 		rc = ENOTSUP;
703 		goto fail1;
704 	}
705 
706 	if ((unsigned int)field_id >= desc_set_nentries) {
707 		rc = EINVAL;
708 		goto fail2;
709 	}
710 
711 	if (descp->emmd_mask_size == 0) {
712 		/* The ID points to a gap in the array of field descriptors. */
713 		rc = EINVAL;
714 		goto fail3;
715 	}
716 
717 	if (value_size != descp->emmd_value_size) {
718 		rc = EINVAL;
719 		goto fail4;
720 	}
721 
722 	if (mask_size != descp->emmd_mask_size) {
723 		rc = EINVAL;
724 		goto fail5;
725 	}
726 
727 	if (descp->emmd_endianness == EFX_MAE_FIELD_BE) {
728 		unsigned int i;
729 
730 		/*
731 		 * The mask/value are in network (big endian) order.
732 		 * The MCDI request field is also big endian.
733 		 */
734 
735 		EFSYS_ASSERT3U(value_size, ==, mask_size);
736 
737 		for (i = 0; i < value_size; ++i) {
738 			uint8_t *v_bytep = mvp + descp->emmd_value_offset + i;
739 			uint8_t *m_bytep = mvp + descp->emmd_mask_offset + i;
740 
741 			/*
742 			 * Apply the mask (which may be all-zeros) to the value.
743 			 *
744 			 * If this API is provided with some value to set for a
745 			 * given field in one specification and with some other
746 			 * value to set for this field in another specification,
747 			 * then, if the two masks are all-zeros, the field will
748 			 * avoid being counted as a mismatch when comparing the
749 			 * specifications using efx_mae_match_specs_equal() API.
750 			 */
751 			*v_bytep = value[i] & mask[i];
752 			*m_bytep = mask[i];
753 		}
754 	} else {
755 		efx_dword_t dword;
756 
757 		/*
758 		 * The mask/value are in host byte order.
759 		 * The MCDI request field is little endian.
760 		 */
761 		switch (value_size) {
762 		case 4:
763 			EFX_POPULATE_DWORD_1(dword,
764 			    EFX_DWORD_0, *(const uint32_t *)value);
765 
766 			memcpy(mvp + descp->emmd_value_offset,
767 			    &dword, sizeof (dword));
768 			break;
769 		default:
770 			EFSYS_ASSERT(B_FALSE);
771 		}
772 
773 		switch (mask_size) {
774 		case 4:
775 			EFX_POPULATE_DWORD_1(dword,
776 			    EFX_DWORD_0, *(const uint32_t *)mask);
777 
778 			memcpy(mvp + descp->emmd_mask_offset,
779 			    &dword, sizeof (dword));
780 			break;
781 		default:
782 			EFSYS_ASSERT(B_FALSE);
783 		}
784 	}
785 
786 	return (0);
787 
788 fail5:
789 	EFSYS_PROBE(fail5);
790 fail4:
791 	EFSYS_PROBE(fail4);
792 fail3:
793 	EFSYS_PROBE(fail3);
794 fail2:
795 	EFSYS_PROBE(fail2);
796 fail1:
797 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
798 	return (rc);
799 }
800 
801 	__checkReturn			efx_rc_t
802 efx_mae_match_spec_mport_set(
803 	__in				efx_mae_match_spec_t *spec,
804 	__in				const efx_mport_sel_t *valuep,
805 	__in_opt			const efx_mport_sel_t *maskp)
806 {
807 	uint32_t full_mask = UINT32_MAX;
808 	const uint8_t *vp;
809 	const uint8_t *mp;
810 	efx_rc_t rc;
811 
812 	if (valuep == NULL) {
813 		rc = EINVAL;
814 		goto fail1;
815 	}
816 
817 	vp = (const uint8_t *)&valuep->sel;
818 	if (maskp != NULL)
819 		mp = (const uint8_t *)&maskp->sel;
820 	else
821 		mp = (const uint8_t *)&full_mask;
822 
823 	rc = efx_mae_match_spec_field_set(spec,
824 	    EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR,
825 	    sizeof (valuep->sel), vp, sizeof (maskp->sel), mp);
826 	if (rc != 0)
827 		goto fail2;
828 
829 	return (0);
830 
831 fail2:
832 	EFSYS_PROBE(fail2);
833 fail1:
834 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
835 	return (rc);
836 }
837 
838 	__checkReturn			boolean_t
839 efx_mae_match_specs_equal(
840 	__in				const efx_mae_match_spec_t *left,
841 	__in				const efx_mae_match_spec_t *right)
842 {
843 	return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
844 }
845 
846 #define	EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit)		\
847 	    ((_mask)[(_bit) / (_mask_page_nbits)] &			\
848 		    (1ULL << ((_bit) & ((_mask_page_nbits) - 1))))
849 
850 static					boolean_t
851 efx_mask_is_prefix(
852 	__in				size_t mask_nbytes,
853 	__in_bcount(mask_nbytes)	const uint8_t *maskp)
854 {
855 	boolean_t prev_bit_is_set = B_TRUE;
856 	unsigned int i;
857 
858 	for (i = 0; i < 8 * mask_nbytes; ++i) {
859 		boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i);
860 
861 		if (!prev_bit_is_set && bit_is_set)
862 			return B_FALSE;
863 
864 		prev_bit_is_set = bit_is_set;
865 	}
866 
867 	return B_TRUE;
868 }
869 
870 static					boolean_t
871 efx_mask_is_all_ones(
872 	__in				size_t mask_nbytes,
873 	__in_bcount(mask_nbytes)	const uint8_t *maskp)
874 {
875 	unsigned int i;
876 	uint8_t t = ~0;
877 
878 	for (i = 0; i < mask_nbytes; ++i)
879 		t &= maskp[i];
880 
881 	return (t == (uint8_t)(~0));
882 }
883 
884 static					boolean_t
885 efx_mask_is_all_zeros(
886 	__in				size_t mask_nbytes,
887 	__in_bcount(mask_nbytes)	const uint8_t *maskp)
888 {
889 	unsigned int i;
890 	uint8_t t = 0;
891 
892 	for (i = 0; i < mask_nbytes; ++i)
893 		t |= maskp[i];
894 
895 	return (t == 0);
896 }
897 
898 	__checkReturn			boolean_t
899 efx_mae_match_spec_is_valid(
900 	__in				efx_nic_t *enp,
901 	__in				const efx_mae_match_spec_t *spec)
902 {
903 	efx_mae_t *maep = enp->en_maep;
904 	unsigned int field_ncaps = maep->em_max_nfields;
905 	const efx_mae_field_cap_t *field_caps;
906 	const efx_mae_mv_desc_t *desc_setp;
907 	unsigned int desc_set_nentries;
908 	boolean_t is_valid = B_TRUE;
909 	efx_mae_field_id_t field_id;
910 	const uint8_t *mvp;
911 
912 	switch (spec->emms_type) {
913 	case EFX_MAE_RULE_OUTER:
914 		field_caps = maep->em_outer_rule_field_caps;
915 		desc_setp = __efx_mae_outer_rule_mv_desc_set;
916 		desc_set_nentries =
917 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
918 		mvp = spec->emms_mask_value_pairs.outer;
919 		break;
920 	case EFX_MAE_RULE_ACTION:
921 		field_caps = maep->em_action_rule_field_caps;
922 		desc_setp = __efx_mae_action_rule_mv_desc_set;
923 		desc_set_nentries =
924 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
925 		mvp = spec->emms_mask_value_pairs.action;
926 		break;
927 	default:
928 		return (B_FALSE);
929 	}
930 
931 	if (field_caps == NULL)
932 		return (B_FALSE);
933 
934 	for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
935 	     ++field_id) {
936 		const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
937 		efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
938 		const uint8_t *alt_m_buf = mvp + descp->emmd_alt_mask_offset;
939 		const uint8_t *m_buf = mvp + descp->emmd_mask_offset;
940 		size_t alt_m_size = descp->emmd_alt_mask_size;
941 		size_t m_size = descp->emmd_mask_size;
942 
943 		if (m_size == 0)
944 			continue; /* Skip array gap */
945 
946 		if ((unsigned int)field_cap_id >= field_ncaps) {
947 			/*
948 			 * The FW has not reported capability status for
949 			 * this field. Make sure that its mask is zeroed.
950 			 */
951 			is_valid = efx_mask_is_all_zeros(m_size, m_buf);
952 			if (is_valid != B_FALSE)
953 				continue;
954 			else
955 				break;
956 		}
957 
958 		switch (field_caps[field_cap_id].emfc_support) {
959 		case MAE_FIELD_SUPPORTED_MATCH_MASK:
960 			is_valid = B_TRUE;
961 			break;
962 		case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
963 			is_valid = efx_mask_is_prefix(m_size, m_buf);
964 			break;
965 		case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
966 			is_valid = (efx_mask_is_all_ones(m_size, m_buf) ||
967 			    efx_mask_is_all_zeros(m_size, m_buf));
968 			break;
969 		case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
970 			is_valid = efx_mask_is_all_ones(m_size, m_buf);
971 
972 			if ((is_valid == B_FALSE) && (alt_m_size != 0)) {
973 				/*
974 				 * This field has an alternative one. The FW
975 				 * reports ALWAYS for both implying that one
976 				 * of them is required to have all-ones mask.
977 				 *
978 				 * The primary field's mask is incorrect; go
979 				 * on to check that of the alternative field.
980 				 */
981 				is_valid = efx_mask_is_all_ones(alt_m_size,
982 								alt_m_buf);
983 			}
984 			break;
985 		case MAE_FIELD_SUPPORTED_MATCH_NEVER:
986 		case MAE_FIELD_UNSUPPORTED:
987 		default:
988 			is_valid = efx_mask_is_all_zeros(m_size, m_buf);
989 			break;
990 		}
991 
992 		if (is_valid == B_FALSE)
993 			break;
994 	}
995 
996 	return (is_valid);
997 }
998 
999 	__checkReturn			efx_rc_t
1000 efx_mae_action_set_spec_init(
1001 	__in				efx_nic_t *enp,
1002 	__out				efx_mae_actions_t **specp)
1003 {
1004 	efx_mae_actions_t *spec;
1005 	efx_rc_t rc;
1006 
1007 	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
1008 	if (spec == NULL) {
1009 		rc = ENOMEM;
1010 		goto fail1;
1011 	}
1012 
1013 	spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
1014 
1015 	*specp = spec;
1016 
1017 	return (0);
1018 
1019 fail1:
1020 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1021 	return (rc);
1022 }
1023 
1024 					void
1025 efx_mae_action_set_spec_fini(
1026 	__in				efx_nic_t *enp,
1027 	__in				efx_mae_actions_t *spec)
1028 {
1029 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
1030 }
1031 
1032 static	__checkReturn			efx_rc_t
1033 efx_mae_action_set_add_decap(
1034 	__in				efx_mae_actions_t *spec,
1035 	__in				size_t arg_size,
1036 	__in_bcount(arg_size)		const uint8_t *arg)
1037 {
1038 	efx_rc_t rc;
1039 
1040 	_NOTE(ARGUNUSED(spec))
1041 
1042 	if (arg_size != 0) {
1043 		rc = EINVAL;
1044 		goto fail1;
1045 	}
1046 
1047 	if (arg != NULL) {
1048 		rc = EINVAL;
1049 		goto fail2;
1050 	}
1051 
1052 	/* This action does not have any arguments, so do nothing here. */
1053 
1054 	return (0);
1055 
1056 fail2:
1057 	EFSYS_PROBE(fail2);
1058 fail1:
1059 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1060 	return (rc);
1061 }
1062 
1063 static	__checkReturn			efx_rc_t
1064 efx_mae_action_set_add_vlan_pop(
1065 	__in				efx_mae_actions_t *spec,
1066 	__in				size_t arg_size,
1067 	__in_bcount(arg_size)		const uint8_t *arg)
1068 {
1069 	efx_rc_t rc;
1070 
1071 	if (arg_size != 0) {
1072 		rc = EINVAL;
1073 		goto fail1;
1074 	}
1075 
1076 	if (arg != NULL) {
1077 		rc = EINVAL;
1078 		goto fail2;
1079 	}
1080 
1081 	if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) {
1082 		rc = ENOTSUP;
1083 		goto fail3;
1084 	}
1085 
1086 	++spec->ema_n_vlan_tags_to_pop;
1087 
1088 	return (0);
1089 
1090 fail3:
1091 	EFSYS_PROBE(fail3);
1092 fail2:
1093 	EFSYS_PROBE(fail2);
1094 fail1:
1095 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1096 	return (rc);
1097 }
1098 
1099 static	__checkReturn			efx_rc_t
1100 efx_mae_action_set_add_vlan_push(
1101 	__in				efx_mae_actions_t *spec,
1102 	__in				size_t arg_size,
1103 	__in_bcount(arg_size)		const uint8_t *arg)
1104 {
1105 	unsigned int n_tags = spec->ema_n_vlan_tags_to_push;
1106 	efx_rc_t rc;
1107 
1108 	if (arg_size != sizeof (*spec->ema_vlan_push_descs)) {
1109 		rc = EINVAL;
1110 		goto fail1;
1111 	}
1112 
1113 	if (arg == NULL) {
1114 		rc = EINVAL;
1115 		goto fail2;
1116 	}
1117 
1118 	if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1119 		rc = ENOTSUP;
1120 		goto fail3;
1121 	}
1122 
1123 	memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size);
1124 	++(spec->ema_n_vlan_tags_to_push);
1125 
1126 	return (0);
1127 
1128 fail3:
1129 	EFSYS_PROBE(fail3);
1130 fail2:
1131 	EFSYS_PROBE(fail2);
1132 fail1:
1133 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1134 	return (rc);
1135 }
1136 
1137 static	__checkReturn			efx_rc_t
1138 efx_mae_action_set_add_encap(
1139 	__in				efx_mae_actions_t *spec,
1140 	__in				size_t arg_size,
1141 	__in_bcount(arg_size)		const uint8_t *arg)
1142 {
1143 	efx_rc_t rc;
1144 
1145 	/*
1146 	 * Adding this specific action to an action set spec and setting encap.
1147 	 * header ID in the spec are two individual steps. This design allows
1148 	 * the client driver to avoid encap. header allocation when it simply
1149 	 * needs to check the order of actions submitted by user ("validate"),
1150 	 * without actually allocating an action set and inserting a rule.
1151 	 *
1152 	 * For now, mark encap. header ID as invalid; the caller will invoke
1153 	 * efx_mae_action_set_fill_in_eh_id() to override the field prior
1154 	 * to action set allocation; otherwise, the allocation will fail.
1155 	 */
1156 	spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
1157 
1158 	/*
1159 	 * As explained above, there are no arguments to handle here.
1160 	 * efx_mae_action_set_fill_in_eh_id() will take care of them.
1161 	 */
1162 	if (arg_size != 0) {
1163 		rc = EINVAL;
1164 		goto fail1;
1165 	}
1166 
1167 	if (arg != NULL) {
1168 		rc = EINVAL;
1169 		goto fail2;
1170 	}
1171 
1172 	return (0);
1173 
1174 fail2:
1175 	EFSYS_PROBE(fail2);
1176 fail1:
1177 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1178 	return (rc);
1179 }
1180 
1181 static	__checkReturn			efx_rc_t
1182 efx_mae_action_set_add_flag(
1183 	__in				efx_mae_actions_t *spec,
1184 	__in				size_t arg_size,
1185 	__in_bcount(arg_size)		const uint8_t *arg)
1186 {
1187 	efx_rc_t rc;
1188 
1189 	_NOTE(ARGUNUSED(spec))
1190 
1191 	if (arg_size != 0) {
1192 		rc = EINVAL;
1193 		goto fail1;
1194 	}
1195 
1196 	if (arg != NULL) {
1197 		rc = EINVAL;
1198 		goto fail2;
1199 	}
1200 
1201 	/* This action does not have any arguments, so do nothing here. */
1202 
1203 	return (0);
1204 
1205 fail2:
1206 	EFSYS_PROBE(fail2);
1207 fail1:
1208 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1209 	return (rc);
1210 }
1211 
1212 static	__checkReturn			efx_rc_t
1213 efx_mae_action_set_add_mark(
1214 	__in				efx_mae_actions_t *spec,
1215 	__in				size_t arg_size,
1216 	__in_bcount(arg_size)		const uint8_t *arg)
1217 {
1218 	efx_rc_t rc;
1219 
1220 	if (arg_size != sizeof (spec->ema_mark_value)) {
1221 		rc = EINVAL;
1222 		goto fail1;
1223 	}
1224 
1225 	if (arg == NULL) {
1226 		rc = EINVAL;
1227 		goto fail2;
1228 	}
1229 
1230 	memcpy(&spec->ema_mark_value, arg, arg_size);
1231 
1232 	return (0);
1233 
1234 fail2:
1235 	EFSYS_PROBE(fail2);
1236 fail1:
1237 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1238 	return (rc);
1239 }
1240 
1241 static	__checkReturn			efx_rc_t
1242 efx_mae_action_set_add_deliver(
1243 	__in				efx_mae_actions_t *spec,
1244 	__in				size_t arg_size,
1245 	__in_bcount(arg_size)		const uint8_t *arg)
1246 {
1247 	efx_rc_t rc;
1248 
1249 	if (arg_size != sizeof (spec->ema_deliver_mport)) {
1250 		rc = EINVAL;
1251 		goto fail1;
1252 	}
1253 
1254 	if (arg == NULL) {
1255 		rc = EINVAL;
1256 		goto fail2;
1257 	}
1258 
1259 	memcpy(&spec->ema_deliver_mport, arg, arg_size);
1260 
1261 	return (0);
1262 
1263 fail2:
1264 	EFSYS_PROBE(fail2);
1265 fail1:
1266 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1267 	return (rc);
1268 }
1269 
1270 typedef struct efx_mae_action_desc_s {
1271 	/* Action specific handler */
1272 	efx_rc_t	(*emad_add)(efx_mae_actions_t *,
1273 				    size_t, const uint8_t *);
1274 } efx_mae_action_desc_t;
1275 
1276 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
1277 	[EFX_MAE_ACTION_DECAP] = {
1278 		.emad_add = efx_mae_action_set_add_decap
1279 	},
1280 	[EFX_MAE_ACTION_VLAN_POP] = {
1281 		.emad_add = efx_mae_action_set_add_vlan_pop
1282 	},
1283 	[EFX_MAE_ACTION_VLAN_PUSH] = {
1284 		.emad_add = efx_mae_action_set_add_vlan_push
1285 	},
1286 	[EFX_MAE_ACTION_ENCAP] = {
1287 		.emad_add = efx_mae_action_set_add_encap
1288 	},
1289 	[EFX_MAE_ACTION_FLAG] = {
1290 		.emad_add = efx_mae_action_set_add_flag
1291 	},
1292 	[EFX_MAE_ACTION_MARK] = {
1293 		.emad_add = efx_mae_action_set_add_mark
1294 	},
1295 	[EFX_MAE_ACTION_DELIVER] = {
1296 		.emad_add = efx_mae_action_set_add_deliver
1297 	}
1298 };
1299 
1300 static const uint32_t efx_mae_action_ordered_map =
1301 	(1U << EFX_MAE_ACTION_DECAP) |
1302 	(1U << EFX_MAE_ACTION_VLAN_POP) |
1303 	(1U << EFX_MAE_ACTION_VLAN_PUSH) |
1304 	(1U << EFX_MAE_ACTION_ENCAP) |
1305 	(1U << EFX_MAE_ACTION_FLAG) |
1306 	(1U << EFX_MAE_ACTION_MARK) |
1307 	(1U << EFX_MAE_ACTION_DELIVER);
1308 
1309 /*
1310  * These actions must not be added after DELIVER, but
1311  * they can have any place among the rest of
1312  * strictly ordered actions.
1313  */
1314 static const uint32_t efx_mae_action_nonstrict_map =
1315 	(1U << EFX_MAE_ACTION_FLAG) |
1316 	(1U << EFX_MAE_ACTION_MARK);
1317 
1318 static const uint32_t efx_mae_action_repeat_map =
1319 	(1U << EFX_MAE_ACTION_VLAN_POP) |
1320 	(1U << EFX_MAE_ACTION_VLAN_PUSH);
1321 
1322 /*
1323  * Add an action to an action set.
1324  *
1325  * This has to be invoked in the desired action order.
1326  * An out-of-order action request will be turned down.
1327  */
1328 static	__checkReturn			efx_rc_t
1329 efx_mae_action_set_spec_populate(
1330 	__in				efx_mae_actions_t *spec,
1331 	__in				efx_mae_action_t type,
1332 	__in				size_t arg_size,
1333 	__in_bcount(arg_size)		const uint8_t *arg)
1334 {
1335 	uint32_t action_mask;
1336 	efx_rc_t rc;
1337 
1338 	EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1339 	    (sizeof (efx_mae_action_ordered_map) * 8));
1340 	EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1341 	    (sizeof (efx_mae_action_repeat_map) * 8));
1342 
1343 	EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
1344 	EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK);
1345 	EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER);
1346 
1347 	if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
1348 		rc = EINVAL;
1349 		goto fail1;
1350 	}
1351 
1352 	action_mask = (1U << type);
1353 
1354 	if ((spec->ema_actions & action_mask) != 0) {
1355 		/* The action set already contains this action. */
1356 		if ((efx_mae_action_repeat_map & action_mask) == 0) {
1357 			/* Cannot add another non-repeatable action. */
1358 			rc = ENOTSUP;
1359 			goto fail2;
1360 		}
1361 	}
1362 
1363 	if ((efx_mae_action_ordered_map & action_mask) != 0) {
1364 		uint32_t strict_ordered_map =
1365 		    efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map;
1366 		uint32_t later_actions_mask =
1367 		    strict_ordered_map & ~(action_mask | (action_mask - 1));
1368 
1369 		if ((spec->ema_actions & later_actions_mask) != 0) {
1370 			/* Cannot add an action after later ordered actions. */
1371 			rc = ENOTSUP;
1372 			goto fail3;
1373 		}
1374 	}
1375 
1376 	if (efx_mae_actions[type].emad_add != NULL) {
1377 		rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
1378 		if (rc != 0)
1379 			goto fail4;
1380 	}
1381 
1382 	spec->ema_actions |= action_mask;
1383 
1384 	return (0);
1385 
1386 fail4:
1387 	EFSYS_PROBE(fail4);
1388 fail3:
1389 	EFSYS_PROBE(fail3);
1390 fail2:
1391 	EFSYS_PROBE(fail2);
1392 fail1:
1393 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1394 	return (rc);
1395 }
1396 
1397 	__checkReturn			efx_rc_t
1398 efx_mae_action_set_populate_decap(
1399 	__in				efx_mae_actions_t *spec)
1400 {
1401 	return (efx_mae_action_set_spec_populate(spec,
1402 	    EFX_MAE_ACTION_DECAP, 0, NULL));
1403 }
1404 
1405 	__checkReturn			efx_rc_t
1406 efx_mae_action_set_populate_vlan_pop(
1407 	__in				efx_mae_actions_t *spec)
1408 {
1409 	return (efx_mae_action_set_spec_populate(spec,
1410 	    EFX_MAE_ACTION_VLAN_POP, 0, NULL));
1411 }
1412 
1413 	__checkReturn			efx_rc_t
1414 efx_mae_action_set_populate_vlan_push(
1415 	__in				efx_mae_actions_t *spec,
1416 	__in				uint16_t tpid_be,
1417 	__in				uint16_t tci_be)
1418 {
1419 	efx_mae_action_vlan_push_t action;
1420 	const uint8_t *arg = (const uint8_t *)&action;
1421 
1422 	action.emavp_tpid_be = tpid_be;
1423 	action.emavp_tci_be = tci_be;
1424 
1425 	return (efx_mae_action_set_spec_populate(spec,
1426 	    EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg));
1427 }
1428 
1429 	__checkReturn			efx_rc_t
1430 efx_mae_action_set_populate_encap(
1431 	__in				efx_mae_actions_t *spec)
1432 {
1433 	/*
1434 	 * There is no argument to pass encap. header ID, thus, one does not
1435 	 * need to allocate an encap. header while parsing application input.
1436 	 * This is useful since building an action set may be done simply to
1437 	 * validate a rule, whilst resource allocation usually consumes time.
1438 	 */
1439 	return (efx_mae_action_set_spec_populate(spec,
1440 	    EFX_MAE_ACTION_ENCAP, 0, NULL));
1441 }
1442 
1443 	__checkReturn			efx_rc_t
1444 efx_mae_action_set_populate_flag(
1445 	__in				efx_mae_actions_t *spec)
1446 {
1447 	return (efx_mae_action_set_spec_populate(spec,
1448 	    EFX_MAE_ACTION_FLAG, 0, NULL));
1449 }
1450 
1451 	__checkReturn			efx_rc_t
1452 efx_mae_action_set_populate_mark(
1453 	__in				efx_mae_actions_t *spec,
1454 	__in				uint32_t mark_value)
1455 {
1456 	const uint8_t *arg = (const uint8_t *)&mark_value;
1457 
1458 	return (efx_mae_action_set_spec_populate(spec,
1459 	    EFX_MAE_ACTION_MARK, sizeof (mark_value), arg));
1460 }
1461 
1462 	__checkReturn			efx_rc_t
1463 efx_mae_action_set_populate_deliver(
1464 	__in				efx_mae_actions_t *spec,
1465 	__in				const efx_mport_sel_t *mportp)
1466 {
1467 	const uint8_t *arg;
1468 	efx_rc_t rc;
1469 
1470 	if (mportp == NULL) {
1471 		rc = EINVAL;
1472 		goto fail1;
1473 	}
1474 
1475 	arg = (const uint8_t *)&mportp->sel;
1476 
1477 	return (efx_mae_action_set_spec_populate(spec,
1478 	    EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
1479 
1480 fail1:
1481 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1482 	return (rc);
1483 }
1484 
1485 	__checkReturn			efx_rc_t
1486 efx_mae_action_set_populate_drop(
1487 	__in				efx_mae_actions_t *spec)
1488 {
1489 	efx_mport_sel_t mport;
1490 	const uint8_t *arg;
1491 	efx_dword_t dword;
1492 
1493 	EFX_POPULATE_DWORD_1(dword,
1494 	    MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL);
1495 
1496 	/*
1497 	 * The constructed DWORD is little-endian,
1498 	 * but the resulting value is meant to be
1499 	 * passed to MCDIs, where it will undergo
1500 	 * host-order to little endian conversion.
1501 	 */
1502 	mport.sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
1503 
1504 	arg = (const uint8_t *)&mport.sel;
1505 
1506 	return (efx_mae_action_set_spec_populate(spec,
1507 	    EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg));
1508 }
1509 
1510 	__checkReturn			boolean_t
1511 efx_mae_action_set_specs_equal(
1512 	__in				const efx_mae_actions_t *left,
1513 	__in				const efx_mae_actions_t *right)
1514 {
1515 	size_t cmp_size = EFX_FIELD_OFFSET(efx_mae_actions_t, ema_rsrc);
1516 
1517 	/*
1518 	 * An action set specification consists of two parts. The first part
1519 	 * indicates what actions are included in the action set, as well as
1520 	 * extra quantitative values (in example, the number of VLAN tags to
1521 	 * push). The second part comprises resource IDs used by the actions.
1522 	 *
1523 	 * A resource, in example, a counter, is allocated from the hardware
1524 	 * by the client, and it's the client who is responsible for keeping
1525 	 * track of allocated resources and comparing resource IDs if needed.
1526 	 *
1527 	 * In this API, don't compare resource IDs in the two specifications.
1528 	 */
1529 
1530 	return ((memcmp(left, right, cmp_size) == 0) ? B_TRUE : B_FALSE);
1531 }
1532 
1533 	__checkReturn			efx_rc_t
1534 efx_mae_match_specs_class_cmp(
1535 	__in				efx_nic_t *enp,
1536 	__in				const efx_mae_match_spec_t *left,
1537 	__in				const efx_mae_match_spec_t *right,
1538 	__out				boolean_t *have_same_classp)
1539 {
1540 	efx_mae_t *maep = enp->en_maep;
1541 	unsigned int field_ncaps = maep->em_max_nfields;
1542 	const efx_mae_field_cap_t *field_caps;
1543 	const efx_mae_mv_desc_t *desc_setp;
1544 	unsigned int desc_set_nentries;
1545 	boolean_t have_same_class = B_TRUE;
1546 	efx_mae_field_id_t field_id;
1547 	const uint8_t *mvpl;
1548 	const uint8_t *mvpr;
1549 	efx_rc_t rc;
1550 
1551 	switch (left->emms_type) {
1552 	case EFX_MAE_RULE_OUTER:
1553 		field_caps = maep->em_outer_rule_field_caps;
1554 		desc_setp = __efx_mae_outer_rule_mv_desc_set;
1555 		desc_set_nentries =
1556 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1557 		mvpl = left->emms_mask_value_pairs.outer;
1558 		mvpr = right->emms_mask_value_pairs.outer;
1559 		break;
1560 	case EFX_MAE_RULE_ACTION:
1561 		field_caps = maep->em_action_rule_field_caps;
1562 		desc_setp = __efx_mae_action_rule_mv_desc_set;
1563 		desc_set_nentries =
1564 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1565 		mvpl = left->emms_mask_value_pairs.action;
1566 		mvpr = right->emms_mask_value_pairs.action;
1567 		break;
1568 	default:
1569 		rc = ENOTSUP;
1570 		goto fail1;
1571 	}
1572 
1573 	if (field_caps == NULL) {
1574 		rc = EAGAIN;
1575 		goto fail2;
1576 	}
1577 
1578 	if (left->emms_type != right->emms_type ||
1579 	    left->emms_prio != right->emms_prio) {
1580 		/*
1581 		 * Rules of different types can never map to the same class.
1582 		 *
1583 		 * The FW can support some set of match criteria for one
1584 		 * priority and not support the very same set for
1585 		 * another priority. Thus, two rules which have
1586 		 * different priorities can never map to
1587 		 * the same class.
1588 		 */
1589 		*have_same_classp = B_FALSE;
1590 		return (0);
1591 	}
1592 
1593 	for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1594 	     ++field_id) {
1595 		const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1596 		efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1597 		const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
1598 		const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
1599 		size_t mask_size = descp->emmd_mask_size;
1600 		const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
1601 		const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
1602 		size_t value_size = descp->emmd_value_size;
1603 
1604 		if (mask_size == 0)
1605 			continue; /* Skip array gap */
1606 
1607 		if ((unsigned int)field_cap_id >= field_ncaps) {
1608 			/*
1609 			 * The FW has not reported capability status for this
1610 			 * field. It's unknown whether any difference between
1611 			 * the two masks / values affects the class. The only
1612 			 * case when the class must be the same is when these
1613 			 * mask-value pairs match. Otherwise, report mismatch.
1614 			 */
1615 			if ((memcmp(lmaskp, rmaskp, mask_size) == 0) &&
1616 			    (memcmp(lvalp, rvalp, value_size) == 0))
1617 				continue;
1618 			else
1619 				break;
1620 		}
1621 
1622 		if (field_caps[field_cap_id].emfc_mask_affects_class) {
1623 			if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
1624 				have_same_class = B_FALSE;
1625 				break;
1626 			}
1627 		}
1628 
1629 		if (field_caps[field_cap_id].emfc_match_affects_class) {
1630 			if (memcmp(lvalp, rvalp, value_size) != 0) {
1631 				have_same_class = B_FALSE;
1632 				break;
1633 			}
1634 		}
1635 	}
1636 
1637 	*have_same_classp = have_same_class;
1638 
1639 	return (0);
1640 
1641 fail2:
1642 	EFSYS_PROBE(fail2);
1643 fail1:
1644 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1645 	return (rc);
1646 }
1647 
1648 	__checkReturn		efx_rc_t
1649 efx_mae_outer_rule_insert(
1650 	__in			efx_nic_t *enp,
1651 	__in			const efx_mae_match_spec_t *spec,
1652 	__in			efx_tunnel_protocol_t encap_type,
1653 	__out			efx_mae_rule_id_t *or_idp)
1654 {
1655 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1656 	efx_mcdi_req_t req;
1657 	EFX_MCDI_DECLARE_BUF(payload,
1658 	    MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2,
1659 	    MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
1660 	uint32_t encap_type_mcdi;
1661 	efx_mae_rule_id_t or_id;
1662 	size_t offset;
1663 	efx_rc_t rc;
1664 
1665 	EFX_STATIC_ASSERT(sizeof (or_idp->id) ==
1666 	    MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN);
1667 
1668 	EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1669 	    MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL);
1670 
1671 	if (encp->enc_mae_supported == B_FALSE) {
1672 		rc = ENOTSUP;
1673 		goto fail1;
1674 	}
1675 
1676 	if (spec->emms_type != EFX_MAE_RULE_OUTER) {
1677 		rc = EINVAL;
1678 		goto fail2;
1679 	}
1680 
1681 	switch (encap_type) {
1682 	case EFX_TUNNEL_PROTOCOL_NONE:
1683 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
1684 		break;
1685 	case EFX_TUNNEL_PROTOCOL_VXLAN:
1686 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
1687 		break;
1688 	case EFX_TUNNEL_PROTOCOL_GENEVE:
1689 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
1690 		break;
1691 	case EFX_TUNNEL_PROTOCOL_NVGRE:
1692 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
1693 		break;
1694 	default:
1695 		rc = ENOTSUP;
1696 		goto fail3;
1697 	}
1698 
1699 	req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT;
1700 	req.emr_in_buf = payload;
1701 	req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2;
1702 	req.emr_out_buf = payload;
1703 	req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN;
1704 
1705 	MCDI_IN_SET_DWORD(req,
1706 	    MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi);
1707 
1708 	MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio);
1709 
1710 	/*
1711 	 * Mask-value pairs have been stored in the byte order needed for the
1712 	 * MCDI request and are thus safe to be copied directly to the buffer.
1713 	 * The library cares about byte order in efx_mae_match_spec_field_set().
1714 	 */
1715 	EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >=
1716 	    MAE_ENC_FIELD_PAIRS_LEN);
1717 	offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST;
1718 	memcpy(payload + offset, spec->emms_mask_value_pairs.outer,
1719 	    MAE_ENC_FIELD_PAIRS_LEN);
1720 
1721 	efx_mcdi_execute(enp, &req);
1722 
1723 	if (req.emr_rc != 0) {
1724 		rc = req.emr_rc;
1725 		goto fail4;
1726 	}
1727 
1728 	if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) {
1729 		rc = EMSGSIZE;
1730 		goto fail5;
1731 	}
1732 
1733 	or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
1734 	if (or_id.id == EFX_MAE_RSRC_ID_INVALID) {
1735 		rc = ENOENT;
1736 		goto fail6;
1737 	}
1738 
1739 	or_idp->id = or_id.id;
1740 
1741 	return (0);
1742 
1743 fail6:
1744 	EFSYS_PROBE(fail6);
1745 fail5:
1746 	EFSYS_PROBE(fail5);
1747 fail4:
1748 	EFSYS_PROBE(fail4);
1749 fail3:
1750 	EFSYS_PROBE(fail3);
1751 fail2:
1752 	EFSYS_PROBE(fail2);
1753 fail1:
1754 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1755 	return (rc);
1756 }
1757 
1758 	__checkReturn		efx_rc_t
1759 efx_mae_outer_rule_remove(
1760 	__in			efx_nic_t *enp,
1761 	__in			const efx_mae_rule_id_t *or_idp)
1762 {
1763 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1764 	efx_mcdi_req_t req;
1765 	EFX_MCDI_DECLARE_BUF(payload,
1766 	    MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1),
1767 	    MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
1768 	efx_rc_t rc;
1769 
1770 	if (encp->enc_mae_supported == B_FALSE) {
1771 		rc = ENOTSUP;
1772 		goto fail1;
1773 	}
1774 
1775 	req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE;
1776 	req.emr_in_buf = payload;
1777 	req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1);
1778 	req.emr_out_buf = payload;
1779 	req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1);
1780 
1781 	MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id);
1782 
1783 	efx_mcdi_execute(enp, &req);
1784 
1785 	if (req.emr_rc != 0) {
1786 		rc = req.emr_rc;
1787 		goto fail2;
1788 	}
1789 
1790 	if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LENMIN) {
1791 		rc = EMSGSIZE;
1792 		goto fail3;
1793 	}
1794 
1795 	if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) !=
1796 	    or_idp->id) {
1797 		/* Firmware failed to remove the outer rule. */
1798 		rc = EAGAIN;
1799 		goto fail4;
1800 	}
1801 
1802 	return (0);
1803 
1804 fail4:
1805 	EFSYS_PROBE(fail4);
1806 fail3:
1807 	EFSYS_PROBE(fail3);
1808 fail2:
1809 	EFSYS_PROBE(fail2);
1810 fail1:
1811 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1812 	return (rc);
1813 }
1814 
1815 	__checkReturn			efx_rc_t
1816 efx_mae_match_spec_outer_rule_id_set(
1817 	__in				efx_mae_match_spec_t *spec,
1818 	__in				const efx_mae_rule_id_t *or_idp)
1819 {
1820 	uint32_t full_mask = UINT32_MAX;
1821 	efx_rc_t rc;
1822 
1823 	if (spec->emms_type != EFX_MAE_RULE_ACTION) {
1824 		rc = EINVAL;
1825 		goto fail1;
1826 	}
1827 
1828 	if (or_idp == NULL) {
1829 		rc = EINVAL;
1830 		goto fail2;
1831 	}
1832 
1833 	rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID,
1834 	    sizeof (or_idp->id), (const uint8_t *)&or_idp->id,
1835 	    sizeof (full_mask), (const uint8_t *)&full_mask);
1836 	if (rc != 0)
1837 		goto fail3;
1838 
1839 	return (0);
1840 
1841 fail3:
1842 	EFSYS_PROBE(fail3);
1843 fail2:
1844 	EFSYS_PROBE(fail2);
1845 fail1:
1846 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1847 	return (rc);
1848 }
1849 
1850 	 __checkReturn			efx_rc_t
1851 efx_mae_encap_header_alloc(
1852 	__in				efx_nic_t *enp,
1853 	__in				efx_tunnel_protocol_t encap_type,
1854 	__in_bcount(header_size)	uint8_t *header_data,
1855 	__in				size_t header_size,
1856 	__out				efx_mae_eh_id_t *eh_idp)
1857 {
1858 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1859 	efx_mcdi_req_t req;
1860 	EFX_MCDI_DECLARE_BUF(payload,
1861 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LENMAX_MCDI2,
1862 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN);
1863 	uint32_t encap_type_mcdi;
1864 	efx_mae_eh_id_t eh_id;
1865 	efx_rc_t rc;
1866 
1867 	EFX_STATIC_ASSERT(sizeof (eh_idp->id) ==
1868 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_LEN);
1869 
1870 	EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1871 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
1872 
1873 	if (encp->enc_mae_supported == B_FALSE) {
1874 		rc = ENOTSUP;
1875 		goto fail1;
1876 	}
1877 
1878 	switch (encap_type) {
1879 	case EFX_TUNNEL_PROTOCOL_NONE:
1880 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
1881 		break;
1882 	case EFX_TUNNEL_PROTOCOL_VXLAN:
1883 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
1884 		break;
1885 	case EFX_TUNNEL_PROTOCOL_GENEVE:
1886 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
1887 		break;
1888 	case EFX_TUNNEL_PROTOCOL_NVGRE:
1889 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
1890 		break;
1891 	default:
1892 		rc = ENOTSUP;
1893 		goto fail2;
1894 	}
1895 
1896 	if (header_size >
1897 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2) {
1898 		rc = EINVAL;
1899 		goto fail3;
1900 	}
1901 
1902 	req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_ALLOC;
1903 	req.emr_in_buf = payload;
1904 	req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(header_size);
1905 	req.emr_out_buf = payload;
1906 	req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN;
1907 
1908 	MCDI_IN_SET_DWORD(req,
1909 	    MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, encap_type_mcdi);
1910 
1911 	memcpy(payload + MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_OFST,
1912 	    header_data, header_size);
1913 
1914 	efx_mcdi_execute(enp, &req);
1915 
1916 	if (req.emr_rc != 0) {
1917 		rc = req.emr_rc;
1918 		goto fail4;
1919 	}
1920 
1921 	if (req.emr_out_length_used < MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN) {
1922 		rc = EMSGSIZE;
1923 		goto fail5;
1924 	}
1925 
1926 	eh_id.id = MCDI_OUT_DWORD(req,
1927 	    MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID);
1928 
1929 	if (eh_id.id == EFX_MAE_RSRC_ID_INVALID) {
1930 		rc = ENOENT;
1931 		goto fail6;
1932 	}
1933 
1934 	eh_idp->id = eh_id.id;
1935 
1936 	return (0);
1937 
1938 fail6:
1939 	EFSYS_PROBE(fail6);
1940 fail5:
1941 	EFSYS_PROBE(fail5);
1942 fail4:
1943 	EFSYS_PROBE(fail4);
1944 fail3:
1945 	EFSYS_PROBE(fail3);
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_encap_header_free(
1955 	__in				efx_nic_t *enp,
1956 	__in				const efx_mae_eh_id_t *eh_idp)
1957 {
1958 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1959 	efx_mcdi_req_t req;
1960 	EFX_MCDI_DECLARE_BUF(payload,
1961 	    MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1),
1962 	    MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1));
1963 	efx_rc_t rc;
1964 
1965 	if (encp->enc_mae_supported == B_FALSE) {
1966 		rc = ENOTSUP;
1967 		goto fail1;
1968 	}
1969 
1970 	req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_FREE;
1971 	req.emr_in_buf = payload;
1972 	req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1);
1973 	req.emr_out_buf = payload;
1974 	req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1);
1975 
1976 	MCDI_IN_SET_DWORD(req, MAE_ENCAP_HEADER_FREE_IN_EH_ID, eh_idp->id);
1977 
1978 	efx_mcdi_execute(enp, &req);
1979 
1980 	if (req.emr_rc != 0) {
1981 		rc = req.emr_rc;
1982 		goto fail2;
1983 	}
1984 
1985 	if (MCDI_OUT_DWORD(req, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) !=
1986 	    eh_idp->id) {
1987 		/* Firmware failed to remove the encap. header. */
1988 		rc = EAGAIN;
1989 		goto fail3;
1990 	}
1991 
1992 	return (0);
1993 
1994 fail3:
1995 	EFSYS_PROBE(fail3);
1996 fail2:
1997 	EFSYS_PROBE(fail2);
1998 fail1:
1999 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2000 	return (rc);
2001 }
2002 
2003 	__checkReturn			efx_rc_t
2004 efx_mae_action_set_fill_in_eh_id(
2005 	__in				efx_mae_actions_t *spec,
2006 	__in				const efx_mae_eh_id_t *eh_idp)
2007 {
2008 	efx_rc_t rc;
2009 
2010 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) == 0) {
2011 		/*
2012 		 * The caller has not intended to have action ENCAP originally,
2013 		 * hence, this attempt to indicate encap. header ID is invalid.
2014 		 */
2015 		rc = EINVAL;
2016 		goto fail1;
2017 	}
2018 
2019 	if (spec->ema_rsrc.emar_eh_id.id != EFX_MAE_RSRC_ID_INVALID) {
2020 		/* The caller attempts to indicate encap. header ID twice. */
2021 		rc = EINVAL;
2022 		goto fail2;
2023 	}
2024 
2025 	if (eh_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2026 		rc = EINVAL;
2027 		goto fail3;
2028 	}
2029 
2030 	spec->ema_rsrc.emar_eh_id.id = eh_idp->id;
2031 
2032 	return (0);
2033 
2034 fail3:
2035 	EFSYS_PROBE(fail3);
2036 fail2:
2037 	EFSYS_PROBE(fail2);
2038 fail1:
2039 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2040 	return (rc);
2041 }
2042 
2043 	__checkReturn			efx_rc_t
2044 efx_mae_action_set_alloc(
2045 	__in				efx_nic_t *enp,
2046 	__in				const efx_mae_actions_t *spec,
2047 	__out				efx_mae_aset_id_t *aset_idp)
2048 {
2049 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2050 	efx_mcdi_req_t req;
2051 	EFX_MCDI_DECLARE_BUF(payload,
2052 	    MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
2053 	    MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
2054 	efx_mae_aset_id_t aset_id;
2055 	efx_rc_t rc;
2056 
2057 	if (encp->enc_mae_supported == B_FALSE) {
2058 		rc = ENOTSUP;
2059 		goto fail1;
2060 	}
2061 
2062 	req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
2063 	req.emr_in_buf = payload;
2064 	req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
2065 	req.emr_out_buf = payload;
2066 	req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
2067 
2068 	/*
2069 	 * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
2070 	 * corresponding resource types are supported by the implementation.
2071 	 * Use proper resource ID assignments instead.
2072 	 */
2073 	MCDI_IN_SET_DWORD(req,
2074 	    MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
2075 	MCDI_IN_SET_DWORD(req,
2076 	    MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
2077 
2078 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECAP)) != 0) {
2079 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2080 		    MAE_ACTION_SET_ALLOC_IN_DECAP, 1);
2081 	}
2082 
2083 	MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2084 	    MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
2085 
2086 	if (spec->ema_n_vlan_tags_to_push > 0) {
2087 		unsigned int outer_tag_idx;
2088 
2089 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2090 		    MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
2091 		    spec->ema_n_vlan_tags_to_push);
2092 
2093 		if (spec->ema_n_vlan_tags_to_push ==
2094 		    EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
2095 			MCDI_IN_SET_WORD(req,
2096 			    MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
2097 			    spec->ema_vlan_push_descs[0].emavp_tpid_be);
2098 			MCDI_IN_SET_WORD(req,
2099 			    MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
2100 			    spec->ema_vlan_push_descs[0].emavp_tci_be);
2101 		}
2102 
2103 		outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
2104 
2105 		MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
2106 		    spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
2107 		MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
2108 		    spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
2109 	}
2110 
2111 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
2112 	    spec->ema_rsrc.emar_eh_id.id);
2113 
2114 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
2115 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2116 		    MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
2117 	}
2118 
2119 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
2120 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2121 		    MAE_ACTION_SET_ALLOC_IN_MARK, 1);
2122 
2123 		MCDI_IN_SET_DWORD(req,
2124 		    MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
2125 	}
2126 
2127 	MCDI_IN_SET_DWORD(req,
2128 	    MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
2129 
2130 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
2131 	    MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2132 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
2133 	    MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2134 
2135 	efx_mcdi_execute(enp, &req);
2136 
2137 	if (req.emr_rc != 0) {
2138 		rc = req.emr_rc;
2139 		goto fail2;
2140 	}
2141 
2142 	if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
2143 		rc = EMSGSIZE;
2144 		goto fail3;
2145 	}
2146 
2147 	aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
2148 	if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
2149 		rc = ENOENT;
2150 		goto fail4;
2151 	}
2152 
2153 	aset_idp->id = aset_id.id;
2154 
2155 	return (0);
2156 
2157 fail4:
2158 	EFSYS_PROBE(fail4);
2159 fail3:
2160 	EFSYS_PROBE(fail3);
2161 fail2:
2162 	EFSYS_PROBE(fail2);
2163 fail1:
2164 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2165 	return (rc);
2166 }
2167 
2168 	__checkReturn			efx_rc_t
2169 efx_mae_action_set_free(
2170 	__in				efx_nic_t *enp,
2171 	__in				const efx_mae_aset_id_t *aset_idp)
2172 {
2173 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2174 	efx_mcdi_req_t req;
2175 	EFX_MCDI_DECLARE_BUF(payload,
2176 	    MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
2177 	    MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
2178 	efx_rc_t rc;
2179 
2180 	if (encp->enc_mae_supported == B_FALSE) {
2181 		rc = ENOTSUP;
2182 		goto fail1;
2183 	}
2184 
2185 	req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
2186 	req.emr_in_buf = payload;
2187 	req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
2188 	req.emr_out_buf = payload;
2189 	req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
2190 
2191 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
2192 
2193 	efx_mcdi_execute(enp, &req);
2194 
2195 	if (req.emr_rc != 0) {
2196 		rc = req.emr_rc;
2197 		goto fail2;
2198 	}
2199 
2200 	if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_FREE_OUT_LENMIN) {
2201 		rc = EMSGSIZE;
2202 		goto fail3;
2203 	}
2204 
2205 	if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
2206 	    aset_idp->id) {
2207 		/* Firmware failed to free the action set. */
2208 		rc = EAGAIN;
2209 		goto fail4;
2210 	}
2211 
2212 	return (0);
2213 
2214 fail4:
2215 	EFSYS_PROBE(fail4);
2216 fail3:
2217 	EFSYS_PROBE(fail3);
2218 fail2:
2219 	EFSYS_PROBE(fail2);
2220 fail1:
2221 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2222 	return (rc);
2223 }
2224 
2225 	__checkReturn			efx_rc_t
2226 efx_mae_action_rule_insert(
2227 	__in				efx_nic_t *enp,
2228 	__in				const efx_mae_match_spec_t *spec,
2229 	__in				const efx_mae_aset_list_id_t *asl_idp,
2230 	__in				const efx_mae_aset_id_t *as_idp,
2231 	__out				efx_mae_rule_id_t *ar_idp)
2232 {
2233 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2234 	efx_mcdi_req_t req;
2235 	EFX_MCDI_DECLARE_BUF(payload,
2236 	    MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2,
2237 	    MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
2238 	efx_oword_t *rule_response;
2239 	efx_mae_rule_id_t ar_id;
2240 	size_t offset;
2241 	efx_rc_t rc;
2242 
2243 	EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
2244 	    MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
2245 
2246 	EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2247 	    MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
2248 
2249 	if (encp->enc_mae_supported == B_FALSE) {
2250 		rc = ENOTSUP;
2251 		goto fail1;
2252 	}
2253 
2254 	if (spec->emms_type != EFX_MAE_RULE_ACTION ||
2255 	    (asl_idp != NULL && as_idp != NULL) ||
2256 	    (asl_idp == NULL && as_idp == NULL)) {
2257 		rc = EINVAL;
2258 		goto fail2;
2259 	}
2260 
2261 	req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
2262 	req.emr_in_buf = payload;
2263 	req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
2264 	req.emr_out_buf = payload;
2265 	req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
2266 
2267 	EFX_STATIC_ASSERT(sizeof (*rule_response) <=
2268 	    MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
2269 	offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
2270 	rule_response = (efx_oword_t *)(payload + offset);
2271 	EFX_POPULATE_OWORD_3(*rule_response,
2272 	    MAE_ACTION_RULE_RESPONSE_ASL_ID,
2273 	    (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
2274 	    MAE_ACTION_RULE_RESPONSE_AS_ID,
2275 	    (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
2276 	    MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
2277 
2278 	MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
2279 
2280 	/*
2281 	 * Mask-value pairs have been stored in the byte order needed for the
2282 	 * MCDI request and are thus safe to be copied directly to the buffer.
2283 	 */
2284 	EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
2285 	    MAE_FIELD_MASK_VALUE_PAIRS_LEN);
2286 	offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
2287 	memcpy(payload + offset, spec->emms_mask_value_pairs.action,
2288 	    MAE_FIELD_MASK_VALUE_PAIRS_LEN);
2289 
2290 	efx_mcdi_execute(enp, &req);
2291 
2292 	if (req.emr_rc != 0) {
2293 		rc = req.emr_rc;
2294 		goto fail3;
2295 	}
2296 
2297 	if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
2298 		rc = EMSGSIZE;
2299 		goto fail4;
2300 	}
2301 
2302 	ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
2303 	if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
2304 		rc = ENOENT;
2305 		goto fail5;
2306 	}
2307 
2308 	ar_idp->id = ar_id.id;
2309 
2310 	return (0);
2311 
2312 fail5:
2313 	EFSYS_PROBE(fail5);
2314 fail4:
2315 	EFSYS_PROBE(fail4);
2316 fail3:
2317 	EFSYS_PROBE(fail3);
2318 fail2:
2319 	EFSYS_PROBE(fail2);
2320 fail1:
2321 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2322 	return (rc);
2323 }
2324 
2325 	__checkReturn			efx_rc_t
2326 efx_mae_action_rule_remove(
2327 	__in				efx_nic_t *enp,
2328 	__in				const efx_mae_rule_id_t *ar_idp)
2329 {
2330 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2331 	efx_mcdi_req_t req;
2332 	EFX_MCDI_DECLARE_BUF(payload,
2333 	    MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
2334 	    MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
2335 	efx_rc_t rc;
2336 
2337 	if (encp->enc_mae_supported == B_FALSE) {
2338 		rc = ENOTSUP;
2339 		goto fail1;
2340 	}
2341 
2342 	req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
2343 	req.emr_in_buf = payload;
2344 	req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
2345 	req.emr_out_buf = payload;
2346 	req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
2347 
2348 	MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
2349 
2350 	efx_mcdi_execute(enp, &req);
2351 
2352 	if (req.emr_rc != 0) {
2353 		rc = req.emr_rc;
2354 		goto fail2;
2355 	}
2356 
2357 	if (req.emr_out_length_used <
2358 	    MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LENMIN) {
2359 		rc = EMSGSIZE;
2360 		goto fail3;
2361 	}
2362 
2363 	if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
2364 	    ar_idp->id) {
2365 		/* Firmware failed to delete the action rule. */
2366 		rc = EAGAIN;
2367 		goto fail4;
2368 	}
2369 
2370 	return (0);
2371 
2372 fail4:
2373 	EFSYS_PROBE(fail4);
2374 fail3:
2375 	EFSYS_PROBE(fail3);
2376 fail2:
2377 	EFSYS_PROBE(fail2);
2378 fail1:
2379 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2380 	return (rc);
2381 }
2382 
2383 #endif /* EFSYS_OPT_MAE */
2384