common/sfc_efx/base: add API to get mport selector by ID
[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         EFX_STATIC_ASSERT(EFX_PCI_VF_INVALID ==
731             MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL);
732
733         if (pf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_PF_ID)) {
734                 rc = EINVAL;
735                 goto fail1;
736         }
737
738         if (vf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_VF_ID)) {
739                 rc = EINVAL;
740                 goto fail2;
741         }
742
743         EFX_POPULATE_DWORD_3(dword,
744             MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
745             MAE_MPORT_SELECTOR_FUNC_PF_ID, pf,
746             MAE_MPORT_SELECTOR_FUNC_VF_ID, vf);
747
748         memset(mportp, 0, sizeof (*mportp));
749         /*
750          * The constructed DWORD is little-endian,
751          * but the resulting value is meant to be
752          * passed to MCDIs, where it will undergo
753          * host-order to little endian conversion.
754          */
755         mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
756
757         return (0);
758
759 fail2:
760         EFSYS_PROBE(fail2);
761 fail1:
762         EFSYS_PROBE1(fail1, efx_rc_t, rc);
763         return (rc);
764 }
765
766 static  __checkReturn                   efx_rc_t
767 efx_mcdi_mae_mport_lookup(
768         __in                            efx_nic_t *enp,
769         __in                            const efx_mport_sel_t *mport_selectorp,
770         __out                           efx_mport_id_t *mport_idp)
771 {
772         efx_mcdi_req_t req;
773         EFX_MCDI_DECLARE_BUF(payload,
774             MC_CMD_MAE_MPORT_LOOKUP_IN_LEN,
775             MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN);
776         efx_rc_t rc;
777
778         req.emr_cmd = MC_CMD_MAE_MPORT_LOOKUP;
779         req.emr_in_buf = payload;
780         req.emr_in_length = MC_CMD_MAE_MPORT_LOOKUP_IN_LEN;
781         req.emr_out_buf = payload;
782         req.emr_out_length = MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN;
783
784         MCDI_IN_SET_DWORD(req, MAE_MPORT_LOOKUP_IN_MPORT_SELECTOR,
785             mport_selectorp->sel);
786
787         efx_mcdi_execute(enp, &req);
788
789         if (req.emr_rc != 0) {
790                 rc = req.emr_rc;
791                 goto fail1;
792         }
793
794         mport_idp->id = MCDI_OUT_DWORD(req, MAE_MPORT_LOOKUP_OUT_MPORT_ID);
795
796         return (0);
797
798 fail1:
799         EFSYS_PROBE1(fail1, efx_rc_t, rc);
800         return (rc);
801 }
802
803         __checkReturn                   efx_rc_t
804 efx_mae_mport_id_by_selector(
805         __in                            efx_nic_t *enp,
806         __in                            const efx_mport_sel_t *mport_selectorp,
807         __out                           efx_mport_id_t *mport_idp)
808 {
809         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
810         efx_rc_t rc;
811
812         if (encp->enc_mae_supported == B_FALSE) {
813                 rc = ENOTSUP;
814                 goto fail1;
815         }
816
817         rc = efx_mcdi_mae_mport_lookup(enp, mport_selectorp, mport_idp);
818         if (rc != 0)
819                 goto fail2;
820
821         return (0);
822
823 fail2:
824         EFSYS_PROBE(fail2);
825 fail1:
826         EFSYS_PROBE1(fail1, efx_rc_t, rc);
827         return (rc);
828 }
829
830         __checkReturn                   efx_rc_t
831 efx_mae_mport_by_id(
832         __in                            const efx_mport_id_t *mport_idp,
833         __out                           efx_mport_sel_t *mportp)
834 {
835         efx_dword_t dword;
836
837         EFX_POPULATE_DWORD_2(dword,
838             MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_MPORT_ID,
839             MAE_MPORT_SELECTOR_MPORT_ID, mport_idp->id);
840
841         memset(mportp, 0, sizeof (*mportp));
842         mportp->sel = __LE_TO_CPU_32(dword.ed_u32[0]);
843
844         return (0);
845 }
846
847         __checkReturn                   efx_rc_t
848 efx_mae_match_spec_field_set(
849         __in                            efx_mae_match_spec_t *spec,
850         __in                            efx_mae_field_id_t field_id,
851         __in                            size_t value_size,
852         __in_bcount(value_size)         const uint8_t *value,
853         __in                            size_t mask_size,
854         __in_bcount(mask_size)          const uint8_t *mask)
855 {
856         const efx_mae_mv_desc_t *descp;
857         unsigned int desc_set_nentries;
858         uint8_t *mvp;
859         efx_rc_t rc;
860
861         switch (spec->emms_type) {
862         case EFX_MAE_RULE_OUTER:
863                 desc_set_nentries =
864                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
865                 descp = &__efx_mae_outer_rule_mv_desc_set[field_id];
866                 mvp = spec->emms_mask_value_pairs.outer;
867                 break;
868         case EFX_MAE_RULE_ACTION:
869                 desc_set_nentries =
870                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
871                 descp = &__efx_mae_action_rule_mv_desc_set[field_id];
872                 mvp = spec->emms_mask_value_pairs.action;
873                 break;
874         default:
875                 rc = ENOTSUP;
876                 goto fail1;
877         }
878
879         if ((unsigned int)field_id >= desc_set_nentries) {
880                 rc = EINVAL;
881                 goto fail2;
882         }
883
884         if (descp->emmd_mask_size == 0) {
885                 /* The ID points to a gap in the array of field descriptors. */
886                 rc = EINVAL;
887                 goto fail3;
888         }
889
890         if (value_size != descp->emmd_value_size) {
891                 rc = EINVAL;
892                 goto fail4;
893         }
894
895         if (mask_size != descp->emmd_mask_size) {
896                 rc = EINVAL;
897                 goto fail5;
898         }
899
900         if (descp->emmd_endianness == EFX_MAE_FIELD_BE) {
901                 unsigned int i;
902
903                 /*
904                  * The mask/value are in network (big endian) order.
905                  * The MCDI request field is also big endian.
906                  */
907
908                 EFSYS_ASSERT3U(value_size, ==, mask_size);
909
910                 for (i = 0; i < value_size; ++i) {
911                         uint8_t *v_bytep = mvp + descp->emmd_value_offset + i;
912                         uint8_t *m_bytep = mvp + descp->emmd_mask_offset + i;
913
914                         /*
915                          * Apply the mask (which may be all-zeros) to the value.
916                          *
917                          * If this API is provided with some value to set for a
918                          * given field in one specification and with some other
919                          * value to set for this field in another specification,
920                          * then, if the two masks are all-zeros, the field will
921                          * avoid being counted as a mismatch when comparing the
922                          * specifications using efx_mae_match_specs_equal() API.
923                          */
924                         *v_bytep = value[i] & mask[i];
925                         *m_bytep = mask[i];
926                 }
927         } else {
928                 efx_dword_t dword;
929
930                 /*
931                  * The mask/value are in host byte order.
932                  * The MCDI request field is little endian.
933                  */
934                 switch (value_size) {
935                 case 4:
936                         EFX_POPULATE_DWORD_1(dword,
937                             EFX_DWORD_0, *(const uint32_t *)value);
938
939                         memcpy(mvp + descp->emmd_value_offset,
940                             &dword, sizeof (dword));
941                         break;
942                 default:
943                         EFSYS_ASSERT(B_FALSE);
944                 }
945
946                 switch (mask_size) {
947                 case 4:
948                         EFX_POPULATE_DWORD_1(dword,
949                             EFX_DWORD_0, *(const uint32_t *)mask);
950
951                         memcpy(mvp + descp->emmd_mask_offset,
952                             &dword, sizeof (dword));
953                         break;
954                 default:
955                         EFSYS_ASSERT(B_FALSE);
956                 }
957         }
958
959         return (0);
960
961 fail5:
962         EFSYS_PROBE(fail5);
963 fail4:
964         EFSYS_PROBE(fail4);
965 fail3:
966         EFSYS_PROBE(fail3);
967 fail2:
968         EFSYS_PROBE(fail2);
969 fail1:
970         EFSYS_PROBE1(fail1, efx_rc_t, rc);
971         return (rc);
972 }
973
974         __checkReturn                   efx_rc_t
975 efx_mae_match_spec_bit_set(
976         __in                            efx_mae_match_spec_t *spec,
977         __in                            efx_mae_field_id_t field_id,
978         __in                            boolean_t value)
979 {
980         const efx_mae_mv_bit_desc_t *bit_descp;
981         unsigned int bit_desc_set_nentries;
982         unsigned int byte_idx;
983         unsigned int bit_idx;
984         uint8_t *mvp;
985         efx_rc_t rc;
986
987         switch (spec->emms_type) {
988         case EFX_MAE_RULE_OUTER:
989                 bit_desc_set_nentries =
990                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
991                 bit_descp = &__efx_mae_outer_rule_mv_bit_desc_set[field_id];
992                 mvp = spec->emms_mask_value_pairs.outer;
993                 break;
994         case EFX_MAE_RULE_ACTION:
995                 bit_desc_set_nentries =
996                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
997                 bit_descp = &__efx_mae_action_rule_mv_bit_desc_set[field_id];
998                 mvp = spec->emms_mask_value_pairs.action;
999                 break;
1000         default:
1001                 rc = ENOTSUP;
1002                 goto fail1;
1003         }
1004
1005         if ((unsigned int)field_id >= bit_desc_set_nentries) {
1006                 rc = EINVAL;
1007                 goto fail2;
1008         }
1009
1010         if (bit_descp->emmbd_entry_is_valid == B_FALSE) {
1011                 rc = EINVAL;
1012                 goto fail3;
1013         }
1014
1015         byte_idx = bit_descp->emmbd_value_ofst + bit_descp->emmbd_value_lbn / 8;
1016         bit_idx = bit_descp->emmbd_value_lbn % 8;
1017
1018         if (value != B_FALSE)
1019                 mvp[byte_idx] |= (1U << bit_idx);
1020         else
1021                 mvp[byte_idx] &= ~(1U << bit_idx);
1022
1023         byte_idx = bit_descp->emmbd_mask_ofst + bit_descp->emmbd_mask_lbn / 8;
1024         bit_idx = bit_descp->emmbd_mask_lbn % 8;
1025         mvp[byte_idx] |= (1U << bit_idx);
1026
1027         return (0);
1028
1029 fail3:
1030         EFSYS_PROBE(fail3);
1031 fail2:
1032         EFSYS_PROBE(fail2);
1033 fail1:
1034         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1035         return (rc);
1036 }
1037
1038         __checkReturn                   efx_rc_t
1039 efx_mae_match_spec_mport_set(
1040         __in                            efx_mae_match_spec_t *spec,
1041         __in                            const efx_mport_sel_t *valuep,
1042         __in_opt                        const efx_mport_sel_t *maskp)
1043 {
1044         uint32_t full_mask = UINT32_MAX;
1045         const uint8_t *vp;
1046         const uint8_t *mp;
1047         efx_rc_t rc;
1048
1049         if (valuep == NULL) {
1050                 rc = EINVAL;
1051                 goto fail1;
1052         }
1053
1054         vp = (const uint8_t *)&valuep->sel;
1055         if (maskp != NULL)
1056                 mp = (const uint8_t *)&maskp->sel;
1057         else
1058                 mp = (const uint8_t *)&full_mask;
1059
1060         rc = efx_mae_match_spec_field_set(spec,
1061             EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR,
1062             sizeof (valuep->sel), vp, sizeof (maskp->sel), mp);
1063         if (rc != 0)
1064                 goto fail2;
1065
1066         return (0);
1067
1068 fail2:
1069         EFSYS_PROBE(fail2);
1070 fail1:
1071         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1072         return (rc);
1073 }
1074
1075         __checkReturn                   boolean_t
1076 efx_mae_match_specs_equal(
1077         __in                            const efx_mae_match_spec_t *left,
1078         __in                            const efx_mae_match_spec_t *right)
1079 {
1080         return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
1081 }
1082
1083 #define EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit)              \
1084             ((_mask)[(_bit) / (_mask_page_nbits)] &                     \
1085                     (1ULL << ((_bit) & ((_mask_page_nbits) - 1))))
1086
1087 static                                  boolean_t
1088 efx_mask_is_prefix(
1089         __in                            size_t mask_nbytes,
1090         __in_bcount(mask_nbytes)        const uint8_t *maskp)
1091 {
1092         boolean_t prev_bit_is_set = B_TRUE;
1093         unsigned int i;
1094
1095         for (i = 0; i < 8 * mask_nbytes; ++i) {
1096                 boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i);
1097
1098                 if (!prev_bit_is_set && bit_is_set)
1099                         return B_FALSE;
1100
1101                 prev_bit_is_set = bit_is_set;
1102         }
1103
1104         return B_TRUE;
1105 }
1106
1107 static                                  boolean_t
1108 efx_mask_is_all_ones(
1109         __in                            size_t mask_nbytes,
1110         __in_bcount(mask_nbytes)        const uint8_t *maskp)
1111 {
1112         unsigned int i;
1113         uint8_t t = ~0;
1114
1115         for (i = 0; i < mask_nbytes; ++i)
1116                 t &= maskp[i];
1117
1118         return (t == (uint8_t)(~0));
1119 }
1120
1121 static                                  boolean_t
1122 efx_mask_is_all_zeros(
1123         __in                            size_t mask_nbytes,
1124         __in_bcount(mask_nbytes)        const uint8_t *maskp)
1125 {
1126         unsigned int i;
1127         uint8_t t = 0;
1128
1129         for (i = 0; i < mask_nbytes; ++i)
1130                 t |= maskp[i];
1131
1132         return (t == 0);
1133 }
1134
1135         __checkReturn                   boolean_t
1136 efx_mae_match_spec_is_valid(
1137         __in                            efx_nic_t *enp,
1138         __in                            const efx_mae_match_spec_t *spec)
1139 {
1140         efx_mae_t *maep = enp->en_maep;
1141         unsigned int field_ncaps = maep->em_max_nfields;
1142         const efx_mae_field_cap_t *field_caps;
1143         const efx_mae_mv_desc_t *desc_setp;
1144         unsigned int desc_set_nentries;
1145         const efx_mae_mv_bit_desc_t *bit_desc_setp;
1146         unsigned int bit_desc_set_nentries;
1147         boolean_t is_valid = B_TRUE;
1148         efx_mae_field_id_t field_id;
1149         const uint8_t *mvp;
1150
1151         switch (spec->emms_type) {
1152         case EFX_MAE_RULE_OUTER:
1153                 field_caps = maep->em_outer_rule_field_caps;
1154                 desc_setp = __efx_mae_outer_rule_mv_desc_set;
1155                 desc_set_nentries =
1156                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1157                 bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
1158                 bit_desc_set_nentries =
1159                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
1160                 mvp = spec->emms_mask_value_pairs.outer;
1161                 break;
1162         case EFX_MAE_RULE_ACTION:
1163                 field_caps = maep->em_action_rule_field_caps;
1164                 desc_setp = __efx_mae_action_rule_mv_desc_set;
1165                 desc_set_nentries =
1166                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1167                 bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
1168                 bit_desc_set_nentries =
1169                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
1170                 mvp = spec->emms_mask_value_pairs.action;
1171                 break;
1172         default:
1173                 return (B_FALSE);
1174         }
1175
1176         if (field_caps == NULL)
1177                 return (B_FALSE);
1178
1179         for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1180              ++field_id) {
1181                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1182                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1183                 const uint8_t *alt_m_buf = mvp + descp->emmd_alt_mask_offset;
1184                 const uint8_t *m_buf = mvp + descp->emmd_mask_offset;
1185                 size_t alt_m_size = descp->emmd_alt_mask_size;
1186                 size_t m_size = descp->emmd_mask_size;
1187
1188                 if (m_size == 0)
1189                         continue; /* Skip array gap */
1190
1191                 if ((unsigned int)field_cap_id >= field_ncaps) {
1192                         /*
1193                          * The FW has not reported capability status for
1194                          * this field. Make sure that its mask is zeroed.
1195                          */
1196                         is_valid = efx_mask_is_all_zeros(m_size, m_buf);
1197                         if (is_valid != B_FALSE)
1198                                 continue;
1199                         else
1200                                 break;
1201                 }
1202
1203                 switch (field_caps[field_cap_id].emfc_support) {
1204                 case MAE_FIELD_SUPPORTED_MATCH_MASK:
1205                         is_valid = B_TRUE;
1206                         break;
1207                 case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
1208                         is_valid = efx_mask_is_prefix(m_size, m_buf);
1209                         break;
1210                 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
1211                         is_valid = (efx_mask_is_all_ones(m_size, m_buf) ||
1212                             efx_mask_is_all_zeros(m_size, m_buf));
1213                         break;
1214                 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
1215                         is_valid = efx_mask_is_all_ones(m_size, m_buf);
1216
1217                         if ((is_valid == B_FALSE) && (alt_m_size != 0)) {
1218                                 /*
1219                                  * This field has an alternative one. The FW
1220                                  * reports ALWAYS for both implying that one
1221                                  * of them is required to have all-ones mask.
1222                                  *
1223                                  * The primary field's mask is incorrect; go
1224                                  * on to check that of the alternative field.
1225                                  */
1226                                 is_valid = efx_mask_is_all_ones(alt_m_size,
1227                                                                 alt_m_buf);
1228                         }
1229                         break;
1230                 case MAE_FIELD_SUPPORTED_MATCH_NEVER:
1231                 case MAE_FIELD_UNSUPPORTED:
1232                 default:
1233                         is_valid = efx_mask_is_all_zeros(m_size, m_buf);
1234                         break;
1235                 }
1236
1237                 if (is_valid == B_FALSE)
1238                         return (B_FALSE);
1239         }
1240
1241         for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
1242              ++field_id) {
1243                 const efx_mae_mv_bit_desc_t *bit_descp =
1244                     &bit_desc_setp[field_id];
1245                 unsigned int byte_idx =
1246                     bit_descp->emmbd_mask_ofst +
1247                     bit_descp->emmbd_mask_lbn / 8;
1248                 unsigned int bit_idx =
1249                     bit_descp->emmbd_mask_lbn % 8;
1250                 efx_mae_field_cap_id_t bit_cap_id =
1251                     bit_descp->emmbd_bit_cap_id;
1252
1253                 if (bit_descp->emmbd_entry_is_valid == B_FALSE)
1254                         continue; /* Skip array gap */
1255
1256                 if ((unsigned int)bit_cap_id >= field_ncaps) {
1257                         /* No capability for this bit = unsupported. */
1258                         is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0);
1259                         if (is_valid == B_FALSE)
1260                                 break;
1261                         else
1262                                 continue;
1263                 }
1264
1265                 switch (field_caps[bit_cap_id].emfc_support) {
1266                 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
1267                         is_valid = B_TRUE;
1268                         break;
1269                 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
1270                         is_valid = ((mvp[byte_idx] & (1U << bit_idx)) != 0);
1271                         break;
1272                 case MAE_FIELD_SUPPORTED_MATCH_NEVER:
1273                 case MAE_FIELD_UNSUPPORTED:
1274                 default:
1275                         is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0);
1276                         break;
1277                 }
1278
1279                 if (is_valid == B_FALSE)
1280                         break;
1281         }
1282
1283         return (is_valid);
1284 }
1285
1286         __checkReturn                   efx_rc_t
1287 efx_mae_action_set_spec_init(
1288         __in                            efx_nic_t *enp,
1289         __out                           efx_mae_actions_t **specp)
1290 {
1291         efx_mae_actions_t *spec;
1292         efx_rc_t rc;
1293
1294         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
1295         if (spec == NULL) {
1296                 rc = ENOMEM;
1297                 goto fail1;
1298         }
1299
1300         spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
1301         spec->ema_rsrc.emar_counter_id.id = EFX_MAE_RSRC_ID_INVALID;
1302
1303         *specp = spec;
1304
1305         return (0);
1306
1307 fail1:
1308         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1309         return (rc);
1310 }
1311
1312                                         void
1313 efx_mae_action_set_spec_fini(
1314         __in                            efx_nic_t *enp,
1315         __in                            efx_mae_actions_t *spec)
1316 {
1317         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
1318 }
1319
1320 static  __checkReturn                   efx_rc_t
1321 efx_mae_action_set_add_decap(
1322         __in                            efx_mae_actions_t *spec,
1323         __in                            size_t arg_size,
1324         __in_bcount(arg_size)           const uint8_t *arg)
1325 {
1326         efx_rc_t rc;
1327
1328         _NOTE(ARGUNUSED(spec))
1329
1330         if (arg_size != 0) {
1331                 rc = EINVAL;
1332                 goto fail1;
1333         }
1334
1335         if (arg != NULL) {
1336                 rc = EINVAL;
1337                 goto fail2;
1338         }
1339
1340         /* This action does not have any arguments, so do nothing here. */
1341
1342         return (0);
1343
1344 fail2:
1345         EFSYS_PROBE(fail2);
1346 fail1:
1347         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1348         return (rc);
1349 }
1350
1351 static  __checkReturn                   efx_rc_t
1352 efx_mae_action_set_add_vlan_pop(
1353         __in                            efx_mae_actions_t *spec,
1354         __in                            size_t arg_size,
1355         __in_bcount(arg_size)           const uint8_t *arg)
1356 {
1357         efx_rc_t rc;
1358
1359         if (arg_size != 0) {
1360                 rc = EINVAL;
1361                 goto fail1;
1362         }
1363
1364         if (arg != NULL) {
1365                 rc = EINVAL;
1366                 goto fail2;
1367         }
1368
1369         if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) {
1370                 rc = ENOTSUP;
1371                 goto fail3;
1372         }
1373
1374         ++spec->ema_n_vlan_tags_to_pop;
1375
1376         return (0);
1377
1378 fail3:
1379         EFSYS_PROBE(fail3);
1380 fail2:
1381         EFSYS_PROBE(fail2);
1382 fail1:
1383         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1384         return (rc);
1385 }
1386
1387 static  __checkReturn                   efx_rc_t
1388 efx_mae_action_set_add_vlan_push(
1389         __in                            efx_mae_actions_t *spec,
1390         __in                            size_t arg_size,
1391         __in_bcount(arg_size)           const uint8_t *arg)
1392 {
1393         unsigned int n_tags = spec->ema_n_vlan_tags_to_push;
1394         efx_rc_t rc;
1395
1396         if (arg_size != sizeof (*spec->ema_vlan_push_descs)) {
1397                 rc = EINVAL;
1398                 goto fail1;
1399         }
1400
1401         if (arg == NULL) {
1402                 rc = EINVAL;
1403                 goto fail2;
1404         }
1405
1406         if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1407                 rc = ENOTSUP;
1408                 goto fail3;
1409         }
1410
1411         memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size);
1412         ++(spec->ema_n_vlan_tags_to_push);
1413
1414         return (0);
1415
1416 fail3:
1417         EFSYS_PROBE(fail3);
1418 fail2:
1419         EFSYS_PROBE(fail2);
1420 fail1:
1421         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1422         return (rc);
1423 }
1424
1425 static  __checkReturn                   efx_rc_t
1426 efx_mae_action_set_add_encap(
1427         __in                            efx_mae_actions_t *spec,
1428         __in                            size_t arg_size,
1429         __in_bcount(arg_size)           const uint8_t *arg)
1430 {
1431         efx_rc_t rc;
1432
1433         /*
1434          * Adding this specific action to an action set spec and setting encap.
1435          * header ID in the spec are two individual steps. This design allows
1436          * the client driver to avoid encap. header allocation when it simply
1437          * needs to check the order of actions submitted by user ("validate"),
1438          * without actually allocating an action set and inserting a rule.
1439          *
1440          * For now, mark encap. header ID as invalid; the caller will invoke
1441          * efx_mae_action_set_fill_in_eh_id() to override the field prior
1442          * to action set allocation; otherwise, the allocation will fail.
1443          */
1444         spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
1445
1446         /*
1447          * As explained above, there are no arguments to handle here.
1448          * efx_mae_action_set_fill_in_eh_id() will take care of them.
1449          */
1450         if (arg_size != 0) {
1451                 rc = EINVAL;
1452                 goto fail1;
1453         }
1454
1455         if (arg != NULL) {
1456                 rc = EINVAL;
1457                 goto fail2;
1458         }
1459
1460         return (0);
1461
1462 fail2:
1463         EFSYS_PROBE(fail2);
1464 fail1:
1465         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1466         return (rc);
1467 }
1468
1469 static  __checkReturn                   efx_rc_t
1470 efx_mae_action_set_add_count(
1471         __in                            efx_mae_actions_t *spec,
1472         __in                            size_t arg_size,
1473         __in_bcount(arg_size)           const uint8_t *arg)
1474 {
1475         efx_rc_t rc;
1476
1477         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1478                           MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL);
1479
1480         /*
1481          * Preparing an action set spec to update a counter requires
1482          * two steps: first add this action to the action spec, and then
1483          * add the counter ID to the spec. This allows validity checking
1484          * and resource allocation to be done separately.
1485          * Mark the counter ID as invalid in the spec to ensure that the
1486          * caller must also invoke efx_mae_action_set_fill_in_counter_id()
1487          * before action set allocation.
1488          */
1489         spec->ema_rsrc.emar_counter_id.id = EFX_MAE_RSRC_ID_INVALID;
1490
1491         /* Nothing else is supposed to take place over here. */
1492         if (arg_size != 0) {
1493                 rc = EINVAL;
1494                 goto fail1;
1495         }
1496
1497         if (arg != NULL) {
1498                 rc = EINVAL;
1499                 goto fail2;
1500         }
1501
1502         ++(spec->ema_n_count_actions);
1503
1504         return (0);
1505
1506 fail2:
1507         EFSYS_PROBE(fail2);
1508 fail1:
1509         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1510         return (rc);
1511 }
1512
1513 static  __checkReturn                   efx_rc_t
1514 efx_mae_action_set_add_flag(
1515         __in                            efx_mae_actions_t *spec,
1516         __in                            size_t arg_size,
1517         __in_bcount(arg_size)           const uint8_t *arg)
1518 {
1519         efx_rc_t rc;
1520
1521         _NOTE(ARGUNUSED(spec))
1522
1523         if (arg_size != 0) {
1524                 rc = EINVAL;
1525                 goto fail1;
1526         }
1527
1528         if (arg != NULL) {
1529                 rc = EINVAL;
1530                 goto fail2;
1531         }
1532
1533         /* This action does not have any arguments, so do nothing here. */
1534
1535         return (0);
1536
1537 fail2:
1538         EFSYS_PROBE(fail2);
1539 fail1:
1540         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1541         return (rc);
1542 }
1543
1544 static  __checkReturn                   efx_rc_t
1545 efx_mae_action_set_add_mark(
1546         __in                            efx_mae_actions_t *spec,
1547         __in                            size_t arg_size,
1548         __in_bcount(arg_size)           const uint8_t *arg)
1549 {
1550         efx_rc_t rc;
1551
1552         if (arg_size != sizeof (spec->ema_mark_value)) {
1553                 rc = EINVAL;
1554                 goto fail1;
1555         }
1556
1557         if (arg == NULL) {
1558                 rc = EINVAL;
1559                 goto fail2;
1560         }
1561
1562         memcpy(&spec->ema_mark_value, arg, arg_size);
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_deliver(
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         if (arg_size != sizeof (spec->ema_deliver_mport)) {
1582                 rc = EINVAL;
1583                 goto fail1;
1584         }
1585
1586         if (arg == NULL) {
1587                 rc = EINVAL;
1588                 goto fail2;
1589         }
1590
1591         memcpy(&spec->ema_deliver_mport, arg, arg_size);
1592
1593         return (0);
1594
1595 fail2:
1596         EFSYS_PROBE(fail2);
1597 fail1:
1598         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1599         return (rc);
1600 }
1601
1602 typedef struct efx_mae_action_desc_s {
1603         /* Action specific handler */
1604         efx_rc_t        (*emad_add)(efx_mae_actions_t *,
1605                                     size_t, const uint8_t *);
1606 } efx_mae_action_desc_t;
1607
1608 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
1609         [EFX_MAE_ACTION_DECAP] = {
1610                 .emad_add = efx_mae_action_set_add_decap
1611         },
1612         [EFX_MAE_ACTION_VLAN_POP] = {
1613                 .emad_add = efx_mae_action_set_add_vlan_pop
1614         },
1615         [EFX_MAE_ACTION_VLAN_PUSH] = {
1616                 .emad_add = efx_mae_action_set_add_vlan_push
1617         },
1618         [EFX_MAE_ACTION_ENCAP] = {
1619                 .emad_add = efx_mae_action_set_add_encap
1620         },
1621         [EFX_MAE_ACTION_COUNT] = {
1622                 .emad_add = efx_mae_action_set_add_count
1623         },
1624         [EFX_MAE_ACTION_FLAG] = {
1625                 .emad_add = efx_mae_action_set_add_flag
1626         },
1627         [EFX_MAE_ACTION_MARK] = {
1628                 .emad_add = efx_mae_action_set_add_mark
1629         },
1630         [EFX_MAE_ACTION_DELIVER] = {
1631                 .emad_add = efx_mae_action_set_add_deliver
1632         }
1633 };
1634
1635 static const uint32_t efx_mae_action_ordered_map =
1636         (1U << EFX_MAE_ACTION_DECAP) |
1637         (1U << EFX_MAE_ACTION_VLAN_POP) |
1638         (1U << EFX_MAE_ACTION_VLAN_PUSH) |
1639         /*
1640          * HW will conduct action COUNT after
1641          * the matching packet has been modified by
1642          * length-affecting actions except for ENCAP.
1643          */
1644         (1U << EFX_MAE_ACTION_COUNT) |
1645         (1U << EFX_MAE_ACTION_ENCAP) |
1646         (1U << EFX_MAE_ACTION_FLAG) |
1647         (1U << EFX_MAE_ACTION_MARK) |
1648         (1U << EFX_MAE_ACTION_DELIVER);
1649
1650 /*
1651  * These actions must not be added after DELIVER, but
1652  * they can have any place among the rest of
1653  * strictly ordered actions.
1654  */
1655 static const uint32_t efx_mae_action_nonstrict_map =
1656         (1U << EFX_MAE_ACTION_COUNT) |
1657         (1U << EFX_MAE_ACTION_FLAG) |
1658         (1U << EFX_MAE_ACTION_MARK);
1659
1660 static const uint32_t efx_mae_action_repeat_map =
1661         (1U << EFX_MAE_ACTION_VLAN_POP) |
1662         (1U << EFX_MAE_ACTION_VLAN_PUSH) |
1663         (1U << EFX_MAE_ACTION_COUNT);
1664
1665 /*
1666  * Add an action to an action set.
1667  *
1668  * This has to be invoked in the desired action order.
1669  * An out-of-order action request will be turned down.
1670  */
1671 static  __checkReturn                   efx_rc_t
1672 efx_mae_action_set_spec_populate(
1673         __in                            efx_mae_actions_t *spec,
1674         __in                            efx_mae_action_t type,
1675         __in                            size_t arg_size,
1676         __in_bcount(arg_size)           const uint8_t *arg)
1677 {
1678         uint32_t action_mask;
1679         efx_rc_t rc;
1680
1681         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1682             (sizeof (efx_mae_action_ordered_map) * 8));
1683         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1684             (sizeof (efx_mae_action_repeat_map) * 8));
1685
1686         EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
1687         EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK);
1688         EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER);
1689
1690         if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
1691                 rc = EINVAL;
1692                 goto fail1;
1693         }
1694
1695         action_mask = (1U << type);
1696
1697         if ((spec->ema_actions & action_mask) != 0) {
1698                 /* The action set already contains this action. */
1699                 if ((efx_mae_action_repeat_map & action_mask) == 0) {
1700                         /* Cannot add another non-repeatable action. */
1701                         rc = ENOTSUP;
1702                         goto fail2;
1703                 }
1704         }
1705
1706         if ((efx_mae_action_ordered_map & action_mask) != 0) {
1707                 uint32_t strict_ordered_map =
1708                     efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map;
1709                 uint32_t later_actions_mask =
1710                     strict_ordered_map & ~(action_mask | (action_mask - 1));
1711
1712                 if ((spec->ema_actions & later_actions_mask) != 0) {
1713                         /* Cannot add an action after later ordered actions. */
1714                         rc = ENOTSUP;
1715                         goto fail3;
1716                 }
1717         }
1718
1719         if (efx_mae_actions[type].emad_add != NULL) {
1720                 rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
1721                 if (rc != 0)
1722                         goto fail4;
1723         }
1724
1725         spec->ema_actions |= action_mask;
1726
1727         return (0);
1728
1729 fail4:
1730         EFSYS_PROBE(fail4);
1731 fail3:
1732         EFSYS_PROBE(fail3);
1733 fail2:
1734         EFSYS_PROBE(fail2);
1735 fail1:
1736         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1737         return (rc);
1738 }
1739
1740         __checkReturn                   efx_rc_t
1741 efx_mae_action_set_populate_decap(
1742         __in                            efx_mae_actions_t *spec)
1743 {
1744         return (efx_mae_action_set_spec_populate(spec,
1745             EFX_MAE_ACTION_DECAP, 0, NULL));
1746 }
1747
1748         __checkReturn                   efx_rc_t
1749 efx_mae_action_set_populate_vlan_pop(
1750         __in                            efx_mae_actions_t *spec)
1751 {
1752         return (efx_mae_action_set_spec_populate(spec,
1753             EFX_MAE_ACTION_VLAN_POP, 0, NULL));
1754 }
1755
1756         __checkReturn                   efx_rc_t
1757 efx_mae_action_set_populate_vlan_push(
1758         __in                            efx_mae_actions_t *spec,
1759         __in                            uint16_t tpid_be,
1760         __in                            uint16_t tci_be)
1761 {
1762         efx_mae_action_vlan_push_t action;
1763         const uint8_t *arg = (const uint8_t *)&action;
1764
1765         action.emavp_tpid_be = tpid_be;
1766         action.emavp_tci_be = tci_be;
1767
1768         return (efx_mae_action_set_spec_populate(spec,
1769             EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg));
1770 }
1771
1772         __checkReturn                   efx_rc_t
1773 efx_mae_action_set_populate_encap(
1774         __in                            efx_mae_actions_t *spec)
1775 {
1776         /*
1777          * There is no argument to pass encap. header ID, thus, one does not
1778          * need to allocate an encap. header while parsing application input.
1779          * This is useful since building an action set may be done simply to
1780          * validate a rule, whilst resource allocation usually consumes time.
1781          */
1782         return (efx_mae_action_set_spec_populate(spec,
1783             EFX_MAE_ACTION_ENCAP, 0, NULL));
1784 }
1785
1786         __checkReturn                   efx_rc_t
1787 efx_mae_action_set_populate_count(
1788         __in                            efx_mae_actions_t *spec)
1789 {
1790         /*
1791          * There is no argument to pass counter ID, thus, one does not
1792          * need to allocate a counter while parsing application input.
1793          * This is useful since building an action set may be done simply to
1794          * validate a rule, whilst resource allocation usually consumes time.
1795          */
1796         return (efx_mae_action_set_spec_populate(spec,
1797             EFX_MAE_ACTION_COUNT, 0, NULL));
1798 }
1799
1800         __checkReturn                   efx_rc_t
1801 efx_mae_action_set_populate_flag(
1802         __in                            efx_mae_actions_t *spec)
1803 {
1804         return (efx_mae_action_set_spec_populate(spec,
1805             EFX_MAE_ACTION_FLAG, 0, NULL));
1806 }
1807
1808         __checkReturn                   efx_rc_t
1809 efx_mae_action_set_populate_mark(
1810         __in                            efx_mae_actions_t *spec,
1811         __in                            uint32_t mark_value)
1812 {
1813         const uint8_t *arg = (const uint8_t *)&mark_value;
1814
1815         return (efx_mae_action_set_spec_populate(spec,
1816             EFX_MAE_ACTION_MARK, sizeof (mark_value), arg));
1817 }
1818
1819         __checkReturn                   efx_rc_t
1820 efx_mae_action_set_populate_deliver(
1821         __in                            efx_mae_actions_t *spec,
1822         __in                            const efx_mport_sel_t *mportp)
1823 {
1824         const uint8_t *arg;
1825         efx_rc_t rc;
1826
1827         if (mportp == NULL) {
1828                 rc = EINVAL;
1829                 goto fail1;
1830         }
1831
1832         arg = (const uint8_t *)&mportp->sel;
1833
1834         return (efx_mae_action_set_spec_populate(spec,
1835             EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
1836
1837 fail1:
1838         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1839         return (rc);
1840 }
1841
1842         __checkReturn                   efx_rc_t
1843 efx_mae_action_set_populate_drop(
1844         __in                            efx_mae_actions_t *spec)
1845 {
1846         efx_mport_sel_t mport;
1847         const uint8_t *arg;
1848         efx_dword_t dword;
1849
1850         EFX_POPULATE_DWORD_1(dword,
1851             MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL);
1852
1853         /*
1854          * The constructed DWORD is little-endian,
1855          * but the resulting value is meant to be
1856          * passed to MCDIs, where it will undergo
1857          * host-order to little endian conversion.
1858          */
1859         mport.sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
1860
1861         arg = (const uint8_t *)&mport.sel;
1862
1863         return (efx_mae_action_set_spec_populate(spec,
1864             EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg));
1865 }
1866
1867         __checkReturn                   boolean_t
1868 efx_mae_action_set_specs_equal(
1869         __in                            const efx_mae_actions_t *left,
1870         __in                            const efx_mae_actions_t *right)
1871 {
1872         size_t cmp_size = EFX_FIELD_OFFSET(efx_mae_actions_t, ema_rsrc);
1873
1874         /*
1875          * An action set specification consists of two parts. The first part
1876          * indicates what actions are included in the action set, as well as
1877          * extra quantitative values (in example, the number of VLAN tags to
1878          * push). The second part comprises resource IDs used by the actions.
1879          *
1880          * A resource, in example, a counter, is allocated from the hardware
1881          * by the client, and it's the client who is responsible for keeping
1882          * track of allocated resources and comparing resource IDs if needed.
1883          *
1884          * In this API, don't compare resource IDs in the two specifications.
1885          */
1886
1887         return ((memcmp(left, right, cmp_size) == 0) ? B_TRUE : B_FALSE);
1888 }
1889
1890         __checkReturn                   efx_rc_t
1891 efx_mae_match_specs_class_cmp(
1892         __in                            efx_nic_t *enp,
1893         __in                            const efx_mae_match_spec_t *left,
1894         __in                            const efx_mae_match_spec_t *right,
1895         __out                           boolean_t *have_same_classp)
1896 {
1897         efx_mae_t *maep = enp->en_maep;
1898         unsigned int field_ncaps = maep->em_max_nfields;
1899         const efx_mae_field_cap_t *field_caps;
1900         const efx_mae_mv_desc_t *desc_setp;
1901         unsigned int desc_set_nentries;
1902         const efx_mae_mv_bit_desc_t *bit_desc_setp;
1903         unsigned int bit_desc_set_nentries;
1904         boolean_t have_same_class = B_TRUE;
1905         efx_mae_field_id_t field_id;
1906         const uint8_t *mvpl;
1907         const uint8_t *mvpr;
1908         efx_rc_t rc;
1909
1910         switch (left->emms_type) {
1911         case EFX_MAE_RULE_OUTER:
1912                 field_caps = maep->em_outer_rule_field_caps;
1913                 desc_setp = __efx_mae_outer_rule_mv_desc_set;
1914                 desc_set_nentries =
1915                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1916                 bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
1917                 bit_desc_set_nentries =
1918                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
1919                 mvpl = left->emms_mask_value_pairs.outer;
1920                 mvpr = right->emms_mask_value_pairs.outer;
1921                 break;
1922         case EFX_MAE_RULE_ACTION:
1923                 field_caps = maep->em_action_rule_field_caps;
1924                 desc_setp = __efx_mae_action_rule_mv_desc_set;
1925                 desc_set_nentries =
1926                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1927                 bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
1928                 bit_desc_set_nentries =
1929                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
1930                 mvpl = left->emms_mask_value_pairs.action;
1931                 mvpr = right->emms_mask_value_pairs.action;
1932                 break;
1933         default:
1934                 rc = ENOTSUP;
1935                 goto fail1;
1936         }
1937
1938         if (field_caps == NULL) {
1939                 rc = EAGAIN;
1940                 goto fail2;
1941         }
1942
1943         if (left->emms_type != right->emms_type ||
1944             left->emms_prio != right->emms_prio) {
1945                 /*
1946                  * Rules of different types can never map to the same class.
1947                  *
1948                  * The FW can support some set of match criteria for one
1949                  * priority and not support the very same set for
1950                  * another priority. Thus, two rules which have
1951                  * different priorities can never map to
1952                  * the same class.
1953                  */
1954                 *have_same_classp = B_FALSE;
1955                 return (0);
1956         }
1957
1958         for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1959              ++field_id) {
1960                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1961                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1962                 const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
1963                 const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
1964                 size_t mask_size = descp->emmd_mask_size;
1965                 const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
1966                 const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
1967                 size_t value_size = descp->emmd_value_size;
1968
1969                 if (mask_size == 0)
1970                         continue; /* Skip array gap */
1971
1972                 if ((unsigned int)field_cap_id >= field_ncaps) {
1973                         /*
1974                          * The FW has not reported capability status for this
1975                          * field. It's unknown whether any difference between
1976                          * the two masks / values affects the class. The only
1977                          * case when the class must be the same is when these
1978                          * mask-value pairs match. Otherwise, report mismatch.
1979                          */
1980                         if ((memcmp(lmaskp, rmaskp, mask_size) == 0) &&
1981                             (memcmp(lvalp, rvalp, value_size) == 0))
1982                                 continue;
1983                         else
1984                                 break;
1985                 }
1986
1987                 if (field_caps[field_cap_id].emfc_mask_affects_class) {
1988                         if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
1989                                 have_same_class = B_FALSE;
1990                                 break;
1991                         }
1992                 }
1993
1994                 if (field_caps[field_cap_id].emfc_match_affects_class) {
1995                         if (memcmp(lvalp, rvalp, value_size) != 0) {
1996                                 have_same_class = B_FALSE;
1997                                 break;
1998                         }
1999                 }
2000         }
2001
2002         if (have_same_class == B_FALSE)
2003                 goto done;
2004
2005         for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
2006              ++field_id) {
2007                 const efx_mae_mv_bit_desc_t *bit_descp =
2008                     &bit_desc_setp[field_id];
2009                 efx_mae_field_cap_id_t bit_cap_id =
2010                     bit_descp->emmbd_bit_cap_id;
2011                 unsigned int byte_idx;
2012                 unsigned int bit_idx;
2013
2014                 if (bit_descp->emmbd_entry_is_valid == B_FALSE)
2015                         continue; /* Skip array gap */
2016
2017                 if ((unsigned int)bit_cap_id >= field_ncaps)
2018                         break;
2019
2020                 byte_idx =
2021                     bit_descp->emmbd_mask_ofst +
2022                     bit_descp->emmbd_mask_lbn / 8;
2023                 bit_idx =
2024                     bit_descp->emmbd_mask_lbn % 8;
2025
2026                 if (field_caps[bit_cap_id].emfc_mask_affects_class &&
2027                     (mvpl[byte_idx] & (1U << bit_idx)) !=
2028                     (mvpr[byte_idx] & (1U << bit_idx))) {
2029                         have_same_class = B_FALSE;
2030                         break;
2031                 }
2032
2033                 byte_idx =
2034                     bit_descp->emmbd_value_ofst +
2035                     bit_descp->emmbd_value_lbn / 8;
2036                 bit_idx =
2037                     bit_descp->emmbd_value_lbn % 8;
2038
2039                 if (field_caps[bit_cap_id].emfc_match_affects_class &&
2040                     (mvpl[byte_idx] & (1U << bit_idx)) !=
2041                     (mvpr[byte_idx] & (1U << bit_idx))) {
2042                         have_same_class = B_FALSE;
2043                         break;
2044                 }
2045         }
2046
2047 done:
2048         *have_same_classp = have_same_class;
2049
2050         return (0);
2051
2052 fail2:
2053         EFSYS_PROBE(fail2);
2054 fail1:
2055         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2056         return (rc);
2057 }
2058
2059         __checkReturn           efx_rc_t
2060 efx_mae_outer_rule_insert(
2061         __in                    efx_nic_t *enp,
2062         __in                    const efx_mae_match_spec_t *spec,
2063         __in                    efx_tunnel_protocol_t encap_type,
2064         __out                   efx_mae_rule_id_t *or_idp)
2065 {
2066         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2067         efx_mcdi_req_t req;
2068         EFX_MCDI_DECLARE_BUF(payload,
2069             MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2,
2070             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
2071         uint32_t encap_type_mcdi;
2072         efx_mae_rule_id_t or_id;
2073         size_t offset;
2074         efx_rc_t rc;
2075
2076         EFX_STATIC_ASSERT(sizeof (or_idp->id) ==
2077             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN);
2078
2079         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2080             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL);
2081
2082         if (encp->enc_mae_supported == B_FALSE) {
2083                 rc = ENOTSUP;
2084                 goto fail1;
2085         }
2086
2087         if (spec->emms_type != EFX_MAE_RULE_OUTER) {
2088                 rc = EINVAL;
2089                 goto fail2;
2090         }
2091
2092         switch (encap_type) {
2093         case EFX_TUNNEL_PROTOCOL_NONE:
2094                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
2095                 break;
2096         case EFX_TUNNEL_PROTOCOL_VXLAN:
2097                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
2098                 break;
2099         case EFX_TUNNEL_PROTOCOL_GENEVE:
2100                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
2101                 break;
2102         case EFX_TUNNEL_PROTOCOL_NVGRE:
2103                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
2104                 break;
2105         default:
2106                 rc = ENOTSUP;
2107                 goto fail3;
2108         }
2109
2110         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT;
2111         req.emr_in_buf = payload;
2112         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2;
2113         req.emr_out_buf = payload;
2114         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN;
2115
2116         MCDI_IN_SET_DWORD(req,
2117             MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi);
2118
2119         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio);
2120
2121         /*
2122          * Mask-value pairs have been stored in the byte order needed for the
2123          * MCDI request and are thus safe to be copied directly to the buffer.
2124          * The library cares about byte order in efx_mae_match_spec_field_set().
2125          */
2126         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >=
2127             MAE_ENC_FIELD_PAIRS_LEN);
2128         offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST;
2129         memcpy(payload + offset, spec->emms_mask_value_pairs.outer,
2130             MAE_ENC_FIELD_PAIRS_LEN);
2131
2132         efx_mcdi_execute(enp, &req);
2133
2134         if (req.emr_rc != 0) {
2135                 rc = req.emr_rc;
2136                 goto fail4;
2137         }
2138
2139         if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) {
2140                 rc = EMSGSIZE;
2141                 goto fail5;
2142         }
2143
2144         or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
2145         if (or_id.id == EFX_MAE_RSRC_ID_INVALID) {
2146                 rc = ENOENT;
2147                 goto fail6;
2148         }
2149
2150         or_idp->id = or_id.id;
2151
2152         return (0);
2153
2154 fail6:
2155         EFSYS_PROBE(fail6);
2156 fail5:
2157         EFSYS_PROBE(fail5);
2158 fail4:
2159         EFSYS_PROBE(fail4);
2160 fail3:
2161         EFSYS_PROBE(fail3);
2162 fail2:
2163         EFSYS_PROBE(fail2);
2164 fail1:
2165         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2166         return (rc);
2167 }
2168
2169         __checkReturn           efx_rc_t
2170 efx_mae_outer_rule_remove(
2171         __in                    efx_nic_t *enp,
2172         __in                    const efx_mae_rule_id_t *or_idp)
2173 {
2174         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2175         efx_mcdi_req_t req;
2176         EFX_MCDI_DECLARE_BUF(payload,
2177             MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1),
2178             MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
2179         efx_rc_t rc;
2180
2181         if (encp->enc_mae_supported == B_FALSE) {
2182                 rc = ENOTSUP;
2183                 goto fail1;
2184         }
2185
2186         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE;
2187         req.emr_in_buf = payload;
2188         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1);
2189         req.emr_out_buf = payload;
2190         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1);
2191
2192         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id);
2193
2194         efx_mcdi_execute(enp, &req);
2195
2196         if (req.emr_rc != 0) {
2197                 rc = req.emr_rc;
2198                 goto fail2;
2199         }
2200
2201         if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LENMIN) {
2202                 rc = EMSGSIZE;
2203                 goto fail3;
2204         }
2205
2206         if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) !=
2207             or_idp->id) {
2208                 /* Firmware failed to remove the outer rule. */
2209                 rc = EAGAIN;
2210                 goto fail4;
2211         }
2212
2213         return (0);
2214
2215 fail4:
2216         EFSYS_PROBE(fail4);
2217 fail3:
2218         EFSYS_PROBE(fail3);
2219 fail2:
2220         EFSYS_PROBE(fail2);
2221 fail1:
2222         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2223         return (rc);
2224 }
2225
2226         __checkReturn                   efx_rc_t
2227 efx_mae_match_spec_outer_rule_id_set(
2228         __in                            efx_mae_match_spec_t *spec,
2229         __in                            const efx_mae_rule_id_t *or_idp)
2230 {
2231         uint32_t full_mask = UINT32_MAX;
2232         efx_rc_t rc;
2233
2234         if (spec->emms_type != EFX_MAE_RULE_ACTION) {
2235                 rc = EINVAL;
2236                 goto fail1;
2237         }
2238
2239         if (or_idp == NULL) {
2240                 rc = EINVAL;
2241                 goto fail2;
2242         }
2243
2244         rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID,
2245             sizeof (or_idp->id), (const uint8_t *)&or_idp->id,
2246             sizeof (full_mask), (const uint8_t *)&full_mask);
2247         if (rc != 0)
2248                 goto fail3;
2249
2250         return (0);
2251
2252 fail3:
2253         EFSYS_PROBE(fail3);
2254 fail2:
2255         EFSYS_PROBE(fail2);
2256 fail1:
2257         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2258         return (rc);
2259 }
2260
2261          __checkReturn                  efx_rc_t
2262 efx_mae_encap_header_alloc(
2263         __in                            efx_nic_t *enp,
2264         __in                            efx_tunnel_protocol_t encap_type,
2265         __in_bcount(header_size)        uint8_t *header_data,
2266         __in                            size_t header_size,
2267         __out                           efx_mae_eh_id_t *eh_idp)
2268 {
2269         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2270         efx_mcdi_req_t req;
2271         EFX_MCDI_DECLARE_BUF(payload,
2272             MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LENMAX_MCDI2,
2273             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN);
2274         uint32_t encap_type_mcdi;
2275         efx_mae_eh_id_t eh_id;
2276         efx_rc_t rc;
2277
2278         EFX_STATIC_ASSERT(sizeof (eh_idp->id) ==
2279             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_LEN);
2280
2281         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2282             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
2283
2284         if (encp->enc_mae_supported == B_FALSE) {
2285                 rc = ENOTSUP;
2286                 goto fail1;
2287         }
2288
2289         switch (encap_type) {
2290         case EFX_TUNNEL_PROTOCOL_NONE:
2291                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
2292                 break;
2293         case EFX_TUNNEL_PROTOCOL_VXLAN:
2294                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
2295                 break;
2296         case EFX_TUNNEL_PROTOCOL_GENEVE:
2297                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
2298                 break;
2299         case EFX_TUNNEL_PROTOCOL_NVGRE:
2300                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
2301                 break;
2302         default:
2303                 rc = ENOTSUP;
2304                 goto fail2;
2305         }
2306
2307         if (header_size >
2308             MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2) {
2309                 rc = EINVAL;
2310                 goto fail3;
2311         }
2312
2313         req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_ALLOC;
2314         req.emr_in_buf = payload;
2315         req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(header_size);
2316         req.emr_out_buf = payload;
2317         req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN;
2318
2319         MCDI_IN_SET_DWORD(req,
2320             MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, encap_type_mcdi);
2321
2322         memcpy(payload + MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_OFST,
2323             header_data, header_size);
2324
2325         efx_mcdi_execute(enp, &req);
2326
2327         if (req.emr_rc != 0) {
2328                 rc = req.emr_rc;
2329                 goto fail4;
2330         }
2331
2332         if (req.emr_out_length_used < MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN) {
2333                 rc = EMSGSIZE;
2334                 goto fail5;
2335         }
2336
2337         eh_id.id = MCDI_OUT_DWORD(req,
2338             MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID);
2339
2340         if (eh_id.id == EFX_MAE_RSRC_ID_INVALID) {
2341                 rc = ENOENT;
2342                 goto fail6;
2343         }
2344
2345         eh_idp->id = eh_id.id;
2346
2347         return (0);
2348
2349 fail6:
2350         EFSYS_PROBE(fail6);
2351 fail5:
2352         EFSYS_PROBE(fail5);
2353 fail4:
2354         EFSYS_PROBE(fail4);
2355 fail3:
2356         EFSYS_PROBE(fail3);
2357 fail2:
2358         EFSYS_PROBE(fail2);
2359 fail1:
2360         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2361         return (rc);
2362 }
2363
2364         __checkReturn                   efx_rc_t
2365 efx_mae_encap_header_free(
2366         __in                            efx_nic_t *enp,
2367         __in                            const efx_mae_eh_id_t *eh_idp)
2368 {
2369         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2370         efx_mcdi_req_t req;
2371         EFX_MCDI_DECLARE_BUF(payload,
2372             MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1),
2373             MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1));
2374         efx_rc_t rc;
2375
2376         if (encp->enc_mae_supported == B_FALSE) {
2377                 rc = ENOTSUP;
2378                 goto fail1;
2379         }
2380
2381         req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_FREE;
2382         req.emr_in_buf = payload;
2383         req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1);
2384         req.emr_out_buf = payload;
2385         req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1);
2386
2387         MCDI_IN_SET_DWORD(req, MAE_ENCAP_HEADER_FREE_IN_EH_ID, eh_idp->id);
2388
2389         efx_mcdi_execute(enp, &req);
2390
2391         if (req.emr_rc != 0) {
2392                 rc = req.emr_rc;
2393                 goto fail2;
2394         }
2395
2396         if (MCDI_OUT_DWORD(req, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) !=
2397             eh_idp->id) {
2398                 /* Firmware failed to remove the encap. header. */
2399                 rc = EAGAIN;
2400                 goto fail3;
2401         }
2402
2403         return (0);
2404
2405 fail3:
2406         EFSYS_PROBE(fail3);
2407 fail2:
2408         EFSYS_PROBE(fail2);
2409 fail1:
2410         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2411         return (rc);
2412 }
2413
2414         __checkReturn                   efx_rc_t
2415 efx_mae_action_set_fill_in_eh_id(
2416         __in                            efx_mae_actions_t *spec,
2417         __in                            const efx_mae_eh_id_t *eh_idp)
2418 {
2419         efx_rc_t rc;
2420
2421         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) == 0) {
2422                 /*
2423                  * The caller has not intended to have action ENCAP originally,
2424                  * hence, this attempt to indicate encap. header ID is invalid.
2425                  */
2426                 rc = EINVAL;
2427                 goto fail1;
2428         }
2429
2430         if (spec->ema_rsrc.emar_eh_id.id != EFX_MAE_RSRC_ID_INVALID) {
2431                 /* The caller attempts to indicate encap. header ID twice. */
2432                 rc = EINVAL;
2433                 goto fail2;
2434         }
2435
2436         if (eh_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2437                 rc = EINVAL;
2438                 goto fail3;
2439         }
2440
2441         spec->ema_rsrc.emar_eh_id.id = eh_idp->id;
2442
2443         return (0);
2444
2445 fail3:
2446         EFSYS_PROBE(fail3);
2447 fail2:
2448         EFSYS_PROBE(fail2);
2449 fail1:
2450         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2451         return (rc);
2452 }
2453
2454         __checkReturn                   efx_rc_t
2455 efx_mae_action_set_alloc(
2456         __in                            efx_nic_t *enp,
2457         __in                            const efx_mae_actions_t *spec,
2458         __out                           efx_mae_aset_id_t *aset_idp)
2459 {
2460         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2461         efx_mcdi_req_t req;
2462         EFX_MCDI_DECLARE_BUF(payload,
2463             MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
2464             MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
2465         efx_mae_aset_id_t aset_id;
2466         efx_rc_t rc;
2467
2468         if (encp->enc_mae_supported == B_FALSE) {
2469                 rc = ENOTSUP;
2470                 goto fail1;
2471         }
2472
2473         req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
2474         req.emr_in_buf = payload;
2475         req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
2476         req.emr_out_buf = payload;
2477         req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
2478
2479         /*
2480          * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
2481          * corresponding resource types are supported by the implementation.
2482          * Use proper resource ID assignments instead.
2483          */
2484         MCDI_IN_SET_DWORD(req,
2485             MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
2486
2487         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECAP)) != 0) {
2488                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2489                     MAE_ACTION_SET_ALLOC_IN_DECAP, 1);
2490         }
2491
2492         MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2493             MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
2494
2495         if (spec->ema_n_vlan_tags_to_push > 0) {
2496                 unsigned int outer_tag_idx;
2497
2498                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2499                     MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
2500                     spec->ema_n_vlan_tags_to_push);
2501
2502                 if (spec->ema_n_vlan_tags_to_push ==
2503                     EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
2504                         MCDI_IN_SET_WORD(req,
2505                             MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
2506                             spec->ema_vlan_push_descs[0].emavp_tpid_be);
2507                         MCDI_IN_SET_WORD(req,
2508                             MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
2509                             spec->ema_vlan_push_descs[0].emavp_tci_be);
2510                 }
2511
2512                 outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
2513
2514                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
2515                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
2516                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
2517                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
2518         }
2519
2520         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
2521             spec->ema_rsrc.emar_eh_id.id);
2522         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
2523             spec->ema_rsrc.emar_counter_id.id);
2524
2525         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
2526                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2527                     MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
2528         }
2529
2530         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
2531                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2532                     MAE_ACTION_SET_ALLOC_IN_MARK, 1);
2533
2534                 MCDI_IN_SET_DWORD(req,
2535                     MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
2536         }
2537
2538         MCDI_IN_SET_DWORD(req,
2539             MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
2540
2541         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
2542             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2543         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
2544             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2545
2546         efx_mcdi_execute(enp, &req);
2547
2548         if (req.emr_rc != 0) {
2549                 rc = req.emr_rc;
2550                 goto fail2;
2551         }
2552
2553         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
2554                 rc = EMSGSIZE;
2555                 goto fail3;
2556         }
2557
2558         aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
2559         if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
2560                 rc = ENOENT;
2561                 goto fail4;
2562         }
2563
2564         aset_idp->id = aset_id.id;
2565
2566         return (0);
2567
2568 fail4:
2569         EFSYS_PROBE(fail4);
2570 fail3:
2571         EFSYS_PROBE(fail3);
2572 fail2:
2573         EFSYS_PROBE(fail2);
2574 fail1:
2575         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2576         return (rc);
2577 }
2578
2579         __checkReturn                   unsigned int
2580 efx_mae_action_set_get_nb_count(
2581         __in                            const efx_mae_actions_t *spec)
2582 {
2583         return (spec->ema_n_count_actions);
2584 }
2585
2586         __checkReturn                   efx_rc_t
2587 efx_mae_action_set_fill_in_counter_id(
2588         __in                            efx_mae_actions_t *spec,
2589         __in                            const efx_counter_t *counter_idp)
2590 {
2591         efx_rc_t rc;
2592
2593         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_COUNT)) == 0) {
2594                 /*
2595                  * Invalid to add counter ID if spec does not have COUNT action.
2596                  */
2597                 rc = EINVAL;
2598                 goto fail1;
2599         }
2600
2601         if (spec->ema_n_count_actions != 1) {
2602                 /*
2603                  * Having multiple COUNT actions in the spec requires a counter
2604                  * list to be used. This API must only be used for a single
2605                  * counter per spec. Turn down the request as inappropriate.
2606                  */
2607                 rc = EINVAL;
2608                 goto fail2;
2609         }
2610
2611         if (spec->ema_rsrc.emar_counter_id.id != EFX_MAE_RSRC_ID_INVALID) {
2612                 /* The caller attempts to indicate counter ID twice. */
2613                 rc = EALREADY;
2614                 goto fail3;
2615         }
2616
2617         if (counter_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2618                 rc = EINVAL;
2619                 goto fail4;
2620         }
2621
2622         spec->ema_rsrc.emar_counter_id.id = counter_idp->id;
2623
2624         return (0);
2625
2626 fail4:
2627         EFSYS_PROBE(fail4);
2628 fail3:
2629         EFSYS_PROBE(fail3);
2630 fail2:
2631         EFSYS_PROBE(fail2);
2632 fail1:
2633         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2634         return (rc);
2635 }
2636
2637         __checkReturn                   efx_rc_t
2638 efx_mae_counters_alloc(
2639         __in                            efx_nic_t *enp,
2640         __in                            uint32_t n_counters,
2641         __out                           uint32_t *n_allocatedp,
2642         __out_ecount(n_counters)        efx_counter_t *countersp,
2643         __out_opt                       uint32_t *gen_countp)
2644 {
2645         EFX_MCDI_DECLARE_BUF(payload,
2646             MC_CMD_MAE_COUNTER_ALLOC_IN_LEN,
2647             MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMAX_MCDI2);
2648         efx_mae_t *maep = enp->en_maep;
2649         uint32_t n_allocated;
2650         efx_mcdi_req_t req;
2651         unsigned int i;
2652         efx_rc_t rc;
2653
2654         if (n_counters > maep->em_max_ncounters ||
2655             n_counters < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM ||
2656             n_counters > MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MAXNUM_MCDI2) {
2657                 rc = EINVAL;
2658                 goto fail1;
2659         }
2660
2661         req.emr_cmd = MC_CMD_MAE_COUNTER_ALLOC;
2662         req.emr_in_buf = payload;
2663         req.emr_in_length = MC_CMD_MAE_COUNTER_ALLOC_IN_LEN;
2664         req.emr_out_buf = payload;
2665         req.emr_out_length = MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(n_counters);
2666
2667         MCDI_IN_SET_DWORD(req, MAE_COUNTER_ALLOC_IN_REQUESTED_COUNT,
2668             n_counters);
2669
2670         efx_mcdi_execute(enp, &req);
2671
2672         if (req.emr_rc != 0) {
2673                 rc = req.emr_rc;
2674                 goto fail2;
2675         }
2676
2677         if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMIN) {
2678                 rc = EMSGSIZE;
2679                 goto fail3;
2680         }
2681
2682         n_allocated = MCDI_OUT_DWORD(req,
2683             MAE_COUNTER_ALLOC_OUT_COUNTER_ID_COUNT);
2684         if (n_allocated < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM) {
2685                 rc = EFAULT;
2686                 goto fail4;
2687         }
2688
2689         for (i = 0; i < n_allocated; i++) {
2690                 countersp[i].id = MCDI_OUT_INDEXED_DWORD(req,
2691                     MAE_COUNTER_ALLOC_OUT_COUNTER_ID, i);
2692         }
2693
2694         if (gen_countp != NULL) {
2695                 *gen_countp = MCDI_OUT_DWORD(req,
2696                                     MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT);
2697         }
2698
2699         *n_allocatedp = n_allocated;
2700
2701         return (0);
2702
2703 fail4:
2704         EFSYS_PROBE(fail4);
2705 fail3:
2706         EFSYS_PROBE(fail3);
2707 fail2:
2708         EFSYS_PROBE(fail2);
2709 fail1:
2710         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2711
2712         return (rc);
2713 }
2714
2715         __checkReturn                   efx_rc_t
2716 efx_mae_counters_free(
2717         __in                            efx_nic_t *enp,
2718         __in                            uint32_t n_counters,
2719         __out                           uint32_t *n_freedp,
2720         __in_ecount(n_counters)         const efx_counter_t *countersp,
2721         __out_opt                       uint32_t *gen_countp)
2722 {
2723         EFX_MCDI_DECLARE_BUF(payload,
2724             MC_CMD_MAE_COUNTER_FREE_IN_LENMAX_MCDI2,
2725             MC_CMD_MAE_COUNTER_FREE_OUT_LENMAX_MCDI2);
2726         efx_mae_t *maep = enp->en_maep;
2727         efx_mcdi_req_t req;
2728         uint32_t n_freed;
2729         unsigned int i;
2730         efx_rc_t rc;
2731
2732         if (n_counters > maep->em_max_ncounters ||
2733             n_counters < MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MINNUM ||
2734             n_counters >
2735             MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MAXNUM_MCDI2) {
2736                 rc = EINVAL;
2737                 goto fail1;
2738         }
2739
2740         req.emr_cmd = MC_CMD_MAE_COUNTER_FREE;
2741         req.emr_in_buf = payload;
2742         req.emr_in_length = MC_CMD_MAE_COUNTER_FREE_IN_LEN(n_counters);
2743         req.emr_out_buf = payload;
2744         req.emr_out_length = MC_CMD_MAE_COUNTER_FREE_OUT_LEN(n_counters);
2745
2746         for (i = 0; i < n_counters; i++) {
2747                 MCDI_IN_SET_INDEXED_DWORD(req,
2748                     MAE_COUNTER_FREE_IN_FREE_COUNTER_ID, i, countersp[i].id);
2749         }
2750         MCDI_IN_SET_DWORD(req, MAE_COUNTER_FREE_IN_COUNTER_ID_COUNT,
2751                           n_counters);
2752
2753         efx_mcdi_execute(enp, &req);
2754
2755         if (req.emr_rc != 0) {
2756                 rc = req.emr_rc;
2757                 goto fail2;
2758         }
2759
2760         if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_FREE_OUT_LENMIN) {
2761                 rc = EMSGSIZE;
2762                 goto fail3;
2763         }
2764
2765         n_freed = MCDI_OUT_DWORD(req, MAE_COUNTER_FREE_OUT_COUNTER_ID_COUNT);
2766
2767         if (n_freed < MC_CMD_MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID_MINNUM) {
2768                 rc = EFAULT;
2769                 goto fail4;
2770         }
2771
2772         if (gen_countp != NULL) {
2773                 *gen_countp = MCDI_OUT_DWORD(req,
2774                                     MAE_COUNTER_FREE_OUT_GENERATION_COUNT);
2775         }
2776
2777         *n_freedp = n_freed;
2778
2779         return (0);
2780
2781 fail4:
2782         EFSYS_PROBE(fail4);
2783 fail3:
2784         EFSYS_PROBE(fail3);
2785 fail2:
2786         EFSYS_PROBE(fail2);
2787 fail1:
2788         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2789
2790         return (rc);
2791 }
2792
2793         __checkReturn                   efx_rc_t
2794 efx_mae_counters_stream_start(
2795         __in                            efx_nic_t *enp,
2796         __in                            uint16_t rxq_id,
2797         __in                            uint16_t packet_size,
2798         __in                            uint32_t flags_in,
2799         __out                           uint32_t *flags_out)
2800 {
2801         efx_mcdi_req_t req;
2802         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN,
2803                              MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN);
2804         efx_rc_t rc;
2805
2806         EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_IN_ZERO_SQUASH_DISABLE ==
2807             1U << MC_CMD_MAE_COUNTERS_STREAM_START_IN_ZERO_SQUASH_DISABLE_LBN);
2808
2809         EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_OUT_USES_CREDITS ==
2810             1U << MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_LBN);
2811
2812         req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_START;
2813         req.emr_in_buf = payload;
2814         req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN;
2815         req.emr_out_buf = payload;
2816         req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN;
2817
2818         MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_QID, rxq_id);
2819         MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_PACKET_SIZE,
2820                          packet_size);
2821         MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_START_IN_FLAGS, flags_in);
2822
2823         efx_mcdi_execute(enp, &req);
2824
2825         if (req.emr_rc != 0) {
2826                 rc = req.emr_rc;
2827                 goto fail1;
2828         }
2829
2830         if (req.emr_out_length_used <
2831             MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN) {
2832                 rc = EMSGSIZE;
2833                 goto fail2;
2834         }
2835
2836         *flags_out = MCDI_OUT_DWORD(req, MAE_COUNTERS_STREAM_START_OUT_FLAGS);
2837
2838         return (0);
2839
2840 fail2:
2841         EFSYS_PROBE(fail2);
2842 fail1:
2843         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2844
2845         return (rc);
2846 }
2847
2848         __checkReturn                   efx_rc_t
2849 efx_mae_counters_stream_stop(
2850         __in                            efx_nic_t *enp,
2851         __in                            uint16_t rxq_id,
2852         __out_opt                       uint32_t *gen_countp)
2853 {
2854         efx_mcdi_req_t req;
2855         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN,
2856                              MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN);
2857         efx_rc_t rc;
2858
2859         req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_STOP;
2860         req.emr_in_buf = payload;
2861         req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN;
2862         req.emr_out_buf = payload;
2863         req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN;
2864
2865         MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_STOP_IN_QID, rxq_id);
2866
2867         efx_mcdi_execute(enp, &req);
2868
2869         if (req.emr_rc != 0) {
2870                 rc = req.emr_rc;
2871                 goto fail1;
2872         }
2873
2874         if (req.emr_out_length_used <
2875             MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN) {
2876                 rc = EMSGSIZE;
2877                 goto fail2;
2878         }
2879
2880         if (gen_countp != NULL) {
2881                 *gen_countp = MCDI_OUT_DWORD(req,
2882                             MAE_COUNTERS_STREAM_STOP_OUT_GENERATION_COUNT);
2883         }
2884
2885         return (0);
2886
2887 fail2:
2888         EFSYS_PROBE(fail2);
2889 fail1:
2890         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2891
2892         return (rc);
2893 }
2894
2895         __checkReturn                   efx_rc_t
2896 efx_mae_counters_stream_give_credits(
2897         __in                            efx_nic_t *enp,
2898         __in                            uint32_t n_credits)
2899 {
2900         efx_mcdi_req_t req;
2901         EFX_MCDI_DECLARE_BUF(payload,
2902                              MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN,
2903                              MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN);
2904         efx_rc_t rc;
2905
2906         req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS;
2907         req.emr_in_buf = payload;
2908         req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN;
2909         req.emr_out_buf = payload;
2910         req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN;
2911
2912         MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_NUM_CREDITS,
2913                          n_credits);
2914
2915         efx_mcdi_execute(enp, &req);
2916
2917         if (req.emr_rc != 0) {
2918                 rc = req.emr_rc;
2919                 goto fail1;
2920         }
2921
2922         return (0);
2923
2924 fail1:
2925         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2926
2927         return (rc);
2928 }
2929
2930         __checkReturn                   efx_rc_t
2931 efx_mae_action_set_free(
2932         __in                            efx_nic_t *enp,
2933         __in                            const efx_mae_aset_id_t *aset_idp)
2934 {
2935         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2936         efx_mcdi_req_t req;
2937         EFX_MCDI_DECLARE_BUF(payload,
2938             MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
2939             MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
2940         efx_rc_t rc;
2941
2942         if (encp->enc_mae_supported == B_FALSE) {
2943                 rc = ENOTSUP;
2944                 goto fail1;
2945         }
2946
2947         req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
2948         req.emr_in_buf = payload;
2949         req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
2950         req.emr_out_buf = payload;
2951         req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
2952
2953         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
2954
2955         efx_mcdi_execute(enp, &req);
2956
2957         if (req.emr_rc != 0) {
2958                 rc = req.emr_rc;
2959                 goto fail2;
2960         }
2961
2962         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_FREE_OUT_LENMIN) {
2963                 rc = EMSGSIZE;
2964                 goto fail3;
2965         }
2966
2967         if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
2968             aset_idp->id) {
2969                 /* Firmware failed to free the action set. */
2970                 rc = EAGAIN;
2971                 goto fail4;
2972         }
2973
2974         return (0);
2975
2976 fail4:
2977         EFSYS_PROBE(fail4);
2978 fail3:
2979         EFSYS_PROBE(fail3);
2980 fail2:
2981         EFSYS_PROBE(fail2);
2982 fail1:
2983         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2984         return (rc);
2985 }
2986
2987         __checkReturn                   efx_rc_t
2988 efx_mae_action_rule_insert(
2989         __in                            efx_nic_t *enp,
2990         __in                            const efx_mae_match_spec_t *spec,
2991         __in                            const efx_mae_aset_list_id_t *asl_idp,
2992         __in                            const efx_mae_aset_id_t *as_idp,
2993         __out                           efx_mae_rule_id_t *ar_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_RULE_INSERT_IN_LENMAX_MCDI2,
2999             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
3000         efx_oword_t *rule_response;
3001         efx_mae_rule_id_t ar_id;
3002         size_t offset;
3003         efx_rc_t rc;
3004
3005         EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
3006             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
3007
3008         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
3009             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
3010
3011         if (encp->enc_mae_supported == B_FALSE) {
3012                 rc = ENOTSUP;
3013                 goto fail1;
3014         }
3015
3016         if (spec->emms_type != EFX_MAE_RULE_ACTION ||
3017             (asl_idp != NULL && as_idp != NULL) ||
3018             (asl_idp == NULL && as_idp == NULL)) {
3019                 rc = EINVAL;
3020                 goto fail2;
3021         }
3022
3023         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
3024         req.emr_in_buf = payload;
3025         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
3026         req.emr_out_buf = payload;
3027         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
3028
3029         EFX_STATIC_ASSERT(sizeof (*rule_response) <=
3030             MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
3031         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
3032         rule_response = (efx_oword_t *)(payload + offset);
3033         EFX_POPULATE_OWORD_3(*rule_response,
3034             MAE_ACTION_RULE_RESPONSE_ASL_ID,
3035             (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
3036             MAE_ACTION_RULE_RESPONSE_AS_ID,
3037             (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
3038             MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
3039
3040         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
3041
3042         /*
3043          * Mask-value pairs have been stored in the byte order needed for the
3044          * MCDI request and are thus safe to be copied directly to the buffer.
3045          */
3046         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
3047             MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
3048         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
3049         memcpy(payload + offset, spec->emms_mask_value_pairs.action,
3050             MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
3051
3052         efx_mcdi_execute(enp, &req);
3053
3054         if (req.emr_rc != 0) {
3055                 rc = req.emr_rc;
3056                 goto fail3;
3057         }
3058
3059         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
3060                 rc = EMSGSIZE;
3061                 goto fail4;
3062         }
3063
3064         ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
3065         if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
3066                 rc = ENOENT;
3067                 goto fail5;
3068         }
3069
3070         ar_idp->id = ar_id.id;
3071
3072         return (0);
3073
3074 fail5:
3075         EFSYS_PROBE(fail5);
3076 fail4:
3077         EFSYS_PROBE(fail4);
3078 fail3:
3079         EFSYS_PROBE(fail3);
3080 fail2:
3081         EFSYS_PROBE(fail2);
3082 fail1:
3083         EFSYS_PROBE1(fail1, efx_rc_t, rc);
3084         return (rc);
3085 }
3086
3087         __checkReturn                   efx_rc_t
3088 efx_mae_action_rule_remove(
3089         __in                            efx_nic_t *enp,
3090         __in                            const efx_mae_rule_id_t *ar_idp)
3091 {
3092         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3093         efx_mcdi_req_t req;
3094         EFX_MCDI_DECLARE_BUF(payload,
3095             MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
3096             MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
3097         efx_rc_t rc;
3098
3099         if (encp->enc_mae_supported == B_FALSE) {
3100                 rc = ENOTSUP;
3101                 goto fail1;
3102         }
3103
3104         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
3105         req.emr_in_buf = payload;
3106         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
3107         req.emr_out_buf = payload;
3108         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
3109
3110         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
3111
3112         efx_mcdi_execute(enp, &req);
3113
3114         if (req.emr_rc != 0) {
3115                 rc = req.emr_rc;
3116                 goto fail2;
3117         }
3118
3119         if (req.emr_out_length_used <
3120             MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LENMIN) {
3121                 rc = EMSGSIZE;
3122                 goto fail3;
3123         }
3124
3125         if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
3126             ar_idp->id) {
3127                 /* Firmware failed to delete the action rule. */
3128                 rc = EAGAIN;
3129                 goto fail4;
3130         }
3131
3132         return (0);
3133
3134 fail4:
3135         EFSYS_PROBE(fail4);
3136 fail3:
3137         EFSYS_PROBE(fail3);
3138 fail2:
3139         EFSYS_PROBE(fail2);
3140 fail1:
3141         EFSYS_PROBE1(fail1, efx_rc_t, rc);
3142         return (rc);
3143 }
3144
3145 #endif /* EFSYS_OPT_MAE */