common/sfc_efx: update copyright year
[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
356         return (0);
357
358 fail1:
359         EFSYS_PROBE1(fail1, efx_rc_t, rc);
360         return (rc);
361 }
362
363         __checkReturn                   efx_rc_t
364 efx_mae_match_spec_init(
365         __in                            efx_nic_t *enp,
366         __in                            efx_mae_rule_type_t type,
367         __in                            uint32_t prio,
368         __out                           efx_mae_match_spec_t **specp)
369 {
370         efx_mae_match_spec_t *spec;
371         efx_rc_t rc;
372
373         switch (type) {
374         case EFX_MAE_RULE_OUTER:
375                 break;
376         case EFX_MAE_RULE_ACTION:
377                 break;
378         default:
379                 rc = ENOTSUP;
380                 goto fail1;
381         }
382
383         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
384         if (spec == NULL) {
385                 rc = ENOMEM;
386                 goto fail2;
387         }
388
389         spec->emms_type = type;
390         spec->emms_prio = prio;
391
392         *specp = spec;
393
394         return (0);
395
396 fail2:
397         EFSYS_PROBE(fail2);
398 fail1:
399         EFSYS_PROBE1(fail1, efx_rc_t, rc);
400         return (rc);
401 }
402
403                                         void
404 efx_mae_match_spec_fini(
405         __in                            efx_nic_t *enp,
406         __in                            efx_mae_match_spec_t *spec)
407 {
408         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
409 }
410
411 /* Named identifiers which are valid indices to efx_mae_field_cap_t */
412 typedef enum efx_mae_field_cap_id_e {
413         EFX_MAE_FIELD_ID_INGRESS_MPORT_SELECTOR = MAE_FIELD_INGRESS_PORT,
414         EFX_MAE_FIELD_ID_ETHER_TYPE_BE = MAE_FIELD_ETHER_TYPE,
415         EFX_MAE_FIELD_ID_ETH_SADDR_BE = MAE_FIELD_ETH_SADDR,
416         EFX_MAE_FIELD_ID_ETH_DADDR_BE = MAE_FIELD_ETH_DADDR,
417         EFX_MAE_FIELD_ID_VLAN0_TCI_BE = MAE_FIELD_VLAN0_TCI,
418         EFX_MAE_FIELD_ID_VLAN0_PROTO_BE = MAE_FIELD_VLAN0_PROTO,
419         EFX_MAE_FIELD_ID_VLAN1_TCI_BE = MAE_FIELD_VLAN1_TCI,
420         EFX_MAE_FIELD_ID_VLAN1_PROTO_BE = MAE_FIELD_VLAN1_PROTO,
421         EFX_MAE_FIELD_ID_SRC_IP4_BE = MAE_FIELD_SRC_IP4,
422         EFX_MAE_FIELD_ID_DST_IP4_BE = MAE_FIELD_DST_IP4,
423         EFX_MAE_FIELD_ID_IP_PROTO = MAE_FIELD_IP_PROTO,
424         EFX_MAE_FIELD_ID_IP_TOS = MAE_FIELD_IP_TOS,
425         EFX_MAE_FIELD_ID_IP_TTL = MAE_FIELD_IP_TTL,
426         EFX_MAE_FIELD_ID_SRC_IP6_BE = MAE_FIELD_SRC_IP6,
427         EFX_MAE_FIELD_ID_DST_IP6_BE = MAE_FIELD_DST_IP6,
428         EFX_MAE_FIELD_ID_L4_SPORT_BE = MAE_FIELD_L4_SPORT,
429         EFX_MAE_FIELD_ID_L4_DPORT_BE = MAE_FIELD_L4_DPORT,
430         EFX_MAE_FIELD_ID_TCP_FLAGS_BE = MAE_FIELD_TCP_FLAGS,
431         EFX_MAE_FIELD_ID_ENC_ETHER_TYPE_BE = MAE_FIELD_ENC_ETHER_TYPE,
432         EFX_MAE_FIELD_ID_ENC_ETH_SADDR_BE = MAE_FIELD_ENC_ETH_SADDR,
433         EFX_MAE_FIELD_ID_ENC_ETH_DADDR_BE = MAE_FIELD_ENC_ETH_DADDR,
434         EFX_MAE_FIELD_ID_ENC_VLAN0_TCI_BE = MAE_FIELD_ENC_VLAN0_TCI,
435         EFX_MAE_FIELD_ID_ENC_VLAN0_PROTO_BE = MAE_FIELD_ENC_VLAN0_PROTO,
436         EFX_MAE_FIELD_ID_ENC_VLAN1_TCI_BE = MAE_FIELD_ENC_VLAN1_TCI,
437         EFX_MAE_FIELD_ID_ENC_VLAN1_PROTO_BE = MAE_FIELD_ENC_VLAN1_PROTO,
438         EFX_MAE_FIELD_ID_ENC_SRC_IP4_BE = MAE_FIELD_ENC_SRC_IP4,
439         EFX_MAE_FIELD_ID_ENC_DST_IP4_BE = MAE_FIELD_ENC_DST_IP4,
440         EFX_MAE_FIELD_ID_ENC_IP_PROTO = MAE_FIELD_ENC_IP_PROTO,
441         EFX_MAE_FIELD_ID_ENC_IP_TOS = MAE_FIELD_ENC_IP_TOS,
442         EFX_MAE_FIELD_ID_ENC_IP_TTL = MAE_FIELD_ENC_IP_TTL,
443         EFX_MAE_FIELD_ID_ENC_SRC_IP6_BE = MAE_FIELD_ENC_SRC_IP6,
444         EFX_MAE_FIELD_ID_ENC_DST_IP6_BE = MAE_FIELD_ENC_DST_IP6,
445         EFX_MAE_FIELD_ID_ENC_L4_SPORT_BE = MAE_FIELD_ENC_L4_SPORT,
446         EFX_MAE_FIELD_ID_ENC_L4_DPORT_BE = MAE_FIELD_ENC_L4_DPORT,
447         EFX_MAE_FIELD_ID_ENC_VNET_ID_BE = MAE_FIELD_ENC_VNET_ID,
448         EFX_MAE_FIELD_ID_OUTER_RULE_ID = MAE_FIELD_OUTER_RULE_ID,
449
450         EFX_MAE_FIELD_CAP_NIDS
451 } efx_mae_field_cap_id_t;
452
453 typedef enum efx_mae_field_endianness_e {
454         EFX_MAE_FIELD_LE = 0,
455         EFX_MAE_FIELD_BE,
456
457         EFX_MAE_FIELD_ENDIANNESS_NTYPES
458 } efx_mae_field_endianness_t;
459
460 /*
461  * The following structure is a means to describe an MAE field.
462  * The information in it is meant to be used internally by
463  * APIs for addressing a given field in a mask-value pairs
464  * structure and for validation purposes.
465  *
466  * A field may have an alternative one. This structure
467  * has additional members to reference the alternative
468  * field's mask. See efx_mae_match_spec_is_valid().
469  */
470 typedef struct efx_mae_mv_desc_s {
471         efx_mae_field_cap_id_t          emmd_field_cap_id;
472
473         size_t                          emmd_value_size;
474         size_t                          emmd_value_offset;
475         size_t                          emmd_mask_size;
476         size_t                          emmd_mask_offset;
477
478         /*
479          * Having the alternative field's mask size set to 0
480          * means that there's no alternative field specified.
481          */
482         size_t                          emmd_alt_mask_size;
483         size_t                          emmd_alt_mask_offset;
484
485         /* Primary field and the alternative one are of the same endianness. */
486         efx_mae_field_endianness_t      emmd_endianness;
487 } efx_mae_mv_desc_t;
488
489 /* Indices to this array are provided by efx_mae_field_id_t */
490 static const efx_mae_mv_desc_t __efx_mae_action_rule_mv_desc_set[] = {
491 #define EFX_MAE_MV_DESC(_name, _endianness)                             \
492         [EFX_MAE_FIELD_##_name] =                                       \
493         {                                                               \
494                 EFX_MAE_FIELD_ID_##_name,                               \
495                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_LEN,               \
496                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_OFST,              \
497                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_LEN,          \
498                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_OFST,         \
499                 0, 0 /* no alternative field */,                        \
500                 _endianness                                             \
501         }
502
503         EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
504         EFX_MAE_MV_DESC(ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
505         EFX_MAE_MV_DESC(ETH_SADDR_BE, EFX_MAE_FIELD_BE),
506         EFX_MAE_MV_DESC(ETH_DADDR_BE, EFX_MAE_FIELD_BE),
507         EFX_MAE_MV_DESC(VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
508         EFX_MAE_MV_DESC(VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
509         EFX_MAE_MV_DESC(VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
510         EFX_MAE_MV_DESC(VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
511         EFX_MAE_MV_DESC(SRC_IP4_BE, EFX_MAE_FIELD_BE),
512         EFX_MAE_MV_DESC(DST_IP4_BE, EFX_MAE_FIELD_BE),
513         EFX_MAE_MV_DESC(IP_PROTO, EFX_MAE_FIELD_BE),
514         EFX_MAE_MV_DESC(IP_TOS, EFX_MAE_FIELD_BE),
515         EFX_MAE_MV_DESC(IP_TTL, EFX_MAE_FIELD_BE),
516         EFX_MAE_MV_DESC(SRC_IP6_BE, EFX_MAE_FIELD_BE),
517         EFX_MAE_MV_DESC(DST_IP6_BE, EFX_MAE_FIELD_BE),
518         EFX_MAE_MV_DESC(L4_SPORT_BE, EFX_MAE_FIELD_BE),
519         EFX_MAE_MV_DESC(L4_DPORT_BE, EFX_MAE_FIELD_BE),
520         EFX_MAE_MV_DESC(TCP_FLAGS_BE, EFX_MAE_FIELD_BE),
521         EFX_MAE_MV_DESC(ENC_VNET_ID_BE, EFX_MAE_FIELD_BE),
522         EFX_MAE_MV_DESC(OUTER_RULE_ID, EFX_MAE_FIELD_LE),
523
524 #undef EFX_MAE_MV_DESC
525 };
526
527 /* Indices to this array are provided by efx_mae_field_id_t */
528 static const efx_mae_mv_desc_t __efx_mae_outer_rule_mv_desc_set[] = {
529 #define EFX_MAE_MV_DESC(_name, _endianness)                             \
530         [EFX_MAE_FIELD_##_name] =                                       \
531         {                                                               \
532                 EFX_MAE_FIELD_ID_##_name,                               \
533                 MAE_ENC_FIELD_PAIRS_##_name##_LEN,                      \
534                 MAE_ENC_FIELD_PAIRS_##_name##_OFST,                     \
535                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,                 \
536                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,                \
537                 0, 0 /* no alternative field */,                        \
538                 _endianness                                             \
539         }
540
541 /* Same as EFX_MAE_MV_DESC(), but also indicates an alternative field. */
542 #define EFX_MAE_MV_DESC_ALT(_name, _alt_name, _endianness)              \
543         [EFX_MAE_FIELD_##_name] =                                       \
544         {                                                               \
545                 EFX_MAE_FIELD_ID_##_name,                               \
546                 MAE_ENC_FIELD_PAIRS_##_name##_LEN,                      \
547                 MAE_ENC_FIELD_PAIRS_##_name##_OFST,                     \
548                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,                 \
549                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,                \
550                 MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_LEN,             \
551                 MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_OFST,            \
552                 _endianness                                             \
553         }
554
555         EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
556         EFX_MAE_MV_DESC(ENC_ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
557         EFX_MAE_MV_DESC(ENC_ETH_SADDR_BE, EFX_MAE_FIELD_BE),
558         EFX_MAE_MV_DESC(ENC_ETH_DADDR_BE, EFX_MAE_FIELD_BE),
559         EFX_MAE_MV_DESC(ENC_VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
560         EFX_MAE_MV_DESC(ENC_VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
561         EFX_MAE_MV_DESC(ENC_VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
562         EFX_MAE_MV_DESC(ENC_VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
563         EFX_MAE_MV_DESC_ALT(ENC_SRC_IP4_BE, ENC_SRC_IP6_BE, EFX_MAE_FIELD_BE),
564         EFX_MAE_MV_DESC_ALT(ENC_DST_IP4_BE, ENC_DST_IP6_BE, EFX_MAE_FIELD_BE),
565         EFX_MAE_MV_DESC(ENC_IP_PROTO, EFX_MAE_FIELD_BE),
566         EFX_MAE_MV_DESC(ENC_IP_TOS, EFX_MAE_FIELD_BE),
567         EFX_MAE_MV_DESC(ENC_IP_TTL, EFX_MAE_FIELD_BE),
568         EFX_MAE_MV_DESC_ALT(ENC_SRC_IP6_BE, ENC_SRC_IP4_BE, EFX_MAE_FIELD_BE),
569         EFX_MAE_MV_DESC_ALT(ENC_DST_IP6_BE, ENC_DST_IP4_BE, EFX_MAE_FIELD_BE),
570         EFX_MAE_MV_DESC(ENC_L4_SPORT_BE, EFX_MAE_FIELD_BE),
571         EFX_MAE_MV_DESC(ENC_L4_DPORT_BE, EFX_MAE_FIELD_BE),
572
573 #undef EFX_MAE_MV_DESC_ALT
574 #undef EFX_MAE_MV_DESC
575 };
576
577         __checkReturn                   efx_rc_t
578 efx_mae_mport_by_phy_port(
579         __in                            uint32_t phy_port,
580         __out                           efx_mport_sel_t *mportp)
581 {
582         efx_dword_t dword;
583         efx_rc_t rc;
584
585         if (phy_port > EFX_MASK32(MAE_MPORT_SELECTOR_PPORT_ID)) {
586                 rc = EINVAL;
587                 goto fail1;
588         }
589
590         EFX_POPULATE_DWORD_2(dword,
591             MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT,
592             MAE_MPORT_SELECTOR_PPORT_ID, phy_port);
593
594         memset(mportp, 0, sizeof (*mportp));
595         /*
596          * The constructed DWORD is little-endian,
597          * but the resulting value is meant to be
598          * passed to MCDIs, where it will undergo
599          * host-order to little endian conversion.
600          */
601         mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
602
603         return (0);
604
605 fail1:
606         EFSYS_PROBE1(fail1, efx_rc_t, rc);
607         return (rc);
608 }
609
610         __checkReturn                   efx_rc_t
611 efx_mae_mport_by_pcie_function(
612         __in                            uint32_t pf,
613         __in                            uint32_t vf,
614         __out                           efx_mport_sel_t *mportp)
615 {
616         efx_dword_t dword;
617         efx_rc_t rc;
618
619         EFX_STATIC_ASSERT(EFX_PCI_VF_INVALID ==
620             MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL);
621
622         if (pf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_PF_ID)) {
623                 rc = EINVAL;
624                 goto fail1;
625         }
626
627         if (vf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_VF_ID)) {
628                 rc = EINVAL;
629                 goto fail2;
630         }
631
632         EFX_POPULATE_DWORD_3(dword,
633             MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
634             MAE_MPORT_SELECTOR_FUNC_PF_ID, pf,
635             MAE_MPORT_SELECTOR_FUNC_VF_ID, vf);
636
637         memset(mportp, 0, sizeof (*mportp));
638         /*
639          * The constructed DWORD is little-endian,
640          * but the resulting value is meant to be
641          * passed to MCDIs, where it will undergo
642          * host-order to little endian conversion.
643          */
644         mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
645
646         return (0);
647
648 fail2:
649         EFSYS_PROBE(fail2);
650 fail1:
651         EFSYS_PROBE1(fail1, efx_rc_t, rc);
652         return (rc);
653 }
654
655         __checkReturn                   efx_rc_t
656 efx_mae_match_spec_field_set(
657         __in                            efx_mae_match_spec_t *spec,
658         __in                            efx_mae_field_id_t field_id,
659         __in                            size_t value_size,
660         __in_bcount(value_size)         const uint8_t *value,
661         __in                            size_t mask_size,
662         __in_bcount(mask_size)          const uint8_t *mask)
663 {
664         const efx_mae_mv_desc_t *descp;
665         unsigned int desc_set_nentries;
666         uint8_t *mvp;
667         efx_rc_t rc;
668
669         switch (spec->emms_type) {
670         case EFX_MAE_RULE_OUTER:
671                 desc_set_nentries =
672                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
673                 descp = &__efx_mae_outer_rule_mv_desc_set[field_id];
674                 mvp = spec->emms_mask_value_pairs.outer;
675                 break;
676         case EFX_MAE_RULE_ACTION:
677                 desc_set_nentries =
678                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
679                 descp = &__efx_mae_action_rule_mv_desc_set[field_id];
680                 mvp = spec->emms_mask_value_pairs.action;
681                 break;
682         default:
683                 rc = ENOTSUP;
684                 goto fail1;
685         }
686
687         if ((unsigned int)field_id >= desc_set_nentries) {
688                 rc = EINVAL;
689                 goto fail2;
690         }
691
692         if (descp->emmd_mask_size == 0) {
693                 /* The ID points to a gap in the array of field descriptors. */
694                 rc = EINVAL;
695                 goto fail3;
696         }
697
698         if (value_size != descp->emmd_value_size) {
699                 rc = EINVAL;
700                 goto fail4;
701         }
702
703         if (mask_size != descp->emmd_mask_size) {
704                 rc = EINVAL;
705                 goto fail5;
706         }
707
708         if (descp->emmd_endianness == EFX_MAE_FIELD_BE) {
709                 unsigned int i;
710
711                 /*
712                  * The mask/value are in network (big endian) order.
713                  * The MCDI request field is also big endian.
714                  */
715
716                 EFSYS_ASSERT3U(value_size, ==, mask_size);
717
718                 for (i = 0; i < value_size; ++i) {
719                         uint8_t *v_bytep = mvp + descp->emmd_value_offset + i;
720                         uint8_t *m_bytep = mvp + descp->emmd_mask_offset + i;
721
722                         /*
723                          * Apply the mask (which may be all-zeros) to the value.
724                          *
725                          * If this API is provided with some value to set for a
726                          * given field in one specification and with some other
727                          * value to set for this field in another specification,
728                          * then, if the two masks are all-zeros, the field will
729                          * avoid being counted as a mismatch when comparing the
730                          * specifications using efx_mae_match_specs_equal() API.
731                          */
732                         *v_bytep = value[i] & mask[i];
733                         *m_bytep = mask[i];
734                 }
735         } else {
736                 efx_dword_t dword;
737
738                 /*
739                  * The mask/value are in host byte order.
740                  * The MCDI request field is little endian.
741                  */
742                 switch (value_size) {
743                 case 4:
744                         EFX_POPULATE_DWORD_1(dword,
745                             EFX_DWORD_0, *(const uint32_t *)value);
746
747                         memcpy(mvp + descp->emmd_value_offset,
748                             &dword, sizeof (dword));
749                         break;
750                 default:
751                         EFSYS_ASSERT(B_FALSE);
752                 }
753
754                 switch (mask_size) {
755                 case 4:
756                         EFX_POPULATE_DWORD_1(dword,
757                             EFX_DWORD_0, *(const uint32_t *)mask);
758
759                         memcpy(mvp + descp->emmd_mask_offset,
760                             &dword, sizeof (dword));
761                         break;
762                 default:
763                         EFSYS_ASSERT(B_FALSE);
764                 }
765         }
766
767         return (0);
768
769 fail5:
770         EFSYS_PROBE(fail5);
771 fail4:
772         EFSYS_PROBE(fail4);
773 fail3:
774         EFSYS_PROBE(fail3);
775 fail2:
776         EFSYS_PROBE(fail2);
777 fail1:
778         EFSYS_PROBE1(fail1, efx_rc_t, rc);
779         return (rc);
780 }
781
782         __checkReturn                   efx_rc_t
783 efx_mae_match_spec_mport_set(
784         __in                            efx_mae_match_spec_t *spec,
785         __in                            const efx_mport_sel_t *valuep,
786         __in_opt                        const efx_mport_sel_t *maskp)
787 {
788         uint32_t full_mask = UINT32_MAX;
789         const uint8_t *vp;
790         const uint8_t *mp;
791         efx_rc_t rc;
792
793         if (valuep == NULL) {
794                 rc = EINVAL;
795                 goto fail1;
796         }
797
798         vp = (const uint8_t *)&valuep->sel;
799         if (maskp != NULL)
800                 mp = (const uint8_t *)&maskp->sel;
801         else
802                 mp = (const uint8_t *)&full_mask;
803
804         rc = efx_mae_match_spec_field_set(spec,
805             EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR,
806             sizeof (valuep->sel), vp, sizeof (maskp->sel), mp);
807         if (rc != 0)
808                 goto fail2;
809
810         return (0);
811
812 fail2:
813         EFSYS_PROBE(fail2);
814 fail1:
815         EFSYS_PROBE1(fail1, efx_rc_t, rc);
816         return (rc);
817 }
818
819         __checkReturn                   boolean_t
820 efx_mae_match_specs_equal(
821         __in                            const efx_mae_match_spec_t *left,
822         __in                            const efx_mae_match_spec_t *right)
823 {
824         return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
825 }
826
827 #define EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit)              \
828             ((_mask)[(_bit) / (_mask_page_nbits)] &                     \
829                     (1ULL << ((_bit) & ((_mask_page_nbits) - 1))))
830
831 static                                  boolean_t
832 efx_mask_is_prefix(
833         __in                            size_t mask_nbytes,
834         __in_bcount(mask_nbytes)        const uint8_t *maskp)
835 {
836         boolean_t prev_bit_is_set = B_TRUE;
837         unsigned int i;
838
839         for (i = 0; i < 8 * mask_nbytes; ++i) {
840                 boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i);
841
842                 if (!prev_bit_is_set && bit_is_set)
843                         return B_FALSE;
844
845                 prev_bit_is_set = bit_is_set;
846         }
847
848         return B_TRUE;
849 }
850
851 static                                  boolean_t
852 efx_mask_is_all_ones(
853         __in                            size_t mask_nbytes,
854         __in_bcount(mask_nbytes)        const uint8_t *maskp)
855 {
856         unsigned int i;
857         uint8_t t = ~0;
858
859         for (i = 0; i < mask_nbytes; ++i)
860                 t &= maskp[i];
861
862         return (t == (uint8_t)(~0));
863 }
864
865 static                                  boolean_t
866 efx_mask_is_all_zeros(
867         __in                            size_t mask_nbytes,
868         __in_bcount(mask_nbytes)        const uint8_t *maskp)
869 {
870         unsigned int i;
871         uint8_t t = 0;
872
873         for (i = 0; i < mask_nbytes; ++i)
874                 t |= maskp[i];
875
876         return (t == 0);
877 }
878
879         __checkReturn                   boolean_t
880 efx_mae_match_spec_is_valid(
881         __in                            efx_nic_t *enp,
882         __in                            const efx_mae_match_spec_t *spec)
883 {
884         efx_mae_t *maep = enp->en_maep;
885         unsigned int field_ncaps = maep->em_max_nfields;
886         const efx_mae_field_cap_t *field_caps;
887         const efx_mae_mv_desc_t *desc_setp;
888         unsigned int desc_set_nentries;
889         boolean_t is_valid = B_TRUE;
890         efx_mae_field_id_t field_id;
891         const uint8_t *mvp;
892
893         switch (spec->emms_type) {
894         case EFX_MAE_RULE_OUTER:
895                 field_caps = maep->em_outer_rule_field_caps;
896                 desc_setp = __efx_mae_outer_rule_mv_desc_set;
897                 desc_set_nentries =
898                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
899                 mvp = spec->emms_mask_value_pairs.outer;
900                 break;
901         case EFX_MAE_RULE_ACTION:
902                 field_caps = maep->em_action_rule_field_caps;
903                 desc_setp = __efx_mae_action_rule_mv_desc_set;
904                 desc_set_nentries =
905                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
906                 mvp = spec->emms_mask_value_pairs.action;
907                 break;
908         default:
909                 return (B_FALSE);
910         }
911
912         if (field_caps == NULL)
913                 return (B_FALSE);
914
915         for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
916              ++field_id) {
917                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
918                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
919                 const uint8_t *alt_m_buf = mvp + descp->emmd_alt_mask_offset;
920                 const uint8_t *m_buf = mvp + descp->emmd_mask_offset;
921                 size_t alt_m_size = descp->emmd_alt_mask_size;
922                 size_t m_size = descp->emmd_mask_size;
923
924                 if (m_size == 0)
925                         continue; /* Skip array gap */
926
927                 if ((unsigned int)field_cap_id >= field_ncaps) {
928                         /*
929                          * The FW has not reported capability status for
930                          * this field. Make sure that its mask is zeroed.
931                          */
932                         is_valid = efx_mask_is_all_zeros(m_size, m_buf);
933                         if (is_valid != B_FALSE)
934                                 continue;
935                         else
936                                 break;
937                 }
938
939                 switch (field_caps[field_cap_id].emfc_support) {
940                 case MAE_FIELD_SUPPORTED_MATCH_MASK:
941                         is_valid = B_TRUE;
942                         break;
943                 case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
944                         is_valid = efx_mask_is_prefix(m_size, m_buf);
945                         break;
946                 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
947                         is_valid = (efx_mask_is_all_ones(m_size, m_buf) ||
948                             efx_mask_is_all_zeros(m_size, m_buf));
949                         break;
950                 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
951                         is_valid = efx_mask_is_all_ones(m_size, m_buf);
952
953                         if ((is_valid == B_FALSE) && (alt_m_size != 0)) {
954                                 /*
955                                  * This field has an alternative one. The FW
956                                  * reports ALWAYS for both implying that one
957                                  * of them is required to have all-ones mask.
958                                  *
959                                  * The primary field's mask is incorrect; go
960                                  * on to check that of the alternative field.
961                                  */
962                                 is_valid = efx_mask_is_all_ones(alt_m_size,
963                                                                 alt_m_buf);
964                         }
965                         break;
966                 case MAE_FIELD_SUPPORTED_MATCH_NEVER:
967                 case MAE_FIELD_UNSUPPORTED:
968                 default:
969                         is_valid = efx_mask_is_all_zeros(m_size, m_buf);
970                         break;
971                 }
972
973                 if (is_valid == B_FALSE)
974                         break;
975         }
976
977         return (is_valid);
978 }
979
980         __checkReturn                   efx_rc_t
981 efx_mae_action_set_spec_init(
982         __in                            efx_nic_t *enp,
983         __out                           efx_mae_actions_t **specp)
984 {
985         efx_mae_actions_t *spec;
986         efx_rc_t rc;
987
988         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
989         if (spec == NULL) {
990                 rc = ENOMEM;
991                 goto fail1;
992         }
993
994         *specp = spec;
995
996         return (0);
997
998 fail1:
999         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1000         return (rc);
1001 }
1002
1003                                         void
1004 efx_mae_action_set_spec_fini(
1005         __in                            efx_nic_t *enp,
1006         __in                            efx_mae_actions_t *spec)
1007 {
1008         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
1009 }
1010
1011 static  __checkReturn                   efx_rc_t
1012 efx_mae_action_set_add_vlan_pop(
1013         __in                            efx_mae_actions_t *spec,
1014         __in                            size_t arg_size,
1015         __in_bcount(arg_size)           const uint8_t *arg)
1016 {
1017         efx_rc_t rc;
1018
1019         if (arg_size != 0) {
1020                 rc = EINVAL;
1021                 goto fail1;
1022         }
1023
1024         if (arg != NULL) {
1025                 rc = EINVAL;
1026                 goto fail2;
1027         }
1028
1029         if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) {
1030                 rc = ENOTSUP;
1031                 goto fail3;
1032         }
1033
1034         ++spec->ema_n_vlan_tags_to_pop;
1035
1036         return (0);
1037
1038 fail3:
1039         EFSYS_PROBE(fail3);
1040 fail2:
1041         EFSYS_PROBE(fail2);
1042 fail1:
1043         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1044         return (rc);
1045 }
1046
1047 static  __checkReturn                   efx_rc_t
1048 efx_mae_action_set_add_vlan_push(
1049         __in                            efx_mae_actions_t *spec,
1050         __in                            size_t arg_size,
1051         __in_bcount(arg_size)           const uint8_t *arg)
1052 {
1053         unsigned int n_tags = spec->ema_n_vlan_tags_to_push;
1054         efx_rc_t rc;
1055
1056         if (arg_size != sizeof (*spec->ema_vlan_push_descs)) {
1057                 rc = EINVAL;
1058                 goto fail1;
1059         }
1060
1061         if (arg == NULL) {
1062                 rc = EINVAL;
1063                 goto fail2;
1064         }
1065
1066         if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1067                 rc = ENOTSUP;
1068                 goto fail3;
1069         }
1070
1071         memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size);
1072         ++(spec->ema_n_vlan_tags_to_push);
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_flag(
1087         __in                            efx_mae_actions_t *spec,
1088         __in                            size_t arg_size,
1089         __in_bcount(arg_size)           const uint8_t *arg)
1090 {
1091         efx_rc_t rc;
1092
1093         _NOTE(ARGUNUSED(spec))
1094
1095         if (arg_size != 0) {
1096                 rc = EINVAL;
1097                 goto fail1;
1098         }
1099
1100         if (arg != NULL) {
1101                 rc = EINVAL;
1102                 goto fail2;
1103         }
1104
1105         /* This action does not have any arguments, so do nothing here. */
1106
1107         return (0);
1108
1109 fail2:
1110         EFSYS_PROBE(fail2);
1111 fail1:
1112         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1113         return (rc);
1114 }
1115
1116 static  __checkReturn                   efx_rc_t
1117 efx_mae_action_set_add_mark(
1118         __in                            efx_mae_actions_t *spec,
1119         __in                            size_t arg_size,
1120         __in_bcount(arg_size)           const uint8_t *arg)
1121 {
1122         efx_rc_t rc;
1123
1124         if (arg_size != sizeof (spec->ema_mark_value)) {
1125                 rc = EINVAL;
1126                 goto fail1;
1127         }
1128
1129         if (arg == NULL) {
1130                 rc = EINVAL;
1131                 goto fail2;
1132         }
1133
1134         memcpy(&spec->ema_mark_value, arg, arg_size);
1135
1136         return (0);
1137
1138 fail2:
1139         EFSYS_PROBE(fail2);
1140 fail1:
1141         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1142         return (rc);
1143 }
1144
1145 static  __checkReturn                   efx_rc_t
1146 efx_mae_action_set_add_deliver(
1147         __in                            efx_mae_actions_t *spec,
1148         __in                            size_t arg_size,
1149         __in_bcount(arg_size)           const uint8_t *arg)
1150 {
1151         efx_rc_t rc;
1152
1153         if (arg_size != sizeof (spec->ema_deliver_mport)) {
1154                 rc = EINVAL;
1155                 goto fail1;
1156         }
1157
1158         if (arg == NULL) {
1159                 rc = EINVAL;
1160                 goto fail2;
1161         }
1162
1163         memcpy(&spec->ema_deliver_mport, arg, arg_size);
1164
1165         return (0);
1166
1167 fail2:
1168         EFSYS_PROBE(fail2);
1169 fail1:
1170         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1171         return (rc);
1172 }
1173
1174 typedef struct efx_mae_action_desc_s {
1175         /* Action specific handler */
1176         efx_rc_t        (*emad_add)(efx_mae_actions_t *,
1177                                     size_t, const uint8_t *);
1178 } efx_mae_action_desc_t;
1179
1180 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
1181         [EFX_MAE_ACTION_VLAN_POP] = {
1182                 .emad_add = efx_mae_action_set_add_vlan_pop
1183         },
1184         [EFX_MAE_ACTION_VLAN_PUSH] = {
1185                 .emad_add = efx_mae_action_set_add_vlan_push
1186         },
1187         [EFX_MAE_ACTION_FLAG] = {
1188                 .emad_add = efx_mae_action_set_add_flag
1189         },
1190         [EFX_MAE_ACTION_MARK] = {
1191                 .emad_add = efx_mae_action_set_add_mark
1192         },
1193         [EFX_MAE_ACTION_DELIVER] = {
1194                 .emad_add = efx_mae_action_set_add_deliver
1195         }
1196 };
1197
1198 static const uint32_t efx_mae_action_ordered_map =
1199         (1U << EFX_MAE_ACTION_VLAN_POP) |
1200         (1U << EFX_MAE_ACTION_VLAN_PUSH) |
1201         (1U << EFX_MAE_ACTION_FLAG) |
1202         (1U << EFX_MAE_ACTION_MARK) |
1203         (1U << EFX_MAE_ACTION_DELIVER);
1204
1205 /*
1206  * These actions must not be added after DELIVER, but
1207  * they can have any place among the rest of
1208  * strictly ordered actions.
1209  */
1210 static const uint32_t efx_mae_action_nonstrict_map =
1211         (1U << EFX_MAE_ACTION_FLAG) |
1212         (1U << EFX_MAE_ACTION_MARK);
1213
1214 static const uint32_t efx_mae_action_repeat_map =
1215         (1U << EFX_MAE_ACTION_VLAN_POP) |
1216         (1U << EFX_MAE_ACTION_VLAN_PUSH);
1217
1218 /*
1219  * Add an action to an action set.
1220  *
1221  * This has to be invoked in the desired action order.
1222  * An out-of-order action request will be turned down.
1223  */
1224 static  __checkReturn                   efx_rc_t
1225 efx_mae_action_set_spec_populate(
1226         __in                            efx_mae_actions_t *spec,
1227         __in                            efx_mae_action_t type,
1228         __in                            size_t arg_size,
1229         __in_bcount(arg_size)           const uint8_t *arg)
1230 {
1231         uint32_t action_mask;
1232         efx_rc_t rc;
1233
1234         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1235             (sizeof (efx_mae_action_ordered_map) * 8));
1236         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1237             (sizeof (efx_mae_action_repeat_map) * 8));
1238
1239         EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
1240         EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK);
1241         EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER);
1242
1243         if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
1244                 rc = EINVAL;
1245                 goto fail1;
1246         }
1247
1248         action_mask = (1U << type);
1249
1250         if ((spec->ema_actions & action_mask) != 0) {
1251                 /* The action set already contains this action. */
1252                 if ((efx_mae_action_repeat_map & action_mask) == 0) {
1253                         /* Cannot add another non-repeatable action. */
1254                         rc = ENOTSUP;
1255                         goto fail2;
1256                 }
1257         }
1258
1259         if ((efx_mae_action_ordered_map & action_mask) != 0) {
1260                 uint32_t strict_ordered_map =
1261                     efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map;
1262                 uint32_t later_actions_mask =
1263                     strict_ordered_map & ~(action_mask | (action_mask - 1));
1264
1265                 if ((spec->ema_actions & later_actions_mask) != 0) {
1266                         /* Cannot add an action after later ordered actions. */
1267                         rc = ENOTSUP;
1268                         goto fail3;
1269                 }
1270         }
1271
1272         if (efx_mae_actions[type].emad_add != NULL) {
1273                 rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
1274                 if (rc != 0)
1275                         goto fail4;
1276         }
1277
1278         spec->ema_actions |= action_mask;
1279
1280         return (0);
1281
1282 fail4:
1283         EFSYS_PROBE(fail4);
1284 fail3:
1285         EFSYS_PROBE(fail3);
1286 fail2:
1287         EFSYS_PROBE(fail2);
1288 fail1:
1289         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1290         return (rc);
1291 }
1292
1293         __checkReturn                   efx_rc_t
1294 efx_mae_action_set_populate_vlan_pop(
1295         __in                            efx_mae_actions_t *spec)
1296 {
1297         return (efx_mae_action_set_spec_populate(spec,
1298             EFX_MAE_ACTION_VLAN_POP, 0, NULL));
1299 }
1300
1301         __checkReturn                   efx_rc_t
1302 efx_mae_action_set_populate_vlan_push(
1303         __in                            efx_mae_actions_t *spec,
1304         __in                            uint16_t tpid_be,
1305         __in                            uint16_t tci_be)
1306 {
1307         efx_mae_action_vlan_push_t action;
1308         const uint8_t *arg = (const uint8_t *)&action;
1309
1310         action.emavp_tpid_be = tpid_be;
1311         action.emavp_tci_be = tci_be;
1312
1313         return (efx_mae_action_set_spec_populate(spec,
1314             EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg));
1315 }
1316
1317         __checkReturn                   efx_rc_t
1318 efx_mae_action_set_populate_flag(
1319         __in                            efx_mae_actions_t *spec)
1320 {
1321         return (efx_mae_action_set_spec_populate(spec,
1322             EFX_MAE_ACTION_FLAG, 0, NULL));
1323 }
1324
1325         __checkReturn                   efx_rc_t
1326 efx_mae_action_set_populate_mark(
1327         __in                            efx_mae_actions_t *spec,
1328         __in                            uint32_t mark_value)
1329 {
1330         const uint8_t *arg = (const uint8_t *)&mark_value;
1331
1332         return (efx_mae_action_set_spec_populate(spec,
1333             EFX_MAE_ACTION_MARK, sizeof (mark_value), arg));
1334 }
1335
1336         __checkReturn                   efx_rc_t
1337 efx_mae_action_set_populate_deliver(
1338         __in                            efx_mae_actions_t *spec,
1339         __in                            const efx_mport_sel_t *mportp)
1340 {
1341         const uint8_t *arg;
1342         efx_rc_t rc;
1343
1344         if (mportp == NULL) {
1345                 rc = EINVAL;
1346                 goto fail1;
1347         }
1348
1349         arg = (const uint8_t *)&mportp->sel;
1350
1351         return (efx_mae_action_set_spec_populate(spec,
1352             EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
1353
1354 fail1:
1355         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1356         return (rc);
1357 }
1358
1359         __checkReturn                   efx_rc_t
1360 efx_mae_action_set_populate_drop(
1361         __in                            efx_mae_actions_t *spec)
1362 {
1363         efx_mport_sel_t mport;
1364         const uint8_t *arg;
1365         efx_dword_t dword;
1366
1367         EFX_POPULATE_DWORD_1(dword,
1368             MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL);
1369
1370         /*
1371          * The constructed DWORD is little-endian,
1372          * but the resulting value is meant to be
1373          * passed to MCDIs, where it will undergo
1374          * host-order to little endian conversion.
1375          */
1376         mport.sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
1377
1378         arg = (const uint8_t *)&mport.sel;
1379
1380         return (efx_mae_action_set_spec_populate(spec,
1381             EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg));
1382 }
1383
1384         __checkReturn                   boolean_t
1385 efx_mae_action_set_specs_equal(
1386         __in                            const efx_mae_actions_t *left,
1387         __in                            const efx_mae_actions_t *right)
1388 {
1389         return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
1390 }
1391
1392         __checkReturn                   efx_rc_t
1393 efx_mae_match_specs_class_cmp(
1394         __in                            efx_nic_t *enp,
1395         __in                            const efx_mae_match_spec_t *left,
1396         __in                            const efx_mae_match_spec_t *right,
1397         __out                           boolean_t *have_same_classp)
1398 {
1399         efx_mae_t *maep = enp->en_maep;
1400         unsigned int field_ncaps = maep->em_max_nfields;
1401         const efx_mae_field_cap_t *field_caps;
1402         const efx_mae_mv_desc_t *desc_setp;
1403         unsigned int desc_set_nentries;
1404         boolean_t have_same_class = B_TRUE;
1405         efx_mae_field_id_t field_id;
1406         const uint8_t *mvpl;
1407         const uint8_t *mvpr;
1408         efx_rc_t rc;
1409
1410         switch (left->emms_type) {
1411         case EFX_MAE_RULE_OUTER:
1412                 field_caps = maep->em_outer_rule_field_caps;
1413                 desc_setp = __efx_mae_outer_rule_mv_desc_set;
1414                 desc_set_nentries =
1415                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1416                 mvpl = left->emms_mask_value_pairs.outer;
1417                 mvpr = right->emms_mask_value_pairs.outer;
1418                 break;
1419         case EFX_MAE_RULE_ACTION:
1420                 field_caps = maep->em_action_rule_field_caps;
1421                 desc_setp = __efx_mae_action_rule_mv_desc_set;
1422                 desc_set_nentries =
1423                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1424                 mvpl = left->emms_mask_value_pairs.action;
1425                 mvpr = right->emms_mask_value_pairs.action;
1426                 break;
1427         default:
1428                 rc = ENOTSUP;
1429                 goto fail1;
1430         }
1431
1432         if (field_caps == NULL) {
1433                 rc = EAGAIN;
1434                 goto fail2;
1435         }
1436
1437         if (left->emms_type != right->emms_type ||
1438             left->emms_prio != right->emms_prio) {
1439                 /*
1440                  * Rules of different types can never map to the same class.
1441                  *
1442                  * The FW can support some set of match criteria for one
1443                  * priority and not support the very same set for
1444                  * another priority. Thus, two rules which have
1445                  * different priorities can never map to
1446                  * the same class.
1447                  */
1448                 *have_same_classp = B_FALSE;
1449                 return (0);
1450         }
1451
1452         for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1453              ++field_id) {
1454                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1455                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1456                 const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
1457                 const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
1458                 size_t mask_size = descp->emmd_mask_size;
1459                 const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
1460                 const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
1461                 size_t value_size = descp->emmd_value_size;
1462
1463                 if (mask_size == 0)
1464                         continue; /* Skip array gap */
1465
1466                 if ((unsigned int)field_cap_id >= field_ncaps) {
1467                         /*
1468                          * The FW has not reported capability status for this
1469                          * field. It's unknown whether any difference between
1470                          * the two masks / values affects the class. The only
1471                          * case when the class must be the same is when these
1472                          * mask-value pairs match. Otherwise, report mismatch.
1473                          */
1474                         if ((memcmp(lmaskp, rmaskp, mask_size) == 0) &&
1475                             (memcmp(lvalp, rvalp, value_size) == 0))
1476                                 continue;
1477                         else
1478                                 break;
1479                 }
1480
1481                 if (field_caps[field_cap_id].emfc_mask_affects_class) {
1482                         if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
1483                                 have_same_class = B_FALSE;
1484                                 break;
1485                         }
1486                 }
1487
1488                 if (field_caps[field_cap_id].emfc_match_affects_class) {
1489                         if (memcmp(lvalp, rvalp, value_size) != 0) {
1490                                 have_same_class = B_FALSE;
1491                                 break;
1492                         }
1493                 }
1494         }
1495
1496         *have_same_classp = have_same_class;
1497
1498         return (0);
1499
1500 fail2:
1501         EFSYS_PROBE(fail2);
1502 fail1:
1503         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1504         return (rc);
1505 }
1506
1507         __checkReturn           efx_rc_t
1508 efx_mae_outer_rule_insert(
1509         __in                    efx_nic_t *enp,
1510         __in                    const efx_mae_match_spec_t *spec,
1511         __in                    efx_tunnel_protocol_t encap_type,
1512         __out                   efx_mae_rule_id_t *or_idp)
1513 {
1514         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1515         efx_mcdi_req_t req;
1516         EFX_MCDI_DECLARE_BUF(payload,
1517             MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2,
1518             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
1519         uint32_t encap_type_mcdi;
1520         efx_mae_rule_id_t or_id;
1521         size_t offset;
1522         efx_rc_t rc;
1523
1524         EFX_STATIC_ASSERT(sizeof (or_idp->id) ==
1525             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN);
1526
1527         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1528             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL);
1529
1530         if (encp->enc_mae_supported == B_FALSE) {
1531                 rc = ENOTSUP;
1532                 goto fail1;
1533         }
1534
1535         if (spec->emms_type != EFX_MAE_RULE_OUTER) {
1536                 rc = EINVAL;
1537                 goto fail2;
1538         }
1539
1540         switch (encap_type) {
1541         case EFX_TUNNEL_PROTOCOL_NONE:
1542                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
1543                 break;
1544         case EFX_TUNNEL_PROTOCOL_VXLAN:
1545                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
1546                 break;
1547         case EFX_TUNNEL_PROTOCOL_GENEVE:
1548                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
1549                 break;
1550         case EFX_TUNNEL_PROTOCOL_NVGRE:
1551                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
1552                 break;
1553         default:
1554                 rc = ENOTSUP;
1555                 goto fail3;
1556         }
1557
1558         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT;
1559         req.emr_in_buf = payload;
1560         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2;
1561         req.emr_out_buf = payload;
1562         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN;
1563
1564         MCDI_IN_SET_DWORD(req,
1565             MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi);
1566
1567         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio);
1568
1569         /*
1570          * Mask-value pairs have been stored in the byte order needed for the
1571          * MCDI request and are thus safe to be copied directly to the buffer.
1572          * The library cares about byte order in efx_mae_match_spec_field_set().
1573          */
1574         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >=
1575             MAE_ENC_FIELD_PAIRS_LEN);
1576         offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST;
1577         memcpy(payload + offset, spec->emms_mask_value_pairs.outer,
1578             MAE_ENC_FIELD_PAIRS_LEN);
1579
1580         efx_mcdi_execute(enp, &req);
1581
1582         if (req.emr_rc != 0) {
1583                 rc = req.emr_rc;
1584                 goto fail4;
1585         }
1586
1587         if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) {
1588                 rc = EMSGSIZE;
1589                 goto fail5;
1590         }
1591
1592         or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
1593         if (or_id.id == EFX_MAE_RSRC_ID_INVALID) {
1594                 rc = ENOENT;
1595                 goto fail6;
1596         }
1597
1598         or_idp->id = or_id.id;
1599
1600         return (0);
1601
1602 fail6:
1603         EFSYS_PROBE(fail6);
1604 fail5:
1605         EFSYS_PROBE(fail5);
1606 fail4:
1607         EFSYS_PROBE(fail4);
1608 fail3:
1609         EFSYS_PROBE(fail3);
1610 fail2:
1611         EFSYS_PROBE(fail2);
1612 fail1:
1613         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1614         return (rc);
1615 }
1616
1617         __checkReturn           efx_rc_t
1618 efx_mae_outer_rule_remove(
1619         __in                    efx_nic_t *enp,
1620         __in                    const efx_mae_rule_id_t *or_idp)
1621 {
1622         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1623         efx_mcdi_req_t req;
1624         EFX_MCDI_DECLARE_BUF(payload,
1625             MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1),
1626             MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
1627         efx_rc_t rc;
1628
1629         if (encp->enc_mae_supported == B_FALSE) {
1630                 rc = ENOTSUP;
1631                 goto fail1;
1632         }
1633
1634         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE;
1635         req.emr_in_buf = payload;
1636         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1);
1637         req.emr_out_buf = payload;
1638         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1);
1639
1640         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id);
1641
1642         efx_mcdi_execute(enp, &req);
1643
1644         if (req.emr_rc != 0) {
1645                 rc = req.emr_rc;
1646                 goto fail2;
1647         }
1648
1649         if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) !=
1650             or_idp->id) {
1651                 /* Firmware failed to remove the outer rule. */
1652                 rc = EAGAIN;
1653                 goto fail3;
1654         }
1655
1656         return (0);
1657
1658 fail3:
1659         EFSYS_PROBE(fail3);
1660 fail2:
1661         EFSYS_PROBE(fail2);
1662 fail1:
1663         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1664         return (rc);
1665 }
1666
1667         __checkReturn                   efx_rc_t
1668 efx_mae_match_spec_outer_rule_id_set(
1669         __in                            efx_mae_match_spec_t *spec,
1670         __in                            const efx_mae_rule_id_t *or_idp)
1671 {
1672         uint32_t full_mask = UINT32_MAX;
1673         efx_rc_t rc;
1674
1675         if (spec->emms_type != EFX_MAE_RULE_ACTION) {
1676                 rc = EINVAL;
1677                 goto fail1;
1678         }
1679
1680         if (or_idp == NULL) {
1681                 rc = EINVAL;
1682                 goto fail2;
1683         }
1684
1685         rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID,
1686             sizeof (or_idp->id), (const uint8_t *)&or_idp->id,
1687             sizeof (full_mask), (const uint8_t *)&full_mask);
1688         if (rc != 0)
1689                 goto fail3;
1690
1691         return (0);
1692
1693 fail3:
1694         EFSYS_PROBE(fail3);
1695 fail2:
1696         EFSYS_PROBE(fail2);
1697 fail1:
1698         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1699         return (rc);
1700 }
1701
1702         __checkReturn                   efx_rc_t
1703 efx_mae_action_set_alloc(
1704         __in                            efx_nic_t *enp,
1705         __in                            const efx_mae_actions_t *spec,
1706         __out                           efx_mae_aset_id_t *aset_idp)
1707 {
1708         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1709         efx_mcdi_req_t req;
1710         EFX_MCDI_DECLARE_BUF(payload,
1711             MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
1712             MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
1713         efx_mae_aset_id_t aset_id;
1714         efx_rc_t rc;
1715
1716         if (encp->enc_mae_supported == B_FALSE) {
1717                 rc = ENOTSUP;
1718                 goto fail1;
1719         }
1720
1721         req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
1722         req.emr_in_buf = payload;
1723         req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
1724         req.emr_out_buf = payload;
1725         req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
1726
1727         /*
1728          * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
1729          * corresponding resource types are supported by the implementation.
1730          * Use proper resource ID assignments instead.
1731          */
1732         MCDI_IN_SET_DWORD(req,
1733             MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
1734         MCDI_IN_SET_DWORD(req,
1735             MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
1736         MCDI_IN_SET_DWORD(req,
1737             MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, EFX_MAE_RSRC_ID_INVALID);
1738
1739         MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1740             MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
1741
1742         if (spec->ema_n_vlan_tags_to_push > 0) {
1743                 unsigned int outer_tag_idx;
1744
1745                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1746                     MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
1747                     spec->ema_n_vlan_tags_to_push);
1748
1749                 if (spec->ema_n_vlan_tags_to_push ==
1750                     EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1751                         MCDI_IN_SET_WORD(req,
1752                             MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
1753                             spec->ema_vlan_push_descs[0].emavp_tpid_be);
1754                         MCDI_IN_SET_WORD(req,
1755                             MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
1756                             spec->ema_vlan_push_descs[0].emavp_tci_be);
1757                 }
1758
1759                 outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
1760
1761                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
1762                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
1763                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
1764                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
1765         }
1766
1767         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
1768                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1769                     MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
1770         }
1771
1772         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
1773                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1774                     MAE_ACTION_SET_ALLOC_IN_MARK, 1);
1775
1776                 MCDI_IN_SET_DWORD(req,
1777                     MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
1778         }
1779
1780         MCDI_IN_SET_DWORD(req,
1781             MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
1782
1783         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
1784             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
1785         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
1786             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
1787
1788         efx_mcdi_execute(enp, &req);
1789
1790         if (req.emr_rc != 0) {
1791                 rc = req.emr_rc;
1792                 goto fail2;
1793         }
1794
1795         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
1796                 rc = EMSGSIZE;
1797                 goto fail3;
1798         }
1799
1800         aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
1801         if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
1802                 rc = ENOENT;
1803                 goto fail4;
1804         }
1805
1806         aset_idp->id = aset_id.id;
1807
1808         return (0);
1809
1810 fail4:
1811         EFSYS_PROBE(fail4);
1812 fail3:
1813         EFSYS_PROBE(fail3);
1814 fail2:
1815         EFSYS_PROBE(fail2);
1816 fail1:
1817         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1818         return (rc);
1819 }
1820
1821         __checkReturn                   efx_rc_t
1822 efx_mae_action_set_free(
1823         __in                            efx_nic_t *enp,
1824         __in                            const efx_mae_aset_id_t *aset_idp)
1825 {
1826         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1827         efx_mcdi_req_t req;
1828         EFX_MCDI_DECLARE_BUF(payload,
1829             MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
1830             MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
1831         efx_rc_t rc;
1832
1833         if (encp->enc_mae_supported == B_FALSE) {
1834                 rc = ENOTSUP;
1835                 goto fail1;
1836         }
1837
1838         req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
1839         req.emr_in_buf = payload;
1840         req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
1841         req.emr_out_buf = payload;
1842         req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
1843
1844         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
1845
1846         efx_mcdi_execute(enp, &req);
1847
1848         if (req.emr_rc != 0) {
1849                 rc = req.emr_rc;
1850                 goto fail2;
1851         }
1852
1853         if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
1854             aset_idp->id) {
1855                 /* Firmware failed to free the action set. */
1856                 rc = EAGAIN;
1857                 goto fail3;
1858         }
1859
1860         return (0);
1861
1862 fail3:
1863         EFSYS_PROBE(fail3);
1864 fail2:
1865         EFSYS_PROBE(fail2);
1866 fail1:
1867         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1868         return (rc);
1869 }
1870
1871         __checkReturn                   efx_rc_t
1872 efx_mae_action_rule_insert(
1873         __in                            efx_nic_t *enp,
1874         __in                            const efx_mae_match_spec_t *spec,
1875         __in                            const efx_mae_aset_list_id_t *asl_idp,
1876         __in                            const efx_mae_aset_id_t *as_idp,
1877         __out                           efx_mae_rule_id_t *ar_idp)
1878 {
1879         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1880         efx_mcdi_req_t req;
1881         EFX_MCDI_DECLARE_BUF(payload,
1882             MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2,
1883             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
1884         efx_oword_t *rule_response;
1885         efx_mae_rule_id_t ar_id;
1886         size_t offset;
1887         efx_rc_t rc;
1888
1889         EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
1890             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
1891
1892         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1893             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
1894
1895         if (encp->enc_mae_supported == B_FALSE) {
1896                 rc = ENOTSUP;
1897                 goto fail1;
1898         }
1899
1900         if (spec->emms_type != EFX_MAE_RULE_ACTION ||
1901             (asl_idp != NULL && as_idp != NULL) ||
1902             (asl_idp == NULL && as_idp == NULL)) {
1903                 rc = EINVAL;
1904                 goto fail2;
1905         }
1906
1907         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
1908         req.emr_in_buf = payload;
1909         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
1910         req.emr_out_buf = payload;
1911         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
1912
1913         EFX_STATIC_ASSERT(sizeof (*rule_response) <=
1914             MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
1915         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
1916         rule_response = (efx_oword_t *)(payload + offset);
1917         EFX_POPULATE_OWORD_3(*rule_response,
1918             MAE_ACTION_RULE_RESPONSE_ASL_ID,
1919             (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
1920             MAE_ACTION_RULE_RESPONSE_AS_ID,
1921             (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
1922             MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
1923
1924         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
1925
1926         /*
1927          * Mask-value pairs have been stored in the byte order needed for the
1928          * MCDI request and are thus safe to be copied directly to the buffer.
1929          */
1930         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
1931             MAE_FIELD_MASK_VALUE_PAIRS_LEN);
1932         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
1933         memcpy(payload + offset, spec->emms_mask_value_pairs.action,
1934             MAE_FIELD_MASK_VALUE_PAIRS_LEN);
1935
1936         efx_mcdi_execute(enp, &req);
1937
1938         if (req.emr_rc != 0) {
1939                 rc = req.emr_rc;
1940                 goto fail3;
1941         }
1942
1943         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
1944                 rc = EMSGSIZE;
1945                 goto fail4;
1946         }
1947
1948         ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
1949         if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
1950                 rc = ENOENT;
1951                 goto fail5;
1952         }
1953
1954         ar_idp->id = ar_id.id;
1955
1956         return (0);
1957
1958 fail5:
1959         EFSYS_PROBE(fail5);
1960 fail4:
1961         EFSYS_PROBE(fail4);
1962 fail3:
1963         EFSYS_PROBE(fail3);
1964 fail2:
1965         EFSYS_PROBE(fail2);
1966 fail1:
1967         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1968         return (rc);
1969 }
1970
1971         __checkReturn                   efx_rc_t
1972 efx_mae_action_rule_remove(
1973         __in                            efx_nic_t *enp,
1974         __in                            const efx_mae_rule_id_t *ar_idp)
1975 {
1976         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1977         efx_mcdi_req_t req;
1978         EFX_MCDI_DECLARE_BUF(payload,
1979             MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
1980             MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
1981         efx_rc_t rc;
1982
1983         if (encp->enc_mae_supported == B_FALSE) {
1984                 rc = ENOTSUP;
1985                 goto fail1;
1986         }
1987
1988         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
1989         req.emr_in_buf = payload;
1990         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
1991         req.emr_out_buf = payload;
1992         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
1993
1994         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
1995
1996         efx_mcdi_execute(enp, &req);
1997
1998         if (req.emr_rc != 0) {
1999                 rc = req.emr_rc;
2000                 goto fail2;
2001         }
2002
2003         if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
2004             ar_idp->id) {
2005                 /* Firmware failed to delete the action rule. */
2006                 rc = EAGAIN;
2007                 goto fail3;
2008         }
2009
2010         return (0);
2011
2012 fail3:
2013         EFSYS_PROBE(fail3);
2014 fail2:
2015         EFSYS_PROBE(fail2);
2016 fail1:
2017         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2018         return (rc);
2019 }
2020
2021 #endif /* EFSYS_OPT_MAE */