common/sfc_efx/base: support adding VLAN pop 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_vlan_pop(
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 != 0) {
653                 rc = EINVAL;
654                 goto fail1;
655         }
656
657         if (arg != NULL) {
658                 rc = EINVAL;
659                 goto fail2;
660         }
661
662         if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) {
663                 rc = ENOTSUP;
664                 goto fail3;
665         }
666
667         ++spec->ema_n_vlan_tags_to_pop;
668
669         return (0);
670
671 fail3:
672         EFSYS_PROBE(fail3);
673 fail2:
674         EFSYS_PROBE(fail2);
675 fail1:
676         EFSYS_PROBE1(fail1, efx_rc_t, rc);
677         return (rc);
678 }
679
680 static  __checkReturn                   efx_rc_t
681 efx_mae_action_set_add_deliver(
682         __in                            efx_mae_actions_t *spec,
683         __in                            size_t arg_size,
684         __in_bcount(arg_size)           const uint8_t *arg)
685 {
686         efx_rc_t rc;
687
688         if (arg_size != sizeof (spec->ema_deliver_mport)) {
689                 rc = EINVAL;
690                 goto fail1;
691         }
692
693         if (arg == NULL) {
694                 rc = EINVAL;
695                 goto fail2;
696         }
697
698         memcpy(&spec->ema_deliver_mport, arg, arg_size);
699
700         return (0);
701
702 fail2:
703         EFSYS_PROBE(fail2);
704 fail1:
705         EFSYS_PROBE1(fail1, efx_rc_t, rc);
706         return (rc);
707 }
708
709 typedef struct efx_mae_action_desc_s {
710         /* Action specific handler */
711         efx_rc_t        (*emad_add)(efx_mae_actions_t *,
712                                     size_t, const uint8_t *);
713 } efx_mae_action_desc_t;
714
715 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
716         [EFX_MAE_ACTION_VLAN_POP] = {
717                 .emad_add = efx_mae_action_set_add_vlan_pop
718         },
719         [EFX_MAE_ACTION_DELIVER] = {
720                 .emad_add = efx_mae_action_set_add_deliver
721         }
722 };
723
724 static const uint32_t efx_mae_action_ordered_map =
725         (1U << EFX_MAE_ACTION_VLAN_POP) |
726         (1U << EFX_MAE_ACTION_DELIVER);
727
728 static const uint32_t efx_mae_action_repeat_map =
729         (1U << EFX_MAE_ACTION_VLAN_POP);
730
731 /*
732  * Add an action to an action set.
733  *
734  * This has to be invoked in the desired action order.
735  * An out-of-order action request will be turned down.
736  */
737 static  __checkReturn                   efx_rc_t
738 efx_mae_action_set_spec_populate(
739         __in                            efx_mae_actions_t *spec,
740         __in                            efx_mae_action_t type,
741         __in                            size_t arg_size,
742         __in_bcount(arg_size)           const uint8_t *arg)
743 {
744         uint32_t action_mask;
745         efx_rc_t rc;
746
747         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
748             (sizeof (efx_mae_action_ordered_map) * 8));
749         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
750             (sizeof (efx_mae_action_repeat_map) * 8));
751
752         EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
753
754         if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
755                 rc = EINVAL;
756                 goto fail1;
757         }
758
759         action_mask = (1U << type);
760
761         if ((spec->ema_actions & action_mask) != 0) {
762                 /* The action set already contains this action. */
763                 if ((efx_mae_action_repeat_map & action_mask) == 0) {
764                         /* Cannot add another non-repeatable action. */
765                         rc = ENOTSUP;
766                         goto fail2;
767                 }
768         }
769
770         if ((efx_mae_action_ordered_map & action_mask) != 0) {
771                 uint32_t later_actions_mask =
772                         efx_mae_action_ordered_map &
773                         ~(action_mask | (action_mask - 1));
774
775                 if ((spec->ema_actions & later_actions_mask) != 0) {
776                         /* Cannot add an action after later ordered actions. */
777                         rc = ENOTSUP;
778                         goto fail3;
779                 }
780         }
781
782         if (efx_mae_actions[type].emad_add != NULL) {
783                 rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
784                 if (rc != 0)
785                         goto fail4;
786         }
787
788         spec->ema_actions |= action_mask;
789
790         return (0);
791
792 fail4:
793         EFSYS_PROBE(fail4);
794 fail3:
795         EFSYS_PROBE(fail3);
796 fail2:
797         EFSYS_PROBE(fail2);
798 fail1:
799         EFSYS_PROBE1(fail1, efx_rc_t, rc);
800         return (rc);
801 }
802
803         __checkReturn                   efx_rc_t
804 efx_mae_action_set_populate_vlan_pop(
805         __in                            efx_mae_actions_t *spec)
806 {
807         return (efx_mae_action_set_spec_populate(spec,
808             EFX_MAE_ACTION_VLAN_POP, 0, NULL));
809 }
810
811         __checkReturn                   efx_rc_t
812 efx_mae_action_set_populate_deliver(
813         __in                            efx_mae_actions_t *spec,
814         __in                            const efx_mport_sel_t *mportp)
815 {
816         const uint8_t *arg;
817         efx_rc_t rc;
818
819         if (mportp == NULL) {
820                 rc = EINVAL;
821                 goto fail1;
822         }
823
824         arg = (const uint8_t *)&mportp->sel;
825
826         return (efx_mae_action_set_spec_populate(spec,
827             EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
828
829 fail1:
830         EFSYS_PROBE1(fail1, efx_rc_t, rc);
831         return (rc);
832 }
833
834         __checkReturn                   boolean_t
835 efx_mae_action_set_specs_equal(
836         __in                            const efx_mae_actions_t *left,
837         __in                            const efx_mae_actions_t *right)
838 {
839         return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
840 }
841
842         __checkReturn                   efx_rc_t
843 efx_mae_match_specs_class_cmp(
844         __in                            efx_nic_t *enp,
845         __in                            const efx_mae_match_spec_t *left,
846         __in                            const efx_mae_match_spec_t *right,
847         __out                           boolean_t *have_same_classp)
848 {
849         efx_mae_t *maep = enp->en_maep;
850         unsigned int field_ncaps = maep->em_max_nfields;
851         const efx_mae_field_cap_t *field_caps;
852         const efx_mae_mv_desc_t *desc_setp;
853         unsigned int desc_set_nentries;
854         boolean_t have_same_class = B_TRUE;
855         efx_mae_field_id_t field_id;
856         const uint8_t *mvpl;
857         const uint8_t *mvpr;
858         efx_rc_t rc;
859
860         switch (left->emms_type) {
861         case EFX_MAE_RULE_ACTION:
862                 field_caps = maep->em_action_rule_field_caps;
863                 desc_setp = __efx_mae_action_rule_mv_desc_set;
864                 desc_set_nentries =
865                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
866                 mvpl = left->emms_mask_value_pairs.action;
867                 mvpr = right->emms_mask_value_pairs.action;
868                 break;
869         default:
870                 rc = ENOTSUP;
871                 goto fail1;
872         }
873
874         if (field_caps == NULL) {
875                 rc = EAGAIN;
876                 goto fail2;
877         }
878
879         if (left->emms_type != right->emms_type ||
880             left->emms_prio != right->emms_prio) {
881                 /*
882                  * Rules of different types can never map to the same class.
883                  *
884                  * The FW can support some set of match criteria for one
885                  * priority and not support the very same set for
886                  * another priority. Thus, two rules which have
887                  * different priorities can never map to
888                  * the same class.
889                  */
890                 *have_same_classp = B_FALSE;
891                 return (0);
892         }
893
894         for (field_id = 0; field_id < desc_set_nentries; ++field_id) {
895                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
896                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
897
898                 if (descp->emmd_mask_size == 0)
899                         continue; /* Skip array gap */
900
901                 if (field_cap_id >= field_ncaps)
902                         break;
903
904                 if (field_caps[field_cap_id].emfc_mask_affects_class) {
905                         const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
906                         const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
907                         size_t mask_size = descp->emmd_mask_size;
908
909                         if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
910                                 have_same_class = B_FALSE;
911                                 break;
912                         }
913                 }
914
915                 if (field_caps[field_cap_id].emfc_match_affects_class) {
916                         const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
917                         const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
918                         size_t value_size = descp->emmd_value_size;
919
920                         if (memcmp(lvalp, rvalp, value_size) != 0) {
921                                 have_same_class = B_FALSE;
922                                 break;
923                         }
924                 }
925         }
926
927         *have_same_classp = have_same_class;
928
929         return (0);
930
931 fail2:
932         EFSYS_PROBE(fail2);
933 fail1:
934         EFSYS_PROBE1(fail1, efx_rc_t, rc);
935         return (rc);
936 }
937
938         __checkReturn                   efx_rc_t
939 efx_mae_action_set_alloc(
940         __in                            efx_nic_t *enp,
941         __in                            const efx_mae_actions_t *spec,
942         __out                           efx_mae_aset_id_t *aset_idp)
943 {
944         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
945         efx_mcdi_req_t req;
946         EFX_MCDI_DECLARE_BUF(payload,
947             MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
948             MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
949         efx_mae_aset_id_t aset_id;
950         efx_rc_t rc;
951
952         if (encp->enc_mae_supported == B_FALSE) {
953                 rc = ENOTSUP;
954                 goto fail1;
955         }
956
957         req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
958         req.emr_in_buf = payload;
959         req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
960         req.emr_out_buf = payload;
961         req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
962
963         /*
964          * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
965          * corresponding resource types are supported by the implementation.
966          * Use proper resource ID assignments instead.
967          */
968         MCDI_IN_SET_DWORD(req,
969             MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
970         MCDI_IN_SET_DWORD(req,
971             MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
972         MCDI_IN_SET_DWORD(req,
973             MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, EFX_MAE_RSRC_ID_INVALID);
974
975         MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
976             MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
977
978         MCDI_IN_SET_DWORD(req,
979             MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
980
981         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
982             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
983         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
984             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
985
986         efx_mcdi_execute(enp, &req);
987
988         if (req.emr_rc != 0) {
989                 rc = req.emr_rc;
990                 goto fail2;
991         }
992
993         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
994                 rc = EMSGSIZE;
995                 goto fail3;
996         }
997
998         aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
999         if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
1000                 rc = ENOENT;
1001                 goto fail4;
1002         }
1003
1004         aset_idp->id = aset_id.id;
1005
1006         return (0);
1007
1008 fail4:
1009         EFSYS_PROBE(fail4);
1010 fail3:
1011         EFSYS_PROBE(fail3);
1012 fail2:
1013         EFSYS_PROBE(fail2);
1014 fail1:
1015         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1016         return (rc);
1017 }
1018
1019         __checkReturn                   efx_rc_t
1020 efx_mae_action_set_free(
1021         __in                            efx_nic_t *enp,
1022         __in                            const efx_mae_aset_id_t *aset_idp)
1023 {
1024         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1025         efx_mcdi_req_t req;
1026         EFX_MCDI_DECLARE_BUF(payload,
1027             MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
1028             MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
1029         efx_rc_t rc;
1030
1031         if (encp->enc_mae_supported == B_FALSE) {
1032                 rc = ENOTSUP;
1033                 goto fail1;
1034         }
1035
1036         req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
1037         req.emr_in_buf = payload;
1038         req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
1039         req.emr_out_buf = payload;
1040         req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
1041
1042         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
1043
1044         efx_mcdi_execute(enp, &req);
1045
1046         if (req.emr_rc != 0) {
1047                 rc = req.emr_rc;
1048                 goto fail2;
1049         }
1050
1051         if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
1052             aset_idp->id) {
1053                 /* Firmware failed to free the action set. */
1054                 rc = EAGAIN;
1055                 goto fail3;
1056         }
1057
1058         return (0);
1059
1060 fail3:
1061         EFSYS_PROBE(fail3);
1062 fail2:
1063         EFSYS_PROBE(fail2);
1064 fail1:
1065         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1066         return (rc);
1067 }
1068
1069         __checkReturn                   efx_rc_t
1070 efx_mae_action_rule_insert(
1071         __in                            efx_nic_t *enp,
1072         __in                            const efx_mae_match_spec_t *spec,
1073         __in                            const efx_mae_aset_list_id_t *asl_idp,
1074         __in                            const efx_mae_aset_id_t *as_idp,
1075         __out                           efx_mae_rule_id_t *ar_idp)
1076 {
1077         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1078         efx_mcdi_req_t req;
1079         EFX_MCDI_DECLARE_BUF(payload,
1080             MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2,
1081             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
1082         efx_oword_t *rule_response;
1083         efx_mae_rule_id_t ar_id;
1084         size_t offset;
1085         efx_rc_t rc;
1086
1087         EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
1088             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
1089
1090         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1091             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
1092
1093         if (encp->enc_mae_supported == B_FALSE) {
1094                 rc = ENOTSUP;
1095                 goto fail1;
1096         }
1097
1098         if (spec->emms_type != EFX_MAE_RULE_ACTION ||
1099             (asl_idp != NULL && as_idp != NULL) ||
1100             (asl_idp == NULL && as_idp == NULL)) {
1101                 rc = EINVAL;
1102                 goto fail2;
1103         }
1104
1105         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
1106         req.emr_in_buf = payload;
1107         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
1108         req.emr_out_buf = payload;
1109         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
1110
1111         EFX_STATIC_ASSERT(sizeof (*rule_response) <=
1112             MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
1113         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
1114         rule_response = (efx_oword_t *)(payload + offset);
1115         EFX_POPULATE_OWORD_3(*rule_response,
1116             MAE_ACTION_RULE_RESPONSE_ASL_ID,
1117             (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
1118             MAE_ACTION_RULE_RESPONSE_AS_ID,
1119             (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
1120             MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
1121
1122         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
1123
1124         /*
1125          * Mask-value pairs have been stored in the byte order needed for the
1126          * MCDI request and are thus safe to be copied directly to the buffer.
1127          */
1128         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
1129             MAE_FIELD_MASK_VALUE_PAIRS_LEN);
1130         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
1131         memcpy(payload + offset, spec->emms_mask_value_pairs.action,
1132             MAE_FIELD_MASK_VALUE_PAIRS_LEN);
1133
1134         efx_mcdi_execute(enp, &req);
1135
1136         if (req.emr_rc != 0) {
1137                 rc = req.emr_rc;
1138                 goto fail3;
1139         }
1140
1141         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
1142                 rc = EMSGSIZE;
1143                 goto fail4;
1144         }
1145
1146         ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
1147         if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
1148                 rc = ENOENT;
1149                 goto fail5;
1150         }
1151
1152         ar_idp->id = ar_id.id;
1153
1154         return (0);
1155
1156 fail5:
1157         EFSYS_PROBE(fail5);
1158 fail4:
1159         EFSYS_PROBE(fail4);
1160 fail3:
1161         EFSYS_PROBE(fail3);
1162 fail2:
1163         EFSYS_PROBE(fail2);
1164 fail1:
1165         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1166         return (rc);
1167 }
1168
1169         __checkReturn                   efx_rc_t
1170 efx_mae_action_rule_remove(
1171         __in                            efx_nic_t *enp,
1172         __in                            const efx_mae_rule_id_t *ar_idp)
1173 {
1174         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1175         efx_mcdi_req_t req;
1176         EFX_MCDI_DECLARE_BUF(payload,
1177             MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
1178             MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
1179         efx_rc_t rc;
1180
1181         if (encp->enc_mae_supported == B_FALSE) {
1182                 rc = ENOTSUP;
1183                 goto fail1;
1184         }
1185
1186         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
1187         req.emr_in_buf = payload;
1188         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
1189         req.emr_out_buf = payload;
1190         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
1191
1192         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
1193
1194         efx_mcdi_execute(enp, &req);
1195
1196         if (req.emr_rc != 0) {
1197                 rc = req.emr_rc;
1198                 goto fail2;
1199         }
1200
1201         if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
1202             ar_idp->id) {
1203                 /* Firmware failed to delete the action rule. */
1204                 rc = EAGAIN;
1205                 goto fail3;
1206         }
1207
1208         return (0);
1209
1210 fail3:
1211         EFSYS_PROBE(fail3);
1212 fail2:
1213         EFSYS_PROBE(fail2);
1214 fail1:
1215         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1216         return (rc);
1217 }
1218
1219 #endif /* EFSYS_OPT_MAE */