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