common/sfc_efx/base: refine adding count action to set
[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_add_decap(
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_encap(
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         /*
1522          * Adding this specific action to an action set spec and setting encap.
1523          * header ID in the spec are two individual steps. This design allows
1524          * the client driver to avoid encap. header allocation when it simply
1525          * needs to check the order of actions submitted by user ("validate"),
1526          * without actually allocating an action set and inserting a rule.
1527          *
1528          * In order to fill in the encap. header ID, the caller is supposed to
1529          * invoke efx_mae_action_set_fill_in_eh_id(). If they do not do that,
1530          * efx_mae_action_set_alloc() invocation will throw an error.
1531          *
1532          * For now, no more work is supposed to be done.
1533          */
1534
1535         if (arg_size != 0) {
1536                 rc = EINVAL;
1537                 goto fail1;
1538         }
1539
1540         if (arg != NULL) {
1541                 rc = EINVAL;
1542                 goto fail2;
1543         }
1544
1545         return (0);
1546
1547 fail2:
1548         EFSYS_PROBE(fail2);
1549 fail1:
1550         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1551         return (rc);
1552 }
1553
1554 static  __checkReturn                   efx_rc_t
1555 efx_mae_action_set_add_count(
1556         __in                            efx_mae_actions_t *spec,
1557         __in                            size_t arg_size,
1558         __in_bcount(arg_size)           const uint8_t *arg)
1559 {
1560         efx_rc_t rc;
1561
1562         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1563                           MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL);
1564
1565         /*
1566          * Preparing an action set spec to update a counter requires
1567          * two steps: first add this action to the action spec, and then
1568          * add the counter ID to the spec. This allows validity checking
1569          * and resource allocation to be done separately.
1570          *
1571          * In order to fill in the counter ID, the caller is supposed to invoke
1572          * efx_mae_action_set_fill_in_counter_id(). If they do not do that,
1573          * efx_mae_action_set_alloc() invocation will throw an error.
1574          *
1575          * For now, no arguments are supposed to be handled.
1576          */
1577
1578         if (arg_size != 0) {
1579                 rc = EINVAL;
1580                 goto fail1;
1581         }
1582
1583         if (arg != NULL) {
1584                 rc = EINVAL;
1585                 goto fail2;
1586         }
1587
1588         ++(spec->ema_n_count_actions);
1589
1590         return (0);
1591
1592 fail2:
1593         EFSYS_PROBE(fail2);
1594 fail1:
1595         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1596         return (rc);
1597 }
1598
1599 static  __checkReturn                   efx_rc_t
1600 efx_mae_action_set_add_flag(
1601         __in                            efx_mae_actions_t *spec,
1602         __in                            size_t arg_size,
1603         __in_bcount(arg_size)           const uint8_t *arg)
1604 {
1605         efx_rc_t rc;
1606
1607         _NOTE(ARGUNUSED(spec))
1608
1609         if (arg_size != 0) {
1610                 rc = EINVAL;
1611                 goto fail1;
1612         }
1613
1614         if (arg != NULL) {
1615                 rc = EINVAL;
1616                 goto fail2;
1617         }
1618
1619         /* This action does not have any arguments, so do nothing here. */
1620
1621         return (0);
1622
1623 fail2:
1624         EFSYS_PROBE(fail2);
1625 fail1:
1626         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1627         return (rc);
1628 }
1629
1630 static  __checkReturn                   efx_rc_t
1631 efx_mae_action_set_add_mark(
1632         __in                            efx_mae_actions_t *spec,
1633         __in                            size_t arg_size,
1634         __in_bcount(arg_size)           const uint8_t *arg)
1635 {
1636         efx_rc_t rc;
1637
1638         if (arg_size != sizeof (spec->ema_mark_value)) {
1639                 rc = EINVAL;
1640                 goto fail1;
1641         }
1642
1643         if (arg == NULL) {
1644                 rc = EINVAL;
1645                 goto fail2;
1646         }
1647
1648         memcpy(&spec->ema_mark_value, arg, arg_size);
1649
1650         return (0);
1651
1652 fail2:
1653         EFSYS_PROBE(fail2);
1654 fail1:
1655         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1656         return (rc);
1657 }
1658
1659 static  __checkReturn                   efx_rc_t
1660 efx_mae_action_set_add_deliver(
1661         __in                            efx_mae_actions_t *spec,
1662         __in                            size_t arg_size,
1663         __in_bcount(arg_size)           const uint8_t *arg)
1664 {
1665         efx_rc_t rc;
1666
1667         if (arg_size != sizeof (spec->ema_deliver_mport)) {
1668                 rc = EINVAL;
1669                 goto fail1;
1670         }
1671
1672         if (arg == NULL) {
1673                 rc = EINVAL;
1674                 goto fail2;
1675         }
1676
1677         memcpy(&spec->ema_deliver_mport, arg, arg_size);
1678
1679         return (0);
1680
1681 fail2:
1682         EFSYS_PROBE(fail2);
1683 fail1:
1684         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1685         return (rc);
1686 }
1687
1688 typedef struct efx_mae_action_desc_s {
1689         /* Action specific handler */
1690         efx_rc_t        (*emad_add)(efx_mae_actions_t *,
1691                                     size_t, const uint8_t *);
1692 } efx_mae_action_desc_t;
1693
1694 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
1695         [EFX_MAE_ACTION_DECAP] = {
1696                 .emad_add = efx_mae_action_set_add_decap
1697         },
1698         [EFX_MAE_ACTION_VLAN_POP] = {
1699                 .emad_add = efx_mae_action_set_add_vlan_pop
1700         },
1701         [EFX_MAE_ACTION_VLAN_PUSH] = {
1702                 .emad_add = efx_mae_action_set_add_vlan_push
1703         },
1704         [EFX_MAE_ACTION_ENCAP] = {
1705                 .emad_add = efx_mae_action_set_add_encap
1706         },
1707         [EFX_MAE_ACTION_COUNT] = {
1708                 .emad_add = efx_mae_action_set_add_count
1709         },
1710         [EFX_MAE_ACTION_FLAG] = {
1711                 .emad_add = efx_mae_action_set_add_flag
1712         },
1713         [EFX_MAE_ACTION_MARK] = {
1714                 .emad_add = efx_mae_action_set_add_mark
1715         },
1716         [EFX_MAE_ACTION_DELIVER] = {
1717                 .emad_add = efx_mae_action_set_add_deliver
1718         }
1719 };
1720
1721 static const uint32_t efx_mae_action_ordered_map =
1722         (1U << EFX_MAE_ACTION_DECAP) |
1723         (1U << EFX_MAE_ACTION_VLAN_POP) |
1724         (1U << EFX_MAE_ACTION_VLAN_PUSH) |
1725         /*
1726          * HW will conduct action COUNT after
1727          * the matching packet has been modified by
1728          * length-affecting actions except for ENCAP.
1729          */
1730         (1U << EFX_MAE_ACTION_COUNT) |
1731         (1U << EFX_MAE_ACTION_ENCAP) |
1732         (1U << EFX_MAE_ACTION_FLAG) |
1733         (1U << EFX_MAE_ACTION_MARK) |
1734         (1U << EFX_MAE_ACTION_DELIVER);
1735
1736 /*
1737  * These actions must not be added after DELIVER, but
1738  * they can have any place among the rest of
1739  * strictly ordered actions.
1740  */
1741 static const uint32_t efx_mae_action_nonstrict_map =
1742         (1U << EFX_MAE_ACTION_COUNT) |
1743         (1U << EFX_MAE_ACTION_FLAG) |
1744         (1U << EFX_MAE_ACTION_MARK);
1745
1746 static const uint32_t efx_mae_action_repeat_map =
1747         (1U << EFX_MAE_ACTION_VLAN_POP) |
1748         (1U << EFX_MAE_ACTION_VLAN_PUSH) |
1749         (1U << EFX_MAE_ACTION_COUNT);
1750
1751 /*
1752  * Add an action to an action set.
1753  *
1754  * This has to be invoked in the desired action order.
1755  * An out-of-order action request will be turned down.
1756  */
1757 static  __checkReturn                   efx_rc_t
1758 efx_mae_action_set_spec_populate(
1759         __in                            efx_mae_actions_t *spec,
1760         __in                            efx_mae_action_t type,
1761         __in                            size_t arg_size,
1762         __in_bcount(arg_size)           const uint8_t *arg)
1763 {
1764         uint32_t action_mask;
1765         efx_rc_t rc;
1766
1767         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1768             (sizeof (efx_mae_action_ordered_map) * 8));
1769         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1770             (sizeof (efx_mae_action_repeat_map) * 8));
1771
1772         EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
1773         EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK);
1774         EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER);
1775
1776         if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
1777                 rc = EINVAL;
1778                 goto fail1;
1779         }
1780
1781         action_mask = (1U << type);
1782
1783         if ((spec->ema_actions & action_mask) != 0) {
1784                 /* The action set already contains this action. */
1785                 if ((efx_mae_action_repeat_map & action_mask) == 0) {
1786                         /* Cannot add another non-repeatable action. */
1787                         rc = ENOTSUP;
1788                         goto fail2;
1789                 }
1790         }
1791
1792         if ((efx_mae_action_ordered_map & action_mask) != 0) {
1793                 uint32_t strict_ordered_map =
1794                     efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map;
1795                 uint32_t later_actions_mask =
1796                     strict_ordered_map & ~(action_mask | (action_mask - 1));
1797
1798                 if ((spec->ema_actions & later_actions_mask) != 0) {
1799                         /* Cannot add an action after later ordered actions. */
1800                         rc = ENOTSUP;
1801                         goto fail3;
1802                 }
1803         }
1804
1805         if (efx_mae_actions[type].emad_add != NULL) {
1806                 rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
1807                 if (rc != 0)
1808                         goto fail4;
1809         }
1810
1811         spec->ema_actions |= action_mask;
1812
1813         return (0);
1814
1815 fail4:
1816         EFSYS_PROBE(fail4);
1817 fail3:
1818         EFSYS_PROBE(fail3);
1819 fail2:
1820         EFSYS_PROBE(fail2);
1821 fail1:
1822         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1823         return (rc);
1824 }
1825
1826         __checkReturn                   efx_rc_t
1827 efx_mae_action_set_populate_decap(
1828         __in                            efx_mae_actions_t *spec)
1829 {
1830         return (efx_mae_action_set_spec_populate(spec,
1831             EFX_MAE_ACTION_DECAP, 0, NULL));
1832 }
1833
1834         __checkReturn                   efx_rc_t
1835 efx_mae_action_set_populate_vlan_pop(
1836         __in                            efx_mae_actions_t *spec)
1837 {
1838         return (efx_mae_action_set_spec_populate(spec,
1839             EFX_MAE_ACTION_VLAN_POP, 0, NULL));
1840 }
1841
1842         __checkReturn                   efx_rc_t
1843 efx_mae_action_set_populate_vlan_push(
1844         __in                            efx_mae_actions_t *spec,
1845         __in                            uint16_t tpid_be,
1846         __in                            uint16_t tci_be)
1847 {
1848         efx_mae_action_vlan_push_t action;
1849         const uint8_t *arg = (const uint8_t *)&action;
1850
1851         action.emavp_tpid_be = tpid_be;
1852         action.emavp_tci_be = tci_be;
1853
1854         return (efx_mae_action_set_spec_populate(spec,
1855             EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg));
1856 }
1857
1858         __checkReturn                   efx_rc_t
1859 efx_mae_action_set_populate_encap(
1860         __in                            efx_mae_actions_t *spec)
1861 {
1862         /*
1863          * There is no argument to pass encap. header ID, thus, one does not
1864          * need to allocate an encap. header while parsing application input.
1865          * This is useful since building an action set may be done simply to
1866          * validate a rule, whilst resource allocation usually consumes time.
1867          */
1868         return (efx_mae_action_set_spec_populate(spec,
1869             EFX_MAE_ACTION_ENCAP, 0, NULL));
1870 }
1871
1872         __checkReturn                   efx_rc_t
1873 efx_mae_action_set_populate_count(
1874         __in                            efx_mae_actions_t *spec)
1875 {
1876         /*
1877          * There is no argument to pass counter ID, thus, one does not
1878          * need to allocate a counter while parsing application input.
1879          * This is useful since building an action set may be done simply to
1880          * validate a rule, whilst resource allocation usually consumes time.
1881          */
1882         return (efx_mae_action_set_spec_populate(spec,
1883             EFX_MAE_ACTION_COUNT, 0, NULL));
1884 }
1885
1886         __checkReturn                   efx_rc_t
1887 efx_mae_action_set_populate_flag(
1888         __in                            efx_mae_actions_t *spec)
1889 {
1890         return (efx_mae_action_set_spec_populate(spec,
1891             EFX_MAE_ACTION_FLAG, 0, NULL));
1892 }
1893
1894         __checkReturn                   efx_rc_t
1895 efx_mae_action_set_populate_mark(
1896         __in                            efx_mae_actions_t *spec,
1897         __in                            uint32_t mark_value)
1898 {
1899         const uint8_t *arg = (const uint8_t *)&mark_value;
1900
1901         return (efx_mae_action_set_spec_populate(spec,
1902             EFX_MAE_ACTION_MARK, sizeof (mark_value), arg));
1903 }
1904
1905         __checkReturn                   efx_rc_t
1906 efx_mae_action_set_populate_deliver(
1907         __in                            efx_mae_actions_t *spec,
1908         __in                            const efx_mport_sel_t *mportp)
1909 {
1910         const uint8_t *arg;
1911         efx_rc_t rc;
1912
1913         if (mportp == NULL) {
1914                 rc = EINVAL;
1915                 goto fail1;
1916         }
1917
1918         arg = (const uint8_t *)&mportp->sel;
1919
1920         return (efx_mae_action_set_spec_populate(spec,
1921             EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
1922
1923 fail1:
1924         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1925         return (rc);
1926 }
1927
1928         __checkReturn                   efx_rc_t
1929 efx_mae_action_set_populate_drop(
1930         __in                            efx_mae_actions_t *spec)
1931 {
1932         efx_mport_sel_t mport;
1933         const uint8_t *arg;
1934         efx_dword_t dword;
1935
1936         EFX_POPULATE_DWORD_1(dword,
1937             MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL);
1938
1939         /*
1940          * The constructed DWORD is little-endian,
1941          * but the resulting value is meant to be
1942          * passed to MCDIs, where it will undergo
1943          * host-order to little endian conversion.
1944          */
1945         mport.sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
1946
1947         arg = (const uint8_t *)&mport.sel;
1948
1949         return (efx_mae_action_set_spec_populate(spec,
1950             EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg));
1951 }
1952
1953         __checkReturn                   boolean_t
1954 efx_mae_action_set_specs_equal(
1955         __in                            const efx_mae_actions_t *left,
1956         __in                            const efx_mae_actions_t *right)
1957 {
1958         size_t cmp_size = EFX_FIELD_OFFSET(efx_mae_actions_t, ema_rsrc);
1959
1960         /*
1961          * An action set specification consists of two parts. The first part
1962          * indicates what actions are included in the action set, as well as
1963          * extra quantitative values (in example, the number of VLAN tags to
1964          * push). The second part comprises resource IDs used by the actions.
1965          *
1966          * A resource, in example, a counter, is allocated from the hardware
1967          * by the client, and it's the client who is responsible for keeping
1968          * track of allocated resources and comparing resource IDs if needed.
1969          *
1970          * In this API, don't compare resource IDs in the two specifications.
1971          */
1972
1973         return ((memcmp(left, right, cmp_size) == 0) ? B_TRUE : B_FALSE);
1974 }
1975
1976         __checkReturn                   efx_rc_t
1977 efx_mae_match_specs_class_cmp(
1978         __in                            efx_nic_t *enp,
1979         __in                            const efx_mae_match_spec_t *left,
1980         __in                            const efx_mae_match_spec_t *right,
1981         __out                           boolean_t *have_same_classp)
1982 {
1983         efx_mae_t *maep = enp->en_maep;
1984         unsigned int field_ncaps = maep->em_max_nfields;
1985         const efx_mae_field_cap_t *field_caps;
1986         const efx_mae_mv_desc_t *desc_setp;
1987         unsigned int desc_set_nentries;
1988         const efx_mae_mv_bit_desc_t *bit_desc_setp;
1989         unsigned int bit_desc_set_nentries;
1990         boolean_t have_same_class = B_TRUE;
1991         efx_mae_field_id_t field_id;
1992         const uint8_t *mvpl;
1993         const uint8_t *mvpr;
1994         efx_rc_t rc;
1995
1996         switch (left->emms_type) {
1997         case EFX_MAE_RULE_OUTER:
1998                 field_caps = maep->em_outer_rule_field_caps;
1999                 desc_setp = __efx_mae_outer_rule_mv_desc_set;
2000                 desc_set_nentries =
2001                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
2002                 bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
2003                 bit_desc_set_nentries =
2004                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
2005                 mvpl = left->emms_mask_value_pairs.outer;
2006                 mvpr = right->emms_mask_value_pairs.outer;
2007                 break;
2008         case EFX_MAE_RULE_ACTION:
2009                 field_caps = maep->em_action_rule_field_caps;
2010                 desc_setp = __efx_mae_action_rule_mv_desc_set;
2011                 desc_set_nentries =
2012                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
2013                 bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
2014                 bit_desc_set_nentries =
2015                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
2016                 mvpl = left->emms_mask_value_pairs.action;
2017                 mvpr = right->emms_mask_value_pairs.action;
2018                 break;
2019         default:
2020                 rc = ENOTSUP;
2021                 goto fail1;
2022         }
2023
2024         if (field_caps == NULL) {
2025                 rc = EAGAIN;
2026                 goto fail2;
2027         }
2028
2029         if (left->emms_type != right->emms_type ||
2030             left->emms_prio != right->emms_prio) {
2031                 /*
2032                  * Rules of different types can never map to the same class.
2033                  *
2034                  * The FW can support some set of match criteria for one
2035                  * priority and not support the very same set for
2036                  * another priority. Thus, two rules which have
2037                  * different priorities can never map to
2038                  * the same class.
2039                  */
2040                 *have_same_classp = B_FALSE;
2041                 return (0);
2042         }
2043
2044         for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
2045              ++field_id) {
2046                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
2047                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
2048                 const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
2049                 const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
2050                 size_t mask_size = descp->emmd_mask_size;
2051                 const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
2052                 const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
2053                 size_t value_size = descp->emmd_value_size;
2054
2055                 if (mask_size == 0)
2056                         continue; /* Skip array gap */
2057
2058                 if ((unsigned int)field_cap_id >= field_ncaps) {
2059                         /*
2060                          * The FW has not reported capability status for this
2061                          * field. It's unknown whether any difference between
2062                          * the two masks / values affects the class. The only
2063                          * case when the class must be the same is when these
2064                          * mask-value pairs match. Otherwise, report mismatch.
2065                          */
2066                         if ((memcmp(lmaskp, rmaskp, mask_size) == 0) &&
2067                             (memcmp(lvalp, rvalp, value_size) == 0))
2068                                 continue;
2069                         else
2070                                 break;
2071                 }
2072
2073                 if (field_caps[field_cap_id].emfc_mask_affects_class) {
2074                         if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
2075                                 have_same_class = B_FALSE;
2076                                 break;
2077                         }
2078                 }
2079
2080                 if (field_caps[field_cap_id].emfc_match_affects_class) {
2081                         if (memcmp(lvalp, rvalp, value_size) != 0) {
2082                                 have_same_class = B_FALSE;
2083                                 break;
2084                         }
2085                 }
2086         }
2087
2088         if (have_same_class == B_FALSE)
2089                 goto done;
2090
2091         for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
2092              ++field_id) {
2093                 const efx_mae_mv_bit_desc_t *bit_descp =
2094                     &bit_desc_setp[field_id];
2095                 efx_mae_field_cap_id_t bit_cap_id =
2096                     bit_descp->emmbd_bit_cap_id;
2097                 unsigned int byte_idx;
2098                 unsigned int bit_idx;
2099
2100                 if (bit_descp->emmbd_entry_is_valid == B_FALSE)
2101                         continue; /* Skip array gap */
2102
2103                 if ((unsigned int)bit_cap_id >= field_ncaps)
2104                         break;
2105
2106                 byte_idx =
2107                     bit_descp->emmbd_mask_ofst +
2108                     bit_descp->emmbd_mask_lbn / 8;
2109                 bit_idx =
2110                     bit_descp->emmbd_mask_lbn % 8;
2111
2112                 if (field_caps[bit_cap_id].emfc_mask_affects_class &&
2113                     (mvpl[byte_idx] & (1U << bit_idx)) !=
2114                     (mvpr[byte_idx] & (1U << bit_idx))) {
2115                         have_same_class = B_FALSE;
2116                         break;
2117                 }
2118
2119                 byte_idx =
2120                     bit_descp->emmbd_value_ofst +
2121                     bit_descp->emmbd_value_lbn / 8;
2122                 bit_idx =
2123                     bit_descp->emmbd_value_lbn % 8;
2124
2125                 if (field_caps[bit_cap_id].emfc_match_affects_class &&
2126                     (mvpl[byte_idx] & (1U << bit_idx)) !=
2127                     (mvpr[byte_idx] & (1U << bit_idx))) {
2128                         have_same_class = B_FALSE;
2129                         break;
2130                 }
2131         }
2132
2133 done:
2134         *have_same_classp = have_same_class;
2135
2136         return (0);
2137
2138 fail2:
2139         EFSYS_PROBE(fail2);
2140 fail1:
2141         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2142         return (rc);
2143 }
2144
2145         __checkReturn                   efx_rc_t
2146 efx_mae_outer_rule_recirc_id_set(
2147         __in                            efx_mae_match_spec_t *spec,
2148         __in                            uint8_t recirc_id)
2149 {
2150         efx_rc_t rc;
2151
2152         if (spec->emms_type != EFX_MAE_RULE_OUTER) {
2153                 rc = EINVAL;
2154                 goto fail1;
2155         }
2156
2157         spec->emms_outer_rule_recirc_id = recirc_id;
2158
2159         return (0);
2160
2161 fail1:
2162         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2163         return (rc);
2164 }
2165
2166         __checkReturn           efx_rc_t
2167 efx_mae_outer_rule_insert(
2168         __in                    efx_nic_t *enp,
2169         __in                    const efx_mae_match_spec_t *spec,
2170         __in                    efx_tunnel_protocol_t encap_type,
2171         __out                   efx_mae_rule_id_t *or_idp)
2172 {
2173         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2174         efx_mcdi_req_t req;
2175         EFX_MCDI_DECLARE_BUF(payload,
2176             MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2,
2177             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
2178         uint32_t encap_type_mcdi;
2179         efx_mae_rule_id_t or_id;
2180         size_t offset;
2181         efx_rc_t rc;
2182
2183         EFX_STATIC_ASSERT(sizeof (or_idp->id) ==
2184             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN);
2185
2186         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2187             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL);
2188
2189         if (encp->enc_mae_supported == B_FALSE) {
2190                 rc = ENOTSUP;
2191                 goto fail1;
2192         }
2193
2194         if (spec->emms_type != EFX_MAE_RULE_OUTER) {
2195                 rc = EINVAL;
2196                 goto fail2;
2197         }
2198
2199         switch (encap_type) {
2200         case EFX_TUNNEL_PROTOCOL_NONE:
2201                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
2202                 break;
2203         case EFX_TUNNEL_PROTOCOL_VXLAN:
2204                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
2205                 break;
2206         case EFX_TUNNEL_PROTOCOL_GENEVE:
2207                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
2208                 break;
2209         case EFX_TUNNEL_PROTOCOL_NVGRE:
2210                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
2211                 break;
2212         default:
2213                 rc = ENOTSUP;
2214                 goto fail3;
2215         }
2216
2217         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT;
2218         req.emr_in_buf = payload;
2219         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2;
2220         req.emr_out_buf = payload;
2221         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN;
2222
2223         MCDI_IN_SET_DWORD(req,
2224             MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi);
2225
2226         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio);
2227
2228         /*
2229          * Mask-value pairs have been stored in the byte order needed for the
2230          * MCDI request and are thus safe to be copied directly to the buffer.
2231          * The library cares about byte order in efx_mae_match_spec_field_set().
2232          */
2233         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >=
2234             MAE_ENC_FIELD_PAIRS_LEN);
2235         offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST;
2236         memcpy(payload + offset, spec->emms_mask_value_pairs.outer,
2237             MAE_ENC_FIELD_PAIRS_LEN);
2238
2239         MCDI_IN_SET_BYTE(req, MAE_OUTER_RULE_INSERT_IN_RECIRC_ID,
2240             spec->emms_outer_rule_recirc_id);
2241
2242         efx_mcdi_execute(enp, &req);
2243
2244         if (req.emr_rc != 0) {
2245                 rc = req.emr_rc;
2246                 goto fail4;
2247         }
2248
2249         if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) {
2250                 rc = EMSGSIZE;
2251                 goto fail5;
2252         }
2253
2254         or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
2255         if (or_id.id == EFX_MAE_RSRC_ID_INVALID) {
2256                 rc = ENOENT;
2257                 goto fail6;
2258         }
2259
2260         or_idp->id = or_id.id;
2261
2262         return (0);
2263
2264 fail6:
2265         EFSYS_PROBE(fail6);
2266 fail5:
2267         EFSYS_PROBE(fail5);
2268 fail4:
2269         EFSYS_PROBE(fail4);
2270 fail3:
2271         EFSYS_PROBE(fail3);
2272 fail2:
2273         EFSYS_PROBE(fail2);
2274 fail1:
2275         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2276         return (rc);
2277 }
2278
2279         __checkReturn           efx_rc_t
2280 efx_mae_outer_rule_remove(
2281         __in                    efx_nic_t *enp,
2282         __in                    const efx_mae_rule_id_t *or_idp)
2283 {
2284         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2285         efx_mcdi_req_t req;
2286         EFX_MCDI_DECLARE_BUF(payload,
2287             MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1),
2288             MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
2289         efx_rc_t rc;
2290
2291         if (encp->enc_mae_supported == B_FALSE) {
2292                 rc = ENOTSUP;
2293                 goto fail1;
2294         }
2295
2296         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE;
2297         req.emr_in_buf = payload;
2298         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1);
2299         req.emr_out_buf = payload;
2300         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1);
2301
2302         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id);
2303
2304         efx_mcdi_execute(enp, &req);
2305
2306         if (req.emr_rc != 0) {
2307                 rc = req.emr_rc;
2308                 goto fail2;
2309         }
2310
2311         if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LENMIN) {
2312                 rc = EMSGSIZE;
2313                 goto fail3;
2314         }
2315
2316         if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) !=
2317             or_idp->id) {
2318                 /* Firmware failed to remove the outer rule. */
2319                 rc = EAGAIN;
2320                 goto fail4;
2321         }
2322
2323         return (0);
2324
2325 fail4:
2326         EFSYS_PROBE(fail4);
2327 fail3:
2328         EFSYS_PROBE(fail3);
2329 fail2:
2330         EFSYS_PROBE(fail2);
2331 fail1:
2332         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2333         return (rc);
2334 }
2335
2336         __checkReturn                   efx_rc_t
2337 efx_mae_match_spec_outer_rule_id_set(
2338         __in                            efx_mae_match_spec_t *spec,
2339         __in                            const efx_mae_rule_id_t *or_idp)
2340 {
2341         uint32_t full_mask = UINT32_MAX;
2342         efx_rc_t rc;
2343
2344         if (spec->emms_type != EFX_MAE_RULE_ACTION) {
2345                 rc = EINVAL;
2346                 goto fail1;
2347         }
2348
2349         if (or_idp == NULL) {
2350                 rc = EINVAL;
2351                 goto fail2;
2352         }
2353
2354         rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID,
2355             sizeof (or_idp->id), (const uint8_t *)&or_idp->id,
2356             sizeof (full_mask), (const uint8_t *)&full_mask);
2357         if (rc != 0)
2358                 goto fail3;
2359
2360         return (0);
2361
2362 fail3:
2363         EFSYS_PROBE(fail3);
2364 fail2:
2365         EFSYS_PROBE(fail2);
2366 fail1:
2367         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2368         return (rc);
2369 }
2370
2371          __checkReturn                  efx_rc_t
2372 efx_mae_encap_header_alloc(
2373         __in                            efx_nic_t *enp,
2374         __in                            efx_tunnel_protocol_t encap_type,
2375         __in_bcount(header_size)        uint8_t *header_data,
2376         __in                            size_t header_size,
2377         __out                           efx_mae_eh_id_t *eh_idp)
2378 {
2379         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2380         efx_mcdi_req_t req;
2381         EFX_MCDI_DECLARE_BUF(payload,
2382             MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LENMAX_MCDI2,
2383             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN);
2384         uint32_t encap_type_mcdi;
2385         efx_mae_eh_id_t eh_id;
2386         efx_rc_t rc;
2387
2388         EFX_STATIC_ASSERT(sizeof (eh_idp->id) ==
2389             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_LEN);
2390
2391         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2392             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
2393
2394         if (encp->enc_mae_supported == B_FALSE) {
2395                 rc = ENOTSUP;
2396                 goto fail1;
2397         }
2398
2399         switch (encap_type) {
2400         case EFX_TUNNEL_PROTOCOL_NONE:
2401                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
2402                 break;
2403         case EFX_TUNNEL_PROTOCOL_VXLAN:
2404                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
2405                 break;
2406         case EFX_TUNNEL_PROTOCOL_GENEVE:
2407                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
2408                 break;
2409         case EFX_TUNNEL_PROTOCOL_NVGRE:
2410                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
2411                 break;
2412         default:
2413                 rc = ENOTSUP;
2414                 goto fail2;
2415         }
2416
2417         if (header_size >
2418             MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2) {
2419                 rc = EINVAL;
2420                 goto fail3;
2421         }
2422
2423         req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_ALLOC;
2424         req.emr_in_buf = payload;
2425         req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(header_size);
2426         req.emr_out_buf = payload;
2427         req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN;
2428
2429         MCDI_IN_SET_DWORD(req,
2430             MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, encap_type_mcdi);
2431
2432         memcpy(payload + MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_OFST,
2433             header_data, header_size);
2434
2435         efx_mcdi_execute(enp, &req);
2436
2437         if (req.emr_rc != 0) {
2438                 rc = req.emr_rc;
2439                 goto fail4;
2440         }
2441
2442         if (req.emr_out_length_used < MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN) {
2443                 rc = EMSGSIZE;
2444                 goto fail5;
2445         }
2446
2447         eh_id.id = MCDI_OUT_DWORD(req,
2448             MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID);
2449
2450         if (eh_id.id == EFX_MAE_RSRC_ID_INVALID) {
2451                 rc = ENOENT;
2452                 goto fail6;
2453         }
2454
2455         eh_idp->id = eh_id.id;
2456
2457         return (0);
2458
2459 fail6:
2460         EFSYS_PROBE(fail6);
2461 fail5:
2462         EFSYS_PROBE(fail5);
2463 fail4:
2464         EFSYS_PROBE(fail4);
2465 fail3:
2466         EFSYS_PROBE(fail3);
2467 fail2:
2468         EFSYS_PROBE(fail2);
2469 fail1:
2470         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2471         return (rc);
2472 }
2473
2474         __checkReturn                   efx_rc_t
2475 efx_mae_encap_header_free(
2476         __in                            efx_nic_t *enp,
2477         __in                            const efx_mae_eh_id_t *eh_idp)
2478 {
2479         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2480         efx_mcdi_req_t req;
2481         EFX_MCDI_DECLARE_BUF(payload,
2482             MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1),
2483             MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1));
2484         efx_rc_t rc;
2485
2486         if (encp->enc_mae_supported == B_FALSE) {
2487                 rc = ENOTSUP;
2488                 goto fail1;
2489         }
2490
2491         req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_FREE;
2492         req.emr_in_buf = payload;
2493         req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1);
2494         req.emr_out_buf = payload;
2495         req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1);
2496
2497         MCDI_IN_SET_DWORD(req, MAE_ENCAP_HEADER_FREE_IN_EH_ID, eh_idp->id);
2498
2499         efx_mcdi_execute(enp, &req);
2500
2501         if (req.emr_rc != 0) {
2502                 rc = req.emr_rc;
2503                 goto fail2;
2504         }
2505
2506         if (MCDI_OUT_DWORD(req, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) !=
2507             eh_idp->id) {
2508                 /* Firmware failed to remove the encap. header. */
2509                 rc = EAGAIN;
2510                 goto fail3;
2511         }
2512
2513         return (0);
2514
2515 fail3:
2516         EFSYS_PROBE(fail3);
2517 fail2:
2518         EFSYS_PROBE(fail2);
2519 fail1:
2520         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2521         return (rc);
2522 }
2523
2524         __checkReturn                   efx_rc_t
2525 efx_mae_action_set_fill_in_eh_id(
2526         __in                            efx_mae_actions_t *spec,
2527         __in                            const efx_mae_eh_id_t *eh_idp)
2528 {
2529         efx_rc_t rc;
2530
2531         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) == 0) {
2532                 /*
2533                  * The caller has not intended to have action ENCAP originally,
2534                  * hence, this attempt to indicate encap. header ID is invalid.
2535                  */
2536                 rc = EINVAL;
2537                 goto fail1;
2538         }
2539
2540         if (spec->ema_rsrc.emar_eh_id.id != EFX_MAE_RSRC_ID_INVALID) {
2541                 /* The caller attempts to indicate encap. header ID twice. */
2542                 rc = EINVAL;
2543                 goto fail2;
2544         }
2545
2546         if (eh_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2547                 rc = EINVAL;
2548                 goto fail3;
2549         }
2550
2551         spec->ema_rsrc.emar_eh_id.id = eh_idp->id;
2552
2553         return (0);
2554
2555 fail3:
2556         EFSYS_PROBE(fail3);
2557 fail2:
2558         EFSYS_PROBE(fail2);
2559 fail1:
2560         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2561         return (rc);
2562 }
2563
2564         __checkReturn                   efx_rc_t
2565 efx_mae_action_set_alloc(
2566         __in                            efx_nic_t *enp,
2567         __in                            const efx_mae_actions_t *spec,
2568         __out                           efx_mae_aset_id_t *aset_idp)
2569 {
2570         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2571         efx_mcdi_req_t req;
2572         EFX_MCDI_DECLARE_BUF(payload,
2573             MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
2574             MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
2575         efx_mae_aset_id_t aset_id;
2576         efx_rc_t rc;
2577
2578         if (encp->enc_mae_supported == B_FALSE) {
2579                 rc = ENOTSUP;
2580                 goto fail1;
2581         }
2582
2583         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) != 0 &&
2584             spec->ema_rsrc.emar_eh_id.id == EFX_MAE_RSRC_ID_INVALID) {
2585                 rc = EINVAL;
2586                 goto fail2;
2587         }
2588
2589         if (spec->ema_n_count_actions == 1 &&
2590             spec->ema_rsrc.emar_counter_id.id == EFX_MAE_RSRC_ID_INVALID) {
2591                 rc = EINVAL;
2592                 goto fail3;
2593         }
2594
2595         req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
2596         req.emr_in_buf = payload;
2597         req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
2598         req.emr_out_buf = payload;
2599         req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
2600
2601         /*
2602          * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
2603          * corresponding resource types are supported by the implementation.
2604          * Use proper resource ID assignments instead.
2605          */
2606         MCDI_IN_SET_DWORD(req,
2607             MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
2608
2609         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECAP)) != 0) {
2610                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2611                     MAE_ACTION_SET_ALLOC_IN_DECAP, 1);
2612         }
2613
2614         MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2615             MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
2616
2617         if (spec->ema_n_vlan_tags_to_push > 0) {
2618                 unsigned int outer_tag_idx;
2619
2620                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2621                     MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
2622                     spec->ema_n_vlan_tags_to_push);
2623
2624                 if (spec->ema_n_vlan_tags_to_push ==
2625                     EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
2626                         MCDI_IN_SET_WORD(req,
2627                             MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
2628                             spec->ema_vlan_push_descs[0].emavp_tpid_be);
2629                         MCDI_IN_SET_WORD(req,
2630                             MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
2631                             spec->ema_vlan_push_descs[0].emavp_tci_be);
2632                 }
2633
2634                 outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
2635
2636                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
2637                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
2638                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
2639                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
2640         }
2641
2642         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
2643             spec->ema_rsrc.emar_eh_id.id);
2644         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
2645             spec->ema_rsrc.emar_counter_id.id);
2646
2647         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
2648                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2649                     MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
2650         }
2651
2652         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
2653                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2654                     MAE_ACTION_SET_ALLOC_IN_MARK, 1);
2655
2656                 MCDI_IN_SET_DWORD(req,
2657                     MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
2658         }
2659
2660         MCDI_IN_SET_DWORD(req,
2661             MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
2662
2663         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
2664             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2665         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
2666             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2667
2668         efx_mcdi_execute(enp, &req);
2669
2670         if (req.emr_rc != 0) {
2671                 rc = req.emr_rc;
2672                 goto fail4;
2673         }
2674
2675         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
2676                 rc = EMSGSIZE;
2677                 goto fail5;
2678         }
2679
2680         aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
2681         if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
2682                 rc = ENOENT;
2683                 goto fail6;
2684         }
2685
2686         aset_idp->id = aset_id.id;
2687
2688         return (0);
2689
2690 fail6:
2691         EFSYS_PROBE(fail6);
2692 fail5:
2693         EFSYS_PROBE(fail5);
2694 fail4:
2695         EFSYS_PROBE(fail4);
2696 fail3:
2697         EFSYS_PROBE(fail3);
2698 fail2:
2699         EFSYS_PROBE(fail2);
2700 fail1:
2701         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2702         return (rc);
2703 }
2704
2705         __checkReturn                   unsigned int
2706 efx_mae_action_set_get_nb_count(
2707         __in                            const efx_mae_actions_t *spec)
2708 {
2709         return (spec->ema_n_count_actions);
2710 }
2711
2712         __checkReturn                   efx_rc_t
2713 efx_mae_action_set_fill_in_counter_id(
2714         __in                            efx_mae_actions_t *spec,
2715         __in                            const efx_counter_t *counter_idp)
2716 {
2717         efx_rc_t rc;
2718
2719         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_COUNT)) == 0) {
2720                 /*
2721                  * Invalid to add counter ID if spec does not have COUNT action.
2722                  */
2723                 rc = EINVAL;
2724                 goto fail1;
2725         }
2726
2727         if (spec->ema_n_count_actions != 1) {
2728                 /*
2729                  * Having multiple COUNT actions in the spec requires a counter
2730                  * list to be used. This API must only be used for a single
2731                  * counter per spec. Turn down the request as inappropriate.
2732                  */
2733                 rc = EINVAL;
2734                 goto fail2;
2735         }
2736
2737         if (spec->ema_rsrc.emar_counter_id.id != EFX_MAE_RSRC_ID_INVALID) {
2738                 /* The caller attempts to indicate counter ID twice. */
2739                 rc = EALREADY;
2740                 goto fail3;
2741         }
2742
2743         if (counter_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2744                 rc = EINVAL;
2745                 goto fail4;
2746         }
2747
2748         spec->ema_rsrc.emar_counter_id.id = counter_idp->id;
2749
2750         return (0);
2751
2752 fail4:
2753         EFSYS_PROBE(fail4);
2754 fail3:
2755         EFSYS_PROBE(fail3);
2756 fail2:
2757         EFSYS_PROBE(fail2);
2758 fail1:
2759         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2760         return (rc);
2761 }
2762
2763         __checkReturn                   efx_rc_t
2764 efx_mae_counters_alloc(
2765         __in                            efx_nic_t *enp,
2766         __in                            uint32_t n_counters,
2767         __out                           uint32_t *n_allocatedp,
2768         __out_ecount(n_counters)        efx_counter_t *countersp,
2769         __out_opt                       uint32_t *gen_countp)
2770 {
2771         EFX_MCDI_DECLARE_BUF(payload,
2772             MC_CMD_MAE_COUNTER_ALLOC_IN_LEN,
2773             MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMAX_MCDI2);
2774         efx_mae_t *maep = enp->en_maep;
2775         uint32_t n_allocated;
2776         efx_mcdi_req_t req;
2777         unsigned int i;
2778         efx_rc_t rc;
2779
2780         if (n_counters > maep->em_max_ncounters ||
2781             n_counters < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM ||
2782             n_counters > MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MAXNUM_MCDI2) {
2783                 rc = EINVAL;
2784                 goto fail1;
2785         }
2786
2787         req.emr_cmd = MC_CMD_MAE_COUNTER_ALLOC;
2788         req.emr_in_buf = payload;
2789         req.emr_in_length = MC_CMD_MAE_COUNTER_ALLOC_IN_LEN;
2790         req.emr_out_buf = payload;
2791         req.emr_out_length = MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(n_counters);
2792
2793         MCDI_IN_SET_DWORD(req, MAE_COUNTER_ALLOC_IN_REQUESTED_COUNT,
2794             n_counters);
2795
2796         efx_mcdi_execute(enp, &req);
2797
2798         if (req.emr_rc != 0) {
2799                 rc = req.emr_rc;
2800                 goto fail2;
2801         }
2802
2803         if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMIN) {
2804                 rc = EMSGSIZE;
2805                 goto fail3;
2806         }
2807
2808         n_allocated = MCDI_OUT_DWORD(req,
2809             MAE_COUNTER_ALLOC_OUT_COUNTER_ID_COUNT);
2810         if (n_allocated < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM) {
2811                 rc = EFAULT;
2812                 goto fail4;
2813         }
2814
2815         for (i = 0; i < n_allocated; i++) {
2816                 countersp[i].id = MCDI_OUT_INDEXED_DWORD(req,
2817                     MAE_COUNTER_ALLOC_OUT_COUNTER_ID, i);
2818         }
2819
2820         if (gen_countp != NULL) {
2821                 *gen_countp = MCDI_OUT_DWORD(req,
2822                                     MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT);
2823         }
2824
2825         *n_allocatedp = n_allocated;
2826
2827         return (0);
2828
2829 fail4:
2830         EFSYS_PROBE(fail4);
2831 fail3:
2832         EFSYS_PROBE(fail3);
2833 fail2:
2834         EFSYS_PROBE(fail2);
2835 fail1:
2836         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2837
2838         return (rc);
2839 }
2840
2841         __checkReturn                   efx_rc_t
2842 efx_mae_counters_free(
2843         __in                            efx_nic_t *enp,
2844         __in                            uint32_t n_counters,
2845         __out                           uint32_t *n_freedp,
2846         __in_ecount(n_counters)         const efx_counter_t *countersp,
2847         __out_opt                       uint32_t *gen_countp)
2848 {
2849         EFX_MCDI_DECLARE_BUF(payload,
2850             MC_CMD_MAE_COUNTER_FREE_IN_LENMAX_MCDI2,
2851             MC_CMD_MAE_COUNTER_FREE_OUT_LENMAX_MCDI2);
2852         efx_mae_t *maep = enp->en_maep;
2853         efx_mcdi_req_t req;
2854         uint32_t n_freed;
2855         unsigned int i;
2856         efx_rc_t rc;
2857
2858         if (n_counters > maep->em_max_ncounters ||
2859             n_counters < MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MINNUM ||
2860             n_counters >
2861             MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MAXNUM_MCDI2) {
2862                 rc = EINVAL;
2863                 goto fail1;
2864         }
2865
2866         req.emr_cmd = MC_CMD_MAE_COUNTER_FREE;
2867         req.emr_in_buf = payload;
2868         req.emr_in_length = MC_CMD_MAE_COUNTER_FREE_IN_LEN(n_counters);
2869         req.emr_out_buf = payload;
2870         req.emr_out_length = MC_CMD_MAE_COUNTER_FREE_OUT_LEN(n_counters);
2871
2872         for (i = 0; i < n_counters; i++) {
2873                 MCDI_IN_SET_INDEXED_DWORD(req,
2874                     MAE_COUNTER_FREE_IN_FREE_COUNTER_ID, i, countersp[i].id);
2875         }
2876         MCDI_IN_SET_DWORD(req, MAE_COUNTER_FREE_IN_COUNTER_ID_COUNT,
2877                           n_counters);
2878
2879         efx_mcdi_execute(enp, &req);
2880
2881         if (req.emr_rc != 0) {
2882                 rc = req.emr_rc;
2883                 goto fail2;
2884         }
2885
2886         if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_FREE_OUT_LENMIN) {
2887                 rc = EMSGSIZE;
2888                 goto fail3;
2889         }
2890
2891         n_freed = MCDI_OUT_DWORD(req, MAE_COUNTER_FREE_OUT_COUNTER_ID_COUNT);
2892
2893         if (n_freed < MC_CMD_MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID_MINNUM) {
2894                 rc = EFAULT;
2895                 goto fail4;
2896         }
2897
2898         if (gen_countp != NULL) {
2899                 *gen_countp = MCDI_OUT_DWORD(req,
2900                                     MAE_COUNTER_FREE_OUT_GENERATION_COUNT);
2901         }
2902
2903         *n_freedp = n_freed;
2904
2905         return (0);
2906
2907 fail4:
2908         EFSYS_PROBE(fail4);
2909 fail3:
2910         EFSYS_PROBE(fail3);
2911 fail2:
2912         EFSYS_PROBE(fail2);
2913 fail1:
2914         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2915
2916         return (rc);
2917 }
2918
2919         __checkReturn                   efx_rc_t
2920 efx_mae_counters_stream_start(
2921         __in                            efx_nic_t *enp,
2922         __in                            uint16_t rxq_id,
2923         __in                            uint16_t packet_size,
2924         __in                            uint32_t flags_in,
2925         __out                           uint32_t *flags_out)
2926 {
2927         efx_mcdi_req_t req;
2928         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN,
2929                              MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN);
2930         efx_rc_t rc;
2931
2932         EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_IN_ZERO_SQUASH_DISABLE ==
2933             1U << MC_CMD_MAE_COUNTERS_STREAM_START_IN_ZERO_SQUASH_DISABLE_LBN);
2934
2935         EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_OUT_USES_CREDITS ==
2936             1U << MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_LBN);
2937
2938         req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_START;
2939         req.emr_in_buf = payload;
2940         req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN;
2941         req.emr_out_buf = payload;
2942         req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN;
2943
2944         MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_QID, rxq_id);
2945         MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_PACKET_SIZE,
2946                          packet_size);
2947         MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_START_IN_FLAGS, flags_in);
2948
2949         efx_mcdi_execute(enp, &req);
2950
2951         if (req.emr_rc != 0) {
2952                 rc = req.emr_rc;
2953                 goto fail1;
2954         }
2955
2956         if (req.emr_out_length_used <
2957             MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN) {
2958                 rc = EMSGSIZE;
2959                 goto fail2;
2960         }
2961
2962         *flags_out = MCDI_OUT_DWORD(req, MAE_COUNTERS_STREAM_START_OUT_FLAGS);
2963
2964         return (0);
2965
2966 fail2:
2967         EFSYS_PROBE(fail2);
2968 fail1:
2969         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2970
2971         return (rc);
2972 }
2973
2974         __checkReturn                   efx_rc_t
2975 efx_mae_counters_stream_stop(
2976         __in                            efx_nic_t *enp,
2977         __in                            uint16_t rxq_id,
2978         __out_opt                       uint32_t *gen_countp)
2979 {
2980         efx_mcdi_req_t req;
2981         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN,
2982                              MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN);
2983         efx_rc_t rc;
2984
2985         req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_STOP;
2986         req.emr_in_buf = payload;
2987         req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN;
2988         req.emr_out_buf = payload;
2989         req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN;
2990
2991         MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_STOP_IN_QID, rxq_id);
2992
2993         efx_mcdi_execute(enp, &req);
2994
2995         if (req.emr_rc != 0) {
2996                 rc = req.emr_rc;
2997                 goto fail1;
2998         }
2999
3000         if (req.emr_out_length_used <
3001             MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN) {
3002                 rc = EMSGSIZE;
3003                 goto fail2;
3004         }
3005
3006         if (gen_countp != NULL) {
3007                 *gen_countp = MCDI_OUT_DWORD(req,
3008                             MAE_COUNTERS_STREAM_STOP_OUT_GENERATION_COUNT);
3009         }
3010
3011         return (0);
3012
3013 fail2:
3014         EFSYS_PROBE(fail2);
3015 fail1:
3016         EFSYS_PROBE1(fail1, efx_rc_t, rc);
3017
3018         return (rc);
3019 }
3020
3021         __checkReturn                   efx_rc_t
3022 efx_mae_counters_stream_give_credits(
3023         __in                            efx_nic_t *enp,
3024         __in                            uint32_t n_credits)
3025 {
3026         efx_mcdi_req_t req;
3027         EFX_MCDI_DECLARE_BUF(payload,
3028                              MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN,
3029                              MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN);
3030         efx_rc_t rc;
3031
3032         req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS;
3033         req.emr_in_buf = payload;
3034         req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN;
3035         req.emr_out_buf = payload;
3036         req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN;
3037
3038         MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_NUM_CREDITS,
3039                          n_credits);
3040
3041         efx_mcdi_execute(enp, &req);
3042
3043         if (req.emr_rc != 0) {
3044                 rc = req.emr_rc;
3045                 goto fail1;
3046         }
3047
3048         return (0);
3049
3050 fail1:
3051         EFSYS_PROBE1(fail1, efx_rc_t, rc);
3052
3053         return (rc);
3054 }
3055
3056         __checkReturn                   efx_rc_t
3057 efx_mae_action_set_free(
3058         __in                            efx_nic_t *enp,
3059         __in                            const efx_mae_aset_id_t *aset_idp)
3060 {
3061         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3062         efx_mcdi_req_t req;
3063         EFX_MCDI_DECLARE_BUF(payload,
3064             MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
3065             MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
3066         efx_rc_t rc;
3067
3068         if (encp->enc_mae_supported == B_FALSE) {
3069                 rc = ENOTSUP;
3070                 goto fail1;
3071         }
3072
3073         req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
3074         req.emr_in_buf = payload;
3075         req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
3076         req.emr_out_buf = payload;
3077         req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
3078
3079         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
3080
3081         efx_mcdi_execute(enp, &req);
3082
3083         if (req.emr_rc != 0) {
3084                 rc = req.emr_rc;
3085                 goto fail2;
3086         }
3087
3088         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_FREE_OUT_LENMIN) {
3089                 rc = EMSGSIZE;
3090                 goto fail3;
3091         }
3092
3093         if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
3094             aset_idp->id) {
3095                 /* Firmware failed to free the action set. */
3096                 rc = EAGAIN;
3097                 goto fail4;
3098         }
3099
3100         return (0);
3101
3102 fail4:
3103         EFSYS_PROBE(fail4);
3104 fail3:
3105         EFSYS_PROBE(fail3);
3106 fail2:
3107         EFSYS_PROBE(fail2);
3108 fail1:
3109         EFSYS_PROBE1(fail1, efx_rc_t, rc);
3110         return (rc);
3111 }
3112
3113         __checkReturn                   efx_rc_t
3114 efx_mae_action_rule_insert(
3115         __in                            efx_nic_t *enp,
3116         __in                            const efx_mae_match_spec_t *spec,
3117         __in                            const efx_mae_aset_list_id_t *asl_idp,
3118         __in                            const efx_mae_aset_id_t *as_idp,
3119         __out                           efx_mae_rule_id_t *ar_idp)
3120 {
3121         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3122         efx_mcdi_req_t req;
3123         EFX_MCDI_DECLARE_BUF(payload,
3124             MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2,
3125             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
3126         efx_oword_t *rule_response;
3127         efx_mae_rule_id_t ar_id;
3128         size_t offset;
3129         efx_rc_t rc;
3130
3131         EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
3132             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
3133
3134         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
3135             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
3136
3137         if (encp->enc_mae_supported == B_FALSE) {
3138                 rc = ENOTSUP;
3139                 goto fail1;
3140         }
3141
3142         if (spec->emms_type != EFX_MAE_RULE_ACTION ||
3143             (asl_idp != NULL && as_idp != NULL) ||
3144             (asl_idp == NULL && as_idp == NULL)) {
3145                 rc = EINVAL;
3146                 goto fail2;
3147         }
3148
3149         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
3150         req.emr_in_buf = payload;
3151         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
3152         req.emr_out_buf = payload;
3153         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
3154
3155         EFX_STATIC_ASSERT(sizeof (*rule_response) <=
3156             MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
3157         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
3158         rule_response = (efx_oword_t *)(payload + offset);
3159         EFX_POPULATE_OWORD_3(*rule_response,
3160             MAE_ACTION_RULE_RESPONSE_ASL_ID,
3161             (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
3162             MAE_ACTION_RULE_RESPONSE_AS_ID,
3163             (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
3164             MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
3165
3166         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
3167
3168         /*
3169          * Mask-value pairs have been stored in the byte order needed for the
3170          * MCDI request and are thus safe to be copied directly to the buffer.
3171          */
3172         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
3173             MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
3174         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
3175         memcpy(payload + offset, spec->emms_mask_value_pairs.action,
3176             MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
3177
3178         efx_mcdi_execute(enp, &req);
3179
3180         if (req.emr_rc != 0) {
3181                 rc = req.emr_rc;
3182                 goto fail3;
3183         }
3184
3185         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
3186                 rc = EMSGSIZE;
3187                 goto fail4;
3188         }
3189
3190         ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
3191         if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
3192                 rc = ENOENT;
3193                 goto fail5;
3194         }
3195
3196         ar_idp->id = ar_id.id;
3197
3198         return (0);
3199
3200 fail5:
3201         EFSYS_PROBE(fail5);
3202 fail4:
3203         EFSYS_PROBE(fail4);
3204 fail3:
3205         EFSYS_PROBE(fail3);
3206 fail2:
3207         EFSYS_PROBE(fail2);
3208 fail1:
3209         EFSYS_PROBE1(fail1, efx_rc_t, rc);
3210         return (rc);
3211 }
3212
3213         __checkReturn                   efx_rc_t
3214 efx_mae_action_rule_remove(
3215         __in                            efx_nic_t *enp,
3216         __in                            const efx_mae_rule_id_t *ar_idp)
3217 {
3218         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3219         efx_mcdi_req_t req;
3220         EFX_MCDI_DECLARE_BUF(payload,
3221             MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
3222             MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
3223         efx_rc_t rc;
3224
3225         if (encp->enc_mae_supported == B_FALSE) {
3226                 rc = ENOTSUP;
3227                 goto fail1;
3228         }
3229
3230         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
3231         req.emr_in_buf = payload;
3232         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
3233         req.emr_out_buf = payload;
3234         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
3235
3236         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
3237
3238         efx_mcdi_execute(enp, &req);
3239
3240         if (req.emr_rc != 0) {
3241                 rc = req.emr_rc;
3242                 goto fail2;
3243         }
3244
3245         if (req.emr_out_length_used <
3246             MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LENMIN) {
3247                 rc = EMSGSIZE;
3248                 goto fail3;
3249         }
3250
3251         if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
3252             ar_idp->id) {
3253                 /* Firmware failed to delete the action rule. */
3254                 rc = EAGAIN;
3255                 goto fail4;
3256         }
3257
3258         return (0);
3259
3260 fail4:
3261         EFSYS_PROBE(fail4);
3262 fail3:
3263         EFSYS_PROBE(fail3);
3264 fail2:
3265         EFSYS_PROBE(fail2);
3266 fail1:
3267         EFSYS_PROBE1(fail1, efx_rc_t, rc);
3268         return (rc);
3269 }
3270
3271         __checkReturn                   efx_rc_t
3272 efx_mcdi_mport_alloc_alias(
3273         __in                            efx_nic_t *enp,
3274         __out                           efx_mport_id_t *mportp,
3275         __out_opt                       uint32_t *labelp)
3276 {
3277         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3278         efx_mcdi_req_t req;
3279         EFX_MCDI_DECLARE_BUF(payload,
3280             MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_LEN,
3281             MC_CMD_MAE_MPORT_ALLOC_ALIAS_OUT_LEN);
3282         efx_rc_t rc;
3283
3284         if (encp->enc_mae_supported == B_FALSE) {
3285                 rc = ENOTSUP;
3286                 goto fail1;
3287         }
3288
3289         req.emr_cmd = MC_CMD_MAE_MPORT_ALLOC;
3290         req.emr_in_buf = payload;
3291         req.emr_in_length = MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_LEN;
3292         req.emr_out_buf = payload;
3293         req.emr_out_length = MC_CMD_MAE_MPORT_ALLOC_ALIAS_OUT_LEN;
3294
3295         MCDI_IN_SET_DWORD(req, MAE_MPORT_ALLOC_IN_TYPE,
3296                           MC_CMD_MAE_MPORT_ALLOC_IN_MPORT_TYPE_ALIAS);
3297         MCDI_IN_SET_DWORD(req, MAE_MPORT_ALLOC_ALIAS_IN_DELIVER_MPORT,
3298                           MAE_MPORT_SELECTOR_ASSIGNED);
3299
3300         efx_mcdi_execute(enp, &req);
3301
3302         if (req.emr_rc != 0) {
3303                 rc = req.emr_rc;
3304                 goto fail2;
3305         }
3306
3307         mportp->id = MCDI_OUT_DWORD(req, MAE_MPORT_ALLOC_OUT_MPORT_ID);
3308         if (labelp != NULL)
3309                 *labelp = MCDI_OUT_DWORD(req, MAE_MPORT_ALLOC_ALIAS_OUT_LABEL);
3310
3311         return (0);
3312
3313 fail2:
3314         EFSYS_PROBE(fail2);
3315 fail1:
3316         EFSYS_PROBE1(fail1, efx_rc_t, rc);
3317         return (rc);
3318 }
3319
3320         __checkReturn                   efx_rc_t
3321 efx_mae_mport_free(
3322         __in                            efx_nic_t *enp,
3323         __in                            const efx_mport_id_t *mportp)
3324 {
3325         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3326         efx_mcdi_req_t req;
3327         EFX_MCDI_DECLARE_BUF(payload,
3328             MC_CMD_MAE_MPORT_FREE_IN_LEN,
3329             MC_CMD_MAE_MPORT_FREE_OUT_LEN);
3330         efx_rc_t rc;
3331
3332         if (encp->enc_mae_supported == B_FALSE) {
3333                 rc = ENOTSUP;
3334                 goto fail1;
3335         }
3336
3337         req.emr_cmd = MC_CMD_MAE_MPORT_FREE;
3338         req.emr_in_buf = payload;
3339         req.emr_in_length = MC_CMD_MAE_MPORT_FREE_IN_LEN;
3340         req.emr_out_buf = payload;
3341         req.emr_out_length = MC_CMD_MAE_MPORT_FREE_OUT_LEN;
3342
3343         MCDI_IN_SET_DWORD(req, MAE_MPORT_FREE_IN_MPORT_ID, mportp->id);
3344
3345         efx_mcdi_execute(enp, &req);
3346
3347         if (req.emr_rc != 0) {
3348                 rc = req.emr_rc;
3349                 goto fail2;
3350         }
3351
3352         return (0);
3353
3354 fail2:
3355         EFSYS_PROBE(fail2);
3356 fail1:
3357         EFSYS_PROBE1(fail1, efx_rc_t, rc);
3358         return (rc);
3359 }
3360
3361 static  __checkReturn                   efx_rc_t
3362 efx_mae_read_mport_journal_single(
3363         __in                            uint8_t *entry_buf,
3364         __out                           efx_mport_desc_t *desc)
3365 {
3366         uint32_t pcie_intf;
3367         efx_rc_t rc;
3368
3369         memset(desc, 0, sizeof (*desc));
3370
3371         desc->emd_id.id = MCDI_STRUCT_DWORD(entry_buf,
3372             MAE_MPORT_DESC_V2_MPORT_ID);
3373
3374         desc->emd_can_receive_on = MCDI_STRUCT_DWORD_FIELD(entry_buf,
3375             MAE_MPORT_DESC_V2_FLAGS,
3376             MAE_MPORT_DESC_V2_CAN_RECEIVE_ON);
3377
3378         desc->emd_can_deliver_to = MCDI_STRUCT_DWORD_FIELD(entry_buf,
3379             MAE_MPORT_DESC_V2_FLAGS,
3380             MAE_MPORT_DESC_V2_CAN_DELIVER_TO);
3381
3382         desc->emd_can_delete = MCDI_STRUCT_DWORD_FIELD(entry_buf,
3383             MAE_MPORT_DESC_V2_FLAGS,
3384             MAE_MPORT_DESC_V2_CAN_DELETE);
3385
3386         desc->emd_zombie = MCDI_STRUCT_DWORD_FIELD(entry_buf,
3387             MAE_MPORT_DESC_V2_FLAGS,
3388             MAE_MPORT_DESC_V2_IS_ZOMBIE);
3389
3390         desc->emd_type = MCDI_STRUCT_DWORD(entry_buf,
3391             MAE_MPORT_DESC_V2_MPORT_TYPE);
3392
3393         /*
3394          * We can't check everything here. If some additional checks are
3395          * required, they should be performed by the callback function.
3396          */
3397         switch (desc->emd_type) {
3398         case EFX_MPORT_TYPE_NET_PORT:
3399                 desc->emd_net_port.ep_index =
3400                     MCDI_STRUCT_DWORD(entry_buf,
3401                         MAE_MPORT_DESC_V2_NET_PORT_IDX);
3402                 break;
3403         case EFX_MPORT_TYPE_ALIAS:
3404                 desc->emd_alias.ea_target_mport_id.id =
3405                     MCDI_STRUCT_DWORD(entry_buf,
3406                         MAE_MPORT_DESC_V2_ALIAS_DELIVER_MPORT_ID);
3407                 break;
3408         case EFX_MPORT_TYPE_VNIC:
3409                 desc->emd_vnic.ev_client_type =
3410                     MCDI_STRUCT_DWORD(entry_buf,
3411                         MAE_MPORT_DESC_V2_VNIC_CLIENT_TYPE);
3412                 if (desc->emd_vnic.ev_client_type !=
3413                     EFX_MPORT_VNIC_CLIENT_FUNCTION)
3414                         break;
3415
3416                 pcie_intf = MCDI_STRUCT_DWORD(entry_buf,
3417                     MAE_MPORT_DESC_V2_VNIC_FUNCTION_INTERFACE);
3418                 rc = efx_mcdi_intf_from_pcie(pcie_intf,
3419                     &desc->emd_vnic.ev_intf);
3420                 if (rc != 0)
3421                         goto fail1;
3422
3423                 desc->emd_vnic.ev_pf = MCDI_STRUCT_WORD(entry_buf,
3424                     MAE_MPORT_DESC_V2_VNIC_FUNCTION_PF_IDX);
3425                 desc->emd_vnic.ev_vf = MCDI_STRUCT_WORD(entry_buf,
3426                     MAE_MPORT_DESC_V2_VNIC_FUNCTION_VF_IDX);
3427                 desc->emd_vnic.ev_handle = MCDI_STRUCT_DWORD(entry_buf,
3428                     MAE_MPORT_DESC_V2_VNIC_CLIENT_HANDLE);
3429                 break;
3430         default:
3431                 rc = EINVAL;
3432                 goto fail2;
3433         }
3434
3435         return (0);
3436
3437 fail2:
3438         EFSYS_PROBE(fail2);
3439 fail1:
3440         EFSYS_PROBE1(fail1, efx_rc_t, rc);
3441         return (rc);
3442 }
3443
3444 static  __checkReturn                   efx_rc_t
3445 efx_mae_read_mport_journal_batch(
3446         __in                            efx_nic_t *enp,
3447         __in                            efx_mae_read_mport_journal_cb *cbp,
3448         __in                            void *cb_datap,
3449         __out                           uint32_t *morep)
3450 {
3451         efx_mcdi_req_t req;
3452         EFX_MCDI_DECLARE_BUF(payload,
3453             MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN,
3454             MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2);
3455         uint32_t n_entries;
3456         uint32_t entry_sz;
3457         uint8_t *entry_buf;
3458         unsigned int i;
3459         efx_rc_t rc;
3460
3461         EFX_STATIC_ASSERT(EFX_MPORT_TYPE_NET_PORT ==
3462             MAE_MPORT_DESC_V2_MPORT_TYPE_NET_PORT);
3463         EFX_STATIC_ASSERT(EFX_MPORT_TYPE_ALIAS ==
3464             MAE_MPORT_DESC_V2_MPORT_TYPE_ALIAS);
3465         EFX_STATIC_ASSERT(EFX_MPORT_TYPE_VNIC ==
3466             MAE_MPORT_DESC_V2_MPORT_TYPE_VNIC);
3467
3468         EFX_STATIC_ASSERT(EFX_MPORT_VNIC_CLIENT_FUNCTION ==
3469             MAE_MPORT_DESC_V2_VNIC_CLIENT_TYPE_FUNCTION);
3470         EFX_STATIC_ASSERT(EFX_MPORT_VNIC_CLIENT_PLUGIN ==
3471             MAE_MPORT_DESC_V2_VNIC_CLIENT_TYPE_PLUGIN);
3472
3473         if (cbp == NULL) {
3474                 rc = EINVAL;
3475                 goto fail1;
3476         }
3477
3478         req.emr_cmd = MC_CMD_MAE_MPORT_READ_JOURNAL;
3479         req.emr_in_buf = payload;
3480         req.emr_in_length = MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN;
3481         req.emr_out_buf = payload;
3482         req.emr_out_length = MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2;
3483
3484         MCDI_IN_SET_DWORD(req, MAE_MPORT_READ_JOURNAL_IN_FLAGS, 0);
3485
3486         efx_mcdi_execute(enp, &req);
3487
3488         if (req.emr_rc != 0) {
3489                 rc = req.emr_rc;
3490                 goto fail2;
3491         }
3492
3493         if (req.emr_out_length_used <
3494             MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMIN) {
3495                 rc = EMSGSIZE;
3496                 goto fail3;
3497         }
3498
3499         if (morep != NULL) {
3500                 *morep = MCDI_OUT_DWORD_FIELD(req,
3501                     MAE_MPORT_READ_JOURNAL_OUT_FLAGS,
3502                     MAE_MPORT_READ_JOURNAL_OUT_MORE);
3503         }
3504         n_entries = MCDI_OUT_DWORD(req,
3505             MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_COUNT);
3506         entry_sz = MCDI_OUT_DWORD(req,
3507             MAE_MPORT_READ_JOURNAL_OUT_SIZEOF_MPORT_DESC);
3508         entry_buf = MCDI_OUT2(req, uint8_t,
3509             MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA);
3510
3511         if (entry_sz < MAE_MPORT_DESC_V2_VNIC_CLIENT_HANDLE_OFST +
3512             MAE_MPORT_DESC_V2_VNIC_CLIENT_HANDLE_LEN) {
3513                 rc = EINVAL;
3514                 goto fail4;
3515         }
3516         if (n_entries * entry_sz / entry_sz != n_entries) {
3517                 rc = EINVAL;
3518                 goto fail5;
3519         }
3520         if (req.emr_out_length_used !=
3521             MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMIN + n_entries * entry_sz) {
3522                 rc = EINVAL;
3523                 goto fail6;
3524         }
3525
3526         for (i = 0; i < n_entries; i++) {
3527                 efx_mport_desc_t desc;
3528
3529                 rc = efx_mae_read_mport_journal_single(entry_buf, &desc);
3530                 if (rc != 0)
3531                         continue;
3532
3533                 (*cbp)(cb_datap, &desc, sizeof (desc));
3534                 entry_buf += entry_sz;
3535         }
3536
3537         return (0);
3538
3539 fail6:
3540         EFSYS_PROBE(fail6);
3541 fail5:
3542         EFSYS_PROBE(fail5);
3543 fail4:
3544         EFSYS_PROBE(fail4);
3545 fail3:
3546         EFSYS_PROBE(fail3);
3547 fail2:
3548         EFSYS_PROBE(fail2);
3549 fail1:
3550         EFSYS_PROBE1(fail1, efx_rc_t, rc);
3551         return (rc);
3552 }
3553
3554         __checkReturn                   efx_rc_t
3555 efx_mae_read_mport_journal(
3556         __in                            efx_nic_t *enp,
3557         __in                            efx_mae_read_mport_journal_cb *cbp,
3558         __in                            void *cb_datap)
3559 {
3560         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3561         uint32_t more = 0;
3562         efx_rc_t rc;
3563
3564         if (encp->enc_mae_supported == B_FALSE) {
3565                 rc = ENOTSUP;
3566                 goto fail1;
3567         }
3568
3569         do {
3570                 rc = efx_mae_read_mport_journal_batch(enp, cbp, cb_datap,
3571                     &more);
3572                 if (rc != 0)
3573                         goto fail2;
3574         } while (more != 0);
3575
3576         return (0);
3577
3578 fail2:
3579         EFSYS_PROBE(fail2);
3580 fail1:
3581         EFSYS_PROBE1(fail1, efx_rc_t, rc);
3582         return (rc);
3583 }
3584
3585 #endif /* EFSYS_OPT_MAE */