common/sfc_efx/base: add max MAE counters to limits
[dpdk.git] / drivers / common / sfc_efx / base / efx_mae.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2019-2021 Xilinx, Inc.
4  */
5
6 #include "efx.h"
7 #include "efx_impl.h"
8
9
10 #if EFSYS_OPT_MAE
11
12 static  __checkReturn                   efx_rc_t
13 efx_mae_get_capabilities(
14         __in                            efx_nic_t *enp)
15 {
16         efx_mcdi_req_t req;
17         EFX_MCDI_DECLARE_BUF(payload,
18             MC_CMD_MAE_GET_CAPS_IN_LEN,
19             MC_CMD_MAE_GET_CAPS_OUT_LEN);
20         struct efx_mae_s *maep = enp->en_maep;
21         efx_rc_t rc;
22
23         req.emr_cmd = MC_CMD_MAE_GET_CAPS;
24         req.emr_in_buf = payload;
25         req.emr_in_length = MC_CMD_MAE_GET_CAPS_IN_LEN;
26         req.emr_out_buf = payload;
27         req.emr_out_length = MC_CMD_MAE_GET_CAPS_OUT_LEN;
28
29         efx_mcdi_execute(enp, &req);
30
31         if (req.emr_rc != 0) {
32                 rc = req.emr_rc;
33                 goto fail1;
34         }
35
36         if (req.emr_out_length_used < MC_CMD_MAE_GET_CAPS_OUT_LEN) {
37                 rc = EMSGSIZE;
38                 goto fail2;
39         }
40
41         maep->em_max_n_outer_prios =
42             MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_OUTER_PRIOS);
43
44         maep->em_max_n_action_prios =
45             MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ACTION_PRIOS);
46
47         maep->em_encap_types_supported = 0;
48
49         if (MCDI_OUT_DWORD_FIELD(req, MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED,
50             MAE_GET_CAPS_OUT_ENCAP_TYPE_VXLAN) != 0) {
51                 maep->em_encap_types_supported |=
52                     (1U << EFX_TUNNEL_PROTOCOL_VXLAN);
53         }
54
55         if (MCDI_OUT_DWORD_FIELD(req, MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED,
56             MAE_GET_CAPS_OUT_ENCAP_TYPE_GENEVE) != 0) {
57                 maep->em_encap_types_supported |=
58                     (1U << EFX_TUNNEL_PROTOCOL_GENEVE);
59         }
60
61         if (MCDI_OUT_DWORD_FIELD(req, MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED,
62             MAE_GET_CAPS_OUT_ENCAP_TYPE_NVGRE) != 0) {
63                 maep->em_encap_types_supported |=
64                     (1U << EFX_TUNNEL_PROTOCOL_NVGRE);
65         }
66
67         maep->em_max_nfields =
68             MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT);
69
70         maep->em_max_ncounters =
71             MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_COUNTERS);
72
73         return (0);
74
75 fail2:
76         EFSYS_PROBE(fail2);
77 fail1:
78         EFSYS_PROBE1(fail1, efx_rc_t, rc);
79         return (rc);
80 }
81
82 static  __checkReturn                   efx_rc_t
83 efx_mae_get_outer_rule_caps(
84         __in                            efx_nic_t *enp,
85         __in                            unsigned int field_ncaps,
86         __out_ecount(field_ncaps)       efx_mae_field_cap_t *field_caps)
87 {
88         efx_mcdi_req_t req;
89         EFX_MCDI_DECLARE_BUF(payload,
90             MC_CMD_MAE_GET_OR_CAPS_IN_LEN,
91             MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2);
92         unsigned int mcdi_field_ncaps;
93         unsigned int i;
94         efx_rc_t rc;
95
96         if (MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps) >
97             MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2) {
98                 rc = EINVAL;
99                 goto fail1;
100         }
101
102         req.emr_cmd = MC_CMD_MAE_GET_OR_CAPS;
103         req.emr_in_buf = payload;
104         req.emr_in_length = MC_CMD_MAE_GET_OR_CAPS_IN_LEN;
105         req.emr_out_buf = payload;
106         req.emr_out_length = MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps);
107
108         efx_mcdi_execute(enp, &req);
109
110         if (req.emr_rc != 0) {
111                 rc = req.emr_rc;
112                 goto fail2;
113         }
114
115         if (req.emr_out_length_used < MC_CMD_MAE_GET_OR_CAPS_OUT_LENMIN) {
116                 rc = EMSGSIZE;
117                 goto fail3;
118         }
119
120         mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_OR_CAPS_OUT_COUNT);
121
122         if (req.emr_out_length_used <
123             MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(mcdi_field_ncaps)) {
124                 rc = EMSGSIZE;
125                 goto fail4;
126         }
127
128         if (mcdi_field_ncaps > field_ncaps) {
129                 rc = EMSGSIZE;
130                 goto fail5;
131         }
132
133         for (i = 0; i < mcdi_field_ncaps; ++i) {
134                 uint32_t match_flag;
135                 uint32_t mask_flag;
136
137                 field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req,
138                     MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
139                     MAE_FIELD_FLAGS_SUPPORT_STATUS);
140
141                 match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
142                     MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
143                     MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS);
144
145                 field_caps[i].emfc_match_affects_class =
146                     (match_flag != 0) ? B_TRUE : B_FALSE;
147
148                 mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
149                     MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
150                     MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS);
151
152                 field_caps[i].emfc_mask_affects_class =
153                     (mask_flag != 0) ? B_TRUE : B_FALSE;
154         }
155
156         return (0);
157
158 fail5:
159         EFSYS_PROBE(fail5);
160 fail4:
161         EFSYS_PROBE(fail4);
162 fail3:
163         EFSYS_PROBE(fail3);
164 fail2:
165         EFSYS_PROBE(fail2);
166 fail1:
167         EFSYS_PROBE1(fail1, efx_rc_t, rc);
168         return (rc);
169 }
170
171 static  __checkReturn                   efx_rc_t
172 efx_mae_get_action_rule_caps(
173         __in                            efx_nic_t *enp,
174         __in                            unsigned int field_ncaps,
175         __out_ecount(field_ncaps)       efx_mae_field_cap_t *field_caps)
176 {
177         efx_mcdi_req_t req;
178         EFX_MCDI_DECLARE_BUF(payload,
179             MC_CMD_MAE_GET_AR_CAPS_IN_LEN,
180             MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2);
181         unsigned int mcdi_field_ncaps;
182         unsigned int i;
183         efx_rc_t rc;
184
185         if (MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps) >
186             MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2) {
187                 rc = EINVAL;
188                 goto fail1;
189         }
190
191         req.emr_cmd = MC_CMD_MAE_GET_AR_CAPS;
192         req.emr_in_buf = payload;
193         req.emr_in_length = MC_CMD_MAE_GET_AR_CAPS_IN_LEN;
194         req.emr_out_buf = payload;
195         req.emr_out_length = MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps);
196
197         efx_mcdi_execute(enp, &req);
198
199         if (req.emr_rc != 0) {
200                 rc = req.emr_rc;
201                 goto fail2;
202         }
203
204         if (req.emr_out_length_used < MC_CMD_MAE_GET_AR_CAPS_OUT_LENMIN) {
205                 rc = EMSGSIZE;
206                 goto fail3;
207         }
208
209         mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_AR_CAPS_OUT_COUNT);
210
211         if (req.emr_out_length_used <
212             MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(mcdi_field_ncaps)) {
213                 rc = EMSGSIZE;
214                 goto fail4;
215         }
216
217         if (mcdi_field_ncaps > field_ncaps) {
218                 rc = EMSGSIZE;
219                 goto fail5;
220         }
221
222         for (i = 0; i < mcdi_field_ncaps; ++i) {
223                 uint32_t match_flag;
224                 uint32_t mask_flag;
225
226                 field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req,
227                     MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
228                     MAE_FIELD_FLAGS_SUPPORT_STATUS);
229
230                 match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
231                     MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
232                     MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS);
233
234                 field_caps[i].emfc_match_affects_class =
235                     (match_flag != 0) ? B_TRUE : B_FALSE;
236
237                 mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
238                     MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
239                     MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS);
240
241                 field_caps[i].emfc_mask_affects_class =
242                     (mask_flag != 0) ? B_TRUE : B_FALSE;
243         }
244
245         return (0);
246
247 fail5:
248         EFSYS_PROBE(fail5);
249 fail4:
250         EFSYS_PROBE(fail4);
251 fail3:
252         EFSYS_PROBE(fail3);
253 fail2:
254         EFSYS_PROBE(fail2);
255 fail1:
256         EFSYS_PROBE1(fail1, efx_rc_t, rc);
257         return (rc);
258 }
259
260         __checkReturn                   efx_rc_t
261 efx_mae_init(
262         __in                            efx_nic_t *enp)
263 {
264         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
265         efx_mae_field_cap_t *or_fcaps;
266         size_t or_fcaps_size;
267         efx_mae_field_cap_t *ar_fcaps;
268         size_t ar_fcaps_size;
269         efx_mae_t *maep;
270         efx_rc_t rc;
271
272         if (encp->enc_mae_supported == B_FALSE) {
273                 rc = ENOTSUP;
274                 goto fail1;
275         }
276
277         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*maep), maep);
278         if (maep == NULL) {
279                 rc = ENOMEM;
280                 goto fail2;
281         }
282
283         enp->en_maep = maep;
284
285         rc = efx_mae_get_capabilities(enp);
286         if (rc != 0)
287                 goto fail3;
288
289         or_fcaps_size = maep->em_max_nfields * sizeof (*or_fcaps);
290         EFSYS_KMEM_ALLOC(enp->en_esip, or_fcaps_size, or_fcaps);
291         if (or_fcaps == NULL) {
292                 rc = ENOMEM;
293                 goto fail4;
294         }
295
296         maep->em_outer_rule_field_caps_size = or_fcaps_size;
297         maep->em_outer_rule_field_caps = or_fcaps;
298
299         rc = efx_mae_get_outer_rule_caps(enp, maep->em_max_nfields, or_fcaps);
300         if (rc != 0)
301                 goto fail5;
302
303         ar_fcaps_size = maep->em_max_nfields * sizeof (*ar_fcaps);
304         EFSYS_KMEM_ALLOC(enp->en_esip, ar_fcaps_size, ar_fcaps);
305         if (ar_fcaps == NULL) {
306                 rc = ENOMEM;
307                 goto fail6;
308         }
309
310         maep->em_action_rule_field_caps_size = ar_fcaps_size;
311         maep->em_action_rule_field_caps = ar_fcaps;
312
313         rc = efx_mae_get_action_rule_caps(enp, maep->em_max_nfields, ar_fcaps);
314         if (rc != 0)
315                 goto fail7;
316
317         return (0);
318
319 fail7:
320         EFSYS_PROBE(fail5);
321         EFSYS_KMEM_FREE(enp->en_esip, ar_fcaps_size, ar_fcaps);
322 fail6:
323         EFSYS_PROBE(fail4);
324 fail5:
325         EFSYS_PROBE(fail5);
326         EFSYS_KMEM_FREE(enp->en_esip, or_fcaps_size, or_fcaps);
327 fail4:
328         EFSYS_PROBE(fail4);
329 fail3:
330         EFSYS_PROBE(fail3);
331         EFSYS_KMEM_FREE(enp->en_esip, sizeof (struct efx_mae_s), enp->en_maep);
332         enp->en_maep = NULL;
333 fail2:
334         EFSYS_PROBE(fail2);
335 fail1:
336         EFSYS_PROBE1(fail1, efx_rc_t, rc);
337         return (rc);
338 }
339
340                                         void
341 efx_mae_fini(
342         __in                            efx_nic_t *enp)
343 {
344         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
345         efx_mae_t *maep = enp->en_maep;
346
347         if (encp->enc_mae_supported == B_FALSE)
348                 return;
349
350         EFSYS_KMEM_FREE(enp->en_esip, maep->em_action_rule_field_caps_size,
351             maep->em_action_rule_field_caps);
352         EFSYS_KMEM_FREE(enp->en_esip, maep->em_outer_rule_field_caps_size,
353             maep->em_outer_rule_field_caps);
354         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*maep), maep);
355         enp->en_maep = NULL;
356 }
357
358         __checkReturn                   efx_rc_t
359 efx_mae_get_limits(
360         __in                            efx_nic_t *enp,
361         __out                           efx_mae_limits_t *emlp)
362 {
363         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
364         struct efx_mae_s *maep = enp->en_maep;
365         efx_rc_t rc;
366
367         if (encp->enc_mae_supported == B_FALSE) {
368                 rc = ENOTSUP;
369                 goto fail1;
370         }
371
372         emlp->eml_max_n_outer_prios = maep->em_max_n_outer_prios;
373         emlp->eml_max_n_action_prios = maep->em_max_n_action_prios;
374         emlp->eml_encap_types_supported = maep->em_encap_types_supported;
375         emlp->eml_encap_header_size_limit =
376             MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2;
377         emlp->eml_max_n_counters = maep->em_max_ncounters;
378
379         return (0);
380
381 fail1:
382         EFSYS_PROBE1(fail1, efx_rc_t, rc);
383         return (rc);
384 }
385
386         __checkReturn                   efx_rc_t
387 efx_mae_match_spec_init(
388         __in                            efx_nic_t *enp,
389         __in                            efx_mae_rule_type_t type,
390         __in                            uint32_t prio,
391         __out                           efx_mae_match_spec_t **specp)
392 {
393         efx_mae_match_spec_t *spec;
394         efx_rc_t rc;
395
396         switch (type) {
397         case EFX_MAE_RULE_OUTER:
398                 break;
399         case EFX_MAE_RULE_ACTION:
400                 break;
401         default:
402                 rc = ENOTSUP;
403                 goto fail1;
404         }
405
406         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
407         if (spec == NULL) {
408                 rc = ENOMEM;
409                 goto fail2;
410         }
411
412         spec->emms_type = type;
413         spec->emms_prio = prio;
414
415         *specp = spec;
416
417         return (0);
418
419 fail2:
420         EFSYS_PROBE(fail2);
421 fail1:
422         EFSYS_PROBE1(fail1, efx_rc_t, rc);
423         return (rc);
424 }
425
426                                         void
427 efx_mae_match_spec_fini(
428         __in                            efx_nic_t *enp,
429         __in                            efx_mae_match_spec_t *spec)
430 {
431         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
432 }
433
434 /* Named identifiers which are valid indices to efx_mae_field_cap_t */
435 typedef enum efx_mae_field_cap_id_e {
436         EFX_MAE_FIELD_ID_INGRESS_MPORT_SELECTOR = MAE_FIELD_INGRESS_PORT,
437         EFX_MAE_FIELD_ID_ETHER_TYPE_BE = MAE_FIELD_ETHER_TYPE,
438         EFX_MAE_FIELD_ID_ETH_SADDR_BE = MAE_FIELD_ETH_SADDR,
439         EFX_MAE_FIELD_ID_ETH_DADDR_BE = MAE_FIELD_ETH_DADDR,
440         EFX_MAE_FIELD_ID_VLAN0_TCI_BE = MAE_FIELD_VLAN0_TCI,
441         EFX_MAE_FIELD_ID_VLAN0_PROTO_BE = MAE_FIELD_VLAN0_PROTO,
442         EFX_MAE_FIELD_ID_VLAN1_TCI_BE = MAE_FIELD_VLAN1_TCI,
443         EFX_MAE_FIELD_ID_VLAN1_PROTO_BE = MAE_FIELD_VLAN1_PROTO,
444         EFX_MAE_FIELD_ID_SRC_IP4_BE = MAE_FIELD_SRC_IP4,
445         EFX_MAE_FIELD_ID_DST_IP4_BE = MAE_FIELD_DST_IP4,
446         EFX_MAE_FIELD_ID_IP_PROTO = MAE_FIELD_IP_PROTO,
447         EFX_MAE_FIELD_ID_IP_TOS = MAE_FIELD_IP_TOS,
448         EFX_MAE_FIELD_ID_IP_TTL = MAE_FIELD_IP_TTL,
449         EFX_MAE_FIELD_ID_SRC_IP6_BE = MAE_FIELD_SRC_IP6,
450         EFX_MAE_FIELD_ID_DST_IP6_BE = MAE_FIELD_DST_IP6,
451         EFX_MAE_FIELD_ID_L4_SPORT_BE = MAE_FIELD_L4_SPORT,
452         EFX_MAE_FIELD_ID_L4_DPORT_BE = MAE_FIELD_L4_DPORT,
453         EFX_MAE_FIELD_ID_TCP_FLAGS_BE = MAE_FIELD_TCP_FLAGS,
454         EFX_MAE_FIELD_ID_ENC_ETHER_TYPE_BE = MAE_FIELD_ENC_ETHER_TYPE,
455         EFX_MAE_FIELD_ID_ENC_ETH_SADDR_BE = MAE_FIELD_ENC_ETH_SADDR,
456         EFX_MAE_FIELD_ID_ENC_ETH_DADDR_BE = MAE_FIELD_ENC_ETH_DADDR,
457         EFX_MAE_FIELD_ID_ENC_VLAN0_TCI_BE = MAE_FIELD_ENC_VLAN0_TCI,
458         EFX_MAE_FIELD_ID_ENC_VLAN0_PROTO_BE = MAE_FIELD_ENC_VLAN0_PROTO,
459         EFX_MAE_FIELD_ID_ENC_VLAN1_TCI_BE = MAE_FIELD_ENC_VLAN1_TCI,
460         EFX_MAE_FIELD_ID_ENC_VLAN1_PROTO_BE = MAE_FIELD_ENC_VLAN1_PROTO,
461         EFX_MAE_FIELD_ID_ENC_SRC_IP4_BE = MAE_FIELD_ENC_SRC_IP4,
462         EFX_MAE_FIELD_ID_ENC_DST_IP4_BE = MAE_FIELD_ENC_DST_IP4,
463         EFX_MAE_FIELD_ID_ENC_IP_PROTO = MAE_FIELD_ENC_IP_PROTO,
464         EFX_MAE_FIELD_ID_ENC_IP_TOS = MAE_FIELD_ENC_IP_TOS,
465         EFX_MAE_FIELD_ID_ENC_IP_TTL = MAE_FIELD_ENC_IP_TTL,
466         EFX_MAE_FIELD_ID_ENC_SRC_IP6_BE = MAE_FIELD_ENC_SRC_IP6,
467         EFX_MAE_FIELD_ID_ENC_DST_IP6_BE = MAE_FIELD_ENC_DST_IP6,
468         EFX_MAE_FIELD_ID_ENC_L4_SPORT_BE = MAE_FIELD_ENC_L4_SPORT,
469         EFX_MAE_FIELD_ID_ENC_L4_DPORT_BE = MAE_FIELD_ENC_L4_DPORT,
470         EFX_MAE_FIELD_ID_ENC_VNET_ID_BE = MAE_FIELD_ENC_VNET_ID,
471         EFX_MAE_FIELD_ID_OUTER_RULE_ID = MAE_FIELD_OUTER_RULE_ID,
472         EFX_MAE_FIELD_ID_HAS_OVLAN = MAE_FIELD_HAS_OVLAN,
473         EFX_MAE_FIELD_ID_HAS_IVLAN = MAE_FIELD_HAS_IVLAN,
474         EFX_MAE_FIELD_ID_ENC_HAS_OVLAN = MAE_FIELD_ENC_HAS_OVLAN,
475         EFX_MAE_FIELD_ID_ENC_HAS_IVLAN = MAE_FIELD_ENC_HAS_IVLAN,
476
477         EFX_MAE_FIELD_CAP_NIDS
478 } efx_mae_field_cap_id_t;
479
480 typedef enum efx_mae_field_endianness_e {
481         EFX_MAE_FIELD_LE = 0,
482         EFX_MAE_FIELD_BE,
483
484         EFX_MAE_FIELD_ENDIANNESS_NTYPES
485 } efx_mae_field_endianness_t;
486
487 /*
488  * The following structure is a means to describe an MAE field.
489  * The information in it is meant to be used internally by
490  * APIs for addressing a given field in a mask-value pairs
491  * structure and for validation purposes.
492  *
493  * A field may have an alternative one. This structure
494  * has additional members to reference the alternative
495  * field's mask. See efx_mae_match_spec_is_valid().
496  */
497 typedef struct efx_mae_mv_desc_s {
498         efx_mae_field_cap_id_t          emmd_field_cap_id;
499
500         size_t                          emmd_value_size;
501         size_t                          emmd_value_offset;
502         size_t                          emmd_mask_size;
503         size_t                          emmd_mask_offset;
504
505         /*
506          * Having the alternative field's mask size set to 0
507          * means that there's no alternative field specified.
508          */
509         size_t                          emmd_alt_mask_size;
510         size_t                          emmd_alt_mask_offset;
511
512         /* Primary field and the alternative one are of the same endianness. */
513         efx_mae_field_endianness_t      emmd_endianness;
514 } efx_mae_mv_desc_t;
515
516 /* Indices to this array are provided by efx_mae_field_id_t */
517 static const efx_mae_mv_desc_t __efx_mae_action_rule_mv_desc_set[] = {
518 #define EFX_MAE_MV_DESC(_name, _endianness)                             \
519         [EFX_MAE_FIELD_##_name] =                                       \
520         {                                                               \
521                 EFX_MAE_FIELD_ID_##_name,                               \
522                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_LEN,               \
523                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_OFST,              \
524                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_LEN,          \
525                 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_OFST,         \
526                 0, 0 /* no alternative field */,                        \
527                 _endianness                                             \
528         }
529
530         EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
531         EFX_MAE_MV_DESC(ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
532         EFX_MAE_MV_DESC(ETH_SADDR_BE, EFX_MAE_FIELD_BE),
533         EFX_MAE_MV_DESC(ETH_DADDR_BE, EFX_MAE_FIELD_BE),
534         EFX_MAE_MV_DESC(VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
535         EFX_MAE_MV_DESC(VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
536         EFX_MAE_MV_DESC(VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
537         EFX_MAE_MV_DESC(VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
538         EFX_MAE_MV_DESC(SRC_IP4_BE, EFX_MAE_FIELD_BE),
539         EFX_MAE_MV_DESC(DST_IP4_BE, EFX_MAE_FIELD_BE),
540         EFX_MAE_MV_DESC(IP_PROTO, EFX_MAE_FIELD_BE),
541         EFX_MAE_MV_DESC(IP_TOS, EFX_MAE_FIELD_BE),
542         EFX_MAE_MV_DESC(IP_TTL, EFX_MAE_FIELD_BE),
543         EFX_MAE_MV_DESC(SRC_IP6_BE, EFX_MAE_FIELD_BE),
544         EFX_MAE_MV_DESC(DST_IP6_BE, EFX_MAE_FIELD_BE),
545         EFX_MAE_MV_DESC(L4_SPORT_BE, EFX_MAE_FIELD_BE),
546         EFX_MAE_MV_DESC(L4_DPORT_BE, EFX_MAE_FIELD_BE),
547         EFX_MAE_MV_DESC(TCP_FLAGS_BE, EFX_MAE_FIELD_BE),
548         EFX_MAE_MV_DESC(ENC_VNET_ID_BE, EFX_MAE_FIELD_BE),
549         EFX_MAE_MV_DESC(OUTER_RULE_ID, EFX_MAE_FIELD_LE),
550
551 #undef EFX_MAE_MV_DESC
552 };
553
554 /* Indices to this array are provided by efx_mae_field_id_t */
555 static const efx_mae_mv_desc_t __efx_mae_outer_rule_mv_desc_set[] = {
556 #define EFX_MAE_MV_DESC(_name, _endianness)                             \
557         [EFX_MAE_FIELD_##_name] =                                       \
558         {                                                               \
559                 EFX_MAE_FIELD_ID_##_name,                               \
560                 MAE_ENC_FIELD_PAIRS_##_name##_LEN,                      \
561                 MAE_ENC_FIELD_PAIRS_##_name##_OFST,                     \
562                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,                 \
563                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,                \
564                 0, 0 /* no alternative field */,                        \
565                 _endianness                                             \
566         }
567
568 /* Same as EFX_MAE_MV_DESC(), but also indicates an alternative field. */
569 #define EFX_MAE_MV_DESC_ALT(_name, _alt_name, _endianness)              \
570         [EFX_MAE_FIELD_##_name] =                                       \
571         {                                                               \
572                 EFX_MAE_FIELD_ID_##_name,                               \
573                 MAE_ENC_FIELD_PAIRS_##_name##_LEN,                      \
574                 MAE_ENC_FIELD_PAIRS_##_name##_OFST,                     \
575                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,                 \
576                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,                \
577                 MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_LEN,             \
578                 MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_OFST,            \
579                 _endianness                                             \
580         }
581
582         EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
583         EFX_MAE_MV_DESC(ENC_ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
584         EFX_MAE_MV_DESC(ENC_ETH_SADDR_BE, EFX_MAE_FIELD_BE),
585         EFX_MAE_MV_DESC(ENC_ETH_DADDR_BE, EFX_MAE_FIELD_BE),
586         EFX_MAE_MV_DESC(ENC_VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
587         EFX_MAE_MV_DESC(ENC_VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
588         EFX_MAE_MV_DESC(ENC_VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
589         EFX_MAE_MV_DESC(ENC_VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
590         EFX_MAE_MV_DESC_ALT(ENC_SRC_IP4_BE, ENC_SRC_IP6_BE, EFX_MAE_FIELD_BE),
591         EFX_MAE_MV_DESC_ALT(ENC_DST_IP4_BE, ENC_DST_IP6_BE, EFX_MAE_FIELD_BE),
592         EFX_MAE_MV_DESC(ENC_IP_PROTO, EFX_MAE_FIELD_BE),
593         EFX_MAE_MV_DESC(ENC_IP_TOS, EFX_MAE_FIELD_BE),
594         EFX_MAE_MV_DESC(ENC_IP_TTL, EFX_MAE_FIELD_BE),
595         EFX_MAE_MV_DESC_ALT(ENC_SRC_IP6_BE, ENC_SRC_IP4_BE, EFX_MAE_FIELD_BE),
596         EFX_MAE_MV_DESC_ALT(ENC_DST_IP6_BE, ENC_DST_IP4_BE, EFX_MAE_FIELD_BE),
597         EFX_MAE_MV_DESC(ENC_L4_SPORT_BE, EFX_MAE_FIELD_BE),
598         EFX_MAE_MV_DESC(ENC_L4_DPORT_BE, EFX_MAE_FIELD_BE),
599
600 #undef EFX_MAE_MV_DESC_ALT
601 #undef EFX_MAE_MV_DESC
602 };
603
604 /*
605  * The following structure is a means to describe an MAE bit.
606  * The information in it is meant to be used internally by
607  * APIs for addressing a given flag in a mask-value pairs
608  * structure and for validation purposes.
609  */
610 typedef struct efx_mae_mv_bit_desc_s {
611         /*
612          * Arrays using this struct are indexed by field IDs.
613          * Fields which aren't meant to be referenced by these
614          * arrays comprise gaps (invalid entries). Below field
615          * helps to identify such entries.
616          */
617         boolean_t                       emmbd_entry_is_valid;
618         efx_mae_field_cap_id_t          emmbd_bit_cap_id;
619         size_t                          emmbd_value_ofst;
620         unsigned int                    emmbd_value_lbn;
621         size_t                          emmbd_mask_ofst;
622         unsigned int                    emmbd_mask_lbn;
623 } efx_mae_mv_bit_desc_t;
624
625 static const efx_mae_mv_bit_desc_t __efx_mae_outer_rule_mv_bit_desc_set[] = {
626 #define EFX_MAE_MV_BIT_DESC(_name)                                      \
627         [EFX_MAE_FIELD_##_name] =                                       \
628         {                                                               \
629                 B_TRUE,                                                 \
630                 EFX_MAE_FIELD_ID_##_name,                               \
631                 MAE_ENC_FIELD_PAIRS_##_name##_OFST,                     \
632                 MAE_ENC_FIELD_PAIRS_##_name##_LBN,                      \
633                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,                \
634                 MAE_ENC_FIELD_PAIRS_##_name##_MASK_LBN,                 \
635         }
636
637         EFX_MAE_MV_BIT_DESC(ENC_HAS_OVLAN),
638         EFX_MAE_MV_BIT_DESC(ENC_HAS_IVLAN),
639
640 #undef EFX_MAE_MV_BIT_DESC
641 };
642
643 static const efx_mae_mv_bit_desc_t __efx_mae_action_rule_mv_bit_desc_set[] = {
644 #define EFX_MAE_MV_BIT_DESC(_name)                                      \
645         [EFX_MAE_FIELD_##_name] =                                       \
646         {                                                               \
647                 B_TRUE,                                                 \
648                 EFX_MAE_FIELD_ID_##_name,                               \
649                 MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_OFST,               \
650                 MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LBN,            \
651                 MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK_OFST,          \
652                 MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LBN,            \
653         }
654
655         EFX_MAE_MV_BIT_DESC(HAS_OVLAN),
656         EFX_MAE_MV_BIT_DESC(HAS_IVLAN),
657         EFX_MAE_MV_BIT_DESC(ENC_HAS_OVLAN),
658         EFX_MAE_MV_BIT_DESC(ENC_HAS_IVLAN),
659
660 #undef EFX_MAE_MV_BIT_DESC
661 };
662
663         __checkReturn                   efx_rc_t
664 efx_mae_mport_by_phy_port(
665         __in                            uint32_t phy_port,
666         __out                           efx_mport_sel_t *mportp)
667 {
668         efx_dword_t dword;
669         efx_rc_t rc;
670
671         if (phy_port > EFX_MASK32(MAE_MPORT_SELECTOR_PPORT_ID)) {
672                 rc = EINVAL;
673                 goto fail1;
674         }
675
676         EFX_POPULATE_DWORD_2(dword,
677             MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT,
678             MAE_MPORT_SELECTOR_PPORT_ID, phy_port);
679
680         memset(mportp, 0, sizeof (*mportp));
681         /*
682          * The constructed DWORD is little-endian,
683          * but the resulting value is meant to be
684          * passed to MCDIs, where it will undergo
685          * host-order to little endian conversion.
686          */
687         mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
688
689         return (0);
690
691 fail1:
692         EFSYS_PROBE1(fail1, efx_rc_t, rc);
693         return (rc);
694 }
695
696         __checkReturn                   efx_rc_t
697 efx_mae_mport_by_pcie_function(
698         __in                            uint32_t pf,
699         __in                            uint32_t vf,
700         __out                           efx_mport_sel_t *mportp)
701 {
702         efx_dword_t dword;
703         efx_rc_t rc;
704
705         EFX_STATIC_ASSERT(EFX_PCI_VF_INVALID ==
706             MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL);
707
708         if (pf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_PF_ID)) {
709                 rc = EINVAL;
710                 goto fail1;
711         }
712
713         if (vf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_VF_ID)) {
714                 rc = EINVAL;
715                 goto fail2;
716         }
717
718         EFX_POPULATE_DWORD_3(dword,
719             MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
720             MAE_MPORT_SELECTOR_FUNC_PF_ID, pf,
721             MAE_MPORT_SELECTOR_FUNC_VF_ID, vf);
722
723         memset(mportp, 0, sizeof (*mportp));
724         /*
725          * The constructed DWORD is little-endian,
726          * but the resulting value is meant to be
727          * passed to MCDIs, where it will undergo
728          * host-order to little endian conversion.
729          */
730         mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
731
732         return (0);
733
734 fail2:
735         EFSYS_PROBE(fail2);
736 fail1:
737         EFSYS_PROBE1(fail1, efx_rc_t, rc);
738         return (rc);
739 }
740
741         __checkReturn                   efx_rc_t
742 efx_mae_match_spec_field_set(
743         __in                            efx_mae_match_spec_t *spec,
744         __in                            efx_mae_field_id_t field_id,
745         __in                            size_t value_size,
746         __in_bcount(value_size)         const uint8_t *value,
747         __in                            size_t mask_size,
748         __in_bcount(mask_size)          const uint8_t *mask)
749 {
750         const efx_mae_mv_desc_t *descp;
751         unsigned int desc_set_nentries;
752         uint8_t *mvp;
753         efx_rc_t rc;
754
755         switch (spec->emms_type) {
756         case EFX_MAE_RULE_OUTER:
757                 desc_set_nentries =
758                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
759                 descp = &__efx_mae_outer_rule_mv_desc_set[field_id];
760                 mvp = spec->emms_mask_value_pairs.outer;
761                 break;
762         case EFX_MAE_RULE_ACTION:
763                 desc_set_nentries =
764                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
765                 descp = &__efx_mae_action_rule_mv_desc_set[field_id];
766                 mvp = spec->emms_mask_value_pairs.action;
767                 break;
768         default:
769                 rc = ENOTSUP;
770                 goto fail1;
771         }
772
773         if ((unsigned int)field_id >= desc_set_nentries) {
774                 rc = EINVAL;
775                 goto fail2;
776         }
777
778         if (descp->emmd_mask_size == 0) {
779                 /* The ID points to a gap in the array of field descriptors. */
780                 rc = EINVAL;
781                 goto fail3;
782         }
783
784         if (value_size != descp->emmd_value_size) {
785                 rc = EINVAL;
786                 goto fail4;
787         }
788
789         if (mask_size != descp->emmd_mask_size) {
790                 rc = EINVAL;
791                 goto fail5;
792         }
793
794         if (descp->emmd_endianness == EFX_MAE_FIELD_BE) {
795                 unsigned int i;
796
797                 /*
798                  * The mask/value are in network (big endian) order.
799                  * The MCDI request field is also big endian.
800                  */
801
802                 EFSYS_ASSERT3U(value_size, ==, mask_size);
803
804                 for (i = 0; i < value_size; ++i) {
805                         uint8_t *v_bytep = mvp + descp->emmd_value_offset + i;
806                         uint8_t *m_bytep = mvp + descp->emmd_mask_offset + i;
807
808                         /*
809                          * Apply the mask (which may be all-zeros) to the value.
810                          *
811                          * If this API is provided with some value to set for a
812                          * given field in one specification and with some other
813                          * value to set for this field in another specification,
814                          * then, if the two masks are all-zeros, the field will
815                          * avoid being counted as a mismatch when comparing the
816                          * specifications using efx_mae_match_specs_equal() API.
817                          */
818                         *v_bytep = value[i] & mask[i];
819                         *m_bytep = mask[i];
820                 }
821         } else {
822                 efx_dword_t dword;
823
824                 /*
825                  * The mask/value are in host byte order.
826                  * The MCDI request field is little endian.
827                  */
828                 switch (value_size) {
829                 case 4:
830                         EFX_POPULATE_DWORD_1(dword,
831                             EFX_DWORD_0, *(const uint32_t *)value);
832
833                         memcpy(mvp + descp->emmd_value_offset,
834                             &dword, sizeof (dword));
835                         break;
836                 default:
837                         EFSYS_ASSERT(B_FALSE);
838                 }
839
840                 switch (mask_size) {
841                 case 4:
842                         EFX_POPULATE_DWORD_1(dword,
843                             EFX_DWORD_0, *(const uint32_t *)mask);
844
845                         memcpy(mvp + descp->emmd_mask_offset,
846                             &dword, sizeof (dword));
847                         break;
848                 default:
849                         EFSYS_ASSERT(B_FALSE);
850                 }
851         }
852
853         return (0);
854
855 fail5:
856         EFSYS_PROBE(fail5);
857 fail4:
858         EFSYS_PROBE(fail4);
859 fail3:
860         EFSYS_PROBE(fail3);
861 fail2:
862         EFSYS_PROBE(fail2);
863 fail1:
864         EFSYS_PROBE1(fail1, efx_rc_t, rc);
865         return (rc);
866 }
867
868         __checkReturn                   efx_rc_t
869 efx_mae_match_spec_bit_set(
870         __in                            efx_mae_match_spec_t *spec,
871         __in                            efx_mae_field_id_t field_id,
872         __in                            boolean_t value)
873 {
874         const efx_mae_mv_bit_desc_t *bit_descp;
875         unsigned int bit_desc_set_nentries;
876         unsigned int byte_idx;
877         unsigned int bit_idx;
878         uint8_t *mvp;
879         efx_rc_t rc;
880
881         switch (spec->emms_type) {
882         case EFX_MAE_RULE_OUTER:
883                 bit_desc_set_nentries =
884                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
885                 bit_descp = &__efx_mae_outer_rule_mv_bit_desc_set[field_id];
886                 mvp = spec->emms_mask_value_pairs.outer;
887                 break;
888         case EFX_MAE_RULE_ACTION:
889                 bit_desc_set_nentries =
890                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
891                 bit_descp = &__efx_mae_action_rule_mv_bit_desc_set[field_id];
892                 mvp = spec->emms_mask_value_pairs.action;
893                 break;
894         default:
895                 rc = ENOTSUP;
896                 goto fail1;
897         }
898
899         if ((unsigned int)field_id >= bit_desc_set_nentries) {
900                 rc = EINVAL;
901                 goto fail2;
902         }
903
904         if (bit_descp->emmbd_entry_is_valid == B_FALSE) {
905                 rc = EINVAL;
906                 goto fail3;
907         }
908
909         byte_idx = bit_descp->emmbd_value_ofst + bit_descp->emmbd_value_lbn / 8;
910         bit_idx = bit_descp->emmbd_value_lbn % 8;
911
912         if (value != B_FALSE)
913                 mvp[byte_idx] |= (1U << bit_idx);
914         else
915                 mvp[byte_idx] &= ~(1U << bit_idx);
916
917         byte_idx = bit_descp->emmbd_mask_ofst + bit_descp->emmbd_mask_lbn / 8;
918         bit_idx = bit_descp->emmbd_mask_lbn % 8;
919         mvp[byte_idx] |= (1U << bit_idx);
920
921         return (0);
922
923 fail3:
924         EFSYS_PROBE(fail3);
925 fail2:
926         EFSYS_PROBE(fail2);
927 fail1:
928         EFSYS_PROBE1(fail1, efx_rc_t, rc);
929         return (rc);
930 }
931
932         __checkReturn                   efx_rc_t
933 efx_mae_match_spec_mport_set(
934         __in                            efx_mae_match_spec_t *spec,
935         __in                            const efx_mport_sel_t *valuep,
936         __in_opt                        const efx_mport_sel_t *maskp)
937 {
938         uint32_t full_mask = UINT32_MAX;
939         const uint8_t *vp;
940         const uint8_t *mp;
941         efx_rc_t rc;
942
943         if (valuep == NULL) {
944                 rc = EINVAL;
945                 goto fail1;
946         }
947
948         vp = (const uint8_t *)&valuep->sel;
949         if (maskp != NULL)
950                 mp = (const uint8_t *)&maskp->sel;
951         else
952                 mp = (const uint8_t *)&full_mask;
953
954         rc = efx_mae_match_spec_field_set(spec,
955             EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR,
956             sizeof (valuep->sel), vp, sizeof (maskp->sel), mp);
957         if (rc != 0)
958                 goto fail2;
959
960         return (0);
961
962 fail2:
963         EFSYS_PROBE(fail2);
964 fail1:
965         EFSYS_PROBE1(fail1, efx_rc_t, rc);
966         return (rc);
967 }
968
969         __checkReturn                   boolean_t
970 efx_mae_match_specs_equal(
971         __in                            const efx_mae_match_spec_t *left,
972         __in                            const efx_mae_match_spec_t *right)
973 {
974         return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
975 }
976
977 #define EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit)              \
978             ((_mask)[(_bit) / (_mask_page_nbits)] &                     \
979                     (1ULL << ((_bit) & ((_mask_page_nbits) - 1))))
980
981 static                                  boolean_t
982 efx_mask_is_prefix(
983         __in                            size_t mask_nbytes,
984         __in_bcount(mask_nbytes)        const uint8_t *maskp)
985 {
986         boolean_t prev_bit_is_set = B_TRUE;
987         unsigned int i;
988
989         for (i = 0; i < 8 * mask_nbytes; ++i) {
990                 boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i);
991
992                 if (!prev_bit_is_set && bit_is_set)
993                         return B_FALSE;
994
995                 prev_bit_is_set = bit_is_set;
996         }
997
998         return B_TRUE;
999 }
1000
1001 static                                  boolean_t
1002 efx_mask_is_all_ones(
1003         __in                            size_t mask_nbytes,
1004         __in_bcount(mask_nbytes)        const uint8_t *maskp)
1005 {
1006         unsigned int i;
1007         uint8_t t = ~0;
1008
1009         for (i = 0; i < mask_nbytes; ++i)
1010                 t &= maskp[i];
1011
1012         return (t == (uint8_t)(~0));
1013 }
1014
1015 static                                  boolean_t
1016 efx_mask_is_all_zeros(
1017         __in                            size_t mask_nbytes,
1018         __in_bcount(mask_nbytes)        const uint8_t *maskp)
1019 {
1020         unsigned int i;
1021         uint8_t t = 0;
1022
1023         for (i = 0; i < mask_nbytes; ++i)
1024                 t |= maskp[i];
1025
1026         return (t == 0);
1027 }
1028
1029         __checkReturn                   boolean_t
1030 efx_mae_match_spec_is_valid(
1031         __in                            efx_nic_t *enp,
1032         __in                            const efx_mae_match_spec_t *spec)
1033 {
1034         efx_mae_t *maep = enp->en_maep;
1035         unsigned int field_ncaps = maep->em_max_nfields;
1036         const efx_mae_field_cap_t *field_caps;
1037         const efx_mae_mv_desc_t *desc_setp;
1038         unsigned int desc_set_nentries;
1039         const efx_mae_mv_bit_desc_t *bit_desc_setp;
1040         unsigned int bit_desc_set_nentries;
1041         boolean_t is_valid = B_TRUE;
1042         efx_mae_field_id_t field_id;
1043         const uint8_t *mvp;
1044
1045         switch (spec->emms_type) {
1046         case EFX_MAE_RULE_OUTER:
1047                 field_caps = maep->em_outer_rule_field_caps;
1048                 desc_setp = __efx_mae_outer_rule_mv_desc_set;
1049                 desc_set_nentries =
1050                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1051                 bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
1052                 bit_desc_set_nentries =
1053                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
1054                 mvp = spec->emms_mask_value_pairs.outer;
1055                 break;
1056         case EFX_MAE_RULE_ACTION:
1057                 field_caps = maep->em_action_rule_field_caps;
1058                 desc_setp = __efx_mae_action_rule_mv_desc_set;
1059                 desc_set_nentries =
1060                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1061                 bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
1062                 bit_desc_set_nentries =
1063                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
1064                 mvp = spec->emms_mask_value_pairs.action;
1065                 break;
1066         default:
1067                 return (B_FALSE);
1068         }
1069
1070         if (field_caps == NULL)
1071                 return (B_FALSE);
1072
1073         for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1074              ++field_id) {
1075                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1076                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1077                 const uint8_t *alt_m_buf = mvp + descp->emmd_alt_mask_offset;
1078                 const uint8_t *m_buf = mvp + descp->emmd_mask_offset;
1079                 size_t alt_m_size = descp->emmd_alt_mask_size;
1080                 size_t m_size = descp->emmd_mask_size;
1081
1082                 if (m_size == 0)
1083                         continue; /* Skip array gap */
1084
1085                 if ((unsigned int)field_cap_id >= field_ncaps) {
1086                         /*
1087                          * The FW has not reported capability status for
1088                          * this field. Make sure that its mask is zeroed.
1089                          */
1090                         is_valid = efx_mask_is_all_zeros(m_size, m_buf);
1091                         if (is_valid != B_FALSE)
1092                                 continue;
1093                         else
1094                                 break;
1095                 }
1096
1097                 switch (field_caps[field_cap_id].emfc_support) {
1098                 case MAE_FIELD_SUPPORTED_MATCH_MASK:
1099                         is_valid = B_TRUE;
1100                         break;
1101                 case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
1102                         is_valid = efx_mask_is_prefix(m_size, m_buf);
1103                         break;
1104                 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
1105                         is_valid = (efx_mask_is_all_ones(m_size, m_buf) ||
1106                             efx_mask_is_all_zeros(m_size, m_buf));
1107                         break;
1108                 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
1109                         is_valid = efx_mask_is_all_ones(m_size, m_buf);
1110
1111                         if ((is_valid == B_FALSE) && (alt_m_size != 0)) {
1112                                 /*
1113                                  * This field has an alternative one. The FW
1114                                  * reports ALWAYS for both implying that one
1115                                  * of them is required to have all-ones mask.
1116                                  *
1117                                  * The primary field's mask is incorrect; go
1118                                  * on to check that of the alternative field.
1119                                  */
1120                                 is_valid = efx_mask_is_all_ones(alt_m_size,
1121                                                                 alt_m_buf);
1122                         }
1123                         break;
1124                 case MAE_FIELD_SUPPORTED_MATCH_NEVER:
1125                 case MAE_FIELD_UNSUPPORTED:
1126                 default:
1127                         is_valid = efx_mask_is_all_zeros(m_size, m_buf);
1128                         break;
1129                 }
1130
1131                 if (is_valid == B_FALSE)
1132                         return (B_FALSE);
1133         }
1134
1135         for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
1136              ++field_id) {
1137                 const efx_mae_mv_bit_desc_t *bit_descp =
1138                     &bit_desc_setp[field_id];
1139                 unsigned int byte_idx =
1140                     bit_descp->emmbd_mask_ofst +
1141                     bit_descp->emmbd_mask_lbn / 8;
1142                 unsigned int bit_idx =
1143                     bit_descp->emmbd_mask_lbn % 8;
1144                 efx_mae_field_cap_id_t bit_cap_id =
1145                     bit_descp->emmbd_bit_cap_id;
1146
1147                 if (bit_descp->emmbd_entry_is_valid == B_FALSE)
1148                         continue; /* Skip array gap */
1149
1150                 if ((unsigned int)bit_cap_id >= field_ncaps) {
1151                         /* No capability for this bit = unsupported. */
1152                         is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0);
1153                         if (is_valid == B_FALSE)
1154                                 break;
1155                         else
1156                                 continue;
1157                 }
1158
1159                 switch (field_caps[bit_cap_id].emfc_support) {
1160                 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
1161                         is_valid = B_TRUE;
1162                         break;
1163                 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
1164                         is_valid = ((mvp[byte_idx] & (1U << bit_idx)) != 0);
1165                         break;
1166                 case MAE_FIELD_SUPPORTED_MATCH_NEVER:
1167                 case MAE_FIELD_UNSUPPORTED:
1168                 default:
1169                         is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0);
1170                         break;
1171                 }
1172
1173                 if (is_valid == B_FALSE)
1174                         break;
1175         }
1176
1177         return (is_valid);
1178 }
1179
1180         __checkReturn                   efx_rc_t
1181 efx_mae_action_set_spec_init(
1182         __in                            efx_nic_t *enp,
1183         __out                           efx_mae_actions_t **specp)
1184 {
1185         efx_mae_actions_t *spec;
1186         efx_rc_t rc;
1187
1188         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
1189         if (spec == NULL) {
1190                 rc = ENOMEM;
1191                 goto fail1;
1192         }
1193
1194         spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
1195         spec->ema_rsrc.emar_counter_id.id = EFX_MAE_RSRC_ID_INVALID;
1196
1197         *specp = spec;
1198
1199         return (0);
1200
1201 fail1:
1202         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1203         return (rc);
1204 }
1205
1206                                         void
1207 efx_mae_action_set_spec_fini(
1208         __in                            efx_nic_t *enp,
1209         __in                            efx_mae_actions_t *spec)
1210 {
1211         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
1212 }
1213
1214 static  __checkReturn                   efx_rc_t
1215 efx_mae_action_set_add_decap(
1216         __in                            efx_mae_actions_t *spec,
1217         __in                            size_t arg_size,
1218         __in_bcount(arg_size)           const uint8_t *arg)
1219 {
1220         efx_rc_t rc;
1221
1222         _NOTE(ARGUNUSED(spec))
1223
1224         if (arg_size != 0) {
1225                 rc = EINVAL;
1226                 goto fail1;
1227         }
1228
1229         if (arg != NULL) {
1230                 rc = EINVAL;
1231                 goto fail2;
1232         }
1233
1234         /* This action does not have any arguments, so do nothing here. */
1235
1236         return (0);
1237
1238 fail2:
1239         EFSYS_PROBE(fail2);
1240 fail1:
1241         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1242         return (rc);
1243 }
1244
1245 static  __checkReturn                   efx_rc_t
1246 efx_mae_action_set_add_vlan_pop(
1247         __in                            efx_mae_actions_t *spec,
1248         __in                            size_t arg_size,
1249         __in_bcount(arg_size)           const uint8_t *arg)
1250 {
1251         efx_rc_t rc;
1252
1253         if (arg_size != 0) {
1254                 rc = EINVAL;
1255                 goto fail1;
1256         }
1257
1258         if (arg != NULL) {
1259                 rc = EINVAL;
1260                 goto fail2;
1261         }
1262
1263         if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) {
1264                 rc = ENOTSUP;
1265                 goto fail3;
1266         }
1267
1268         ++spec->ema_n_vlan_tags_to_pop;
1269
1270         return (0);
1271
1272 fail3:
1273         EFSYS_PROBE(fail3);
1274 fail2:
1275         EFSYS_PROBE(fail2);
1276 fail1:
1277         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1278         return (rc);
1279 }
1280
1281 static  __checkReturn                   efx_rc_t
1282 efx_mae_action_set_add_vlan_push(
1283         __in                            efx_mae_actions_t *spec,
1284         __in                            size_t arg_size,
1285         __in_bcount(arg_size)           const uint8_t *arg)
1286 {
1287         unsigned int n_tags = spec->ema_n_vlan_tags_to_push;
1288         efx_rc_t rc;
1289
1290         if (arg_size != sizeof (*spec->ema_vlan_push_descs)) {
1291                 rc = EINVAL;
1292                 goto fail1;
1293         }
1294
1295         if (arg == NULL) {
1296                 rc = EINVAL;
1297                 goto fail2;
1298         }
1299
1300         if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1301                 rc = ENOTSUP;
1302                 goto fail3;
1303         }
1304
1305         memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size);
1306         ++(spec->ema_n_vlan_tags_to_push);
1307
1308         return (0);
1309
1310 fail3:
1311         EFSYS_PROBE(fail3);
1312 fail2:
1313         EFSYS_PROBE(fail2);
1314 fail1:
1315         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1316         return (rc);
1317 }
1318
1319 static  __checkReturn                   efx_rc_t
1320 efx_mae_action_set_add_encap(
1321         __in                            efx_mae_actions_t *spec,
1322         __in                            size_t arg_size,
1323         __in_bcount(arg_size)           const uint8_t *arg)
1324 {
1325         efx_rc_t rc;
1326
1327         /*
1328          * Adding this specific action to an action set spec and setting encap.
1329          * header ID in the spec are two individual steps. This design allows
1330          * the client driver to avoid encap. header allocation when it simply
1331          * needs to check the order of actions submitted by user ("validate"),
1332          * without actually allocating an action set and inserting a rule.
1333          *
1334          * For now, mark encap. header ID as invalid; the caller will invoke
1335          * efx_mae_action_set_fill_in_eh_id() to override the field prior
1336          * to action set allocation; otherwise, the allocation will fail.
1337          */
1338         spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
1339
1340         /*
1341          * As explained above, there are no arguments to handle here.
1342          * efx_mae_action_set_fill_in_eh_id() will take care of them.
1343          */
1344         if (arg_size != 0) {
1345                 rc = EINVAL;
1346                 goto fail1;
1347         }
1348
1349         if (arg != NULL) {
1350                 rc = EINVAL;
1351                 goto fail2;
1352         }
1353
1354         return (0);
1355
1356 fail2:
1357         EFSYS_PROBE(fail2);
1358 fail1:
1359         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1360         return (rc);
1361 }
1362
1363 static  __checkReturn                   efx_rc_t
1364 efx_mae_action_set_add_count(
1365         __in                            efx_mae_actions_t *spec,
1366         __in                            size_t arg_size,
1367         __in_bcount(arg_size)           const uint8_t *arg)
1368 {
1369         efx_rc_t rc;
1370
1371         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1372                           MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL);
1373
1374         /*
1375          * Preparing an action set spec to update a counter requires
1376          * two steps: first add this action to the action spec, and then
1377          * add the counter ID to the spec. This allows validity checking
1378          * and resource allocation to be done separately.
1379          * Mark the counter ID as invalid in the spec to ensure that the
1380          * caller must also invoke efx_mae_action_set_fill_in_counter_id()
1381          * before action set allocation.
1382          */
1383         spec->ema_rsrc.emar_counter_id.id = EFX_MAE_RSRC_ID_INVALID;
1384
1385         /* Nothing else is supposed to take place over here. */
1386         if (arg_size != 0) {
1387                 rc = EINVAL;
1388                 goto fail1;
1389         }
1390
1391         if (arg != NULL) {
1392                 rc = EINVAL;
1393                 goto fail2;
1394         }
1395
1396         ++(spec->ema_n_count_actions);
1397
1398         return (0);
1399
1400 fail2:
1401         EFSYS_PROBE(fail2);
1402 fail1:
1403         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1404         return (rc);
1405 }
1406
1407 static  __checkReturn                   efx_rc_t
1408 efx_mae_action_set_add_flag(
1409         __in                            efx_mae_actions_t *spec,
1410         __in                            size_t arg_size,
1411         __in_bcount(arg_size)           const uint8_t *arg)
1412 {
1413         efx_rc_t rc;
1414
1415         _NOTE(ARGUNUSED(spec))
1416
1417         if (arg_size != 0) {
1418                 rc = EINVAL;
1419                 goto fail1;
1420         }
1421
1422         if (arg != NULL) {
1423                 rc = EINVAL;
1424                 goto fail2;
1425         }
1426
1427         /* This action does not have any arguments, so do nothing here. */
1428
1429         return (0);
1430
1431 fail2:
1432         EFSYS_PROBE(fail2);
1433 fail1:
1434         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1435         return (rc);
1436 }
1437
1438 static  __checkReturn                   efx_rc_t
1439 efx_mae_action_set_add_mark(
1440         __in                            efx_mae_actions_t *spec,
1441         __in                            size_t arg_size,
1442         __in_bcount(arg_size)           const uint8_t *arg)
1443 {
1444         efx_rc_t rc;
1445
1446         if (arg_size != sizeof (spec->ema_mark_value)) {
1447                 rc = EINVAL;
1448                 goto fail1;
1449         }
1450
1451         if (arg == NULL) {
1452                 rc = EINVAL;
1453                 goto fail2;
1454         }
1455
1456         memcpy(&spec->ema_mark_value, arg, arg_size);
1457
1458         return (0);
1459
1460 fail2:
1461         EFSYS_PROBE(fail2);
1462 fail1:
1463         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1464         return (rc);
1465 }
1466
1467 static  __checkReturn                   efx_rc_t
1468 efx_mae_action_set_add_deliver(
1469         __in                            efx_mae_actions_t *spec,
1470         __in                            size_t arg_size,
1471         __in_bcount(arg_size)           const uint8_t *arg)
1472 {
1473         efx_rc_t rc;
1474
1475         if (arg_size != sizeof (spec->ema_deliver_mport)) {
1476                 rc = EINVAL;
1477                 goto fail1;
1478         }
1479
1480         if (arg == NULL) {
1481                 rc = EINVAL;
1482                 goto fail2;
1483         }
1484
1485         memcpy(&spec->ema_deliver_mport, arg, arg_size);
1486
1487         return (0);
1488
1489 fail2:
1490         EFSYS_PROBE(fail2);
1491 fail1:
1492         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1493         return (rc);
1494 }
1495
1496 typedef struct efx_mae_action_desc_s {
1497         /* Action specific handler */
1498         efx_rc_t        (*emad_add)(efx_mae_actions_t *,
1499                                     size_t, const uint8_t *);
1500 } efx_mae_action_desc_t;
1501
1502 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
1503         [EFX_MAE_ACTION_DECAP] = {
1504                 .emad_add = efx_mae_action_set_add_decap
1505         },
1506         [EFX_MAE_ACTION_VLAN_POP] = {
1507                 .emad_add = efx_mae_action_set_add_vlan_pop
1508         },
1509         [EFX_MAE_ACTION_VLAN_PUSH] = {
1510                 .emad_add = efx_mae_action_set_add_vlan_push
1511         },
1512         [EFX_MAE_ACTION_ENCAP] = {
1513                 .emad_add = efx_mae_action_set_add_encap
1514         },
1515         [EFX_MAE_ACTION_COUNT] = {
1516                 .emad_add = efx_mae_action_set_add_count
1517         },
1518         [EFX_MAE_ACTION_FLAG] = {
1519                 .emad_add = efx_mae_action_set_add_flag
1520         },
1521         [EFX_MAE_ACTION_MARK] = {
1522                 .emad_add = efx_mae_action_set_add_mark
1523         },
1524         [EFX_MAE_ACTION_DELIVER] = {
1525                 .emad_add = efx_mae_action_set_add_deliver
1526         }
1527 };
1528
1529 static const uint32_t efx_mae_action_ordered_map =
1530         (1U << EFX_MAE_ACTION_DECAP) |
1531         (1U << EFX_MAE_ACTION_VLAN_POP) |
1532         (1U << EFX_MAE_ACTION_VLAN_PUSH) |
1533         /*
1534          * HW will conduct action COUNT after
1535          * the matching packet has been modified by
1536          * length-affecting actions except for ENCAP.
1537          */
1538         (1U << EFX_MAE_ACTION_COUNT) |
1539         (1U << EFX_MAE_ACTION_ENCAP) |
1540         (1U << EFX_MAE_ACTION_FLAG) |
1541         (1U << EFX_MAE_ACTION_MARK) |
1542         (1U << EFX_MAE_ACTION_DELIVER);
1543
1544 /*
1545  * These actions must not be added after DELIVER, but
1546  * they can have any place among the rest of
1547  * strictly ordered actions.
1548  */
1549 static const uint32_t efx_mae_action_nonstrict_map =
1550         (1U << EFX_MAE_ACTION_FLAG) |
1551         (1U << EFX_MAE_ACTION_MARK);
1552
1553 static const uint32_t efx_mae_action_repeat_map =
1554         (1U << EFX_MAE_ACTION_VLAN_POP) |
1555         (1U << EFX_MAE_ACTION_VLAN_PUSH) |
1556         (1U << EFX_MAE_ACTION_COUNT);
1557
1558 /*
1559  * Add an action to an action set.
1560  *
1561  * This has to be invoked in the desired action order.
1562  * An out-of-order action request will be turned down.
1563  */
1564 static  __checkReturn                   efx_rc_t
1565 efx_mae_action_set_spec_populate(
1566         __in                            efx_mae_actions_t *spec,
1567         __in                            efx_mae_action_t type,
1568         __in                            size_t arg_size,
1569         __in_bcount(arg_size)           const uint8_t *arg)
1570 {
1571         uint32_t action_mask;
1572         efx_rc_t rc;
1573
1574         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1575             (sizeof (efx_mae_action_ordered_map) * 8));
1576         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1577             (sizeof (efx_mae_action_repeat_map) * 8));
1578
1579         EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
1580         EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK);
1581         EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER);
1582
1583         if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
1584                 rc = EINVAL;
1585                 goto fail1;
1586         }
1587
1588         action_mask = (1U << type);
1589
1590         if ((spec->ema_actions & action_mask) != 0) {
1591                 /* The action set already contains this action. */
1592                 if ((efx_mae_action_repeat_map & action_mask) == 0) {
1593                         /* Cannot add another non-repeatable action. */
1594                         rc = ENOTSUP;
1595                         goto fail2;
1596                 }
1597         }
1598
1599         if ((efx_mae_action_ordered_map & action_mask) != 0) {
1600                 uint32_t strict_ordered_map =
1601                     efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map;
1602                 uint32_t later_actions_mask =
1603                     strict_ordered_map & ~(action_mask | (action_mask - 1));
1604
1605                 if ((spec->ema_actions & later_actions_mask) != 0) {
1606                         /* Cannot add an action after later ordered actions. */
1607                         rc = ENOTSUP;
1608                         goto fail3;
1609                 }
1610         }
1611
1612         if (efx_mae_actions[type].emad_add != NULL) {
1613                 rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
1614                 if (rc != 0)
1615                         goto fail4;
1616         }
1617
1618         spec->ema_actions |= action_mask;
1619
1620         return (0);
1621
1622 fail4:
1623         EFSYS_PROBE(fail4);
1624 fail3:
1625         EFSYS_PROBE(fail3);
1626 fail2:
1627         EFSYS_PROBE(fail2);
1628 fail1:
1629         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1630         return (rc);
1631 }
1632
1633         __checkReturn                   efx_rc_t
1634 efx_mae_action_set_populate_decap(
1635         __in                            efx_mae_actions_t *spec)
1636 {
1637         return (efx_mae_action_set_spec_populate(spec,
1638             EFX_MAE_ACTION_DECAP, 0, NULL));
1639 }
1640
1641         __checkReturn                   efx_rc_t
1642 efx_mae_action_set_populate_vlan_pop(
1643         __in                            efx_mae_actions_t *spec)
1644 {
1645         return (efx_mae_action_set_spec_populate(spec,
1646             EFX_MAE_ACTION_VLAN_POP, 0, NULL));
1647 }
1648
1649         __checkReturn                   efx_rc_t
1650 efx_mae_action_set_populate_vlan_push(
1651         __in                            efx_mae_actions_t *spec,
1652         __in                            uint16_t tpid_be,
1653         __in                            uint16_t tci_be)
1654 {
1655         efx_mae_action_vlan_push_t action;
1656         const uint8_t *arg = (const uint8_t *)&action;
1657
1658         action.emavp_tpid_be = tpid_be;
1659         action.emavp_tci_be = tci_be;
1660
1661         return (efx_mae_action_set_spec_populate(spec,
1662             EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg));
1663 }
1664
1665         __checkReturn                   efx_rc_t
1666 efx_mae_action_set_populate_encap(
1667         __in                            efx_mae_actions_t *spec)
1668 {
1669         /*
1670          * There is no argument to pass encap. header ID, thus, one does not
1671          * need to allocate an encap. header while parsing application input.
1672          * This is useful since building an action set may be done simply to
1673          * validate a rule, whilst resource allocation usually consumes time.
1674          */
1675         return (efx_mae_action_set_spec_populate(spec,
1676             EFX_MAE_ACTION_ENCAP, 0, NULL));
1677 }
1678
1679         __checkReturn                   efx_rc_t
1680 efx_mae_action_set_populate_count(
1681         __in                            efx_mae_actions_t *spec)
1682 {
1683         /*
1684          * There is no argument to pass counter ID, thus, one does not
1685          * need to allocate a counter while parsing application input.
1686          * This is useful since building an action set may be done simply to
1687          * validate a rule, whilst resource allocation usually consumes time.
1688          */
1689         return (efx_mae_action_set_spec_populate(spec,
1690             EFX_MAE_ACTION_COUNT, 0, NULL));
1691 }
1692
1693         __checkReturn                   efx_rc_t
1694 efx_mae_action_set_populate_flag(
1695         __in                            efx_mae_actions_t *spec)
1696 {
1697         return (efx_mae_action_set_spec_populate(spec,
1698             EFX_MAE_ACTION_FLAG, 0, NULL));
1699 }
1700
1701         __checkReturn                   efx_rc_t
1702 efx_mae_action_set_populate_mark(
1703         __in                            efx_mae_actions_t *spec,
1704         __in                            uint32_t mark_value)
1705 {
1706         const uint8_t *arg = (const uint8_t *)&mark_value;
1707
1708         return (efx_mae_action_set_spec_populate(spec,
1709             EFX_MAE_ACTION_MARK, sizeof (mark_value), arg));
1710 }
1711
1712         __checkReturn                   efx_rc_t
1713 efx_mae_action_set_populate_deliver(
1714         __in                            efx_mae_actions_t *spec,
1715         __in                            const efx_mport_sel_t *mportp)
1716 {
1717         const uint8_t *arg;
1718         efx_rc_t rc;
1719
1720         if (mportp == NULL) {
1721                 rc = EINVAL;
1722                 goto fail1;
1723         }
1724
1725         arg = (const uint8_t *)&mportp->sel;
1726
1727         return (efx_mae_action_set_spec_populate(spec,
1728             EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
1729
1730 fail1:
1731         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1732         return (rc);
1733 }
1734
1735         __checkReturn                   efx_rc_t
1736 efx_mae_action_set_populate_drop(
1737         __in                            efx_mae_actions_t *spec)
1738 {
1739         efx_mport_sel_t mport;
1740         const uint8_t *arg;
1741         efx_dword_t dword;
1742
1743         EFX_POPULATE_DWORD_1(dword,
1744             MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL);
1745
1746         /*
1747          * The constructed DWORD is little-endian,
1748          * but the resulting value is meant to be
1749          * passed to MCDIs, where it will undergo
1750          * host-order to little endian conversion.
1751          */
1752         mport.sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
1753
1754         arg = (const uint8_t *)&mport.sel;
1755
1756         return (efx_mae_action_set_spec_populate(spec,
1757             EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg));
1758 }
1759
1760         __checkReturn                   boolean_t
1761 efx_mae_action_set_specs_equal(
1762         __in                            const efx_mae_actions_t *left,
1763         __in                            const efx_mae_actions_t *right)
1764 {
1765         size_t cmp_size = EFX_FIELD_OFFSET(efx_mae_actions_t, ema_rsrc);
1766
1767         /*
1768          * An action set specification consists of two parts. The first part
1769          * indicates what actions are included in the action set, as well as
1770          * extra quantitative values (in example, the number of VLAN tags to
1771          * push). The second part comprises resource IDs used by the actions.
1772          *
1773          * A resource, in example, a counter, is allocated from the hardware
1774          * by the client, and it's the client who is responsible for keeping
1775          * track of allocated resources and comparing resource IDs if needed.
1776          *
1777          * In this API, don't compare resource IDs in the two specifications.
1778          */
1779
1780         return ((memcmp(left, right, cmp_size) == 0) ? B_TRUE : B_FALSE);
1781 }
1782
1783         __checkReturn                   efx_rc_t
1784 efx_mae_match_specs_class_cmp(
1785         __in                            efx_nic_t *enp,
1786         __in                            const efx_mae_match_spec_t *left,
1787         __in                            const efx_mae_match_spec_t *right,
1788         __out                           boolean_t *have_same_classp)
1789 {
1790         efx_mae_t *maep = enp->en_maep;
1791         unsigned int field_ncaps = maep->em_max_nfields;
1792         const efx_mae_field_cap_t *field_caps;
1793         const efx_mae_mv_desc_t *desc_setp;
1794         unsigned int desc_set_nentries;
1795         const efx_mae_mv_bit_desc_t *bit_desc_setp;
1796         unsigned int bit_desc_set_nentries;
1797         boolean_t have_same_class = B_TRUE;
1798         efx_mae_field_id_t field_id;
1799         const uint8_t *mvpl;
1800         const uint8_t *mvpr;
1801         efx_rc_t rc;
1802
1803         switch (left->emms_type) {
1804         case EFX_MAE_RULE_OUTER:
1805                 field_caps = maep->em_outer_rule_field_caps;
1806                 desc_setp = __efx_mae_outer_rule_mv_desc_set;
1807                 desc_set_nentries =
1808                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1809                 bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
1810                 bit_desc_set_nentries =
1811                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
1812                 mvpl = left->emms_mask_value_pairs.outer;
1813                 mvpr = right->emms_mask_value_pairs.outer;
1814                 break;
1815         case EFX_MAE_RULE_ACTION:
1816                 field_caps = maep->em_action_rule_field_caps;
1817                 desc_setp = __efx_mae_action_rule_mv_desc_set;
1818                 desc_set_nentries =
1819                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1820                 bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
1821                 bit_desc_set_nentries =
1822                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
1823                 mvpl = left->emms_mask_value_pairs.action;
1824                 mvpr = right->emms_mask_value_pairs.action;
1825                 break;
1826         default:
1827                 rc = ENOTSUP;
1828                 goto fail1;
1829         }
1830
1831         if (field_caps == NULL) {
1832                 rc = EAGAIN;
1833                 goto fail2;
1834         }
1835
1836         if (left->emms_type != right->emms_type ||
1837             left->emms_prio != right->emms_prio) {
1838                 /*
1839                  * Rules of different types can never map to the same class.
1840                  *
1841                  * The FW can support some set of match criteria for one
1842                  * priority and not support the very same set for
1843                  * another priority. Thus, two rules which have
1844                  * different priorities can never map to
1845                  * the same class.
1846                  */
1847                 *have_same_classp = B_FALSE;
1848                 return (0);
1849         }
1850
1851         for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1852              ++field_id) {
1853                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1854                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1855                 const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
1856                 const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
1857                 size_t mask_size = descp->emmd_mask_size;
1858                 const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
1859                 const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
1860                 size_t value_size = descp->emmd_value_size;
1861
1862                 if (mask_size == 0)
1863                         continue; /* Skip array gap */
1864
1865                 if ((unsigned int)field_cap_id >= field_ncaps) {
1866                         /*
1867                          * The FW has not reported capability status for this
1868                          * field. It's unknown whether any difference between
1869                          * the two masks / values affects the class. The only
1870                          * case when the class must be the same is when these
1871                          * mask-value pairs match. Otherwise, report mismatch.
1872                          */
1873                         if ((memcmp(lmaskp, rmaskp, mask_size) == 0) &&
1874                             (memcmp(lvalp, rvalp, value_size) == 0))
1875                                 continue;
1876                         else
1877                                 break;
1878                 }
1879
1880                 if (field_caps[field_cap_id].emfc_mask_affects_class) {
1881                         if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
1882                                 have_same_class = B_FALSE;
1883                                 break;
1884                         }
1885                 }
1886
1887                 if (field_caps[field_cap_id].emfc_match_affects_class) {
1888                         if (memcmp(lvalp, rvalp, value_size) != 0) {
1889                                 have_same_class = B_FALSE;
1890                                 break;
1891                         }
1892                 }
1893         }
1894
1895         if (have_same_class == B_FALSE)
1896                 goto done;
1897
1898         for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
1899              ++field_id) {
1900                 const efx_mae_mv_bit_desc_t *bit_descp =
1901                     &bit_desc_setp[field_id];
1902                 efx_mae_field_cap_id_t bit_cap_id =
1903                     bit_descp->emmbd_bit_cap_id;
1904                 unsigned int byte_idx;
1905                 unsigned int bit_idx;
1906
1907                 if (bit_descp->emmbd_entry_is_valid == B_FALSE)
1908                         continue; /* Skip array gap */
1909
1910                 if ((unsigned int)bit_cap_id >= field_ncaps)
1911                         break;
1912
1913                 byte_idx =
1914                     bit_descp->emmbd_mask_ofst +
1915                     bit_descp->emmbd_mask_lbn / 8;
1916                 bit_idx =
1917                     bit_descp->emmbd_mask_lbn % 8;
1918
1919                 if (field_caps[bit_cap_id].emfc_mask_affects_class &&
1920                     (mvpl[byte_idx] & (1U << bit_idx)) !=
1921                     (mvpr[byte_idx] & (1U << bit_idx))) {
1922                         have_same_class = B_FALSE;
1923                         break;
1924                 }
1925
1926                 byte_idx =
1927                     bit_descp->emmbd_value_ofst +
1928                     bit_descp->emmbd_value_lbn / 8;
1929                 bit_idx =
1930                     bit_descp->emmbd_value_lbn % 8;
1931
1932                 if (field_caps[bit_cap_id].emfc_match_affects_class &&
1933                     (mvpl[byte_idx] & (1U << bit_idx)) !=
1934                     (mvpr[byte_idx] & (1U << bit_idx))) {
1935                         have_same_class = B_FALSE;
1936                         break;
1937                 }
1938         }
1939
1940 done:
1941         *have_same_classp = have_same_class;
1942
1943         return (0);
1944
1945 fail2:
1946         EFSYS_PROBE(fail2);
1947 fail1:
1948         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1949         return (rc);
1950 }
1951
1952         __checkReturn           efx_rc_t
1953 efx_mae_outer_rule_insert(
1954         __in                    efx_nic_t *enp,
1955         __in                    const efx_mae_match_spec_t *spec,
1956         __in                    efx_tunnel_protocol_t encap_type,
1957         __out                   efx_mae_rule_id_t *or_idp)
1958 {
1959         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1960         efx_mcdi_req_t req;
1961         EFX_MCDI_DECLARE_BUF(payload,
1962             MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2,
1963             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
1964         uint32_t encap_type_mcdi;
1965         efx_mae_rule_id_t or_id;
1966         size_t offset;
1967         efx_rc_t rc;
1968
1969         EFX_STATIC_ASSERT(sizeof (or_idp->id) ==
1970             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN);
1971
1972         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1973             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL);
1974
1975         if (encp->enc_mae_supported == B_FALSE) {
1976                 rc = ENOTSUP;
1977                 goto fail1;
1978         }
1979
1980         if (spec->emms_type != EFX_MAE_RULE_OUTER) {
1981                 rc = EINVAL;
1982                 goto fail2;
1983         }
1984
1985         switch (encap_type) {
1986         case EFX_TUNNEL_PROTOCOL_NONE:
1987                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
1988                 break;
1989         case EFX_TUNNEL_PROTOCOL_VXLAN:
1990                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
1991                 break;
1992         case EFX_TUNNEL_PROTOCOL_GENEVE:
1993                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
1994                 break;
1995         case EFX_TUNNEL_PROTOCOL_NVGRE:
1996                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
1997                 break;
1998         default:
1999                 rc = ENOTSUP;
2000                 goto fail3;
2001         }
2002
2003         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT;
2004         req.emr_in_buf = payload;
2005         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2;
2006         req.emr_out_buf = payload;
2007         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN;
2008
2009         MCDI_IN_SET_DWORD(req,
2010             MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi);
2011
2012         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio);
2013
2014         /*
2015          * Mask-value pairs have been stored in the byte order needed for the
2016          * MCDI request and are thus safe to be copied directly to the buffer.
2017          * The library cares about byte order in efx_mae_match_spec_field_set().
2018          */
2019         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >=
2020             MAE_ENC_FIELD_PAIRS_LEN);
2021         offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST;
2022         memcpy(payload + offset, spec->emms_mask_value_pairs.outer,
2023             MAE_ENC_FIELD_PAIRS_LEN);
2024
2025         efx_mcdi_execute(enp, &req);
2026
2027         if (req.emr_rc != 0) {
2028                 rc = req.emr_rc;
2029                 goto fail4;
2030         }
2031
2032         if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) {
2033                 rc = EMSGSIZE;
2034                 goto fail5;
2035         }
2036
2037         or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
2038         if (or_id.id == EFX_MAE_RSRC_ID_INVALID) {
2039                 rc = ENOENT;
2040                 goto fail6;
2041         }
2042
2043         or_idp->id = or_id.id;
2044
2045         return (0);
2046
2047 fail6:
2048         EFSYS_PROBE(fail6);
2049 fail5:
2050         EFSYS_PROBE(fail5);
2051 fail4:
2052         EFSYS_PROBE(fail4);
2053 fail3:
2054         EFSYS_PROBE(fail3);
2055 fail2:
2056         EFSYS_PROBE(fail2);
2057 fail1:
2058         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2059         return (rc);
2060 }
2061
2062         __checkReturn           efx_rc_t
2063 efx_mae_outer_rule_remove(
2064         __in                    efx_nic_t *enp,
2065         __in                    const efx_mae_rule_id_t *or_idp)
2066 {
2067         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2068         efx_mcdi_req_t req;
2069         EFX_MCDI_DECLARE_BUF(payload,
2070             MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1),
2071             MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
2072         efx_rc_t rc;
2073
2074         if (encp->enc_mae_supported == B_FALSE) {
2075                 rc = ENOTSUP;
2076                 goto fail1;
2077         }
2078
2079         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE;
2080         req.emr_in_buf = payload;
2081         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1);
2082         req.emr_out_buf = payload;
2083         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1);
2084
2085         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id);
2086
2087         efx_mcdi_execute(enp, &req);
2088
2089         if (req.emr_rc != 0) {
2090                 rc = req.emr_rc;
2091                 goto fail2;
2092         }
2093
2094         if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LENMIN) {
2095                 rc = EMSGSIZE;
2096                 goto fail3;
2097         }
2098
2099         if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) !=
2100             or_idp->id) {
2101                 /* Firmware failed to remove the outer rule. */
2102                 rc = EAGAIN;
2103                 goto fail4;
2104         }
2105
2106         return (0);
2107
2108 fail4:
2109         EFSYS_PROBE(fail4);
2110 fail3:
2111         EFSYS_PROBE(fail3);
2112 fail2:
2113         EFSYS_PROBE(fail2);
2114 fail1:
2115         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2116         return (rc);
2117 }
2118
2119         __checkReturn                   efx_rc_t
2120 efx_mae_match_spec_outer_rule_id_set(
2121         __in                            efx_mae_match_spec_t *spec,
2122         __in                            const efx_mae_rule_id_t *or_idp)
2123 {
2124         uint32_t full_mask = UINT32_MAX;
2125         efx_rc_t rc;
2126
2127         if (spec->emms_type != EFX_MAE_RULE_ACTION) {
2128                 rc = EINVAL;
2129                 goto fail1;
2130         }
2131
2132         if (or_idp == NULL) {
2133                 rc = EINVAL;
2134                 goto fail2;
2135         }
2136
2137         rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID,
2138             sizeof (or_idp->id), (const uint8_t *)&or_idp->id,
2139             sizeof (full_mask), (const uint8_t *)&full_mask);
2140         if (rc != 0)
2141                 goto fail3;
2142
2143         return (0);
2144
2145 fail3:
2146         EFSYS_PROBE(fail3);
2147 fail2:
2148         EFSYS_PROBE(fail2);
2149 fail1:
2150         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2151         return (rc);
2152 }
2153
2154          __checkReturn                  efx_rc_t
2155 efx_mae_encap_header_alloc(
2156         __in                            efx_nic_t *enp,
2157         __in                            efx_tunnel_protocol_t encap_type,
2158         __in_bcount(header_size)        uint8_t *header_data,
2159         __in                            size_t header_size,
2160         __out                           efx_mae_eh_id_t *eh_idp)
2161 {
2162         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2163         efx_mcdi_req_t req;
2164         EFX_MCDI_DECLARE_BUF(payload,
2165             MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LENMAX_MCDI2,
2166             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN);
2167         uint32_t encap_type_mcdi;
2168         efx_mae_eh_id_t eh_id;
2169         efx_rc_t rc;
2170
2171         EFX_STATIC_ASSERT(sizeof (eh_idp->id) ==
2172             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_LEN);
2173
2174         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2175             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
2176
2177         if (encp->enc_mae_supported == B_FALSE) {
2178                 rc = ENOTSUP;
2179                 goto fail1;
2180         }
2181
2182         switch (encap_type) {
2183         case EFX_TUNNEL_PROTOCOL_NONE:
2184                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
2185                 break;
2186         case EFX_TUNNEL_PROTOCOL_VXLAN:
2187                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
2188                 break;
2189         case EFX_TUNNEL_PROTOCOL_GENEVE:
2190                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
2191                 break;
2192         case EFX_TUNNEL_PROTOCOL_NVGRE:
2193                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
2194                 break;
2195         default:
2196                 rc = ENOTSUP;
2197                 goto fail2;
2198         }
2199
2200         if (header_size >
2201             MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2) {
2202                 rc = EINVAL;
2203                 goto fail3;
2204         }
2205
2206         req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_ALLOC;
2207         req.emr_in_buf = payload;
2208         req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(header_size);
2209         req.emr_out_buf = payload;
2210         req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN;
2211
2212         MCDI_IN_SET_DWORD(req,
2213             MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, encap_type_mcdi);
2214
2215         memcpy(payload + MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_OFST,
2216             header_data, header_size);
2217
2218         efx_mcdi_execute(enp, &req);
2219
2220         if (req.emr_rc != 0) {
2221                 rc = req.emr_rc;
2222                 goto fail4;
2223         }
2224
2225         if (req.emr_out_length_used < MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN) {
2226                 rc = EMSGSIZE;
2227                 goto fail5;
2228         }
2229
2230         eh_id.id = MCDI_OUT_DWORD(req,
2231             MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID);
2232
2233         if (eh_id.id == EFX_MAE_RSRC_ID_INVALID) {
2234                 rc = ENOENT;
2235                 goto fail6;
2236         }
2237
2238         eh_idp->id = eh_id.id;
2239
2240         return (0);
2241
2242 fail6:
2243         EFSYS_PROBE(fail6);
2244 fail5:
2245         EFSYS_PROBE(fail5);
2246 fail4:
2247         EFSYS_PROBE(fail4);
2248 fail3:
2249         EFSYS_PROBE(fail3);
2250 fail2:
2251         EFSYS_PROBE(fail2);
2252 fail1:
2253         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2254         return (rc);
2255 }
2256
2257         __checkReturn                   efx_rc_t
2258 efx_mae_encap_header_free(
2259         __in                            efx_nic_t *enp,
2260         __in                            const efx_mae_eh_id_t *eh_idp)
2261 {
2262         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2263         efx_mcdi_req_t req;
2264         EFX_MCDI_DECLARE_BUF(payload,
2265             MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1),
2266             MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1));
2267         efx_rc_t rc;
2268
2269         if (encp->enc_mae_supported == B_FALSE) {
2270                 rc = ENOTSUP;
2271                 goto fail1;
2272         }
2273
2274         req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_FREE;
2275         req.emr_in_buf = payload;
2276         req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1);
2277         req.emr_out_buf = payload;
2278         req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1);
2279
2280         MCDI_IN_SET_DWORD(req, MAE_ENCAP_HEADER_FREE_IN_EH_ID, eh_idp->id);
2281
2282         efx_mcdi_execute(enp, &req);
2283
2284         if (req.emr_rc != 0) {
2285                 rc = req.emr_rc;
2286                 goto fail2;
2287         }
2288
2289         if (MCDI_OUT_DWORD(req, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) !=
2290             eh_idp->id) {
2291                 /* Firmware failed to remove the encap. header. */
2292                 rc = EAGAIN;
2293                 goto fail3;
2294         }
2295
2296         return (0);
2297
2298 fail3:
2299         EFSYS_PROBE(fail3);
2300 fail2:
2301         EFSYS_PROBE(fail2);
2302 fail1:
2303         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2304         return (rc);
2305 }
2306
2307         __checkReturn                   efx_rc_t
2308 efx_mae_action_set_fill_in_eh_id(
2309         __in                            efx_mae_actions_t *spec,
2310         __in                            const efx_mae_eh_id_t *eh_idp)
2311 {
2312         efx_rc_t rc;
2313
2314         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) == 0) {
2315                 /*
2316                  * The caller has not intended to have action ENCAP originally,
2317                  * hence, this attempt to indicate encap. header ID is invalid.
2318                  */
2319                 rc = EINVAL;
2320                 goto fail1;
2321         }
2322
2323         if (spec->ema_rsrc.emar_eh_id.id != EFX_MAE_RSRC_ID_INVALID) {
2324                 /* The caller attempts to indicate encap. header ID twice. */
2325                 rc = EINVAL;
2326                 goto fail2;
2327         }
2328
2329         if (eh_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2330                 rc = EINVAL;
2331                 goto fail3;
2332         }
2333
2334         spec->ema_rsrc.emar_eh_id.id = eh_idp->id;
2335
2336         return (0);
2337
2338 fail3:
2339         EFSYS_PROBE(fail3);
2340 fail2:
2341         EFSYS_PROBE(fail2);
2342 fail1:
2343         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2344         return (rc);
2345 }
2346
2347         __checkReturn                   efx_rc_t
2348 efx_mae_action_set_alloc(
2349         __in                            efx_nic_t *enp,
2350         __in                            const efx_mae_actions_t *spec,
2351         __out                           efx_mae_aset_id_t *aset_idp)
2352 {
2353         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2354         efx_mcdi_req_t req;
2355         EFX_MCDI_DECLARE_BUF(payload,
2356             MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
2357             MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
2358         efx_mae_aset_id_t aset_id;
2359         efx_rc_t rc;
2360
2361         if (encp->enc_mae_supported == B_FALSE) {
2362                 rc = ENOTSUP;
2363                 goto fail1;
2364         }
2365
2366         req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
2367         req.emr_in_buf = payload;
2368         req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
2369         req.emr_out_buf = payload;
2370         req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
2371
2372         /*
2373          * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
2374          * corresponding resource types are supported by the implementation.
2375          * Use proper resource ID assignments instead.
2376          */
2377         MCDI_IN_SET_DWORD(req,
2378             MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
2379
2380         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECAP)) != 0) {
2381                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2382                     MAE_ACTION_SET_ALLOC_IN_DECAP, 1);
2383         }
2384
2385         MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2386             MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
2387
2388         if (spec->ema_n_vlan_tags_to_push > 0) {
2389                 unsigned int outer_tag_idx;
2390
2391                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2392                     MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
2393                     spec->ema_n_vlan_tags_to_push);
2394
2395                 if (spec->ema_n_vlan_tags_to_push ==
2396                     EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
2397                         MCDI_IN_SET_WORD(req,
2398                             MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
2399                             spec->ema_vlan_push_descs[0].emavp_tpid_be);
2400                         MCDI_IN_SET_WORD(req,
2401                             MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
2402                             spec->ema_vlan_push_descs[0].emavp_tci_be);
2403                 }
2404
2405                 outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
2406
2407                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
2408                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
2409                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
2410                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
2411         }
2412
2413         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
2414             spec->ema_rsrc.emar_eh_id.id);
2415         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
2416             spec->ema_rsrc.emar_counter_id.id);
2417
2418         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
2419                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2420                     MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
2421         }
2422
2423         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
2424                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2425                     MAE_ACTION_SET_ALLOC_IN_MARK, 1);
2426
2427                 MCDI_IN_SET_DWORD(req,
2428                     MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
2429         }
2430
2431         MCDI_IN_SET_DWORD(req,
2432             MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
2433
2434         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
2435             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2436         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
2437             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2438
2439         efx_mcdi_execute(enp, &req);
2440
2441         if (req.emr_rc != 0) {
2442                 rc = req.emr_rc;
2443                 goto fail2;
2444         }
2445
2446         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
2447                 rc = EMSGSIZE;
2448                 goto fail3;
2449         }
2450
2451         aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
2452         if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
2453                 rc = ENOENT;
2454                 goto fail4;
2455         }
2456
2457         aset_idp->id = aset_id.id;
2458
2459         return (0);
2460
2461 fail4:
2462         EFSYS_PROBE(fail4);
2463 fail3:
2464         EFSYS_PROBE(fail3);
2465 fail2:
2466         EFSYS_PROBE(fail2);
2467 fail1:
2468         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2469         return (rc);
2470 }
2471
2472         __checkReturn                   unsigned int
2473 efx_mae_action_set_get_nb_count(
2474         __in                            const efx_mae_actions_t *spec)
2475 {
2476         return (spec->ema_n_count_actions);
2477 }
2478
2479         __checkReturn                   efx_rc_t
2480 efx_mae_action_set_fill_in_counter_id(
2481         __in                            efx_mae_actions_t *spec,
2482         __in                            const efx_counter_t *counter_idp)
2483 {
2484         efx_rc_t rc;
2485
2486         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_COUNT)) == 0) {
2487                 /*
2488                  * Invalid to add counter ID if spec does not have COUNT action.
2489                  */
2490                 rc = EINVAL;
2491                 goto fail1;
2492         }
2493
2494         if (spec->ema_n_count_actions != 1) {
2495                 /*
2496                  * Having multiple COUNT actions in the spec requires a counter
2497                  * list to be used. This API must only be used for a single
2498                  * counter per spec. Turn down the request as inappropriate.
2499                  */
2500                 rc = EINVAL;
2501                 goto fail2;
2502         }
2503
2504         if (spec->ema_rsrc.emar_counter_id.id != EFX_MAE_RSRC_ID_INVALID) {
2505                 /* The caller attempts to indicate counter ID twice. */
2506                 rc = EALREADY;
2507                 goto fail3;
2508         }
2509
2510         if (counter_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2511                 rc = EINVAL;
2512                 goto fail4;
2513         }
2514
2515         spec->ema_rsrc.emar_counter_id.id = counter_idp->id;
2516
2517         return (0);
2518
2519 fail4:
2520         EFSYS_PROBE(fail4);
2521 fail3:
2522         EFSYS_PROBE(fail3);
2523 fail2:
2524         EFSYS_PROBE(fail2);
2525 fail1:
2526         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2527         return (rc);
2528 }
2529
2530         __checkReturn                   efx_rc_t
2531 efx_mae_counters_alloc(
2532         __in                            efx_nic_t *enp,
2533         __in                            uint32_t n_counters,
2534         __out                           uint32_t *n_allocatedp,
2535         __out_ecount(n_counters)        efx_counter_t *countersp,
2536         __out_opt                       uint32_t *gen_countp)
2537 {
2538         EFX_MCDI_DECLARE_BUF(payload,
2539             MC_CMD_MAE_COUNTER_ALLOC_IN_LEN,
2540             MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMAX_MCDI2);
2541         efx_mae_t *maep = enp->en_maep;
2542         uint32_t n_allocated;
2543         efx_mcdi_req_t req;
2544         unsigned int i;
2545         efx_rc_t rc;
2546
2547         if (n_counters > maep->em_max_ncounters ||
2548             n_counters < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM ||
2549             n_counters > MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MAXNUM_MCDI2) {
2550                 rc = EINVAL;
2551                 goto fail1;
2552         }
2553
2554         req.emr_cmd = MC_CMD_MAE_COUNTER_ALLOC;
2555         req.emr_in_buf = payload;
2556         req.emr_in_length = MC_CMD_MAE_COUNTER_ALLOC_IN_LEN;
2557         req.emr_out_buf = payload;
2558         req.emr_out_length = MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(n_counters);
2559
2560         MCDI_IN_SET_DWORD(req, MAE_COUNTER_ALLOC_IN_REQUESTED_COUNT,
2561             n_counters);
2562
2563         efx_mcdi_execute(enp, &req);
2564
2565         if (req.emr_rc != 0) {
2566                 rc = req.emr_rc;
2567                 goto fail2;
2568         }
2569
2570         if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMIN) {
2571                 rc = EMSGSIZE;
2572                 goto fail3;
2573         }
2574
2575         n_allocated = MCDI_OUT_DWORD(req,
2576             MAE_COUNTER_ALLOC_OUT_COUNTER_ID_COUNT);
2577         if (n_allocated < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM) {
2578                 rc = EFAULT;
2579                 goto fail4;
2580         }
2581
2582         for (i = 0; i < n_allocated; i++) {
2583                 countersp[i].id = MCDI_OUT_INDEXED_DWORD(req,
2584                     MAE_COUNTER_ALLOC_OUT_COUNTER_ID, i);
2585         }
2586
2587         if (gen_countp != NULL) {
2588                 *gen_countp = MCDI_OUT_DWORD(req,
2589                                     MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT);
2590         }
2591
2592         *n_allocatedp = n_allocated;
2593
2594         return (0);
2595
2596 fail4:
2597         EFSYS_PROBE(fail4);
2598 fail3:
2599         EFSYS_PROBE(fail3);
2600 fail2:
2601         EFSYS_PROBE(fail2);
2602 fail1:
2603         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2604
2605         return (rc);
2606 }
2607
2608         __checkReturn                   efx_rc_t
2609 efx_mae_counters_free(
2610         __in                            efx_nic_t *enp,
2611         __in                            uint32_t n_counters,
2612         __out                           uint32_t *n_freedp,
2613         __in_ecount(n_counters)         const efx_counter_t *countersp,
2614         __out_opt                       uint32_t *gen_countp)
2615 {
2616         EFX_MCDI_DECLARE_BUF(payload,
2617             MC_CMD_MAE_COUNTER_FREE_IN_LENMAX_MCDI2,
2618             MC_CMD_MAE_COUNTER_FREE_OUT_LENMAX_MCDI2);
2619         efx_mae_t *maep = enp->en_maep;
2620         efx_mcdi_req_t req;
2621         uint32_t n_freed;
2622         unsigned int i;
2623         efx_rc_t rc;
2624
2625         if (n_counters > maep->em_max_ncounters ||
2626             n_counters < MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MINNUM ||
2627             n_counters >
2628             MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MAXNUM_MCDI2) {
2629                 rc = EINVAL;
2630                 goto fail1;
2631         }
2632
2633         req.emr_cmd = MC_CMD_MAE_COUNTER_FREE;
2634         req.emr_in_buf = payload;
2635         req.emr_in_length = MC_CMD_MAE_COUNTER_FREE_IN_LEN(n_counters);
2636         req.emr_out_buf = payload;
2637         req.emr_out_length = MC_CMD_MAE_COUNTER_FREE_OUT_LEN(n_counters);
2638
2639         for (i = 0; i < n_counters; i++) {
2640                 MCDI_IN_SET_INDEXED_DWORD(req,
2641                     MAE_COUNTER_FREE_IN_FREE_COUNTER_ID, i, countersp[i].id);
2642         }
2643         MCDI_IN_SET_DWORD(req, MAE_COUNTER_FREE_IN_COUNTER_ID_COUNT,
2644                           n_counters);
2645
2646         efx_mcdi_execute(enp, &req);
2647
2648         if (req.emr_rc != 0) {
2649                 rc = req.emr_rc;
2650                 goto fail2;
2651         }
2652
2653         if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_FREE_OUT_LENMIN) {
2654                 rc = EMSGSIZE;
2655                 goto fail3;
2656         }
2657
2658         n_freed = MCDI_OUT_DWORD(req, MAE_COUNTER_FREE_OUT_COUNTER_ID_COUNT);
2659
2660         if (n_freed < MC_CMD_MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID_MINNUM) {
2661                 rc = EFAULT;
2662                 goto fail4;
2663         }
2664
2665         if (gen_countp != NULL) {
2666                 *gen_countp = MCDI_OUT_DWORD(req,
2667                                     MAE_COUNTER_FREE_OUT_GENERATION_COUNT);
2668         }
2669
2670         *n_freedp = n_freed;
2671
2672         return (0);
2673
2674 fail4:
2675         EFSYS_PROBE(fail4);
2676 fail3:
2677         EFSYS_PROBE(fail3);
2678 fail2:
2679         EFSYS_PROBE(fail2);
2680 fail1:
2681         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2682
2683         return (rc);
2684 }
2685
2686         __checkReturn                   efx_rc_t
2687 efx_mae_counters_stream_start(
2688         __in                            efx_nic_t *enp,
2689         __in                            uint16_t rxq_id,
2690         __in                            uint16_t packet_size,
2691         __in                            uint32_t flags_in,
2692         __out                           uint32_t *flags_out)
2693 {
2694         efx_mcdi_req_t req;
2695         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN,
2696                              MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN);
2697         efx_rc_t rc;
2698
2699         EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_IN_ZERO_SQUASH_DISABLE ==
2700             1U << MC_CMD_MAE_COUNTERS_STREAM_START_IN_ZERO_SQUASH_DISABLE_LBN);
2701
2702         EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_OUT_USES_CREDITS ==
2703             1U << MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_LBN);
2704
2705         req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_START;
2706         req.emr_in_buf = payload;
2707         req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN;
2708         req.emr_out_buf = payload;
2709         req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN;
2710
2711         MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_QID, rxq_id);
2712         MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_PACKET_SIZE,
2713                          packet_size);
2714         MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_START_IN_FLAGS, flags_in);
2715
2716         efx_mcdi_execute(enp, &req);
2717
2718         if (req.emr_rc != 0) {
2719                 rc = req.emr_rc;
2720                 goto fail1;
2721         }
2722
2723         if (req.emr_out_length_used <
2724             MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN) {
2725                 rc = EMSGSIZE;
2726                 goto fail2;
2727         }
2728
2729         *flags_out = MCDI_OUT_DWORD(req, MAE_COUNTERS_STREAM_START_OUT_FLAGS);
2730
2731         return (0);
2732
2733 fail2:
2734         EFSYS_PROBE(fail2);
2735 fail1:
2736         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2737
2738         return (rc);
2739 }
2740
2741         __checkReturn                   efx_rc_t
2742 efx_mae_counters_stream_stop(
2743         __in                            efx_nic_t *enp,
2744         __in                            uint16_t rxq_id,
2745         __out_opt                       uint32_t *gen_countp)
2746 {
2747         efx_mcdi_req_t req;
2748         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN,
2749                              MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN);
2750         efx_rc_t rc;
2751
2752         req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_STOP;
2753         req.emr_in_buf = payload;
2754         req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN;
2755         req.emr_out_buf = payload;
2756         req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN;
2757
2758         MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_STOP_IN_QID, rxq_id);
2759
2760         efx_mcdi_execute(enp, &req);
2761
2762         if (req.emr_rc != 0) {
2763                 rc = req.emr_rc;
2764                 goto fail1;
2765         }
2766
2767         if (req.emr_out_length_used <
2768             MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN) {
2769                 rc = EMSGSIZE;
2770                 goto fail2;
2771         }
2772
2773         if (gen_countp != NULL) {
2774                 *gen_countp = MCDI_OUT_DWORD(req,
2775                             MAE_COUNTERS_STREAM_STOP_OUT_GENERATION_COUNT);
2776         }
2777
2778         return (0);
2779
2780 fail2:
2781         EFSYS_PROBE(fail2);
2782 fail1:
2783         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2784
2785         return (rc);
2786 }
2787
2788         __checkReturn                   efx_rc_t
2789 efx_mae_counters_stream_give_credits(
2790         __in                            efx_nic_t *enp,
2791         __in                            uint32_t n_credits)
2792 {
2793         efx_mcdi_req_t req;
2794         EFX_MCDI_DECLARE_BUF(payload,
2795                              MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN,
2796                              MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN);
2797         efx_rc_t rc;
2798
2799         req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS;
2800         req.emr_in_buf = payload;
2801         req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN;
2802         req.emr_out_buf = payload;
2803         req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN;
2804
2805         MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_NUM_CREDITS,
2806                          n_credits);
2807
2808         efx_mcdi_execute(enp, &req);
2809
2810         if (req.emr_rc != 0) {
2811                 rc = req.emr_rc;
2812                 goto fail1;
2813         }
2814
2815         return (0);
2816
2817 fail1:
2818         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2819
2820         return (rc);
2821 }
2822
2823         __checkReturn                   efx_rc_t
2824 efx_mae_action_set_free(
2825         __in                            efx_nic_t *enp,
2826         __in                            const efx_mae_aset_id_t *aset_idp)
2827 {
2828         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2829         efx_mcdi_req_t req;
2830         EFX_MCDI_DECLARE_BUF(payload,
2831             MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
2832             MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
2833         efx_rc_t rc;
2834
2835         if (encp->enc_mae_supported == B_FALSE) {
2836                 rc = ENOTSUP;
2837                 goto fail1;
2838         }
2839
2840         req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
2841         req.emr_in_buf = payload;
2842         req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
2843         req.emr_out_buf = payload;
2844         req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
2845
2846         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
2847
2848         efx_mcdi_execute(enp, &req);
2849
2850         if (req.emr_rc != 0) {
2851                 rc = req.emr_rc;
2852                 goto fail2;
2853         }
2854
2855         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_FREE_OUT_LENMIN) {
2856                 rc = EMSGSIZE;
2857                 goto fail3;
2858         }
2859
2860         if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
2861             aset_idp->id) {
2862                 /* Firmware failed to free the action set. */
2863                 rc = EAGAIN;
2864                 goto fail4;
2865         }
2866
2867         return (0);
2868
2869 fail4:
2870         EFSYS_PROBE(fail4);
2871 fail3:
2872         EFSYS_PROBE(fail3);
2873 fail2:
2874         EFSYS_PROBE(fail2);
2875 fail1:
2876         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2877         return (rc);
2878 }
2879
2880         __checkReturn                   efx_rc_t
2881 efx_mae_action_rule_insert(
2882         __in                            efx_nic_t *enp,
2883         __in                            const efx_mae_match_spec_t *spec,
2884         __in                            const efx_mae_aset_list_id_t *asl_idp,
2885         __in                            const efx_mae_aset_id_t *as_idp,
2886         __out                           efx_mae_rule_id_t *ar_idp)
2887 {
2888         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2889         efx_mcdi_req_t req;
2890         EFX_MCDI_DECLARE_BUF(payload,
2891             MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2,
2892             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
2893         efx_oword_t *rule_response;
2894         efx_mae_rule_id_t ar_id;
2895         size_t offset;
2896         efx_rc_t rc;
2897
2898         EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
2899             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
2900
2901         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2902             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
2903
2904         if (encp->enc_mae_supported == B_FALSE) {
2905                 rc = ENOTSUP;
2906                 goto fail1;
2907         }
2908
2909         if (spec->emms_type != EFX_MAE_RULE_ACTION ||
2910             (asl_idp != NULL && as_idp != NULL) ||
2911             (asl_idp == NULL && as_idp == NULL)) {
2912                 rc = EINVAL;
2913                 goto fail2;
2914         }
2915
2916         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
2917         req.emr_in_buf = payload;
2918         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
2919         req.emr_out_buf = payload;
2920         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
2921
2922         EFX_STATIC_ASSERT(sizeof (*rule_response) <=
2923             MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
2924         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
2925         rule_response = (efx_oword_t *)(payload + offset);
2926         EFX_POPULATE_OWORD_3(*rule_response,
2927             MAE_ACTION_RULE_RESPONSE_ASL_ID,
2928             (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
2929             MAE_ACTION_RULE_RESPONSE_AS_ID,
2930             (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
2931             MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
2932
2933         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
2934
2935         /*
2936          * Mask-value pairs have been stored in the byte order needed for the
2937          * MCDI request and are thus safe to be copied directly to the buffer.
2938          */
2939         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
2940             MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
2941         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
2942         memcpy(payload + offset, spec->emms_mask_value_pairs.action,
2943             MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
2944
2945         efx_mcdi_execute(enp, &req);
2946
2947         if (req.emr_rc != 0) {
2948                 rc = req.emr_rc;
2949                 goto fail3;
2950         }
2951
2952         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
2953                 rc = EMSGSIZE;
2954                 goto fail4;
2955         }
2956
2957         ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
2958         if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
2959                 rc = ENOENT;
2960                 goto fail5;
2961         }
2962
2963         ar_idp->id = ar_id.id;
2964
2965         return (0);
2966
2967 fail5:
2968         EFSYS_PROBE(fail5);
2969 fail4:
2970         EFSYS_PROBE(fail4);
2971 fail3:
2972         EFSYS_PROBE(fail3);
2973 fail2:
2974         EFSYS_PROBE(fail2);
2975 fail1:
2976         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2977         return (rc);
2978 }
2979
2980         __checkReturn                   efx_rc_t
2981 efx_mae_action_rule_remove(
2982         __in                            efx_nic_t *enp,
2983         __in                            const efx_mae_rule_id_t *ar_idp)
2984 {
2985         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2986         efx_mcdi_req_t req;
2987         EFX_MCDI_DECLARE_BUF(payload,
2988             MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
2989             MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
2990         efx_rc_t rc;
2991
2992         if (encp->enc_mae_supported == B_FALSE) {
2993                 rc = ENOTSUP;
2994                 goto fail1;
2995         }
2996
2997         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
2998         req.emr_in_buf = payload;
2999         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
3000         req.emr_out_buf = payload;
3001         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
3002
3003         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
3004
3005         efx_mcdi_execute(enp, &req);
3006
3007         if (req.emr_rc != 0) {
3008                 rc = req.emr_rc;
3009                 goto fail2;
3010         }
3011
3012         if (req.emr_out_length_used <
3013             MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LENMIN) {
3014                 rc = EMSGSIZE;
3015                 goto fail3;
3016         }
3017
3018         if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
3019             ar_idp->id) {
3020                 /* Firmware failed to delete the action rule. */
3021                 rc = EAGAIN;
3022                 goto fail4;
3023         }
3024
3025         return (0);
3026
3027 fail4:
3028         EFSYS_PROBE(fail4);
3029 fail3:
3030         EFSYS_PROBE(fail3);
3031 fail2:
3032         EFSYS_PROBE(fail2);
3033 fail1:
3034         EFSYS_PROBE1(fail1, efx_rc_t, rc);
3035         return (rc);
3036 }
3037
3038 #endif /* EFSYS_OPT_MAE */