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