common/sfc_efx/base: support counter in action set
[dpdk.git] / drivers / common / sfc_efx / base / efx_mae.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2019-2021 Xilinx, Inc.
4  */
5
6 #include "efx.h"
7 #include "efx_impl.h"
8
9
10 #if EFSYS_OPT_MAE
11
12 static  __checkReturn                   efx_rc_t
13 efx_mae_get_capabilities(
14         __in                            efx_nic_t *enp)
15 {
16         efx_mcdi_req_t req;
17         EFX_MCDI_DECLARE_BUF(payload,
18             MC_CMD_MAE_GET_CAPS_IN_LEN,
19             MC_CMD_MAE_GET_CAPS_OUT_LEN);
20         struct efx_mae_s *maep = enp->en_maep;
21         efx_rc_t rc;
22
23         req.emr_cmd = MC_CMD_MAE_GET_CAPS;
24         req.emr_in_buf = payload;
25         req.emr_in_length = MC_CMD_MAE_GET_CAPS_IN_LEN;
26         req.emr_out_buf = payload;
27         req.emr_out_length = MC_CMD_MAE_GET_CAPS_OUT_LEN;
28
29         efx_mcdi_execute(enp, &req);
30
31         if (req.emr_rc != 0) {
32                 rc = req.emr_rc;
33                 goto fail1;
34         }
35
36         if (req.emr_out_length_used < MC_CMD_MAE_GET_CAPS_OUT_LEN) {
37                 rc = EMSGSIZE;
38                 goto fail2;
39         }
40
41         maep->em_max_n_outer_prios =
42             MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_OUTER_PRIOS);
43
44         maep->em_max_n_action_prios =
45             MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ACTION_PRIOS);
46
47         maep->em_encap_types_supported = 0;
48
49         if (MCDI_OUT_DWORD_FIELD(req, MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED,
50             MAE_GET_CAPS_OUT_ENCAP_TYPE_VXLAN) != 0) {
51                 maep->em_encap_types_supported |=
52                     (1U << EFX_TUNNEL_PROTOCOL_VXLAN);
53         }
54
55         if (MCDI_OUT_DWORD_FIELD(req, MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED,
56             MAE_GET_CAPS_OUT_ENCAP_TYPE_GENEVE) != 0) {
57                 maep->em_encap_types_supported |=
58                     (1U << EFX_TUNNEL_PROTOCOL_GENEVE);
59         }
60
61         if (MCDI_OUT_DWORD_FIELD(req, MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED,
62             MAE_GET_CAPS_OUT_ENCAP_TYPE_NVGRE) != 0) {
63                 maep->em_encap_types_supported |=
64                     (1U << EFX_TUNNEL_PROTOCOL_NVGRE);
65         }
66
67         maep->em_max_nfields =
68             MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT);
69
70         maep->em_max_ncounters =
71             MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_COUNTERS);
72
73         return (0);
74
75 fail2:
76         EFSYS_PROBE(fail2);
77 fail1:
78         EFSYS_PROBE1(fail1, efx_rc_t, rc);
79         return (rc);
80 }
81
82 static  __checkReturn                   efx_rc_t
83 efx_mae_get_outer_rule_caps(
84         __in                            efx_nic_t *enp,
85         __in                            unsigned int field_ncaps,
86         __out_ecount(field_ncaps)       efx_mae_field_cap_t *field_caps)
87 {
88         efx_mcdi_req_t req;
89         EFX_MCDI_DECLARE_BUF(payload,
90             MC_CMD_MAE_GET_OR_CAPS_IN_LEN,
91             MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2);
92         unsigned int mcdi_field_ncaps;
93         unsigned int i;
94         efx_rc_t rc;
95
96         if (MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps) >
97             MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2) {
98                 rc = EINVAL;
99                 goto fail1;
100         }
101
102         req.emr_cmd = MC_CMD_MAE_GET_OR_CAPS;
103         req.emr_in_buf = payload;
104         req.emr_in_length = MC_CMD_MAE_GET_OR_CAPS_IN_LEN;
105         req.emr_out_buf = payload;
106         req.emr_out_length = MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps);
107
108         efx_mcdi_execute(enp, &req);
109
110         if (req.emr_rc != 0) {
111                 rc = req.emr_rc;
112                 goto fail2;
113         }
114
115         if (req.emr_out_length_used < MC_CMD_MAE_GET_OR_CAPS_OUT_LENMIN) {
116                 rc = EMSGSIZE;
117                 goto fail3;
118         }
119
120         mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_OR_CAPS_OUT_COUNT);
121
122         if (req.emr_out_length_used <
123             MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(mcdi_field_ncaps)) {
124                 rc = EMSGSIZE;
125                 goto fail4;
126         }
127
128         if (mcdi_field_ncaps > field_ncaps) {
129                 rc = EMSGSIZE;
130                 goto fail5;
131         }
132
133         for (i = 0; i < mcdi_field_ncaps; ++i) {
134                 uint32_t match_flag;
135                 uint32_t mask_flag;
136
137                 field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req,
138                     MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
139                     MAE_FIELD_FLAGS_SUPPORT_STATUS);
140
141                 match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
142                     MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
143                     MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS);
144
145                 field_caps[i].emfc_match_affects_class =
146                     (match_flag != 0) ? B_TRUE : B_FALSE;
147
148                 mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
149                     MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
150                     MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS);
151
152                 field_caps[i].emfc_mask_affects_class =
153                     (mask_flag != 0) ? B_TRUE : B_FALSE;
154         }
155
156         return (0);
157
158 fail5:
159         EFSYS_PROBE(fail5);
160 fail4:
161         EFSYS_PROBE(fail4);
162 fail3:
163         EFSYS_PROBE(fail3);
164 fail2:
165         EFSYS_PROBE(fail2);
166 fail1:
167         EFSYS_PROBE1(fail1, efx_rc_t, rc);
168         return (rc);
169 }
170
171 static  __checkReturn                   efx_rc_t
172 efx_mae_get_action_rule_caps(
173         __in                            efx_nic_t *enp,
174         __in                            unsigned int field_ncaps,
175         __out_ecount(field_ncaps)       efx_mae_field_cap_t *field_caps)
176 {
177         efx_mcdi_req_t req;
178         EFX_MCDI_DECLARE_BUF(payload,
179             MC_CMD_MAE_GET_AR_CAPS_IN_LEN,
180             MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2);
181         unsigned int mcdi_field_ncaps;
182         unsigned int i;
183         efx_rc_t rc;
184
185         if (MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps) >
186             MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2) {
187                 rc = EINVAL;
188                 goto fail1;
189         }
190
191         req.emr_cmd = MC_CMD_MAE_GET_AR_CAPS;
192         req.emr_in_buf = payload;
193         req.emr_in_length = MC_CMD_MAE_GET_AR_CAPS_IN_LEN;
194         req.emr_out_buf = payload;
195         req.emr_out_length = MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps);
196
197         efx_mcdi_execute(enp, &req);
198
199         if (req.emr_rc != 0) {
200                 rc = req.emr_rc;
201                 goto fail2;
202         }
203
204         if (req.emr_out_length_used < MC_CMD_MAE_GET_AR_CAPS_OUT_LENMIN) {
205                 rc = EMSGSIZE;
206                 goto fail3;
207         }
208
209         mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_AR_CAPS_OUT_COUNT);
210
211         if (req.emr_out_length_used <
212             MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(mcdi_field_ncaps)) {
213                 rc = EMSGSIZE;
214                 goto fail4;
215         }
216
217         if (mcdi_field_ncaps > field_ncaps) {
218                 rc = EMSGSIZE;
219                 goto fail5;
220         }
221
222         for (i = 0; i < mcdi_field_ncaps; ++i) {
223                 uint32_t match_flag;
224                 uint32_t mask_flag;
225
226                 field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req,
227                     MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
228                     MAE_FIELD_FLAGS_SUPPORT_STATUS);
229
230                 match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
231                     MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
232                     MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS);
233
234                 field_caps[i].emfc_match_affects_class =
235                     (match_flag != 0) ? B_TRUE : B_FALSE;
236
237                 mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
238                     MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
239                     MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS);
240
241                 field_caps[i].emfc_mask_affects_class =
242                     (mask_flag != 0) ? B_TRUE : B_FALSE;
243         }
244
245         return (0);
246
247 fail5:
248         EFSYS_PROBE(fail5);
249 fail4:
250         EFSYS_PROBE(fail4);
251 fail3:
252         EFSYS_PROBE(fail3);
253 fail2:
254         EFSYS_PROBE(fail2);
255 fail1:
256         EFSYS_PROBE1(fail1, efx_rc_t, rc);
257         return (rc);
258 }
259
260         __checkReturn                   efx_rc_t
261 efx_mae_init(
262         __in                            efx_nic_t *enp)
263 {
264         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
265         efx_mae_field_cap_t *or_fcaps;
266         size_t or_fcaps_size;
267         efx_mae_field_cap_t *ar_fcaps;
268         size_t ar_fcaps_size;
269         efx_mae_t *maep;
270         efx_rc_t rc;
271
272         if (encp->enc_mae_supported == B_FALSE) {
273                 rc = ENOTSUP;
274                 goto fail1;
275         }
276
277         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*maep), maep);
278         if (maep == NULL) {
279                 rc = ENOMEM;
280                 goto fail2;
281         }
282
283         enp->en_maep = maep;
284
285         rc = efx_mae_get_capabilities(enp);
286         if (rc != 0)
287                 goto fail3;
288
289         or_fcaps_size = maep->em_max_nfields * sizeof (*or_fcaps);
290         EFSYS_KMEM_ALLOC(enp->en_esip, or_fcaps_size, or_fcaps);
291         if (or_fcaps == NULL) {
292                 rc = ENOMEM;
293                 goto fail4;
294         }
295
296         maep->em_outer_rule_field_caps_size = or_fcaps_size;
297         maep->em_outer_rule_field_caps = or_fcaps;
298
299         rc = efx_mae_get_outer_rule_caps(enp, maep->em_max_nfields, or_fcaps);
300         if (rc != 0)
301                 goto fail5;
302
303         ar_fcaps_size = maep->em_max_nfields * sizeof (*ar_fcaps);
304         EFSYS_KMEM_ALLOC(enp->en_esip, ar_fcaps_size, ar_fcaps);
305         if (ar_fcaps == NULL) {
306                 rc = ENOMEM;
307                 goto fail6;
308         }
309
310         maep->em_action_rule_field_caps_size = ar_fcaps_size;
311         maep->em_action_rule_field_caps = ar_fcaps;
312
313         rc = efx_mae_get_action_rule_caps(enp, maep->em_max_nfields, ar_fcaps);
314         if (rc != 0)
315                 goto fail7;
316
317         return (0);
318
319 fail7:
320         EFSYS_PROBE(fail5);
321         EFSYS_KMEM_FREE(enp->en_esip, ar_fcaps_size, ar_fcaps);
322 fail6:
323         EFSYS_PROBE(fail4);
324 fail5:
325         EFSYS_PROBE(fail5);
326         EFSYS_KMEM_FREE(enp->en_esip, or_fcaps_size, or_fcaps);
327 fail4:
328         EFSYS_PROBE(fail4);
329 fail3:
330         EFSYS_PROBE(fail3);
331         EFSYS_KMEM_FREE(enp->en_esip, sizeof (struct efx_mae_s), enp->en_maep);
332         enp->en_maep = NULL;
333 fail2:
334         EFSYS_PROBE(fail2);
335 fail1:
336         EFSYS_PROBE1(fail1, efx_rc_t, rc);
337         return (rc);
338 }
339
340                                         void
341 efx_mae_fini(
342         __in                            efx_nic_t *enp)
343 {
344         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
345         efx_mae_t *maep = enp->en_maep;
346
347         if (encp->enc_mae_supported == B_FALSE)
348                 return;
349
350         EFSYS_KMEM_FREE(enp->en_esip, maep->em_action_rule_field_caps_size,
351             maep->em_action_rule_field_caps);
352         EFSYS_KMEM_FREE(enp->en_esip, maep->em_outer_rule_field_caps_size,
353             maep->em_outer_rule_field_caps);
354         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*maep), maep);
355         enp->en_maep = NULL;
356 }
357
358         __checkReturn                   efx_rc_t
359 efx_mae_get_limits(
360         __in                            efx_nic_t *enp,
361         __out                           efx_mae_limits_t *emlp)
362 {
363         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
364         struct efx_mae_s *maep = enp->en_maep;
365         efx_rc_t rc;
366
367         if (encp->enc_mae_supported == B_FALSE) {
368                 rc = ENOTSUP;
369                 goto fail1;
370         }
371
372         emlp->eml_max_n_outer_prios = maep->em_max_n_outer_prios;
373         emlp->eml_max_n_action_prios = maep->em_max_n_action_prios;
374         emlp->eml_encap_types_supported = maep->em_encap_types_supported;
375         emlp->eml_encap_header_size_limit =
376             MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2;
377
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         spec->ema_rsrc.emar_counter_id.id = EFX_MAE_RSRC_ID_INVALID;
1195
1196         *specp = spec;
1197
1198         return (0);
1199
1200 fail1:
1201         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1202         return (rc);
1203 }
1204
1205                                         void
1206 efx_mae_action_set_spec_fini(
1207         __in                            efx_nic_t *enp,
1208         __in                            efx_mae_actions_t *spec)
1209 {
1210         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
1211 }
1212
1213 static  __checkReturn                   efx_rc_t
1214 efx_mae_action_set_add_decap(
1215         __in                            efx_mae_actions_t *spec,
1216         __in                            size_t arg_size,
1217         __in_bcount(arg_size)           const uint8_t *arg)
1218 {
1219         efx_rc_t rc;
1220
1221         _NOTE(ARGUNUSED(spec))
1222
1223         if (arg_size != 0) {
1224                 rc = EINVAL;
1225                 goto fail1;
1226         }
1227
1228         if (arg != NULL) {
1229                 rc = EINVAL;
1230                 goto fail2;
1231         }
1232
1233         /* This action does not have any arguments, so do nothing here. */
1234
1235         return (0);
1236
1237 fail2:
1238         EFSYS_PROBE(fail2);
1239 fail1:
1240         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1241         return (rc);
1242 }
1243
1244 static  __checkReturn                   efx_rc_t
1245 efx_mae_action_set_add_vlan_pop(
1246         __in                            efx_mae_actions_t *spec,
1247         __in                            size_t arg_size,
1248         __in_bcount(arg_size)           const uint8_t *arg)
1249 {
1250         efx_rc_t rc;
1251
1252         if (arg_size != 0) {
1253                 rc = EINVAL;
1254                 goto fail1;
1255         }
1256
1257         if (arg != NULL) {
1258                 rc = EINVAL;
1259                 goto fail2;
1260         }
1261
1262         if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) {
1263                 rc = ENOTSUP;
1264                 goto fail3;
1265         }
1266
1267         ++spec->ema_n_vlan_tags_to_pop;
1268
1269         return (0);
1270
1271 fail3:
1272         EFSYS_PROBE(fail3);
1273 fail2:
1274         EFSYS_PROBE(fail2);
1275 fail1:
1276         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1277         return (rc);
1278 }
1279
1280 static  __checkReturn                   efx_rc_t
1281 efx_mae_action_set_add_vlan_push(
1282         __in                            efx_mae_actions_t *spec,
1283         __in                            size_t arg_size,
1284         __in_bcount(arg_size)           const uint8_t *arg)
1285 {
1286         unsigned int n_tags = spec->ema_n_vlan_tags_to_push;
1287         efx_rc_t rc;
1288
1289         if (arg_size != sizeof (*spec->ema_vlan_push_descs)) {
1290                 rc = EINVAL;
1291                 goto fail1;
1292         }
1293
1294         if (arg == NULL) {
1295                 rc = EINVAL;
1296                 goto fail2;
1297         }
1298
1299         if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1300                 rc = ENOTSUP;
1301                 goto fail3;
1302         }
1303
1304         memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size);
1305         ++(spec->ema_n_vlan_tags_to_push);
1306
1307         return (0);
1308
1309 fail3:
1310         EFSYS_PROBE(fail3);
1311 fail2:
1312         EFSYS_PROBE(fail2);
1313 fail1:
1314         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1315         return (rc);
1316 }
1317
1318 static  __checkReturn                   efx_rc_t
1319 efx_mae_action_set_add_encap(
1320         __in                            efx_mae_actions_t *spec,
1321         __in                            size_t arg_size,
1322         __in_bcount(arg_size)           const uint8_t *arg)
1323 {
1324         efx_rc_t rc;
1325
1326         /*
1327          * Adding this specific action to an action set spec and setting encap.
1328          * header ID in the spec are two individual steps. This design allows
1329          * the client driver to avoid encap. header allocation when it simply
1330          * needs to check the order of actions submitted by user ("validate"),
1331          * without actually allocating an action set and inserting a rule.
1332          *
1333          * For now, mark encap. header ID as invalid; the caller will invoke
1334          * efx_mae_action_set_fill_in_eh_id() to override the field prior
1335          * to action set allocation; otherwise, the allocation will fail.
1336          */
1337         spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
1338
1339         /*
1340          * As explained above, there are no arguments to handle here.
1341          * efx_mae_action_set_fill_in_eh_id() will take care of them.
1342          */
1343         if (arg_size != 0) {
1344                 rc = EINVAL;
1345                 goto fail1;
1346         }
1347
1348         if (arg != NULL) {
1349                 rc = EINVAL;
1350                 goto fail2;
1351         }
1352
1353         return (0);
1354
1355 fail2:
1356         EFSYS_PROBE(fail2);
1357 fail1:
1358         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1359         return (rc);
1360 }
1361
1362 static  __checkReturn                   efx_rc_t
1363 efx_mae_action_set_add_count(
1364         __in                            efx_mae_actions_t *spec,
1365         __in                            size_t arg_size,
1366         __in_bcount(arg_size)           const uint8_t *arg)
1367 {
1368         efx_rc_t rc;
1369
1370         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1371                           MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL);
1372
1373         /*
1374          * Preparing an action set spec to update a counter requires
1375          * two steps: first add this action to the action spec, and then
1376          * add the counter ID to the spec. This allows validity checking
1377          * and resource allocation to be done separately.
1378          * Mark the counter ID as invalid in the spec to ensure that the
1379          * caller must also invoke efx_mae_action_set_fill_in_counter_id()
1380          * before action set allocation.
1381          */
1382         spec->ema_rsrc.emar_counter_id.id = EFX_MAE_RSRC_ID_INVALID;
1383
1384         /* Nothing else is supposed to take place over here. */
1385         if (arg_size != 0) {
1386                 rc = EINVAL;
1387                 goto fail1;
1388         }
1389
1390         if (arg != NULL) {
1391                 rc = EINVAL;
1392                 goto fail2;
1393         }
1394
1395         ++(spec->ema_n_count_actions);
1396
1397         return (0);
1398
1399 fail2:
1400         EFSYS_PROBE(fail2);
1401 fail1:
1402         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1403         return (rc);
1404 }
1405
1406 static  __checkReturn                   efx_rc_t
1407 efx_mae_action_set_add_flag(
1408         __in                            efx_mae_actions_t *spec,
1409         __in                            size_t arg_size,
1410         __in_bcount(arg_size)           const uint8_t *arg)
1411 {
1412         efx_rc_t rc;
1413
1414         _NOTE(ARGUNUSED(spec))
1415
1416         if (arg_size != 0) {
1417                 rc = EINVAL;
1418                 goto fail1;
1419         }
1420
1421         if (arg != NULL) {
1422                 rc = EINVAL;
1423                 goto fail2;
1424         }
1425
1426         /* This action does not have any arguments, so do nothing here. */
1427
1428         return (0);
1429
1430 fail2:
1431         EFSYS_PROBE(fail2);
1432 fail1:
1433         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1434         return (rc);
1435 }
1436
1437 static  __checkReturn                   efx_rc_t
1438 efx_mae_action_set_add_mark(
1439         __in                            efx_mae_actions_t *spec,
1440         __in                            size_t arg_size,
1441         __in_bcount(arg_size)           const uint8_t *arg)
1442 {
1443         efx_rc_t rc;
1444
1445         if (arg_size != sizeof (spec->ema_mark_value)) {
1446                 rc = EINVAL;
1447                 goto fail1;
1448         }
1449
1450         if (arg == NULL) {
1451                 rc = EINVAL;
1452                 goto fail2;
1453         }
1454
1455         memcpy(&spec->ema_mark_value, arg, arg_size);
1456
1457         return (0);
1458
1459 fail2:
1460         EFSYS_PROBE(fail2);
1461 fail1:
1462         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1463         return (rc);
1464 }
1465
1466 static  __checkReturn                   efx_rc_t
1467 efx_mae_action_set_add_deliver(
1468         __in                            efx_mae_actions_t *spec,
1469         __in                            size_t arg_size,
1470         __in_bcount(arg_size)           const uint8_t *arg)
1471 {
1472         efx_rc_t rc;
1473
1474         if (arg_size != sizeof (spec->ema_deliver_mport)) {
1475                 rc = EINVAL;
1476                 goto fail1;
1477         }
1478
1479         if (arg == NULL) {
1480                 rc = EINVAL;
1481                 goto fail2;
1482         }
1483
1484         memcpy(&spec->ema_deliver_mport, arg, arg_size);
1485
1486         return (0);
1487
1488 fail2:
1489         EFSYS_PROBE(fail2);
1490 fail1:
1491         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1492         return (rc);
1493 }
1494
1495 typedef struct efx_mae_action_desc_s {
1496         /* Action specific handler */
1497         efx_rc_t        (*emad_add)(efx_mae_actions_t *,
1498                                     size_t, const uint8_t *);
1499 } efx_mae_action_desc_t;
1500
1501 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
1502         [EFX_MAE_ACTION_DECAP] = {
1503                 .emad_add = efx_mae_action_set_add_decap
1504         },
1505         [EFX_MAE_ACTION_VLAN_POP] = {
1506                 .emad_add = efx_mae_action_set_add_vlan_pop
1507         },
1508         [EFX_MAE_ACTION_VLAN_PUSH] = {
1509                 .emad_add = efx_mae_action_set_add_vlan_push
1510         },
1511         [EFX_MAE_ACTION_ENCAP] = {
1512                 .emad_add = efx_mae_action_set_add_encap
1513         },
1514         [EFX_MAE_ACTION_COUNT] = {
1515                 .emad_add = efx_mae_action_set_add_count
1516         },
1517         [EFX_MAE_ACTION_FLAG] = {
1518                 .emad_add = efx_mae_action_set_add_flag
1519         },
1520         [EFX_MAE_ACTION_MARK] = {
1521                 .emad_add = efx_mae_action_set_add_mark
1522         },
1523         [EFX_MAE_ACTION_DELIVER] = {
1524                 .emad_add = efx_mae_action_set_add_deliver
1525         }
1526 };
1527
1528 static const uint32_t efx_mae_action_ordered_map =
1529         (1U << EFX_MAE_ACTION_DECAP) |
1530         (1U << EFX_MAE_ACTION_VLAN_POP) |
1531         (1U << EFX_MAE_ACTION_VLAN_PUSH) |
1532         /*
1533          * HW will conduct action COUNT after
1534          * the matching packet has been modified by
1535          * length-affecting actions except for ENCAP.
1536          */
1537         (1U << EFX_MAE_ACTION_COUNT) |
1538         (1U << EFX_MAE_ACTION_ENCAP) |
1539         (1U << EFX_MAE_ACTION_FLAG) |
1540         (1U << EFX_MAE_ACTION_MARK) |
1541         (1U << EFX_MAE_ACTION_DELIVER);
1542
1543 /*
1544  * These actions must not be added after DELIVER, but
1545  * they can have any place among the rest of
1546  * strictly ordered actions.
1547  */
1548 static const uint32_t efx_mae_action_nonstrict_map =
1549         (1U << EFX_MAE_ACTION_FLAG) |
1550         (1U << EFX_MAE_ACTION_MARK);
1551
1552 static const uint32_t efx_mae_action_repeat_map =
1553         (1U << EFX_MAE_ACTION_VLAN_POP) |
1554         (1U << EFX_MAE_ACTION_VLAN_PUSH) |
1555         (1U << EFX_MAE_ACTION_COUNT);
1556
1557 /*
1558  * Add an action to an action set.
1559  *
1560  * This has to be invoked in the desired action order.
1561  * An out-of-order action request will be turned down.
1562  */
1563 static  __checkReturn                   efx_rc_t
1564 efx_mae_action_set_spec_populate(
1565         __in                            efx_mae_actions_t *spec,
1566         __in                            efx_mae_action_t type,
1567         __in                            size_t arg_size,
1568         __in_bcount(arg_size)           const uint8_t *arg)
1569 {
1570         uint32_t action_mask;
1571         efx_rc_t rc;
1572
1573         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1574             (sizeof (efx_mae_action_ordered_map) * 8));
1575         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1576             (sizeof (efx_mae_action_repeat_map) * 8));
1577
1578         EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
1579         EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK);
1580         EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER);
1581
1582         if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
1583                 rc = EINVAL;
1584                 goto fail1;
1585         }
1586
1587         action_mask = (1U << type);
1588
1589         if ((spec->ema_actions & action_mask) != 0) {
1590                 /* The action set already contains this action. */
1591                 if ((efx_mae_action_repeat_map & action_mask) == 0) {
1592                         /* Cannot add another non-repeatable action. */
1593                         rc = ENOTSUP;
1594                         goto fail2;
1595                 }
1596         }
1597
1598         if ((efx_mae_action_ordered_map & action_mask) != 0) {
1599                 uint32_t strict_ordered_map =
1600                     efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map;
1601                 uint32_t later_actions_mask =
1602                     strict_ordered_map & ~(action_mask | (action_mask - 1));
1603
1604                 if ((spec->ema_actions & later_actions_mask) != 0) {
1605                         /* Cannot add an action after later ordered actions. */
1606                         rc = ENOTSUP;
1607                         goto fail3;
1608                 }
1609         }
1610
1611         if (efx_mae_actions[type].emad_add != NULL) {
1612                 rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
1613                 if (rc != 0)
1614                         goto fail4;
1615         }
1616
1617         spec->ema_actions |= action_mask;
1618
1619         return (0);
1620
1621 fail4:
1622         EFSYS_PROBE(fail4);
1623 fail3:
1624         EFSYS_PROBE(fail3);
1625 fail2:
1626         EFSYS_PROBE(fail2);
1627 fail1:
1628         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1629         return (rc);
1630 }
1631
1632         __checkReturn                   efx_rc_t
1633 efx_mae_action_set_populate_decap(
1634         __in                            efx_mae_actions_t *spec)
1635 {
1636         return (efx_mae_action_set_spec_populate(spec,
1637             EFX_MAE_ACTION_DECAP, 0, NULL));
1638 }
1639
1640         __checkReturn                   efx_rc_t
1641 efx_mae_action_set_populate_vlan_pop(
1642         __in                            efx_mae_actions_t *spec)
1643 {
1644         return (efx_mae_action_set_spec_populate(spec,
1645             EFX_MAE_ACTION_VLAN_POP, 0, NULL));
1646 }
1647
1648         __checkReturn                   efx_rc_t
1649 efx_mae_action_set_populate_vlan_push(
1650         __in                            efx_mae_actions_t *spec,
1651         __in                            uint16_t tpid_be,
1652         __in                            uint16_t tci_be)
1653 {
1654         efx_mae_action_vlan_push_t action;
1655         const uint8_t *arg = (const uint8_t *)&action;
1656
1657         action.emavp_tpid_be = tpid_be;
1658         action.emavp_tci_be = tci_be;
1659
1660         return (efx_mae_action_set_spec_populate(spec,
1661             EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg));
1662 }
1663
1664         __checkReturn                   efx_rc_t
1665 efx_mae_action_set_populate_encap(
1666         __in                            efx_mae_actions_t *spec)
1667 {
1668         /*
1669          * There is no argument to pass encap. header ID, thus, one does not
1670          * need to allocate an encap. header while parsing application input.
1671          * This is useful since building an action set may be done simply to
1672          * validate a rule, whilst resource allocation usually consumes time.
1673          */
1674         return (efx_mae_action_set_spec_populate(spec,
1675             EFX_MAE_ACTION_ENCAP, 0, NULL));
1676 }
1677
1678         __checkReturn                   efx_rc_t
1679 efx_mae_action_set_populate_count(
1680         __in                            efx_mae_actions_t *spec)
1681 {
1682         /*
1683          * There is no argument to pass counter ID, thus, one does not
1684          * need to allocate a counter while parsing application input.
1685          * This is useful since building an action set may be done simply to
1686          * validate a rule, whilst resource allocation usually consumes time.
1687          */
1688         return (efx_mae_action_set_spec_populate(spec,
1689             EFX_MAE_ACTION_COUNT, 0, NULL));
1690 }
1691
1692         __checkReturn                   efx_rc_t
1693 efx_mae_action_set_populate_flag(
1694         __in                            efx_mae_actions_t *spec)
1695 {
1696         return (efx_mae_action_set_spec_populate(spec,
1697             EFX_MAE_ACTION_FLAG, 0, NULL));
1698 }
1699
1700         __checkReturn                   efx_rc_t
1701 efx_mae_action_set_populate_mark(
1702         __in                            efx_mae_actions_t *spec,
1703         __in                            uint32_t mark_value)
1704 {
1705         const uint8_t *arg = (const uint8_t *)&mark_value;
1706
1707         return (efx_mae_action_set_spec_populate(spec,
1708             EFX_MAE_ACTION_MARK, sizeof (mark_value), arg));
1709 }
1710
1711         __checkReturn                   efx_rc_t
1712 efx_mae_action_set_populate_deliver(
1713         __in                            efx_mae_actions_t *spec,
1714         __in                            const efx_mport_sel_t *mportp)
1715 {
1716         const uint8_t *arg;
1717         efx_rc_t rc;
1718
1719         if (mportp == NULL) {
1720                 rc = EINVAL;
1721                 goto fail1;
1722         }
1723
1724         arg = (const uint8_t *)&mportp->sel;
1725
1726         return (efx_mae_action_set_spec_populate(spec,
1727             EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
1728
1729 fail1:
1730         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1731         return (rc);
1732 }
1733
1734         __checkReturn                   efx_rc_t
1735 efx_mae_action_set_populate_drop(
1736         __in                            efx_mae_actions_t *spec)
1737 {
1738         efx_mport_sel_t mport;
1739         const uint8_t *arg;
1740         efx_dword_t dword;
1741
1742         EFX_POPULATE_DWORD_1(dword,
1743             MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL);
1744
1745         /*
1746          * The constructed DWORD is little-endian,
1747          * but the resulting value is meant to be
1748          * passed to MCDIs, where it will undergo
1749          * host-order to little endian conversion.
1750          */
1751         mport.sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
1752
1753         arg = (const uint8_t *)&mport.sel;
1754
1755         return (efx_mae_action_set_spec_populate(spec,
1756             EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg));
1757 }
1758
1759         __checkReturn                   boolean_t
1760 efx_mae_action_set_specs_equal(
1761         __in                            const efx_mae_actions_t *left,
1762         __in                            const efx_mae_actions_t *right)
1763 {
1764         size_t cmp_size = EFX_FIELD_OFFSET(efx_mae_actions_t, ema_rsrc);
1765
1766         /*
1767          * An action set specification consists of two parts. The first part
1768          * indicates what actions are included in the action set, as well as
1769          * extra quantitative values (in example, the number of VLAN tags to
1770          * push). The second part comprises resource IDs used by the actions.
1771          *
1772          * A resource, in example, a counter, is allocated from the hardware
1773          * by the client, and it's the client who is responsible for keeping
1774          * track of allocated resources and comparing resource IDs if needed.
1775          *
1776          * In this API, don't compare resource IDs in the two specifications.
1777          */
1778
1779         return ((memcmp(left, right, cmp_size) == 0) ? B_TRUE : B_FALSE);
1780 }
1781
1782         __checkReturn                   efx_rc_t
1783 efx_mae_match_specs_class_cmp(
1784         __in                            efx_nic_t *enp,
1785         __in                            const efx_mae_match_spec_t *left,
1786         __in                            const efx_mae_match_spec_t *right,
1787         __out                           boolean_t *have_same_classp)
1788 {
1789         efx_mae_t *maep = enp->en_maep;
1790         unsigned int field_ncaps = maep->em_max_nfields;
1791         const efx_mae_field_cap_t *field_caps;
1792         const efx_mae_mv_desc_t *desc_setp;
1793         unsigned int desc_set_nentries;
1794         const efx_mae_mv_bit_desc_t *bit_desc_setp;
1795         unsigned int bit_desc_set_nentries;
1796         boolean_t have_same_class = B_TRUE;
1797         efx_mae_field_id_t field_id;
1798         const uint8_t *mvpl;
1799         const uint8_t *mvpr;
1800         efx_rc_t rc;
1801
1802         switch (left->emms_type) {
1803         case EFX_MAE_RULE_OUTER:
1804                 field_caps = maep->em_outer_rule_field_caps;
1805                 desc_setp = __efx_mae_outer_rule_mv_desc_set;
1806                 desc_set_nentries =
1807                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1808                 bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
1809                 bit_desc_set_nentries =
1810                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
1811                 mvpl = left->emms_mask_value_pairs.outer;
1812                 mvpr = right->emms_mask_value_pairs.outer;
1813                 break;
1814         case EFX_MAE_RULE_ACTION:
1815                 field_caps = maep->em_action_rule_field_caps;
1816                 desc_setp = __efx_mae_action_rule_mv_desc_set;
1817                 desc_set_nentries =
1818                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1819                 bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
1820                 bit_desc_set_nentries =
1821                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
1822                 mvpl = left->emms_mask_value_pairs.action;
1823                 mvpr = right->emms_mask_value_pairs.action;
1824                 break;
1825         default:
1826                 rc = ENOTSUP;
1827                 goto fail1;
1828         }
1829
1830         if (field_caps == NULL) {
1831                 rc = EAGAIN;
1832                 goto fail2;
1833         }
1834
1835         if (left->emms_type != right->emms_type ||
1836             left->emms_prio != right->emms_prio) {
1837                 /*
1838                  * Rules of different types can never map to the same class.
1839                  *
1840                  * The FW can support some set of match criteria for one
1841                  * priority and not support the very same set for
1842                  * another priority. Thus, two rules which have
1843                  * different priorities can never map to
1844                  * the same class.
1845                  */
1846                 *have_same_classp = B_FALSE;
1847                 return (0);
1848         }
1849
1850         for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1851              ++field_id) {
1852                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1853                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1854                 const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
1855                 const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
1856                 size_t mask_size = descp->emmd_mask_size;
1857                 const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
1858                 const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
1859                 size_t value_size = descp->emmd_value_size;
1860
1861                 if (mask_size == 0)
1862                         continue; /* Skip array gap */
1863
1864                 if ((unsigned int)field_cap_id >= field_ncaps) {
1865                         /*
1866                          * The FW has not reported capability status for this
1867                          * field. It's unknown whether any difference between
1868                          * the two masks / values affects the class. The only
1869                          * case when the class must be the same is when these
1870                          * mask-value pairs match. Otherwise, report mismatch.
1871                          */
1872                         if ((memcmp(lmaskp, rmaskp, mask_size) == 0) &&
1873                             (memcmp(lvalp, rvalp, value_size) == 0))
1874                                 continue;
1875                         else
1876                                 break;
1877                 }
1878
1879                 if (field_caps[field_cap_id].emfc_mask_affects_class) {
1880                         if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
1881                                 have_same_class = B_FALSE;
1882                                 break;
1883                         }
1884                 }
1885
1886                 if (field_caps[field_cap_id].emfc_match_affects_class) {
1887                         if (memcmp(lvalp, rvalp, value_size) != 0) {
1888                                 have_same_class = B_FALSE;
1889                                 break;
1890                         }
1891                 }
1892         }
1893
1894         if (have_same_class == B_FALSE)
1895                 goto done;
1896
1897         for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
1898              ++field_id) {
1899                 const efx_mae_mv_bit_desc_t *bit_descp =
1900                     &bit_desc_setp[field_id];
1901                 efx_mae_field_cap_id_t bit_cap_id =
1902                     bit_descp->emmbd_bit_cap_id;
1903                 unsigned int byte_idx;
1904                 unsigned int bit_idx;
1905
1906                 if (bit_descp->emmbd_entry_is_valid == B_FALSE)
1907                         continue; /* Skip array gap */
1908
1909                 if ((unsigned int)bit_cap_id >= field_ncaps)
1910                         break;
1911
1912                 byte_idx =
1913                     bit_descp->emmbd_mask_ofst +
1914                     bit_descp->emmbd_mask_lbn / 8;
1915                 bit_idx =
1916                     bit_descp->emmbd_mask_lbn % 8;
1917
1918                 if (field_caps[bit_cap_id].emfc_mask_affects_class &&
1919                     (mvpl[byte_idx] & (1U << bit_idx)) !=
1920                     (mvpr[byte_idx] & (1U << bit_idx))) {
1921                         have_same_class = B_FALSE;
1922                         break;
1923                 }
1924
1925                 byte_idx =
1926                     bit_descp->emmbd_value_ofst +
1927                     bit_descp->emmbd_value_lbn / 8;
1928                 bit_idx =
1929                     bit_descp->emmbd_value_lbn % 8;
1930
1931                 if (field_caps[bit_cap_id].emfc_match_affects_class &&
1932                     (mvpl[byte_idx] & (1U << bit_idx)) !=
1933                     (mvpr[byte_idx] & (1U << bit_idx))) {
1934                         have_same_class = B_FALSE;
1935                         break;
1936                 }
1937         }
1938
1939 done:
1940         *have_same_classp = have_same_class;
1941
1942         return (0);
1943
1944 fail2:
1945         EFSYS_PROBE(fail2);
1946 fail1:
1947         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1948         return (rc);
1949 }
1950
1951         __checkReturn           efx_rc_t
1952 efx_mae_outer_rule_insert(
1953         __in                    efx_nic_t *enp,
1954         __in                    const efx_mae_match_spec_t *spec,
1955         __in                    efx_tunnel_protocol_t encap_type,
1956         __out                   efx_mae_rule_id_t *or_idp)
1957 {
1958         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1959         efx_mcdi_req_t req;
1960         EFX_MCDI_DECLARE_BUF(payload,
1961             MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2,
1962             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
1963         uint32_t encap_type_mcdi;
1964         efx_mae_rule_id_t or_id;
1965         size_t offset;
1966         efx_rc_t rc;
1967
1968         EFX_STATIC_ASSERT(sizeof (or_idp->id) ==
1969             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN);
1970
1971         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1972             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL);
1973
1974         if (encp->enc_mae_supported == B_FALSE) {
1975                 rc = ENOTSUP;
1976                 goto fail1;
1977         }
1978
1979         if (spec->emms_type != EFX_MAE_RULE_OUTER) {
1980                 rc = EINVAL;
1981                 goto fail2;
1982         }
1983
1984         switch (encap_type) {
1985         case EFX_TUNNEL_PROTOCOL_NONE:
1986                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
1987                 break;
1988         case EFX_TUNNEL_PROTOCOL_VXLAN:
1989                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
1990                 break;
1991         case EFX_TUNNEL_PROTOCOL_GENEVE:
1992                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
1993                 break;
1994         case EFX_TUNNEL_PROTOCOL_NVGRE:
1995                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
1996                 break;
1997         default:
1998                 rc = ENOTSUP;
1999                 goto fail3;
2000         }
2001
2002         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT;
2003         req.emr_in_buf = payload;
2004         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2;
2005         req.emr_out_buf = payload;
2006         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN;
2007
2008         MCDI_IN_SET_DWORD(req,
2009             MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi);
2010
2011         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio);
2012
2013         /*
2014          * Mask-value pairs have been stored in the byte order needed for the
2015          * MCDI request and are thus safe to be copied directly to the buffer.
2016          * The library cares about byte order in efx_mae_match_spec_field_set().
2017          */
2018         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >=
2019             MAE_ENC_FIELD_PAIRS_LEN);
2020         offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST;
2021         memcpy(payload + offset, spec->emms_mask_value_pairs.outer,
2022             MAE_ENC_FIELD_PAIRS_LEN);
2023
2024         efx_mcdi_execute(enp, &req);
2025
2026         if (req.emr_rc != 0) {
2027                 rc = req.emr_rc;
2028                 goto fail4;
2029         }
2030
2031         if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) {
2032                 rc = EMSGSIZE;
2033                 goto fail5;
2034         }
2035
2036         or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
2037         if (or_id.id == EFX_MAE_RSRC_ID_INVALID) {
2038                 rc = ENOENT;
2039                 goto fail6;
2040         }
2041
2042         or_idp->id = or_id.id;
2043
2044         return (0);
2045
2046 fail6:
2047         EFSYS_PROBE(fail6);
2048 fail5:
2049         EFSYS_PROBE(fail5);
2050 fail4:
2051         EFSYS_PROBE(fail4);
2052 fail3:
2053         EFSYS_PROBE(fail3);
2054 fail2:
2055         EFSYS_PROBE(fail2);
2056 fail1:
2057         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2058         return (rc);
2059 }
2060
2061         __checkReturn           efx_rc_t
2062 efx_mae_outer_rule_remove(
2063         __in                    efx_nic_t *enp,
2064         __in                    const efx_mae_rule_id_t *or_idp)
2065 {
2066         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2067         efx_mcdi_req_t req;
2068         EFX_MCDI_DECLARE_BUF(payload,
2069             MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1),
2070             MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
2071         efx_rc_t rc;
2072
2073         if (encp->enc_mae_supported == B_FALSE) {
2074                 rc = ENOTSUP;
2075                 goto fail1;
2076         }
2077
2078         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE;
2079         req.emr_in_buf = payload;
2080         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1);
2081         req.emr_out_buf = payload;
2082         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1);
2083
2084         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id);
2085
2086         efx_mcdi_execute(enp, &req);
2087
2088         if (req.emr_rc != 0) {
2089                 rc = req.emr_rc;
2090                 goto fail2;
2091         }
2092
2093         if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LENMIN) {
2094                 rc = EMSGSIZE;
2095                 goto fail3;
2096         }
2097
2098         if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) !=
2099             or_idp->id) {
2100                 /* Firmware failed to remove the outer rule. */
2101                 rc = EAGAIN;
2102                 goto fail4;
2103         }
2104
2105         return (0);
2106
2107 fail4:
2108         EFSYS_PROBE(fail4);
2109 fail3:
2110         EFSYS_PROBE(fail3);
2111 fail2:
2112         EFSYS_PROBE(fail2);
2113 fail1:
2114         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2115         return (rc);
2116 }
2117
2118         __checkReturn                   efx_rc_t
2119 efx_mae_match_spec_outer_rule_id_set(
2120         __in                            efx_mae_match_spec_t *spec,
2121         __in                            const efx_mae_rule_id_t *or_idp)
2122 {
2123         uint32_t full_mask = UINT32_MAX;
2124         efx_rc_t rc;
2125
2126         if (spec->emms_type != EFX_MAE_RULE_ACTION) {
2127                 rc = EINVAL;
2128                 goto fail1;
2129         }
2130
2131         if (or_idp == NULL) {
2132                 rc = EINVAL;
2133                 goto fail2;
2134         }
2135
2136         rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID,
2137             sizeof (or_idp->id), (const uint8_t *)&or_idp->id,
2138             sizeof (full_mask), (const uint8_t *)&full_mask);
2139         if (rc != 0)
2140                 goto fail3;
2141
2142         return (0);
2143
2144 fail3:
2145         EFSYS_PROBE(fail3);
2146 fail2:
2147         EFSYS_PROBE(fail2);
2148 fail1:
2149         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2150         return (rc);
2151 }
2152
2153          __checkReturn                  efx_rc_t
2154 efx_mae_encap_header_alloc(
2155         __in                            efx_nic_t *enp,
2156         __in                            efx_tunnel_protocol_t encap_type,
2157         __in_bcount(header_size)        uint8_t *header_data,
2158         __in                            size_t header_size,
2159         __out                           efx_mae_eh_id_t *eh_idp)
2160 {
2161         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2162         efx_mcdi_req_t req;
2163         EFX_MCDI_DECLARE_BUF(payload,
2164             MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LENMAX_MCDI2,
2165             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN);
2166         uint32_t encap_type_mcdi;
2167         efx_mae_eh_id_t eh_id;
2168         efx_rc_t rc;
2169
2170         EFX_STATIC_ASSERT(sizeof (eh_idp->id) ==
2171             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_LEN);
2172
2173         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2174             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
2175
2176         if (encp->enc_mae_supported == B_FALSE) {
2177                 rc = ENOTSUP;
2178                 goto fail1;
2179         }
2180
2181         switch (encap_type) {
2182         case EFX_TUNNEL_PROTOCOL_NONE:
2183                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
2184                 break;
2185         case EFX_TUNNEL_PROTOCOL_VXLAN:
2186                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
2187                 break;
2188         case EFX_TUNNEL_PROTOCOL_GENEVE:
2189                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
2190                 break;
2191         case EFX_TUNNEL_PROTOCOL_NVGRE:
2192                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
2193                 break;
2194         default:
2195                 rc = ENOTSUP;
2196                 goto fail2;
2197         }
2198
2199         if (header_size >
2200             MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2) {
2201                 rc = EINVAL;
2202                 goto fail3;
2203         }
2204
2205         req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_ALLOC;
2206         req.emr_in_buf = payload;
2207         req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(header_size);
2208         req.emr_out_buf = payload;
2209         req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN;
2210
2211         MCDI_IN_SET_DWORD(req,
2212             MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, encap_type_mcdi);
2213
2214         memcpy(payload + MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_OFST,
2215             header_data, header_size);
2216
2217         efx_mcdi_execute(enp, &req);
2218
2219         if (req.emr_rc != 0) {
2220                 rc = req.emr_rc;
2221                 goto fail4;
2222         }
2223
2224         if (req.emr_out_length_used < MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN) {
2225                 rc = EMSGSIZE;
2226                 goto fail5;
2227         }
2228
2229         eh_id.id = MCDI_OUT_DWORD(req,
2230             MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID);
2231
2232         if (eh_id.id == EFX_MAE_RSRC_ID_INVALID) {
2233                 rc = ENOENT;
2234                 goto fail6;
2235         }
2236
2237         eh_idp->id = eh_id.id;
2238
2239         return (0);
2240
2241 fail6:
2242         EFSYS_PROBE(fail6);
2243 fail5:
2244         EFSYS_PROBE(fail5);
2245 fail4:
2246         EFSYS_PROBE(fail4);
2247 fail3:
2248         EFSYS_PROBE(fail3);
2249 fail2:
2250         EFSYS_PROBE(fail2);
2251 fail1:
2252         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2253         return (rc);
2254 }
2255
2256         __checkReturn                   efx_rc_t
2257 efx_mae_encap_header_free(
2258         __in                            efx_nic_t *enp,
2259         __in                            const efx_mae_eh_id_t *eh_idp)
2260 {
2261         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2262         efx_mcdi_req_t req;
2263         EFX_MCDI_DECLARE_BUF(payload,
2264             MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1),
2265             MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1));
2266         efx_rc_t rc;
2267
2268         if (encp->enc_mae_supported == B_FALSE) {
2269                 rc = ENOTSUP;
2270                 goto fail1;
2271         }
2272
2273         req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_FREE;
2274         req.emr_in_buf = payload;
2275         req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1);
2276         req.emr_out_buf = payload;
2277         req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1);
2278
2279         MCDI_IN_SET_DWORD(req, MAE_ENCAP_HEADER_FREE_IN_EH_ID, eh_idp->id);
2280
2281         efx_mcdi_execute(enp, &req);
2282
2283         if (req.emr_rc != 0) {
2284                 rc = req.emr_rc;
2285                 goto fail2;
2286         }
2287
2288         if (MCDI_OUT_DWORD(req, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) !=
2289             eh_idp->id) {
2290                 /* Firmware failed to remove the encap. header. */
2291                 rc = EAGAIN;
2292                 goto fail3;
2293         }
2294
2295         return (0);
2296
2297 fail3:
2298         EFSYS_PROBE(fail3);
2299 fail2:
2300         EFSYS_PROBE(fail2);
2301 fail1:
2302         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2303         return (rc);
2304 }
2305
2306         __checkReturn                   efx_rc_t
2307 efx_mae_action_set_fill_in_eh_id(
2308         __in                            efx_mae_actions_t *spec,
2309         __in                            const efx_mae_eh_id_t *eh_idp)
2310 {
2311         efx_rc_t rc;
2312
2313         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) == 0) {
2314                 /*
2315                  * The caller has not intended to have action ENCAP originally,
2316                  * hence, this attempt to indicate encap. header ID is invalid.
2317                  */
2318                 rc = EINVAL;
2319                 goto fail1;
2320         }
2321
2322         if (spec->ema_rsrc.emar_eh_id.id != EFX_MAE_RSRC_ID_INVALID) {
2323                 /* The caller attempts to indicate encap. header ID twice. */
2324                 rc = EINVAL;
2325                 goto fail2;
2326         }
2327
2328         if (eh_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2329                 rc = EINVAL;
2330                 goto fail3;
2331         }
2332
2333         spec->ema_rsrc.emar_eh_id.id = eh_idp->id;
2334
2335         return (0);
2336
2337 fail3:
2338         EFSYS_PROBE(fail3);
2339 fail2:
2340         EFSYS_PROBE(fail2);
2341 fail1:
2342         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2343         return (rc);
2344 }
2345
2346         __checkReturn                   efx_rc_t
2347 efx_mae_action_set_alloc(
2348         __in                            efx_nic_t *enp,
2349         __in                            const efx_mae_actions_t *spec,
2350         __out                           efx_mae_aset_id_t *aset_idp)
2351 {
2352         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2353         efx_mcdi_req_t req;
2354         EFX_MCDI_DECLARE_BUF(payload,
2355             MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
2356             MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
2357         efx_mae_aset_id_t aset_id;
2358         efx_rc_t rc;
2359
2360         if (encp->enc_mae_supported == B_FALSE) {
2361                 rc = ENOTSUP;
2362                 goto fail1;
2363         }
2364
2365         req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
2366         req.emr_in_buf = payload;
2367         req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
2368         req.emr_out_buf = payload;
2369         req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
2370
2371         /*
2372          * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
2373          * corresponding resource types are supported by the implementation.
2374          * Use proper resource ID assignments instead.
2375          */
2376         MCDI_IN_SET_DWORD(req,
2377             MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
2378
2379         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECAP)) != 0) {
2380                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2381                     MAE_ACTION_SET_ALLOC_IN_DECAP, 1);
2382         }
2383
2384         MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2385             MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
2386
2387         if (spec->ema_n_vlan_tags_to_push > 0) {
2388                 unsigned int outer_tag_idx;
2389
2390                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2391                     MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
2392                     spec->ema_n_vlan_tags_to_push);
2393
2394                 if (spec->ema_n_vlan_tags_to_push ==
2395                     EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
2396                         MCDI_IN_SET_WORD(req,
2397                             MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
2398                             spec->ema_vlan_push_descs[0].emavp_tpid_be);
2399                         MCDI_IN_SET_WORD(req,
2400                             MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
2401                             spec->ema_vlan_push_descs[0].emavp_tci_be);
2402                 }
2403
2404                 outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
2405
2406                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
2407                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
2408                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
2409                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
2410         }
2411
2412         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
2413             spec->ema_rsrc.emar_eh_id.id);
2414         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
2415             spec->ema_rsrc.emar_counter_id.id);
2416
2417         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
2418                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2419                     MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
2420         }
2421
2422         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
2423                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2424                     MAE_ACTION_SET_ALLOC_IN_MARK, 1);
2425
2426                 MCDI_IN_SET_DWORD(req,
2427                     MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
2428         }
2429
2430         MCDI_IN_SET_DWORD(req,
2431             MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
2432
2433         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
2434             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2435         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
2436             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2437
2438         efx_mcdi_execute(enp, &req);
2439
2440         if (req.emr_rc != 0) {
2441                 rc = req.emr_rc;
2442                 goto fail2;
2443         }
2444
2445         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
2446                 rc = EMSGSIZE;
2447                 goto fail3;
2448         }
2449
2450         aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
2451         if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
2452                 rc = ENOENT;
2453                 goto fail4;
2454         }
2455
2456         aset_idp->id = aset_id.id;
2457
2458         return (0);
2459
2460 fail4:
2461         EFSYS_PROBE(fail4);
2462 fail3:
2463         EFSYS_PROBE(fail3);
2464 fail2:
2465         EFSYS_PROBE(fail2);
2466 fail1:
2467         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2468         return (rc);
2469 }
2470
2471         __checkReturn                   unsigned int
2472 efx_mae_action_set_get_nb_count(
2473         __in                            const efx_mae_actions_t *spec)
2474 {
2475         return (spec->ema_n_count_actions);
2476 }
2477
2478         __checkReturn                   efx_rc_t
2479 efx_mae_action_set_fill_in_counter_id(
2480         __in                            efx_mae_actions_t *spec,
2481         __in                            const efx_counter_t *counter_idp)
2482 {
2483         efx_rc_t rc;
2484
2485         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_COUNT)) == 0) {
2486                 /*
2487                  * Invalid to add counter ID if spec does not have COUNT action.
2488                  */
2489                 rc = EINVAL;
2490                 goto fail1;
2491         }
2492
2493         if (spec->ema_n_count_actions != 1) {
2494                 /*
2495                  * Having multiple COUNT actions in the spec requires a counter
2496                  * list to be used. This API must only be used for a single
2497                  * counter per spec. Turn down the request as inappropriate.
2498                  */
2499                 rc = EINVAL;
2500                 goto fail2;
2501         }
2502
2503         if (spec->ema_rsrc.emar_counter_id.id != EFX_MAE_RSRC_ID_INVALID) {
2504                 /* The caller attempts to indicate counter ID twice. */
2505                 rc = EALREADY;
2506                 goto fail3;
2507         }
2508
2509         if (counter_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2510                 rc = EINVAL;
2511                 goto fail4;
2512         }
2513
2514         spec->ema_rsrc.emar_counter_id.id = counter_idp->id;
2515
2516         return (0);
2517
2518 fail4:
2519         EFSYS_PROBE(fail4);
2520 fail3:
2521         EFSYS_PROBE(fail3);
2522 fail2:
2523         EFSYS_PROBE(fail2);
2524 fail1:
2525         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2526         return (rc);
2527 }
2528
2529         __checkReturn                   efx_rc_t
2530 efx_mae_counters_alloc(
2531         __in                            efx_nic_t *enp,
2532         __in                            uint32_t n_counters,
2533         __out                           uint32_t *n_allocatedp,
2534         __out_ecount(n_counters)        efx_counter_t *countersp,
2535         __out_opt                       uint32_t *gen_countp)
2536 {
2537         EFX_MCDI_DECLARE_BUF(payload,
2538             MC_CMD_MAE_COUNTER_ALLOC_IN_LEN,
2539             MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMAX_MCDI2);
2540         efx_mae_t *maep = enp->en_maep;
2541         uint32_t n_allocated;
2542         efx_mcdi_req_t req;
2543         unsigned int i;
2544         efx_rc_t rc;
2545
2546         if (n_counters > maep->em_max_ncounters ||
2547             n_counters < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM ||
2548             n_counters > MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MAXNUM_MCDI2) {
2549                 rc = EINVAL;
2550                 goto fail1;
2551         }
2552
2553         req.emr_cmd = MC_CMD_MAE_COUNTER_ALLOC;
2554         req.emr_in_buf = payload;
2555         req.emr_in_length = MC_CMD_MAE_COUNTER_ALLOC_IN_LEN;
2556         req.emr_out_buf = payload;
2557         req.emr_out_length = MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(n_counters);
2558
2559         MCDI_IN_SET_DWORD(req, MAE_COUNTER_ALLOC_IN_REQUESTED_COUNT,
2560             n_counters);
2561
2562         efx_mcdi_execute(enp, &req);
2563
2564         if (req.emr_rc != 0) {
2565                 rc = req.emr_rc;
2566                 goto fail2;
2567         }
2568
2569         if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMIN) {
2570                 rc = EMSGSIZE;
2571                 goto fail3;
2572         }
2573
2574         n_allocated = MCDI_OUT_DWORD(req,
2575             MAE_COUNTER_ALLOC_OUT_COUNTER_ID_COUNT);
2576         if (n_allocated < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM) {
2577                 rc = EFAULT;
2578                 goto fail4;
2579         }
2580
2581         for (i = 0; i < n_allocated; i++) {
2582                 countersp[i].id = MCDI_OUT_INDEXED_DWORD(req,
2583                     MAE_COUNTER_ALLOC_OUT_COUNTER_ID, i);
2584         }
2585
2586         if (gen_countp != NULL) {
2587                 *gen_countp = MCDI_OUT_DWORD(req,
2588                                     MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT);
2589         }
2590
2591         *n_allocatedp = n_allocated;
2592
2593         return (0);
2594
2595 fail4:
2596         EFSYS_PROBE(fail4);
2597 fail3:
2598         EFSYS_PROBE(fail3);
2599 fail2:
2600         EFSYS_PROBE(fail2);
2601 fail1:
2602         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2603
2604         return (rc);
2605 }
2606
2607         __checkReturn                   efx_rc_t
2608 efx_mae_counters_free(
2609         __in                            efx_nic_t *enp,
2610         __in                            uint32_t n_counters,
2611         __out                           uint32_t *n_freedp,
2612         __in_ecount(n_counters)         const efx_counter_t *countersp,
2613         __out_opt                       uint32_t *gen_countp)
2614 {
2615         EFX_MCDI_DECLARE_BUF(payload,
2616             MC_CMD_MAE_COUNTER_FREE_IN_LENMAX_MCDI2,
2617             MC_CMD_MAE_COUNTER_FREE_OUT_LENMAX_MCDI2);
2618         efx_mae_t *maep = enp->en_maep;
2619         efx_mcdi_req_t req;
2620         uint32_t n_freed;
2621         unsigned int i;
2622         efx_rc_t rc;
2623
2624         if (n_counters > maep->em_max_ncounters ||
2625             n_counters < MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MINNUM ||
2626             n_counters >
2627             MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MAXNUM_MCDI2) {
2628                 rc = EINVAL;
2629                 goto fail1;
2630         }
2631
2632         req.emr_cmd = MC_CMD_MAE_COUNTER_FREE;
2633         req.emr_in_buf = payload;
2634         req.emr_in_length = MC_CMD_MAE_COUNTER_FREE_IN_LEN(n_counters);
2635         req.emr_out_buf = payload;
2636         req.emr_out_length = MC_CMD_MAE_COUNTER_FREE_OUT_LEN(n_counters);
2637
2638         for (i = 0; i < n_counters; i++) {
2639                 MCDI_IN_SET_INDEXED_DWORD(req,
2640                     MAE_COUNTER_FREE_IN_FREE_COUNTER_ID, i, countersp[i].id);
2641         }
2642         MCDI_IN_SET_DWORD(req, MAE_COUNTER_FREE_IN_COUNTER_ID_COUNT,
2643                           n_counters);
2644
2645         efx_mcdi_execute(enp, &req);
2646
2647         if (req.emr_rc != 0) {
2648                 rc = req.emr_rc;
2649                 goto fail2;
2650         }
2651
2652         if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_FREE_OUT_LENMIN) {
2653                 rc = EMSGSIZE;
2654                 goto fail3;
2655         }
2656
2657         n_freed = MCDI_OUT_DWORD(req, MAE_COUNTER_FREE_OUT_COUNTER_ID_COUNT);
2658
2659         if (n_freed < MC_CMD_MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID_MINNUM) {
2660                 rc = EFAULT;
2661                 goto fail4;
2662         }
2663
2664         if (gen_countp != NULL) {
2665                 *gen_countp = MCDI_OUT_DWORD(req,
2666                                     MAE_COUNTER_FREE_OUT_GENERATION_COUNT);
2667         }
2668
2669         *n_freedp = n_freed;
2670
2671         return (0);
2672
2673 fail4:
2674         EFSYS_PROBE(fail4);
2675 fail3:
2676         EFSYS_PROBE(fail3);
2677 fail2:
2678         EFSYS_PROBE(fail2);
2679 fail1:
2680         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2681
2682         return (rc);
2683 }
2684
2685         __checkReturn                   efx_rc_t
2686 efx_mae_counters_stream_start(
2687         __in                            efx_nic_t *enp,
2688         __in                            uint16_t rxq_id,
2689         __in                            uint16_t packet_size,
2690         __in                            uint32_t flags_in,
2691         __out                           uint32_t *flags_out)
2692 {
2693         efx_mcdi_req_t req;
2694         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN,
2695                              MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN);
2696         efx_rc_t rc;
2697
2698         EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_IN_ZERO_SQUASH_DISABLE ==
2699             1U << MC_CMD_MAE_COUNTERS_STREAM_START_IN_ZERO_SQUASH_DISABLE_LBN);
2700
2701         EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_OUT_USES_CREDITS ==
2702             1U << MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_LBN);
2703
2704         req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_START;
2705         req.emr_in_buf = payload;
2706         req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN;
2707         req.emr_out_buf = payload;
2708         req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN;
2709
2710         MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_QID, rxq_id);
2711         MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_PACKET_SIZE,
2712                          packet_size);
2713         MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_START_IN_FLAGS, flags_in);
2714
2715         efx_mcdi_execute(enp, &req);
2716
2717         if (req.emr_rc != 0) {
2718                 rc = req.emr_rc;
2719                 goto fail1;
2720         }
2721
2722         if (req.emr_out_length_used <
2723             MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN) {
2724                 rc = EMSGSIZE;
2725                 goto fail2;
2726         }
2727
2728         *flags_out = MCDI_OUT_DWORD(req, MAE_COUNTERS_STREAM_START_OUT_FLAGS);
2729
2730         return (0);
2731
2732 fail2:
2733         EFSYS_PROBE(fail2);
2734 fail1:
2735         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2736
2737         return (rc);
2738 }
2739
2740         __checkReturn                   efx_rc_t
2741 efx_mae_counters_stream_stop(
2742         __in                            efx_nic_t *enp,
2743         __in                            uint16_t rxq_id,
2744         __out_opt                       uint32_t *gen_countp)
2745 {
2746         efx_mcdi_req_t req;
2747         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN,
2748                              MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN);
2749         efx_rc_t rc;
2750
2751         req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_STOP;
2752         req.emr_in_buf = payload;
2753         req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN;
2754         req.emr_out_buf = payload;
2755         req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN;
2756
2757         MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_STOP_IN_QID, rxq_id);
2758
2759         efx_mcdi_execute(enp, &req);
2760
2761         if (req.emr_rc != 0) {
2762                 rc = req.emr_rc;
2763                 goto fail1;
2764         }
2765
2766         if (req.emr_out_length_used <
2767             MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN) {
2768                 rc = EMSGSIZE;
2769                 goto fail2;
2770         }
2771
2772         if (gen_countp != NULL) {
2773                 *gen_countp = MCDI_OUT_DWORD(req,
2774                             MAE_COUNTERS_STREAM_STOP_OUT_GENERATION_COUNT);
2775         }
2776
2777         return (0);
2778
2779 fail2:
2780         EFSYS_PROBE(fail2);
2781 fail1:
2782         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2783
2784         return (rc);
2785 }
2786
2787         __checkReturn                   efx_rc_t
2788 efx_mae_counters_stream_give_credits(
2789         __in                            efx_nic_t *enp,
2790         __in                            uint32_t n_credits)
2791 {
2792         efx_mcdi_req_t req;
2793         EFX_MCDI_DECLARE_BUF(payload,
2794                              MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN,
2795                              MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN);
2796         efx_rc_t rc;
2797
2798         req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS;
2799         req.emr_in_buf = payload;
2800         req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN;
2801         req.emr_out_buf = payload;
2802         req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN;
2803
2804         MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_NUM_CREDITS,
2805                          n_credits);
2806
2807         efx_mcdi_execute(enp, &req);
2808
2809         if (req.emr_rc != 0) {
2810                 rc = req.emr_rc;
2811                 goto fail1;
2812         }
2813
2814         return (0);
2815
2816 fail1:
2817         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2818
2819         return (rc);
2820 }
2821
2822         __checkReturn                   efx_rc_t
2823 efx_mae_action_set_free(
2824         __in                            efx_nic_t *enp,
2825         __in                            const efx_mae_aset_id_t *aset_idp)
2826 {
2827         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2828         efx_mcdi_req_t req;
2829         EFX_MCDI_DECLARE_BUF(payload,
2830             MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
2831             MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
2832         efx_rc_t rc;
2833
2834         if (encp->enc_mae_supported == B_FALSE) {
2835                 rc = ENOTSUP;
2836                 goto fail1;
2837         }
2838
2839         req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
2840         req.emr_in_buf = payload;
2841         req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
2842         req.emr_out_buf = payload;
2843         req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
2844
2845         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
2846
2847         efx_mcdi_execute(enp, &req);
2848
2849         if (req.emr_rc != 0) {
2850                 rc = req.emr_rc;
2851                 goto fail2;
2852         }
2853
2854         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_FREE_OUT_LENMIN) {
2855                 rc = EMSGSIZE;
2856                 goto fail3;
2857         }
2858
2859         if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
2860             aset_idp->id) {
2861                 /* Firmware failed to free the action set. */
2862                 rc = EAGAIN;
2863                 goto fail4;
2864         }
2865
2866         return (0);
2867
2868 fail4:
2869         EFSYS_PROBE(fail4);
2870 fail3:
2871         EFSYS_PROBE(fail3);
2872 fail2:
2873         EFSYS_PROBE(fail2);
2874 fail1:
2875         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2876         return (rc);
2877 }
2878
2879         __checkReturn                   efx_rc_t
2880 efx_mae_action_rule_insert(
2881         __in                            efx_nic_t *enp,
2882         __in                            const efx_mae_match_spec_t *spec,
2883         __in                            const efx_mae_aset_list_id_t *asl_idp,
2884         __in                            const efx_mae_aset_id_t *as_idp,
2885         __out                           efx_mae_rule_id_t *ar_idp)
2886 {
2887         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2888         efx_mcdi_req_t req;
2889         EFX_MCDI_DECLARE_BUF(payload,
2890             MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2,
2891             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
2892         efx_oword_t *rule_response;
2893         efx_mae_rule_id_t ar_id;
2894         size_t offset;
2895         efx_rc_t rc;
2896
2897         EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
2898             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
2899
2900         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2901             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
2902
2903         if (encp->enc_mae_supported == B_FALSE) {
2904                 rc = ENOTSUP;
2905                 goto fail1;
2906         }
2907
2908         if (spec->emms_type != EFX_MAE_RULE_ACTION ||
2909             (asl_idp != NULL && as_idp != NULL) ||
2910             (asl_idp == NULL && as_idp == NULL)) {
2911                 rc = EINVAL;
2912                 goto fail2;
2913         }
2914
2915         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
2916         req.emr_in_buf = payload;
2917         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
2918         req.emr_out_buf = payload;
2919         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
2920
2921         EFX_STATIC_ASSERT(sizeof (*rule_response) <=
2922             MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
2923         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
2924         rule_response = (efx_oword_t *)(payload + offset);
2925         EFX_POPULATE_OWORD_3(*rule_response,
2926             MAE_ACTION_RULE_RESPONSE_ASL_ID,
2927             (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
2928             MAE_ACTION_RULE_RESPONSE_AS_ID,
2929             (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
2930             MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
2931
2932         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
2933
2934         /*
2935          * Mask-value pairs have been stored in the byte order needed for the
2936          * MCDI request and are thus safe to be copied directly to the buffer.
2937          */
2938         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
2939             MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
2940         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
2941         memcpy(payload + offset, spec->emms_mask_value_pairs.action,
2942             MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
2943
2944         efx_mcdi_execute(enp, &req);
2945
2946         if (req.emr_rc != 0) {
2947                 rc = req.emr_rc;
2948                 goto fail3;
2949         }
2950
2951         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
2952                 rc = EMSGSIZE;
2953                 goto fail4;
2954         }
2955
2956         ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
2957         if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
2958                 rc = ENOENT;
2959                 goto fail5;
2960         }
2961
2962         ar_idp->id = ar_id.id;
2963
2964         return (0);
2965
2966 fail5:
2967         EFSYS_PROBE(fail5);
2968 fail4:
2969         EFSYS_PROBE(fail4);
2970 fail3:
2971         EFSYS_PROBE(fail3);
2972 fail2:
2973         EFSYS_PROBE(fail2);
2974 fail1:
2975         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2976         return (rc);
2977 }
2978
2979         __checkReturn                   efx_rc_t
2980 efx_mae_action_rule_remove(
2981         __in                            efx_nic_t *enp,
2982         __in                            const efx_mae_rule_id_t *ar_idp)
2983 {
2984         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2985         efx_mcdi_req_t req;
2986         EFX_MCDI_DECLARE_BUF(payload,
2987             MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
2988             MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
2989         efx_rc_t rc;
2990
2991         if (encp->enc_mae_supported == B_FALSE) {
2992                 rc = ENOTSUP;
2993                 goto fail1;
2994         }
2995
2996         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
2997         req.emr_in_buf = payload;
2998         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
2999         req.emr_out_buf = payload;
3000         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
3001
3002         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
3003
3004         efx_mcdi_execute(enp, &req);
3005
3006         if (req.emr_rc != 0) {
3007                 rc = req.emr_rc;
3008                 goto fail2;
3009         }
3010
3011         if (req.emr_out_length_used <
3012             MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LENMIN) {
3013                 rc = EMSGSIZE;
3014                 goto fail3;
3015         }
3016
3017         if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
3018             ar_idp->id) {
3019                 /* Firmware failed to delete the action rule. */
3020                 rc = EAGAIN;
3021                 goto fail4;
3022         }
3023
3024         return (0);
3025
3026 fail4:
3027         EFSYS_PROBE(fail4);
3028 fail3:
3029         EFSYS_PROBE(fail3);
3030 fail2:
3031         EFSYS_PROBE(fail2);
3032 fail1:
3033         EFSYS_PROBE1(fail1, efx_rc_t, rc);
3034         return (rc);
3035 }
3036
3037 #endif /* EFSYS_OPT_MAE */