common/sfc_efx/base: fix signed/unsigned mismatch warnings
[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 typedef struct efx_mae_mv_desc_s {
468         efx_mae_field_cap_id_t          emmd_field_cap_id;
469
470         size_t                          emmd_value_size;
471         size_t                          emmd_value_offset;
472         size_t                          emmd_mask_size;
473         size_t                          emmd_mask_offset;
474
475         efx_mae_field_endianness_t      emmd_endianness;
476 } efx_mae_mv_desc_t;
477
478 /* Indices to this array are provided by efx_mae_field_id_t */
479 static const efx_mae_mv_desc_t __efx_mae_action_rule_mv_desc_set[] = {
480 #define EFX_MAE_MV_DESC(_name, _endianness)                             \
481         [EFX_MAE_FIELD_##_name] =                                       \
482         {                                                               \
483                 EFX_MAE_FIELD_ID_##_name,                               \
484                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_LEN,               \
485                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_OFST,              \
486                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_LEN,          \
487                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_OFST,         \
488                 _endianness                                             \
489         }
490
491         EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
492         EFX_MAE_MV_DESC(ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
493         EFX_MAE_MV_DESC(ETH_SADDR_BE, EFX_MAE_FIELD_BE),
494         EFX_MAE_MV_DESC(ETH_DADDR_BE, EFX_MAE_FIELD_BE),
495         EFX_MAE_MV_DESC(VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
496         EFX_MAE_MV_DESC(VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
497         EFX_MAE_MV_DESC(VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
498         EFX_MAE_MV_DESC(VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
499         EFX_MAE_MV_DESC(SRC_IP4_BE, EFX_MAE_FIELD_BE),
500         EFX_MAE_MV_DESC(DST_IP4_BE, EFX_MAE_FIELD_BE),
501         EFX_MAE_MV_DESC(IP_PROTO, EFX_MAE_FIELD_BE),
502         EFX_MAE_MV_DESC(IP_TOS, EFX_MAE_FIELD_BE),
503         EFX_MAE_MV_DESC(IP_TTL, EFX_MAE_FIELD_BE),
504         EFX_MAE_MV_DESC(SRC_IP6_BE, EFX_MAE_FIELD_BE),
505         EFX_MAE_MV_DESC(DST_IP6_BE, EFX_MAE_FIELD_BE),
506         EFX_MAE_MV_DESC(L4_SPORT_BE, EFX_MAE_FIELD_BE),
507         EFX_MAE_MV_DESC(L4_DPORT_BE, EFX_MAE_FIELD_BE),
508         EFX_MAE_MV_DESC(TCP_FLAGS_BE, EFX_MAE_FIELD_BE),
509         EFX_MAE_MV_DESC(ENC_VNET_ID_BE, EFX_MAE_FIELD_BE),
510         EFX_MAE_MV_DESC(OUTER_RULE_ID, EFX_MAE_FIELD_LE),
511
512 #undef EFX_MAE_MV_DESC
513 };
514
515 /* Indices to this array are provided by efx_mae_field_id_t */
516 static const efx_mae_mv_desc_t __efx_mae_outer_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_ENC_FIELD_PAIRS_##_name##_LEN,                      \
522                 MAE_ENC_FIELD_PAIRS_##_name##_OFST,                     \
523                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,                 \
524                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,                \
525                 _endianness                                             \
526         }
527
528         EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
529         EFX_MAE_MV_DESC(ENC_ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
530         EFX_MAE_MV_DESC(ENC_ETH_SADDR_BE, EFX_MAE_FIELD_BE),
531         EFX_MAE_MV_DESC(ENC_ETH_DADDR_BE, EFX_MAE_FIELD_BE),
532         EFX_MAE_MV_DESC(ENC_VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
533         EFX_MAE_MV_DESC(ENC_VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
534         EFX_MAE_MV_DESC(ENC_VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
535         EFX_MAE_MV_DESC(ENC_VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
536         EFX_MAE_MV_DESC(ENC_SRC_IP4_BE, EFX_MAE_FIELD_BE),
537         EFX_MAE_MV_DESC(ENC_DST_IP4_BE, EFX_MAE_FIELD_BE),
538         EFX_MAE_MV_DESC(ENC_IP_PROTO, EFX_MAE_FIELD_BE),
539         EFX_MAE_MV_DESC(ENC_IP_TOS, EFX_MAE_FIELD_BE),
540         EFX_MAE_MV_DESC(ENC_IP_TTL, EFX_MAE_FIELD_BE),
541         EFX_MAE_MV_DESC(ENC_SRC_IP6_BE, EFX_MAE_FIELD_BE),
542         EFX_MAE_MV_DESC(ENC_DST_IP6_BE, EFX_MAE_FIELD_BE),
543         EFX_MAE_MV_DESC(ENC_L4_SPORT_BE, EFX_MAE_FIELD_BE),
544         EFX_MAE_MV_DESC(ENC_L4_DPORT_BE, EFX_MAE_FIELD_BE),
545
546 #undef EFX_MAE_MV_DESC
547 };
548
549         __checkReturn                   efx_rc_t
550 efx_mae_mport_by_phy_port(
551         __in                            uint32_t phy_port,
552         __out                           efx_mport_sel_t *mportp)
553 {
554         efx_dword_t dword;
555         efx_rc_t rc;
556
557         if (phy_port > EFX_MASK32(MAE_MPORT_SELECTOR_PPORT_ID)) {
558                 rc = EINVAL;
559                 goto fail1;
560         }
561
562         EFX_POPULATE_DWORD_2(dword,
563             MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT,
564             MAE_MPORT_SELECTOR_PPORT_ID, phy_port);
565
566         memset(mportp, 0, sizeof (*mportp));
567         mportp->sel = dword.ed_u32[0];
568
569         return (0);
570
571 fail1:
572         EFSYS_PROBE1(fail1, efx_rc_t, rc);
573         return (rc);
574 }
575
576         __checkReturn                   efx_rc_t
577 efx_mae_mport_by_pcie_function(
578         __in                            uint32_t pf,
579         __in                            uint32_t vf,
580         __out                           efx_mport_sel_t *mportp)
581 {
582         efx_dword_t dword;
583         efx_rc_t rc;
584
585         EFX_STATIC_ASSERT(EFX_PCI_VF_INVALID ==
586             MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL);
587
588         if (pf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_PF_ID)) {
589                 rc = EINVAL;
590                 goto fail1;
591         }
592
593         if (vf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_VF_ID)) {
594                 rc = EINVAL;
595                 goto fail2;
596         }
597
598         EFX_POPULATE_DWORD_3(dword,
599             MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
600             MAE_MPORT_SELECTOR_FUNC_PF_ID, pf,
601             MAE_MPORT_SELECTOR_FUNC_VF_ID, vf);
602
603         memset(mportp, 0, sizeof (*mportp));
604         mportp->sel = dword.ed_u32[0];
605
606         return (0);
607
608 fail2:
609         EFSYS_PROBE(fail2);
610 fail1:
611         EFSYS_PROBE1(fail1, efx_rc_t, rc);
612         return (rc);
613 }
614
615         __checkReturn                   efx_rc_t
616 efx_mae_match_spec_field_set(
617         __in                            efx_mae_match_spec_t *spec,
618         __in                            efx_mae_field_id_t field_id,
619         __in                            size_t value_size,
620         __in_bcount(value_size)         const uint8_t *value,
621         __in                            size_t mask_size,
622         __in_bcount(mask_size)          const uint8_t *mask)
623 {
624         const efx_mae_mv_desc_t *descp;
625         unsigned int desc_set_nentries;
626         uint8_t *mvp;
627         efx_rc_t rc;
628
629         switch (spec->emms_type) {
630         case EFX_MAE_RULE_OUTER:
631                 desc_set_nentries =
632                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
633                 descp = &__efx_mae_outer_rule_mv_desc_set[field_id];
634                 mvp = spec->emms_mask_value_pairs.outer;
635                 break;
636         case EFX_MAE_RULE_ACTION:
637                 desc_set_nentries =
638                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
639                 descp = &__efx_mae_action_rule_mv_desc_set[field_id];
640                 mvp = spec->emms_mask_value_pairs.action;
641                 break;
642         default:
643                 rc = ENOTSUP;
644                 goto fail1;
645         }
646
647         if ((unsigned int)field_id >= desc_set_nentries) {
648                 rc = EINVAL;
649                 goto fail2;
650         }
651
652         if (value_size != descp->emmd_value_size) {
653                 rc = EINVAL;
654                 goto fail3;
655         }
656
657         if (mask_size != descp->emmd_mask_size) {
658                 rc = EINVAL;
659                 goto fail4;
660         }
661
662         if (descp->emmd_endianness == EFX_MAE_FIELD_BE) {
663                 /*
664                  * The mask/value are in network (big endian) order.
665                  * The MCDI request field is also big endian.
666                  */
667                 memcpy(mvp + descp->emmd_value_offset, value, value_size);
668                 memcpy(mvp + descp->emmd_mask_offset, mask, mask_size);
669         } else {
670                 efx_dword_t dword;
671
672                 /*
673                  * The mask/value are in host byte order.
674                  * The MCDI request field is little endian.
675                  */
676                 switch (value_size) {
677                 case 4:
678                         EFX_POPULATE_DWORD_1(dword,
679                             EFX_DWORD_0, *(const uint32_t *)value);
680
681                         memcpy(mvp + descp->emmd_value_offset,
682                             &dword, sizeof (dword));
683                         break;
684                 default:
685                         EFSYS_ASSERT(B_FALSE);
686                 }
687
688                 switch (mask_size) {
689                 case 4:
690                         EFX_POPULATE_DWORD_1(dword,
691                             EFX_DWORD_0, *(const uint32_t *)mask);
692
693                         memcpy(mvp + descp->emmd_mask_offset,
694                             &dword, sizeof (dword));
695                         break;
696                 default:
697                         EFSYS_ASSERT(B_FALSE);
698                 }
699         }
700
701         return (0);
702
703 fail4:
704         EFSYS_PROBE(fail4);
705 fail3:
706         EFSYS_PROBE(fail3);
707 fail2:
708         EFSYS_PROBE(fail2);
709 fail1:
710         EFSYS_PROBE1(fail1, efx_rc_t, rc);
711         return (rc);
712 }
713
714         __checkReturn                   efx_rc_t
715 efx_mae_match_spec_mport_set(
716         __in                            efx_mae_match_spec_t *spec,
717         __in                            const efx_mport_sel_t *valuep,
718         __in_opt                        const efx_mport_sel_t *maskp)
719 {
720         uint32_t full_mask = UINT32_MAX;
721         const uint8_t *vp;
722         const uint8_t *mp;
723         efx_rc_t rc;
724
725         if (valuep == NULL) {
726                 rc = EINVAL;
727                 goto fail1;
728         }
729
730         vp = (const uint8_t *)&valuep->sel;
731         if (maskp != NULL)
732                 mp = (const uint8_t *)&maskp->sel;
733         else
734                 mp = (const uint8_t *)&full_mask;
735
736         rc = efx_mae_match_spec_field_set(spec,
737             EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR,
738             sizeof (valuep->sel), vp, sizeof (maskp->sel), mp);
739         if (rc != 0)
740                 goto fail2;
741
742         return (0);
743
744 fail2:
745         EFSYS_PROBE(fail2);
746 fail1:
747         EFSYS_PROBE1(fail1, efx_rc_t, rc);
748         return (rc);
749 }
750
751         __checkReturn                   boolean_t
752 efx_mae_match_specs_equal(
753         __in                            const efx_mae_match_spec_t *left,
754         __in                            const efx_mae_match_spec_t *right)
755 {
756         return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
757 }
758
759 #define EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit)              \
760             ((_mask)[(_bit) / (_mask_page_nbits)] &                     \
761                     (1ULL << ((_bit) & ((_mask_page_nbits) - 1))))
762
763 static                                  boolean_t
764 efx_mask_is_prefix(
765         __in                            size_t mask_nbytes,
766         __in_bcount(mask_nbytes)        const uint8_t *maskp)
767 {
768         boolean_t prev_bit_is_set = B_TRUE;
769         unsigned int i;
770
771         for (i = 0; i < 8 * mask_nbytes; ++i) {
772                 boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i);
773
774                 if (!prev_bit_is_set && bit_is_set)
775                         return B_FALSE;
776
777                 prev_bit_is_set = bit_is_set;
778         }
779
780         return B_TRUE;
781 }
782
783 static                                  boolean_t
784 efx_mask_is_all_ones(
785         __in                            size_t mask_nbytes,
786         __in_bcount(mask_nbytes)        const uint8_t *maskp)
787 {
788         unsigned int i;
789         uint8_t t = ~0;
790
791         for (i = 0; i < mask_nbytes; ++i)
792                 t &= maskp[i];
793
794         return (t == (uint8_t)(~0));
795 }
796
797 static                                  boolean_t
798 efx_mask_is_all_zeros(
799         __in                            size_t mask_nbytes,
800         __in_bcount(mask_nbytes)        const uint8_t *maskp)
801 {
802         unsigned int i;
803         uint8_t t = 0;
804
805         for (i = 0; i < mask_nbytes; ++i)
806                 t |= maskp[i];
807
808         return (t == 0);
809 }
810
811         __checkReturn                   boolean_t
812 efx_mae_match_spec_is_valid(
813         __in                            efx_nic_t *enp,
814         __in                            const efx_mae_match_spec_t *spec)
815 {
816         efx_mae_t *maep = enp->en_maep;
817         unsigned int field_ncaps = maep->em_max_nfields;
818         const efx_mae_field_cap_t *field_caps;
819         const efx_mae_mv_desc_t *desc_setp;
820         unsigned int desc_set_nentries;
821         boolean_t is_valid = B_TRUE;
822         efx_mae_field_id_t field_id;
823         const uint8_t *mvp;
824
825         switch (spec->emms_type) {
826         case EFX_MAE_RULE_OUTER:
827                 field_caps = maep->em_outer_rule_field_caps;
828                 desc_setp = __efx_mae_outer_rule_mv_desc_set;
829                 desc_set_nentries =
830                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
831                 mvp = spec->emms_mask_value_pairs.outer;
832                 break;
833         case EFX_MAE_RULE_ACTION:
834                 field_caps = maep->em_action_rule_field_caps;
835                 desc_setp = __efx_mae_action_rule_mv_desc_set;
836                 desc_set_nentries =
837                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
838                 mvp = spec->emms_mask_value_pairs.action;
839                 break;
840         default:
841                 return (B_FALSE);
842         }
843
844         if (field_caps == NULL)
845                 return (B_FALSE);
846
847         for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
848              ++field_id) {
849                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
850                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
851                 const uint8_t *m_buf = mvp + descp->emmd_mask_offset;
852                 size_t m_size = descp->emmd_mask_size;
853
854                 if (m_size == 0)
855                         continue; /* Skip array gap */
856
857                 if ((unsigned int)field_cap_id >= field_ncaps)
858                         break;
859
860                 switch (field_caps[field_cap_id].emfc_support) {
861                 case MAE_FIELD_SUPPORTED_MATCH_MASK:
862                         is_valid = B_TRUE;
863                         break;
864                 case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
865                         is_valid = efx_mask_is_prefix(m_size, m_buf);
866                         break;
867                 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
868                         is_valid = (efx_mask_is_all_ones(m_size, m_buf) ||
869                             efx_mask_is_all_zeros(m_size, m_buf));
870                         break;
871                 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
872                         is_valid = efx_mask_is_all_ones(m_size, m_buf);
873                         break;
874                 case MAE_FIELD_SUPPORTED_MATCH_NEVER:
875                 case MAE_FIELD_UNSUPPORTED:
876                 default:
877                         is_valid = efx_mask_is_all_zeros(m_size, m_buf);
878                         break;
879                 }
880
881                 if (is_valid == B_FALSE)
882                         break;
883         }
884
885         return (is_valid);
886 }
887
888         __checkReturn                   efx_rc_t
889 efx_mae_action_set_spec_init(
890         __in                            efx_nic_t *enp,
891         __out                           efx_mae_actions_t **specp)
892 {
893         efx_mae_actions_t *spec;
894         efx_rc_t rc;
895
896         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
897         if (spec == NULL) {
898                 rc = ENOMEM;
899                 goto fail1;
900         }
901
902         *specp = spec;
903
904         return (0);
905
906 fail1:
907         EFSYS_PROBE1(fail1, efx_rc_t, rc);
908         return (rc);
909 }
910
911                                         void
912 efx_mae_action_set_spec_fini(
913         __in                            efx_nic_t *enp,
914         __in                            efx_mae_actions_t *spec)
915 {
916         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
917 }
918
919 static  __checkReturn                   efx_rc_t
920 efx_mae_action_set_add_vlan_pop(
921         __in                            efx_mae_actions_t *spec,
922         __in                            size_t arg_size,
923         __in_bcount(arg_size)           const uint8_t *arg)
924 {
925         efx_rc_t rc;
926
927         if (arg_size != 0) {
928                 rc = EINVAL;
929                 goto fail1;
930         }
931
932         if (arg != NULL) {
933                 rc = EINVAL;
934                 goto fail2;
935         }
936
937         if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) {
938                 rc = ENOTSUP;
939                 goto fail3;
940         }
941
942         ++spec->ema_n_vlan_tags_to_pop;
943
944         return (0);
945
946 fail3:
947         EFSYS_PROBE(fail3);
948 fail2:
949         EFSYS_PROBE(fail2);
950 fail1:
951         EFSYS_PROBE1(fail1, efx_rc_t, rc);
952         return (rc);
953 }
954
955 static  __checkReturn                   efx_rc_t
956 efx_mae_action_set_add_vlan_push(
957         __in                            efx_mae_actions_t *spec,
958         __in                            size_t arg_size,
959         __in_bcount(arg_size)           const uint8_t *arg)
960 {
961         unsigned int n_tags = spec->ema_n_vlan_tags_to_push;
962         efx_rc_t rc;
963
964         if (arg_size != sizeof (*spec->ema_vlan_push_descs)) {
965                 rc = EINVAL;
966                 goto fail1;
967         }
968
969         if (arg == NULL) {
970                 rc = EINVAL;
971                 goto fail2;
972         }
973
974         if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
975                 rc = ENOTSUP;
976                 goto fail3;
977         }
978
979         memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size);
980         ++(spec->ema_n_vlan_tags_to_push);
981
982         return (0);
983
984 fail3:
985         EFSYS_PROBE(fail3);
986 fail2:
987         EFSYS_PROBE(fail2);
988 fail1:
989         EFSYS_PROBE1(fail1, efx_rc_t, rc);
990         return (rc);
991 }
992
993 static  __checkReturn                   efx_rc_t
994 efx_mae_action_set_add_flag(
995         __in                            efx_mae_actions_t *spec,
996         __in                            size_t arg_size,
997         __in_bcount(arg_size)           const uint8_t *arg)
998 {
999         efx_rc_t rc;
1000
1001         _NOTE(ARGUNUSED(spec))
1002
1003         if (arg_size != 0) {
1004                 rc = EINVAL;
1005                 goto fail1;
1006         }
1007
1008         if (arg != NULL) {
1009                 rc = EINVAL;
1010                 goto fail2;
1011         }
1012
1013         /* This action does not have any arguments, so do nothing here. */
1014
1015         return (0);
1016
1017 fail2:
1018         EFSYS_PROBE(fail2);
1019 fail1:
1020         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1021         return (rc);
1022 }
1023
1024 static  __checkReturn                   efx_rc_t
1025 efx_mae_action_set_add_mark(
1026         __in                            efx_mae_actions_t *spec,
1027         __in                            size_t arg_size,
1028         __in_bcount(arg_size)           const uint8_t *arg)
1029 {
1030         efx_rc_t rc;
1031
1032         if (arg_size != sizeof (spec->ema_mark_value)) {
1033                 rc = EINVAL;
1034                 goto fail1;
1035         }
1036
1037         if (arg == NULL) {
1038                 rc = EINVAL;
1039                 goto fail2;
1040         }
1041
1042         memcpy(&spec->ema_mark_value, arg, arg_size);
1043
1044         return (0);
1045
1046 fail2:
1047         EFSYS_PROBE(fail2);
1048 fail1:
1049         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1050         return (rc);
1051 }
1052
1053 static  __checkReturn                   efx_rc_t
1054 efx_mae_action_set_add_deliver(
1055         __in                            efx_mae_actions_t *spec,
1056         __in                            size_t arg_size,
1057         __in_bcount(arg_size)           const uint8_t *arg)
1058 {
1059         efx_rc_t rc;
1060
1061         if (arg_size != sizeof (spec->ema_deliver_mport)) {
1062                 rc = EINVAL;
1063                 goto fail1;
1064         }
1065
1066         if (arg == NULL) {
1067                 rc = EINVAL;
1068                 goto fail2;
1069         }
1070
1071         memcpy(&spec->ema_deliver_mport, arg, arg_size);
1072
1073         return (0);
1074
1075 fail2:
1076         EFSYS_PROBE(fail2);
1077 fail1:
1078         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1079         return (rc);
1080 }
1081
1082 typedef struct efx_mae_action_desc_s {
1083         /* Action specific handler */
1084         efx_rc_t        (*emad_add)(efx_mae_actions_t *,
1085                                     size_t, const uint8_t *);
1086 } efx_mae_action_desc_t;
1087
1088 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
1089         [EFX_MAE_ACTION_VLAN_POP] = {
1090                 .emad_add = efx_mae_action_set_add_vlan_pop
1091         },
1092         [EFX_MAE_ACTION_VLAN_PUSH] = {
1093                 .emad_add = efx_mae_action_set_add_vlan_push
1094         },
1095         [EFX_MAE_ACTION_FLAG] = {
1096                 .emad_add = efx_mae_action_set_add_flag
1097         },
1098         [EFX_MAE_ACTION_MARK] = {
1099                 .emad_add = efx_mae_action_set_add_mark
1100         },
1101         [EFX_MAE_ACTION_DELIVER] = {
1102                 .emad_add = efx_mae_action_set_add_deliver
1103         }
1104 };
1105
1106 static const uint32_t efx_mae_action_ordered_map =
1107         (1U << EFX_MAE_ACTION_VLAN_POP) |
1108         (1U << EFX_MAE_ACTION_VLAN_PUSH) |
1109         (1U << EFX_MAE_ACTION_FLAG) |
1110         (1U << EFX_MAE_ACTION_MARK) |
1111         (1U << EFX_MAE_ACTION_DELIVER);
1112
1113 /*
1114  * These actions must not be added after DELIVER, but
1115  * they can have any place among the rest of
1116  * strictly ordered actions.
1117  */
1118 static const uint32_t efx_mae_action_nonstrict_map =
1119         (1U << EFX_MAE_ACTION_FLAG) |
1120         (1U << EFX_MAE_ACTION_MARK);
1121
1122 static const uint32_t efx_mae_action_repeat_map =
1123         (1U << EFX_MAE_ACTION_VLAN_POP) |
1124         (1U << EFX_MAE_ACTION_VLAN_PUSH);
1125
1126 /*
1127  * Add an action to an action set.
1128  *
1129  * This has to be invoked in the desired action order.
1130  * An out-of-order action request will be turned down.
1131  */
1132 static  __checkReturn                   efx_rc_t
1133 efx_mae_action_set_spec_populate(
1134         __in                            efx_mae_actions_t *spec,
1135         __in                            efx_mae_action_t type,
1136         __in                            size_t arg_size,
1137         __in_bcount(arg_size)           const uint8_t *arg)
1138 {
1139         uint32_t action_mask;
1140         efx_rc_t rc;
1141
1142         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1143             (sizeof (efx_mae_action_ordered_map) * 8));
1144         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1145             (sizeof (efx_mae_action_repeat_map) * 8));
1146
1147         EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
1148         EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK);
1149         EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER);
1150
1151         if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
1152                 rc = EINVAL;
1153                 goto fail1;
1154         }
1155
1156         action_mask = (1U << type);
1157
1158         if ((spec->ema_actions & action_mask) != 0) {
1159                 /* The action set already contains this action. */
1160                 if ((efx_mae_action_repeat_map & action_mask) == 0) {
1161                         /* Cannot add another non-repeatable action. */
1162                         rc = ENOTSUP;
1163                         goto fail2;
1164                 }
1165         }
1166
1167         if ((efx_mae_action_ordered_map & action_mask) != 0) {
1168                 uint32_t strict_ordered_map =
1169                     efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map;
1170                 uint32_t later_actions_mask =
1171                     strict_ordered_map & ~(action_mask | (action_mask - 1));
1172
1173                 if ((spec->ema_actions & later_actions_mask) != 0) {
1174                         /* Cannot add an action after later ordered actions. */
1175                         rc = ENOTSUP;
1176                         goto fail3;
1177                 }
1178         }
1179
1180         if (efx_mae_actions[type].emad_add != NULL) {
1181                 rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
1182                 if (rc != 0)
1183                         goto fail4;
1184         }
1185
1186         spec->ema_actions |= action_mask;
1187
1188         return (0);
1189
1190 fail4:
1191         EFSYS_PROBE(fail4);
1192 fail3:
1193         EFSYS_PROBE(fail3);
1194 fail2:
1195         EFSYS_PROBE(fail2);
1196 fail1:
1197         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1198         return (rc);
1199 }
1200
1201         __checkReturn                   efx_rc_t
1202 efx_mae_action_set_populate_vlan_pop(
1203         __in                            efx_mae_actions_t *spec)
1204 {
1205         return (efx_mae_action_set_spec_populate(spec,
1206             EFX_MAE_ACTION_VLAN_POP, 0, NULL));
1207 }
1208
1209         __checkReturn                   efx_rc_t
1210 efx_mae_action_set_populate_vlan_push(
1211         __in                            efx_mae_actions_t *spec,
1212         __in                            uint16_t tpid_be,
1213         __in                            uint16_t tci_be)
1214 {
1215         efx_mae_action_vlan_push_t action;
1216         const uint8_t *arg = (const uint8_t *)&action;
1217
1218         action.emavp_tpid_be = tpid_be;
1219         action.emavp_tci_be = tci_be;
1220
1221         return (efx_mae_action_set_spec_populate(spec,
1222             EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg));
1223 }
1224
1225         __checkReturn                   efx_rc_t
1226 efx_mae_action_set_populate_flag(
1227         __in                            efx_mae_actions_t *spec)
1228 {
1229         return (efx_mae_action_set_spec_populate(spec,
1230             EFX_MAE_ACTION_FLAG, 0, NULL));
1231 }
1232
1233         __checkReturn                   efx_rc_t
1234 efx_mae_action_set_populate_mark(
1235         __in                            efx_mae_actions_t *spec,
1236         __in                            uint32_t mark_value)
1237 {
1238         const uint8_t *arg = (const uint8_t *)&mark_value;
1239
1240         return (efx_mae_action_set_spec_populate(spec,
1241             EFX_MAE_ACTION_MARK, sizeof (mark_value), arg));
1242 }
1243
1244         __checkReturn                   efx_rc_t
1245 efx_mae_action_set_populate_deliver(
1246         __in                            efx_mae_actions_t *spec,
1247         __in                            const efx_mport_sel_t *mportp)
1248 {
1249         const uint8_t *arg;
1250         efx_rc_t rc;
1251
1252         if (mportp == NULL) {
1253                 rc = EINVAL;
1254                 goto fail1;
1255         }
1256
1257         arg = (const uint8_t *)&mportp->sel;
1258
1259         return (efx_mae_action_set_spec_populate(spec,
1260             EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
1261
1262 fail1:
1263         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1264         return (rc);
1265 }
1266
1267         __checkReturn                   efx_rc_t
1268 efx_mae_action_set_populate_drop(
1269         __in                            efx_mae_actions_t *spec)
1270 {
1271         efx_mport_sel_t mport;
1272         const uint8_t *arg;
1273         efx_dword_t dword;
1274
1275         EFX_POPULATE_DWORD_1(dword,
1276             MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL);
1277
1278         mport.sel = dword.ed_u32[0];
1279
1280         arg = (const uint8_t *)&mport.sel;
1281
1282         return (efx_mae_action_set_spec_populate(spec,
1283             EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg));
1284 }
1285
1286         __checkReturn                   boolean_t
1287 efx_mae_action_set_specs_equal(
1288         __in                            const efx_mae_actions_t *left,
1289         __in                            const efx_mae_actions_t *right)
1290 {
1291         return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
1292 }
1293
1294         __checkReturn                   efx_rc_t
1295 efx_mae_match_specs_class_cmp(
1296         __in                            efx_nic_t *enp,
1297         __in                            const efx_mae_match_spec_t *left,
1298         __in                            const efx_mae_match_spec_t *right,
1299         __out                           boolean_t *have_same_classp)
1300 {
1301         efx_mae_t *maep = enp->en_maep;
1302         unsigned int field_ncaps = maep->em_max_nfields;
1303         const efx_mae_field_cap_t *field_caps;
1304         const efx_mae_mv_desc_t *desc_setp;
1305         unsigned int desc_set_nentries;
1306         boolean_t have_same_class = B_TRUE;
1307         efx_mae_field_id_t field_id;
1308         const uint8_t *mvpl;
1309         const uint8_t *mvpr;
1310         efx_rc_t rc;
1311
1312         switch (left->emms_type) {
1313         case EFX_MAE_RULE_OUTER:
1314                 field_caps = maep->em_outer_rule_field_caps;
1315                 desc_setp = __efx_mae_outer_rule_mv_desc_set;
1316                 desc_set_nentries =
1317                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1318                 mvpl = left->emms_mask_value_pairs.outer;
1319                 mvpr = right->emms_mask_value_pairs.outer;
1320                 break;
1321         case EFX_MAE_RULE_ACTION:
1322                 field_caps = maep->em_action_rule_field_caps;
1323                 desc_setp = __efx_mae_action_rule_mv_desc_set;
1324                 desc_set_nentries =
1325                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1326                 mvpl = left->emms_mask_value_pairs.action;
1327                 mvpr = right->emms_mask_value_pairs.action;
1328                 break;
1329         default:
1330                 rc = ENOTSUP;
1331                 goto fail1;
1332         }
1333
1334         if (field_caps == NULL) {
1335                 rc = EAGAIN;
1336                 goto fail2;
1337         }
1338
1339         if (left->emms_type != right->emms_type ||
1340             left->emms_prio != right->emms_prio) {
1341                 /*
1342                  * Rules of different types can never map to the same class.
1343                  *
1344                  * The FW can support some set of match criteria for one
1345                  * priority and not support the very same set for
1346                  * another priority. Thus, two rules which have
1347                  * different priorities can never map to
1348                  * the same class.
1349                  */
1350                 *have_same_classp = B_FALSE;
1351                 return (0);
1352         }
1353
1354         for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1355              ++field_id) {
1356                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1357                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1358
1359                 if (descp->emmd_mask_size == 0)
1360                         continue; /* Skip array gap */
1361
1362                 if ((unsigned int)field_cap_id >= field_ncaps)
1363                         break;
1364
1365                 if (field_caps[field_cap_id].emfc_mask_affects_class) {
1366                         const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
1367                         const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
1368                         size_t mask_size = descp->emmd_mask_size;
1369
1370                         if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
1371                                 have_same_class = B_FALSE;
1372                                 break;
1373                         }
1374                 }
1375
1376                 if (field_caps[field_cap_id].emfc_match_affects_class) {
1377                         const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
1378                         const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
1379                         size_t value_size = descp->emmd_value_size;
1380
1381                         if (memcmp(lvalp, rvalp, value_size) != 0) {
1382                                 have_same_class = B_FALSE;
1383                                 break;
1384                         }
1385                 }
1386         }
1387
1388         *have_same_classp = have_same_class;
1389
1390         return (0);
1391
1392 fail2:
1393         EFSYS_PROBE(fail2);
1394 fail1:
1395         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1396         return (rc);
1397 }
1398
1399         __checkReturn           efx_rc_t
1400 efx_mae_outer_rule_insert(
1401         __in                    efx_nic_t *enp,
1402         __in                    const efx_mae_match_spec_t *spec,
1403         __in                    efx_tunnel_protocol_t encap_type,
1404         __out                   efx_mae_rule_id_t *or_idp)
1405 {
1406         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1407         efx_mcdi_req_t req;
1408         EFX_MCDI_DECLARE_BUF(payload,
1409             MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2,
1410             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
1411         uint32_t encap_type_mcdi;
1412         efx_mae_rule_id_t or_id;
1413         size_t offset;
1414         efx_rc_t rc;
1415
1416         EFX_STATIC_ASSERT(sizeof (or_idp->id) ==
1417             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN);
1418
1419         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1420             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL);
1421
1422         if (encp->enc_mae_supported == B_FALSE) {
1423                 rc = ENOTSUP;
1424                 goto fail1;
1425         }
1426
1427         if (spec->emms_type != EFX_MAE_RULE_OUTER) {
1428                 rc = EINVAL;
1429                 goto fail2;
1430         }
1431
1432         switch (encap_type) {
1433         case EFX_TUNNEL_PROTOCOL_NONE:
1434                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
1435                 break;
1436         case EFX_TUNNEL_PROTOCOL_VXLAN:
1437                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
1438                 break;
1439         case EFX_TUNNEL_PROTOCOL_GENEVE:
1440                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
1441                 break;
1442         case EFX_TUNNEL_PROTOCOL_NVGRE:
1443                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
1444                 break;
1445         default:
1446                 rc = ENOTSUP;
1447                 goto fail3;
1448         }
1449
1450         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT;
1451         req.emr_in_buf = payload;
1452         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2;
1453         req.emr_out_buf = payload;
1454         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN;
1455
1456         MCDI_IN_SET_DWORD(req,
1457             MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi);
1458
1459         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio);
1460
1461         /*
1462          * Mask-value pairs have been stored in the byte order needed for the
1463          * MCDI request and are thus safe to be copied directly to the buffer.
1464          * The library cares about byte order in efx_mae_match_spec_field_set().
1465          */
1466         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >=
1467             MAE_ENC_FIELD_PAIRS_LEN);
1468         offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST;
1469         memcpy(payload + offset, spec->emms_mask_value_pairs.outer,
1470             MAE_ENC_FIELD_PAIRS_LEN);
1471
1472         efx_mcdi_execute(enp, &req);
1473
1474         if (req.emr_rc != 0) {
1475                 rc = req.emr_rc;
1476                 goto fail4;
1477         }
1478
1479         if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) {
1480                 rc = EMSGSIZE;
1481                 goto fail5;
1482         }
1483
1484         or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
1485         if (or_id.id == EFX_MAE_RSRC_ID_INVALID) {
1486                 rc = ENOENT;
1487                 goto fail6;
1488         }
1489
1490         or_idp->id = or_id.id;
1491
1492         return (0);
1493
1494 fail6:
1495         EFSYS_PROBE(fail6);
1496 fail5:
1497         EFSYS_PROBE(fail5);
1498 fail4:
1499         EFSYS_PROBE(fail4);
1500 fail3:
1501         EFSYS_PROBE(fail3);
1502 fail2:
1503         EFSYS_PROBE(fail2);
1504 fail1:
1505         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1506         return (rc);
1507 }
1508
1509         __checkReturn           efx_rc_t
1510 efx_mae_outer_rule_remove(
1511         __in                    efx_nic_t *enp,
1512         __in                    const efx_mae_rule_id_t *or_idp)
1513 {
1514         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1515         efx_mcdi_req_t req;
1516         EFX_MCDI_DECLARE_BUF(payload,
1517             MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1),
1518             MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
1519         efx_rc_t rc;
1520
1521         if (encp->enc_mae_supported == B_FALSE) {
1522                 rc = ENOTSUP;
1523                 goto fail1;
1524         }
1525
1526         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE;
1527         req.emr_in_buf = payload;
1528         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1);
1529         req.emr_out_buf = payload;
1530         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1);
1531
1532         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id);
1533
1534         efx_mcdi_execute(enp, &req);
1535
1536         if (req.emr_rc != 0) {
1537                 rc = req.emr_rc;
1538                 goto fail2;
1539         }
1540
1541         if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) !=
1542             or_idp->id) {
1543                 /* Firmware failed to remove the outer rule. */
1544                 rc = EAGAIN;
1545                 goto fail3;
1546         }
1547
1548         return (0);
1549
1550 fail3:
1551         EFSYS_PROBE(fail3);
1552 fail2:
1553         EFSYS_PROBE(fail2);
1554 fail1:
1555         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1556         return (rc);
1557 }
1558
1559         __checkReturn                   efx_rc_t
1560 efx_mae_match_spec_outer_rule_id_set(
1561         __in                            efx_mae_match_spec_t *spec,
1562         __in                            const efx_mae_rule_id_t *or_idp)
1563 {
1564         uint32_t full_mask = UINT32_MAX;
1565         efx_rc_t rc;
1566
1567         if (spec->emms_type != EFX_MAE_RULE_ACTION) {
1568                 rc = EINVAL;
1569                 goto fail1;
1570         }
1571
1572         if (or_idp == NULL) {
1573                 rc = EINVAL;
1574                 goto fail2;
1575         }
1576
1577         rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID,
1578             sizeof (or_idp->id), (const uint8_t *)&or_idp->id,
1579             sizeof (full_mask), (const uint8_t *)&full_mask);
1580         if (rc != 0)
1581                 goto fail3;
1582
1583         return (0);
1584
1585 fail3:
1586         EFSYS_PROBE(fail3);
1587 fail2:
1588         EFSYS_PROBE(fail2);
1589 fail1:
1590         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1591         return (rc);
1592 }
1593
1594         __checkReturn                   efx_rc_t
1595 efx_mae_action_set_alloc(
1596         __in                            efx_nic_t *enp,
1597         __in                            const efx_mae_actions_t *spec,
1598         __out                           efx_mae_aset_id_t *aset_idp)
1599 {
1600         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1601         efx_mcdi_req_t req;
1602         EFX_MCDI_DECLARE_BUF(payload,
1603             MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
1604             MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
1605         efx_mae_aset_id_t aset_id;
1606         efx_rc_t rc;
1607
1608         if (encp->enc_mae_supported == B_FALSE) {
1609                 rc = ENOTSUP;
1610                 goto fail1;
1611         }
1612
1613         req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
1614         req.emr_in_buf = payload;
1615         req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
1616         req.emr_out_buf = payload;
1617         req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
1618
1619         /*
1620          * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
1621          * corresponding resource types are supported by the implementation.
1622          * Use proper resource ID assignments instead.
1623          */
1624         MCDI_IN_SET_DWORD(req,
1625             MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
1626         MCDI_IN_SET_DWORD(req,
1627             MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
1628         MCDI_IN_SET_DWORD(req,
1629             MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, EFX_MAE_RSRC_ID_INVALID);
1630
1631         MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1632             MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
1633
1634         if (spec->ema_n_vlan_tags_to_push > 0) {
1635                 unsigned int outer_tag_idx;
1636
1637                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1638                     MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
1639                     spec->ema_n_vlan_tags_to_push);
1640
1641                 if (spec->ema_n_vlan_tags_to_push ==
1642                     EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1643                         MCDI_IN_SET_WORD(req,
1644                             MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
1645                             spec->ema_vlan_push_descs[0].emavp_tpid_be);
1646                         MCDI_IN_SET_WORD(req,
1647                             MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
1648                             spec->ema_vlan_push_descs[0].emavp_tci_be);
1649                 }
1650
1651                 outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
1652
1653                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
1654                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
1655                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
1656                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
1657         }
1658
1659         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
1660                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1661                     MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
1662         }
1663
1664         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
1665                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1666                     MAE_ACTION_SET_ALLOC_IN_MARK, 1);
1667
1668                 MCDI_IN_SET_DWORD(req,
1669                     MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
1670         }
1671
1672         MCDI_IN_SET_DWORD(req,
1673             MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
1674
1675         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
1676             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
1677         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
1678             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
1679
1680         efx_mcdi_execute(enp, &req);
1681
1682         if (req.emr_rc != 0) {
1683                 rc = req.emr_rc;
1684                 goto fail2;
1685         }
1686
1687         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
1688                 rc = EMSGSIZE;
1689                 goto fail3;
1690         }
1691
1692         aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
1693         if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
1694                 rc = ENOENT;
1695                 goto fail4;
1696         }
1697
1698         aset_idp->id = aset_id.id;
1699
1700         return (0);
1701
1702 fail4:
1703         EFSYS_PROBE(fail4);
1704 fail3:
1705         EFSYS_PROBE(fail3);
1706 fail2:
1707         EFSYS_PROBE(fail2);
1708 fail1:
1709         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1710         return (rc);
1711 }
1712
1713         __checkReturn                   efx_rc_t
1714 efx_mae_action_set_free(
1715         __in                            efx_nic_t *enp,
1716         __in                            const efx_mae_aset_id_t *aset_idp)
1717 {
1718         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1719         efx_mcdi_req_t req;
1720         EFX_MCDI_DECLARE_BUF(payload,
1721             MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
1722             MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
1723         efx_rc_t rc;
1724
1725         if (encp->enc_mae_supported == B_FALSE) {
1726                 rc = ENOTSUP;
1727                 goto fail1;
1728         }
1729
1730         req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
1731         req.emr_in_buf = payload;
1732         req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
1733         req.emr_out_buf = payload;
1734         req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
1735
1736         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
1737
1738         efx_mcdi_execute(enp, &req);
1739
1740         if (req.emr_rc != 0) {
1741                 rc = req.emr_rc;
1742                 goto fail2;
1743         }
1744
1745         if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
1746             aset_idp->id) {
1747                 /* Firmware failed to free the action set. */
1748                 rc = EAGAIN;
1749                 goto fail3;
1750         }
1751
1752         return (0);
1753
1754 fail3:
1755         EFSYS_PROBE(fail3);
1756 fail2:
1757         EFSYS_PROBE(fail2);
1758 fail1:
1759         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1760         return (rc);
1761 }
1762
1763         __checkReturn                   efx_rc_t
1764 efx_mae_action_rule_insert(
1765         __in                            efx_nic_t *enp,
1766         __in                            const efx_mae_match_spec_t *spec,
1767         __in                            const efx_mae_aset_list_id_t *asl_idp,
1768         __in                            const efx_mae_aset_id_t *as_idp,
1769         __out                           efx_mae_rule_id_t *ar_idp)
1770 {
1771         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1772         efx_mcdi_req_t req;
1773         EFX_MCDI_DECLARE_BUF(payload,
1774             MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2,
1775             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
1776         efx_oword_t *rule_response;
1777         efx_mae_rule_id_t ar_id;
1778         size_t offset;
1779         efx_rc_t rc;
1780
1781         EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
1782             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
1783
1784         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1785             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
1786
1787         if (encp->enc_mae_supported == B_FALSE) {
1788                 rc = ENOTSUP;
1789                 goto fail1;
1790         }
1791
1792         if (spec->emms_type != EFX_MAE_RULE_ACTION ||
1793             (asl_idp != NULL && as_idp != NULL) ||
1794             (asl_idp == NULL && as_idp == NULL)) {
1795                 rc = EINVAL;
1796                 goto fail2;
1797         }
1798
1799         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
1800         req.emr_in_buf = payload;
1801         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
1802         req.emr_out_buf = payload;
1803         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
1804
1805         EFX_STATIC_ASSERT(sizeof (*rule_response) <=
1806             MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
1807         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
1808         rule_response = (efx_oword_t *)(payload + offset);
1809         EFX_POPULATE_OWORD_3(*rule_response,
1810             MAE_ACTION_RULE_RESPONSE_ASL_ID,
1811             (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
1812             MAE_ACTION_RULE_RESPONSE_AS_ID,
1813             (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
1814             MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
1815
1816         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
1817
1818         /*
1819          * Mask-value pairs have been stored in the byte order needed for the
1820          * MCDI request and are thus safe to be copied directly to the buffer.
1821          */
1822         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
1823             MAE_FIELD_MASK_VALUE_PAIRS_LEN);
1824         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
1825         memcpy(payload + offset, spec->emms_mask_value_pairs.action,
1826             MAE_FIELD_MASK_VALUE_PAIRS_LEN);
1827
1828         efx_mcdi_execute(enp, &req);
1829
1830         if (req.emr_rc != 0) {
1831                 rc = req.emr_rc;
1832                 goto fail3;
1833         }
1834
1835         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
1836                 rc = EMSGSIZE;
1837                 goto fail4;
1838         }
1839
1840         ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
1841         if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
1842                 rc = ENOENT;
1843                 goto fail5;
1844         }
1845
1846         ar_idp->id = ar_id.id;
1847
1848         return (0);
1849
1850 fail5:
1851         EFSYS_PROBE(fail5);
1852 fail4:
1853         EFSYS_PROBE(fail4);
1854 fail3:
1855         EFSYS_PROBE(fail3);
1856 fail2:
1857         EFSYS_PROBE(fail2);
1858 fail1:
1859         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1860         return (rc);
1861 }
1862
1863         __checkReturn                   efx_rc_t
1864 efx_mae_action_rule_remove(
1865         __in                            efx_nic_t *enp,
1866         __in                            const efx_mae_rule_id_t *ar_idp)
1867 {
1868         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1869         efx_mcdi_req_t req;
1870         EFX_MCDI_DECLARE_BUF(payload,
1871             MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
1872             MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
1873         efx_rc_t rc;
1874
1875         if (encp->enc_mae_supported == B_FALSE) {
1876                 rc = ENOTSUP;
1877                 goto fail1;
1878         }
1879
1880         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
1881         req.emr_in_buf = payload;
1882         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
1883         req.emr_out_buf = payload;
1884         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
1885
1886         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
1887
1888         efx_mcdi_execute(enp, &req);
1889
1890         if (req.emr_rc != 0) {
1891                 rc = req.emr_rc;
1892                 goto fail2;
1893         }
1894
1895         if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
1896             ar_idp->id) {
1897                 /* Firmware failed to delete the action rule. */
1898                 rc = EAGAIN;
1899                 goto fail3;
1900         }
1901
1902         return (0);
1903
1904 fail3:
1905         EFSYS_PROBE(fail3);
1906 fail2:
1907         EFSYS_PROBE(fail2);
1908 fail1:
1909         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1910         return (rc);
1911 }
1912
1913 #endif /* EFSYS_OPT_MAE */