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