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