common/sfc_efx/base: support adding deliver action to set
[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_match_spec_field_set(
367         __in                            efx_mae_match_spec_t *spec,
368         __in                            efx_mae_field_id_t field_id,
369         __in                            size_t value_size,
370         __in_bcount(value_size)         const uint8_t *value,
371         __in                            size_t mask_size,
372         __in_bcount(mask_size)          const uint8_t *mask)
373 {
374         const efx_mae_mv_desc_t *descp;
375         uint8_t *mvp;
376         efx_rc_t rc;
377
378         if (field_id >= EFX_MAE_FIELD_NIDS) {
379                 rc = EINVAL;
380                 goto fail1;
381         }
382
383         switch (spec->emms_type) {
384         case EFX_MAE_RULE_ACTION:
385                 descp = &__efx_mae_action_rule_mv_desc_set[field_id];
386                 mvp = spec->emms_mask_value_pairs.action;
387                 break;
388         default:
389                 rc = ENOTSUP;
390                 goto fail2;
391         }
392
393         if (value_size != descp->emmd_value_size) {
394                 rc = EINVAL;
395                 goto fail3;
396         }
397
398         if (mask_size != descp->emmd_mask_size) {
399                 rc = EINVAL;
400                 goto fail4;
401         }
402
403         if (descp->emmd_endianness == EFX_MAE_FIELD_BE) {
404                 /*
405                  * The mask/value are in network (big endian) order.
406                  * The MCDI request field is also big endian.
407                  */
408                 memcpy(mvp + descp->emmd_value_offset, value, value_size);
409                 memcpy(mvp + descp->emmd_mask_offset, mask, mask_size);
410         } else {
411                 efx_dword_t dword;
412
413                 /*
414                  * The mask/value are in host byte order.
415                  * The MCDI request field is little endian.
416                  */
417                 switch (value_size) {
418                 case 4:
419                         EFX_POPULATE_DWORD_1(dword,
420                             EFX_DWORD_0, *(const uint32_t *)value);
421
422                         memcpy(mvp + descp->emmd_value_offset,
423                             &dword, sizeof (dword));
424                         break;
425                 default:
426                         EFSYS_ASSERT(B_FALSE);
427                 }
428
429                 switch (mask_size) {
430                 case 4:
431                         EFX_POPULATE_DWORD_1(dword,
432                             EFX_DWORD_0, *(const uint32_t *)mask);
433
434                         memcpy(mvp + descp->emmd_mask_offset,
435                             &dword, sizeof (dword));
436                         break;
437                 default:
438                         EFSYS_ASSERT(B_FALSE);
439                 }
440         }
441
442         return (0);
443
444 fail4:
445         EFSYS_PROBE(fail4);
446 fail3:
447         EFSYS_PROBE(fail3);
448 fail2:
449         EFSYS_PROBE(fail2);
450 fail1:
451         EFSYS_PROBE1(fail1, efx_rc_t, rc);
452         return (rc);
453 }
454
455         __checkReturn                   efx_rc_t
456 efx_mae_match_spec_mport_set(
457         __in                            efx_mae_match_spec_t *spec,
458         __in                            const efx_mport_sel_t *valuep,
459         __in_opt                        const efx_mport_sel_t *maskp)
460 {
461         uint32_t full_mask = UINT32_MAX;
462         const uint8_t *vp;
463         const uint8_t *mp;
464         efx_rc_t rc;
465
466         if (valuep == NULL) {
467                 rc = EINVAL;
468                 goto fail1;
469         }
470
471         vp = (const uint8_t *)&valuep->sel;
472         if (maskp != NULL)
473                 mp = (const uint8_t *)&maskp->sel;
474         else
475                 mp = (const uint8_t *)&full_mask;
476
477         rc = efx_mae_match_spec_field_set(spec,
478             EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR,
479             sizeof (valuep->sel), vp, sizeof (maskp->sel), mp);
480         if (rc != 0)
481                 goto fail2;
482
483         return (0);
484
485 fail2:
486         EFSYS_PROBE(fail2);
487 fail1:
488         EFSYS_PROBE1(fail1, efx_rc_t, rc);
489         return (rc);
490 }
491
492 #define EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit)              \
493             ((_mask)[(_bit) / (_mask_page_nbits)] &                     \
494                     (1ULL << ((_bit) & ((_mask_page_nbits) - 1))))
495
496 static inline                           boolean_t
497 efx_mask_is_prefix(
498         __in                            size_t mask_nbytes,
499         __in_bcount(mask_nbytes)        const uint8_t *maskp)
500 {
501         boolean_t prev_bit_is_set = B_TRUE;
502         unsigned int i;
503
504         for (i = 0; i < 8 * mask_nbytes; ++i) {
505                 boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i);
506
507                 if (!prev_bit_is_set && bit_is_set)
508                         return B_FALSE;
509
510                 prev_bit_is_set = bit_is_set;
511         }
512
513         return B_TRUE;
514 }
515
516 static inline                           boolean_t
517 efx_mask_is_all_ones(
518         __in                            size_t mask_nbytes,
519         __in_bcount(mask_nbytes)        const uint8_t *maskp)
520 {
521         unsigned int i;
522         uint8_t t = ~0;
523
524         for (i = 0; i < mask_nbytes; ++i)
525                 t &= maskp[i];
526
527         return (t == (uint8_t)(~0));
528 }
529
530 static inline                           boolean_t
531 efx_mask_is_all_zeros(
532         __in                            size_t mask_nbytes,
533         __in_bcount(mask_nbytes)        const uint8_t *maskp)
534 {
535         unsigned int i;
536         uint8_t t = 0;
537
538         for (i = 0; i < mask_nbytes; ++i)
539                 t |= maskp[i];
540
541         return (t == 0);
542 }
543
544         __checkReturn                   boolean_t
545 efx_mae_match_spec_is_valid(
546         __in                            efx_nic_t *enp,
547         __in                            const efx_mae_match_spec_t *spec)
548 {
549         efx_mae_t *maep = enp->en_maep;
550         unsigned int field_ncaps = maep->em_max_nfields;
551         const efx_mae_field_cap_t *field_caps;
552         const efx_mae_mv_desc_t *desc_setp;
553         unsigned int desc_set_nentries;
554         boolean_t is_valid = B_TRUE;
555         efx_mae_field_id_t field_id;
556         const uint8_t *mvp;
557
558         switch (spec->emms_type) {
559         case EFX_MAE_RULE_ACTION:
560                 field_caps = maep->em_action_rule_field_caps;
561                 desc_setp = __efx_mae_action_rule_mv_desc_set;
562                 desc_set_nentries =
563                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
564                 mvp = spec->emms_mask_value_pairs.action;
565                 break;
566         default:
567                 return (B_FALSE);
568         }
569
570         if (field_caps == NULL)
571                 return (B_FALSE);
572
573         for (field_id = 0; field_id < desc_set_nentries; ++field_id) {
574                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
575                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
576                 const uint8_t *m_buf = mvp + descp->emmd_mask_offset;
577                 size_t m_size = descp->emmd_mask_size;
578
579                 if (m_size == 0)
580                         continue; /* Skip array gap */
581
582                 if (field_cap_id >= field_ncaps)
583                         break;
584
585                 switch (field_caps[field_cap_id].emfc_support) {
586                 case MAE_FIELD_SUPPORTED_MATCH_MASK:
587                         is_valid = B_TRUE;
588                         break;
589                 case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
590                         is_valid = efx_mask_is_prefix(m_size, m_buf);
591                         break;
592                 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
593                         is_valid = (efx_mask_is_all_ones(m_size, m_buf) ||
594                             efx_mask_is_all_zeros(m_size, m_buf));
595                         break;
596                 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
597                         is_valid = efx_mask_is_all_ones(m_size, m_buf);
598                         break;
599                 case MAE_FIELD_SUPPORTED_MATCH_NEVER:
600                 case MAE_FIELD_UNSUPPORTED:
601                 default:
602                         is_valid = efx_mask_is_all_zeros(m_size, m_buf);
603                         break;
604                 }
605
606                 if (is_valid == B_FALSE)
607                         break;
608         }
609
610         return (is_valid);
611 }
612
613         __checkReturn                   efx_rc_t
614 efx_mae_action_set_spec_init(
615         __in                            efx_nic_t *enp,
616         __out                           efx_mae_actions_t **specp)
617 {
618         efx_mae_actions_t *spec;
619         efx_rc_t rc;
620
621         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
622         if (spec == NULL) {
623                 rc = ENOMEM;
624                 goto fail1;
625         }
626
627         *specp = spec;
628
629         return (0);
630
631 fail1:
632         EFSYS_PROBE1(fail1, efx_rc_t, rc);
633         return (rc);
634 }
635
636                                         void
637 efx_mae_action_set_spec_fini(
638         __in                            efx_nic_t *enp,
639         __in                            efx_mae_actions_t *spec)
640 {
641         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
642 }
643
644 static  __checkReturn                   efx_rc_t
645 efx_mae_action_set_add_deliver(
646         __in                            efx_mae_actions_t *spec,
647         __in                            size_t arg_size,
648         __in_bcount(arg_size)           const uint8_t *arg)
649 {
650         efx_rc_t rc;
651
652         if (arg_size != sizeof (spec->ema_deliver_mport)) {
653                 rc = EINVAL;
654                 goto fail1;
655         }
656
657         if (arg == NULL) {
658                 rc = EINVAL;
659                 goto fail2;
660         }
661
662         memcpy(&spec->ema_deliver_mport, arg, arg_size);
663
664         return (0);
665
666 fail2:
667         EFSYS_PROBE(fail2);
668 fail1:
669         EFSYS_PROBE1(fail1, efx_rc_t, rc);
670         return (rc);
671 }
672
673 typedef struct efx_mae_action_desc_s {
674         /* Action specific handler */
675         efx_rc_t        (*emad_add)(efx_mae_actions_t *,
676                                     size_t, const uint8_t *);
677 } efx_mae_action_desc_t;
678
679 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
680         [EFX_MAE_ACTION_DELIVER] = {
681                 .emad_add = efx_mae_action_set_add_deliver
682         }
683 };
684
685 static const uint32_t efx_mae_action_ordered_map =
686         (1U << EFX_MAE_ACTION_DELIVER);
687
688 static const uint32_t efx_mae_action_repeat_map = 0;
689
690 /*
691  * Add an action to an action set.
692  *
693  * This has to be invoked in the desired action order.
694  * An out-of-order action request will be turned down.
695  */
696 static  __checkReturn                   efx_rc_t
697 efx_mae_action_set_spec_populate(
698         __in                            efx_mae_actions_t *spec,
699         __in                            efx_mae_action_t type,
700         __in                            size_t arg_size,
701         __in_bcount(arg_size)           const uint8_t *arg)
702 {
703         uint32_t action_mask;
704         efx_rc_t rc;
705
706         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
707             (sizeof (efx_mae_action_ordered_map) * 8));
708         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
709             (sizeof (efx_mae_action_repeat_map) * 8));
710
711         EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
712
713         if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
714                 rc = EINVAL;
715                 goto fail1;
716         }
717
718         action_mask = (1U << type);
719
720         if ((spec->ema_actions & action_mask) != 0) {
721                 /* The action set already contains this action. */
722                 if ((efx_mae_action_repeat_map & action_mask) == 0) {
723                         /* Cannot add another non-repeatable action. */
724                         rc = ENOTSUP;
725                         goto fail2;
726                 }
727         }
728
729         if ((efx_mae_action_ordered_map & action_mask) != 0) {
730                 uint32_t later_actions_mask =
731                         efx_mae_action_ordered_map &
732                         ~(action_mask | (action_mask - 1));
733
734                 if ((spec->ema_actions & later_actions_mask) != 0) {
735                         /* Cannot add an action after later ordered actions. */
736                         rc = ENOTSUP;
737                         goto fail3;
738                 }
739         }
740
741         if (efx_mae_actions[type].emad_add != NULL) {
742                 rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
743                 if (rc != 0)
744                         goto fail4;
745         }
746
747         spec->ema_actions |= action_mask;
748
749         return (0);
750
751 fail4:
752         EFSYS_PROBE(fail4);
753 fail3:
754         EFSYS_PROBE(fail3);
755 fail2:
756         EFSYS_PROBE(fail2);
757 fail1:
758         EFSYS_PROBE1(fail1, efx_rc_t, rc);
759         return (rc);
760 }
761
762         __checkReturn                   efx_rc_t
763 efx_mae_action_set_populate_deliver(
764         __in                            efx_mae_actions_t *spec,
765         __in                            const efx_mport_sel_t *mportp)
766 {
767         const uint8_t *arg;
768         efx_rc_t rc;
769
770         if (mportp == NULL) {
771                 rc = EINVAL;
772                 goto fail1;
773         }
774
775         arg = (const uint8_t *)&mportp->sel;
776
777         return (efx_mae_action_set_spec_populate(spec,
778             EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
779
780 fail1:
781         EFSYS_PROBE1(fail1, efx_rc_t, rc);
782         return (rc);
783 }
784
785         __checkReturn                   boolean_t
786 efx_mae_action_set_specs_equal(
787         __in                            const efx_mae_actions_t *left,
788         __in                            const efx_mae_actions_t *right)
789 {
790         return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
791 }
792
793         __checkReturn                   efx_rc_t
794 efx_mae_match_specs_class_cmp(
795         __in                            efx_nic_t *enp,
796         __in                            const efx_mae_match_spec_t *left,
797         __in                            const efx_mae_match_spec_t *right,
798         __out                           boolean_t *have_same_classp)
799 {
800         efx_mae_t *maep = enp->en_maep;
801         unsigned int field_ncaps = maep->em_max_nfields;
802         const efx_mae_field_cap_t *field_caps;
803         const efx_mae_mv_desc_t *desc_setp;
804         unsigned int desc_set_nentries;
805         boolean_t have_same_class = B_TRUE;
806         efx_mae_field_id_t field_id;
807         const uint8_t *mvpl;
808         const uint8_t *mvpr;
809         efx_rc_t rc;
810
811         switch (left->emms_type) {
812         case EFX_MAE_RULE_ACTION:
813                 field_caps = maep->em_action_rule_field_caps;
814                 desc_setp = __efx_mae_action_rule_mv_desc_set;
815                 desc_set_nentries =
816                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
817                 mvpl = left->emms_mask_value_pairs.action;
818                 mvpr = right->emms_mask_value_pairs.action;
819                 break;
820         default:
821                 rc = ENOTSUP;
822                 goto fail1;
823         }
824
825         if (field_caps == NULL) {
826                 rc = EAGAIN;
827                 goto fail2;
828         }
829
830         if (left->emms_type != right->emms_type ||
831             left->emms_prio != right->emms_prio) {
832                 /*
833                  * Rules of different types can never map to the same class.
834                  *
835                  * The FW can support some set of match criteria for one
836                  * priority and not support the very same set for
837                  * another priority. Thus, two rules which have
838                  * different priorities can never map to
839                  * the same class.
840                  */
841                 *have_same_classp = B_FALSE;
842                 return (0);
843         }
844
845         for (field_id = 0; field_id < desc_set_nentries; ++field_id) {
846                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
847                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
848
849                 if (descp->emmd_mask_size == 0)
850                         continue; /* Skip array gap */
851
852                 if (field_cap_id >= field_ncaps)
853                         break;
854
855                 if (field_caps[field_cap_id].emfc_mask_affects_class) {
856                         const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
857                         const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
858                         size_t mask_size = descp->emmd_mask_size;
859
860                         if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
861                                 have_same_class = B_FALSE;
862                                 break;
863                         }
864                 }
865
866                 if (field_caps[field_cap_id].emfc_match_affects_class) {
867                         const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
868                         const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
869                         size_t value_size = descp->emmd_value_size;
870
871                         if (memcmp(lvalp, rvalp, value_size) != 0) {
872                                 have_same_class = B_FALSE;
873                                 break;
874                         }
875                 }
876         }
877
878         *have_same_classp = have_same_class;
879
880         return (0);
881
882 fail2:
883         EFSYS_PROBE(fail2);
884 fail1:
885         EFSYS_PROBE1(fail1, efx_rc_t, rc);
886         return (rc);
887 }
888
889 #endif /* EFSYS_OPT_MAE */