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