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