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