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