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