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