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