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