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