common/sfc_efx/base: support encap header provisioning
[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         *specp = spec;
997
998         return (0);
999
1000 fail1:
1001         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1002         return (rc);
1003 }
1004
1005                                         void
1006 efx_mae_action_set_spec_fini(
1007         __in                            efx_nic_t *enp,
1008         __in                            efx_mae_actions_t *spec)
1009 {
1010         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
1011 }
1012
1013 static  __checkReturn                   efx_rc_t
1014 efx_mae_action_set_add_vlan_pop(
1015         __in                            efx_mae_actions_t *spec,
1016         __in                            size_t arg_size,
1017         __in_bcount(arg_size)           const uint8_t *arg)
1018 {
1019         efx_rc_t rc;
1020
1021         if (arg_size != 0) {
1022                 rc = EINVAL;
1023                 goto fail1;
1024         }
1025
1026         if (arg != NULL) {
1027                 rc = EINVAL;
1028                 goto fail2;
1029         }
1030
1031         if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) {
1032                 rc = ENOTSUP;
1033                 goto fail3;
1034         }
1035
1036         ++spec->ema_n_vlan_tags_to_pop;
1037
1038         return (0);
1039
1040 fail3:
1041         EFSYS_PROBE(fail3);
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_push(
1051         __in                            efx_mae_actions_t *spec,
1052         __in                            size_t arg_size,
1053         __in_bcount(arg_size)           const uint8_t *arg)
1054 {
1055         unsigned int n_tags = spec->ema_n_vlan_tags_to_push;
1056         efx_rc_t rc;
1057
1058         if (arg_size != sizeof (*spec->ema_vlan_push_descs)) {
1059                 rc = EINVAL;
1060                 goto fail1;
1061         }
1062
1063         if (arg == NULL) {
1064                 rc = EINVAL;
1065                 goto fail2;
1066         }
1067
1068         if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1069                 rc = ENOTSUP;
1070                 goto fail3;
1071         }
1072
1073         memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size);
1074         ++(spec->ema_n_vlan_tags_to_push);
1075
1076         return (0);
1077
1078 fail3:
1079         EFSYS_PROBE(fail3);
1080 fail2:
1081         EFSYS_PROBE(fail2);
1082 fail1:
1083         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1084         return (rc);
1085 }
1086
1087 static  __checkReturn                   efx_rc_t
1088 efx_mae_action_set_add_flag(
1089         __in                            efx_mae_actions_t *spec,
1090         __in                            size_t arg_size,
1091         __in_bcount(arg_size)           const uint8_t *arg)
1092 {
1093         efx_rc_t rc;
1094
1095         _NOTE(ARGUNUSED(spec))
1096
1097         if (arg_size != 0) {
1098                 rc = EINVAL;
1099                 goto fail1;
1100         }
1101
1102         if (arg != NULL) {
1103                 rc = EINVAL;
1104                 goto fail2;
1105         }
1106
1107         /* This action does not have any arguments, so do nothing here. */
1108
1109         return (0);
1110
1111 fail2:
1112         EFSYS_PROBE(fail2);
1113 fail1:
1114         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1115         return (rc);
1116 }
1117
1118 static  __checkReturn                   efx_rc_t
1119 efx_mae_action_set_add_mark(
1120         __in                            efx_mae_actions_t *spec,
1121         __in                            size_t arg_size,
1122         __in_bcount(arg_size)           const uint8_t *arg)
1123 {
1124         efx_rc_t rc;
1125
1126         if (arg_size != sizeof (spec->ema_mark_value)) {
1127                 rc = EINVAL;
1128                 goto fail1;
1129         }
1130
1131         if (arg == NULL) {
1132                 rc = EINVAL;
1133                 goto fail2;
1134         }
1135
1136         memcpy(&spec->ema_mark_value, arg, arg_size);
1137
1138         return (0);
1139
1140 fail2:
1141         EFSYS_PROBE(fail2);
1142 fail1:
1143         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1144         return (rc);
1145 }
1146
1147 static  __checkReturn                   efx_rc_t
1148 efx_mae_action_set_add_deliver(
1149         __in                            efx_mae_actions_t *spec,
1150         __in                            size_t arg_size,
1151         __in_bcount(arg_size)           const uint8_t *arg)
1152 {
1153         efx_rc_t rc;
1154
1155         if (arg_size != sizeof (spec->ema_deliver_mport)) {
1156                 rc = EINVAL;
1157                 goto fail1;
1158         }
1159
1160         if (arg == NULL) {
1161                 rc = EINVAL;
1162                 goto fail2;
1163         }
1164
1165         memcpy(&spec->ema_deliver_mport, arg, arg_size);
1166
1167         return (0);
1168
1169 fail2:
1170         EFSYS_PROBE(fail2);
1171 fail1:
1172         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1173         return (rc);
1174 }
1175
1176 typedef struct efx_mae_action_desc_s {
1177         /* Action specific handler */
1178         efx_rc_t        (*emad_add)(efx_mae_actions_t *,
1179                                     size_t, const uint8_t *);
1180 } efx_mae_action_desc_t;
1181
1182 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
1183         [EFX_MAE_ACTION_VLAN_POP] = {
1184                 .emad_add = efx_mae_action_set_add_vlan_pop
1185         },
1186         [EFX_MAE_ACTION_VLAN_PUSH] = {
1187                 .emad_add = efx_mae_action_set_add_vlan_push
1188         },
1189         [EFX_MAE_ACTION_FLAG] = {
1190                 .emad_add = efx_mae_action_set_add_flag
1191         },
1192         [EFX_MAE_ACTION_MARK] = {
1193                 .emad_add = efx_mae_action_set_add_mark
1194         },
1195         [EFX_MAE_ACTION_DELIVER] = {
1196                 .emad_add = efx_mae_action_set_add_deliver
1197         }
1198 };
1199
1200 static const uint32_t efx_mae_action_ordered_map =
1201         (1U << EFX_MAE_ACTION_VLAN_POP) |
1202         (1U << EFX_MAE_ACTION_VLAN_PUSH) |
1203         (1U << EFX_MAE_ACTION_FLAG) |
1204         (1U << EFX_MAE_ACTION_MARK) |
1205         (1U << EFX_MAE_ACTION_DELIVER);
1206
1207 /*
1208  * These actions must not be added after DELIVER, but
1209  * they can have any place among the rest of
1210  * strictly ordered actions.
1211  */
1212 static const uint32_t efx_mae_action_nonstrict_map =
1213         (1U << EFX_MAE_ACTION_FLAG) |
1214         (1U << EFX_MAE_ACTION_MARK);
1215
1216 static const uint32_t efx_mae_action_repeat_map =
1217         (1U << EFX_MAE_ACTION_VLAN_POP) |
1218         (1U << EFX_MAE_ACTION_VLAN_PUSH);
1219
1220 /*
1221  * Add an action to an action set.
1222  *
1223  * This has to be invoked in the desired action order.
1224  * An out-of-order action request will be turned down.
1225  */
1226 static  __checkReturn                   efx_rc_t
1227 efx_mae_action_set_spec_populate(
1228         __in                            efx_mae_actions_t *spec,
1229         __in                            efx_mae_action_t type,
1230         __in                            size_t arg_size,
1231         __in_bcount(arg_size)           const uint8_t *arg)
1232 {
1233         uint32_t action_mask;
1234         efx_rc_t rc;
1235
1236         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1237             (sizeof (efx_mae_action_ordered_map) * 8));
1238         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1239             (sizeof (efx_mae_action_repeat_map) * 8));
1240
1241         EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
1242         EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK);
1243         EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER);
1244
1245         if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
1246                 rc = EINVAL;
1247                 goto fail1;
1248         }
1249
1250         action_mask = (1U << type);
1251
1252         if ((spec->ema_actions & action_mask) != 0) {
1253                 /* The action set already contains this action. */
1254                 if ((efx_mae_action_repeat_map & action_mask) == 0) {
1255                         /* Cannot add another non-repeatable action. */
1256                         rc = ENOTSUP;
1257                         goto fail2;
1258                 }
1259         }
1260
1261         if ((efx_mae_action_ordered_map & action_mask) != 0) {
1262                 uint32_t strict_ordered_map =
1263                     efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map;
1264                 uint32_t later_actions_mask =
1265                     strict_ordered_map & ~(action_mask | (action_mask - 1));
1266
1267                 if ((spec->ema_actions & later_actions_mask) != 0) {
1268                         /* Cannot add an action after later ordered actions. */
1269                         rc = ENOTSUP;
1270                         goto fail3;
1271                 }
1272         }
1273
1274         if (efx_mae_actions[type].emad_add != NULL) {
1275                 rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
1276                 if (rc != 0)
1277                         goto fail4;
1278         }
1279
1280         spec->ema_actions |= action_mask;
1281
1282         return (0);
1283
1284 fail4:
1285         EFSYS_PROBE(fail4);
1286 fail3:
1287         EFSYS_PROBE(fail3);
1288 fail2:
1289         EFSYS_PROBE(fail2);
1290 fail1:
1291         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1292         return (rc);
1293 }
1294
1295         __checkReturn                   efx_rc_t
1296 efx_mae_action_set_populate_vlan_pop(
1297         __in                            efx_mae_actions_t *spec)
1298 {
1299         return (efx_mae_action_set_spec_populate(spec,
1300             EFX_MAE_ACTION_VLAN_POP, 0, NULL));
1301 }
1302
1303         __checkReturn                   efx_rc_t
1304 efx_mae_action_set_populate_vlan_push(
1305         __in                            efx_mae_actions_t *spec,
1306         __in                            uint16_t tpid_be,
1307         __in                            uint16_t tci_be)
1308 {
1309         efx_mae_action_vlan_push_t action;
1310         const uint8_t *arg = (const uint8_t *)&action;
1311
1312         action.emavp_tpid_be = tpid_be;
1313         action.emavp_tci_be = tci_be;
1314
1315         return (efx_mae_action_set_spec_populate(spec,
1316             EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg));
1317 }
1318
1319         __checkReturn                   efx_rc_t
1320 efx_mae_action_set_populate_flag(
1321         __in                            efx_mae_actions_t *spec)
1322 {
1323         return (efx_mae_action_set_spec_populate(spec,
1324             EFX_MAE_ACTION_FLAG, 0, NULL));
1325 }
1326
1327         __checkReturn                   efx_rc_t
1328 efx_mae_action_set_populate_mark(
1329         __in                            efx_mae_actions_t *spec,
1330         __in                            uint32_t mark_value)
1331 {
1332         const uint8_t *arg = (const uint8_t *)&mark_value;
1333
1334         return (efx_mae_action_set_spec_populate(spec,
1335             EFX_MAE_ACTION_MARK, sizeof (mark_value), arg));
1336 }
1337
1338         __checkReturn                   efx_rc_t
1339 efx_mae_action_set_populate_deliver(
1340         __in                            efx_mae_actions_t *spec,
1341         __in                            const efx_mport_sel_t *mportp)
1342 {
1343         const uint8_t *arg;
1344         efx_rc_t rc;
1345
1346         if (mportp == NULL) {
1347                 rc = EINVAL;
1348                 goto fail1;
1349         }
1350
1351         arg = (const uint8_t *)&mportp->sel;
1352
1353         return (efx_mae_action_set_spec_populate(spec,
1354             EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
1355
1356 fail1:
1357         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1358         return (rc);
1359 }
1360
1361         __checkReturn                   efx_rc_t
1362 efx_mae_action_set_populate_drop(
1363         __in                            efx_mae_actions_t *spec)
1364 {
1365         efx_mport_sel_t mport;
1366         const uint8_t *arg;
1367         efx_dword_t dword;
1368
1369         EFX_POPULATE_DWORD_1(dword,
1370             MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL);
1371
1372         /*
1373          * The constructed DWORD is little-endian,
1374          * but the resulting value is meant to be
1375          * passed to MCDIs, where it will undergo
1376          * host-order to little endian conversion.
1377          */
1378         mport.sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
1379
1380         arg = (const uint8_t *)&mport.sel;
1381
1382         return (efx_mae_action_set_spec_populate(spec,
1383             EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg));
1384 }
1385
1386         __checkReturn                   boolean_t
1387 efx_mae_action_set_specs_equal(
1388         __in                            const efx_mae_actions_t *left,
1389         __in                            const efx_mae_actions_t *right)
1390 {
1391         return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
1392 }
1393
1394         __checkReturn                   efx_rc_t
1395 efx_mae_match_specs_class_cmp(
1396         __in                            efx_nic_t *enp,
1397         __in                            const efx_mae_match_spec_t *left,
1398         __in                            const efx_mae_match_spec_t *right,
1399         __out                           boolean_t *have_same_classp)
1400 {
1401         efx_mae_t *maep = enp->en_maep;
1402         unsigned int field_ncaps = maep->em_max_nfields;
1403         const efx_mae_field_cap_t *field_caps;
1404         const efx_mae_mv_desc_t *desc_setp;
1405         unsigned int desc_set_nentries;
1406         boolean_t have_same_class = B_TRUE;
1407         efx_mae_field_id_t field_id;
1408         const uint8_t *mvpl;
1409         const uint8_t *mvpr;
1410         efx_rc_t rc;
1411
1412         switch (left->emms_type) {
1413         case EFX_MAE_RULE_OUTER:
1414                 field_caps = maep->em_outer_rule_field_caps;
1415                 desc_setp = __efx_mae_outer_rule_mv_desc_set;
1416                 desc_set_nentries =
1417                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1418                 mvpl = left->emms_mask_value_pairs.outer;
1419                 mvpr = right->emms_mask_value_pairs.outer;
1420                 break;
1421         case EFX_MAE_RULE_ACTION:
1422                 field_caps = maep->em_action_rule_field_caps;
1423                 desc_setp = __efx_mae_action_rule_mv_desc_set;
1424                 desc_set_nentries =
1425                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1426                 mvpl = left->emms_mask_value_pairs.action;
1427                 mvpr = right->emms_mask_value_pairs.action;
1428                 break;
1429         default:
1430                 rc = ENOTSUP;
1431                 goto fail1;
1432         }
1433
1434         if (field_caps == NULL) {
1435                 rc = EAGAIN;
1436                 goto fail2;
1437         }
1438
1439         if (left->emms_type != right->emms_type ||
1440             left->emms_prio != right->emms_prio) {
1441                 /*
1442                  * Rules of different types can never map to the same class.
1443                  *
1444                  * The FW can support some set of match criteria for one
1445                  * priority and not support the very same set for
1446                  * another priority. Thus, two rules which have
1447                  * different priorities can never map to
1448                  * the same class.
1449                  */
1450                 *have_same_classp = B_FALSE;
1451                 return (0);
1452         }
1453
1454         for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1455              ++field_id) {
1456                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1457                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1458                 const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
1459                 const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
1460                 size_t mask_size = descp->emmd_mask_size;
1461                 const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
1462                 const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
1463                 size_t value_size = descp->emmd_value_size;
1464
1465                 if (mask_size == 0)
1466                         continue; /* Skip array gap */
1467
1468                 if ((unsigned int)field_cap_id >= field_ncaps) {
1469                         /*
1470                          * The FW has not reported capability status for this
1471                          * field. It's unknown whether any difference between
1472                          * the two masks / values affects the class. The only
1473                          * case when the class must be the same is when these
1474                          * mask-value pairs match. Otherwise, report mismatch.
1475                          */
1476                         if ((memcmp(lmaskp, rmaskp, mask_size) == 0) &&
1477                             (memcmp(lvalp, rvalp, value_size) == 0))
1478                                 continue;
1479                         else
1480                                 break;
1481                 }
1482
1483                 if (field_caps[field_cap_id].emfc_mask_affects_class) {
1484                         if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
1485                                 have_same_class = B_FALSE;
1486                                 break;
1487                         }
1488                 }
1489
1490                 if (field_caps[field_cap_id].emfc_match_affects_class) {
1491                         if (memcmp(lvalp, rvalp, value_size) != 0) {
1492                                 have_same_class = B_FALSE;
1493                                 break;
1494                         }
1495                 }
1496         }
1497
1498         *have_same_classp = have_same_class;
1499
1500         return (0);
1501
1502 fail2:
1503         EFSYS_PROBE(fail2);
1504 fail1:
1505         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1506         return (rc);
1507 }
1508
1509         __checkReturn           efx_rc_t
1510 efx_mae_outer_rule_insert(
1511         __in                    efx_nic_t *enp,
1512         __in                    const efx_mae_match_spec_t *spec,
1513         __in                    efx_tunnel_protocol_t encap_type,
1514         __out                   efx_mae_rule_id_t *or_idp)
1515 {
1516         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1517         efx_mcdi_req_t req;
1518         EFX_MCDI_DECLARE_BUF(payload,
1519             MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2,
1520             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
1521         uint32_t encap_type_mcdi;
1522         efx_mae_rule_id_t or_id;
1523         size_t offset;
1524         efx_rc_t rc;
1525
1526         EFX_STATIC_ASSERT(sizeof (or_idp->id) ==
1527             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN);
1528
1529         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1530             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL);
1531
1532         if (encp->enc_mae_supported == B_FALSE) {
1533                 rc = ENOTSUP;
1534                 goto fail1;
1535         }
1536
1537         if (spec->emms_type != EFX_MAE_RULE_OUTER) {
1538                 rc = EINVAL;
1539                 goto fail2;
1540         }
1541
1542         switch (encap_type) {
1543         case EFX_TUNNEL_PROTOCOL_NONE:
1544                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
1545                 break;
1546         case EFX_TUNNEL_PROTOCOL_VXLAN:
1547                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
1548                 break;
1549         case EFX_TUNNEL_PROTOCOL_GENEVE:
1550                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
1551                 break;
1552         case EFX_TUNNEL_PROTOCOL_NVGRE:
1553                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
1554                 break;
1555         default:
1556                 rc = ENOTSUP;
1557                 goto fail3;
1558         }
1559
1560         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT;
1561         req.emr_in_buf = payload;
1562         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2;
1563         req.emr_out_buf = payload;
1564         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN;
1565
1566         MCDI_IN_SET_DWORD(req,
1567             MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi);
1568
1569         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio);
1570
1571         /*
1572          * Mask-value pairs have been stored in the byte order needed for the
1573          * MCDI request and are thus safe to be copied directly to the buffer.
1574          * The library cares about byte order in efx_mae_match_spec_field_set().
1575          */
1576         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >=
1577             MAE_ENC_FIELD_PAIRS_LEN);
1578         offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST;
1579         memcpy(payload + offset, spec->emms_mask_value_pairs.outer,
1580             MAE_ENC_FIELD_PAIRS_LEN);
1581
1582         efx_mcdi_execute(enp, &req);
1583
1584         if (req.emr_rc != 0) {
1585                 rc = req.emr_rc;
1586                 goto fail4;
1587         }
1588
1589         if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) {
1590                 rc = EMSGSIZE;
1591                 goto fail5;
1592         }
1593
1594         or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
1595         if (or_id.id == EFX_MAE_RSRC_ID_INVALID) {
1596                 rc = ENOENT;
1597                 goto fail6;
1598         }
1599
1600         or_idp->id = or_id.id;
1601
1602         return (0);
1603
1604 fail6:
1605         EFSYS_PROBE(fail6);
1606 fail5:
1607         EFSYS_PROBE(fail5);
1608 fail4:
1609         EFSYS_PROBE(fail4);
1610 fail3:
1611         EFSYS_PROBE(fail3);
1612 fail2:
1613         EFSYS_PROBE(fail2);
1614 fail1:
1615         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1616         return (rc);
1617 }
1618
1619         __checkReturn           efx_rc_t
1620 efx_mae_outer_rule_remove(
1621         __in                    efx_nic_t *enp,
1622         __in                    const efx_mae_rule_id_t *or_idp)
1623 {
1624         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1625         efx_mcdi_req_t req;
1626         EFX_MCDI_DECLARE_BUF(payload,
1627             MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1),
1628             MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
1629         efx_rc_t rc;
1630
1631         if (encp->enc_mae_supported == B_FALSE) {
1632                 rc = ENOTSUP;
1633                 goto fail1;
1634         }
1635
1636         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE;
1637         req.emr_in_buf = payload;
1638         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1);
1639         req.emr_out_buf = payload;
1640         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1);
1641
1642         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id);
1643
1644         efx_mcdi_execute(enp, &req);
1645
1646         if (req.emr_rc != 0) {
1647                 rc = req.emr_rc;
1648                 goto fail2;
1649         }
1650
1651         if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) !=
1652             or_idp->id) {
1653                 /* Firmware failed to remove the outer rule. */
1654                 rc = EAGAIN;
1655                 goto fail3;
1656         }
1657
1658         return (0);
1659
1660 fail3:
1661         EFSYS_PROBE(fail3);
1662 fail2:
1663         EFSYS_PROBE(fail2);
1664 fail1:
1665         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1666         return (rc);
1667 }
1668
1669         __checkReturn                   efx_rc_t
1670 efx_mae_match_spec_outer_rule_id_set(
1671         __in                            efx_mae_match_spec_t *spec,
1672         __in                            const efx_mae_rule_id_t *or_idp)
1673 {
1674         uint32_t full_mask = UINT32_MAX;
1675         efx_rc_t rc;
1676
1677         if (spec->emms_type != EFX_MAE_RULE_ACTION) {
1678                 rc = EINVAL;
1679                 goto fail1;
1680         }
1681
1682         if (or_idp == NULL) {
1683                 rc = EINVAL;
1684                 goto fail2;
1685         }
1686
1687         rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID,
1688             sizeof (or_idp->id), (const uint8_t *)&or_idp->id,
1689             sizeof (full_mask), (const uint8_t *)&full_mask);
1690         if (rc != 0)
1691                 goto fail3;
1692
1693         return (0);
1694
1695 fail3:
1696         EFSYS_PROBE(fail3);
1697 fail2:
1698         EFSYS_PROBE(fail2);
1699 fail1:
1700         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1701         return (rc);
1702 }
1703
1704          __checkReturn                  efx_rc_t
1705 efx_mae_encap_header_alloc(
1706         __in                            efx_nic_t *enp,
1707         __in                            efx_tunnel_protocol_t encap_type,
1708         __in_bcount(header_size)        uint8_t *header_data,
1709         __in                            size_t header_size,
1710         __out                           efx_mae_eh_id_t *eh_idp)
1711 {
1712         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1713         efx_mcdi_req_t req;
1714         EFX_MCDI_DECLARE_BUF(payload,
1715             MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LENMAX_MCDI2,
1716             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN);
1717         uint32_t encap_type_mcdi;
1718         efx_mae_eh_id_t eh_id;
1719         efx_rc_t rc;
1720
1721         EFX_STATIC_ASSERT(sizeof (eh_idp->id) ==
1722             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_LEN);
1723
1724         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1725             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
1726
1727         if (encp->enc_mae_supported == B_FALSE) {
1728                 rc = ENOTSUP;
1729                 goto fail1;
1730         }
1731
1732         switch (encap_type) {
1733         case EFX_TUNNEL_PROTOCOL_NONE:
1734                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
1735                 break;
1736         case EFX_TUNNEL_PROTOCOL_VXLAN:
1737                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
1738                 break;
1739         case EFX_TUNNEL_PROTOCOL_GENEVE:
1740                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
1741                 break;
1742         case EFX_TUNNEL_PROTOCOL_NVGRE:
1743                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
1744                 break;
1745         default:
1746                 rc = ENOTSUP;
1747                 goto fail2;
1748         }
1749
1750         if (header_size >
1751             MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2) {
1752                 rc = EINVAL;
1753                 goto fail3;
1754         }
1755
1756         req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_ALLOC;
1757         req.emr_in_buf = payload;
1758         req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(header_size);
1759         req.emr_out_buf = payload;
1760         req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN;
1761
1762         MCDI_IN_SET_DWORD(req,
1763             MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, encap_type_mcdi);
1764
1765         memcpy(payload + MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_OFST,
1766             header_data, header_size);
1767
1768         efx_mcdi_execute(enp, &req);
1769
1770         if (req.emr_rc != 0) {
1771                 rc = req.emr_rc;
1772                 goto fail4;
1773         }
1774
1775         if (req.emr_out_length_used < MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN) {
1776                 rc = EMSGSIZE;
1777                 goto fail5;
1778         }
1779
1780         eh_id.id = MCDI_OUT_DWORD(req,
1781             MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID);
1782
1783         if (eh_id.id == EFX_MAE_RSRC_ID_INVALID) {
1784                 rc = ENOENT;
1785                 goto fail6;
1786         }
1787
1788         eh_idp->id = eh_id.id;
1789
1790         return (0);
1791
1792 fail6:
1793         EFSYS_PROBE(fail6);
1794 fail5:
1795         EFSYS_PROBE(fail5);
1796 fail4:
1797         EFSYS_PROBE(fail4);
1798 fail3:
1799         EFSYS_PROBE(fail3);
1800 fail2:
1801         EFSYS_PROBE(fail2);
1802 fail1:
1803         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1804         return (rc);
1805 }
1806
1807         __checkReturn                   efx_rc_t
1808 efx_mae_encap_header_free(
1809         __in                            efx_nic_t *enp,
1810         __in                            const efx_mae_eh_id_t *eh_idp)
1811 {
1812         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1813         efx_mcdi_req_t req;
1814         EFX_MCDI_DECLARE_BUF(payload,
1815             MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1),
1816             MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1));
1817         efx_rc_t rc;
1818
1819         if (encp->enc_mae_supported == B_FALSE) {
1820                 rc = ENOTSUP;
1821                 goto fail1;
1822         }
1823
1824         req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_FREE;
1825         req.emr_in_buf = payload;
1826         req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1);
1827         req.emr_out_buf = payload;
1828         req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1);
1829
1830         MCDI_IN_SET_DWORD(req, MAE_ENCAP_HEADER_FREE_IN_EH_ID, eh_idp->id);
1831
1832         efx_mcdi_execute(enp, &req);
1833
1834         if (req.emr_rc != 0) {
1835                 rc = req.emr_rc;
1836                 goto fail2;
1837         }
1838
1839         if (MCDI_OUT_DWORD(req, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) !=
1840             eh_idp->id) {
1841                 /* Firmware failed to remove the encap. header. */
1842                 rc = EAGAIN;
1843                 goto fail3;
1844         }
1845
1846         return (0);
1847
1848 fail3:
1849         EFSYS_PROBE(fail3);
1850 fail2:
1851         EFSYS_PROBE(fail2);
1852 fail1:
1853         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1854         return (rc);
1855 }
1856
1857         __checkReturn                   efx_rc_t
1858 efx_mae_action_set_alloc(
1859         __in                            efx_nic_t *enp,
1860         __in                            const efx_mae_actions_t *spec,
1861         __out                           efx_mae_aset_id_t *aset_idp)
1862 {
1863         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1864         efx_mcdi_req_t req;
1865         EFX_MCDI_DECLARE_BUF(payload,
1866             MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
1867             MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
1868         efx_mae_aset_id_t aset_id;
1869         efx_rc_t rc;
1870
1871         if (encp->enc_mae_supported == B_FALSE) {
1872                 rc = ENOTSUP;
1873                 goto fail1;
1874         }
1875
1876         req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
1877         req.emr_in_buf = payload;
1878         req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
1879         req.emr_out_buf = payload;
1880         req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
1881
1882         /*
1883          * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
1884          * corresponding resource types are supported by the implementation.
1885          * Use proper resource ID assignments instead.
1886          */
1887         MCDI_IN_SET_DWORD(req,
1888             MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
1889         MCDI_IN_SET_DWORD(req,
1890             MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
1891         MCDI_IN_SET_DWORD(req,
1892             MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, EFX_MAE_RSRC_ID_INVALID);
1893
1894         MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1895             MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
1896
1897         if (spec->ema_n_vlan_tags_to_push > 0) {
1898                 unsigned int outer_tag_idx;
1899
1900                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1901                     MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
1902                     spec->ema_n_vlan_tags_to_push);
1903
1904                 if (spec->ema_n_vlan_tags_to_push ==
1905                     EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1906                         MCDI_IN_SET_WORD(req,
1907                             MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
1908                             spec->ema_vlan_push_descs[0].emavp_tpid_be);
1909                         MCDI_IN_SET_WORD(req,
1910                             MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
1911                             spec->ema_vlan_push_descs[0].emavp_tci_be);
1912                 }
1913
1914                 outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
1915
1916                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
1917                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
1918                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
1919                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
1920         }
1921
1922         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
1923                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1924                     MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
1925         }
1926
1927         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
1928                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1929                     MAE_ACTION_SET_ALLOC_IN_MARK, 1);
1930
1931                 MCDI_IN_SET_DWORD(req,
1932                     MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
1933         }
1934
1935         MCDI_IN_SET_DWORD(req,
1936             MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
1937
1938         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
1939             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
1940         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
1941             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
1942
1943         efx_mcdi_execute(enp, &req);
1944
1945         if (req.emr_rc != 0) {
1946                 rc = req.emr_rc;
1947                 goto fail2;
1948         }
1949
1950         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
1951                 rc = EMSGSIZE;
1952                 goto fail3;
1953         }
1954
1955         aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
1956         if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
1957                 rc = ENOENT;
1958                 goto fail4;
1959         }
1960
1961         aset_idp->id = aset_id.id;
1962
1963         return (0);
1964
1965 fail4:
1966         EFSYS_PROBE(fail4);
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_free(
1978         __in                            efx_nic_t *enp,
1979         __in                            const efx_mae_aset_id_t *aset_idp)
1980 {
1981         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1982         efx_mcdi_req_t req;
1983         EFX_MCDI_DECLARE_BUF(payload,
1984             MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
1985             MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
1986         efx_rc_t rc;
1987
1988         if (encp->enc_mae_supported == B_FALSE) {
1989                 rc = ENOTSUP;
1990                 goto fail1;
1991         }
1992
1993         req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
1994         req.emr_in_buf = payload;
1995         req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
1996         req.emr_out_buf = payload;
1997         req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
1998
1999         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
2000
2001         efx_mcdi_execute(enp, &req);
2002
2003         if (req.emr_rc != 0) {
2004                 rc = req.emr_rc;
2005                 goto fail2;
2006         }
2007
2008         if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
2009             aset_idp->id) {
2010                 /* Firmware failed to free the action set. */
2011                 rc = EAGAIN;
2012                 goto fail3;
2013         }
2014
2015         return (0);
2016
2017 fail3:
2018         EFSYS_PROBE(fail3);
2019 fail2:
2020         EFSYS_PROBE(fail2);
2021 fail1:
2022         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2023         return (rc);
2024 }
2025
2026         __checkReturn                   efx_rc_t
2027 efx_mae_action_rule_insert(
2028         __in                            efx_nic_t *enp,
2029         __in                            const efx_mae_match_spec_t *spec,
2030         __in                            const efx_mae_aset_list_id_t *asl_idp,
2031         __in                            const efx_mae_aset_id_t *as_idp,
2032         __out                           efx_mae_rule_id_t *ar_idp)
2033 {
2034         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2035         efx_mcdi_req_t req;
2036         EFX_MCDI_DECLARE_BUF(payload,
2037             MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2,
2038             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
2039         efx_oword_t *rule_response;
2040         efx_mae_rule_id_t ar_id;
2041         size_t offset;
2042         efx_rc_t rc;
2043
2044         EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
2045             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
2046
2047         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2048             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
2049
2050         if (encp->enc_mae_supported == B_FALSE) {
2051                 rc = ENOTSUP;
2052                 goto fail1;
2053         }
2054
2055         if (spec->emms_type != EFX_MAE_RULE_ACTION ||
2056             (asl_idp != NULL && as_idp != NULL) ||
2057             (asl_idp == NULL && as_idp == NULL)) {
2058                 rc = EINVAL;
2059                 goto fail2;
2060         }
2061
2062         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
2063         req.emr_in_buf = payload;
2064         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
2065         req.emr_out_buf = payload;
2066         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
2067
2068         EFX_STATIC_ASSERT(sizeof (*rule_response) <=
2069             MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
2070         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
2071         rule_response = (efx_oword_t *)(payload + offset);
2072         EFX_POPULATE_OWORD_3(*rule_response,
2073             MAE_ACTION_RULE_RESPONSE_ASL_ID,
2074             (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
2075             MAE_ACTION_RULE_RESPONSE_AS_ID,
2076             (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
2077             MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
2078
2079         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
2080
2081         /*
2082          * Mask-value pairs have been stored in the byte order needed for the
2083          * MCDI request and are thus safe to be copied directly to the buffer.
2084          */
2085         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
2086             MAE_FIELD_MASK_VALUE_PAIRS_LEN);
2087         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
2088         memcpy(payload + offset, spec->emms_mask_value_pairs.action,
2089             MAE_FIELD_MASK_VALUE_PAIRS_LEN);
2090
2091         efx_mcdi_execute(enp, &req);
2092
2093         if (req.emr_rc != 0) {
2094                 rc = req.emr_rc;
2095                 goto fail3;
2096         }
2097
2098         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
2099                 rc = EMSGSIZE;
2100                 goto fail4;
2101         }
2102
2103         ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
2104         if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
2105                 rc = ENOENT;
2106                 goto fail5;
2107         }
2108
2109         ar_idp->id = ar_id.id;
2110
2111         return (0);
2112
2113 fail5:
2114         EFSYS_PROBE(fail5);
2115 fail4:
2116         EFSYS_PROBE(fail4);
2117 fail3:
2118         EFSYS_PROBE(fail3);
2119 fail2:
2120         EFSYS_PROBE(fail2);
2121 fail1:
2122         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2123         return (rc);
2124 }
2125
2126         __checkReturn                   efx_rc_t
2127 efx_mae_action_rule_remove(
2128         __in                            efx_nic_t *enp,
2129         __in                            const efx_mae_rule_id_t *ar_idp)
2130 {
2131         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2132         efx_mcdi_req_t req;
2133         EFX_MCDI_DECLARE_BUF(payload,
2134             MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
2135             MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
2136         efx_rc_t rc;
2137
2138         if (encp->enc_mae_supported == B_FALSE) {
2139                 rc = ENOTSUP;
2140                 goto fail1;
2141         }
2142
2143         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
2144         req.emr_in_buf = payload;
2145         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
2146         req.emr_out_buf = payload;
2147         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
2148
2149         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
2150
2151         efx_mcdi_execute(enp, &req);
2152
2153         if (req.emr_rc != 0) {
2154                 rc = req.emr_rc;
2155                 goto fail2;
2156         }
2157
2158         if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
2159             ar_idp->id) {
2160                 /* Firmware failed to delete the action rule. */
2161                 rc = EAGAIN;
2162                 goto fail3;
2163         }
2164
2165         return (0);
2166
2167 fail3:
2168         EFSYS_PROBE(fail3);
2169 fail2:
2170         EFSYS_PROBE(fail2);
2171 fail1:
2172         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2173         return (rc);
2174 }
2175
2176 #endif /* EFSYS_OPT_MAE */