4b569119f85f5354b0a0f815a582e27e911d931a
[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                   efx_rc_t
1032 efx_mae_action_set_populate_drop(
1033         __in                            efx_mae_actions_t *spec)
1034 {
1035         efx_mport_sel_t mport;
1036         const uint8_t *arg;
1037         efx_dword_t dword;
1038
1039         EFX_POPULATE_DWORD_1(dword,
1040             MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL);
1041
1042         mport.sel = dword.ed_u32[0];
1043
1044         arg = (const uint8_t *)&mport.sel;
1045
1046         return (efx_mae_action_set_spec_populate(spec,
1047             EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg));
1048 }
1049
1050         __checkReturn                   boolean_t
1051 efx_mae_action_set_specs_equal(
1052         __in                            const efx_mae_actions_t *left,
1053         __in                            const efx_mae_actions_t *right)
1054 {
1055         return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
1056 }
1057
1058         __checkReturn                   efx_rc_t
1059 efx_mae_match_specs_class_cmp(
1060         __in                            efx_nic_t *enp,
1061         __in                            const efx_mae_match_spec_t *left,
1062         __in                            const efx_mae_match_spec_t *right,
1063         __out                           boolean_t *have_same_classp)
1064 {
1065         efx_mae_t *maep = enp->en_maep;
1066         unsigned int field_ncaps = maep->em_max_nfields;
1067         const efx_mae_field_cap_t *field_caps;
1068         const efx_mae_mv_desc_t *desc_setp;
1069         unsigned int desc_set_nentries;
1070         boolean_t have_same_class = B_TRUE;
1071         efx_mae_field_id_t field_id;
1072         const uint8_t *mvpl;
1073         const uint8_t *mvpr;
1074         efx_rc_t rc;
1075
1076         switch (left->emms_type) {
1077         case EFX_MAE_RULE_ACTION:
1078                 field_caps = maep->em_action_rule_field_caps;
1079                 desc_setp = __efx_mae_action_rule_mv_desc_set;
1080                 desc_set_nentries =
1081                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1082                 mvpl = left->emms_mask_value_pairs.action;
1083                 mvpr = right->emms_mask_value_pairs.action;
1084                 break;
1085         default:
1086                 rc = ENOTSUP;
1087                 goto fail1;
1088         }
1089
1090         if (field_caps == NULL) {
1091                 rc = EAGAIN;
1092                 goto fail2;
1093         }
1094
1095         if (left->emms_type != right->emms_type ||
1096             left->emms_prio != right->emms_prio) {
1097                 /*
1098                  * Rules of different types can never map to the same class.
1099                  *
1100                  * The FW can support some set of match criteria for one
1101                  * priority and not support the very same set for
1102                  * another priority. Thus, two rules which have
1103                  * different priorities can never map to
1104                  * the same class.
1105                  */
1106                 *have_same_classp = B_FALSE;
1107                 return (0);
1108         }
1109
1110         for (field_id = 0; field_id < desc_set_nentries; ++field_id) {
1111                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1112                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1113
1114                 if (descp->emmd_mask_size == 0)
1115                         continue; /* Skip array gap */
1116
1117                 if (field_cap_id >= field_ncaps)
1118                         break;
1119
1120                 if (field_caps[field_cap_id].emfc_mask_affects_class) {
1121                         const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
1122                         const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
1123                         size_t mask_size = descp->emmd_mask_size;
1124
1125                         if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
1126                                 have_same_class = B_FALSE;
1127                                 break;
1128                         }
1129                 }
1130
1131                 if (field_caps[field_cap_id].emfc_match_affects_class) {
1132                         const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
1133                         const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
1134                         size_t value_size = descp->emmd_value_size;
1135
1136                         if (memcmp(lvalp, rvalp, value_size) != 0) {
1137                                 have_same_class = B_FALSE;
1138                                 break;
1139                         }
1140                 }
1141         }
1142
1143         *have_same_classp = have_same_class;
1144
1145         return (0);
1146
1147 fail2:
1148         EFSYS_PROBE(fail2);
1149 fail1:
1150         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1151         return (rc);
1152 }
1153
1154         __checkReturn                   efx_rc_t
1155 efx_mae_action_set_alloc(
1156         __in                            efx_nic_t *enp,
1157         __in                            const efx_mae_actions_t *spec,
1158         __out                           efx_mae_aset_id_t *aset_idp)
1159 {
1160         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1161         efx_mcdi_req_t req;
1162         EFX_MCDI_DECLARE_BUF(payload,
1163             MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
1164             MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
1165         efx_mae_aset_id_t aset_id;
1166         efx_rc_t rc;
1167
1168         if (encp->enc_mae_supported == B_FALSE) {
1169                 rc = ENOTSUP;
1170                 goto fail1;
1171         }
1172
1173         req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
1174         req.emr_in_buf = payload;
1175         req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
1176         req.emr_out_buf = payload;
1177         req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
1178
1179         /*
1180          * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
1181          * corresponding resource types are supported by the implementation.
1182          * Use proper resource ID assignments instead.
1183          */
1184         MCDI_IN_SET_DWORD(req,
1185             MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
1186         MCDI_IN_SET_DWORD(req,
1187             MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
1188         MCDI_IN_SET_DWORD(req,
1189             MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, EFX_MAE_RSRC_ID_INVALID);
1190
1191         MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1192             MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
1193
1194         if (spec->ema_n_vlan_tags_to_push > 0) {
1195                 unsigned int outer_tag_idx;
1196
1197                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1198                     MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
1199                     spec->ema_n_vlan_tags_to_push);
1200
1201                 if (spec->ema_n_vlan_tags_to_push ==
1202                     EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1203                         MCDI_IN_SET_WORD(req,
1204                             MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
1205                             spec->ema_vlan_push_descs[0].emavp_tpid_be);
1206                         MCDI_IN_SET_WORD(req,
1207                             MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
1208                             spec->ema_vlan_push_descs[0].emavp_tci_be);
1209                 }
1210
1211                 outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
1212
1213                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
1214                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
1215                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
1216                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
1217         }
1218
1219         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
1220                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1221                     MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
1222         }
1223
1224         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
1225                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1226                     MAE_ACTION_SET_ALLOC_IN_MARK, 1);
1227
1228                 MCDI_IN_SET_DWORD(req,
1229                     MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
1230         }
1231
1232         MCDI_IN_SET_DWORD(req,
1233             MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
1234
1235         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
1236             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
1237         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
1238             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
1239
1240         efx_mcdi_execute(enp, &req);
1241
1242         if (req.emr_rc != 0) {
1243                 rc = req.emr_rc;
1244                 goto fail2;
1245         }
1246
1247         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
1248                 rc = EMSGSIZE;
1249                 goto fail3;
1250         }
1251
1252         aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
1253         if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
1254                 rc = ENOENT;
1255                 goto fail4;
1256         }
1257
1258         aset_idp->id = aset_id.id;
1259
1260         return (0);
1261
1262 fail4:
1263         EFSYS_PROBE(fail4);
1264 fail3:
1265         EFSYS_PROBE(fail3);
1266 fail2:
1267         EFSYS_PROBE(fail2);
1268 fail1:
1269         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1270         return (rc);
1271 }
1272
1273         __checkReturn                   efx_rc_t
1274 efx_mae_action_set_free(
1275         __in                            efx_nic_t *enp,
1276         __in                            const efx_mae_aset_id_t *aset_idp)
1277 {
1278         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1279         efx_mcdi_req_t req;
1280         EFX_MCDI_DECLARE_BUF(payload,
1281             MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
1282             MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
1283         efx_rc_t rc;
1284
1285         if (encp->enc_mae_supported == B_FALSE) {
1286                 rc = ENOTSUP;
1287                 goto fail1;
1288         }
1289
1290         req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
1291         req.emr_in_buf = payload;
1292         req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
1293         req.emr_out_buf = payload;
1294         req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
1295
1296         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
1297
1298         efx_mcdi_execute(enp, &req);
1299
1300         if (req.emr_rc != 0) {
1301                 rc = req.emr_rc;
1302                 goto fail2;
1303         }
1304
1305         if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
1306             aset_idp->id) {
1307                 /* Firmware failed to free the action set. */
1308                 rc = EAGAIN;
1309                 goto fail3;
1310         }
1311
1312         return (0);
1313
1314 fail3:
1315         EFSYS_PROBE(fail3);
1316 fail2:
1317         EFSYS_PROBE(fail2);
1318 fail1:
1319         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1320         return (rc);
1321 }
1322
1323         __checkReturn                   efx_rc_t
1324 efx_mae_action_rule_insert(
1325         __in                            efx_nic_t *enp,
1326         __in                            const efx_mae_match_spec_t *spec,
1327         __in                            const efx_mae_aset_list_id_t *asl_idp,
1328         __in                            const efx_mae_aset_id_t *as_idp,
1329         __out                           efx_mae_rule_id_t *ar_idp)
1330 {
1331         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1332         efx_mcdi_req_t req;
1333         EFX_MCDI_DECLARE_BUF(payload,
1334             MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2,
1335             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
1336         efx_oword_t *rule_response;
1337         efx_mae_rule_id_t ar_id;
1338         size_t offset;
1339         efx_rc_t rc;
1340
1341         EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
1342             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
1343
1344         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1345             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
1346
1347         if (encp->enc_mae_supported == B_FALSE) {
1348                 rc = ENOTSUP;
1349                 goto fail1;
1350         }
1351
1352         if (spec->emms_type != EFX_MAE_RULE_ACTION ||
1353             (asl_idp != NULL && as_idp != NULL) ||
1354             (asl_idp == NULL && as_idp == NULL)) {
1355                 rc = EINVAL;
1356                 goto fail2;
1357         }
1358
1359         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
1360         req.emr_in_buf = payload;
1361         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
1362         req.emr_out_buf = payload;
1363         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
1364
1365         EFX_STATIC_ASSERT(sizeof (*rule_response) <=
1366             MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
1367         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
1368         rule_response = (efx_oword_t *)(payload + offset);
1369         EFX_POPULATE_OWORD_3(*rule_response,
1370             MAE_ACTION_RULE_RESPONSE_ASL_ID,
1371             (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
1372             MAE_ACTION_RULE_RESPONSE_AS_ID,
1373             (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
1374             MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
1375
1376         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
1377
1378         /*
1379          * Mask-value pairs have been stored in the byte order needed for the
1380          * MCDI request and are thus safe to be copied directly to the buffer.
1381          */
1382         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
1383             MAE_FIELD_MASK_VALUE_PAIRS_LEN);
1384         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
1385         memcpy(payload + offset, spec->emms_mask_value_pairs.action,
1386             MAE_FIELD_MASK_VALUE_PAIRS_LEN);
1387
1388         efx_mcdi_execute(enp, &req);
1389
1390         if (req.emr_rc != 0) {
1391                 rc = req.emr_rc;
1392                 goto fail3;
1393         }
1394
1395         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
1396                 rc = EMSGSIZE;
1397                 goto fail4;
1398         }
1399
1400         ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
1401         if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
1402                 rc = ENOENT;
1403                 goto fail5;
1404         }
1405
1406         ar_idp->id = ar_id.id;
1407
1408         return (0);
1409
1410 fail5:
1411         EFSYS_PROBE(fail5);
1412 fail4:
1413         EFSYS_PROBE(fail4);
1414 fail3:
1415         EFSYS_PROBE(fail3);
1416 fail2:
1417         EFSYS_PROBE(fail2);
1418 fail1:
1419         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1420         return (rc);
1421 }
1422
1423         __checkReturn                   efx_rc_t
1424 efx_mae_action_rule_remove(
1425         __in                            efx_nic_t *enp,
1426         __in                            const efx_mae_rule_id_t *ar_idp)
1427 {
1428         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1429         efx_mcdi_req_t req;
1430         EFX_MCDI_DECLARE_BUF(payload,
1431             MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
1432             MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
1433         efx_rc_t rc;
1434
1435         if (encp->enc_mae_supported == B_FALSE) {
1436                 rc = ENOTSUP;
1437                 goto fail1;
1438         }
1439
1440         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
1441         req.emr_in_buf = payload;
1442         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
1443         req.emr_out_buf = payload;
1444         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
1445
1446         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
1447
1448         efx_mcdi_execute(enp, &req);
1449
1450         if (req.emr_rc != 0) {
1451                 rc = req.emr_rc;
1452                 goto fail2;
1453         }
1454
1455         if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
1456             ar_idp->id) {
1457                 /* Firmware failed to delete the action rule. */
1458                 rc = EAGAIN;
1459                 goto fail3;
1460         }
1461
1462         return (0);
1463
1464 fail3:
1465         EFSYS_PROBE(fail3);
1466 fail2:
1467         EFSYS_PROBE(fail2);
1468 fail1:
1469         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1470         return (rc);
1471 }
1472
1473 #endif /* EFSYS_OPT_MAE */