xref: /dpdk/drivers/common/sfc_efx/base/efx_mae.c (revision e253c33d)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2019 Xilinx, Inc. All rights reserved.
4  * All rights reserved.
5  */
6 
7 #include "efx.h"
8 #include "efx_impl.h"
9 
10 
11 #if EFSYS_OPT_MAE
12 
13 static	__checkReturn			efx_rc_t
14 efx_mae_get_capabilities(
15 	__in				efx_nic_t *enp)
16 {
17 	efx_mcdi_req_t req;
18 	EFX_MCDI_DECLARE_BUF(payload,
19 	    MC_CMD_MAE_GET_CAPS_IN_LEN,
20 	    MC_CMD_MAE_GET_CAPS_OUT_LEN);
21 	struct efx_mae_s *maep = enp->en_maep;
22 	efx_rc_t rc;
23 
24 	req.emr_cmd = MC_CMD_MAE_GET_CAPS;
25 	req.emr_in_buf = payload;
26 	req.emr_in_length = MC_CMD_MAE_GET_CAPS_IN_LEN;
27 	req.emr_out_buf = payload;
28 	req.emr_out_length = MC_CMD_MAE_GET_CAPS_OUT_LEN;
29 
30 	efx_mcdi_execute(enp, &req);
31 
32 	if (req.emr_rc != 0) {
33 		rc = req.emr_rc;
34 		goto fail1;
35 	}
36 
37 	if (req.emr_out_length_used < MC_CMD_MAE_GET_CAPS_OUT_LEN) {
38 		rc = EMSGSIZE;
39 		goto fail2;
40 	}
41 
42 	maep->em_max_n_outer_prios =
43 	    MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_OUTER_PRIOS);
44 
45 	maep->em_max_n_action_prios =
46 	    MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ACTION_PRIOS);
47 
48 	maep->em_encap_types_supported = 0;
49 
50 	if (MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ENCAP_TYPE_VXLAN) == 1) {
51 		maep->em_encap_types_supported |=
52 		    (1U << EFX_TUNNEL_PROTOCOL_VXLAN);
53 	}
54 
55 	if (MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ENCAP_TYPE_GENEVE) == 1) {
56 		maep->em_encap_types_supported |=
57 		    (1U << EFX_TUNNEL_PROTOCOL_GENEVE);
58 	}
59 
60 	if (MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ENCAP_TYPE_NVGRE) == 1) {
61 		maep->em_encap_types_supported |=
62 		    (1U << EFX_TUNNEL_PROTOCOL_NVGRE);
63 	}
64 
65 	maep->em_max_nfields =
66 	    MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT);
67 
68 	return (0);
69 
70 fail2:
71 	EFSYS_PROBE(fail2);
72 fail1:
73 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
74 	return (rc);
75 }
76 
77 static	__checkReturn			efx_rc_t
78 efx_mae_get_outer_rule_caps(
79 	__in				efx_nic_t *enp,
80 	__in				unsigned int field_ncaps,
81 	__out_ecount(field_ncaps)	efx_mae_field_cap_t *field_caps)
82 {
83 	efx_mcdi_req_t req;
84 	EFX_MCDI_DECLARE_BUF(payload,
85 	    MC_CMD_MAE_GET_OR_CAPS_IN_LEN,
86 	    MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2);
87 	unsigned int mcdi_field_ncaps;
88 	unsigned int i;
89 	efx_rc_t rc;
90 
91 	if (MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps) >
92 	    MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2) {
93 		rc = EINVAL;
94 		goto fail1;
95 	}
96 
97 	req.emr_cmd = MC_CMD_MAE_GET_OR_CAPS;
98 	req.emr_in_buf = payload;
99 	req.emr_in_length = MC_CMD_MAE_GET_OR_CAPS_IN_LEN;
100 	req.emr_out_buf = payload;
101 	req.emr_out_length = MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps);
102 
103 	efx_mcdi_execute(enp, &req);
104 
105 	if (req.emr_rc != 0) {
106 		rc = req.emr_rc;
107 		goto fail2;
108 	}
109 
110 	mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_OR_CAPS_OUT_COUNT);
111 
112 	if (req.emr_out_length_used <
113 	    MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(mcdi_field_ncaps)) {
114 		rc = EMSGSIZE;
115 		goto fail3;
116 	}
117 
118 	if (mcdi_field_ncaps > field_ncaps) {
119 		rc = EMSGSIZE;
120 		goto fail4;
121 	}
122 
123 	for (i = 0; i < mcdi_field_ncaps; ++i) {
124 		uint32_t match_flag;
125 		uint32_t mask_flag;
126 
127 		field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req,
128 		    MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
129 		    MAE_FIELD_FLAGS_SUPPORT_STATUS);
130 
131 		match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
132 		    MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
133 		    MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS);
134 
135 		field_caps[i].emfc_match_affects_class =
136 		    (match_flag != 0) ? B_TRUE : B_FALSE;
137 
138 		mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
139 		    MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
140 		    MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS);
141 
142 		field_caps[i].emfc_mask_affects_class =
143 		    (mask_flag != 0) ? B_TRUE : B_FALSE;
144 	}
145 
146 	return (0);
147 
148 fail4:
149 	EFSYS_PROBE(fail4);
150 fail3:
151 	EFSYS_PROBE(fail3);
152 fail2:
153 	EFSYS_PROBE(fail2);
154 fail1:
155 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
156 	return (rc);
157 }
158 
159 static	__checkReturn			efx_rc_t
160 efx_mae_get_action_rule_caps(
161 	__in				efx_nic_t *enp,
162 	__in				unsigned int field_ncaps,
163 	__out_ecount(field_ncaps)	efx_mae_field_cap_t *field_caps)
164 {
165 	efx_mcdi_req_t req;
166 	EFX_MCDI_DECLARE_BUF(payload,
167 	    MC_CMD_MAE_GET_AR_CAPS_IN_LEN,
168 	    MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2);
169 	unsigned int mcdi_field_ncaps;
170 	unsigned int i;
171 	efx_rc_t rc;
172 
173 	if (MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps) >
174 	    MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2) {
175 		rc = EINVAL;
176 		goto fail1;
177 	}
178 
179 	req.emr_cmd = MC_CMD_MAE_GET_AR_CAPS;
180 	req.emr_in_buf = payload;
181 	req.emr_in_length = MC_CMD_MAE_GET_AR_CAPS_IN_LEN;
182 	req.emr_out_buf = payload;
183 	req.emr_out_length = MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps);
184 
185 	efx_mcdi_execute(enp, &req);
186 
187 	if (req.emr_rc != 0) {
188 		rc = req.emr_rc;
189 		goto fail2;
190 	}
191 
192 	mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_OR_CAPS_OUT_COUNT);
193 
194 	if (req.emr_out_length_used <
195 	    MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(mcdi_field_ncaps)) {
196 		rc = EMSGSIZE;
197 		goto fail3;
198 	}
199 
200 	if (mcdi_field_ncaps > field_ncaps) {
201 		rc = EMSGSIZE;
202 		goto fail4;
203 	}
204 
205 	for (i = 0; i < mcdi_field_ncaps; ++i) {
206 		uint32_t match_flag;
207 		uint32_t mask_flag;
208 
209 		field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req,
210 		    MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
211 		    MAE_FIELD_FLAGS_SUPPORT_STATUS);
212 
213 		match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
214 		    MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
215 		    MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS);
216 
217 		field_caps[i].emfc_match_affects_class =
218 		    (match_flag != 0) ? B_TRUE : B_FALSE;
219 
220 		mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
221 		    MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
222 		    MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS);
223 
224 		field_caps[i].emfc_mask_affects_class =
225 		    (mask_flag != 0) ? B_TRUE : B_FALSE;
226 	}
227 
228 	return (0);
229 
230 fail4:
231 	EFSYS_PROBE(fail4);
232 fail3:
233 	EFSYS_PROBE(fail3);
234 fail2:
235 	EFSYS_PROBE(fail2);
236 fail1:
237 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
238 	return (rc);
239 }
240 
241 	__checkReturn			efx_rc_t
242 efx_mae_init(
243 	__in				efx_nic_t *enp)
244 {
245 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
246 	efx_mae_field_cap_t *or_fcaps;
247 	size_t or_fcaps_size;
248 	efx_mae_field_cap_t *ar_fcaps;
249 	size_t ar_fcaps_size;
250 	efx_mae_t *maep;
251 	efx_rc_t rc;
252 
253 	if (encp->enc_mae_supported == B_FALSE) {
254 		rc = ENOTSUP;
255 		goto fail1;
256 	}
257 
258 	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*maep), maep);
259 	if (maep == NULL) {
260 		rc = ENOMEM;
261 		goto fail2;
262 	}
263 
264 	enp->en_maep = maep;
265 
266 	rc = efx_mae_get_capabilities(enp);
267 	if (rc != 0)
268 		goto fail3;
269 
270 	or_fcaps_size = maep->em_max_nfields * sizeof (*or_fcaps);
271 	EFSYS_KMEM_ALLOC(enp->en_esip, or_fcaps_size, or_fcaps);
272 	if (or_fcaps == NULL) {
273 		rc = ENOMEM;
274 		goto fail4;
275 	}
276 
277 	maep->em_outer_rule_field_caps_size = or_fcaps_size;
278 	maep->em_outer_rule_field_caps = or_fcaps;
279 
280 	rc = efx_mae_get_outer_rule_caps(enp, maep->em_max_nfields, or_fcaps);
281 	if (rc != 0)
282 		goto fail5;
283 
284 	ar_fcaps_size = maep->em_max_nfields * sizeof (*ar_fcaps);
285 	EFSYS_KMEM_ALLOC(enp->en_esip, ar_fcaps_size, ar_fcaps);
286 	if (ar_fcaps == NULL) {
287 		rc = ENOMEM;
288 		goto fail6;
289 	}
290 
291 	maep->em_action_rule_field_caps_size = ar_fcaps_size;
292 	maep->em_action_rule_field_caps = ar_fcaps;
293 
294 	rc = efx_mae_get_action_rule_caps(enp, maep->em_max_nfields, ar_fcaps);
295 	if (rc != 0)
296 		goto fail7;
297 
298 	return (0);
299 
300 fail7:
301 	EFSYS_PROBE(fail5);
302 	EFSYS_KMEM_FREE(enp->en_esip, ar_fcaps_size, ar_fcaps);
303 fail6:
304 	EFSYS_PROBE(fail4);
305 fail5:
306 	EFSYS_PROBE(fail5);
307 	EFSYS_KMEM_FREE(enp->en_esip, or_fcaps_size, or_fcaps);
308 fail4:
309 	EFSYS_PROBE(fail4);
310 fail3:
311 	EFSYS_PROBE(fail3);
312 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (struct efx_mae_s), enp->en_maep);
313 	enp->en_maep = NULL;
314 fail2:
315 	EFSYS_PROBE(fail2);
316 fail1:
317 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
318 	return (rc);
319 }
320 
321 					void
322 efx_mae_fini(
323 	__in				efx_nic_t *enp)
324 {
325 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
326 	efx_mae_t *maep = enp->en_maep;
327 
328 	if (encp->enc_mae_supported == B_FALSE)
329 		return;
330 
331 	EFSYS_KMEM_FREE(enp->en_esip, maep->em_action_rule_field_caps_size,
332 	    maep->em_action_rule_field_caps);
333 	EFSYS_KMEM_FREE(enp->en_esip, maep->em_outer_rule_field_caps_size,
334 	    maep->em_outer_rule_field_caps);
335 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (*maep), maep);
336 	enp->en_maep = NULL;
337 }
338 
339 	__checkReturn			efx_rc_t
340 efx_mae_get_limits(
341 	__in				efx_nic_t *enp,
342 	__out				efx_mae_limits_t *emlp)
343 {
344 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
345 	struct efx_mae_s *maep = enp->en_maep;
346 	efx_rc_t rc;
347 
348 	if (encp->enc_mae_supported == B_FALSE) {
349 		rc = ENOTSUP;
350 		goto fail1;
351 	}
352 
353 	emlp->eml_max_n_outer_prios = maep->em_max_n_outer_prios;
354 	emlp->eml_max_n_action_prios = maep->em_max_n_action_prios;
355 	emlp->eml_encap_types_supported = maep->em_encap_types_supported;
356 
357 	return (0);
358 
359 fail1:
360 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
361 	return (rc);
362 }
363 
364 	__checkReturn			efx_rc_t
365 efx_mae_match_spec_init(
366 	__in				efx_nic_t *enp,
367 	__in				efx_mae_rule_type_t type,
368 	__in				uint32_t prio,
369 	__out				efx_mae_match_spec_t **specp)
370 {
371 	efx_mae_match_spec_t *spec;
372 	efx_rc_t rc;
373 
374 	switch (type) {
375 	case EFX_MAE_RULE_OUTER:
376 		break;
377 	case EFX_MAE_RULE_ACTION:
378 		break;
379 	default:
380 		rc = ENOTSUP;
381 		goto fail1;
382 	}
383 
384 	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
385 	if (spec == NULL) {
386 		rc = ENOMEM;
387 		goto fail2;
388 	}
389 
390 	spec->emms_type = type;
391 	spec->emms_prio = prio;
392 
393 	*specp = spec;
394 
395 	return (0);
396 
397 fail2:
398 	EFSYS_PROBE(fail2);
399 fail1:
400 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
401 	return (rc);
402 }
403 
404 					void
405 efx_mae_match_spec_fini(
406 	__in				efx_nic_t *enp,
407 	__in				efx_mae_match_spec_t *spec)
408 {
409 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
410 }
411 
412 /* Named identifiers which are valid indices to efx_mae_field_cap_t */
413 typedef enum efx_mae_field_cap_id_e {
414 	EFX_MAE_FIELD_ID_INGRESS_MPORT_SELECTOR = MAE_FIELD_INGRESS_PORT,
415 	EFX_MAE_FIELD_ID_ETHER_TYPE_BE = MAE_FIELD_ETHER_TYPE,
416 	EFX_MAE_FIELD_ID_ETH_SADDR_BE = MAE_FIELD_ETH_SADDR,
417 	EFX_MAE_FIELD_ID_ETH_DADDR_BE = MAE_FIELD_ETH_DADDR,
418 	EFX_MAE_FIELD_ID_VLAN0_TCI_BE = MAE_FIELD_VLAN0_TCI,
419 	EFX_MAE_FIELD_ID_VLAN0_PROTO_BE = MAE_FIELD_VLAN0_PROTO,
420 	EFX_MAE_FIELD_ID_VLAN1_TCI_BE = MAE_FIELD_VLAN1_TCI,
421 	EFX_MAE_FIELD_ID_VLAN1_PROTO_BE = MAE_FIELD_VLAN1_PROTO,
422 	EFX_MAE_FIELD_ID_SRC_IP4_BE = MAE_FIELD_SRC_IP4,
423 	EFX_MAE_FIELD_ID_DST_IP4_BE = MAE_FIELD_DST_IP4,
424 	EFX_MAE_FIELD_ID_IP_PROTO = MAE_FIELD_IP_PROTO,
425 	EFX_MAE_FIELD_ID_IP_TOS = MAE_FIELD_IP_TOS,
426 	EFX_MAE_FIELD_ID_IP_TTL = MAE_FIELD_IP_TTL,
427 	EFX_MAE_FIELD_ID_SRC_IP6_BE = MAE_FIELD_SRC_IP6,
428 	EFX_MAE_FIELD_ID_DST_IP6_BE = MAE_FIELD_DST_IP6,
429 	EFX_MAE_FIELD_ID_L4_SPORT_BE = MAE_FIELD_L4_SPORT,
430 	EFX_MAE_FIELD_ID_L4_DPORT_BE = MAE_FIELD_L4_DPORT,
431 	EFX_MAE_FIELD_ID_TCP_FLAGS_BE = MAE_FIELD_TCP_FLAGS,
432 	EFX_MAE_FIELD_ID_ENC_ETHER_TYPE_BE = MAE_FIELD_ENC_ETHER_TYPE,
433 	EFX_MAE_FIELD_ID_ENC_ETH_SADDR_BE = MAE_FIELD_ENC_ETH_SADDR,
434 	EFX_MAE_FIELD_ID_ENC_ETH_DADDR_BE = MAE_FIELD_ENC_ETH_DADDR,
435 	EFX_MAE_FIELD_ID_ENC_VLAN0_TCI_BE = MAE_FIELD_ENC_VLAN0_TCI,
436 	EFX_MAE_FIELD_ID_ENC_VLAN0_PROTO_BE = MAE_FIELD_ENC_VLAN0_PROTO,
437 	EFX_MAE_FIELD_ID_ENC_VLAN1_TCI_BE = MAE_FIELD_ENC_VLAN1_TCI,
438 	EFX_MAE_FIELD_ID_ENC_VLAN1_PROTO_BE = MAE_FIELD_ENC_VLAN1_PROTO,
439 	EFX_MAE_FIELD_ID_ENC_SRC_IP4_BE = MAE_FIELD_ENC_SRC_IP4,
440 	EFX_MAE_FIELD_ID_ENC_DST_IP4_BE = MAE_FIELD_ENC_DST_IP4,
441 	EFX_MAE_FIELD_ID_ENC_IP_PROTO = MAE_FIELD_ENC_IP_PROTO,
442 	EFX_MAE_FIELD_ID_ENC_IP_TOS = MAE_FIELD_ENC_IP_TOS,
443 	EFX_MAE_FIELD_ID_ENC_IP_TTL = MAE_FIELD_ENC_IP_TTL,
444 	EFX_MAE_FIELD_ID_ENC_SRC_IP6_BE = MAE_FIELD_ENC_SRC_IP6,
445 	EFX_MAE_FIELD_ID_ENC_DST_IP6_BE = MAE_FIELD_ENC_DST_IP6,
446 	EFX_MAE_FIELD_ID_ENC_L4_SPORT_BE = MAE_FIELD_ENC_L4_SPORT,
447 	EFX_MAE_FIELD_ID_ENC_L4_DPORT_BE = MAE_FIELD_ENC_L4_DPORT,
448 	EFX_MAE_FIELD_ID_ENC_VNET_ID_BE = MAE_FIELD_ENC_VNET_ID,
449 	EFX_MAE_FIELD_ID_OUTER_RULE_ID = MAE_FIELD_OUTER_RULE_ID,
450 
451 	EFX_MAE_FIELD_CAP_NIDS
452 } efx_mae_field_cap_id_t;
453 
454 typedef enum efx_mae_field_endianness_e {
455 	EFX_MAE_FIELD_LE = 0,
456 	EFX_MAE_FIELD_BE,
457 
458 	EFX_MAE_FIELD_ENDIANNESS_NTYPES
459 } efx_mae_field_endianness_t;
460 
461 /*
462  * The following structure is a means to describe an MAE field.
463  * The information in it is meant to be used internally by
464  * APIs for addressing a given field in a mask-value pairs
465  * structure and for validation purposes.
466  *
467  * A field may have an alternative one. This structure
468  * has additional members to reference the alternative
469  * field's mask. See efx_mae_match_spec_is_valid().
470  */
471 typedef struct efx_mae_mv_desc_s {
472 	efx_mae_field_cap_id_t		emmd_field_cap_id;
473 
474 	size_t				emmd_value_size;
475 	size_t				emmd_value_offset;
476 	size_t				emmd_mask_size;
477 	size_t				emmd_mask_offset;
478 
479 	/*
480 	 * Having the alternative field's mask size set to 0
481 	 * means that there's no alternative field specified.
482 	 */
483 	size_t				emmd_alt_mask_size;
484 	size_t				emmd_alt_mask_offset;
485 
486 	/* Primary field and the alternative one are of the same endianness. */
487 	efx_mae_field_endianness_t	emmd_endianness;
488 } efx_mae_mv_desc_t;
489 
490 /* Indices to this array are provided by efx_mae_field_id_t */
491 static const efx_mae_mv_desc_t __efx_mae_action_rule_mv_desc_set[] = {
492 #define	EFX_MAE_MV_DESC(_name, _endianness)				\
493 	[EFX_MAE_FIELD_##_name] =					\
494 	{								\
495 		EFX_MAE_FIELD_ID_##_name,				\
496 		MAE_FIELD_MASK_VALUE_PAIRS_##_name##_LEN,		\
497 		MAE_FIELD_MASK_VALUE_PAIRS_##_name##_OFST,		\
498 		MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_LEN,		\
499 		MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_OFST,		\
500 		0, 0 /* no alternative field */,			\
501 		_endianness						\
502 	}
503 
504 	EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
505 	EFX_MAE_MV_DESC(ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
506 	EFX_MAE_MV_DESC(ETH_SADDR_BE, EFX_MAE_FIELD_BE),
507 	EFX_MAE_MV_DESC(ETH_DADDR_BE, EFX_MAE_FIELD_BE),
508 	EFX_MAE_MV_DESC(VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
509 	EFX_MAE_MV_DESC(VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
510 	EFX_MAE_MV_DESC(VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
511 	EFX_MAE_MV_DESC(VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
512 	EFX_MAE_MV_DESC(SRC_IP4_BE, EFX_MAE_FIELD_BE),
513 	EFX_MAE_MV_DESC(DST_IP4_BE, EFX_MAE_FIELD_BE),
514 	EFX_MAE_MV_DESC(IP_PROTO, EFX_MAE_FIELD_BE),
515 	EFX_MAE_MV_DESC(IP_TOS, EFX_MAE_FIELD_BE),
516 	EFX_MAE_MV_DESC(IP_TTL, EFX_MAE_FIELD_BE),
517 	EFX_MAE_MV_DESC(SRC_IP6_BE, EFX_MAE_FIELD_BE),
518 	EFX_MAE_MV_DESC(DST_IP6_BE, EFX_MAE_FIELD_BE),
519 	EFX_MAE_MV_DESC(L4_SPORT_BE, EFX_MAE_FIELD_BE),
520 	EFX_MAE_MV_DESC(L4_DPORT_BE, EFX_MAE_FIELD_BE),
521 	EFX_MAE_MV_DESC(TCP_FLAGS_BE, EFX_MAE_FIELD_BE),
522 	EFX_MAE_MV_DESC(ENC_VNET_ID_BE, EFX_MAE_FIELD_BE),
523 	EFX_MAE_MV_DESC(OUTER_RULE_ID, EFX_MAE_FIELD_LE),
524 
525 #undef EFX_MAE_MV_DESC
526 };
527 
528 /* Indices to this array are provided by efx_mae_field_id_t */
529 static const efx_mae_mv_desc_t __efx_mae_outer_rule_mv_desc_set[] = {
530 #define	EFX_MAE_MV_DESC(_name, _endianness)				\
531 	[EFX_MAE_FIELD_##_name] =					\
532 	{								\
533 		EFX_MAE_FIELD_ID_##_name,				\
534 		MAE_ENC_FIELD_PAIRS_##_name##_LEN,			\
535 		MAE_ENC_FIELD_PAIRS_##_name##_OFST,			\
536 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,			\
537 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,		\
538 		0, 0 /* no alternative field */,			\
539 		_endianness						\
540 	}
541 
542 /* Same as EFX_MAE_MV_DESC(), but also indicates an alternative field. */
543 #define	EFX_MAE_MV_DESC_ALT(_name, _alt_name, _endianness)		\
544 	[EFX_MAE_FIELD_##_name] =					\
545 	{								\
546 		EFX_MAE_FIELD_ID_##_name,				\
547 		MAE_ENC_FIELD_PAIRS_##_name##_LEN,			\
548 		MAE_ENC_FIELD_PAIRS_##_name##_OFST,			\
549 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,			\
550 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,		\
551 		MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_LEN,		\
552 		MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_OFST,		\
553 		_endianness						\
554 	}
555 
556 	EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
557 	EFX_MAE_MV_DESC(ENC_ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
558 	EFX_MAE_MV_DESC(ENC_ETH_SADDR_BE, EFX_MAE_FIELD_BE),
559 	EFX_MAE_MV_DESC(ENC_ETH_DADDR_BE, EFX_MAE_FIELD_BE),
560 	EFX_MAE_MV_DESC(ENC_VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
561 	EFX_MAE_MV_DESC(ENC_VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
562 	EFX_MAE_MV_DESC(ENC_VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
563 	EFX_MAE_MV_DESC(ENC_VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
564 	EFX_MAE_MV_DESC_ALT(ENC_SRC_IP4_BE, ENC_SRC_IP6_BE, EFX_MAE_FIELD_BE),
565 	EFX_MAE_MV_DESC_ALT(ENC_DST_IP4_BE, ENC_DST_IP6_BE, EFX_MAE_FIELD_BE),
566 	EFX_MAE_MV_DESC(ENC_IP_PROTO, EFX_MAE_FIELD_BE),
567 	EFX_MAE_MV_DESC(ENC_IP_TOS, EFX_MAE_FIELD_BE),
568 	EFX_MAE_MV_DESC(ENC_IP_TTL, EFX_MAE_FIELD_BE),
569 	EFX_MAE_MV_DESC_ALT(ENC_SRC_IP6_BE, ENC_SRC_IP4_BE, EFX_MAE_FIELD_BE),
570 	EFX_MAE_MV_DESC_ALT(ENC_DST_IP6_BE, ENC_DST_IP4_BE, EFX_MAE_FIELD_BE),
571 	EFX_MAE_MV_DESC(ENC_L4_SPORT_BE, EFX_MAE_FIELD_BE),
572 	EFX_MAE_MV_DESC(ENC_L4_DPORT_BE, EFX_MAE_FIELD_BE),
573 
574 #undef EFX_MAE_MV_DESC_ALT
575 #undef EFX_MAE_MV_DESC
576 };
577 
578 	__checkReturn			efx_rc_t
579 efx_mae_mport_by_phy_port(
580 	__in				uint32_t phy_port,
581 	__out				efx_mport_sel_t *mportp)
582 {
583 	efx_dword_t dword;
584 	efx_rc_t rc;
585 
586 	if (phy_port > EFX_MASK32(MAE_MPORT_SELECTOR_PPORT_ID)) {
587 		rc = EINVAL;
588 		goto fail1;
589 	}
590 
591 	EFX_POPULATE_DWORD_2(dword,
592 	    MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT,
593 	    MAE_MPORT_SELECTOR_PPORT_ID, phy_port);
594 
595 	memset(mportp, 0, sizeof (*mportp));
596 	mportp->sel = dword.ed_u32[0];
597 
598 	return (0);
599 
600 fail1:
601 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
602 	return (rc);
603 }
604 
605 	__checkReturn			efx_rc_t
606 efx_mae_mport_by_pcie_function(
607 	__in				uint32_t pf,
608 	__in				uint32_t vf,
609 	__out				efx_mport_sel_t *mportp)
610 {
611 	efx_dword_t dword;
612 	efx_rc_t rc;
613 
614 	EFX_STATIC_ASSERT(EFX_PCI_VF_INVALID ==
615 	    MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL);
616 
617 	if (pf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_PF_ID)) {
618 		rc = EINVAL;
619 		goto fail1;
620 	}
621 
622 	if (vf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_VF_ID)) {
623 		rc = EINVAL;
624 		goto fail2;
625 	}
626 
627 	EFX_POPULATE_DWORD_3(dword,
628 	    MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
629 	    MAE_MPORT_SELECTOR_FUNC_PF_ID, pf,
630 	    MAE_MPORT_SELECTOR_FUNC_VF_ID, vf);
631 
632 	memset(mportp, 0, sizeof (*mportp));
633 	mportp->sel = dword.ed_u32[0];
634 
635 	return (0);
636 
637 fail2:
638 	EFSYS_PROBE(fail2);
639 fail1:
640 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
641 	return (rc);
642 }
643 
644 	__checkReturn			efx_rc_t
645 efx_mae_match_spec_field_set(
646 	__in				efx_mae_match_spec_t *spec,
647 	__in				efx_mae_field_id_t field_id,
648 	__in				size_t value_size,
649 	__in_bcount(value_size)		const uint8_t *value,
650 	__in				size_t mask_size,
651 	__in_bcount(mask_size)		const uint8_t *mask)
652 {
653 	const efx_mae_mv_desc_t *descp;
654 	unsigned int desc_set_nentries;
655 	uint8_t *mvp;
656 	efx_rc_t rc;
657 
658 	switch (spec->emms_type) {
659 	case EFX_MAE_RULE_OUTER:
660 		desc_set_nentries =
661 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
662 		descp = &__efx_mae_outer_rule_mv_desc_set[field_id];
663 		mvp = spec->emms_mask_value_pairs.outer;
664 		break;
665 	case EFX_MAE_RULE_ACTION:
666 		desc_set_nentries =
667 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
668 		descp = &__efx_mae_action_rule_mv_desc_set[field_id];
669 		mvp = spec->emms_mask_value_pairs.action;
670 		break;
671 	default:
672 		rc = ENOTSUP;
673 		goto fail1;
674 	}
675 
676 	if ((unsigned int)field_id >= desc_set_nentries) {
677 		rc = EINVAL;
678 		goto fail2;
679 	}
680 
681 	if (value_size != descp->emmd_value_size) {
682 		rc = EINVAL;
683 		goto fail3;
684 	}
685 
686 	if (mask_size != descp->emmd_mask_size) {
687 		rc = EINVAL;
688 		goto fail4;
689 	}
690 
691 	if (descp->emmd_endianness == EFX_MAE_FIELD_BE) {
692 		/*
693 		 * The mask/value are in network (big endian) order.
694 		 * The MCDI request field is also big endian.
695 		 */
696 		memcpy(mvp + descp->emmd_value_offset, value, value_size);
697 		memcpy(mvp + descp->emmd_mask_offset, mask, mask_size);
698 	} else {
699 		efx_dword_t dword;
700 
701 		/*
702 		 * The mask/value are in host byte order.
703 		 * The MCDI request field is little endian.
704 		 */
705 		switch (value_size) {
706 		case 4:
707 			EFX_POPULATE_DWORD_1(dword,
708 			    EFX_DWORD_0, *(const uint32_t *)value);
709 
710 			memcpy(mvp + descp->emmd_value_offset,
711 			    &dword, sizeof (dword));
712 			break;
713 		default:
714 			EFSYS_ASSERT(B_FALSE);
715 		}
716 
717 		switch (mask_size) {
718 		case 4:
719 			EFX_POPULATE_DWORD_1(dword,
720 			    EFX_DWORD_0, *(const uint32_t *)mask);
721 
722 			memcpy(mvp + descp->emmd_mask_offset,
723 			    &dword, sizeof (dword));
724 			break;
725 		default:
726 			EFSYS_ASSERT(B_FALSE);
727 		}
728 	}
729 
730 	return (0);
731 
732 fail4:
733 	EFSYS_PROBE(fail4);
734 fail3:
735 	EFSYS_PROBE(fail3);
736 fail2:
737 	EFSYS_PROBE(fail2);
738 fail1:
739 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
740 	return (rc);
741 }
742 
743 	__checkReturn			efx_rc_t
744 efx_mae_match_spec_mport_set(
745 	__in				efx_mae_match_spec_t *spec,
746 	__in				const efx_mport_sel_t *valuep,
747 	__in_opt			const efx_mport_sel_t *maskp)
748 {
749 	uint32_t full_mask = UINT32_MAX;
750 	const uint8_t *vp;
751 	const uint8_t *mp;
752 	efx_rc_t rc;
753 
754 	if (valuep == NULL) {
755 		rc = EINVAL;
756 		goto fail1;
757 	}
758 
759 	vp = (const uint8_t *)&valuep->sel;
760 	if (maskp != NULL)
761 		mp = (const uint8_t *)&maskp->sel;
762 	else
763 		mp = (const uint8_t *)&full_mask;
764 
765 	rc = efx_mae_match_spec_field_set(spec,
766 	    EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR,
767 	    sizeof (valuep->sel), vp, sizeof (maskp->sel), mp);
768 	if (rc != 0)
769 		goto fail2;
770 
771 	return (0);
772 
773 fail2:
774 	EFSYS_PROBE(fail2);
775 fail1:
776 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
777 	return (rc);
778 }
779 
780 	__checkReturn			boolean_t
781 efx_mae_match_specs_equal(
782 	__in				const efx_mae_match_spec_t *left,
783 	__in				const efx_mae_match_spec_t *right)
784 {
785 	return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
786 }
787 
788 #define	EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit)		\
789 	    ((_mask)[(_bit) / (_mask_page_nbits)] &			\
790 		    (1ULL << ((_bit) & ((_mask_page_nbits) - 1))))
791 
792 static					boolean_t
793 efx_mask_is_prefix(
794 	__in				size_t mask_nbytes,
795 	__in_bcount(mask_nbytes)	const uint8_t *maskp)
796 {
797 	boolean_t prev_bit_is_set = B_TRUE;
798 	unsigned int i;
799 
800 	for (i = 0; i < 8 * mask_nbytes; ++i) {
801 		boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i);
802 
803 		if (!prev_bit_is_set && bit_is_set)
804 			return B_FALSE;
805 
806 		prev_bit_is_set = bit_is_set;
807 	}
808 
809 	return B_TRUE;
810 }
811 
812 static					boolean_t
813 efx_mask_is_all_ones(
814 	__in				size_t mask_nbytes,
815 	__in_bcount(mask_nbytes)	const uint8_t *maskp)
816 {
817 	unsigned int i;
818 	uint8_t t = ~0;
819 
820 	for (i = 0; i < mask_nbytes; ++i)
821 		t &= maskp[i];
822 
823 	return (t == (uint8_t)(~0));
824 }
825 
826 static					boolean_t
827 efx_mask_is_all_zeros(
828 	__in				size_t mask_nbytes,
829 	__in_bcount(mask_nbytes)	const uint8_t *maskp)
830 {
831 	unsigned int i;
832 	uint8_t t = 0;
833 
834 	for (i = 0; i < mask_nbytes; ++i)
835 		t |= maskp[i];
836 
837 	return (t == 0);
838 }
839 
840 	__checkReturn			boolean_t
841 efx_mae_match_spec_is_valid(
842 	__in				efx_nic_t *enp,
843 	__in				const efx_mae_match_spec_t *spec)
844 {
845 	efx_mae_t *maep = enp->en_maep;
846 	unsigned int field_ncaps = maep->em_max_nfields;
847 	const efx_mae_field_cap_t *field_caps;
848 	const efx_mae_mv_desc_t *desc_setp;
849 	unsigned int desc_set_nentries;
850 	boolean_t is_valid = B_TRUE;
851 	efx_mae_field_id_t field_id;
852 	const uint8_t *mvp;
853 
854 	switch (spec->emms_type) {
855 	case EFX_MAE_RULE_OUTER:
856 		field_caps = maep->em_outer_rule_field_caps;
857 		desc_setp = __efx_mae_outer_rule_mv_desc_set;
858 		desc_set_nentries =
859 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
860 		mvp = spec->emms_mask_value_pairs.outer;
861 		break;
862 	case EFX_MAE_RULE_ACTION:
863 		field_caps = maep->em_action_rule_field_caps;
864 		desc_setp = __efx_mae_action_rule_mv_desc_set;
865 		desc_set_nentries =
866 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
867 		mvp = spec->emms_mask_value_pairs.action;
868 		break;
869 	default:
870 		return (B_FALSE);
871 	}
872 
873 	if (field_caps == NULL)
874 		return (B_FALSE);
875 
876 	for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
877 	     ++field_id) {
878 		const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
879 		efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
880 		const uint8_t *alt_m_buf = mvp + descp->emmd_alt_mask_offset;
881 		const uint8_t *m_buf = mvp + descp->emmd_mask_offset;
882 		size_t alt_m_size = descp->emmd_alt_mask_size;
883 		size_t m_size = descp->emmd_mask_size;
884 
885 		if (m_size == 0)
886 			continue; /* Skip array gap */
887 
888 		if ((unsigned int)field_cap_id >= field_ncaps)
889 			break;
890 
891 		switch (field_caps[field_cap_id].emfc_support) {
892 		case MAE_FIELD_SUPPORTED_MATCH_MASK:
893 			is_valid = B_TRUE;
894 			break;
895 		case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
896 			is_valid = efx_mask_is_prefix(m_size, m_buf);
897 			break;
898 		case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
899 			is_valid = (efx_mask_is_all_ones(m_size, m_buf) ||
900 			    efx_mask_is_all_zeros(m_size, m_buf));
901 			break;
902 		case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
903 			is_valid = efx_mask_is_all_ones(m_size, m_buf);
904 
905 			if ((is_valid == B_FALSE) && (alt_m_size != 0)) {
906 				/*
907 				 * This field has an alternative one. The FW
908 				 * reports ALWAYS for both implying that one
909 				 * of them is required to have all-ones mask.
910 				 *
911 				 * The primary field's mask is incorrect; go
912 				 * on to check that of the alternative field.
913 				 */
914 				is_valid = efx_mask_is_all_ones(alt_m_size,
915 								alt_m_buf);
916 			}
917 			break;
918 		case MAE_FIELD_SUPPORTED_MATCH_NEVER:
919 		case MAE_FIELD_UNSUPPORTED:
920 		default:
921 			is_valid = efx_mask_is_all_zeros(m_size, m_buf);
922 			break;
923 		}
924 
925 		if (is_valid == B_FALSE)
926 			break;
927 	}
928 
929 	return (is_valid);
930 }
931 
932 	__checkReturn			efx_rc_t
933 efx_mae_action_set_spec_init(
934 	__in				efx_nic_t *enp,
935 	__out				efx_mae_actions_t **specp)
936 {
937 	efx_mae_actions_t *spec;
938 	efx_rc_t rc;
939 
940 	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
941 	if (spec == NULL) {
942 		rc = ENOMEM;
943 		goto fail1;
944 	}
945 
946 	*specp = spec;
947 
948 	return (0);
949 
950 fail1:
951 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
952 	return (rc);
953 }
954 
955 					void
956 efx_mae_action_set_spec_fini(
957 	__in				efx_nic_t *enp,
958 	__in				efx_mae_actions_t *spec)
959 {
960 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
961 }
962 
963 static	__checkReturn			efx_rc_t
964 efx_mae_action_set_add_vlan_pop(
965 	__in				efx_mae_actions_t *spec,
966 	__in				size_t arg_size,
967 	__in_bcount(arg_size)		const uint8_t *arg)
968 {
969 	efx_rc_t rc;
970 
971 	if (arg_size != 0) {
972 		rc = EINVAL;
973 		goto fail1;
974 	}
975 
976 	if (arg != NULL) {
977 		rc = EINVAL;
978 		goto fail2;
979 	}
980 
981 	if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) {
982 		rc = ENOTSUP;
983 		goto fail3;
984 	}
985 
986 	++spec->ema_n_vlan_tags_to_pop;
987 
988 	return (0);
989 
990 fail3:
991 	EFSYS_PROBE(fail3);
992 fail2:
993 	EFSYS_PROBE(fail2);
994 fail1:
995 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
996 	return (rc);
997 }
998 
999 static	__checkReturn			efx_rc_t
1000 efx_mae_action_set_add_vlan_push(
1001 	__in				efx_mae_actions_t *spec,
1002 	__in				size_t arg_size,
1003 	__in_bcount(arg_size)		const uint8_t *arg)
1004 {
1005 	unsigned int n_tags = spec->ema_n_vlan_tags_to_push;
1006 	efx_rc_t rc;
1007 
1008 	if (arg_size != sizeof (*spec->ema_vlan_push_descs)) {
1009 		rc = EINVAL;
1010 		goto fail1;
1011 	}
1012 
1013 	if (arg == NULL) {
1014 		rc = EINVAL;
1015 		goto fail2;
1016 	}
1017 
1018 	if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1019 		rc = ENOTSUP;
1020 		goto fail3;
1021 	}
1022 
1023 	memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size);
1024 	++(spec->ema_n_vlan_tags_to_push);
1025 
1026 	return (0);
1027 
1028 fail3:
1029 	EFSYS_PROBE(fail3);
1030 fail2:
1031 	EFSYS_PROBE(fail2);
1032 fail1:
1033 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1034 	return (rc);
1035 }
1036 
1037 static	__checkReturn			efx_rc_t
1038 efx_mae_action_set_add_flag(
1039 	__in				efx_mae_actions_t *spec,
1040 	__in				size_t arg_size,
1041 	__in_bcount(arg_size)		const uint8_t *arg)
1042 {
1043 	efx_rc_t rc;
1044 
1045 	_NOTE(ARGUNUSED(spec))
1046 
1047 	if (arg_size != 0) {
1048 		rc = EINVAL;
1049 		goto fail1;
1050 	}
1051 
1052 	if (arg != NULL) {
1053 		rc = EINVAL;
1054 		goto fail2;
1055 	}
1056 
1057 	/* This action does not have any arguments, so do nothing here. */
1058 
1059 	return (0);
1060 
1061 fail2:
1062 	EFSYS_PROBE(fail2);
1063 fail1:
1064 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1065 	return (rc);
1066 }
1067 
1068 static	__checkReturn			efx_rc_t
1069 efx_mae_action_set_add_mark(
1070 	__in				efx_mae_actions_t *spec,
1071 	__in				size_t arg_size,
1072 	__in_bcount(arg_size)		const uint8_t *arg)
1073 {
1074 	efx_rc_t rc;
1075 
1076 	if (arg_size != sizeof (spec->ema_mark_value)) {
1077 		rc = EINVAL;
1078 		goto fail1;
1079 	}
1080 
1081 	if (arg == NULL) {
1082 		rc = EINVAL;
1083 		goto fail2;
1084 	}
1085 
1086 	memcpy(&spec->ema_mark_value, arg, arg_size);
1087 
1088 	return (0);
1089 
1090 fail2:
1091 	EFSYS_PROBE(fail2);
1092 fail1:
1093 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1094 	return (rc);
1095 }
1096 
1097 static	__checkReturn			efx_rc_t
1098 efx_mae_action_set_add_deliver(
1099 	__in				efx_mae_actions_t *spec,
1100 	__in				size_t arg_size,
1101 	__in_bcount(arg_size)		const uint8_t *arg)
1102 {
1103 	efx_rc_t rc;
1104 
1105 	if (arg_size != sizeof (spec->ema_deliver_mport)) {
1106 		rc = EINVAL;
1107 		goto fail1;
1108 	}
1109 
1110 	if (arg == NULL) {
1111 		rc = EINVAL;
1112 		goto fail2;
1113 	}
1114 
1115 	memcpy(&spec->ema_deliver_mport, arg, arg_size);
1116 
1117 	return (0);
1118 
1119 fail2:
1120 	EFSYS_PROBE(fail2);
1121 fail1:
1122 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1123 	return (rc);
1124 }
1125 
1126 typedef struct efx_mae_action_desc_s {
1127 	/* Action specific handler */
1128 	efx_rc_t	(*emad_add)(efx_mae_actions_t *,
1129 				    size_t, const uint8_t *);
1130 } efx_mae_action_desc_t;
1131 
1132 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
1133 	[EFX_MAE_ACTION_VLAN_POP] = {
1134 		.emad_add = efx_mae_action_set_add_vlan_pop
1135 	},
1136 	[EFX_MAE_ACTION_VLAN_PUSH] = {
1137 		.emad_add = efx_mae_action_set_add_vlan_push
1138 	},
1139 	[EFX_MAE_ACTION_FLAG] = {
1140 		.emad_add = efx_mae_action_set_add_flag
1141 	},
1142 	[EFX_MAE_ACTION_MARK] = {
1143 		.emad_add = efx_mae_action_set_add_mark
1144 	},
1145 	[EFX_MAE_ACTION_DELIVER] = {
1146 		.emad_add = efx_mae_action_set_add_deliver
1147 	}
1148 };
1149 
1150 static const uint32_t efx_mae_action_ordered_map =
1151 	(1U << EFX_MAE_ACTION_VLAN_POP) |
1152 	(1U << EFX_MAE_ACTION_VLAN_PUSH) |
1153 	(1U << EFX_MAE_ACTION_FLAG) |
1154 	(1U << EFX_MAE_ACTION_MARK) |
1155 	(1U << EFX_MAE_ACTION_DELIVER);
1156 
1157 /*
1158  * These actions must not be added after DELIVER, but
1159  * they can have any place among the rest of
1160  * strictly ordered actions.
1161  */
1162 static const uint32_t efx_mae_action_nonstrict_map =
1163 	(1U << EFX_MAE_ACTION_FLAG) |
1164 	(1U << EFX_MAE_ACTION_MARK);
1165 
1166 static const uint32_t efx_mae_action_repeat_map =
1167 	(1U << EFX_MAE_ACTION_VLAN_POP) |
1168 	(1U << EFX_MAE_ACTION_VLAN_PUSH);
1169 
1170 /*
1171  * Add an action to an action set.
1172  *
1173  * This has to be invoked in the desired action order.
1174  * An out-of-order action request will be turned down.
1175  */
1176 static	__checkReturn			efx_rc_t
1177 efx_mae_action_set_spec_populate(
1178 	__in				efx_mae_actions_t *spec,
1179 	__in				efx_mae_action_t type,
1180 	__in				size_t arg_size,
1181 	__in_bcount(arg_size)		const uint8_t *arg)
1182 {
1183 	uint32_t action_mask;
1184 	efx_rc_t rc;
1185 
1186 	EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1187 	    (sizeof (efx_mae_action_ordered_map) * 8));
1188 	EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1189 	    (sizeof (efx_mae_action_repeat_map) * 8));
1190 
1191 	EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
1192 	EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK);
1193 	EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER);
1194 
1195 	if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
1196 		rc = EINVAL;
1197 		goto fail1;
1198 	}
1199 
1200 	action_mask = (1U << type);
1201 
1202 	if ((spec->ema_actions & action_mask) != 0) {
1203 		/* The action set already contains this action. */
1204 		if ((efx_mae_action_repeat_map & action_mask) == 0) {
1205 			/* Cannot add another non-repeatable action. */
1206 			rc = ENOTSUP;
1207 			goto fail2;
1208 		}
1209 	}
1210 
1211 	if ((efx_mae_action_ordered_map & action_mask) != 0) {
1212 		uint32_t strict_ordered_map =
1213 		    efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map;
1214 		uint32_t later_actions_mask =
1215 		    strict_ordered_map & ~(action_mask | (action_mask - 1));
1216 
1217 		if ((spec->ema_actions & later_actions_mask) != 0) {
1218 			/* Cannot add an action after later ordered actions. */
1219 			rc = ENOTSUP;
1220 			goto fail3;
1221 		}
1222 	}
1223 
1224 	if (efx_mae_actions[type].emad_add != NULL) {
1225 		rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
1226 		if (rc != 0)
1227 			goto fail4;
1228 	}
1229 
1230 	spec->ema_actions |= action_mask;
1231 
1232 	return (0);
1233 
1234 fail4:
1235 	EFSYS_PROBE(fail4);
1236 fail3:
1237 	EFSYS_PROBE(fail3);
1238 fail2:
1239 	EFSYS_PROBE(fail2);
1240 fail1:
1241 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1242 	return (rc);
1243 }
1244 
1245 	__checkReturn			efx_rc_t
1246 efx_mae_action_set_populate_vlan_pop(
1247 	__in				efx_mae_actions_t *spec)
1248 {
1249 	return (efx_mae_action_set_spec_populate(spec,
1250 	    EFX_MAE_ACTION_VLAN_POP, 0, NULL));
1251 }
1252 
1253 	__checkReturn			efx_rc_t
1254 efx_mae_action_set_populate_vlan_push(
1255 	__in				efx_mae_actions_t *spec,
1256 	__in				uint16_t tpid_be,
1257 	__in				uint16_t tci_be)
1258 {
1259 	efx_mae_action_vlan_push_t action;
1260 	const uint8_t *arg = (const uint8_t *)&action;
1261 
1262 	action.emavp_tpid_be = tpid_be;
1263 	action.emavp_tci_be = tci_be;
1264 
1265 	return (efx_mae_action_set_spec_populate(spec,
1266 	    EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg));
1267 }
1268 
1269 	__checkReturn			efx_rc_t
1270 efx_mae_action_set_populate_flag(
1271 	__in				efx_mae_actions_t *spec)
1272 {
1273 	return (efx_mae_action_set_spec_populate(spec,
1274 	    EFX_MAE_ACTION_FLAG, 0, NULL));
1275 }
1276 
1277 	__checkReturn			efx_rc_t
1278 efx_mae_action_set_populate_mark(
1279 	__in				efx_mae_actions_t *spec,
1280 	__in				uint32_t mark_value)
1281 {
1282 	const uint8_t *arg = (const uint8_t *)&mark_value;
1283 
1284 	return (efx_mae_action_set_spec_populate(spec,
1285 	    EFX_MAE_ACTION_MARK, sizeof (mark_value), arg));
1286 }
1287 
1288 	__checkReturn			efx_rc_t
1289 efx_mae_action_set_populate_deliver(
1290 	__in				efx_mae_actions_t *spec,
1291 	__in				const efx_mport_sel_t *mportp)
1292 {
1293 	const uint8_t *arg;
1294 	efx_rc_t rc;
1295 
1296 	if (mportp == NULL) {
1297 		rc = EINVAL;
1298 		goto fail1;
1299 	}
1300 
1301 	arg = (const uint8_t *)&mportp->sel;
1302 
1303 	return (efx_mae_action_set_spec_populate(spec,
1304 	    EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
1305 
1306 fail1:
1307 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1308 	return (rc);
1309 }
1310 
1311 	__checkReturn			efx_rc_t
1312 efx_mae_action_set_populate_drop(
1313 	__in				efx_mae_actions_t *spec)
1314 {
1315 	efx_mport_sel_t mport;
1316 	const uint8_t *arg;
1317 	efx_dword_t dword;
1318 
1319 	EFX_POPULATE_DWORD_1(dword,
1320 	    MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL);
1321 
1322 	mport.sel = dword.ed_u32[0];
1323 
1324 	arg = (const uint8_t *)&mport.sel;
1325 
1326 	return (efx_mae_action_set_spec_populate(spec,
1327 	    EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg));
1328 }
1329 
1330 	__checkReturn			boolean_t
1331 efx_mae_action_set_specs_equal(
1332 	__in				const efx_mae_actions_t *left,
1333 	__in				const efx_mae_actions_t *right)
1334 {
1335 	return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
1336 }
1337 
1338 	__checkReturn			efx_rc_t
1339 efx_mae_match_specs_class_cmp(
1340 	__in				efx_nic_t *enp,
1341 	__in				const efx_mae_match_spec_t *left,
1342 	__in				const efx_mae_match_spec_t *right,
1343 	__out				boolean_t *have_same_classp)
1344 {
1345 	efx_mae_t *maep = enp->en_maep;
1346 	unsigned int field_ncaps = maep->em_max_nfields;
1347 	const efx_mae_field_cap_t *field_caps;
1348 	const efx_mae_mv_desc_t *desc_setp;
1349 	unsigned int desc_set_nentries;
1350 	boolean_t have_same_class = B_TRUE;
1351 	efx_mae_field_id_t field_id;
1352 	const uint8_t *mvpl;
1353 	const uint8_t *mvpr;
1354 	efx_rc_t rc;
1355 
1356 	switch (left->emms_type) {
1357 	case EFX_MAE_RULE_OUTER:
1358 		field_caps = maep->em_outer_rule_field_caps;
1359 		desc_setp = __efx_mae_outer_rule_mv_desc_set;
1360 		desc_set_nentries =
1361 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1362 		mvpl = left->emms_mask_value_pairs.outer;
1363 		mvpr = right->emms_mask_value_pairs.outer;
1364 		break;
1365 	case EFX_MAE_RULE_ACTION:
1366 		field_caps = maep->em_action_rule_field_caps;
1367 		desc_setp = __efx_mae_action_rule_mv_desc_set;
1368 		desc_set_nentries =
1369 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1370 		mvpl = left->emms_mask_value_pairs.action;
1371 		mvpr = right->emms_mask_value_pairs.action;
1372 		break;
1373 	default:
1374 		rc = ENOTSUP;
1375 		goto fail1;
1376 	}
1377 
1378 	if (field_caps == NULL) {
1379 		rc = EAGAIN;
1380 		goto fail2;
1381 	}
1382 
1383 	if (left->emms_type != right->emms_type ||
1384 	    left->emms_prio != right->emms_prio) {
1385 		/*
1386 		 * Rules of different types can never map to the same class.
1387 		 *
1388 		 * The FW can support some set of match criteria for one
1389 		 * priority and not support the very same set for
1390 		 * another priority. Thus, two rules which have
1391 		 * different priorities can never map to
1392 		 * the same class.
1393 		 */
1394 		*have_same_classp = B_FALSE;
1395 		return (0);
1396 	}
1397 
1398 	for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1399 	     ++field_id) {
1400 		const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1401 		efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1402 
1403 		if (descp->emmd_mask_size == 0)
1404 			continue; /* Skip array gap */
1405 
1406 		if ((unsigned int)field_cap_id >= field_ncaps)
1407 			break;
1408 
1409 		if (field_caps[field_cap_id].emfc_mask_affects_class) {
1410 			const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
1411 			const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
1412 			size_t mask_size = descp->emmd_mask_size;
1413 
1414 			if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
1415 				have_same_class = B_FALSE;
1416 				break;
1417 			}
1418 		}
1419 
1420 		if (field_caps[field_cap_id].emfc_match_affects_class) {
1421 			const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
1422 			const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
1423 			size_t value_size = descp->emmd_value_size;
1424 
1425 			if (memcmp(lvalp, rvalp, value_size) != 0) {
1426 				have_same_class = B_FALSE;
1427 				break;
1428 			}
1429 		}
1430 	}
1431 
1432 	*have_same_classp = have_same_class;
1433 
1434 	return (0);
1435 
1436 fail2:
1437 	EFSYS_PROBE(fail2);
1438 fail1:
1439 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1440 	return (rc);
1441 }
1442 
1443 	__checkReturn		efx_rc_t
1444 efx_mae_outer_rule_insert(
1445 	__in			efx_nic_t *enp,
1446 	__in			const efx_mae_match_spec_t *spec,
1447 	__in			efx_tunnel_protocol_t encap_type,
1448 	__out			efx_mae_rule_id_t *or_idp)
1449 {
1450 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1451 	efx_mcdi_req_t req;
1452 	EFX_MCDI_DECLARE_BUF(payload,
1453 	    MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2,
1454 	    MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
1455 	uint32_t encap_type_mcdi;
1456 	efx_mae_rule_id_t or_id;
1457 	size_t offset;
1458 	efx_rc_t rc;
1459 
1460 	EFX_STATIC_ASSERT(sizeof (or_idp->id) ==
1461 	    MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN);
1462 
1463 	EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1464 	    MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL);
1465 
1466 	if (encp->enc_mae_supported == B_FALSE) {
1467 		rc = ENOTSUP;
1468 		goto fail1;
1469 	}
1470 
1471 	if (spec->emms_type != EFX_MAE_RULE_OUTER) {
1472 		rc = EINVAL;
1473 		goto fail2;
1474 	}
1475 
1476 	switch (encap_type) {
1477 	case EFX_TUNNEL_PROTOCOL_NONE:
1478 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
1479 		break;
1480 	case EFX_TUNNEL_PROTOCOL_VXLAN:
1481 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
1482 		break;
1483 	case EFX_TUNNEL_PROTOCOL_GENEVE:
1484 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
1485 		break;
1486 	case EFX_TUNNEL_PROTOCOL_NVGRE:
1487 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
1488 		break;
1489 	default:
1490 		rc = ENOTSUP;
1491 		goto fail3;
1492 	}
1493 
1494 	req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT;
1495 	req.emr_in_buf = payload;
1496 	req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2;
1497 	req.emr_out_buf = payload;
1498 	req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN;
1499 
1500 	MCDI_IN_SET_DWORD(req,
1501 	    MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi);
1502 
1503 	MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio);
1504 
1505 	/*
1506 	 * Mask-value pairs have been stored in the byte order needed for the
1507 	 * MCDI request and are thus safe to be copied directly to the buffer.
1508 	 * The library cares about byte order in efx_mae_match_spec_field_set().
1509 	 */
1510 	EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >=
1511 	    MAE_ENC_FIELD_PAIRS_LEN);
1512 	offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST;
1513 	memcpy(payload + offset, spec->emms_mask_value_pairs.outer,
1514 	    MAE_ENC_FIELD_PAIRS_LEN);
1515 
1516 	efx_mcdi_execute(enp, &req);
1517 
1518 	if (req.emr_rc != 0) {
1519 		rc = req.emr_rc;
1520 		goto fail4;
1521 	}
1522 
1523 	if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) {
1524 		rc = EMSGSIZE;
1525 		goto fail5;
1526 	}
1527 
1528 	or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
1529 	if (or_id.id == EFX_MAE_RSRC_ID_INVALID) {
1530 		rc = ENOENT;
1531 		goto fail6;
1532 	}
1533 
1534 	or_idp->id = or_id.id;
1535 
1536 	return (0);
1537 
1538 fail6:
1539 	EFSYS_PROBE(fail6);
1540 fail5:
1541 	EFSYS_PROBE(fail5);
1542 fail4:
1543 	EFSYS_PROBE(fail4);
1544 fail3:
1545 	EFSYS_PROBE(fail3);
1546 fail2:
1547 	EFSYS_PROBE(fail2);
1548 fail1:
1549 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1550 	return (rc);
1551 }
1552 
1553 	__checkReturn		efx_rc_t
1554 efx_mae_outer_rule_remove(
1555 	__in			efx_nic_t *enp,
1556 	__in			const efx_mae_rule_id_t *or_idp)
1557 {
1558 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1559 	efx_mcdi_req_t req;
1560 	EFX_MCDI_DECLARE_BUF(payload,
1561 	    MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1),
1562 	    MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
1563 	efx_rc_t rc;
1564 
1565 	if (encp->enc_mae_supported == B_FALSE) {
1566 		rc = ENOTSUP;
1567 		goto fail1;
1568 	}
1569 
1570 	req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE;
1571 	req.emr_in_buf = payload;
1572 	req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1);
1573 	req.emr_out_buf = payload;
1574 	req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1);
1575 
1576 	MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id);
1577 
1578 	efx_mcdi_execute(enp, &req);
1579 
1580 	if (req.emr_rc != 0) {
1581 		rc = req.emr_rc;
1582 		goto fail2;
1583 	}
1584 
1585 	if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) !=
1586 	    or_idp->id) {
1587 		/* Firmware failed to remove the outer rule. */
1588 		rc = EAGAIN;
1589 		goto fail3;
1590 	}
1591 
1592 	return (0);
1593 
1594 fail3:
1595 	EFSYS_PROBE(fail3);
1596 fail2:
1597 	EFSYS_PROBE(fail2);
1598 fail1:
1599 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1600 	return (rc);
1601 }
1602 
1603 	__checkReturn			efx_rc_t
1604 efx_mae_match_spec_outer_rule_id_set(
1605 	__in				efx_mae_match_spec_t *spec,
1606 	__in				const efx_mae_rule_id_t *or_idp)
1607 {
1608 	uint32_t full_mask = UINT32_MAX;
1609 	efx_rc_t rc;
1610 
1611 	if (spec->emms_type != EFX_MAE_RULE_ACTION) {
1612 		rc = EINVAL;
1613 		goto fail1;
1614 	}
1615 
1616 	if (or_idp == NULL) {
1617 		rc = EINVAL;
1618 		goto fail2;
1619 	}
1620 
1621 	rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID,
1622 	    sizeof (or_idp->id), (const uint8_t *)&or_idp->id,
1623 	    sizeof (full_mask), (const uint8_t *)&full_mask);
1624 	if (rc != 0)
1625 		goto fail3;
1626 
1627 	return (0);
1628 
1629 fail3:
1630 	EFSYS_PROBE(fail3);
1631 fail2:
1632 	EFSYS_PROBE(fail2);
1633 fail1:
1634 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1635 	return (rc);
1636 }
1637 
1638 	__checkReturn			efx_rc_t
1639 efx_mae_action_set_alloc(
1640 	__in				efx_nic_t *enp,
1641 	__in				const efx_mae_actions_t *spec,
1642 	__out				efx_mae_aset_id_t *aset_idp)
1643 {
1644 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1645 	efx_mcdi_req_t req;
1646 	EFX_MCDI_DECLARE_BUF(payload,
1647 	    MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
1648 	    MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
1649 	efx_mae_aset_id_t aset_id;
1650 	efx_rc_t rc;
1651 
1652 	if (encp->enc_mae_supported == B_FALSE) {
1653 		rc = ENOTSUP;
1654 		goto fail1;
1655 	}
1656 
1657 	req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
1658 	req.emr_in_buf = payload;
1659 	req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
1660 	req.emr_out_buf = payload;
1661 	req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
1662 
1663 	/*
1664 	 * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
1665 	 * corresponding resource types are supported by the implementation.
1666 	 * Use proper resource ID assignments instead.
1667 	 */
1668 	MCDI_IN_SET_DWORD(req,
1669 	    MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
1670 	MCDI_IN_SET_DWORD(req,
1671 	    MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
1672 	MCDI_IN_SET_DWORD(req,
1673 	    MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, EFX_MAE_RSRC_ID_INVALID);
1674 
1675 	MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1676 	    MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
1677 
1678 	if (spec->ema_n_vlan_tags_to_push > 0) {
1679 		unsigned int outer_tag_idx;
1680 
1681 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1682 		    MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
1683 		    spec->ema_n_vlan_tags_to_push);
1684 
1685 		if (spec->ema_n_vlan_tags_to_push ==
1686 		    EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1687 			MCDI_IN_SET_WORD(req,
1688 			    MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
1689 			    spec->ema_vlan_push_descs[0].emavp_tpid_be);
1690 			MCDI_IN_SET_WORD(req,
1691 			    MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
1692 			    spec->ema_vlan_push_descs[0].emavp_tci_be);
1693 		}
1694 
1695 		outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
1696 
1697 		MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
1698 		    spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
1699 		MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
1700 		    spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
1701 	}
1702 
1703 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
1704 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1705 		    MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
1706 	}
1707 
1708 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
1709 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1710 		    MAE_ACTION_SET_ALLOC_IN_MARK, 1);
1711 
1712 		MCDI_IN_SET_DWORD(req,
1713 		    MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
1714 	}
1715 
1716 	MCDI_IN_SET_DWORD(req,
1717 	    MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
1718 
1719 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
1720 	    MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
1721 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
1722 	    MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
1723 
1724 	efx_mcdi_execute(enp, &req);
1725 
1726 	if (req.emr_rc != 0) {
1727 		rc = req.emr_rc;
1728 		goto fail2;
1729 	}
1730 
1731 	if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
1732 		rc = EMSGSIZE;
1733 		goto fail3;
1734 	}
1735 
1736 	aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
1737 	if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
1738 		rc = ENOENT;
1739 		goto fail4;
1740 	}
1741 
1742 	aset_idp->id = aset_id.id;
1743 
1744 	return (0);
1745 
1746 fail4:
1747 	EFSYS_PROBE(fail4);
1748 fail3:
1749 	EFSYS_PROBE(fail3);
1750 fail2:
1751 	EFSYS_PROBE(fail2);
1752 fail1:
1753 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1754 	return (rc);
1755 }
1756 
1757 	__checkReturn			efx_rc_t
1758 efx_mae_action_set_free(
1759 	__in				efx_nic_t *enp,
1760 	__in				const efx_mae_aset_id_t *aset_idp)
1761 {
1762 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1763 	efx_mcdi_req_t req;
1764 	EFX_MCDI_DECLARE_BUF(payload,
1765 	    MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
1766 	    MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
1767 	efx_rc_t rc;
1768 
1769 	if (encp->enc_mae_supported == B_FALSE) {
1770 		rc = ENOTSUP;
1771 		goto fail1;
1772 	}
1773 
1774 	req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
1775 	req.emr_in_buf = payload;
1776 	req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
1777 	req.emr_out_buf = payload;
1778 	req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
1779 
1780 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
1781 
1782 	efx_mcdi_execute(enp, &req);
1783 
1784 	if (req.emr_rc != 0) {
1785 		rc = req.emr_rc;
1786 		goto fail2;
1787 	}
1788 
1789 	if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
1790 	    aset_idp->id) {
1791 		/* Firmware failed to free the action set. */
1792 		rc = EAGAIN;
1793 		goto fail3;
1794 	}
1795 
1796 	return (0);
1797 
1798 fail3:
1799 	EFSYS_PROBE(fail3);
1800 fail2:
1801 	EFSYS_PROBE(fail2);
1802 fail1:
1803 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1804 	return (rc);
1805 }
1806 
1807 	__checkReturn			efx_rc_t
1808 efx_mae_action_rule_insert(
1809 	__in				efx_nic_t *enp,
1810 	__in				const efx_mae_match_spec_t *spec,
1811 	__in				const efx_mae_aset_list_id_t *asl_idp,
1812 	__in				const efx_mae_aset_id_t *as_idp,
1813 	__out				efx_mae_rule_id_t *ar_idp)
1814 {
1815 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1816 	efx_mcdi_req_t req;
1817 	EFX_MCDI_DECLARE_BUF(payload,
1818 	    MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2,
1819 	    MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
1820 	efx_oword_t *rule_response;
1821 	efx_mae_rule_id_t ar_id;
1822 	size_t offset;
1823 	efx_rc_t rc;
1824 
1825 	EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
1826 	    MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
1827 
1828 	EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1829 	    MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
1830 
1831 	if (encp->enc_mae_supported == B_FALSE) {
1832 		rc = ENOTSUP;
1833 		goto fail1;
1834 	}
1835 
1836 	if (spec->emms_type != EFX_MAE_RULE_ACTION ||
1837 	    (asl_idp != NULL && as_idp != NULL) ||
1838 	    (asl_idp == NULL && as_idp == NULL)) {
1839 		rc = EINVAL;
1840 		goto fail2;
1841 	}
1842 
1843 	req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
1844 	req.emr_in_buf = payload;
1845 	req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
1846 	req.emr_out_buf = payload;
1847 	req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
1848 
1849 	EFX_STATIC_ASSERT(sizeof (*rule_response) <=
1850 	    MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
1851 	offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
1852 	rule_response = (efx_oword_t *)(payload + offset);
1853 	EFX_POPULATE_OWORD_3(*rule_response,
1854 	    MAE_ACTION_RULE_RESPONSE_ASL_ID,
1855 	    (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
1856 	    MAE_ACTION_RULE_RESPONSE_AS_ID,
1857 	    (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
1858 	    MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
1859 
1860 	MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
1861 
1862 	/*
1863 	 * Mask-value pairs have been stored in the byte order needed for the
1864 	 * MCDI request and are thus safe to be copied directly to the buffer.
1865 	 */
1866 	EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
1867 	    MAE_FIELD_MASK_VALUE_PAIRS_LEN);
1868 	offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
1869 	memcpy(payload + offset, spec->emms_mask_value_pairs.action,
1870 	    MAE_FIELD_MASK_VALUE_PAIRS_LEN);
1871 
1872 	efx_mcdi_execute(enp, &req);
1873 
1874 	if (req.emr_rc != 0) {
1875 		rc = req.emr_rc;
1876 		goto fail3;
1877 	}
1878 
1879 	if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
1880 		rc = EMSGSIZE;
1881 		goto fail4;
1882 	}
1883 
1884 	ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
1885 	if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
1886 		rc = ENOENT;
1887 		goto fail5;
1888 	}
1889 
1890 	ar_idp->id = ar_id.id;
1891 
1892 	return (0);
1893 
1894 fail5:
1895 	EFSYS_PROBE(fail5);
1896 fail4:
1897 	EFSYS_PROBE(fail4);
1898 fail3:
1899 	EFSYS_PROBE(fail3);
1900 fail2:
1901 	EFSYS_PROBE(fail2);
1902 fail1:
1903 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1904 	return (rc);
1905 }
1906 
1907 	__checkReturn			efx_rc_t
1908 efx_mae_action_rule_remove(
1909 	__in				efx_nic_t *enp,
1910 	__in				const efx_mae_rule_id_t *ar_idp)
1911 {
1912 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1913 	efx_mcdi_req_t req;
1914 	EFX_MCDI_DECLARE_BUF(payload,
1915 	    MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
1916 	    MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
1917 	efx_rc_t rc;
1918 
1919 	if (encp->enc_mae_supported == B_FALSE) {
1920 		rc = ENOTSUP;
1921 		goto fail1;
1922 	}
1923 
1924 	req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
1925 	req.emr_in_buf = payload;
1926 	req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
1927 	req.emr_out_buf = payload;
1928 	req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
1929 
1930 	MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
1931 
1932 	efx_mcdi_execute(enp, &req);
1933 
1934 	if (req.emr_rc != 0) {
1935 		rc = req.emr_rc;
1936 		goto fail2;
1937 	}
1938 
1939 	if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
1940 	    ar_idp->id) {
1941 		/* Firmware failed to delete the action rule. */
1942 		rc = EAGAIN;
1943 		goto fail3;
1944 	}
1945 
1946 	return (0);
1947 
1948 fail3:
1949 	EFSYS_PROBE(fail3);
1950 fail2:
1951 	EFSYS_PROBE(fail2);
1952 fail1:
1953 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1954 	return (rc);
1955 }
1956 
1957 #endif /* EFSYS_OPT_MAE */
1958