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