common/sfc_efx/base: add counter creation MCDI wrappers
[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
378         return (0);
379
380 fail1:
381         EFSYS_PROBE1(fail1, efx_rc_t, rc);
382         return (rc);
383 }
384
385         __checkReturn                   efx_rc_t
386 efx_mae_match_spec_init(
387         __in                            efx_nic_t *enp,
388         __in                            efx_mae_rule_type_t type,
389         __in                            uint32_t prio,
390         __out                           efx_mae_match_spec_t **specp)
391 {
392         efx_mae_match_spec_t *spec;
393         efx_rc_t rc;
394
395         switch (type) {
396         case EFX_MAE_RULE_OUTER:
397                 break;
398         case EFX_MAE_RULE_ACTION:
399                 break;
400         default:
401                 rc = ENOTSUP;
402                 goto fail1;
403         }
404
405         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
406         if (spec == NULL) {
407                 rc = ENOMEM;
408                 goto fail2;
409         }
410
411         spec->emms_type = type;
412         spec->emms_prio = prio;
413
414         *specp = spec;
415
416         return (0);
417
418 fail2:
419         EFSYS_PROBE(fail2);
420 fail1:
421         EFSYS_PROBE1(fail1, efx_rc_t, rc);
422         return (rc);
423 }
424
425                                         void
426 efx_mae_match_spec_fini(
427         __in                            efx_nic_t *enp,
428         __in                            efx_mae_match_spec_t *spec)
429 {
430         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
431 }
432
433 /* Named identifiers which are valid indices to efx_mae_field_cap_t */
434 typedef enum efx_mae_field_cap_id_e {
435         EFX_MAE_FIELD_ID_INGRESS_MPORT_SELECTOR = MAE_FIELD_INGRESS_PORT,
436         EFX_MAE_FIELD_ID_ETHER_TYPE_BE = MAE_FIELD_ETHER_TYPE,
437         EFX_MAE_FIELD_ID_ETH_SADDR_BE = MAE_FIELD_ETH_SADDR,
438         EFX_MAE_FIELD_ID_ETH_DADDR_BE = MAE_FIELD_ETH_DADDR,
439         EFX_MAE_FIELD_ID_VLAN0_TCI_BE = MAE_FIELD_VLAN0_TCI,
440         EFX_MAE_FIELD_ID_VLAN0_PROTO_BE = MAE_FIELD_VLAN0_PROTO,
441         EFX_MAE_FIELD_ID_VLAN1_TCI_BE = MAE_FIELD_VLAN1_TCI,
442         EFX_MAE_FIELD_ID_VLAN1_PROTO_BE = MAE_FIELD_VLAN1_PROTO,
443         EFX_MAE_FIELD_ID_SRC_IP4_BE = MAE_FIELD_SRC_IP4,
444         EFX_MAE_FIELD_ID_DST_IP4_BE = MAE_FIELD_DST_IP4,
445         EFX_MAE_FIELD_ID_IP_PROTO = MAE_FIELD_IP_PROTO,
446         EFX_MAE_FIELD_ID_IP_TOS = MAE_FIELD_IP_TOS,
447         EFX_MAE_FIELD_ID_IP_TTL = MAE_FIELD_IP_TTL,
448         EFX_MAE_FIELD_ID_SRC_IP6_BE = MAE_FIELD_SRC_IP6,
449         EFX_MAE_FIELD_ID_DST_IP6_BE = MAE_FIELD_DST_IP6,
450         EFX_MAE_FIELD_ID_L4_SPORT_BE = MAE_FIELD_L4_SPORT,
451         EFX_MAE_FIELD_ID_L4_DPORT_BE = MAE_FIELD_L4_DPORT,
452         EFX_MAE_FIELD_ID_TCP_FLAGS_BE = MAE_FIELD_TCP_FLAGS,
453         EFX_MAE_FIELD_ID_ENC_ETHER_TYPE_BE = MAE_FIELD_ENC_ETHER_TYPE,
454         EFX_MAE_FIELD_ID_ENC_ETH_SADDR_BE = MAE_FIELD_ENC_ETH_SADDR,
455         EFX_MAE_FIELD_ID_ENC_ETH_DADDR_BE = MAE_FIELD_ENC_ETH_DADDR,
456         EFX_MAE_FIELD_ID_ENC_VLAN0_TCI_BE = MAE_FIELD_ENC_VLAN0_TCI,
457         EFX_MAE_FIELD_ID_ENC_VLAN0_PROTO_BE = MAE_FIELD_ENC_VLAN0_PROTO,
458         EFX_MAE_FIELD_ID_ENC_VLAN1_TCI_BE = MAE_FIELD_ENC_VLAN1_TCI,
459         EFX_MAE_FIELD_ID_ENC_VLAN1_PROTO_BE = MAE_FIELD_ENC_VLAN1_PROTO,
460         EFX_MAE_FIELD_ID_ENC_SRC_IP4_BE = MAE_FIELD_ENC_SRC_IP4,
461         EFX_MAE_FIELD_ID_ENC_DST_IP4_BE = MAE_FIELD_ENC_DST_IP4,
462         EFX_MAE_FIELD_ID_ENC_IP_PROTO = MAE_FIELD_ENC_IP_PROTO,
463         EFX_MAE_FIELD_ID_ENC_IP_TOS = MAE_FIELD_ENC_IP_TOS,
464         EFX_MAE_FIELD_ID_ENC_IP_TTL = MAE_FIELD_ENC_IP_TTL,
465         EFX_MAE_FIELD_ID_ENC_SRC_IP6_BE = MAE_FIELD_ENC_SRC_IP6,
466         EFX_MAE_FIELD_ID_ENC_DST_IP6_BE = MAE_FIELD_ENC_DST_IP6,
467         EFX_MAE_FIELD_ID_ENC_L4_SPORT_BE = MAE_FIELD_ENC_L4_SPORT,
468         EFX_MAE_FIELD_ID_ENC_L4_DPORT_BE = MAE_FIELD_ENC_L4_DPORT,
469         EFX_MAE_FIELD_ID_ENC_VNET_ID_BE = MAE_FIELD_ENC_VNET_ID,
470         EFX_MAE_FIELD_ID_OUTER_RULE_ID = MAE_FIELD_OUTER_RULE_ID,
471         EFX_MAE_FIELD_ID_HAS_OVLAN = MAE_FIELD_HAS_OVLAN,
472         EFX_MAE_FIELD_ID_HAS_IVLAN = MAE_FIELD_HAS_IVLAN,
473         EFX_MAE_FIELD_ID_ENC_HAS_OVLAN = MAE_FIELD_ENC_HAS_OVLAN,
474         EFX_MAE_FIELD_ID_ENC_HAS_IVLAN = MAE_FIELD_ENC_HAS_IVLAN,
475
476         EFX_MAE_FIELD_CAP_NIDS
477 } efx_mae_field_cap_id_t;
478
479 typedef enum efx_mae_field_endianness_e {
480         EFX_MAE_FIELD_LE = 0,
481         EFX_MAE_FIELD_BE,
482
483         EFX_MAE_FIELD_ENDIANNESS_NTYPES
484 } efx_mae_field_endianness_t;
485
486 /*
487  * The following structure is a means to describe an MAE field.
488  * The information in it is meant to be used internally by
489  * APIs for addressing a given field in a mask-value pairs
490  * structure and for validation purposes.
491  *
492  * A field may have an alternative one. This structure
493  * has additional members to reference the alternative
494  * field's mask. See efx_mae_match_spec_is_valid().
495  */
496 typedef struct efx_mae_mv_desc_s {
497         efx_mae_field_cap_id_t          emmd_field_cap_id;
498
499         size_t                          emmd_value_size;
500         size_t                          emmd_value_offset;
501         size_t                          emmd_mask_size;
502         size_t                          emmd_mask_offset;
503
504         /*
505          * Having the alternative field's mask size set to 0
506          * means that there's no alternative field specified.
507          */
508         size_t                          emmd_alt_mask_size;
509         size_t                          emmd_alt_mask_offset;
510
511         /* Primary field and the alternative one are of the same endianness. */
512         efx_mae_field_endianness_t      emmd_endianness;
513 } efx_mae_mv_desc_t;
514
515 /* Indices to this array are provided by efx_mae_field_id_t */
516 static const efx_mae_mv_desc_t __efx_mae_action_rule_mv_desc_set[] = {
517 #define EFX_MAE_MV_DESC(_name, _endianness)                             \
518         [EFX_MAE_FIELD_##_name] =                                       \
519         {                                                               \
520                 EFX_MAE_FIELD_ID_##_name,                               \
521                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_LEN,               \
522                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_OFST,              \
523                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_LEN,          \
524                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_OFST,         \
525                 0, 0 /* no alternative field */,                        \
526                 _endianness                                             \
527         }
528
529         EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
530         EFX_MAE_MV_DESC(ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
531         EFX_MAE_MV_DESC(ETH_SADDR_BE, EFX_MAE_FIELD_BE),
532         EFX_MAE_MV_DESC(ETH_DADDR_BE, EFX_MAE_FIELD_BE),
533         EFX_MAE_MV_DESC(VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
534         EFX_MAE_MV_DESC(VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
535         EFX_MAE_MV_DESC(VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
536         EFX_MAE_MV_DESC(VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
537         EFX_MAE_MV_DESC(SRC_IP4_BE, EFX_MAE_FIELD_BE),
538         EFX_MAE_MV_DESC(DST_IP4_BE, EFX_MAE_FIELD_BE),
539         EFX_MAE_MV_DESC(IP_PROTO, EFX_MAE_FIELD_BE),
540         EFX_MAE_MV_DESC(IP_TOS, EFX_MAE_FIELD_BE),
541         EFX_MAE_MV_DESC(IP_TTL, EFX_MAE_FIELD_BE),
542         EFX_MAE_MV_DESC(SRC_IP6_BE, EFX_MAE_FIELD_BE),
543         EFX_MAE_MV_DESC(DST_IP6_BE, EFX_MAE_FIELD_BE),
544         EFX_MAE_MV_DESC(L4_SPORT_BE, EFX_MAE_FIELD_BE),
545         EFX_MAE_MV_DESC(L4_DPORT_BE, EFX_MAE_FIELD_BE),
546         EFX_MAE_MV_DESC(TCP_FLAGS_BE, EFX_MAE_FIELD_BE),
547         EFX_MAE_MV_DESC(ENC_VNET_ID_BE, EFX_MAE_FIELD_BE),
548         EFX_MAE_MV_DESC(OUTER_RULE_ID, EFX_MAE_FIELD_LE),
549
550 #undef EFX_MAE_MV_DESC
551 };
552
553 /* Indices to this array are provided by efx_mae_field_id_t */
554 static const efx_mae_mv_desc_t __efx_mae_outer_rule_mv_desc_set[] = {
555 #define EFX_MAE_MV_DESC(_name, _endianness)                             \
556         [EFX_MAE_FIELD_##_name] =                                       \
557         {                                                               \
558                 EFX_MAE_FIELD_ID_##_name,                               \
559                 MAE_ENC_FIELD_PAIRS_##_name##_LEN,                      \
560                 MAE_ENC_FIELD_PAIRS_##_name##_OFST,                     \
561                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,                 \
562                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,                \
563                 0, 0 /* no alternative field */,                        \
564                 _endianness                                             \
565         }
566
567 /* Same as EFX_MAE_MV_DESC(), but also indicates an alternative field. */
568 #define EFX_MAE_MV_DESC_ALT(_name, _alt_name, _endianness)              \
569         [EFX_MAE_FIELD_##_name] =                                       \
570         {                                                               \
571                 EFX_MAE_FIELD_ID_##_name,                               \
572                 MAE_ENC_FIELD_PAIRS_##_name##_LEN,                      \
573                 MAE_ENC_FIELD_PAIRS_##_name##_OFST,                     \
574                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,                 \
575                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,                \
576                 MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_LEN,             \
577                 MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_OFST,            \
578                 _endianness                                             \
579         }
580
581         EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
582         EFX_MAE_MV_DESC(ENC_ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
583         EFX_MAE_MV_DESC(ENC_ETH_SADDR_BE, EFX_MAE_FIELD_BE),
584         EFX_MAE_MV_DESC(ENC_ETH_DADDR_BE, EFX_MAE_FIELD_BE),
585         EFX_MAE_MV_DESC(ENC_VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
586         EFX_MAE_MV_DESC(ENC_VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
587         EFX_MAE_MV_DESC(ENC_VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
588         EFX_MAE_MV_DESC(ENC_VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
589         EFX_MAE_MV_DESC_ALT(ENC_SRC_IP4_BE, ENC_SRC_IP6_BE, EFX_MAE_FIELD_BE),
590         EFX_MAE_MV_DESC_ALT(ENC_DST_IP4_BE, ENC_DST_IP6_BE, EFX_MAE_FIELD_BE),
591         EFX_MAE_MV_DESC(ENC_IP_PROTO, EFX_MAE_FIELD_BE),
592         EFX_MAE_MV_DESC(ENC_IP_TOS, EFX_MAE_FIELD_BE),
593         EFX_MAE_MV_DESC(ENC_IP_TTL, EFX_MAE_FIELD_BE),
594         EFX_MAE_MV_DESC_ALT(ENC_SRC_IP6_BE, ENC_SRC_IP4_BE, EFX_MAE_FIELD_BE),
595         EFX_MAE_MV_DESC_ALT(ENC_DST_IP6_BE, ENC_DST_IP4_BE, EFX_MAE_FIELD_BE),
596         EFX_MAE_MV_DESC(ENC_L4_SPORT_BE, EFX_MAE_FIELD_BE),
597         EFX_MAE_MV_DESC(ENC_L4_DPORT_BE, EFX_MAE_FIELD_BE),
598
599 #undef EFX_MAE_MV_DESC_ALT
600 #undef EFX_MAE_MV_DESC
601 };
602
603 /*
604  * The following structure is a means to describe an MAE bit.
605  * The information in it is meant to be used internally by
606  * APIs for addressing a given flag in a mask-value pairs
607  * structure and for validation purposes.
608  */
609 typedef struct efx_mae_mv_bit_desc_s {
610         /*
611          * Arrays using this struct are indexed by field IDs.
612          * Fields which aren't meant to be referenced by these
613          * arrays comprise gaps (invalid entries). Below field
614          * helps to identify such entries.
615          */
616         boolean_t                       emmbd_entry_is_valid;
617         efx_mae_field_cap_id_t          emmbd_bit_cap_id;
618         size_t                          emmbd_value_ofst;
619         unsigned int                    emmbd_value_lbn;
620         size_t                          emmbd_mask_ofst;
621         unsigned int                    emmbd_mask_lbn;
622 } efx_mae_mv_bit_desc_t;
623
624 static const efx_mae_mv_bit_desc_t __efx_mae_outer_rule_mv_bit_desc_set[] = {
625 #define EFX_MAE_MV_BIT_DESC(_name)                                      \
626         [EFX_MAE_FIELD_##_name] =                                       \
627         {                                                               \
628                 B_TRUE,                                                 \
629                 EFX_MAE_FIELD_ID_##_name,                               \
630                 MAE_ENC_FIELD_PAIRS_##_name##_OFST,                     \
631                 MAE_ENC_FIELD_PAIRS_##_name##_LBN,                      \
632                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,                \
633                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_LBN,                 \
634         }
635
636         EFX_MAE_MV_BIT_DESC(ENC_HAS_OVLAN),
637         EFX_MAE_MV_BIT_DESC(ENC_HAS_IVLAN),
638
639 #undef EFX_MAE_MV_BIT_DESC
640 };
641
642 static const efx_mae_mv_bit_desc_t __efx_mae_action_rule_mv_bit_desc_set[] = {
643 #define EFX_MAE_MV_BIT_DESC(_name)                                      \
644         [EFX_MAE_FIELD_##_name] =                                       \
645         {                                                               \
646                 B_TRUE,                                                 \
647                 EFX_MAE_FIELD_ID_##_name,                               \
648                 MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_OFST,               \
649                 MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LBN,            \
650                 MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK_OFST,          \
651                 MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LBN,            \
652         }
653
654         EFX_MAE_MV_BIT_DESC(HAS_OVLAN),
655         EFX_MAE_MV_BIT_DESC(HAS_IVLAN),
656         EFX_MAE_MV_BIT_DESC(ENC_HAS_OVLAN),
657         EFX_MAE_MV_BIT_DESC(ENC_HAS_IVLAN),
658
659 #undef EFX_MAE_MV_BIT_DESC
660 };
661
662         __checkReturn                   efx_rc_t
663 efx_mae_mport_by_phy_port(
664         __in                            uint32_t phy_port,
665         __out                           efx_mport_sel_t *mportp)
666 {
667         efx_dword_t dword;
668         efx_rc_t rc;
669
670         if (phy_port > EFX_MASK32(MAE_MPORT_SELECTOR_PPORT_ID)) {
671                 rc = EINVAL;
672                 goto fail1;
673         }
674
675         EFX_POPULATE_DWORD_2(dword,
676             MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT,
677             MAE_MPORT_SELECTOR_PPORT_ID, phy_port);
678
679         memset(mportp, 0, sizeof (*mportp));
680         /*
681          * The constructed DWORD is little-endian,
682          * but the resulting value is meant to be
683          * passed to MCDIs, where it will undergo
684          * host-order to little endian conversion.
685          */
686         mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
687
688         return (0);
689
690 fail1:
691         EFSYS_PROBE1(fail1, efx_rc_t, rc);
692         return (rc);
693 }
694
695         __checkReturn                   efx_rc_t
696 efx_mae_mport_by_pcie_function(
697         __in                            uint32_t pf,
698         __in                            uint32_t vf,
699         __out                           efx_mport_sel_t *mportp)
700 {
701         efx_dword_t dword;
702         efx_rc_t rc;
703
704         EFX_STATIC_ASSERT(EFX_PCI_VF_INVALID ==
705             MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL);
706
707         if (pf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_PF_ID)) {
708                 rc = EINVAL;
709                 goto fail1;
710         }
711
712         if (vf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_VF_ID)) {
713                 rc = EINVAL;
714                 goto fail2;
715         }
716
717         EFX_POPULATE_DWORD_3(dword,
718             MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
719             MAE_MPORT_SELECTOR_FUNC_PF_ID, pf,
720             MAE_MPORT_SELECTOR_FUNC_VF_ID, vf);
721
722         memset(mportp, 0, sizeof (*mportp));
723         /*
724          * The constructed DWORD is little-endian,
725          * but the resulting value is meant to be
726          * passed to MCDIs, where it will undergo
727          * host-order to little endian conversion.
728          */
729         mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
730
731         return (0);
732
733 fail2:
734         EFSYS_PROBE(fail2);
735 fail1:
736         EFSYS_PROBE1(fail1, efx_rc_t, rc);
737         return (rc);
738 }
739
740         __checkReturn                   efx_rc_t
741 efx_mae_match_spec_field_set(
742         __in                            efx_mae_match_spec_t *spec,
743         __in                            efx_mae_field_id_t field_id,
744         __in                            size_t value_size,
745         __in_bcount(value_size)         const uint8_t *value,
746         __in                            size_t mask_size,
747         __in_bcount(mask_size)          const uint8_t *mask)
748 {
749         const efx_mae_mv_desc_t *descp;
750         unsigned int desc_set_nentries;
751         uint8_t *mvp;
752         efx_rc_t rc;
753
754         switch (spec->emms_type) {
755         case EFX_MAE_RULE_OUTER:
756                 desc_set_nentries =
757                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
758                 descp = &__efx_mae_outer_rule_mv_desc_set[field_id];
759                 mvp = spec->emms_mask_value_pairs.outer;
760                 break;
761         case EFX_MAE_RULE_ACTION:
762                 desc_set_nentries =
763                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
764                 descp = &__efx_mae_action_rule_mv_desc_set[field_id];
765                 mvp = spec->emms_mask_value_pairs.action;
766                 break;
767         default:
768                 rc = ENOTSUP;
769                 goto fail1;
770         }
771
772         if ((unsigned int)field_id >= desc_set_nentries) {
773                 rc = EINVAL;
774                 goto fail2;
775         }
776
777         if (descp->emmd_mask_size == 0) {
778                 /* The ID points to a gap in the array of field descriptors. */
779                 rc = EINVAL;
780                 goto fail3;
781         }
782
783         if (value_size != descp->emmd_value_size) {
784                 rc = EINVAL;
785                 goto fail4;
786         }
787
788         if (mask_size != descp->emmd_mask_size) {
789                 rc = EINVAL;
790                 goto fail5;
791         }
792
793         if (descp->emmd_endianness == EFX_MAE_FIELD_BE) {
794                 unsigned int i;
795
796                 /*
797                  * The mask/value are in network (big endian) order.
798                  * The MCDI request field is also big endian.
799                  */
800
801                 EFSYS_ASSERT3U(value_size, ==, mask_size);
802
803                 for (i = 0; i < value_size; ++i) {
804                         uint8_t *v_bytep = mvp + descp->emmd_value_offset + i;
805                         uint8_t *m_bytep = mvp + descp->emmd_mask_offset + i;
806
807                         /*
808                          * Apply the mask (which may be all-zeros) to the value.
809                          *
810                          * If this API is provided with some value to set for a
811                          * given field in one specification and with some other
812                          * value to set for this field in another specification,
813                          * then, if the two masks are all-zeros, the field will
814                          * avoid being counted as a mismatch when comparing the
815                          * specifications using efx_mae_match_specs_equal() API.
816                          */
817                         *v_bytep = value[i] & mask[i];
818                         *m_bytep = mask[i];
819                 }
820         } else {
821                 efx_dword_t dword;
822
823                 /*
824                  * The mask/value are in host byte order.
825                  * The MCDI request field is little endian.
826                  */
827                 switch (value_size) {
828                 case 4:
829                         EFX_POPULATE_DWORD_1(dword,
830                             EFX_DWORD_0, *(const uint32_t *)value);
831
832                         memcpy(mvp + descp->emmd_value_offset,
833                             &dword, sizeof (dword));
834                         break;
835                 default:
836                         EFSYS_ASSERT(B_FALSE);
837                 }
838
839                 switch (mask_size) {
840                 case 4:
841                         EFX_POPULATE_DWORD_1(dword,
842                             EFX_DWORD_0, *(const uint32_t *)mask);
843
844                         memcpy(mvp + descp->emmd_mask_offset,
845                             &dword, sizeof (dword));
846                         break;
847                 default:
848                         EFSYS_ASSERT(B_FALSE);
849                 }
850         }
851
852         return (0);
853
854 fail5:
855         EFSYS_PROBE(fail5);
856 fail4:
857         EFSYS_PROBE(fail4);
858 fail3:
859         EFSYS_PROBE(fail3);
860 fail2:
861         EFSYS_PROBE(fail2);
862 fail1:
863         EFSYS_PROBE1(fail1, efx_rc_t, rc);
864         return (rc);
865 }
866
867         __checkReturn                   efx_rc_t
868 efx_mae_match_spec_bit_set(
869         __in                            efx_mae_match_spec_t *spec,
870         __in                            efx_mae_field_id_t field_id,
871         __in                            boolean_t value)
872 {
873         const efx_mae_mv_bit_desc_t *bit_descp;
874         unsigned int bit_desc_set_nentries;
875         unsigned int byte_idx;
876         unsigned int bit_idx;
877         uint8_t *mvp;
878         efx_rc_t rc;
879
880         switch (spec->emms_type) {
881         case EFX_MAE_RULE_OUTER:
882                 bit_desc_set_nentries =
883                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
884                 bit_descp = &__efx_mae_outer_rule_mv_bit_desc_set[field_id];
885                 mvp = spec->emms_mask_value_pairs.outer;
886                 break;
887         case EFX_MAE_RULE_ACTION:
888                 bit_desc_set_nentries =
889                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
890                 bit_descp = &__efx_mae_action_rule_mv_bit_desc_set[field_id];
891                 mvp = spec->emms_mask_value_pairs.action;
892                 break;
893         default:
894                 rc = ENOTSUP;
895                 goto fail1;
896         }
897
898         if ((unsigned int)field_id >= bit_desc_set_nentries) {
899                 rc = EINVAL;
900                 goto fail2;
901         }
902
903         if (bit_descp->emmbd_entry_is_valid == B_FALSE) {
904                 rc = EINVAL;
905                 goto fail3;
906         }
907
908         byte_idx = bit_descp->emmbd_value_ofst + bit_descp->emmbd_value_lbn / 8;
909         bit_idx = bit_descp->emmbd_value_lbn % 8;
910
911         if (value != B_FALSE)
912                 mvp[byte_idx] |= (1U << bit_idx);
913         else
914                 mvp[byte_idx] &= ~(1U << bit_idx);
915
916         byte_idx = bit_descp->emmbd_mask_ofst + bit_descp->emmbd_mask_lbn / 8;
917         bit_idx = bit_descp->emmbd_mask_lbn % 8;
918         mvp[byte_idx] |= (1U << bit_idx);
919
920         return (0);
921
922 fail3:
923         EFSYS_PROBE(fail3);
924 fail2:
925         EFSYS_PROBE(fail2);
926 fail1:
927         EFSYS_PROBE1(fail1, efx_rc_t, rc);
928         return (rc);
929 }
930
931         __checkReturn                   efx_rc_t
932 efx_mae_match_spec_mport_set(
933         __in                            efx_mae_match_spec_t *spec,
934         __in                            const efx_mport_sel_t *valuep,
935         __in_opt                        const efx_mport_sel_t *maskp)
936 {
937         uint32_t full_mask = UINT32_MAX;
938         const uint8_t *vp;
939         const uint8_t *mp;
940         efx_rc_t rc;
941
942         if (valuep == NULL) {
943                 rc = EINVAL;
944                 goto fail1;
945         }
946
947         vp = (const uint8_t *)&valuep->sel;
948         if (maskp != NULL)
949                 mp = (const uint8_t *)&maskp->sel;
950         else
951                 mp = (const uint8_t *)&full_mask;
952
953         rc = efx_mae_match_spec_field_set(spec,
954             EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR,
955             sizeof (valuep->sel), vp, sizeof (maskp->sel), mp);
956         if (rc != 0)
957                 goto fail2;
958
959         return (0);
960
961 fail2:
962         EFSYS_PROBE(fail2);
963 fail1:
964         EFSYS_PROBE1(fail1, efx_rc_t, rc);
965         return (rc);
966 }
967
968         __checkReturn                   boolean_t
969 efx_mae_match_specs_equal(
970         __in                            const efx_mae_match_spec_t *left,
971         __in                            const efx_mae_match_spec_t *right)
972 {
973         return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
974 }
975
976 #define EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit)              \
977             ((_mask)[(_bit) / (_mask_page_nbits)] &                     \
978                     (1ULL << ((_bit) & ((_mask_page_nbits) - 1))))
979
980 static                                  boolean_t
981 efx_mask_is_prefix(
982         __in                            size_t mask_nbytes,
983         __in_bcount(mask_nbytes)        const uint8_t *maskp)
984 {
985         boolean_t prev_bit_is_set = B_TRUE;
986         unsigned int i;
987
988         for (i = 0; i < 8 * mask_nbytes; ++i) {
989                 boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i);
990
991                 if (!prev_bit_is_set && bit_is_set)
992                         return B_FALSE;
993
994                 prev_bit_is_set = bit_is_set;
995         }
996
997         return B_TRUE;
998 }
999
1000 static                                  boolean_t
1001 efx_mask_is_all_ones(
1002         __in                            size_t mask_nbytes,
1003         __in_bcount(mask_nbytes)        const uint8_t *maskp)
1004 {
1005         unsigned int i;
1006         uint8_t t = ~0;
1007
1008         for (i = 0; i < mask_nbytes; ++i)
1009                 t &= maskp[i];
1010
1011         return (t == (uint8_t)(~0));
1012 }
1013
1014 static                                  boolean_t
1015 efx_mask_is_all_zeros(
1016         __in                            size_t mask_nbytes,
1017         __in_bcount(mask_nbytes)        const uint8_t *maskp)
1018 {
1019         unsigned int i;
1020         uint8_t t = 0;
1021
1022         for (i = 0; i < mask_nbytes; ++i)
1023                 t |= maskp[i];
1024
1025         return (t == 0);
1026 }
1027
1028         __checkReturn                   boolean_t
1029 efx_mae_match_spec_is_valid(
1030         __in                            efx_nic_t *enp,
1031         __in                            const efx_mae_match_spec_t *spec)
1032 {
1033         efx_mae_t *maep = enp->en_maep;
1034         unsigned int field_ncaps = maep->em_max_nfields;
1035         const efx_mae_field_cap_t *field_caps;
1036         const efx_mae_mv_desc_t *desc_setp;
1037         unsigned int desc_set_nentries;
1038         const efx_mae_mv_bit_desc_t *bit_desc_setp;
1039         unsigned int bit_desc_set_nentries;
1040         boolean_t is_valid = B_TRUE;
1041         efx_mae_field_id_t field_id;
1042         const uint8_t *mvp;
1043
1044         switch (spec->emms_type) {
1045         case EFX_MAE_RULE_OUTER:
1046                 field_caps = maep->em_outer_rule_field_caps;
1047                 desc_setp = __efx_mae_outer_rule_mv_desc_set;
1048                 desc_set_nentries =
1049                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1050                 bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
1051                 bit_desc_set_nentries =
1052                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
1053                 mvp = spec->emms_mask_value_pairs.outer;
1054                 break;
1055         case EFX_MAE_RULE_ACTION:
1056                 field_caps = maep->em_action_rule_field_caps;
1057                 desc_setp = __efx_mae_action_rule_mv_desc_set;
1058                 desc_set_nentries =
1059                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1060                 bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
1061                 bit_desc_set_nentries =
1062                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
1063                 mvp = spec->emms_mask_value_pairs.action;
1064                 break;
1065         default:
1066                 return (B_FALSE);
1067         }
1068
1069         if (field_caps == NULL)
1070                 return (B_FALSE);
1071
1072         for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1073              ++field_id) {
1074                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1075                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1076                 const uint8_t *alt_m_buf = mvp + descp->emmd_alt_mask_offset;
1077                 const uint8_t *m_buf = mvp + descp->emmd_mask_offset;
1078                 size_t alt_m_size = descp->emmd_alt_mask_size;
1079                 size_t m_size = descp->emmd_mask_size;
1080
1081                 if (m_size == 0)
1082                         continue; /* Skip array gap */
1083
1084                 if ((unsigned int)field_cap_id >= field_ncaps) {
1085                         /*
1086                          * The FW has not reported capability status for
1087                          * this field. Make sure that its mask is zeroed.
1088                          */
1089                         is_valid = efx_mask_is_all_zeros(m_size, m_buf);
1090                         if (is_valid != B_FALSE)
1091                                 continue;
1092                         else
1093                                 break;
1094                 }
1095
1096                 switch (field_caps[field_cap_id].emfc_support) {
1097                 case MAE_FIELD_SUPPORTED_MATCH_MASK:
1098                         is_valid = B_TRUE;
1099                         break;
1100                 case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
1101                         is_valid = efx_mask_is_prefix(m_size, m_buf);
1102                         break;
1103                 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
1104                         is_valid = (efx_mask_is_all_ones(m_size, m_buf) ||
1105                             efx_mask_is_all_zeros(m_size, m_buf));
1106                         break;
1107                 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
1108                         is_valid = efx_mask_is_all_ones(m_size, m_buf);
1109
1110                         if ((is_valid == B_FALSE) && (alt_m_size != 0)) {
1111                                 /*
1112                                  * This field has an alternative one. The FW
1113                                  * reports ALWAYS for both implying that one
1114                                  * of them is required to have all-ones mask.
1115                                  *
1116                                  * The primary field's mask is incorrect; go
1117                                  * on to check that of the alternative field.
1118                                  */
1119                                 is_valid = efx_mask_is_all_ones(alt_m_size,
1120                                                                 alt_m_buf);
1121                         }
1122                         break;
1123                 case MAE_FIELD_SUPPORTED_MATCH_NEVER:
1124                 case MAE_FIELD_UNSUPPORTED:
1125                 default:
1126                         is_valid = efx_mask_is_all_zeros(m_size, m_buf);
1127                         break;
1128                 }
1129
1130                 if (is_valid == B_FALSE)
1131                         return (B_FALSE);
1132         }
1133
1134         for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
1135              ++field_id) {
1136                 const efx_mae_mv_bit_desc_t *bit_descp =
1137                     &bit_desc_setp[field_id];
1138                 unsigned int byte_idx =
1139                     bit_descp->emmbd_mask_ofst +
1140                     bit_descp->emmbd_mask_lbn / 8;
1141                 unsigned int bit_idx =
1142                     bit_descp->emmbd_mask_lbn % 8;
1143                 efx_mae_field_cap_id_t bit_cap_id =
1144                     bit_descp->emmbd_bit_cap_id;
1145
1146                 if (bit_descp->emmbd_entry_is_valid == B_FALSE)
1147                         continue; /* Skip array gap */
1148
1149                 if ((unsigned int)bit_cap_id >= field_ncaps) {
1150                         /* No capability for this bit = unsupported. */
1151                         is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0);
1152                         if (is_valid == B_FALSE)
1153                                 break;
1154                         else
1155                                 continue;
1156                 }
1157
1158                 switch (field_caps[bit_cap_id].emfc_support) {
1159                 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
1160                         is_valid = B_TRUE;
1161                         break;
1162                 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
1163                         is_valid = ((mvp[byte_idx] & (1U << bit_idx)) != 0);
1164                         break;
1165                 case MAE_FIELD_SUPPORTED_MATCH_NEVER:
1166                 case MAE_FIELD_UNSUPPORTED:
1167                 default:
1168                         is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0);
1169                         break;
1170                 }
1171
1172                 if (is_valid == B_FALSE)
1173                         break;
1174         }
1175
1176         return (is_valid);
1177 }
1178
1179         __checkReturn                   efx_rc_t
1180 efx_mae_action_set_spec_init(
1181         __in                            efx_nic_t *enp,
1182         __out                           efx_mae_actions_t **specp)
1183 {
1184         efx_mae_actions_t *spec;
1185         efx_rc_t rc;
1186
1187         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
1188         if (spec == NULL) {
1189                 rc = ENOMEM;
1190                 goto fail1;
1191         }
1192
1193         spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
1194
1195         *specp = spec;
1196
1197         return (0);
1198
1199 fail1:
1200         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1201         return (rc);
1202 }
1203
1204                                         void
1205 efx_mae_action_set_spec_fini(
1206         __in                            efx_nic_t *enp,
1207         __in                            efx_mae_actions_t *spec)
1208 {
1209         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
1210 }
1211
1212 static  __checkReturn                   efx_rc_t
1213 efx_mae_action_set_add_decap(
1214         __in                            efx_mae_actions_t *spec,
1215         __in                            size_t arg_size,
1216         __in_bcount(arg_size)           const uint8_t *arg)
1217 {
1218         efx_rc_t rc;
1219
1220         _NOTE(ARGUNUSED(spec))
1221
1222         if (arg_size != 0) {
1223                 rc = EINVAL;
1224                 goto fail1;
1225         }
1226
1227         if (arg != NULL) {
1228                 rc = EINVAL;
1229                 goto fail2;
1230         }
1231
1232         /* This action does not have any arguments, so do nothing here. */
1233
1234         return (0);
1235
1236 fail2:
1237         EFSYS_PROBE(fail2);
1238 fail1:
1239         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1240         return (rc);
1241 }
1242
1243 static  __checkReturn                   efx_rc_t
1244 efx_mae_action_set_add_vlan_pop(
1245         __in                            efx_mae_actions_t *spec,
1246         __in                            size_t arg_size,
1247         __in_bcount(arg_size)           const uint8_t *arg)
1248 {
1249         efx_rc_t rc;
1250
1251         if (arg_size != 0) {
1252                 rc = EINVAL;
1253                 goto fail1;
1254         }
1255
1256         if (arg != NULL) {
1257                 rc = EINVAL;
1258                 goto fail2;
1259         }
1260
1261         if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) {
1262                 rc = ENOTSUP;
1263                 goto fail3;
1264         }
1265
1266         ++spec->ema_n_vlan_tags_to_pop;
1267
1268         return (0);
1269
1270 fail3:
1271         EFSYS_PROBE(fail3);
1272 fail2:
1273         EFSYS_PROBE(fail2);
1274 fail1:
1275         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1276         return (rc);
1277 }
1278
1279 static  __checkReturn                   efx_rc_t
1280 efx_mae_action_set_add_vlan_push(
1281         __in                            efx_mae_actions_t *spec,
1282         __in                            size_t arg_size,
1283         __in_bcount(arg_size)           const uint8_t *arg)
1284 {
1285         unsigned int n_tags = spec->ema_n_vlan_tags_to_push;
1286         efx_rc_t rc;
1287
1288         if (arg_size != sizeof (*spec->ema_vlan_push_descs)) {
1289                 rc = EINVAL;
1290                 goto fail1;
1291         }
1292
1293         if (arg == NULL) {
1294                 rc = EINVAL;
1295                 goto fail2;
1296         }
1297
1298         if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1299                 rc = ENOTSUP;
1300                 goto fail3;
1301         }
1302
1303         memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size);
1304         ++(spec->ema_n_vlan_tags_to_push);
1305
1306         return (0);
1307
1308 fail3:
1309         EFSYS_PROBE(fail3);
1310 fail2:
1311         EFSYS_PROBE(fail2);
1312 fail1:
1313         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1314         return (rc);
1315 }
1316
1317 static  __checkReturn                   efx_rc_t
1318 efx_mae_action_set_add_encap(
1319         __in                            efx_mae_actions_t *spec,
1320         __in                            size_t arg_size,
1321         __in_bcount(arg_size)           const uint8_t *arg)
1322 {
1323         efx_rc_t rc;
1324
1325         /*
1326          * Adding this specific action to an action set spec and setting encap.
1327          * header ID in the spec are two individual steps. This design allows
1328          * the client driver to avoid encap. header allocation when it simply
1329          * needs to check the order of actions submitted by user ("validate"),
1330          * without actually allocating an action set and inserting a rule.
1331          *
1332          * For now, mark encap. header ID as invalid; the caller will invoke
1333          * efx_mae_action_set_fill_in_eh_id() to override the field prior
1334          * to action set allocation; otherwise, the allocation will fail.
1335          */
1336         spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
1337
1338         /*
1339          * As explained above, there are no arguments to handle here.
1340          * efx_mae_action_set_fill_in_eh_id() will take care of them.
1341          */
1342         if (arg_size != 0) {
1343                 rc = EINVAL;
1344                 goto fail1;
1345         }
1346
1347         if (arg != NULL) {
1348                 rc = EINVAL;
1349                 goto fail2;
1350         }
1351
1352         return (0);
1353
1354 fail2:
1355         EFSYS_PROBE(fail2);
1356 fail1:
1357         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1358         return (rc);
1359 }
1360
1361 static  __checkReturn                   efx_rc_t
1362 efx_mae_action_set_add_flag(
1363         __in                            efx_mae_actions_t *spec,
1364         __in                            size_t arg_size,
1365         __in_bcount(arg_size)           const uint8_t *arg)
1366 {
1367         efx_rc_t rc;
1368
1369         _NOTE(ARGUNUSED(spec))
1370
1371         if (arg_size != 0) {
1372                 rc = EINVAL;
1373                 goto fail1;
1374         }
1375
1376         if (arg != NULL) {
1377                 rc = EINVAL;
1378                 goto fail2;
1379         }
1380
1381         /* This action does not have any arguments, so do nothing here. */
1382
1383         return (0);
1384
1385 fail2:
1386         EFSYS_PROBE(fail2);
1387 fail1:
1388         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1389         return (rc);
1390 }
1391
1392 static  __checkReturn                   efx_rc_t
1393 efx_mae_action_set_add_mark(
1394         __in                            efx_mae_actions_t *spec,
1395         __in                            size_t arg_size,
1396         __in_bcount(arg_size)           const uint8_t *arg)
1397 {
1398         efx_rc_t rc;
1399
1400         if (arg_size != sizeof (spec->ema_mark_value)) {
1401                 rc = EINVAL;
1402                 goto fail1;
1403         }
1404
1405         if (arg == NULL) {
1406                 rc = EINVAL;
1407                 goto fail2;
1408         }
1409
1410         memcpy(&spec->ema_mark_value, arg, arg_size);
1411
1412         return (0);
1413
1414 fail2:
1415         EFSYS_PROBE(fail2);
1416 fail1:
1417         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1418         return (rc);
1419 }
1420
1421 static  __checkReturn                   efx_rc_t
1422 efx_mae_action_set_add_deliver(
1423         __in                            efx_mae_actions_t *spec,
1424         __in                            size_t arg_size,
1425         __in_bcount(arg_size)           const uint8_t *arg)
1426 {
1427         efx_rc_t rc;
1428
1429         if (arg_size != sizeof (spec->ema_deliver_mport)) {
1430                 rc = EINVAL;
1431                 goto fail1;
1432         }
1433
1434         if (arg == NULL) {
1435                 rc = EINVAL;
1436                 goto fail2;
1437         }
1438
1439         memcpy(&spec->ema_deliver_mport, arg, arg_size);
1440
1441         return (0);
1442
1443 fail2:
1444         EFSYS_PROBE(fail2);
1445 fail1:
1446         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1447         return (rc);
1448 }
1449
1450 typedef struct efx_mae_action_desc_s {
1451         /* Action specific handler */
1452         efx_rc_t        (*emad_add)(efx_mae_actions_t *,
1453                                     size_t, const uint8_t *);
1454 } efx_mae_action_desc_t;
1455
1456 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
1457         [EFX_MAE_ACTION_DECAP] = {
1458                 .emad_add = efx_mae_action_set_add_decap
1459         },
1460         [EFX_MAE_ACTION_VLAN_POP] = {
1461                 .emad_add = efx_mae_action_set_add_vlan_pop
1462         },
1463         [EFX_MAE_ACTION_VLAN_PUSH] = {
1464                 .emad_add = efx_mae_action_set_add_vlan_push
1465         },
1466         [EFX_MAE_ACTION_ENCAP] = {
1467                 .emad_add = efx_mae_action_set_add_encap
1468         },
1469         [EFX_MAE_ACTION_FLAG] = {
1470                 .emad_add = efx_mae_action_set_add_flag
1471         },
1472         [EFX_MAE_ACTION_MARK] = {
1473                 .emad_add = efx_mae_action_set_add_mark
1474         },
1475         [EFX_MAE_ACTION_DELIVER] = {
1476                 .emad_add = efx_mae_action_set_add_deliver
1477         }
1478 };
1479
1480 static const uint32_t efx_mae_action_ordered_map =
1481         (1U << EFX_MAE_ACTION_DECAP) |
1482         (1U << EFX_MAE_ACTION_VLAN_POP) |
1483         (1U << EFX_MAE_ACTION_VLAN_PUSH) |
1484         (1U << EFX_MAE_ACTION_ENCAP) |
1485         (1U << EFX_MAE_ACTION_FLAG) |
1486         (1U << EFX_MAE_ACTION_MARK) |
1487         (1U << EFX_MAE_ACTION_DELIVER);
1488
1489 /*
1490  * These actions must not be added after DELIVER, but
1491  * they can have any place among the rest of
1492  * strictly ordered actions.
1493  */
1494 static const uint32_t efx_mae_action_nonstrict_map =
1495         (1U << EFX_MAE_ACTION_FLAG) |
1496         (1U << EFX_MAE_ACTION_MARK);
1497
1498 static const uint32_t efx_mae_action_repeat_map =
1499         (1U << EFX_MAE_ACTION_VLAN_POP) |
1500         (1U << EFX_MAE_ACTION_VLAN_PUSH);
1501
1502 /*
1503  * Add an action to an action set.
1504  *
1505  * This has to be invoked in the desired action order.
1506  * An out-of-order action request will be turned down.
1507  */
1508 static  __checkReturn                   efx_rc_t
1509 efx_mae_action_set_spec_populate(
1510         __in                            efx_mae_actions_t *spec,
1511         __in                            efx_mae_action_t type,
1512         __in                            size_t arg_size,
1513         __in_bcount(arg_size)           const uint8_t *arg)
1514 {
1515         uint32_t action_mask;
1516         efx_rc_t rc;
1517
1518         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1519             (sizeof (efx_mae_action_ordered_map) * 8));
1520         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1521             (sizeof (efx_mae_action_repeat_map) * 8));
1522
1523         EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
1524         EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK);
1525         EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER);
1526
1527         if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
1528                 rc = EINVAL;
1529                 goto fail1;
1530         }
1531
1532         action_mask = (1U << type);
1533
1534         if ((spec->ema_actions & action_mask) != 0) {
1535                 /* The action set already contains this action. */
1536                 if ((efx_mae_action_repeat_map & action_mask) == 0) {
1537                         /* Cannot add another non-repeatable action. */
1538                         rc = ENOTSUP;
1539                         goto fail2;
1540                 }
1541         }
1542
1543         if ((efx_mae_action_ordered_map & action_mask) != 0) {
1544                 uint32_t strict_ordered_map =
1545                     efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map;
1546                 uint32_t later_actions_mask =
1547                     strict_ordered_map & ~(action_mask | (action_mask - 1));
1548
1549                 if ((spec->ema_actions & later_actions_mask) != 0) {
1550                         /* Cannot add an action after later ordered actions. */
1551                         rc = ENOTSUP;
1552                         goto fail3;
1553                 }
1554         }
1555
1556         if (efx_mae_actions[type].emad_add != NULL) {
1557                 rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
1558                 if (rc != 0)
1559                         goto fail4;
1560         }
1561
1562         spec->ema_actions |= action_mask;
1563
1564         return (0);
1565
1566 fail4:
1567         EFSYS_PROBE(fail4);
1568 fail3:
1569         EFSYS_PROBE(fail3);
1570 fail2:
1571         EFSYS_PROBE(fail2);
1572 fail1:
1573         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1574         return (rc);
1575 }
1576
1577         __checkReturn                   efx_rc_t
1578 efx_mae_action_set_populate_decap(
1579         __in                            efx_mae_actions_t *spec)
1580 {
1581         return (efx_mae_action_set_spec_populate(spec,
1582             EFX_MAE_ACTION_DECAP, 0, NULL));
1583 }
1584
1585         __checkReturn                   efx_rc_t
1586 efx_mae_action_set_populate_vlan_pop(
1587         __in                            efx_mae_actions_t *spec)
1588 {
1589         return (efx_mae_action_set_spec_populate(spec,
1590             EFX_MAE_ACTION_VLAN_POP, 0, NULL));
1591 }
1592
1593         __checkReturn                   efx_rc_t
1594 efx_mae_action_set_populate_vlan_push(
1595         __in                            efx_mae_actions_t *spec,
1596         __in                            uint16_t tpid_be,
1597         __in                            uint16_t tci_be)
1598 {
1599         efx_mae_action_vlan_push_t action;
1600         const uint8_t *arg = (const uint8_t *)&action;
1601
1602         action.emavp_tpid_be = tpid_be;
1603         action.emavp_tci_be = tci_be;
1604
1605         return (efx_mae_action_set_spec_populate(spec,
1606             EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg));
1607 }
1608
1609         __checkReturn                   efx_rc_t
1610 efx_mae_action_set_populate_encap(
1611         __in                            efx_mae_actions_t *spec)
1612 {
1613         /*
1614          * There is no argument to pass encap. header ID, thus, one does not
1615          * need to allocate an encap. header while parsing application input.
1616          * This is useful since building an action set may be done simply to
1617          * validate a rule, whilst resource allocation usually consumes time.
1618          */
1619         return (efx_mae_action_set_spec_populate(spec,
1620             EFX_MAE_ACTION_ENCAP, 0, NULL));
1621 }
1622
1623         __checkReturn                   efx_rc_t
1624 efx_mae_action_set_populate_flag(
1625         __in                            efx_mae_actions_t *spec)
1626 {
1627         return (efx_mae_action_set_spec_populate(spec,
1628             EFX_MAE_ACTION_FLAG, 0, NULL));
1629 }
1630
1631         __checkReturn                   efx_rc_t
1632 efx_mae_action_set_populate_mark(
1633         __in                            efx_mae_actions_t *spec,
1634         __in                            uint32_t mark_value)
1635 {
1636         const uint8_t *arg = (const uint8_t *)&mark_value;
1637
1638         return (efx_mae_action_set_spec_populate(spec,
1639             EFX_MAE_ACTION_MARK, sizeof (mark_value), arg));
1640 }
1641
1642         __checkReturn                   efx_rc_t
1643 efx_mae_action_set_populate_deliver(
1644         __in                            efx_mae_actions_t *spec,
1645         __in                            const efx_mport_sel_t *mportp)
1646 {
1647         const uint8_t *arg;
1648         efx_rc_t rc;
1649
1650         if (mportp == NULL) {
1651                 rc = EINVAL;
1652                 goto fail1;
1653         }
1654
1655         arg = (const uint8_t *)&mportp->sel;
1656
1657         return (efx_mae_action_set_spec_populate(spec,
1658             EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
1659
1660 fail1:
1661         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1662         return (rc);
1663 }
1664
1665         __checkReturn                   efx_rc_t
1666 efx_mae_action_set_populate_drop(
1667         __in                            efx_mae_actions_t *spec)
1668 {
1669         efx_mport_sel_t mport;
1670         const uint8_t *arg;
1671         efx_dword_t dword;
1672
1673         EFX_POPULATE_DWORD_1(dword,
1674             MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL);
1675
1676         /*
1677          * The constructed DWORD is little-endian,
1678          * but the resulting value is meant to be
1679          * passed to MCDIs, where it will undergo
1680          * host-order to little endian conversion.
1681          */
1682         mport.sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
1683
1684         arg = (const uint8_t *)&mport.sel;
1685
1686         return (efx_mae_action_set_spec_populate(spec,
1687             EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg));
1688 }
1689
1690         __checkReturn                   boolean_t
1691 efx_mae_action_set_specs_equal(
1692         __in                            const efx_mae_actions_t *left,
1693         __in                            const efx_mae_actions_t *right)
1694 {
1695         size_t cmp_size = EFX_FIELD_OFFSET(efx_mae_actions_t, ema_rsrc);
1696
1697         /*
1698          * An action set specification consists of two parts. The first part
1699          * indicates what actions are included in the action set, as well as
1700          * extra quantitative values (in example, the number of VLAN tags to
1701          * push). The second part comprises resource IDs used by the actions.
1702          *
1703          * A resource, in example, a counter, is allocated from the hardware
1704          * by the client, and it's the client who is responsible for keeping
1705          * track of allocated resources and comparing resource IDs if needed.
1706          *
1707          * In this API, don't compare resource IDs in the two specifications.
1708          */
1709
1710         return ((memcmp(left, right, cmp_size) == 0) ? B_TRUE : B_FALSE);
1711 }
1712
1713         __checkReturn                   efx_rc_t
1714 efx_mae_match_specs_class_cmp(
1715         __in                            efx_nic_t *enp,
1716         __in                            const efx_mae_match_spec_t *left,
1717         __in                            const efx_mae_match_spec_t *right,
1718         __out                           boolean_t *have_same_classp)
1719 {
1720         efx_mae_t *maep = enp->en_maep;
1721         unsigned int field_ncaps = maep->em_max_nfields;
1722         const efx_mae_field_cap_t *field_caps;
1723         const efx_mae_mv_desc_t *desc_setp;
1724         unsigned int desc_set_nentries;
1725         const efx_mae_mv_bit_desc_t *bit_desc_setp;
1726         unsigned int bit_desc_set_nentries;
1727         boolean_t have_same_class = B_TRUE;
1728         efx_mae_field_id_t field_id;
1729         const uint8_t *mvpl;
1730         const uint8_t *mvpr;
1731         efx_rc_t rc;
1732
1733         switch (left->emms_type) {
1734         case EFX_MAE_RULE_OUTER:
1735                 field_caps = maep->em_outer_rule_field_caps;
1736                 desc_setp = __efx_mae_outer_rule_mv_desc_set;
1737                 desc_set_nentries =
1738                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1739                 bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
1740                 bit_desc_set_nentries =
1741                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
1742                 mvpl = left->emms_mask_value_pairs.outer;
1743                 mvpr = right->emms_mask_value_pairs.outer;
1744                 break;
1745         case EFX_MAE_RULE_ACTION:
1746                 field_caps = maep->em_action_rule_field_caps;
1747                 desc_setp = __efx_mae_action_rule_mv_desc_set;
1748                 desc_set_nentries =
1749                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1750                 bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
1751                 bit_desc_set_nentries =
1752                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
1753                 mvpl = left->emms_mask_value_pairs.action;
1754                 mvpr = right->emms_mask_value_pairs.action;
1755                 break;
1756         default:
1757                 rc = ENOTSUP;
1758                 goto fail1;
1759         }
1760
1761         if (field_caps == NULL) {
1762                 rc = EAGAIN;
1763                 goto fail2;
1764         }
1765
1766         if (left->emms_type != right->emms_type ||
1767             left->emms_prio != right->emms_prio) {
1768                 /*
1769                  * Rules of different types can never map to the same class.
1770                  *
1771                  * The FW can support some set of match criteria for one
1772                  * priority and not support the very same set for
1773                  * another priority. Thus, two rules which have
1774                  * different priorities can never map to
1775                  * the same class.
1776                  */
1777                 *have_same_classp = B_FALSE;
1778                 return (0);
1779         }
1780
1781         for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1782              ++field_id) {
1783                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1784                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1785                 const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
1786                 const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
1787                 size_t mask_size = descp->emmd_mask_size;
1788                 const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
1789                 const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
1790                 size_t value_size = descp->emmd_value_size;
1791
1792                 if (mask_size == 0)
1793                         continue; /* Skip array gap */
1794
1795                 if ((unsigned int)field_cap_id >= field_ncaps) {
1796                         /*
1797                          * The FW has not reported capability status for this
1798                          * field. It's unknown whether any difference between
1799                          * the two masks / values affects the class. The only
1800                          * case when the class must be the same is when these
1801                          * mask-value pairs match. Otherwise, report mismatch.
1802                          */
1803                         if ((memcmp(lmaskp, rmaskp, mask_size) == 0) &&
1804                             (memcmp(lvalp, rvalp, value_size) == 0))
1805                                 continue;
1806                         else
1807                                 break;
1808                 }
1809
1810                 if (field_caps[field_cap_id].emfc_mask_affects_class) {
1811                         if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
1812                                 have_same_class = B_FALSE;
1813                                 break;
1814                         }
1815                 }
1816
1817                 if (field_caps[field_cap_id].emfc_match_affects_class) {
1818                         if (memcmp(lvalp, rvalp, value_size) != 0) {
1819                                 have_same_class = B_FALSE;
1820                                 break;
1821                         }
1822                 }
1823         }
1824
1825         if (have_same_class == B_FALSE)
1826                 goto done;
1827
1828         for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
1829              ++field_id) {
1830                 const efx_mae_mv_bit_desc_t *bit_descp =
1831                     &bit_desc_setp[field_id];
1832                 efx_mae_field_cap_id_t bit_cap_id =
1833                     bit_descp->emmbd_bit_cap_id;
1834                 unsigned int byte_idx;
1835                 unsigned int bit_idx;
1836
1837                 if (bit_descp->emmbd_entry_is_valid == B_FALSE)
1838                         continue; /* Skip array gap */
1839
1840                 if ((unsigned int)bit_cap_id >= field_ncaps)
1841                         break;
1842
1843                 byte_idx =
1844                     bit_descp->emmbd_mask_ofst +
1845                     bit_descp->emmbd_mask_lbn / 8;
1846                 bit_idx =
1847                     bit_descp->emmbd_mask_lbn % 8;
1848
1849                 if (field_caps[bit_cap_id].emfc_mask_affects_class &&
1850                     (mvpl[byte_idx] & (1U << bit_idx)) !=
1851                     (mvpr[byte_idx] & (1U << bit_idx))) {
1852                         have_same_class = B_FALSE;
1853                         break;
1854                 }
1855
1856                 byte_idx =
1857                     bit_descp->emmbd_value_ofst +
1858                     bit_descp->emmbd_value_lbn / 8;
1859                 bit_idx =
1860                     bit_descp->emmbd_value_lbn % 8;
1861
1862                 if (field_caps[bit_cap_id].emfc_match_affects_class &&
1863                     (mvpl[byte_idx] & (1U << bit_idx)) !=
1864                     (mvpr[byte_idx] & (1U << bit_idx))) {
1865                         have_same_class = B_FALSE;
1866                         break;
1867                 }
1868         }
1869
1870 done:
1871         *have_same_classp = have_same_class;
1872
1873         return (0);
1874
1875 fail2:
1876         EFSYS_PROBE(fail2);
1877 fail1:
1878         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1879         return (rc);
1880 }
1881
1882         __checkReturn           efx_rc_t
1883 efx_mae_outer_rule_insert(
1884         __in                    efx_nic_t *enp,
1885         __in                    const efx_mae_match_spec_t *spec,
1886         __in                    efx_tunnel_protocol_t encap_type,
1887         __out                   efx_mae_rule_id_t *or_idp)
1888 {
1889         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1890         efx_mcdi_req_t req;
1891         EFX_MCDI_DECLARE_BUF(payload,
1892             MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2,
1893             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
1894         uint32_t encap_type_mcdi;
1895         efx_mae_rule_id_t or_id;
1896         size_t offset;
1897         efx_rc_t rc;
1898
1899         EFX_STATIC_ASSERT(sizeof (or_idp->id) ==
1900             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN);
1901
1902         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1903             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL);
1904
1905         if (encp->enc_mae_supported == B_FALSE) {
1906                 rc = ENOTSUP;
1907                 goto fail1;
1908         }
1909
1910         if (spec->emms_type != EFX_MAE_RULE_OUTER) {
1911                 rc = EINVAL;
1912                 goto fail2;
1913         }
1914
1915         switch (encap_type) {
1916         case EFX_TUNNEL_PROTOCOL_NONE:
1917                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
1918                 break;
1919         case EFX_TUNNEL_PROTOCOL_VXLAN:
1920                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
1921                 break;
1922         case EFX_TUNNEL_PROTOCOL_GENEVE:
1923                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
1924                 break;
1925         case EFX_TUNNEL_PROTOCOL_NVGRE:
1926                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
1927                 break;
1928         default:
1929                 rc = ENOTSUP;
1930                 goto fail3;
1931         }
1932
1933         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT;
1934         req.emr_in_buf = payload;
1935         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2;
1936         req.emr_out_buf = payload;
1937         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN;
1938
1939         MCDI_IN_SET_DWORD(req,
1940             MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi);
1941
1942         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio);
1943
1944         /*
1945          * Mask-value pairs have been stored in the byte order needed for the
1946          * MCDI request and are thus safe to be copied directly to the buffer.
1947          * The library cares about byte order in efx_mae_match_spec_field_set().
1948          */
1949         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >=
1950             MAE_ENC_FIELD_PAIRS_LEN);
1951         offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST;
1952         memcpy(payload + offset, spec->emms_mask_value_pairs.outer,
1953             MAE_ENC_FIELD_PAIRS_LEN);
1954
1955         efx_mcdi_execute(enp, &req);
1956
1957         if (req.emr_rc != 0) {
1958                 rc = req.emr_rc;
1959                 goto fail4;
1960         }
1961
1962         if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) {
1963                 rc = EMSGSIZE;
1964                 goto fail5;
1965         }
1966
1967         or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
1968         if (or_id.id == EFX_MAE_RSRC_ID_INVALID) {
1969                 rc = ENOENT;
1970                 goto fail6;
1971         }
1972
1973         or_idp->id = or_id.id;
1974
1975         return (0);
1976
1977 fail6:
1978         EFSYS_PROBE(fail6);
1979 fail5:
1980         EFSYS_PROBE(fail5);
1981 fail4:
1982         EFSYS_PROBE(fail4);
1983 fail3:
1984         EFSYS_PROBE(fail3);
1985 fail2:
1986         EFSYS_PROBE(fail2);
1987 fail1:
1988         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1989         return (rc);
1990 }
1991
1992         __checkReturn           efx_rc_t
1993 efx_mae_outer_rule_remove(
1994         __in                    efx_nic_t *enp,
1995         __in                    const efx_mae_rule_id_t *or_idp)
1996 {
1997         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1998         efx_mcdi_req_t req;
1999         EFX_MCDI_DECLARE_BUF(payload,
2000             MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1),
2001             MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
2002         efx_rc_t rc;
2003
2004         if (encp->enc_mae_supported == B_FALSE) {
2005                 rc = ENOTSUP;
2006                 goto fail1;
2007         }
2008
2009         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE;
2010         req.emr_in_buf = payload;
2011         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1);
2012         req.emr_out_buf = payload;
2013         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1);
2014
2015         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id);
2016
2017         efx_mcdi_execute(enp, &req);
2018
2019         if (req.emr_rc != 0) {
2020                 rc = req.emr_rc;
2021                 goto fail2;
2022         }
2023
2024         if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LENMIN) {
2025                 rc = EMSGSIZE;
2026                 goto fail3;
2027         }
2028
2029         if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) !=
2030             or_idp->id) {
2031                 /* Firmware failed to remove the outer rule. */
2032                 rc = EAGAIN;
2033                 goto fail4;
2034         }
2035
2036         return (0);
2037
2038 fail4:
2039         EFSYS_PROBE(fail4);
2040 fail3:
2041         EFSYS_PROBE(fail3);
2042 fail2:
2043         EFSYS_PROBE(fail2);
2044 fail1:
2045         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2046         return (rc);
2047 }
2048
2049         __checkReturn                   efx_rc_t
2050 efx_mae_match_spec_outer_rule_id_set(
2051         __in                            efx_mae_match_spec_t *spec,
2052         __in                            const efx_mae_rule_id_t *or_idp)
2053 {
2054         uint32_t full_mask = UINT32_MAX;
2055         efx_rc_t rc;
2056
2057         if (spec->emms_type != EFX_MAE_RULE_ACTION) {
2058                 rc = EINVAL;
2059                 goto fail1;
2060         }
2061
2062         if (or_idp == NULL) {
2063                 rc = EINVAL;
2064                 goto fail2;
2065         }
2066
2067         rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID,
2068             sizeof (or_idp->id), (const uint8_t *)&or_idp->id,
2069             sizeof (full_mask), (const uint8_t *)&full_mask);
2070         if (rc != 0)
2071                 goto fail3;
2072
2073         return (0);
2074
2075 fail3:
2076         EFSYS_PROBE(fail3);
2077 fail2:
2078         EFSYS_PROBE(fail2);
2079 fail1:
2080         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2081         return (rc);
2082 }
2083
2084          __checkReturn                  efx_rc_t
2085 efx_mae_encap_header_alloc(
2086         __in                            efx_nic_t *enp,
2087         __in                            efx_tunnel_protocol_t encap_type,
2088         __in_bcount(header_size)        uint8_t *header_data,
2089         __in                            size_t header_size,
2090         __out                           efx_mae_eh_id_t *eh_idp)
2091 {
2092         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2093         efx_mcdi_req_t req;
2094         EFX_MCDI_DECLARE_BUF(payload,
2095             MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LENMAX_MCDI2,
2096             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN);
2097         uint32_t encap_type_mcdi;
2098         efx_mae_eh_id_t eh_id;
2099         efx_rc_t rc;
2100
2101         EFX_STATIC_ASSERT(sizeof (eh_idp->id) ==
2102             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_LEN);
2103
2104         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2105             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
2106
2107         if (encp->enc_mae_supported == B_FALSE) {
2108                 rc = ENOTSUP;
2109                 goto fail1;
2110         }
2111
2112         switch (encap_type) {
2113         case EFX_TUNNEL_PROTOCOL_NONE:
2114                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
2115                 break;
2116         case EFX_TUNNEL_PROTOCOL_VXLAN:
2117                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
2118                 break;
2119         case EFX_TUNNEL_PROTOCOL_GENEVE:
2120                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
2121                 break;
2122         case EFX_TUNNEL_PROTOCOL_NVGRE:
2123                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
2124                 break;
2125         default:
2126                 rc = ENOTSUP;
2127                 goto fail2;
2128         }
2129
2130         if (header_size >
2131             MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2) {
2132                 rc = EINVAL;
2133                 goto fail3;
2134         }
2135
2136         req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_ALLOC;
2137         req.emr_in_buf = payload;
2138         req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(header_size);
2139         req.emr_out_buf = payload;
2140         req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN;
2141
2142         MCDI_IN_SET_DWORD(req,
2143             MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, encap_type_mcdi);
2144
2145         memcpy(payload + MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_OFST,
2146             header_data, header_size);
2147
2148         efx_mcdi_execute(enp, &req);
2149
2150         if (req.emr_rc != 0) {
2151                 rc = req.emr_rc;
2152                 goto fail4;
2153         }
2154
2155         if (req.emr_out_length_used < MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN) {
2156                 rc = EMSGSIZE;
2157                 goto fail5;
2158         }
2159
2160         eh_id.id = MCDI_OUT_DWORD(req,
2161             MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID);
2162
2163         if (eh_id.id == EFX_MAE_RSRC_ID_INVALID) {
2164                 rc = ENOENT;
2165                 goto fail6;
2166         }
2167
2168         eh_idp->id = eh_id.id;
2169
2170         return (0);
2171
2172 fail6:
2173         EFSYS_PROBE(fail6);
2174 fail5:
2175         EFSYS_PROBE(fail5);
2176 fail4:
2177         EFSYS_PROBE(fail4);
2178 fail3:
2179         EFSYS_PROBE(fail3);
2180 fail2:
2181         EFSYS_PROBE(fail2);
2182 fail1:
2183         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2184         return (rc);
2185 }
2186
2187         __checkReturn                   efx_rc_t
2188 efx_mae_encap_header_free(
2189         __in                            efx_nic_t *enp,
2190         __in                            const efx_mae_eh_id_t *eh_idp)
2191 {
2192         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2193         efx_mcdi_req_t req;
2194         EFX_MCDI_DECLARE_BUF(payload,
2195             MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1),
2196             MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1));
2197         efx_rc_t rc;
2198
2199         if (encp->enc_mae_supported == B_FALSE) {
2200                 rc = ENOTSUP;
2201                 goto fail1;
2202         }
2203
2204         req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_FREE;
2205         req.emr_in_buf = payload;
2206         req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1);
2207         req.emr_out_buf = payload;
2208         req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1);
2209
2210         MCDI_IN_SET_DWORD(req, MAE_ENCAP_HEADER_FREE_IN_EH_ID, eh_idp->id);
2211
2212         efx_mcdi_execute(enp, &req);
2213
2214         if (req.emr_rc != 0) {
2215                 rc = req.emr_rc;
2216                 goto fail2;
2217         }
2218
2219         if (MCDI_OUT_DWORD(req, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) !=
2220             eh_idp->id) {
2221                 /* Firmware failed to remove the encap. header. */
2222                 rc = EAGAIN;
2223                 goto fail3;
2224         }
2225
2226         return (0);
2227
2228 fail3:
2229         EFSYS_PROBE(fail3);
2230 fail2:
2231         EFSYS_PROBE(fail2);
2232 fail1:
2233         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2234         return (rc);
2235 }
2236
2237         __checkReturn                   efx_rc_t
2238 efx_mae_action_set_fill_in_eh_id(
2239         __in                            efx_mae_actions_t *spec,
2240         __in                            const efx_mae_eh_id_t *eh_idp)
2241 {
2242         efx_rc_t rc;
2243
2244         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) == 0) {
2245                 /*
2246                  * The caller has not intended to have action ENCAP originally,
2247                  * hence, this attempt to indicate encap. header ID is invalid.
2248                  */
2249                 rc = EINVAL;
2250                 goto fail1;
2251         }
2252
2253         if (spec->ema_rsrc.emar_eh_id.id != EFX_MAE_RSRC_ID_INVALID) {
2254                 /* The caller attempts to indicate encap. header ID twice. */
2255                 rc = EINVAL;
2256                 goto fail2;
2257         }
2258
2259         if (eh_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2260                 rc = EINVAL;
2261                 goto fail3;
2262         }
2263
2264         spec->ema_rsrc.emar_eh_id.id = eh_idp->id;
2265
2266         return (0);
2267
2268 fail3:
2269         EFSYS_PROBE(fail3);
2270 fail2:
2271         EFSYS_PROBE(fail2);
2272 fail1:
2273         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2274         return (rc);
2275 }
2276
2277         __checkReturn                   efx_rc_t
2278 efx_mae_action_set_alloc(
2279         __in                            efx_nic_t *enp,
2280         __in                            const efx_mae_actions_t *spec,
2281         __out                           efx_mae_aset_id_t *aset_idp)
2282 {
2283         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2284         efx_mcdi_req_t req;
2285         EFX_MCDI_DECLARE_BUF(payload,
2286             MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
2287             MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
2288         efx_mae_aset_id_t aset_id;
2289         efx_rc_t rc;
2290
2291         if (encp->enc_mae_supported == B_FALSE) {
2292                 rc = ENOTSUP;
2293                 goto fail1;
2294         }
2295
2296         req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
2297         req.emr_in_buf = payload;
2298         req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
2299         req.emr_out_buf = payload;
2300         req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
2301
2302         /*
2303          * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
2304          * corresponding resource types are supported by the implementation.
2305          * Use proper resource ID assignments instead.
2306          */
2307         MCDI_IN_SET_DWORD(req,
2308             MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
2309         MCDI_IN_SET_DWORD(req,
2310             MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
2311
2312         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECAP)) != 0) {
2313                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2314                     MAE_ACTION_SET_ALLOC_IN_DECAP, 1);
2315         }
2316
2317         MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2318             MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
2319
2320         if (spec->ema_n_vlan_tags_to_push > 0) {
2321                 unsigned int outer_tag_idx;
2322
2323                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2324                     MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
2325                     spec->ema_n_vlan_tags_to_push);
2326
2327                 if (spec->ema_n_vlan_tags_to_push ==
2328                     EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
2329                         MCDI_IN_SET_WORD(req,
2330                             MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
2331                             spec->ema_vlan_push_descs[0].emavp_tpid_be);
2332                         MCDI_IN_SET_WORD(req,
2333                             MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
2334                             spec->ema_vlan_push_descs[0].emavp_tci_be);
2335                 }
2336
2337                 outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
2338
2339                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
2340                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
2341                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
2342                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
2343         }
2344
2345         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
2346             spec->ema_rsrc.emar_eh_id.id);
2347
2348         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
2349                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2350                     MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
2351         }
2352
2353         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
2354                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2355                     MAE_ACTION_SET_ALLOC_IN_MARK, 1);
2356
2357                 MCDI_IN_SET_DWORD(req,
2358                     MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
2359         }
2360
2361         MCDI_IN_SET_DWORD(req,
2362             MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
2363
2364         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
2365             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2366         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
2367             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2368
2369         efx_mcdi_execute(enp, &req);
2370
2371         if (req.emr_rc != 0) {
2372                 rc = req.emr_rc;
2373                 goto fail2;
2374         }
2375
2376         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
2377                 rc = EMSGSIZE;
2378                 goto fail3;
2379         }
2380
2381         aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
2382         if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
2383                 rc = ENOENT;
2384                 goto fail4;
2385         }
2386
2387         aset_idp->id = aset_id.id;
2388
2389         return (0);
2390
2391 fail4:
2392         EFSYS_PROBE(fail4);
2393 fail3:
2394         EFSYS_PROBE(fail3);
2395 fail2:
2396         EFSYS_PROBE(fail2);
2397 fail1:
2398         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2399         return (rc);
2400 }
2401
2402         __checkReturn                   efx_rc_t
2403 efx_mae_counters_alloc(
2404         __in                            efx_nic_t *enp,
2405         __in                            uint32_t n_counters,
2406         __out                           uint32_t *n_allocatedp,
2407         __out_ecount(n_counters)        efx_counter_t *countersp,
2408         __out_opt                       uint32_t *gen_countp)
2409 {
2410         EFX_MCDI_DECLARE_BUF(payload,
2411             MC_CMD_MAE_COUNTER_ALLOC_IN_LEN,
2412             MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMAX_MCDI2);
2413         efx_mae_t *maep = enp->en_maep;
2414         uint32_t n_allocated;
2415         efx_mcdi_req_t req;
2416         unsigned int i;
2417         efx_rc_t rc;
2418
2419         if (n_counters > maep->em_max_ncounters ||
2420             n_counters < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM ||
2421             n_counters > MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MAXNUM_MCDI2) {
2422                 rc = EINVAL;
2423                 goto fail1;
2424         }
2425
2426         req.emr_cmd = MC_CMD_MAE_COUNTER_ALLOC;
2427         req.emr_in_buf = payload;
2428         req.emr_in_length = MC_CMD_MAE_COUNTER_ALLOC_IN_LEN;
2429         req.emr_out_buf = payload;
2430         req.emr_out_length = MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(n_counters);
2431
2432         MCDI_IN_SET_DWORD(req, MAE_COUNTER_ALLOC_IN_REQUESTED_COUNT,
2433             n_counters);
2434
2435         efx_mcdi_execute(enp, &req);
2436
2437         if (req.emr_rc != 0) {
2438                 rc = req.emr_rc;
2439                 goto fail2;
2440         }
2441
2442         if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMIN) {
2443                 rc = EMSGSIZE;
2444                 goto fail3;
2445         }
2446
2447         n_allocated = MCDI_OUT_DWORD(req,
2448             MAE_COUNTER_ALLOC_OUT_COUNTER_ID_COUNT);
2449         if (n_allocated < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM) {
2450                 rc = EFAULT;
2451                 goto fail4;
2452         }
2453
2454         for (i = 0; i < n_allocated; i++) {
2455                 countersp[i].id = MCDI_OUT_INDEXED_DWORD(req,
2456                     MAE_COUNTER_ALLOC_OUT_COUNTER_ID, i);
2457         }
2458
2459         if (gen_countp != NULL) {
2460                 *gen_countp = MCDI_OUT_DWORD(req,
2461                                     MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT);
2462         }
2463
2464         *n_allocatedp = n_allocated;
2465
2466         return (0);
2467
2468 fail4:
2469         EFSYS_PROBE(fail4);
2470 fail3:
2471         EFSYS_PROBE(fail3);
2472 fail2:
2473         EFSYS_PROBE(fail2);
2474 fail1:
2475         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2476
2477         return (rc);
2478 }
2479
2480         __checkReturn                   efx_rc_t
2481 efx_mae_counters_free(
2482         __in                            efx_nic_t *enp,
2483         __in                            uint32_t n_counters,
2484         __out                           uint32_t *n_freedp,
2485         __in_ecount(n_counters)         const efx_counter_t *countersp,
2486         __out_opt                       uint32_t *gen_countp)
2487 {
2488         EFX_MCDI_DECLARE_BUF(payload,
2489             MC_CMD_MAE_COUNTER_FREE_IN_LENMAX_MCDI2,
2490             MC_CMD_MAE_COUNTER_FREE_OUT_LENMAX_MCDI2);
2491         efx_mae_t *maep = enp->en_maep;
2492         efx_mcdi_req_t req;
2493         uint32_t n_freed;
2494         unsigned int i;
2495         efx_rc_t rc;
2496
2497         if (n_counters > maep->em_max_ncounters ||
2498             n_counters < MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MINNUM ||
2499             n_counters >
2500             MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MAXNUM_MCDI2) {
2501                 rc = EINVAL;
2502                 goto fail1;
2503         }
2504
2505         req.emr_cmd = MC_CMD_MAE_COUNTER_FREE;
2506         req.emr_in_buf = payload;
2507         req.emr_in_length = MC_CMD_MAE_COUNTER_FREE_IN_LEN(n_counters);
2508         req.emr_out_buf = payload;
2509         req.emr_out_length = MC_CMD_MAE_COUNTER_FREE_OUT_LEN(n_counters);
2510
2511         for (i = 0; i < n_counters; i++) {
2512                 MCDI_IN_SET_INDEXED_DWORD(req,
2513                     MAE_COUNTER_FREE_IN_FREE_COUNTER_ID, i, countersp[i].id);
2514         }
2515         MCDI_IN_SET_DWORD(req, MAE_COUNTER_FREE_IN_COUNTER_ID_COUNT,
2516                           n_counters);
2517
2518         efx_mcdi_execute(enp, &req);
2519
2520         if (req.emr_rc != 0) {
2521                 rc = req.emr_rc;
2522                 goto fail2;
2523         }
2524
2525         if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_FREE_OUT_LENMIN) {
2526                 rc = EMSGSIZE;
2527                 goto fail3;
2528         }
2529
2530         n_freed = MCDI_OUT_DWORD(req, MAE_COUNTER_FREE_OUT_COUNTER_ID_COUNT);
2531
2532         if (n_freed < MC_CMD_MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID_MINNUM) {
2533                 rc = EFAULT;
2534                 goto fail4;
2535         }
2536
2537         if (gen_countp != NULL) {
2538                 *gen_countp = MCDI_OUT_DWORD(req,
2539                                     MAE_COUNTER_FREE_OUT_GENERATION_COUNT);
2540         }
2541
2542         *n_freedp = n_freed;
2543
2544         return (0);
2545
2546 fail4:
2547         EFSYS_PROBE(fail4);
2548 fail3:
2549         EFSYS_PROBE(fail3);
2550 fail2:
2551         EFSYS_PROBE(fail2);
2552 fail1:
2553         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2554         return (rc);
2555 }
2556
2557         __checkReturn                   efx_rc_t
2558 efx_mae_action_set_free(
2559         __in                            efx_nic_t *enp,
2560         __in                            const efx_mae_aset_id_t *aset_idp)
2561 {
2562         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2563         efx_mcdi_req_t req;
2564         EFX_MCDI_DECLARE_BUF(payload,
2565             MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
2566             MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
2567         efx_rc_t rc;
2568
2569         if (encp->enc_mae_supported == B_FALSE) {
2570                 rc = ENOTSUP;
2571                 goto fail1;
2572         }
2573
2574         req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
2575         req.emr_in_buf = payload;
2576         req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
2577         req.emr_out_buf = payload;
2578         req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
2579
2580         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
2581
2582         efx_mcdi_execute(enp, &req);
2583
2584         if (req.emr_rc != 0) {
2585                 rc = req.emr_rc;
2586                 goto fail2;
2587         }
2588
2589         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_FREE_OUT_LENMIN) {
2590                 rc = EMSGSIZE;
2591                 goto fail3;
2592         }
2593
2594         if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
2595             aset_idp->id) {
2596                 /* Firmware failed to free the action set. */
2597                 rc = EAGAIN;
2598                 goto fail4;
2599         }
2600
2601         return (0);
2602
2603 fail4:
2604         EFSYS_PROBE(fail4);
2605 fail3:
2606         EFSYS_PROBE(fail3);
2607 fail2:
2608         EFSYS_PROBE(fail2);
2609 fail1:
2610         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2611         return (rc);
2612 }
2613
2614         __checkReturn                   efx_rc_t
2615 efx_mae_action_rule_insert(
2616         __in                            efx_nic_t *enp,
2617         __in                            const efx_mae_match_spec_t *spec,
2618         __in                            const efx_mae_aset_list_id_t *asl_idp,
2619         __in                            const efx_mae_aset_id_t *as_idp,
2620         __out                           efx_mae_rule_id_t *ar_idp)
2621 {
2622         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2623         efx_mcdi_req_t req;
2624         EFX_MCDI_DECLARE_BUF(payload,
2625             MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2,
2626             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
2627         efx_oword_t *rule_response;
2628         efx_mae_rule_id_t ar_id;
2629         size_t offset;
2630         efx_rc_t rc;
2631
2632         EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
2633             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
2634
2635         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2636             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
2637
2638         if (encp->enc_mae_supported == B_FALSE) {
2639                 rc = ENOTSUP;
2640                 goto fail1;
2641         }
2642
2643         if (spec->emms_type != EFX_MAE_RULE_ACTION ||
2644             (asl_idp != NULL && as_idp != NULL) ||
2645             (asl_idp == NULL && as_idp == NULL)) {
2646                 rc = EINVAL;
2647                 goto fail2;
2648         }
2649
2650         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
2651         req.emr_in_buf = payload;
2652         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
2653         req.emr_out_buf = payload;
2654         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
2655
2656         EFX_STATIC_ASSERT(sizeof (*rule_response) <=
2657             MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
2658         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
2659         rule_response = (efx_oword_t *)(payload + offset);
2660         EFX_POPULATE_OWORD_3(*rule_response,
2661             MAE_ACTION_RULE_RESPONSE_ASL_ID,
2662             (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
2663             MAE_ACTION_RULE_RESPONSE_AS_ID,
2664             (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
2665             MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
2666
2667         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
2668
2669         /*
2670          * Mask-value pairs have been stored in the byte order needed for the
2671          * MCDI request and are thus safe to be copied directly to the buffer.
2672          */
2673         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
2674             MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
2675         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
2676         memcpy(payload + offset, spec->emms_mask_value_pairs.action,
2677             MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
2678
2679         efx_mcdi_execute(enp, &req);
2680
2681         if (req.emr_rc != 0) {
2682                 rc = req.emr_rc;
2683                 goto fail3;
2684         }
2685
2686         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
2687                 rc = EMSGSIZE;
2688                 goto fail4;
2689         }
2690
2691         ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
2692         if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
2693                 rc = ENOENT;
2694                 goto fail5;
2695         }
2696
2697         ar_idp->id = ar_id.id;
2698
2699         return (0);
2700
2701 fail5:
2702         EFSYS_PROBE(fail5);
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         return (rc);
2712 }
2713
2714         __checkReturn                   efx_rc_t
2715 efx_mae_action_rule_remove(
2716         __in                            efx_nic_t *enp,
2717         __in                            const efx_mae_rule_id_t *ar_idp)
2718 {
2719         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2720         efx_mcdi_req_t req;
2721         EFX_MCDI_DECLARE_BUF(payload,
2722             MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
2723             MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
2724         efx_rc_t rc;
2725
2726         if (encp->enc_mae_supported == B_FALSE) {
2727                 rc = ENOTSUP;
2728                 goto fail1;
2729         }
2730
2731         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
2732         req.emr_in_buf = payload;
2733         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
2734         req.emr_out_buf = payload;
2735         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
2736
2737         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
2738
2739         efx_mcdi_execute(enp, &req);
2740
2741         if (req.emr_rc != 0) {
2742                 rc = req.emr_rc;
2743                 goto fail2;
2744         }
2745
2746         if (req.emr_out_length_used <
2747             MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LENMIN) {
2748                 rc = EMSGSIZE;
2749                 goto fail3;
2750         }
2751
2752         if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
2753             ar_idp->id) {
2754                 /* Firmware failed to delete the action rule. */
2755                 rc = EAGAIN;
2756                 goto fail4;
2757         }
2758
2759         return (0);
2760
2761 fail4:
2762         EFSYS_PROBE(fail4);
2763 fail3:
2764         EFSYS_PROBE(fail3);
2765 fail2:
2766         EFSYS_PROBE(fail2);
2767 fail1:
2768         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2769         return (rc);
2770 }
2771
2772 #endif /* EFSYS_OPT_MAE */