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