common/sfc_efx/base: indicate MAE support for encapsulation
[dpdk.git] / drivers / common / sfc_efx / base / efx_mae.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2019 Xilinx, Inc. All rights reserved.
4  * All rights reserved.
5  */
6
7 #include "efx.h"
8 #include "efx_impl.h"
9
10
11 #if EFSYS_OPT_MAE
12
13 static  __checkReturn                   efx_rc_t
14 efx_mae_get_capabilities(
15         __in                            efx_nic_t *enp)
16 {
17         efx_mcdi_req_t req;
18         EFX_MCDI_DECLARE_BUF(payload,
19             MC_CMD_MAE_GET_CAPS_IN_LEN,
20             MC_CMD_MAE_GET_CAPS_OUT_LEN);
21         struct efx_mae_s *maep = enp->en_maep;
22         efx_rc_t rc;
23
24         req.emr_cmd = MC_CMD_MAE_GET_CAPS;
25         req.emr_in_buf = payload;
26         req.emr_in_length = MC_CMD_MAE_GET_CAPS_IN_LEN;
27         req.emr_out_buf = payload;
28         req.emr_out_length = MC_CMD_MAE_GET_CAPS_OUT_LEN;
29
30         efx_mcdi_execute(enp, &req);
31
32         if (req.emr_rc != 0) {
33                 rc = req.emr_rc;
34                 goto fail1;
35         }
36
37         if (req.emr_out_length_used < MC_CMD_MAE_GET_CAPS_OUT_LEN) {
38                 rc = EMSGSIZE;
39                 goto fail2;
40         }
41
42         maep->em_max_n_outer_prios =
43             MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_OUTER_PRIOS);
44
45         maep->em_max_n_action_prios =
46             MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ACTION_PRIOS);
47
48         maep->em_encap_types_supported = 0;
49
50         if (MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ENCAP_TYPE_VXLAN) == 1) {
51                 maep->em_encap_types_supported |=
52                     (1U << EFX_TUNNEL_PROTOCOL_VXLAN);
53         }
54
55         if (MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ENCAP_TYPE_GENEVE) == 1) {
56                 maep->em_encap_types_supported |=
57                     (1U << EFX_TUNNEL_PROTOCOL_GENEVE);
58         }
59
60         if (MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ENCAP_TYPE_NVGRE) == 1) {
61                 maep->em_encap_types_supported |=
62                     (1U << EFX_TUNNEL_PROTOCOL_NVGRE);
63         }
64
65         maep->em_max_nfields =
66             MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT);
67
68         return (0);
69
70 fail2:
71         EFSYS_PROBE(fail2);
72 fail1:
73         EFSYS_PROBE1(fail1, efx_rc_t, rc);
74         return (rc);
75 }
76
77 static  __checkReturn                   efx_rc_t
78 efx_mae_get_action_rule_caps(
79         __in                            efx_nic_t *enp,
80         __in                            unsigned int field_ncaps,
81         __out_ecount(field_ncaps)       efx_mae_field_cap_t *field_caps)
82 {
83         efx_mcdi_req_t req;
84         EFX_MCDI_DECLARE_BUF(payload,
85             MC_CMD_MAE_GET_AR_CAPS_IN_LEN,
86             MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2);
87         unsigned int mcdi_field_ncaps;
88         unsigned int i;
89         efx_rc_t rc;
90
91         if (MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps) >
92             MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2) {
93                 rc = EINVAL;
94                 goto fail1;
95         }
96
97         req.emr_cmd = MC_CMD_MAE_GET_AR_CAPS;
98         req.emr_in_buf = payload;
99         req.emr_in_length = MC_CMD_MAE_GET_AR_CAPS_IN_LEN;
100         req.emr_out_buf = payload;
101         req.emr_out_length = MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps);
102
103         efx_mcdi_execute(enp, &req);
104
105         if (req.emr_rc != 0) {
106                 rc = req.emr_rc;
107                 goto fail2;
108         }
109
110         mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_OR_CAPS_OUT_COUNT);
111
112         if (req.emr_out_length_used <
113             MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(mcdi_field_ncaps)) {
114                 rc = EMSGSIZE;
115                 goto fail3;
116         }
117
118         if (mcdi_field_ncaps > field_ncaps) {
119                 rc = EMSGSIZE;
120                 goto fail4;
121         }
122
123         for (i = 0; i < mcdi_field_ncaps; ++i) {
124                 uint32_t match_flag;
125                 uint32_t mask_flag;
126
127                 field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req,
128                     MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
129                     MAE_FIELD_FLAGS_SUPPORT_STATUS);
130
131                 match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
132                     MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
133                     MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS);
134
135                 field_caps[i].emfc_match_affects_class =
136                     (match_flag != 0) ? B_TRUE : B_FALSE;
137
138                 mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
139                     MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
140                     MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS);
141
142                 field_caps[i].emfc_mask_affects_class =
143                     (mask_flag != 0) ? B_TRUE : B_FALSE;
144         }
145
146         return (0);
147
148 fail4:
149         EFSYS_PROBE(fail4);
150 fail3:
151         EFSYS_PROBE(fail3);
152 fail2:
153         EFSYS_PROBE(fail2);
154 fail1:
155         EFSYS_PROBE1(fail1, efx_rc_t, rc);
156         return (rc);
157 }
158
159         __checkReturn                   efx_rc_t
160 efx_mae_init(
161         __in                            efx_nic_t *enp)
162 {
163         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
164         efx_mae_field_cap_t *ar_fcaps;
165         size_t ar_fcaps_size;
166         efx_mae_t *maep;
167         efx_rc_t rc;
168
169         if (encp->enc_mae_supported == B_FALSE) {
170                 rc = ENOTSUP;
171                 goto fail1;
172         }
173
174         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*maep), maep);
175         if (maep == NULL) {
176                 rc = ENOMEM;
177                 goto fail2;
178         }
179
180         enp->en_maep = maep;
181
182         rc = efx_mae_get_capabilities(enp);
183         if (rc != 0)
184                 goto fail3;
185
186         ar_fcaps_size = maep->em_max_nfields * sizeof (*ar_fcaps);
187         EFSYS_KMEM_ALLOC(enp->en_esip, ar_fcaps_size, ar_fcaps);
188         if (ar_fcaps == NULL) {
189                 rc = ENOMEM;
190                 goto fail4;
191         }
192
193         maep->em_action_rule_field_caps_size = ar_fcaps_size;
194         maep->em_action_rule_field_caps = ar_fcaps;
195
196         rc = efx_mae_get_action_rule_caps(enp, maep->em_max_nfields, ar_fcaps);
197         if (rc != 0)
198                 goto fail5;
199
200         return (0);
201
202 fail5:
203         EFSYS_PROBE(fail5);
204         EFSYS_KMEM_FREE(enp->en_esip, ar_fcaps_size, ar_fcaps);
205 fail4:
206         EFSYS_PROBE(fail4);
207 fail3:
208         EFSYS_PROBE(fail3);
209         EFSYS_KMEM_FREE(enp->en_esip, sizeof (struct efx_mae_s), enp->en_maep);
210         enp->en_maep = NULL;
211 fail2:
212         EFSYS_PROBE(fail2);
213 fail1:
214         EFSYS_PROBE1(fail1, efx_rc_t, rc);
215         return (rc);
216 }
217
218                                         void
219 efx_mae_fini(
220         __in                            efx_nic_t *enp)
221 {
222         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
223         efx_mae_t *maep = enp->en_maep;
224
225         if (encp->enc_mae_supported == B_FALSE)
226                 return;
227
228         EFSYS_KMEM_FREE(enp->en_esip, maep->em_action_rule_field_caps_size,
229             maep->em_action_rule_field_caps);
230         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*maep), maep);
231         enp->en_maep = NULL;
232 }
233
234         __checkReturn                   efx_rc_t
235 efx_mae_get_limits(
236         __in                            efx_nic_t *enp,
237         __out                           efx_mae_limits_t *emlp)
238 {
239         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
240         struct efx_mae_s *maep = enp->en_maep;
241         efx_rc_t rc;
242
243         if (encp->enc_mae_supported == B_FALSE) {
244                 rc = ENOTSUP;
245                 goto fail1;
246         }
247
248         emlp->eml_max_n_outer_prios = maep->em_max_n_outer_prios;
249         emlp->eml_max_n_action_prios = maep->em_max_n_action_prios;
250         emlp->eml_encap_types_supported = maep->em_encap_types_supported;
251
252         return (0);
253
254 fail1:
255         EFSYS_PROBE1(fail1, efx_rc_t, rc);
256         return (rc);
257 }
258
259         __checkReturn                   efx_rc_t
260 efx_mae_match_spec_init(
261         __in                            efx_nic_t *enp,
262         __in                            efx_mae_rule_type_t type,
263         __in                            uint32_t prio,
264         __out                           efx_mae_match_spec_t **specp)
265 {
266         efx_mae_match_spec_t *spec;
267         efx_rc_t rc;
268
269         switch (type) {
270         case EFX_MAE_RULE_ACTION:
271                 break;
272         default:
273                 rc = ENOTSUP;
274                 goto fail1;
275         }
276
277         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
278         if (spec == NULL) {
279                 rc = ENOMEM;
280                 goto fail2;
281         }
282
283         spec->emms_type = type;
284         spec->emms_prio = prio;
285
286         *specp = spec;
287
288         return (0);
289
290 fail2:
291         EFSYS_PROBE(fail2);
292 fail1:
293         EFSYS_PROBE1(fail1, efx_rc_t, rc);
294         return (rc);
295 }
296
297                                         void
298 efx_mae_match_spec_fini(
299         __in                            efx_nic_t *enp,
300         __in                            efx_mae_match_spec_t *spec)
301 {
302         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
303 }
304
305 /* Named identifiers which are valid indices to efx_mae_field_cap_t */
306 typedef enum efx_mae_field_cap_id_e {
307         EFX_MAE_FIELD_ID_INGRESS_MPORT_SELECTOR = MAE_FIELD_INGRESS_PORT,
308         EFX_MAE_FIELD_ID_ETHER_TYPE_BE = MAE_FIELD_ETHER_TYPE,
309         EFX_MAE_FIELD_ID_ETH_SADDR_BE = MAE_FIELD_ETH_SADDR,
310         EFX_MAE_FIELD_ID_ETH_DADDR_BE = MAE_FIELD_ETH_DADDR,
311         EFX_MAE_FIELD_ID_VLAN0_TCI_BE = MAE_FIELD_VLAN0_TCI,
312         EFX_MAE_FIELD_ID_VLAN0_PROTO_BE = MAE_FIELD_VLAN0_PROTO,
313         EFX_MAE_FIELD_ID_VLAN1_TCI_BE = MAE_FIELD_VLAN1_TCI,
314         EFX_MAE_FIELD_ID_VLAN1_PROTO_BE = MAE_FIELD_VLAN1_PROTO,
315         EFX_MAE_FIELD_ID_SRC_IP4_BE = MAE_FIELD_SRC_IP4,
316         EFX_MAE_FIELD_ID_DST_IP4_BE = MAE_FIELD_DST_IP4,
317         EFX_MAE_FIELD_ID_IP_PROTO = MAE_FIELD_IP_PROTO,
318         EFX_MAE_FIELD_ID_IP_TOS = MAE_FIELD_IP_TOS,
319         EFX_MAE_FIELD_ID_IP_TTL = MAE_FIELD_IP_TTL,
320         EFX_MAE_FIELD_ID_SRC_IP6_BE = MAE_FIELD_SRC_IP6,
321         EFX_MAE_FIELD_ID_DST_IP6_BE = MAE_FIELD_DST_IP6,
322         EFX_MAE_FIELD_ID_L4_SPORT_BE = MAE_FIELD_L4_SPORT,
323         EFX_MAE_FIELD_ID_L4_DPORT_BE = MAE_FIELD_L4_DPORT,
324         EFX_MAE_FIELD_ID_TCP_FLAGS_BE = MAE_FIELD_TCP_FLAGS,
325
326         EFX_MAE_FIELD_CAP_NIDS
327 } efx_mae_field_cap_id_t;
328
329 typedef enum efx_mae_field_endianness_e {
330         EFX_MAE_FIELD_LE = 0,
331         EFX_MAE_FIELD_BE,
332
333         EFX_MAE_FIELD_ENDIANNESS_NTYPES
334 } efx_mae_field_endianness_t;
335
336 /*
337  * The following structure is a means to describe an MAE field.
338  * The information in it is meant to be used internally by
339  * APIs for addressing a given field in a mask-value pairs
340  * structure and for validation purposes.
341  */
342 typedef struct efx_mae_mv_desc_s {
343         efx_mae_field_cap_id_t          emmd_field_cap_id;
344
345         size_t                          emmd_value_size;
346         size_t                          emmd_value_offset;
347         size_t                          emmd_mask_size;
348         size_t                          emmd_mask_offset;
349
350         efx_mae_field_endianness_t      emmd_endianness;
351 } efx_mae_mv_desc_t;
352
353 /* Indices to this array are provided by efx_mae_field_id_t */
354 static const efx_mae_mv_desc_t __efx_mae_action_rule_mv_desc_set[] = {
355 #define EFX_MAE_MV_DESC(_name, _endianness)                             \
356         [EFX_MAE_FIELD_##_name] =                                       \
357         {                                                               \
358                 EFX_MAE_FIELD_ID_##_name,                               \
359                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_LEN,               \
360                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_OFST,              \
361                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_LEN,          \
362                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_OFST,         \
363                 _endianness                                             \
364         }
365
366         EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
367         EFX_MAE_MV_DESC(ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
368         EFX_MAE_MV_DESC(ETH_SADDR_BE, EFX_MAE_FIELD_BE),
369         EFX_MAE_MV_DESC(ETH_DADDR_BE, EFX_MAE_FIELD_BE),
370         EFX_MAE_MV_DESC(VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
371         EFX_MAE_MV_DESC(VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
372         EFX_MAE_MV_DESC(VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
373         EFX_MAE_MV_DESC(VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
374         EFX_MAE_MV_DESC(SRC_IP4_BE, EFX_MAE_FIELD_BE),
375         EFX_MAE_MV_DESC(DST_IP4_BE, EFX_MAE_FIELD_BE),
376         EFX_MAE_MV_DESC(IP_PROTO, EFX_MAE_FIELD_BE),
377         EFX_MAE_MV_DESC(IP_TOS, EFX_MAE_FIELD_BE),
378         EFX_MAE_MV_DESC(IP_TTL, EFX_MAE_FIELD_BE),
379         EFX_MAE_MV_DESC(SRC_IP6_BE, EFX_MAE_FIELD_BE),
380         EFX_MAE_MV_DESC(DST_IP6_BE, EFX_MAE_FIELD_BE),
381         EFX_MAE_MV_DESC(L4_SPORT_BE, EFX_MAE_FIELD_BE),
382         EFX_MAE_MV_DESC(L4_DPORT_BE, EFX_MAE_FIELD_BE),
383         EFX_MAE_MV_DESC(TCP_FLAGS_BE, EFX_MAE_FIELD_BE),
384
385 #undef EFX_MAE_MV_DESC
386 };
387
388         __checkReturn                   efx_rc_t
389 efx_mae_mport_by_phy_port(
390         __in                            uint32_t phy_port,
391         __out                           efx_mport_sel_t *mportp)
392 {
393         efx_dword_t dword;
394         efx_rc_t rc;
395
396         if (phy_port > EFX_MASK32(MAE_MPORT_SELECTOR_PPORT_ID)) {
397                 rc = EINVAL;
398                 goto fail1;
399         }
400
401         EFX_POPULATE_DWORD_2(dword,
402             MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT,
403             MAE_MPORT_SELECTOR_PPORT_ID, phy_port);
404
405         memset(mportp, 0, sizeof (*mportp));
406         mportp->sel = dword.ed_u32[0];
407
408         return (0);
409
410 fail1:
411         EFSYS_PROBE1(fail1, efx_rc_t, rc);
412         return (rc);
413 }
414
415         __checkReturn                   efx_rc_t
416 efx_mae_mport_by_pcie_function(
417         __in                            uint32_t pf,
418         __in                            uint32_t vf,
419         __out                           efx_mport_sel_t *mportp)
420 {
421         efx_dword_t dword;
422         efx_rc_t rc;
423
424         EFX_STATIC_ASSERT(EFX_PCI_VF_INVALID ==
425             MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL);
426
427         if (pf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_PF_ID)) {
428                 rc = EINVAL;
429                 goto fail1;
430         }
431
432         if (vf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_VF_ID)) {
433                 rc = EINVAL;
434                 goto fail2;
435         }
436
437         EFX_POPULATE_DWORD_3(dword,
438             MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
439             MAE_MPORT_SELECTOR_FUNC_PF_ID, pf,
440             MAE_MPORT_SELECTOR_FUNC_VF_ID, vf);
441
442         memset(mportp, 0, sizeof (*mportp));
443         mportp->sel = dword.ed_u32[0];
444
445         return (0);
446
447 fail2:
448         EFSYS_PROBE(fail2);
449 fail1:
450         EFSYS_PROBE1(fail1, efx_rc_t, rc);
451         return (rc);
452 }
453
454         __checkReturn                   efx_rc_t
455 efx_mae_match_spec_field_set(
456         __in                            efx_mae_match_spec_t *spec,
457         __in                            efx_mae_field_id_t field_id,
458         __in                            size_t value_size,
459         __in_bcount(value_size)         const uint8_t *value,
460         __in                            size_t mask_size,
461         __in_bcount(mask_size)          const uint8_t *mask)
462 {
463         const efx_mae_mv_desc_t *descp;
464         uint8_t *mvp;
465         efx_rc_t rc;
466
467         if (field_id >= EFX_MAE_FIELD_NIDS) {
468                 rc = EINVAL;
469                 goto fail1;
470         }
471
472         switch (spec->emms_type) {
473         case EFX_MAE_RULE_ACTION:
474                 descp = &__efx_mae_action_rule_mv_desc_set[field_id];
475                 mvp = spec->emms_mask_value_pairs.action;
476                 break;
477         default:
478                 rc = ENOTSUP;
479                 goto fail2;
480         }
481
482         if (value_size != descp->emmd_value_size) {
483                 rc = EINVAL;
484                 goto fail3;
485         }
486
487         if (mask_size != descp->emmd_mask_size) {
488                 rc = EINVAL;
489                 goto fail4;
490         }
491
492         if (descp->emmd_endianness == EFX_MAE_FIELD_BE) {
493                 /*
494                  * The mask/value are in network (big endian) order.
495                  * The MCDI request field is also big endian.
496                  */
497                 memcpy(mvp + descp->emmd_value_offset, value, value_size);
498                 memcpy(mvp + descp->emmd_mask_offset, mask, mask_size);
499         } else {
500                 efx_dword_t dword;
501
502                 /*
503                  * The mask/value are in host byte order.
504                  * The MCDI request field is little endian.
505                  */
506                 switch (value_size) {
507                 case 4:
508                         EFX_POPULATE_DWORD_1(dword,
509                             EFX_DWORD_0, *(const uint32_t *)value);
510
511                         memcpy(mvp + descp->emmd_value_offset,
512                             &dword, sizeof (dword));
513                         break;
514                 default:
515                         EFSYS_ASSERT(B_FALSE);
516                 }
517
518                 switch (mask_size) {
519                 case 4:
520                         EFX_POPULATE_DWORD_1(dword,
521                             EFX_DWORD_0, *(const uint32_t *)mask);
522
523                         memcpy(mvp + descp->emmd_mask_offset,
524                             &dword, sizeof (dword));
525                         break;
526                 default:
527                         EFSYS_ASSERT(B_FALSE);
528                 }
529         }
530
531         return (0);
532
533 fail4:
534         EFSYS_PROBE(fail4);
535 fail3:
536         EFSYS_PROBE(fail3);
537 fail2:
538         EFSYS_PROBE(fail2);
539 fail1:
540         EFSYS_PROBE1(fail1, efx_rc_t, rc);
541         return (rc);
542 }
543
544         __checkReturn                   efx_rc_t
545 efx_mae_match_spec_mport_set(
546         __in                            efx_mae_match_spec_t *spec,
547         __in                            const efx_mport_sel_t *valuep,
548         __in_opt                        const efx_mport_sel_t *maskp)
549 {
550         uint32_t full_mask = UINT32_MAX;
551         const uint8_t *vp;
552         const uint8_t *mp;
553         efx_rc_t rc;
554
555         if (valuep == NULL) {
556                 rc = EINVAL;
557                 goto fail1;
558         }
559
560         vp = (const uint8_t *)&valuep->sel;
561         if (maskp != NULL)
562                 mp = (const uint8_t *)&maskp->sel;
563         else
564                 mp = (const uint8_t *)&full_mask;
565
566         rc = efx_mae_match_spec_field_set(spec,
567             EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR,
568             sizeof (valuep->sel), vp, sizeof (maskp->sel), mp);
569         if (rc != 0)
570                 goto fail2;
571
572         return (0);
573
574 fail2:
575         EFSYS_PROBE(fail2);
576 fail1:
577         EFSYS_PROBE1(fail1, efx_rc_t, rc);
578         return (rc);
579 }
580
581 #define EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit)              \
582             ((_mask)[(_bit) / (_mask_page_nbits)] &                     \
583                     (1ULL << ((_bit) & ((_mask_page_nbits) - 1))))
584
585 static inline                           boolean_t
586 efx_mask_is_prefix(
587         __in                            size_t mask_nbytes,
588         __in_bcount(mask_nbytes)        const uint8_t *maskp)
589 {
590         boolean_t prev_bit_is_set = B_TRUE;
591         unsigned int i;
592
593         for (i = 0; i < 8 * mask_nbytes; ++i) {
594                 boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i);
595
596                 if (!prev_bit_is_set && bit_is_set)
597                         return B_FALSE;
598
599                 prev_bit_is_set = bit_is_set;
600         }
601
602         return B_TRUE;
603 }
604
605 static inline                           boolean_t
606 efx_mask_is_all_ones(
607         __in                            size_t mask_nbytes,
608         __in_bcount(mask_nbytes)        const uint8_t *maskp)
609 {
610         unsigned int i;
611         uint8_t t = ~0;
612
613         for (i = 0; i < mask_nbytes; ++i)
614                 t &= maskp[i];
615
616         return (t == (uint8_t)(~0));
617 }
618
619 static inline                           boolean_t
620 efx_mask_is_all_zeros(
621         __in                            size_t mask_nbytes,
622         __in_bcount(mask_nbytes)        const uint8_t *maskp)
623 {
624         unsigned int i;
625         uint8_t t = 0;
626
627         for (i = 0; i < mask_nbytes; ++i)
628                 t |= maskp[i];
629
630         return (t == 0);
631 }
632
633         __checkReturn                   boolean_t
634 efx_mae_match_spec_is_valid(
635         __in                            efx_nic_t *enp,
636         __in                            const efx_mae_match_spec_t *spec)
637 {
638         efx_mae_t *maep = enp->en_maep;
639         unsigned int field_ncaps = maep->em_max_nfields;
640         const efx_mae_field_cap_t *field_caps;
641         const efx_mae_mv_desc_t *desc_setp;
642         unsigned int desc_set_nentries;
643         boolean_t is_valid = B_TRUE;
644         efx_mae_field_id_t field_id;
645         const uint8_t *mvp;
646
647         switch (spec->emms_type) {
648         case EFX_MAE_RULE_ACTION:
649                 field_caps = maep->em_action_rule_field_caps;
650                 desc_setp = __efx_mae_action_rule_mv_desc_set;
651                 desc_set_nentries =
652                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
653                 mvp = spec->emms_mask_value_pairs.action;
654                 break;
655         default:
656                 return (B_FALSE);
657         }
658
659         if (field_caps == NULL)
660                 return (B_FALSE);
661
662         for (field_id = 0; field_id < desc_set_nentries; ++field_id) {
663                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
664                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
665                 const uint8_t *m_buf = mvp + descp->emmd_mask_offset;
666                 size_t m_size = descp->emmd_mask_size;
667
668                 if (m_size == 0)
669                         continue; /* Skip array gap */
670
671                 if (field_cap_id >= field_ncaps)
672                         break;
673
674                 switch (field_caps[field_cap_id].emfc_support) {
675                 case MAE_FIELD_SUPPORTED_MATCH_MASK:
676                         is_valid = B_TRUE;
677                         break;
678                 case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
679                         is_valid = efx_mask_is_prefix(m_size, m_buf);
680                         break;
681                 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
682                         is_valid = (efx_mask_is_all_ones(m_size, m_buf) ||
683                             efx_mask_is_all_zeros(m_size, m_buf));
684                         break;
685                 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
686                         is_valid = efx_mask_is_all_ones(m_size, m_buf);
687                         break;
688                 case MAE_FIELD_SUPPORTED_MATCH_NEVER:
689                 case MAE_FIELD_UNSUPPORTED:
690                 default:
691                         is_valid = efx_mask_is_all_zeros(m_size, m_buf);
692                         break;
693                 }
694
695                 if (is_valid == B_FALSE)
696                         break;
697         }
698
699         return (is_valid);
700 }
701
702         __checkReturn                   efx_rc_t
703 efx_mae_action_set_spec_init(
704         __in                            efx_nic_t *enp,
705         __out                           efx_mae_actions_t **specp)
706 {
707         efx_mae_actions_t *spec;
708         efx_rc_t rc;
709
710         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
711         if (spec == NULL) {
712                 rc = ENOMEM;
713                 goto fail1;
714         }
715
716         *specp = spec;
717
718         return (0);
719
720 fail1:
721         EFSYS_PROBE1(fail1, efx_rc_t, rc);
722         return (rc);
723 }
724
725                                         void
726 efx_mae_action_set_spec_fini(
727         __in                            efx_nic_t *enp,
728         __in                            efx_mae_actions_t *spec)
729 {
730         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
731 }
732
733 static  __checkReturn                   efx_rc_t
734 efx_mae_action_set_add_vlan_pop(
735         __in                            efx_mae_actions_t *spec,
736         __in                            size_t arg_size,
737         __in_bcount(arg_size)           const uint8_t *arg)
738 {
739         efx_rc_t rc;
740
741         if (arg_size != 0) {
742                 rc = EINVAL;
743                 goto fail1;
744         }
745
746         if (arg != NULL) {
747                 rc = EINVAL;
748                 goto fail2;
749         }
750
751         if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) {
752                 rc = ENOTSUP;
753                 goto fail3;
754         }
755
756         ++spec->ema_n_vlan_tags_to_pop;
757
758         return (0);
759
760 fail3:
761         EFSYS_PROBE(fail3);
762 fail2:
763         EFSYS_PROBE(fail2);
764 fail1:
765         EFSYS_PROBE1(fail1, efx_rc_t, rc);
766         return (rc);
767 }
768
769 static  __checkReturn                   efx_rc_t
770 efx_mae_action_set_add_vlan_push(
771         __in                            efx_mae_actions_t *spec,
772         __in                            size_t arg_size,
773         __in_bcount(arg_size)           const uint8_t *arg)
774 {
775         unsigned int n_tags = spec->ema_n_vlan_tags_to_push;
776         efx_rc_t rc;
777
778         if (arg_size != sizeof (*spec->ema_vlan_push_descs)) {
779                 rc = EINVAL;
780                 goto fail1;
781         }
782
783         if (arg == NULL) {
784                 rc = EINVAL;
785                 goto fail2;
786         }
787
788         if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
789                 rc = ENOTSUP;
790                 goto fail3;
791         }
792
793         memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size);
794         ++(spec->ema_n_vlan_tags_to_push);
795
796         return (0);
797
798 fail3:
799         EFSYS_PROBE(fail3);
800 fail2:
801         EFSYS_PROBE(fail2);
802 fail1:
803         EFSYS_PROBE1(fail1, efx_rc_t, rc);
804         return (rc);
805 }
806
807 static  __checkReturn                   efx_rc_t
808 efx_mae_action_set_add_flag(
809         __in                            efx_mae_actions_t *spec,
810         __in                            size_t arg_size,
811         __in_bcount(arg_size)           const uint8_t *arg)
812 {
813         efx_rc_t rc;
814
815         _NOTE(ARGUNUSED(spec))
816
817         if (arg_size != 0) {
818                 rc = EINVAL;
819                 goto fail1;
820         }
821
822         if (arg != NULL) {
823                 rc = EINVAL;
824                 goto fail2;
825         }
826
827         /* This action does not have any arguments, so do nothing here. */
828
829         return (0);
830
831 fail2:
832         EFSYS_PROBE(fail2);
833 fail1:
834         EFSYS_PROBE1(fail1, efx_rc_t, rc);
835         return (rc);
836 }
837
838 static  __checkReturn                   efx_rc_t
839 efx_mae_action_set_add_mark(
840         __in                            efx_mae_actions_t *spec,
841         __in                            size_t arg_size,
842         __in_bcount(arg_size)           const uint8_t *arg)
843 {
844         efx_rc_t rc;
845
846         if (arg_size != sizeof (spec->ema_mark_value)) {
847                 rc = EINVAL;
848                 goto fail1;
849         }
850
851         if (arg == NULL) {
852                 rc = EINVAL;
853                 goto fail2;
854         }
855
856         memcpy(&spec->ema_mark_value, arg, arg_size);
857
858         return (0);
859
860 fail2:
861         EFSYS_PROBE(fail2);
862 fail1:
863         EFSYS_PROBE1(fail1, efx_rc_t, rc);
864         return (rc);
865 }
866
867 static  __checkReturn                   efx_rc_t
868 efx_mae_action_set_add_deliver(
869         __in                            efx_mae_actions_t *spec,
870         __in                            size_t arg_size,
871         __in_bcount(arg_size)           const uint8_t *arg)
872 {
873         efx_rc_t rc;
874
875         if (arg_size != sizeof (spec->ema_deliver_mport)) {
876                 rc = EINVAL;
877                 goto fail1;
878         }
879
880         if (arg == NULL) {
881                 rc = EINVAL;
882                 goto fail2;
883         }
884
885         memcpy(&spec->ema_deliver_mport, arg, arg_size);
886
887         return (0);
888
889 fail2:
890         EFSYS_PROBE(fail2);
891 fail1:
892         EFSYS_PROBE1(fail1, efx_rc_t, rc);
893         return (rc);
894 }
895
896 typedef struct efx_mae_action_desc_s {
897         /* Action specific handler */
898         efx_rc_t        (*emad_add)(efx_mae_actions_t *,
899                                     size_t, const uint8_t *);
900 } efx_mae_action_desc_t;
901
902 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
903         [EFX_MAE_ACTION_VLAN_POP] = {
904                 .emad_add = efx_mae_action_set_add_vlan_pop
905         },
906         [EFX_MAE_ACTION_VLAN_PUSH] = {
907                 .emad_add = efx_mae_action_set_add_vlan_push
908         },
909         [EFX_MAE_ACTION_FLAG] = {
910                 .emad_add = efx_mae_action_set_add_flag
911         },
912         [EFX_MAE_ACTION_MARK] = {
913                 .emad_add = efx_mae_action_set_add_mark
914         },
915         [EFX_MAE_ACTION_DELIVER] = {
916                 .emad_add = efx_mae_action_set_add_deliver
917         }
918 };
919
920 static const uint32_t efx_mae_action_ordered_map =
921         (1U << EFX_MAE_ACTION_VLAN_POP) |
922         (1U << EFX_MAE_ACTION_VLAN_PUSH) |
923         (1U << EFX_MAE_ACTION_FLAG) |
924         (1U << EFX_MAE_ACTION_MARK) |
925         (1U << EFX_MAE_ACTION_DELIVER);
926
927 /*
928  * These actions must not be added after DELIVER, but
929  * they can have any place among the rest of
930  * strictly ordered actions.
931  */
932 static const uint32_t efx_mae_action_nonstrict_map =
933         (1U << EFX_MAE_ACTION_FLAG) |
934         (1U << EFX_MAE_ACTION_MARK);
935
936 static const uint32_t efx_mae_action_repeat_map =
937         (1U << EFX_MAE_ACTION_VLAN_POP) |
938         (1U << EFX_MAE_ACTION_VLAN_PUSH);
939
940 /*
941  * Add an action to an action set.
942  *
943  * This has to be invoked in the desired action order.
944  * An out-of-order action request will be turned down.
945  */
946 static  __checkReturn                   efx_rc_t
947 efx_mae_action_set_spec_populate(
948         __in                            efx_mae_actions_t *spec,
949         __in                            efx_mae_action_t type,
950         __in                            size_t arg_size,
951         __in_bcount(arg_size)           const uint8_t *arg)
952 {
953         uint32_t action_mask;
954         efx_rc_t rc;
955
956         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
957             (sizeof (efx_mae_action_ordered_map) * 8));
958         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
959             (sizeof (efx_mae_action_repeat_map) * 8));
960
961         EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
962         EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK);
963         EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER);
964
965         if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
966                 rc = EINVAL;
967                 goto fail1;
968         }
969
970         action_mask = (1U << type);
971
972         if ((spec->ema_actions & action_mask) != 0) {
973                 /* The action set already contains this action. */
974                 if ((efx_mae_action_repeat_map & action_mask) == 0) {
975                         /* Cannot add another non-repeatable action. */
976                         rc = ENOTSUP;
977                         goto fail2;
978                 }
979         }
980
981         if ((efx_mae_action_ordered_map & action_mask) != 0) {
982                 uint32_t strict_ordered_map =
983                     efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map;
984                 uint32_t later_actions_mask =
985                     strict_ordered_map & ~(action_mask | (action_mask - 1));
986
987                 if ((spec->ema_actions & later_actions_mask) != 0) {
988                         /* Cannot add an action after later ordered actions. */
989                         rc = ENOTSUP;
990                         goto fail3;
991                 }
992         }
993
994         if (efx_mae_actions[type].emad_add != NULL) {
995                 rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
996                 if (rc != 0)
997                         goto fail4;
998         }
999
1000         spec->ema_actions |= action_mask;
1001
1002         return (0);
1003
1004 fail4:
1005         EFSYS_PROBE(fail4);
1006 fail3:
1007         EFSYS_PROBE(fail3);
1008 fail2:
1009         EFSYS_PROBE(fail2);
1010 fail1:
1011         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1012         return (rc);
1013 }
1014
1015         __checkReturn                   efx_rc_t
1016 efx_mae_action_set_populate_vlan_pop(
1017         __in                            efx_mae_actions_t *spec)
1018 {
1019         return (efx_mae_action_set_spec_populate(spec,
1020             EFX_MAE_ACTION_VLAN_POP, 0, NULL));
1021 }
1022
1023         __checkReturn                   efx_rc_t
1024 efx_mae_action_set_populate_vlan_push(
1025         __in                            efx_mae_actions_t *spec,
1026         __in                            uint16_t tpid_be,
1027         __in                            uint16_t tci_be)
1028 {
1029         efx_mae_action_vlan_push_t action;
1030         const uint8_t *arg = (const uint8_t *)&action;
1031
1032         action.emavp_tpid_be = tpid_be;
1033         action.emavp_tci_be = tci_be;
1034
1035         return (efx_mae_action_set_spec_populate(spec,
1036             EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg));
1037 }
1038
1039         __checkReturn                   efx_rc_t
1040 efx_mae_action_set_populate_flag(
1041         __in                            efx_mae_actions_t *spec)
1042 {
1043         return (efx_mae_action_set_spec_populate(spec,
1044             EFX_MAE_ACTION_FLAG, 0, NULL));
1045 }
1046
1047         __checkReturn                   efx_rc_t
1048 efx_mae_action_set_populate_mark(
1049         __in                            efx_mae_actions_t *spec,
1050         __in                            uint32_t mark_value)
1051 {
1052         const uint8_t *arg = (const uint8_t *)&mark_value;
1053
1054         return (efx_mae_action_set_spec_populate(spec,
1055             EFX_MAE_ACTION_MARK, sizeof (mark_value), arg));
1056 }
1057
1058         __checkReturn                   efx_rc_t
1059 efx_mae_action_set_populate_deliver(
1060         __in                            efx_mae_actions_t *spec,
1061         __in                            const efx_mport_sel_t *mportp)
1062 {
1063         const uint8_t *arg;
1064         efx_rc_t rc;
1065
1066         if (mportp == NULL) {
1067                 rc = EINVAL;
1068                 goto fail1;
1069         }
1070
1071         arg = (const uint8_t *)&mportp->sel;
1072
1073         return (efx_mae_action_set_spec_populate(spec,
1074             EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
1075
1076 fail1:
1077         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1078         return (rc);
1079 }
1080
1081         __checkReturn                   efx_rc_t
1082 efx_mae_action_set_populate_drop(
1083         __in                            efx_mae_actions_t *spec)
1084 {
1085         efx_mport_sel_t mport;
1086         const uint8_t *arg;
1087         efx_dword_t dword;
1088
1089         EFX_POPULATE_DWORD_1(dword,
1090             MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL);
1091
1092         mport.sel = dword.ed_u32[0];
1093
1094         arg = (const uint8_t *)&mport.sel;
1095
1096         return (efx_mae_action_set_spec_populate(spec,
1097             EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg));
1098 }
1099
1100         __checkReturn                   boolean_t
1101 efx_mae_action_set_specs_equal(
1102         __in                            const efx_mae_actions_t *left,
1103         __in                            const efx_mae_actions_t *right)
1104 {
1105         return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
1106 }
1107
1108         __checkReturn                   efx_rc_t
1109 efx_mae_match_specs_class_cmp(
1110         __in                            efx_nic_t *enp,
1111         __in                            const efx_mae_match_spec_t *left,
1112         __in                            const efx_mae_match_spec_t *right,
1113         __out                           boolean_t *have_same_classp)
1114 {
1115         efx_mae_t *maep = enp->en_maep;
1116         unsigned int field_ncaps = maep->em_max_nfields;
1117         const efx_mae_field_cap_t *field_caps;
1118         const efx_mae_mv_desc_t *desc_setp;
1119         unsigned int desc_set_nentries;
1120         boolean_t have_same_class = B_TRUE;
1121         efx_mae_field_id_t field_id;
1122         const uint8_t *mvpl;
1123         const uint8_t *mvpr;
1124         efx_rc_t rc;
1125
1126         switch (left->emms_type) {
1127         case EFX_MAE_RULE_ACTION:
1128                 field_caps = maep->em_action_rule_field_caps;
1129                 desc_setp = __efx_mae_action_rule_mv_desc_set;
1130                 desc_set_nentries =
1131                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1132                 mvpl = left->emms_mask_value_pairs.action;
1133                 mvpr = right->emms_mask_value_pairs.action;
1134                 break;
1135         default:
1136                 rc = ENOTSUP;
1137                 goto fail1;
1138         }
1139
1140         if (field_caps == NULL) {
1141                 rc = EAGAIN;
1142                 goto fail2;
1143         }
1144
1145         if (left->emms_type != right->emms_type ||
1146             left->emms_prio != right->emms_prio) {
1147                 /*
1148                  * Rules of different types can never map to the same class.
1149                  *
1150                  * The FW can support some set of match criteria for one
1151                  * priority and not support the very same set for
1152                  * another priority. Thus, two rules which have
1153                  * different priorities can never map to
1154                  * the same class.
1155                  */
1156                 *have_same_classp = B_FALSE;
1157                 return (0);
1158         }
1159
1160         for (field_id = 0; field_id < desc_set_nentries; ++field_id) {
1161                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1162                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1163
1164                 if (descp->emmd_mask_size == 0)
1165                         continue; /* Skip array gap */
1166
1167                 if (field_cap_id >= field_ncaps)
1168                         break;
1169
1170                 if (field_caps[field_cap_id].emfc_mask_affects_class) {
1171                         const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
1172                         const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
1173                         size_t mask_size = descp->emmd_mask_size;
1174
1175                         if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
1176                                 have_same_class = B_FALSE;
1177                                 break;
1178                         }
1179                 }
1180
1181                 if (field_caps[field_cap_id].emfc_match_affects_class) {
1182                         const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
1183                         const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
1184                         size_t value_size = descp->emmd_value_size;
1185
1186                         if (memcmp(lvalp, rvalp, value_size) != 0) {
1187                                 have_same_class = B_FALSE;
1188                                 break;
1189                         }
1190                 }
1191         }
1192
1193         *have_same_classp = have_same_class;
1194
1195         return (0);
1196
1197 fail2:
1198         EFSYS_PROBE(fail2);
1199 fail1:
1200         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1201         return (rc);
1202 }
1203
1204         __checkReturn                   efx_rc_t
1205 efx_mae_action_set_alloc(
1206         __in                            efx_nic_t *enp,
1207         __in                            const efx_mae_actions_t *spec,
1208         __out                           efx_mae_aset_id_t *aset_idp)
1209 {
1210         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1211         efx_mcdi_req_t req;
1212         EFX_MCDI_DECLARE_BUF(payload,
1213             MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
1214             MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
1215         efx_mae_aset_id_t aset_id;
1216         efx_rc_t rc;
1217
1218         if (encp->enc_mae_supported == B_FALSE) {
1219                 rc = ENOTSUP;
1220                 goto fail1;
1221         }
1222
1223         req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
1224         req.emr_in_buf = payload;
1225         req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
1226         req.emr_out_buf = payload;
1227         req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
1228
1229         /*
1230          * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
1231          * corresponding resource types are supported by the implementation.
1232          * Use proper resource ID assignments instead.
1233          */
1234         MCDI_IN_SET_DWORD(req,
1235             MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
1236         MCDI_IN_SET_DWORD(req,
1237             MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
1238         MCDI_IN_SET_DWORD(req,
1239             MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, EFX_MAE_RSRC_ID_INVALID);
1240
1241         MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1242             MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
1243
1244         if (spec->ema_n_vlan_tags_to_push > 0) {
1245                 unsigned int outer_tag_idx;
1246
1247                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1248                     MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
1249                     spec->ema_n_vlan_tags_to_push);
1250
1251                 if (spec->ema_n_vlan_tags_to_push ==
1252                     EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1253                         MCDI_IN_SET_WORD(req,
1254                             MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
1255                             spec->ema_vlan_push_descs[0].emavp_tpid_be);
1256                         MCDI_IN_SET_WORD(req,
1257                             MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
1258                             spec->ema_vlan_push_descs[0].emavp_tci_be);
1259                 }
1260
1261                 outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
1262
1263                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
1264                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
1265                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
1266                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
1267         }
1268
1269         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
1270                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1271                     MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
1272         }
1273
1274         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
1275                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1276                     MAE_ACTION_SET_ALLOC_IN_MARK, 1);
1277
1278                 MCDI_IN_SET_DWORD(req,
1279                     MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
1280         }
1281
1282         MCDI_IN_SET_DWORD(req,
1283             MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
1284
1285         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
1286             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
1287         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
1288             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
1289
1290         efx_mcdi_execute(enp, &req);
1291
1292         if (req.emr_rc != 0) {
1293                 rc = req.emr_rc;
1294                 goto fail2;
1295         }
1296
1297         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
1298                 rc = EMSGSIZE;
1299                 goto fail3;
1300         }
1301
1302         aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
1303         if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
1304                 rc = ENOENT;
1305                 goto fail4;
1306         }
1307
1308         aset_idp->id = aset_id.id;
1309
1310         return (0);
1311
1312 fail4:
1313         EFSYS_PROBE(fail4);
1314 fail3:
1315         EFSYS_PROBE(fail3);
1316 fail2:
1317         EFSYS_PROBE(fail2);
1318 fail1:
1319         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1320         return (rc);
1321 }
1322
1323         __checkReturn                   efx_rc_t
1324 efx_mae_action_set_free(
1325         __in                            efx_nic_t *enp,
1326         __in                            const efx_mae_aset_id_t *aset_idp)
1327 {
1328         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1329         efx_mcdi_req_t req;
1330         EFX_MCDI_DECLARE_BUF(payload,
1331             MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
1332             MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
1333         efx_rc_t rc;
1334
1335         if (encp->enc_mae_supported == B_FALSE) {
1336                 rc = ENOTSUP;
1337                 goto fail1;
1338         }
1339
1340         req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
1341         req.emr_in_buf = payload;
1342         req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
1343         req.emr_out_buf = payload;
1344         req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
1345
1346         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
1347
1348         efx_mcdi_execute(enp, &req);
1349
1350         if (req.emr_rc != 0) {
1351                 rc = req.emr_rc;
1352                 goto fail2;
1353         }
1354
1355         if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
1356             aset_idp->id) {
1357                 /* Firmware failed to free the action set. */
1358                 rc = EAGAIN;
1359                 goto fail3;
1360         }
1361
1362         return (0);
1363
1364 fail3:
1365         EFSYS_PROBE(fail3);
1366 fail2:
1367         EFSYS_PROBE(fail2);
1368 fail1:
1369         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1370         return (rc);
1371 }
1372
1373         __checkReturn                   efx_rc_t
1374 efx_mae_action_rule_insert(
1375         __in                            efx_nic_t *enp,
1376         __in                            const efx_mae_match_spec_t *spec,
1377         __in                            const efx_mae_aset_list_id_t *asl_idp,
1378         __in                            const efx_mae_aset_id_t *as_idp,
1379         __out                           efx_mae_rule_id_t *ar_idp)
1380 {
1381         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1382         efx_mcdi_req_t req;
1383         EFX_MCDI_DECLARE_BUF(payload,
1384             MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2,
1385             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
1386         efx_oword_t *rule_response;
1387         efx_mae_rule_id_t ar_id;
1388         size_t offset;
1389         efx_rc_t rc;
1390
1391         EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
1392             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
1393
1394         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1395             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
1396
1397         if (encp->enc_mae_supported == B_FALSE) {
1398                 rc = ENOTSUP;
1399                 goto fail1;
1400         }
1401
1402         if (spec->emms_type != EFX_MAE_RULE_ACTION ||
1403             (asl_idp != NULL && as_idp != NULL) ||
1404             (asl_idp == NULL && as_idp == NULL)) {
1405                 rc = EINVAL;
1406                 goto fail2;
1407         }
1408
1409         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
1410         req.emr_in_buf = payload;
1411         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
1412         req.emr_out_buf = payload;
1413         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
1414
1415         EFX_STATIC_ASSERT(sizeof (*rule_response) <=
1416             MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
1417         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
1418         rule_response = (efx_oword_t *)(payload + offset);
1419         EFX_POPULATE_OWORD_3(*rule_response,
1420             MAE_ACTION_RULE_RESPONSE_ASL_ID,
1421             (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
1422             MAE_ACTION_RULE_RESPONSE_AS_ID,
1423             (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
1424             MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
1425
1426         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
1427
1428         /*
1429          * Mask-value pairs have been stored in the byte order needed for the
1430          * MCDI request and are thus safe to be copied directly to the buffer.
1431          */
1432         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
1433             MAE_FIELD_MASK_VALUE_PAIRS_LEN);
1434         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
1435         memcpy(payload + offset, spec->emms_mask_value_pairs.action,
1436             MAE_FIELD_MASK_VALUE_PAIRS_LEN);
1437
1438         efx_mcdi_execute(enp, &req);
1439
1440         if (req.emr_rc != 0) {
1441                 rc = req.emr_rc;
1442                 goto fail3;
1443         }
1444
1445         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
1446                 rc = EMSGSIZE;
1447                 goto fail4;
1448         }
1449
1450         ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
1451         if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
1452                 rc = ENOENT;
1453                 goto fail5;
1454         }
1455
1456         ar_idp->id = ar_id.id;
1457
1458         return (0);
1459
1460 fail5:
1461         EFSYS_PROBE(fail5);
1462 fail4:
1463         EFSYS_PROBE(fail4);
1464 fail3:
1465         EFSYS_PROBE(fail3);
1466 fail2:
1467         EFSYS_PROBE(fail2);
1468 fail1:
1469         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1470         return (rc);
1471 }
1472
1473         __checkReturn                   efx_rc_t
1474 efx_mae_action_rule_remove(
1475         __in                            efx_nic_t *enp,
1476         __in                            const efx_mae_rule_id_t *ar_idp)
1477 {
1478         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1479         efx_mcdi_req_t req;
1480         EFX_MCDI_DECLARE_BUF(payload,
1481             MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
1482             MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
1483         efx_rc_t rc;
1484
1485         if (encp->enc_mae_supported == B_FALSE) {
1486                 rc = ENOTSUP;
1487                 goto fail1;
1488         }
1489
1490         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
1491         req.emr_in_buf = payload;
1492         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
1493         req.emr_out_buf = payload;
1494         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
1495
1496         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
1497
1498         efx_mcdi_execute(enp, &req);
1499
1500         if (req.emr_rc != 0) {
1501                 rc = req.emr_rc;
1502                 goto fail2;
1503         }
1504
1505         if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
1506             ar_idp->id) {
1507                 /* Firmware failed to delete the action rule. */
1508                 rc = EAGAIN;
1509                 goto fail3;
1510         }
1511
1512         return (0);
1513
1514 fail3:
1515         EFSYS_PROBE(fail3);
1516 fail2:
1517         EFSYS_PROBE(fail2);
1518 fail1:
1519         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1520         return (rc);
1521 }
1522
1523 #endif /* EFSYS_OPT_MAE */