common/sfc_efx/base: apply mask to value on match field set
[dpdk.git] / drivers / common / sfc_efx / base / efx_mae.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2019 Xilinx, Inc. All rights reserved.
4  * All rights reserved.
5  */
6
7 #include "efx.h"
8 #include "efx_impl.h"
9
10
11 #if EFSYS_OPT_MAE
12
13 static  __checkReturn                   efx_rc_t
14 efx_mae_get_capabilities(
15         __in                            efx_nic_t *enp)
16 {
17         efx_mcdi_req_t req;
18         EFX_MCDI_DECLARE_BUF(payload,
19             MC_CMD_MAE_GET_CAPS_IN_LEN,
20             MC_CMD_MAE_GET_CAPS_OUT_LEN);
21         struct efx_mae_s *maep = enp->en_maep;
22         efx_rc_t rc;
23
24         req.emr_cmd = MC_CMD_MAE_GET_CAPS;
25         req.emr_in_buf = payload;
26         req.emr_in_length = MC_CMD_MAE_GET_CAPS_IN_LEN;
27         req.emr_out_buf = payload;
28         req.emr_out_length = MC_CMD_MAE_GET_CAPS_OUT_LEN;
29
30         efx_mcdi_execute(enp, &req);
31
32         if (req.emr_rc != 0) {
33                 rc = req.emr_rc;
34                 goto fail1;
35         }
36
37         if (req.emr_out_length_used < MC_CMD_MAE_GET_CAPS_OUT_LEN) {
38                 rc = EMSGSIZE;
39                 goto fail2;
40         }
41
42         maep->em_max_n_outer_prios =
43             MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_OUTER_PRIOS);
44
45         maep->em_max_n_action_prios =
46             MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ACTION_PRIOS);
47
48         maep->em_encap_types_supported = 0;
49
50         if (MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ENCAP_TYPE_VXLAN) == 1) {
51                 maep->em_encap_types_supported |=
52                     (1U << EFX_TUNNEL_PROTOCOL_VXLAN);
53         }
54
55         if (MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ENCAP_TYPE_GENEVE) == 1) {
56                 maep->em_encap_types_supported |=
57                     (1U << EFX_TUNNEL_PROTOCOL_GENEVE);
58         }
59
60         if (MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ENCAP_TYPE_NVGRE) == 1) {
61                 maep->em_encap_types_supported |=
62                     (1U << EFX_TUNNEL_PROTOCOL_NVGRE);
63         }
64
65         maep->em_max_nfields =
66             MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT);
67
68         return (0);
69
70 fail2:
71         EFSYS_PROBE(fail2);
72 fail1:
73         EFSYS_PROBE1(fail1, efx_rc_t, rc);
74         return (rc);
75 }
76
77 static  __checkReturn                   efx_rc_t
78 efx_mae_get_outer_rule_caps(
79         __in                            efx_nic_t *enp,
80         __in                            unsigned int field_ncaps,
81         __out_ecount(field_ncaps)       efx_mae_field_cap_t *field_caps)
82 {
83         efx_mcdi_req_t req;
84         EFX_MCDI_DECLARE_BUF(payload,
85             MC_CMD_MAE_GET_OR_CAPS_IN_LEN,
86             MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2);
87         unsigned int mcdi_field_ncaps;
88         unsigned int i;
89         efx_rc_t rc;
90
91         if (MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps) >
92             MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2) {
93                 rc = EINVAL;
94                 goto fail1;
95         }
96
97         req.emr_cmd = MC_CMD_MAE_GET_OR_CAPS;
98         req.emr_in_buf = payload;
99         req.emr_in_length = MC_CMD_MAE_GET_OR_CAPS_IN_LEN;
100         req.emr_out_buf = payload;
101         req.emr_out_length = MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps);
102
103         efx_mcdi_execute(enp, &req);
104
105         if (req.emr_rc != 0) {
106                 rc = req.emr_rc;
107                 goto fail2;
108         }
109
110         mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_OR_CAPS_OUT_COUNT);
111
112         if (req.emr_out_length_used <
113             MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(mcdi_field_ncaps)) {
114                 rc = EMSGSIZE;
115                 goto fail3;
116         }
117
118         if (mcdi_field_ncaps > field_ncaps) {
119                 rc = EMSGSIZE;
120                 goto fail4;
121         }
122
123         for (i = 0; i < mcdi_field_ncaps; ++i) {
124                 uint32_t match_flag;
125                 uint32_t mask_flag;
126
127                 field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req,
128                     MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
129                     MAE_FIELD_FLAGS_SUPPORT_STATUS);
130
131                 match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
132                     MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
133                     MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS);
134
135                 field_caps[i].emfc_match_affects_class =
136                     (match_flag != 0) ? B_TRUE : B_FALSE;
137
138                 mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
139                     MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
140                     MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS);
141
142                 field_caps[i].emfc_mask_affects_class =
143                     (mask_flag != 0) ? B_TRUE : B_FALSE;
144         }
145
146         return (0);
147
148 fail4:
149         EFSYS_PROBE(fail4);
150 fail3:
151         EFSYS_PROBE(fail3);
152 fail2:
153         EFSYS_PROBE(fail2);
154 fail1:
155         EFSYS_PROBE1(fail1, efx_rc_t, rc);
156         return (rc);
157 }
158
159 static  __checkReturn                   efx_rc_t
160 efx_mae_get_action_rule_caps(
161         __in                            efx_nic_t *enp,
162         __in                            unsigned int field_ncaps,
163         __out_ecount(field_ncaps)       efx_mae_field_cap_t *field_caps)
164 {
165         efx_mcdi_req_t req;
166         EFX_MCDI_DECLARE_BUF(payload,
167             MC_CMD_MAE_GET_AR_CAPS_IN_LEN,
168             MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2);
169         unsigned int mcdi_field_ncaps;
170         unsigned int i;
171         efx_rc_t rc;
172
173         if (MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps) >
174             MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2) {
175                 rc = EINVAL;
176                 goto fail1;
177         }
178
179         req.emr_cmd = MC_CMD_MAE_GET_AR_CAPS;
180         req.emr_in_buf = payload;
181         req.emr_in_length = MC_CMD_MAE_GET_AR_CAPS_IN_LEN;
182         req.emr_out_buf = payload;
183         req.emr_out_length = MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps);
184
185         efx_mcdi_execute(enp, &req);
186
187         if (req.emr_rc != 0) {
188                 rc = req.emr_rc;
189                 goto fail2;
190         }
191
192         mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_OR_CAPS_OUT_COUNT);
193
194         if (req.emr_out_length_used <
195             MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(mcdi_field_ncaps)) {
196                 rc = EMSGSIZE;
197                 goto fail3;
198         }
199
200         if (mcdi_field_ncaps > field_ncaps) {
201                 rc = EMSGSIZE;
202                 goto fail4;
203         }
204
205         for (i = 0; i < mcdi_field_ncaps; ++i) {
206                 uint32_t match_flag;
207                 uint32_t mask_flag;
208
209                 field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req,
210                     MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
211                     MAE_FIELD_FLAGS_SUPPORT_STATUS);
212
213                 match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
214                     MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
215                     MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS);
216
217                 field_caps[i].emfc_match_affects_class =
218                     (match_flag != 0) ? B_TRUE : B_FALSE;
219
220                 mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
221                     MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
222                     MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS);
223
224                 field_caps[i].emfc_mask_affects_class =
225                     (mask_flag != 0) ? B_TRUE : B_FALSE;
226         }
227
228         return (0);
229
230 fail4:
231         EFSYS_PROBE(fail4);
232 fail3:
233         EFSYS_PROBE(fail3);
234 fail2:
235         EFSYS_PROBE(fail2);
236 fail1:
237         EFSYS_PROBE1(fail1, efx_rc_t, rc);
238         return (rc);
239 }
240
241         __checkReturn                   efx_rc_t
242 efx_mae_init(
243         __in                            efx_nic_t *enp)
244 {
245         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
246         efx_mae_field_cap_t *or_fcaps;
247         size_t or_fcaps_size;
248         efx_mae_field_cap_t *ar_fcaps;
249         size_t ar_fcaps_size;
250         efx_mae_t *maep;
251         efx_rc_t rc;
252
253         if (encp->enc_mae_supported == B_FALSE) {
254                 rc = ENOTSUP;
255                 goto fail1;
256         }
257
258         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*maep), maep);
259         if (maep == NULL) {
260                 rc = ENOMEM;
261                 goto fail2;
262         }
263
264         enp->en_maep = maep;
265
266         rc = efx_mae_get_capabilities(enp);
267         if (rc != 0)
268                 goto fail3;
269
270         or_fcaps_size = maep->em_max_nfields * sizeof (*or_fcaps);
271         EFSYS_KMEM_ALLOC(enp->en_esip, or_fcaps_size, or_fcaps);
272         if (or_fcaps == NULL) {
273                 rc = ENOMEM;
274                 goto fail4;
275         }
276
277         maep->em_outer_rule_field_caps_size = or_fcaps_size;
278         maep->em_outer_rule_field_caps = or_fcaps;
279
280         rc = efx_mae_get_outer_rule_caps(enp, maep->em_max_nfields, or_fcaps);
281         if (rc != 0)
282                 goto fail5;
283
284         ar_fcaps_size = maep->em_max_nfields * sizeof (*ar_fcaps);
285         EFSYS_KMEM_ALLOC(enp->en_esip, ar_fcaps_size, ar_fcaps);
286         if (ar_fcaps == NULL) {
287                 rc = ENOMEM;
288                 goto fail6;
289         }
290
291         maep->em_action_rule_field_caps_size = ar_fcaps_size;
292         maep->em_action_rule_field_caps = ar_fcaps;
293
294         rc = efx_mae_get_action_rule_caps(enp, maep->em_max_nfields, ar_fcaps);
295         if (rc != 0)
296                 goto fail7;
297
298         return (0);
299
300 fail7:
301         EFSYS_PROBE(fail5);
302         EFSYS_KMEM_FREE(enp->en_esip, ar_fcaps_size, ar_fcaps);
303 fail6:
304         EFSYS_PROBE(fail4);
305 fail5:
306         EFSYS_PROBE(fail5);
307         EFSYS_KMEM_FREE(enp->en_esip, or_fcaps_size, or_fcaps);
308 fail4:
309         EFSYS_PROBE(fail4);
310 fail3:
311         EFSYS_PROBE(fail3);
312         EFSYS_KMEM_FREE(enp->en_esip, sizeof (struct efx_mae_s), enp->en_maep);
313         enp->en_maep = NULL;
314 fail2:
315         EFSYS_PROBE(fail2);
316 fail1:
317         EFSYS_PROBE1(fail1, efx_rc_t, rc);
318         return (rc);
319 }
320
321                                         void
322 efx_mae_fini(
323         __in                            efx_nic_t *enp)
324 {
325         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
326         efx_mae_t *maep = enp->en_maep;
327
328         if (encp->enc_mae_supported == B_FALSE)
329                 return;
330
331         EFSYS_KMEM_FREE(enp->en_esip, maep->em_action_rule_field_caps_size,
332             maep->em_action_rule_field_caps);
333         EFSYS_KMEM_FREE(enp->en_esip, maep->em_outer_rule_field_caps_size,
334             maep->em_outer_rule_field_caps);
335         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*maep), maep);
336         enp->en_maep = NULL;
337 }
338
339         __checkReturn                   efx_rc_t
340 efx_mae_get_limits(
341         __in                            efx_nic_t *enp,
342         __out                           efx_mae_limits_t *emlp)
343 {
344         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
345         struct efx_mae_s *maep = enp->en_maep;
346         efx_rc_t rc;
347
348         if (encp->enc_mae_supported == B_FALSE) {
349                 rc = ENOTSUP;
350                 goto fail1;
351         }
352
353         emlp->eml_max_n_outer_prios = maep->em_max_n_outer_prios;
354         emlp->eml_max_n_action_prios = maep->em_max_n_action_prios;
355         emlp->eml_encap_types_supported = maep->em_encap_types_supported;
356
357         return (0);
358
359 fail1:
360         EFSYS_PROBE1(fail1, efx_rc_t, rc);
361         return (rc);
362 }
363
364         __checkReturn                   efx_rc_t
365 efx_mae_match_spec_init(
366         __in                            efx_nic_t *enp,
367         __in                            efx_mae_rule_type_t type,
368         __in                            uint32_t prio,
369         __out                           efx_mae_match_spec_t **specp)
370 {
371         efx_mae_match_spec_t *spec;
372         efx_rc_t rc;
373
374         switch (type) {
375         case EFX_MAE_RULE_OUTER:
376                 break;
377         case EFX_MAE_RULE_ACTION:
378                 break;
379         default:
380                 rc = ENOTSUP;
381                 goto fail1;
382         }
383
384         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
385         if (spec == NULL) {
386                 rc = ENOMEM;
387                 goto fail2;
388         }
389
390         spec->emms_type = type;
391         spec->emms_prio = prio;
392
393         *specp = spec;
394
395         return (0);
396
397 fail2:
398         EFSYS_PROBE(fail2);
399 fail1:
400         EFSYS_PROBE1(fail1, efx_rc_t, rc);
401         return (rc);
402 }
403
404                                         void
405 efx_mae_match_spec_fini(
406         __in                            efx_nic_t *enp,
407         __in                            efx_mae_match_spec_t *spec)
408 {
409         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
410 }
411
412 /* Named identifiers which are valid indices to efx_mae_field_cap_t */
413 typedef enum efx_mae_field_cap_id_e {
414         EFX_MAE_FIELD_ID_INGRESS_MPORT_SELECTOR = MAE_FIELD_INGRESS_PORT,
415         EFX_MAE_FIELD_ID_ETHER_TYPE_BE = MAE_FIELD_ETHER_TYPE,
416         EFX_MAE_FIELD_ID_ETH_SADDR_BE = MAE_FIELD_ETH_SADDR,
417         EFX_MAE_FIELD_ID_ETH_DADDR_BE = MAE_FIELD_ETH_DADDR,
418         EFX_MAE_FIELD_ID_VLAN0_TCI_BE = MAE_FIELD_VLAN0_TCI,
419         EFX_MAE_FIELD_ID_VLAN0_PROTO_BE = MAE_FIELD_VLAN0_PROTO,
420         EFX_MAE_FIELD_ID_VLAN1_TCI_BE = MAE_FIELD_VLAN1_TCI,
421         EFX_MAE_FIELD_ID_VLAN1_PROTO_BE = MAE_FIELD_VLAN1_PROTO,
422         EFX_MAE_FIELD_ID_SRC_IP4_BE = MAE_FIELD_SRC_IP4,
423         EFX_MAE_FIELD_ID_DST_IP4_BE = MAE_FIELD_DST_IP4,
424         EFX_MAE_FIELD_ID_IP_PROTO = MAE_FIELD_IP_PROTO,
425         EFX_MAE_FIELD_ID_IP_TOS = MAE_FIELD_IP_TOS,
426         EFX_MAE_FIELD_ID_IP_TTL = MAE_FIELD_IP_TTL,
427         EFX_MAE_FIELD_ID_SRC_IP6_BE = MAE_FIELD_SRC_IP6,
428         EFX_MAE_FIELD_ID_DST_IP6_BE = MAE_FIELD_DST_IP6,
429         EFX_MAE_FIELD_ID_L4_SPORT_BE = MAE_FIELD_L4_SPORT,
430         EFX_MAE_FIELD_ID_L4_DPORT_BE = MAE_FIELD_L4_DPORT,
431         EFX_MAE_FIELD_ID_TCP_FLAGS_BE = MAE_FIELD_TCP_FLAGS,
432         EFX_MAE_FIELD_ID_ENC_ETHER_TYPE_BE = MAE_FIELD_ENC_ETHER_TYPE,
433         EFX_MAE_FIELD_ID_ENC_ETH_SADDR_BE = MAE_FIELD_ENC_ETH_SADDR,
434         EFX_MAE_FIELD_ID_ENC_ETH_DADDR_BE = MAE_FIELD_ENC_ETH_DADDR,
435         EFX_MAE_FIELD_ID_ENC_VLAN0_TCI_BE = MAE_FIELD_ENC_VLAN0_TCI,
436         EFX_MAE_FIELD_ID_ENC_VLAN0_PROTO_BE = MAE_FIELD_ENC_VLAN0_PROTO,
437         EFX_MAE_FIELD_ID_ENC_VLAN1_TCI_BE = MAE_FIELD_ENC_VLAN1_TCI,
438         EFX_MAE_FIELD_ID_ENC_VLAN1_PROTO_BE = MAE_FIELD_ENC_VLAN1_PROTO,
439         EFX_MAE_FIELD_ID_ENC_SRC_IP4_BE = MAE_FIELD_ENC_SRC_IP4,
440         EFX_MAE_FIELD_ID_ENC_DST_IP4_BE = MAE_FIELD_ENC_DST_IP4,
441         EFX_MAE_FIELD_ID_ENC_IP_PROTO = MAE_FIELD_ENC_IP_PROTO,
442         EFX_MAE_FIELD_ID_ENC_IP_TOS = MAE_FIELD_ENC_IP_TOS,
443         EFX_MAE_FIELD_ID_ENC_IP_TTL = MAE_FIELD_ENC_IP_TTL,
444         EFX_MAE_FIELD_ID_ENC_SRC_IP6_BE = MAE_FIELD_ENC_SRC_IP6,
445         EFX_MAE_FIELD_ID_ENC_DST_IP6_BE = MAE_FIELD_ENC_DST_IP6,
446         EFX_MAE_FIELD_ID_ENC_L4_SPORT_BE = MAE_FIELD_ENC_L4_SPORT,
447         EFX_MAE_FIELD_ID_ENC_L4_DPORT_BE = MAE_FIELD_ENC_L4_DPORT,
448         EFX_MAE_FIELD_ID_ENC_VNET_ID_BE = MAE_FIELD_ENC_VNET_ID,
449         EFX_MAE_FIELD_ID_OUTER_RULE_ID = MAE_FIELD_OUTER_RULE_ID,
450
451         EFX_MAE_FIELD_CAP_NIDS
452 } efx_mae_field_cap_id_t;
453
454 typedef enum efx_mae_field_endianness_e {
455         EFX_MAE_FIELD_LE = 0,
456         EFX_MAE_FIELD_BE,
457
458         EFX_MAE_FIELD_ENDIANNESS_NTYPES
459 } efx_mae_field_endianness_t;
460
461 /*
462  * The following structure is a means to describe an MAE field.
463  * The information in it is meant to be used internally by
464  * APIs for addressing a given field in a mask-value pairs
465  * structure and for validation purposes.
466  *
467  * A field may have an alternative one. This structure
468  * has additional members to reference the alternative
469  * field's mask. See efx_mae_match_spec_is_valid().
470  */
471 typedef struct efx_mae_mv_desc_s {
472         efx_mae_field_cap_id_t          emmd_field_cap_id;
473
474         size_t                          emmd_value_size;
475         size_t                          emmd_value_offset;
476         size_t                          emmd_mask_size;
477         size_t                          emmd_mask_offset;
478
479         /*
480          * Having the alternative field's mask size set to 0
481          * means that there's no alternative field specified.
482          */
483         size_t                          emmd_alt_mask_size;
484         size_t                          emmd_alt_mask_offset;
485
486         /* Primary field and the alternative one are of the same endianness. */
487         efx_mae_field_endianness_t      emmd_endianness;
488 } efx_mae_mv_desc_t;
489
490 /* Indices to this array are provided by efx_mae_field_id_t */
491 static const efx_mae_mv_desc_t __efx_mae_action_rule_mv_desc_set[] = {
492 #define EFX_MAE_MV_DESC(_name, _endianness)                             \
493         [EFX_MAE_FIELD_##_name] =                                       \
494         {                                                               \
495                 EFX_MAE_FIELD_ID_##_name,                               \
496                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_LEN,               \
497                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_OFST,              \
498                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_LEN,          \
499                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_OFST,         \
500                 0, 0 /* no alternative field */,                        \
501                 _endianness                                             \
502         }
503
504         EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
505         EFX_MAE_MV_DESC(ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
506         EFX_MAE_MV_DESC(ETH_SADDR_BE, EFX_MAE_FIELD_BE),
507         EFX_MAE_MV_DESC(ETH_DADDR_BE, EFX_MAE_FIELD_BE),
508         EFX_MAE_MV_DESC(VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
509         EFX_MAE_MV_DESC(VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
510         EFX_MAE_MV_DESC(VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
511         EFX_MAE_MV_DESC(VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
512         EFX_MAE_MV_DESC(SRC_IP4_BE, EFX_MAE_FIELD_BE),
513         EFX_MAE_MV_DESC(DST_IP4_BE, EFX_MAE_FIELD_BE),
514         EFX_MAE_MV_DESC(IP_PROTO, EFX_MAE_FIELD_BE),
515         EFX_MAE_MV_DESC(IP_TOS, EFX_MAE_FIELD_BE),
516         EFX_MAE_MV_DESC(IP_TTL, EFX_MAE_FIELD_BE),
517         EFX_MAE_MV_DESC(SRC_IP6_BE, EFX_MAE_FIELD_BE),
518         EFX_MAE_MV_DESC(DST_IP6_BE, EFX_MAE_FIELD_BE),
519         EFX_MAE_MV_DESC(L4_SPORT_BE, EFX_MAE_FIELD_BE),
520         EFX_MAE_MV_DESC(L4_DPORT_BE, EFX_MAE_FIELD_BE),
521         EFX_MAE_MV_DESC(TCP_FLAGS_BE, EFX_MAE_FIELD_BE),
522         EFX_MAE_MV_DESC(ENC_VNET_ID_BE, EFX_MAE_FIELD_BE),
523         EFX_MAE_MV_DESC(OUTER_RULE_ID, EFX_MAE_FIELD_LE),
524
525 #undef EFX_MAE_MV_DESC
526 };
527
528 /* Indices to this array are provided by efx_mae_field_id_t */
529 static const efx_mae_mv_desc_t __efx_mae_outer_rule_mv_desc_set[] = {
530 #define EFX_MAE_MV_DESC(_name, _endianness)                             \
531         [EFX_MAE_FIELD_##_name] =                                       \
532         {                                                               \
533                 EFX_MAE_FIELD_ID_##_name,                               \
534                 MAE_ENC_FIELD_PAIRS_##_name##_LEN,                      \
535                 MAE_ENC_FIELD_PAIRS_##_name##_OFST,                     \
536                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,                 \
537                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,                \
538                 0, 0 /* no alternative field */,                        \
539                 _endianness                                             \
540         }
541
542 /* Same as EFX_MAE_MV_DESC(), but also indicates an alternative field. */
543 #define EFX_MAE_MV_DESC_ALT(_name, _alt_name, _endianness)              \
544         [EFX_MAE_FIELD_##_name] =                                       \
545         {                                                               \
546                 EFX_MAE_FIELD_ID_##_name,                               \
547                 MAE_ENC_FIELD_PAIRS_##_name##_LEN,                      \
548                 MAE_ENC_FIELD_PAIRS_##_name##_OFST,                     \
549                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,                 \
550                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,                \
551                 MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_LEN,             \
552                 MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_OFST,            \
553                 _endianness                                             \
554         }
555
556         EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
557         EFX_MAE_MV_DESC(ENC_ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
558         EFX_MAE_MV_DESC(ENC_ETH_SADDR_BE, EFX_MAE_FIELD_BE),
559         EFX_MAE_MV_DESC(ENC_ETH_DADDR_BE, EFX_MAE_FIELD_BE),
560         EFX_MAE_MV_DESC(ENC_VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
561         EFX_MAE_MV_DESC(ENC_VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
562         EFX_MAE_MV_DESC(ENC_VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
563         EFX_MAE_MV_DESC(ENC_VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
564         EFX_MAE_MV_DESC_ALT(ENC_SRC_IP4_BE, ENC_SRC_IP6_BE, EFX_MAE_FIELD_BE),
565         EFX_MAE_MV_DESC_ALT(ENC_DST_IP4_BE, ENC_DST_IP6_BE, EFX_MAE_FIELD_BE),
566         EFX_MAE_MV_DESC(ENC_IP_PROTO, EFX_MAE_FIELD_BE),
567         EFX_MAE_MV_DESC(ENC_IP_TOS, EFX_MAE_FIELD_BE),
568         EFX_MAE_MV_DESC(ENC_IP_TTL, EFX_MAE_FIELD_BE),
569         EFX_MAE_MV_DESC_ALT(ENC_SRC_IP6_BE, ENC_SRC_IP4_BE, EFX_MAE_FIELD_BE),
570         EFX_MAE_MV_DESC_ALT(ENC_DST_IP6_BE, ENC_DST_IP4_BE, EFX_MAE_FIELD_BE),
571         EFX_MAE_MV_DESC(ENC_L4_SPORT_BE, EFX_MAE_FIELD_BE),
572         EFX_MAE_MV_DESC(ENC_L4_DPORT_BE, EFX_MAE_FIELD_BE),
573
574 #undef EFX_MAE_MV_DESC_ALT
575 #undef EFX_MAE_MV_DESC
576 };
577
578         __checkReturn                   efx_rc_t
579 efx_mae_mport_by_phy_port(
580         __in                            uint32_t phy_port,
581         __out                           efx_mport_sel_t *mportp)
582 {
583         efx_dword_t dword;
584         efx_rc_t rc;
585
586         if (phy_port > EFX_MASK32(MAE_MPORT_SELECTOR_PPORT_ID)) {
587                 rc = EINVAL;
588                 goto fail1;
589         }
590
591         EFX_POPULATE_DWORD_2(dword,
592             MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT,
593             MAE_MPORT_SELECTOR_PPORT_ID, phy_port);
594
595         memset(mportp, 0, sizeof (*mportp));
596         /*
597          * The constructed DWORD is little-endian,
598          * but the resulting value is meant to be
599          * passed to MCDIs, where it will undergo
600          * host-order to little endian conversion.
601          */
602         mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
603
604         return (0);
605
606 fail1:
607         EFSYS_PROBE1(fail1, efx_rc_t, rc);
608         return (rc);
609 }
610
611         __checkReturn                   efx_rc_t
612 efx_mae_mport_by_pcie_function(
613         __in                            uint32_t pf,
614         __in                            uint32_t vf,
615         __out                           efx_mport_sel_t *mportp)
616 {
617         efx_dword_t dword;
618         efx_rc_t rc;
619
620         EFX_STATIC_ASSERT(EFX_PCI_VF_INVALID ==
621             MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL);
622
623         if (pf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_PF_ID)) {
624                 rc = EINVAL;
625                 goto fail1;
626         }
627
628         if (vf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_VF_ID)) {
629                 rc = EINVAL;
630                 goto fail2;
631         }
632
633         EFX_POPULATE_DWORD_3(dword,
634             MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
635             MAE_MPORT_SELECTOR_FUNC_PF_ID, pf,
636             MAE_MPORT_SELECTOR_FUNC_VF_ID, vf);
637
638         memset(mportp, 0, sizeof (*mportp));
639         /*
640          * The constructed DWORD is little-endian,
641          * but the resulting value is meant to be
642          * passed to MCDIs, where it will undergo
643          * host-order to little endian conversion.
644          */
645         mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
646
647         return (0);
648
649 fail2:
650         EFSYS_PROBE(fail2);
651 fail1:
652         EFSYS_PROBE1(fail1, efx_rc_t, rc);
653         return (rc);
654 }
655
656         __checkReturn                   efx_rc_t
657 efx_mae_match_spec_field_set(
658         __in                            efx_mae_match_spec_t *spec,
659         __in                            efx_mae_field_id_t field_id,
660         __in                            size_t value_size,
661         __in_bcount(value_size)         const uint8_t *value,
662         __in                            size_t mask_size,
663         __in_bcount(mask_size)          const uint8_t *mask)
664 {
665         const efx_mae_mv_desc_t *descp;
666         unsigned int desc_set_nentries;
667         uint8_t *mvp;
668         efx_rc_t rc;
669
670         switch (spec->emms_type) {
671         case EFX_MAE_RULE_OUTER:
672                 desc_set_nentries =
673                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
674                 descp = &__efx_mae_outer_rule_mv_desc_set[field_id];
675                 mvp = spec->emms_mask_value_pairs.outer;
676                 break;
677         case EFX_MAE_RULE_ACTION:
678                 desc_set_nentries =
679                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
680                 descp = &__efx_mae_action_rule_mv_desc_set[field_id];
681                 mvp = spec->emms_mask_value_pairs.action;
682                 break;
683         default:
684                 rc = ENOTSUP;
685                 goto fail1;
686         }
687
688         if ((unsigned int)field_id >= desc_set_nentries) {
689                 rc = EINVAL;
690                 goto fail2;
691         }
692
693         if (descp->emmd_mask_size == 0) {
694                 /* The ID points to a gap in the array of field descriptors. */
695                 rc = EINVAL;
696                 goto fail3;
697         }
698
699         if (value_size != descp->emmd_value_size) {
700                 rc = EINVAL;
701                 goto fail4;
702         }
703
704         if (mask_size != descp->emmd_mask_size) {
705                 rc = EINVAL;
706                 goto fail5;
707         }
708
709         if (descp->emmd_endianness == EFX_MAE_FIELD_BE) {
710                 unsigned int i;
711
712                 /*
713                  * The mask/value are in network (big endian) order.
714                  * The MCDI request field is also big endian.
715                  */
716
717                 EFSYS_ASSERT3U(value_size, ==, mask_size);
718
719                 for (i = 0; i < value_size; ++i) {
720                         uint8_t *v_bytep = mvp + descp->emmd_value_offset + i;
721                         uint8_t *m_bytep = mvp + descp->emmd_mask_offset + i;
722
723                         /*
724                          * Apply the mask (which may be all-zeros) to the value.
725                          *
726                          * If this API is provided with some value to set for a
727                          * given field in one specification and with some other
728                          * value to set for this field in another specification,
729                          * then, if the two masks are all-zeros, the field will
730                          * avoid being counted as a mismatch when comparing the
731                          * specifications using efx_mae_match_specs_equal() API.
732                          */
733                         *v_bytep = value[i] & mask[i];
734                         *m_bytep = mask[i];
735                 }
736         } else {
737                 efx_dword_t dword;
738
739                 /*
740                  * The mask/value are in host byte order.
741                  * The MCDI request field is little endian.
742                  */
743                 switch (value_size) {
744                 case 4:
745                         EFX_POPULATE_DWORD_1(dword,
746                             EFX_DWORD_0, *(const uint32_t *)value);
747
748                         memcpy(mvp + descp->emmd_value_offset,
749                             &dword, sizeof (dword));
750                         break;
751                 default:
752                         EFSYS_ASSERT(B_FALSE);
753                 }
754
755                 switch (mask_size) {
756                 case 4:
757                         EFX_POPULATE_DWORD_1(dword,
758                             EFX_DWORD_0, *(const uint32_t *)mask);
759
760                         memcpy(mvp + descp->emmd_mask_offset,
761                             &dword, sizeof (dword));
762                         break;
763                 default:
764                         EFSYS_ASSERT(B_FALSE);
765                 }
766         }
767
768         return (0);
769
770 fail5:
771         EFSYS_PROBE(fail5);
772 fail4:
773         EFSYS_PROBE(fail4);
774 fail3:
775         EFSYS_PROBE(fail3);
776 fail2:
777         EFSYS_PROBE(fail2);
778 fail1:
779         EFSYS_PROBE1(fail1, efx_rc_t, rc);
780         return (rc);
781 }
782
783         __checkReturn                   efx_rc_t
784 efx_mae_match_spec_mport_set(
785         __in                            efx_mae_match_spec_t *spec,
786         __in                            const efx_mport_sel_t *valuep,
787         __in_opt                        const efx_mport_sel_t *maskp)
788 {
789         uint32_t full_mask = UINT32_MAX;
790         const uint8_t *vp;
791         const uint8_t *mp;
792         efx_rc_t rc;
793
794         if (valuep == NULL) {
795                 rc = EINVAL;
796                 goto fail1;
797         }
798
799         vp = (const uint8_t *)&valuep->sel;
800         if (maskp != NULL)
801                 mp = (const uint8_t *)&maskp->sel;
802         else
803                 mp = (const uint8_t *)&full_mask;
804
805         rc = efx_mae_match_spec_field_set(spec,
806             EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR,
807             sizeof (valuep->sel), vp, sizeof (maskp->sel), mp);
808         if (rc != 0)
809                 goto fail2;
810
811         return (0);
812
813 fail2:
814         EFSYS_PROBE(fail2);
815 fail1:
816         EFSYS_PROBE1(fail1, efx_rc_t, rc);
817         return (rc);
818 }
819
820         __checkReturn                   boolean_t
821 efx_mae_match_specs_equal(
822         __in                            const efx_mae_match_spec_t *left,
823         __in                            const efx_mae_match_spec_t *right)
824 {
825         return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
826 }
827
828 #define EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit)              \
829             ((_mask)[(_bit) / (_mask_page_nbits)] &                     \
830                     (1ULL << ((_bit) & ((_mask_page_nbits) - 1))))
831
832 static                                  boolean_t
833 efx_mask_is_prefix(
834         __in                            size_t mask_nbytes,
835         __in_bcount(mask_nbytes)        const uint8_t *maskp)
836 {
837         boolean_t prev_bit_is_set = B_TRUE;
838         unsigned int i;
839
840         for (i = 0; i < 8 * mask_nbytes; ++i) {
841                 boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i);
842
843                 if (!prev_bit_is_set && bit_is_set)
844                         return B_FALSE;
845
846                 prev_bit_is_set = bit_is_set;
847         }
848
849         return B_TRUE;
850 }
851
852 static                                  boolean_t
853 efx_mask_is_all_ones(
854         __in                            size_t mask_nbytes,
855         __in_bcount(mask_nbytes)        const uint8_t *maskp)
856 {
857         unsigned int i;
858         uint8_t t = ~0;
859
860         for (i = 0; i < mask_nbytes; ++i)
861                 t &= maskp[i];
862
863         return (t == (uint8_t)(~0));
864 }
865
866 static                                  boolean_t
867 efx_mask_is_all_zeros(
868         __in                            size_t mask_nbytes,
869         __in_bcount(mask_nbytes)        const uint8_t *maskp)
870 {
871         unsigned int i;
872         uint8_t t = 0;
873
874         for (i = 0; i < mask_nbytes; ++i)
875                 t |= maskp[i];
876
877         return (t == 0);
878 }
879
880         __checkReturn                   boolean_t
881 efx_mae_match_spec_is_valid(
882         __in                            efx_nic_t *enp,
883         __in                            const efx_mae_match_spec_t *spec)
884 {
885         efx_mae_t *maep = enp->en_maep;
886         unsigned int field_ncaps = maep->em_max_nfields;
887         const efx_mae_field_cap_t *field_caps;
888         const efx_mae_mv_desc_t *desc_setp;
889         unsigned int desc_set_nentries;
890         boolean_t is_valid = B_TRUE;
891         efx_mae_field_id_t field_id;
892         const uint8_t *mvp;
893
894         switch (spec->emms_type) {
895         case EFX_MAE_RULE_OUTER:
896                 field_caps = maep->em_outer_rule_field_caps;
897                 desc_setp = __efx_mae_outer_rule_mv_desc_set;
898                 desc_set_nentries =
899                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
900                 mvp = spec->emms_mask_value_pairs.outer;
901                 break;
902         case EFX_MAE_RULE_ACTION:
903                 field_caps = maep->em_action_rule_field_caps;
904                 desc_setp = __efx_mae_action_rule_mv_desc_set;
905                 desc_set_nentries =
906                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
907                 mvp = spec->emms_mask_value_pairs.action;
908                 break;
909         default:
910                 return (B_FALSE);
911         }
912
913         if (field_caps == NULL)
914                 return (B_FALSE);
915
916         for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
917              ++field_id) {
918                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
919                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
920                 const uint8_t *alt_m_buf = mvp + descp->emmd_alt_mask_offset;
921                 const uint8_t *m_buf = mvp + descp->emmd_mask_offset;
922                 size_t alt_m_size = descp->emmd_alt_mask_size;
923                 size_t m_size = descp->emmd_mask_size;
924
925                 if (m_size == 0)
926                         continue; /* Skip array gap */
927
928                 if ((unsigned int)field_cap_id >= field_ncaps) {
929                         /*
930                          * The FW has not reported capability status for
931                          * this field. Make sure that its mask is zeroed.
932                          */
933                         is_valid = efx_mask_is_all_zeros(m_size, m_buf);
934                         if (is_valid != B_FALSE)
935                                 continue;
936                         else
937                                 break;
938                 }
939
940                 switch (field_caps[field_cap_id].emfc_support) {
941                 case MAE_FIELD_SUPPORTED_MATCH_MASK:
942                         is_valid = B_TRUE;
943                         break;
944                 case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
945                         is_valid = efx_mask_is_prefix(m_size, m_buf);
946                         break;
947                 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
948                         is_valid = (efx_mask_is_all_ones(m_size, m_buf) ||
949                             efx_mask_is_all_zeros(m_size, m_buf));
950                         break;
951                 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
952                         is_valid = efx_mask_is_all_ones(m_size, m_buf);
953
954                         if ((is_valid == B_FALSE) && (alt_m_size != 0)) {
955                                 /*
956                                  * This field has an alternative one. The FW
957                                  * reports ALWAYS for both implying that one
958                                  * of them is required to have all-ones mask.
959                                  *
960                                  * The primary field's mask is incorrect; go
961                                  * on to check that of the alternative field.
962                                  */
963                                 is_valid = efx_mask_is_all_ones(alt_m_size,
964                                                                 alt_m_buf);
965                         }
966                         break;
967                 case MAE_FIELD_SUPPORTED_MATCH_NEVER:
968                 case MAE_FIELD_UNSUPPORTED:
969                 default:
970                         is_valid = efx_mask_is_all_zeros(m_size, m_buf);
971                         break;
972                 }
973
974                 if (is_valid == B_FALSE)
975                         break;
976         }
977
978         return (is_valid);
979 }
980
981         __checkReturn                   efx_rc_t
982 efx_mae_action_set_spec_init(
983         __in                            efx_nic_t *enp,
984         __out                           efx_mae_actions_t **specp)
985 {
986         efx_mae_actions_t *spec;
987         efx_rc_t rc;
988
989         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
990         if (spec == NULL) {
991                 rc = ENOMEM;
992                 goto fail1;
993         }
994
995         *specp = spec;
996
997         return (0);
998
999 fail1:
1000         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1001         return (rc);
1002 }
1003
1004                                         void
1005 efx_mae_action_set_spec_fini(
1006         __in                            efx_nic_t *enp,
1007         __in                            efx_mae_actions_t *spec)
1008 {
1009         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
1010 }
1011
1012 static  __checkReturn                   efx_rc_t
1013 efx_mae_action_set_add_vlan_pop(
1014         __in                            efx_mae_actions_t *spec,
1015         __in                            size_t arg_size,
1016         __in_bcount(arg_size)           const uint8_t *arg)
1017 {
1018         efx_rc_t rc;
1019
1020         if (arg_size != 0) {
1021                 rc = EINVAL;
1022                 goto fail1;
1023         }
1024
1025         if (arg != NULL) {
1026                 rc = EINVAL;
1027                 goto fail2;
1028         }
1029
1030         if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) {
1031                 rc = ENOTSUP;
1032                 goto fail3;
1033         }
1034
1035         ++spec->ema_n_vlan_tags_to_pop;
1036
1037         return (0);
1038
1039 fail3:
1040         EFSYS_PROBE(fail3);
1041 fail2:
1042         EFSYS_PROBE(fail2);
1043 fail1:
1044         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1045         return (rc);
1046 }
1047
1048 static  __checkReturn                   efx_rc_t
1049 efx_mae_action_set_add_vlan_push(
1050         __in                            efx_mae_actions_t *spec,
1051         __in                            size_t arg_size,
1052         __in_bcount(arg_size)           const uint8_t *arg)
1053 {
1054         unsigned int n_tags = spec->ema_n_vlan_tags_to_push;
1055         efx_rc_t rc;
1056
1057         if (arg_size != sizeof (*spec->ema_vlan_push_descs)) {
1058                 rc = EINVAL;
1059                 goto fail1;
1060         }
1061
1062         if (arg == NULL) {
1063                 rc = EINVAL;
1064                 goto fail2;
1065         }
1066
1067         if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1068                 rc = ENOTSUP;
1069                 goto fail3;
1070         }
1071
1072         memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size);
1073         ++(spec->ema_n_vlan_tags_to_push);
1074
1075         return (0);
1076
1077 fail3:
1078         EFSYS_PROBE(fail3);
1079 fail2:
1080         EFSYS_PROBE(fail2);
1081 fail1:
1082         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1083         return (rc);
1084 }
1085
1086 static  __checkReturn                   efx_rc_t
1087 efx_mae_action_set_add_flag(
1088         __in                            efx_mae_actions_t *spec,
1089         __in                            size_t arg_size,
1090         __in_bcount(arg_size)           const uint8_t *arg)
1091 {
1092         efx_rc_t rc;
1093
1094         _NOTE(ARGUNUSED(spec))
1095
1096         if (arg_size != 0) {
1097                 rc = EINVAL;
1098                 goto fail1;
1099         }
1100
1101         if (arg != NULL) {
1102                 rc = EINVAL;
1103                 goto fail2;
1104         }
1105
1106         /* This action does not have any arguments, so do nothing here. */
1107
1108         return (0);
1109
1110 fail2:
1111         EFSYS_PROBE(fail2);
1112 fail1:
1113         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1114         return (rc);
1115 }
1116
1117 static  __checkReturn                   efx_rc_t
1118 efx_mae_action_set_add_mark(
1119         __in                            efx_mae_actions_t *spec,
1120         __in                            size_t arg_size,
1121         __in_bcount(arg_size)           const uint8_t *arg)
1122 {
1123         efx_rc_t rc;
1124
1125         if (arg_size != sizeof (spec->ema_mark_value)) {
1126                 rc = EINVAL;
1127                 goto fail1;
1128         }
1129
1130         if (arg == NULL) {
1131                 rc = EINVAL;
1132                 goto fail2;
1133         }
1134
1135         memcpy(&spec->ema_mark_value, arg, arg_size);
1136
1137         return (0);
1138
1139 fail2:
1140         EFSYS_PROBE(fail2);
1141 fail1:
1142         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1143         return (rc);
1144 }
1145
1146 static  __checkReturn                   efx_rc_t
1147 efx_mae_action_set_add_deliver(
1148         __in                            efx_mae_actions_t *spec,
1149         __in                            size_t arg_size,
1150         __in_bcount(arg_size)           const uint8_t *arg)
1151 {
1152         efx_rc_t rc;
1153
1154         if (arg_size != sizeof (spec->ema_deliver_mport)) {
1155                 rc = EINVAL;
1156                 goto fail1;
1157         }
1158
1159         if (arg == NULL) {
1160                 rc = EINVAL;
1161                 goto fail2;
1162         }
1163
1164         memcpy(&spec->ema_deliver_mport, arg, arg_size);
1165
1166         return (0);
1167
1168 fail2:
1169         EFSYS_PROBE(fail2);
1170 fail1:
1171         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1172         return (rc);
1173 }
1174
1175 typedef struct efx_mae_action_desc_s {
1176         /* Action specific handler */
1177         efx_rc_t        (*emad_add)(efx_mae_actions_t *,
1178                                     size_t, const uint8_t *);
1179 } efx_mae_action_desc_t;
1180
1181 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
1182         [EFX_MAE_ACTION_VLAN_POP] = {
1183                 .emad_add = efx_mae_action_set_add_vlan_pop
1184         },
1185         [EFX_MAE_ACTION_VLAN_PUSH] = {
1186                 .emad_add = efx_mae_action_set_add_vlan_push
1187         },
1188         [EFX_MAE_ACTION_FLAG] = {
1189                 .emad_add = efx_mae_action_set_add_flag
1190         },
1191         [EFX_MAE_ACTION_MARK] = {
1192                 .emad_add = efx_mae_action_set_add_mark
1193         },
1194         [EFX_MAE_ACTION_DELIVER] = {
1195                 .emad_add = efx_mae_action_set_add_deliver
1196         }
1197 };
1198
1199 static const uint32_t efx_mae_action_ordered_map =
1200         (1U << EFX_MAE_ACTION_VLAN_POP) |
1201         (1U << EFX_MAE_ACTION_VLAN_PUSH) |
1202         (1U << EFX_MAE_ACTION_FLAG) |
1203         (1U << EFX_MAE_ACTION_MARK) |
1204         (1U << EFX_MAE_ACTION_DELIVER);
1205
1206 /*
1207  * These actions must not be added after DELIVER, but
1208  * they can have any place among the rest of
1209  * strictly ordered actions.
1210  */
1211 static const uint32_t efx_mae_action_nonstrict_map =
1212         (1U << EFX_MAE_ACTION_FLAG) |
1213         (1U << EFX_MAE_ACTION_MARK);
1214
1215 static const uint32_t efx_mae_action_repeat_map =
1216         (1U << EFX_MAE_ACTION_VLAN_POP) |
1217         (1U << EFX_MAE_ACTION_VLAN_PUSH);
1218
1219 /*
1220  * Add an action to an action set.
1221  *
1222  * This has to be invoked in the desired action order.
1223  * An out-of-order action request will be turned down.
1224  */
1225 static  __checkReturn                   efx_rc_t
1226 efx_mae_action_set_spec_populate(
1227         __in                            efx_mae_actions_t *spec,
1228         __in                            efx_mae_action_t type,
1229         __in                            size_t arg_size,
1230         __in_bcount(arg_size)           const uint8_t *arg)
1231 {
1232         uint32_t action_mask;
1233         efx_rc_t rc;
1234
1235         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1236             (sizeof (efx_mae_action_ordered_map) * 8));
1237         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1238             (sizeof (efx_mae_action_repeat_map) * 8));
1239
1240         EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
1241         EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK);
1242         EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER);
1243
1244         if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
1245                 rc = EINVAL;
1246                 goto fail1;
1247         }
1248
1249         action_mask = (1U << type);
1250
1251         if ((spec->ema_actions & action_mask) != 0) {
1252                 /* The action set already contains this action. */
1253                 if ((efx_mae_action_repeat_map & action_mask) == 0) {
1254                         /* Cannot add another non-repeatable action. */
1255                         rc = ENOTSUP;
1256                         goto fail2;
1257                 }
1258         }
1259
1260         if ((efx_mae_action_ordered_map & action_mask) != 0) {
1261                 uint32_t strict_ordered_map =
1262                     efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map;
1263                 uint32_t later_actions_mask =
1264                     strict_ordered_map & ~(action_mask | (action_mask - 1));
1265
1266                 if ((spec->ema_actions & later_actions_mask) != 0) {
1267                         /* Cannot add an action after later ordered actions. */
1268                         rc = ENOTSUP;
1269                         goto fail3;
1270                 }
1271         }
1272
1273         if (efx_mae_actions[type].emad_add != NULL) {
1274                 rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
1275                 if (rc != 0)
1276                         goto fail4;
1277         }
1278
1279         spec->ema_actions |= action_mask;
1280
1281         return (0);
1282
1283 fail4:
1284         EFSYS_PROBE(fail4);
1285 fail3:
1286         EFSYS_PROBE(fail3);
1287 fail2:
1288         EFSYS_PROBE(fail2);
1289 fail1:
1290         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1291         return (rc);
1292 }
1293
1294         __checkReturn                   efx_rc_t
1295 efx_mae_action_set_populate_vlan_pop(
1296         __in                            efx_mae_actions_t *spec)
1297 {
1298         return (efx_mae_action_set_spec_populate(spec,
1299             EFX_MAE_ACTION_VLAN_POP, 0, NULL));
1300 }
1301
1302         __checkReturn                   efx_rc_t
1303 efx_mae_action_set_populate_vlan_push(
1304         __in                            efx_mae_actions_t *spec,
1305         __in                            uint16_t tpid_be,
1306         __in                            uint16_t tci_be)
1307 {
1308         efx_mae_action_vlan_push_t action;
1309         const uint8_t *arg = (const uint8_t *)&action;
1310
1311         action.emavp_tpid_be = tpid_be;
1312         action.emavp_tci_be = tci_be;
1313
1314         return (efx_mae_action_set_spec_populate(spec,
1315             EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg));
1316 }
1317
1318         __checkReturn                   efx_rc_t
1319 efx_mae_action_set_populate_flag(
1320         __in                            efx_mae_actions_t *spec)
1321 {
1322         return (efx_mae_action_set_spec_populate(spec,
1323             EFX_MAE_ACTION_FLAG, 0, NULL));
1324 }
1325
1326         __checkReturn                   efx_rc_t
1327 efx_mae_action_set_populate_mark(
1328         __in                            efx_mae_actions_t *spec,
1329         __in                            uint32_t mark_value)
1330 {
1331         const uint8_t *arg = (const uint8_t *)&mark_value;
1332
1333         return (efx_mae_action_set_spec_populate(spec,
1334             EFX_MAE_ACTION_MARK, sizeof (mark_value), arg));
1335 }
1336
1337         __checkReturn                   efx_rc_t
1338 efx_mae_action_set_populate_deliver(
1339         __in                            efx_mae_actions_t *spec,
1340         __in                            const efx_mport_sel_t *mportp)
1341 {
1342         const uint8_t *arg;
1343         efx_rc_t rc;
1344
1345         if (mportp == NULL) {
1346                 rc = EINVAL;
1347                 goto fail1;
1348         }
1349
1350         arg = (const uint8_t *)&mportp->sel;
1351
1352         return (efx_mae_action_set_spec_populate(spec,
1353             EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
1354
1355 fail1:
1356         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1357         return (rc);
1358 }
1359
1360         __checkReturn                   efx_rc_t
1361 efx_mae_action_set_populate_drop(
1362         __in                            efx_mae_actions_t *spec)
1363 {
1364         efx_mport_sel_t mport;
1365         const uint8_t *arg;
1366         efx_dword_t dword;
1367
1368         EFX_POPULATE_DWORD_1(dword,
1369             MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL);
1370
1371         /*
1372          * The constructed DWORD is little-endian,
1373          * but the resulting value is meant to be
1374          * passed to MCDIs, where it will undergo
1375          * host-order to little endian conversion.
1376          */
1377         mport.sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
1378
1379         arg = (const uint8_t *)&mport.sel;
1380
1381         return (efx_mae_action_set_spec_populate(spec,
1382             EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg));
1383 }
1384
1385         __checkReturn                   boolean_t
1386 efx_mae_action_set_specs_equal(
1387         __in                            const efx_mae_actions_t *left,
1388         __in                            const efx_mae_actions_t *right)
1389 {
1390         return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
1391 }
1392
1393         __checkReturn                   efx_rc_t
1394 efx_mae_match_specs_class_cmp(
1395         __in                            efx_nic_t *enp,
1396         __in                            const efx_mae_match_spec_t *left,
1397         __in                            const efx_mae_match_spec_t *right,
1398         __out                           boolean_t *have_same_classp)
1399 {
1400         efx_mae_t *maep = enp->en_maep;
1401         unsigned int field_ncaps = maep->em_max_nfields;
1402         const efx_mae_field_cap_t *field_caps;
1403         const efx_mae_mv_desc_t *desc_setp;
1404         unsigned int desc_set_nentries;
1405         boolean_t have_same_class = B_TRUE;
1406         efx_mae_field_id_t field_id;
1407         const uint8_t *mvpl;
1408         const uint8_t *mvpr;
1409         efx_rc_t rc;
1410
1411         switch (left->emms_type) {
1412         case EFX_MAE_RULE_OUTER:
1413                 field_caps = maep->em_outer_rule_field_caps;
1414                 desc_setp = __efx_mae_outer_rule_mv_desc_set;
1415                 desc_set_nentries =
1416                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1417                 mvpl = left->emms_mask_value_pairs.outer;
1418                 mvpr = right->emms_mask_value_pairs.outer;
1419                 break;
1420         case EFX_MAE_RULE_ACTION:
1421                 field_caps = maep->em_action_rule_field_caps;
1422                 desc_setp = __efx_mae_action_rule_mv_desc_set;
1423                 desc_set_nentries =
1424                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1425                 mvpl = left->emms_mask_value_pairs.action;
1426                 mvpr = right->emms_mask_value_pairs.action;
1427                 break;
1428         default:
1429                 rc = ENOTSUP;
1430                 goto fail1;
1431         }
1432
1433         if (field_caps == NULL) {
1434                 rc = EAGAIN;
1435                 goto fail2;
1436         }
1437
1438         if (left->emms_type != right->emms_type ||
1439             left->emms_prio != right->emms_prio) {
1440                 /*
1441                  * Rules of different types can never map to the same class.
1442                  *
1443                  * The FW can support some set of match criteria for one
1444                  * priority and not support the very same set for
1445                  * another priority. Thus, two rules which have
1446                  * different priorities can never map to
1447                  * the same class.
1448                  */
1449                 *have_same_classp = B_FALSE;
1450                 return (0);
1451         }
1452
1453         for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1454              ++field_id) {
1455                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1456                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1457                 const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
1458                 const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
1459                 size_t mask_size = descp->emmd_mask_size;
1460                 const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
1461                 const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
1462                 size_t value_size = descp->emmd_value_size;
1463
1464                 if (mask_size == 0)
1465                         continue; /* Skip array gap */
1466
1467                 if ((unsigned int)field_cap_id >= field_ncaps) {
1468                         /*
1469                          * The FW has not reported capability status for this
1470                          * field. It's unknown whether any difference between
1471                          * the two masks / values affects the class. The only
1472                          * case when the class must be the same is when these
1473                          * mask-value pairs match. Otherwise, report mismatch.
1474                          */
1475                         if ((memcmp(lmaskp, rmaskp, mask_size) == 0) &&
1476                             (memcmp(lvalp, rvalp, value_size) == 0))
1477                                 continue;
1478                         else
1479                                 break;
1480                 }
1481
1482                 if (field_caps[field_cap_id].emfc_mask_affects_class) {
1483                         if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
1484                                 have_same_class = B_FALSE;
1485                                 break;
1486                         }
1487                 }
1488
1489                 if (field_caps[field_cap_id].emfc_match_affects_class) {
1490                         if (memcmp(lvalp, rvalp, value_size) != 0) {
1491                                 have_same_class = B_FALSE;
1492                                 break;
1493                         }
1494                 }
1495         }
1496
1497         *have_same_classp = have_same_class;
1498
1499         return (0);
1500
1501 fail2:
1502         EFSYS_PROBE(fail2);
1503 fail1:
1504         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1505         return (rc);
1506 }
1507
1508         __checkReturn           efx_rc_t
1509 efx_mae_outer_rule_insert(
1510         __in                    efx_nic_t *enp,
1511         __in                    const efx_mae_match_spec_t *spec,
1512         __in                    efx_tunnel_protocol_t encap_type,
1513         __out                   efx_mae_rule_id_t *or_idp)
1514 {
1515         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1516         efx_mcdi_req_t req;
1517         EFX_MCDI_DECLARE_BUF(payload,
1518             MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2,
1519             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
1520         uint32_t encap_type_mcdi;
1521         efx_mae_rule_id_t or_id;
1522         size_t offset;
1523         efx_rc_t rc;
1524
1525         EFX_STATIC_ASSERT(sizeof (or_idp->id) ==
1526             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN);
1527
1528         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1529             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL);
1530
1531         if (encp->enc_mae_supported == B_FALSE) {
1532                 rc = ENOTSUP;
1533                 goto fail1;
1534         }
1535
1536         if (spec->emms_type != EFX_MAE_RULE_OUTER) {
1537                 rc = EINVAL;
1538                 goto fail2;
1539         }
1540
1541         switch (encap_type) {
1542         case EFX_TUNNEL_PROTOCOL_NONE:
1543                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
1544                 break;
1545         case EFX_TUNNEL_PROTOCOL_VXLAN:
1546                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
1547                 break;
1548         case EFX_TUNNEL_PROTOCOL_GENEVE:
1549                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
1550                 break;
1551         case EFX_TUNNEL_PROTOCOL_NVGRE:
1552                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
1553                 break;
1554         default:
1555                 rc = ENOTSUP;
1556                 goto fail3;
1557         }
1558
1559         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT;
1560         req.emr_in_buf = payload;
1561         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2;
1562         req.emr_out_buf = payload;
1563         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN;
1564
1565         MCDI_IN_SET_DWORD(req,
1566             MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi);
1567
1568         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio);
1569
1570         /*
1571          * Mask-value pairs have been stored in the byte order needed for the
1572          * MCDI request and are thus safe to be copied directly to the buffer.
1573          * The library cares about byte order in efx_mae_match_spec_field_set().
1574          */
1575         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >=
1576             MAE_ENC_FIELD_PAIRS_LEN);
1577         offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST;
1578         memcpy(payload + offset, spec->emms_mask_value_pairs.outer,
1579             MAE_ENC_FIELD_PAIRS_LEN);
1580
1581         efx_mcdi_execute(enp, &req);
1582
1583         if (req.emr_rc != 0) {
1584                 rc = req.emr_rc;
1585                 goto fail4;
1586         }
1587
1588         if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) {
1589                 rc = EMSGSIZE;
1590                 goto fail5;
1591         }
1592
1593         or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
1594         if (or_id.id == EFX_MAE_RSRC_ID_INVALID) {
1595                 rc = ENOENT;
1596                 goto fail6;
1597         }
1598
1599         or_idp->id = or_id.id;
1600
1601         return (0);
1602
1603 fail6:
1604         EFSYS_PROBE(fail6);
1605 fail5:
1606         EFSYS_PROBE(fail5);
1607 fail4:
1608         EFSYS_PROBE(fail4);
1609 fail3:
1610         EFSYS_PROBE(fail3);
1611 fail2:
1612         EFSYS_PROBE(fail2);
1613 fail1:
1614         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1615         return (rc);
1616 }
1617
1618         __checkReturn           efx_rc_t
1619 efx_mae_outer_rule_remove(
1620         __in                    efx_nic_t *enp,
1621         __in                    const efx_mae_rule_id_t *or_idp)
1622 {
1623         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1624         efx_mcdi_req_t req;
1625         EFX_MCDI_DECLARE_BUF(payload,
1626             MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1),
1627             MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
1628         efx_rc_t rc;
1629
1630         if (encp->enc_mae_supported == B_FALSE) {
1631                 rc = ENOTSUP;
1632                 goto fail1;
1633         }
1634
1635         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE;
1636         req.emr_in_buf = payload;
1637         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1);
1638         req.emr_out_buf = payload;
1639         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1);
1640
1641         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id);
1642
1643         efx_mcdi_execute(enp, &req);
1644
1645         if (req.emr_rc != 0) {
1646                 rc = req.emr_rc;
1647                 goto fail2;
1648         }
1649
1650         if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) !=
1651             or_idp->id) {
1652                 /* Firmware failed to remove the outer rule. */
1653                 rc = EAGAIN;
1654                 goto fail3;
1655         }
1656
1657         return (0);
1658
1659 fail3:
1660         EFSYS_PROBE(fail3);
1661 fail2:
1662         EFSYS_PROBE(fail2);
1663 fail1:
1664         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1665         return (rc);
1666 }
1667
1668         __checkReturn                   efx_rc_t
1669 efx_mae_match_spec_outer_rule_id_set(
1670         __in                            efx_mae_match_spec_t *spec,
1671         __in                            const efx_mae_rule_id_t *or_idp)
1672 {
1673         uint32_t full_mask = UINT32_MAX;
1674         efx_rc_t rc;
1675
1676         if (spec->emms_type != EFX_MAE_RULE_ACTION) {
1677                 rc = EINVAL;
1678                 goto fail1;
1679         }
1680
1681         if (or_idp == NULL) {
1682                 rc = EINVAL;
1683                 goto fail2;
1684         }
1685
1686         rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID,
1687             sizeof (or_idp->id), (const uint8_t *)&or_idp->id,
1688             sizeof (full_mask), (const uint8_t *)&full_mask);
1689         if (rc != 0)
1690                 goto fail3;
1691
1692         return (0);
1693
1694 fail3:
1695         EFSYS_PROBE(fail3);
1696 fail2:
1697         EFSYS_PROBE(fail2);
1698 fail1:
1699         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1700         return (rc);
1701 }
1702
1703         __checkReturn                   efx_rc_t
1704 efx_mae_action_set_alloc(
1705         __in                            efx_nic_t *enp,
1706         __in                            const efx_mae_actions_t *spec,
1707         __out                           efx_mae_aset_id_t *aset_idp)
1708 {
1709         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1710         efx_mcdi_req_t req;
1711         EFX_MCDI_DECLARE_BUF(payload,
1712             MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
1713             MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
1714         efx_mae_aset_id_t aset_id;
1715         efx_rc_t rc;
1716
1717         if (encp->enc_mae_supported == B_FALSE) {
1718                 rc = ENOTSUP;
1719                 goto fail1;
1720         }
1721
1722         req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
1723         req.emr_in_buf = payload;
1724         req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
1725         req.emr_out_buf = payload;
1726         req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
1727
1728         /*
1729          * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
1730          * corresponding resource types are supported by the implementation.
1731          * Use proper resource ID assignments instead.
1732          */
1733         MCDI_IN_SET_DWORD(req,
1734             MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
1735         MCDI_IN_SET_DWORD(req,
1736             MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
1737         MCDI_IN_SET_DWORD(req,
1738             MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, EFX_MAE_RSRC_ID_INVALID);
1739
1740         MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1741             MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
1742
1743         if (spec->ema_n_vlan_tags_to_push > 0) {
1744                 unsigned int outer_tag_idx;
1745
1746                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1747                     MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
1748                     spec->ema_n_vlan_tags_to_push);
1749
1750                 if (spec->ema_n_vlan_tags_to_push ==
1751                     EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1752                         MCDI_IN_SET_WORD(req,
1753                             MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
1754                             spec->ema_vlan_push_descs[0].emavp_tpid_be);
1755                         MCDI_IN_SET_WORD(req,
1756                             MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
1757                             spec->ema_vlan_push_descs[0].emavp_tci_be);
1758                 }
1759
1760                 outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
1761
1762                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
1763                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
1764                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
1765                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
1766         }
1767
1768         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
1769                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1770                     MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
1771         }
1772
1773         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
1774                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1775                     MAE_ACTION_SET_ALLOC_IN_MARK, 1);
1776
1777                 MCDI_IN_SET_DWORD(req,
1778                     MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
1779         }
1780
1781         MCDI_IN_SET_DWORD(req,
1782             MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
1783
1784         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
1785             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
1786         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
1787             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
1788
1789         efx_mcdi_execute(enp, &req);
1790
1791         if (req.emr_rc != 0) {
1792                 rc = req.emr_rc;
1793                 goto fail2;
1794         }
1795
1796         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
1797                 rc = EMSGSIZE;
1798                 goto fail3;
1799         }
1800
1801         aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
1802         if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
1803                 rc = ENOENT;
1804                 goto fail4;
1805         }
1806
1807         aset_idp->id = aset_id.id;
1808
1809         return (0);
1810
1811 fail4:
1812         EFSYS_PROBE(fail4);
1813 fail3:
1814         EFSYS_PROBE(fail3);
1815 fail2:
1816         EFSYS_PROBE(fail2);
1817 fail1:
1818         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1819         return (rc);
1820 }
1821
1822         __checkReturn                   efx_rc_t
1823 efx_mae_action_set_free(
1824         __in                            efx_nic_t *enp,
1825         __in                            const efx_mae_aset_id_t *aset_idp)
1826 {
1827         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1828         efx_mcdi_req_t req;
1829         EFX_MCDI_DECLARE_BUF(payload,
1830             MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
1831             MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
1832         efx_rc_t rc;
1833
1834         if (encp->enc_mae_supported == B_FALSE) {
1835                 rc = ENOTSUP;
1836                 goto fail1;
1837         }
1838
1839         req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
1840         req.emr_in_buf = payload;
1841         req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
1842         req.emr_out_buf = payload;
1843         req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
1844
1845         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
1846
1847         efx_mcdi_execute(enp, &req);
1848
1849         if (req.emr_rc != 0) {
1850                 rc = req.emr_rc;
1851                 goto fail2;
1852         }
1853
1854         if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
1855             aset_idp->id) {
1856                 /* Firmware failed to free the action set. */
1857                 rc = EAGAIN;
1858                 goto fail3;
1859         }
1860
1861         return (0);
1862
1863 fail3:
1864         EFSYS_PROBE(fail3);
1865 fail2:
1866         EFSYS_PROBE(fail2);
1867 fail1:
1868         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1869         return (rc);
1870 }
1871
1872         __checkReturn                   efx_rc_t
1873 efx_mae_action_rule_insert(
1874         __in                            efx_nic_t *enp,
1875         __in                            const efx_mae_match_spec_t *spec,
1876         __in                            const efx_mae_aset_list_id_t *asl_idp,
1877         __in                            const efx_mae_aset_id_t *as_idp,
1878         __out                           efx_mae_rule_id_t *ar_idp)
1879 {
1880         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1881         efx_mcdi_req_t req;
1882         EFX_MCDI_DECLARE_BUF(payload,
1883             MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2,
1884             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
1885         efx_oword_t *rule_response;
1886         efx_mae_rule_id_t ar_id;
1887         size_t offset;
1888         efx_rc_t rc;
1889
1890         EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
1891             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
1892
1893         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1894             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
1895
1896         if (encp->enc_mae_supported == B_FALSE) {
1897                 rc = ENOTSUP;
1898                 goto fail1;
1899         }
1900
1901         if (spec->emms_type != EFX_MAE_RULE_ACTION ||
1902             (asl_idp != NULL && as_idp != NULL) ||
1903             (asl_idp == NULL && as_idp == NULL)) {
1904                 rc = EINVAL;
1905                 goto fail2;
1906         }
1907
1908         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
1909         req.emr_in_buf = payload;
1910         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
1911         req.emr_out_buf = payload;
1912         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
1913
1914         EFX_STATIC_ASSERT(sizeof (*rule_response) <=
1915             MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
1916         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
1917         rule_response = (efx_oword_t *)(payload + offset);
1918         EFX_POPULATE_OWORD_3(*rule_response,
1919             MAE_ACTION_RULE_RESPONSE_ASL_ID,
1920             (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
1921             MAE_ACTION_RULE_RESPONSE_AS_ID,
1922             (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
1923             MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
1924
1925         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
1926
1927         /*
1928          * Mask-value pairs have been stored in the byte order needed for the
1929          * MCDI request and are thus safe to be copied directly to the buffer.
1930          */
1931         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
1932             MAE_FIELD_MASK_VALUE_PAIRS_LEN);
1933         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
1934         memcpy(payload + offset, spec->emms_mask_value_pairs.action,
1935             MAE_FIELD_MASK_VALUE_PAIRS_LEN);
1936
1937         efx_mcdi_execute(enp, &req);
1938
1939         if (req.emr_rc != 0) {
1940                 rc = req.emr_rc;
1941                 goto fail3;
1942         }
1943
1944         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
1945                 rc = EMSGSIZE;
1946                 goto fail4;
1947         }
1948
1949         ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
1950         if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
1951                 rc = ENOENT;
1952                 goto fail5;
1953         }
1954
1955         ar_idp->id = ar_id.id;
1956
1957         return (0);
1958
1959 fail5:
1960         EFSYS_PROBE(fail5);
1961 fail4:
1962         EFSYS_PROBE(fail4);
1963 fail3:
1964         EFSYS_PROBE(fail3);
1965 fail2:
1966         EFSYS_PROBE(fail2);
1967 fail1:
1968         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1969         return (rc);
1970 }
1971
1972         __checkReturn                   efx_rc_t
1973 efx_mae_action_rule_remove(
1974         __in                            efx_nic_t *enp,
1975         __in                            const efx_mae_rule_id_t *ar_idp)
1976 {
1977         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1978         efx_mcdi_req_t req;
1979         EFX_MCDI_DECLARE_BUF(payload,
1980             MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
1981             MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
1982         efx_rc_t rc;
1983
1984         if (encp->enc_mae_supported == B_FALSE) {
1985                 rc = ENOTSUP;
1986                 goto fail1;
1987         }
1988
1989         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
1990         req.emr_in_buf = payload;
1991         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
1992         req.emr_out_buf = payload;
1993         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
1994
1995         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
1996
1997         efx_mcdi_execute(enp, &req);
1998
1999         if (req.emr_rc != 0) {
2000                 rc = req.emr_rc;
2001                 goto fail2;
2002         }
2003
2004         if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
2005             ar_idp->id) {
2006                 /* Firmware failed to delete the action rule. */
2007                 rc = EAGAIN;
2008                 goto fail3;
2009         }
2010
2011         return (0);
2012
2013 fail3:
2014         EFSYS_PROBE(fail3);
2015 fail2:
2016         EFSYS_PROBE(fail2);
2017 fail1:
2018         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2019         return (rc);
2020 }
2021
2022 #endif /* EFSYS_OPT_MAE */