common/sfc_efx/base: add API to get mport ID by selector
[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 static  __checkReturn                   efx_rc_t
742 efx_mcdi_mae_mport_lookup(
743         __in                            efx_nic_t *enp,
744         __in                            const efx_mport_sel_t *mport_selectorp,
745         __out                           efx_mport_id_t *mport_idp)
746 {
747         efx_mcdi_req_t req;
748         EFX_MCDI_DECLARE_BUF(payload,
749             MC_CMD_MAE_MPORT_LOOKUP_IN_LEN,
750             MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN);
751         efx_rc_t rc;
752
753         req.emr_cmd = MC_CMD_MAE_MPORT_LOOKUP;
754         req.emr_in_buf = payload;
755         req.emr_in_length = MC_CMD_MAE_MPORT_LOOKUP_IN_LEN;
756         req.emr_out_buf = payload;
757         req.emr_out_length = MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN;
758
759         MCDI_IN_SET_DWORD(req, MAE_MPORT_LOOKUP_IN_MPORT_SELECTOR,
760             mport_selectorp->sel);
761
762         efx_mcdi_execute(enp, &req);
763
764         if (req.emr_rc != 0) {
765                 rc = req.emr_rc;
766                 goto fail1;
767         }
768
769         mport_idp->id = MCDI_OUT_DWORD(req, MAE_MPORT_LOOKUP_OUT_MPORT_ID);
770
771         return (0);
772
773 fail1:
774         EFSYS_PROBE1(fail1, efx_rc_t, rc);
775         return (rc);
776 }
777
778         __checkReturn                   efx_rc_t
779 efx_mae_mport_id_by_selector(
780         __in                            efx_nic_t *enp,
781         __in                            const efx_mport_sel_t *mport_selectorp,
782         __out                           efx_mport_id_t *mport_idp)
783 {
784         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
785         efx_rc_t rc;
786
787         if (encp->enc_mae_supported == B_FALSE) {
788                 rc = ENOTSUP;
789                 goto fail1;
790         }
791
792         rc = efx_mcdi_mae_mport_lookup(enp, mport_selectorp, mport_idp);
793         if (rc != 0)
794                 goto fail2;
795
796         return (0);
797
798 fail2:
799         EFSYS_PROBE(fail2);
800 fail1:
801         EFSYS_PROBE1(fail1, efx_rc_t, rc);
802         return (rc);
803 }
804
805         __checkReturn                   efx_rc_t
806 efx_mae_match_spec_field_set(
807         __in                            efx_mae_match_spec_t *spec,
808         __in                            efx_mae_field_id_t field_id,
809         __in                            size_t value_size,
810         __in_bcount(value_size)         const uint8_t *value,
811         __in                            size_t mask_size,
812         __in_bcount(mask_size)          const uint8_t *mask)
813 {
814         const efx_mae_mv_desc_t *descp;
815         unsigned int desc_set_nentries;
816         uint8_t *mvp;
817         efx_rc_t rc;
818
819         switch (spec->emms_type) {
820         case EFX_MAE_RULE_OUTER:
821                 desc_set_nentries =
822                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
823                 descp = &__efx_mae_outer_rule_mv_desc_set[field_id];
824                 mvp = spec->emms_mask_value_pairs.outer;
825                 break;
826         case EFX_MAE_RULE_ACTION:
827                 desc_set_nentries =
828                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
829                 descp = &__efx_mae_action_rule_mv_desc_set[field_id];
830                 mvp = spec->emms_mask_value_pairs.action;
831                 break;
832         default:
833                 rc = ENOTSUP;
834                 goto fail1;
835         }
836
837         if ((unsigned int)field_id >= desc_set_nentries) {
838                 rc = EINVAL;
839                 goto fail2;
840         }
841
842         if (descp->emmd_mask_size == 0) {
843                 /* The ID points to a gap in the array of field descriptors. */
844                 rc = EINVAL;
845                 goto fail3;
846         }
847
848         if (value_size != descp->emmd_value_size) {
849                 rc = EINVAL;
850                 goto fail4;
851         }
852
853         if (mask_size != descp->emmd_mask_size) {
854                 rc = EINVAL;
855                 goto fail5;
856         }
857
858         if (descp->emmd_endianness == EFX_MAE_FIELD_BE) {
859                 unsigned int i;
860
861                 /*
862                  * The mask/value are in network (big endian) order.
863                  * The MCDI request field is also big endian.
864                  */
865
866                 EFSYS_ASSERT3U(value_size, ==, mask_size);
867
868                 for (i = 0; i < value_size; ++i) {
869                         uint8_t *v_bytep = mvp + descp->emmd_value_offset + i;
870                         uint8_t *m_bytep = mvp + descp->emmd_mask_offset + i;
871
872                         /*
873                          * Apply the mask (which may be all-zeros) to the value.
874                          *
875                          * If this API is provided with some value to set for a
876                          * given field in one specification and with some other
877                          * value to set for this field in another specification,
878                          * then, if the two masks are all-zeros, the field will
879                          * avoid being counted as a mismatch when comparing the
880                          * specifications using efx_mae_match_specs_equal() API.
881                          */
882                         *v_bytep = value[i] & mask[i];
883                         *m_bytep = mask[i];
884                 }
885         } else {
886                 efx_dword_t dword;
887
888                 /*
889                  * The mask/value are in host byte order.
890                  * The MCDI request field is little endian.
891                  */
892                 switch (value_size) {
893                 case 4:
894                         EFX_POPULATE_DWORD_1(dword,
895                             EFX_DWORD_0, *(const uint32_t *)value);
896
897                         memcpy(mvp + descp->emmd_value_offset,
898                             &dword, sizeof (dword));
899                         break;
900                 default:
901                         EFSYS_ASSERT(B_FALSE);
902                 }
903
904                 switch (mask_size) {
905                 case 4:
906                         EFX_POPULATE_DWORD_1(dword,
907                             EFX_DWORD_0, *(const uint32_t *)mask);
908
909                         memcpy(mvp + descp->emmd_mask_offset,
910                             &dword, sizeof (dword));
911                         break;
912                 default:
913                         EFSYS_ASSERT(B_FALSE);
914                 }
915         }
916
917         return (0);
918
919 fail5:
920         EFSYS_PROBE(fail5);
921 fail4:
922         EFSYS_PROBE(fail4);
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_bit_set(
934         __in                            efx_mae_match_spec_t *spec,
935         __in                            efx_mae_field_id_t field_id,
936         __in                            boolean_t value)
937 {
938         const efx_mae_mv_bit_desc_t *bit_descp;
939         unsigned int bit_desc_set_nentries;
940         unsigned int byte_idx;
941         unsigned int bit_idx;
942         uint8_t *mvp;
943         efx_rc_t rc;
944
945         switch (spec->emms_type) {
946         case EFX_MAE_RULE_OUTER:
947                 bit_desc_set_nentries =
948                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
949                 bit_descp = &__efx_mae_outer_rule_mv_bit_desc_set[field_id];
950                 mvp = spec->emms_mask_value_pairs.outer;
951                 break;
952         case EFX_MAE_RULE_ACTION:
953                 bit_desc_set_nentries =
954                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
955                 bit_descp = &__efx_mae_action_rule_mv_bit_desc_set[field_id];
956                 mvp = spec->emms_mask_value_pairs.action;
957                 break;
958         default:
959                 rc = ENOTSUP;
960                 goto fail1;
961         }
962
963         if ((unsigned int)field_id >= bit_desc_set_nentries) {
964                 rc = EINVAL;
965                 goto fail2;
966         }
967
968         if (bit_descp->emmbd_entry_is_valid == B_FALSE) {
969                 rc = EINVAL;
970                 goto fail3;
971         }
972
973         byte_idx = bit_descp->emmbd_value_ofst + bit_descp->emmbd_value_lbn / 8;
974         bit_idx = bit_descp->emmbd_value_lbn % 8;
975
976         if (value != B_FALSE)
977                 mvp[byte_idx] |= (1U << bit_idx);
978         else
979                 mvp[byte_idx] &= ~(1U << bit_idx);
980
981         byte_idx = bit_descp->emmbd_mask_ofst + bit_descp->emmbd_mask_lbn / 8;
982         bit_idx = bit_descp->emmbd_mask_lbn % 8;
983         mvp[byte_idx] |= (1U << bit_idx);
984
985         return (0);
986
987 fail3:
988         EFSYS_PROBE(fail3);
989 fail2:
990         EFSYS_PROBE(fail2);
991 fail1:
992         EFSYS_PROBE1(fail1, efx_rc_t, rc);
993         return (rc);
994 }
995
996         __checkReturn                   efx_rc_t
997 efx_mae_match_spec_mport_set(
998         __in                            efx_mae_match_spec_t *spec,
999         __in                            const efx_mport_sel_t *valuep,
1000         __in_opt                        const efx_mport_sel_t *maskp)
1001 {
1002         uint32_t full_mask = UINT32_MAX;
1003         const uint8_t *vp;
1004         const uint8_t *mp;
1005         efx_rc_t rc;
1006
1007         if (valuep == NULL) {
1008                 rc = EINVAL;
1009                 goto fail1;
1010         }
1011
1012         vp = (const uint8_t *)&valuep->sel;
1013         if (maskp != NULL)
1014                 mp = (const uint8_t *)&maskp->sel;
1015         else
1016                 mp = (const uint8_t *)&full_mask;
1017
1018         rc = efx_mae_match_spec_field_set(spec,
1019             EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR,
1020             sizeof (valuep->sel), vp, sizeof (maskp->sel), mp);
1021         if (rc != 0)
1022                 goto fail2;
1023
1024         return (0);
1025
1026 fail2:
1027         EFSYS_PROBE(fail2);
1028 fail1:
1029         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1030         return (rc);
1031 }
1032
1033         __checkReturn                   boolean_t
1034 efx_mae_match_specs_equal(
1035         __in                            const efx_mae_match_spec_t *left,
1036         __in                            const efx_mae_match_spec_t *right)
1037 {
1038         return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
1039 }
1040
1041 #define EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit)              \
1042             ((_mask)[(_bit) / (_mask_page_nbits)] &                     \
1043                     (1ULL << ((_bit) & ((_mask_page_nbits) - 1))))
1044
1045 static                                  boolean_t
1046 efx_mask_is_prefix(
1047         __in                            size_t mask_nbytes,
1048         __in_bcount(mask_nbytes)        const uint8_t *maskp)
1049 {
1050         boolean_t prev_bit_is_set = B_TRUE;
1051         unsigned int i;
1052
1053         for (i = 0; i < 8 * mask_nbytes; ++i) {
1054                 boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i);
1055
1056                 if (!prev_bit_is_set && bit_is_set)
1057                         return B_FALSE;
1058
1059                 prev_bit_is_set = bit_is_set;
1060         }
1061
1062         return B_TRUE;
1063 }
1064
1065 static                                  boolean_t
1066 efx_mask_is_all_ones(
1067         __in                            size_t mask_nbytes,
1068         __in_bcount(mask_nbytes)        const uint8_t *maskp)
1069 {
1070         unsigned int i;
1071         uint8_t t = ~0;
1072
1073         for (i = 0; i < mask_nbytes; ++i)
1074                 t &= maskp[i];
1075
1076         return (t == (uint8_t)(~0));
1077 }
1078
1079 static                                  boolean_t
1080 efx_mask_is_all_zeros(
1081         __in                            size_t mask_nbytes,
1082         __in_bcount(mask_nbytes)        const uint8_t *maskp)
1083 {
1084         unsigned int i;
1085         uint8_t t = 0;
1086
1087         for (i = 0; i < mask_nbytes; ++i)
1088                 t |= maskp[i];
1089
1090         return (t == 0);
1091 }
1092
1093         __checkReturn                   boolean_t
1094 efx_mae_match_spec_is_valid(
1095         __in                            efx_nic_t *enp,
1096         __in                            const efx_mae_match_spec_t *spec)
1097 {
1098         efx_mae_t *maep = enp->en_maep;
1099         unsigned int field_ncaps = maep->em_max_nfields;
1100         const efx_mae_field_cap_t *field_caps;
1101         const efx_mae_mv_desc_t *desc_setp;
1102         unsigned int desc_set_nentries;
1103         const efx_mae_mv_bit_desc_t *bit_desc_setp;
1104         unsigned int bit_desc_set_nentries;
1105         boolean_t is_valid = B_TRUE;
1106         efx_mae_field_id_t field_id;
1107         const uint8_t *mvp;
1108
1109         switch (spec->emms_type) {
1110         case EFX_MAE_RULE_OUTER:
1111                 field_caps = maep->em_outer_rule_field_caps;
1112                 desc_setp = __efx_mae_outer_rule_mv_desc_set;
1113                 desc_set_nentries =
1114                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1115                 bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
1116                 bit_desc_set_nentries =
1117                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
1118                 mvp = spec->emms_mask_value_pairs.outer;
1119                 break;
1120         case EFX_MAE_RULE_ACTION:
1121                 field_caps = maep->em_action_rule_field_caps;
1122                 desc_setp = __efx_mae_action_rule_mv_desc_set;
1123                 desc_set_nentries =
1124                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1125                 bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
1126                 bit_desc_set_nentries =
1127                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
1128                 mvp = spec->emms_mask_value_pairs.action;
1129                 break;
1130         default:
1131                 return (B_FALSE);
1132         }
1133
1134         if (field_caps == NULL)
1135                 return (B_FALSE);
1136
1137         for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1138              ++field_id) {
1139                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1140                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1141                 const uint8_t *alt_m_buf = mvp + descp->emmd_alt_mask_offset;
1142                 const uint8_t *m_buf = mvp + descp->emmd_mask_offset;
1143                 size_t alt_m_size = descp->emmd_alt_mask_size;
1144                 size_t m_size = descp->emmd_mask_size;
1145
1146                 if (m_size == 0)
1147                         continue; /* Skip array gap */
1148
1149                 if ((unsigned int)field_cap_id >= field_ncaps) {
1150                         /*
1151                          * The FW has not reported capability status for
1152                          * this field. Make sure that its mask is zeroed.
1153                          */
1154                         is_valid = efx_mask_is_all_zeros(m_size, m_buf);
1155                         if (is_valid != B_FALSE)
1156                                 continue;
1157                         else
1158                                 break;
1159                 }
1160
1161                 switch (field_caps[field_cap_id].emfc_support) {
1162                 case MAE_FIELD_SUPPORTED_MATCH_MASK:
1163                         is_valid = B_TRUE;
1164                         break;
1165                 case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
1166                         is_valid = efx_mask_is_prefix(m_size, m_buf);
1167                         break;
1168                 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
1169                         is_valid = (efx_mask_is_all_ones(m_size, m_buf) ||
1170                             efx_mask_is_all_zeros(m_size, m_buf));
1171                         break;
1172                 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
1173                         is_valid = efx_mask_is_all_ones(m_size, m_buf);
1174
1175                         if ((is_valid == B_FALSE) && (alt_m_size != 0)) {
1176                                 /*
1177                                  * This field has an alternative one. The FW
1178                                  * reports ALWAYS for both implying that one
1179                                  * of them is required to have all-ones mask.
1180                                  *
1181                                  * The primary field's mask is incorrect; go
1182                                  * on to check that of the alternative field.
1183                                  */
1184                                 is_valid = efx_mask_is_all_ones(alt_m_size,
1185                                                                 alt_m_buf);
1186                         }
1187                         break;
1188                 case MAE_FIELD_SUPPORTED_MATCH_NEVER:
1189                 case MAE_FIELD_UNSUPPORTED:
1190                 default:
1191                         is_valid = efx_mask_is_all_zeros(m_size, m_buf);
1192                         break;
1193                 }
1194
1195                 if (is_valid == B_FALSE)
1196                         return (B_FALSE);
1197         }
1198
1199         for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
1200              ++field_id) {
1201                 const efx_mae_mv_bit_desc_t *bit_descp =
1202                     &bit_desc_setp[field_id];
1203                 unsigned int byte_idx =
1204                     bit_descp->emmbd_mask_ofst +
1205                     bit_descp->emmbd_mask_lbn / 8;
1206                 unsigned int bit_idx =
1207                     bit_descp->emmbd_mask_lbn % 8;
1208                 efx_mae_field_cap_id_t bit_cap_id =
1209                     bit_descp->emmbd_bit_cap_id;
1210
1211                 if (bit_descp->emmbd_entry_is_valid == B_FALSE)
1212                         continue; /* Skip array gap */
1213
1214                 if ((unsigned int)bit_cap_id >= field_ncaps) {
1215                         /* No capability for this bit = unsupported. */
1216                         is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0);
1217                         if (is_valid == B_FALSE)
1218                                 break;
1219                         else
1220                                 continue;
1221                 }
1222
1223                 switch (field_caps[bit_cap_id].emfc_support) {
1224                 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
1225                         is_valid = B_TRUE;
1226                         break;
1227                 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
1228                         is_valid = ((mvp[byte_idx] & (1U << bit_idx)) != 0);
1229                         break;
1230                 case MAE_FIELD_SUPPORTED_MATCH_NEVER:
1231                 case MAE_FIELD_UNSUPPORTED:
1232                 default:
1233                         is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0);
1234                         break;
1235                 }
1236
1237                 if (is_valid == B_FALSE)
1238                         break;
1239         }
1240
1241         return (is_valid);
1242 }
1243
1244         __checkReturn                   efx_rc_t
1245 efx_mae_action_set_spec_init(
1246         __in                            efx_nic_t *enp,
1247         __out                           efx_mae_actions_t **specp)
1248 {
1249         efx_mae_actions_t *spec;
1250         efx_rc_t rc;
1251
1252         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
1253         if (spec == NULL) {
1254                 rc = ENOMEM;
1255                 goto fail1;
1256         }
1257
1258         spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
1259         spec->ema_rsrc.emar_counter_id.id = EFX_MAE_RSRC_ID_INVALID;
1260
1261         *specp = spec;
1262
1263         return (0);
1264
1265 fail1:
1266         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1267         return (rc);
1268 }
1269
1270                                         void
1271 efx_mae_action_set_spec_fini(
1272         __in                            efx_nic_t *enp,
1273         __in                            efx_mae_actions_t *spec)
1274 {
1275         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
1276 }
1277
1278 static  __checkReturn                   efx_rc_t
1279 efx_mae_action_set_add_decap(
1280         __in                            efx_mae_actions_t *spec,
1281         __in                            size_t arg_size,
1282         __in_bcount(arg_size)           const uint8_t *arg)
1283 {
1284         efx_rc_t rc;
1285
1286         _NOTE(ARGUNUSED(spec))
1287
1288         if (arg_size != 0) {
1289                 rc = EINVAL;
1290                 goto fail1;
1291         }
1292
1293         if (arg != NULL) {
1294                 rc = EINVAL;
1295                 goto fail2;
1296         }
1297
1298         /* This action does not have any arguments, so do nothing here. */
1299
1300         return (0);
1301
1302 fail2:
1303         EFSYS_PROBE(fail2);
1304 fail1:
1305         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1306         return (rc);
1307 }
1308
1309 static  __checkReturn                   efx_rc_t
1310 efx_mae_action_set_add_vlan_pop(
1311         __in                            efx_mae_actions_t *spec,
1312         __in                            size_t arg_size,
1313         __in_bcount(arg_size)           const uint8_t *arg)
1314 {
1315         efx_rc_t rc;
1316
1317         if (arg_size != 0) {
1318                 rc = EINVAL;
1319                 goto fail1;
1320         }
1321
1322         if (arg != NULL) {
1323                 rc = EINVAL;
1324                 goto fail2;
1325         }
1326
1327         if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) {
1328                 rc = ENOTSUP;
1329                 goto fail3;
1330         }
1331
1332         ++spec->ema_n_vlan_tags_to_pop;
1333
1334         return (0);
1335
1336 fail3:
1337         EFSYS_PROBE(fail3);
1338 fail2:
1339         EFSYS_PROBE(fail2);
1340 fail1:
1341         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1342         return (rc);
1343 }
1344
1345 static  __checkReturn                   efx_rc_t
1346 efx_mae_action_set_add_vlan_push(
1347         __in                            efx_mae_actions_t *spec,
1348         __in                            size_t arg_size,
1349         __in_bcount(arg_size)           const uint8_t *arg)
1350 {
1351         unsigned int n_tags = spec->ema_n_vlan_tags_to_push;
1352         efx_rc_t rc;
1353
1354         if (arg_size != sizeof (*spec->ema_vlan_push_descs)) {
1355                 rc = EINVAL;
1356                 goto fail1;
1357         }
1358
1359         if (arg == NULL) {
1360                 rc = EINVAL;
1361                 goto fail2;
1362         }
1363
1364         if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1365                 rc = ENOTSUP;
1366                 goto fail3;
1367         }
1368
1369         memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size);
1370         ++(spec->ema_n_vlan_tags_to_push);
1371
1372         return (0);
1373
1374 fail3:
1375         EFSYS_PROBE(fail3);
1376 fail2:
1377         EFSYS_PROBE(fail2);
1378 fail1:
1379         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1380         return (rc);
1381 }
1382
1383 static  __checkReturn                   efx_rc_t
1384 efx_mae_action_set_add_encap(
1385         __in                            efx_mae_actions_t *spec,
1386         __in                            size_t arg_size,
1387         __in_bcount(arg_size)           const uint8_t *arg)
1388 {
1389         efx_rc_t rc;
1390
1391         /*
1392          * Adding this specific action to an action set spec and setting encap.
1393          * header ID in the spec are two individual steps. This design allows
1394          * the client driver to avoid encap. header allocation when it simply
1395          * needs to check the order of actions submitted by user ("validate"),
1396          * without actually allocating an action set and inserting a rule.
1397          *
1398          * For now, mark encap. header ID as invalid; the caller will invoke
1399          * efx_mae_action_set_fill_in_eh_id() to override the field prior
1400          * to action set allocation; otherwise, the allocation will fail.
1401          */
1402         spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
1403
1404         /*
1405          * As explained above, there are no arguments to handle here.
1406          * efx_mae_action_set_fill_in_eh_id() will take care of them.
1407          */
1408         if (arg_size != 0) {
1409                 rc = EINVAL;
1410                 goto fail1;
1411         }
1412
1413         if (arg != NULL) {
1414                 rc = EINVAL;
1415                 goto fail2;
1416         }
1417
1418         return (0);
1419
1420 fail2:
1421         EFSYS_PROBE(fail2);
1422 fail1:
1423         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1424         return (rc);
1425 }
1426
1427 static  __checkReturn                   efx_rc_t
1428 efx_mae_action_set_add_count(
1429         __in                            efx_mae_actions_t *spec,
1430         __in                            size_t arg_size,
1431         __in_bcount(arg_size)           const uint8_t *arg)
1432 {
1433         efx_rc_t rc;
1434
1435         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1436                           MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL);
1437
1438         /*
1439          * Preparing an action set spec to update a counter requires
1440          * two steps: first add this action to the action spec, and then
1441          * add the counter ID to the spec. This allows validity checking
1442          * and resource allocation to be done separately.
1443          * Mark the counter ID as invalid in the spec to ensure that the
1444          * caller must also invoke efx_mae_action_set_fill_in_counter_id()
1445          * before action set allocation.
1446          */
1447         spec->ema_rsrc.emar_counter_id.id = EFX_MAE_RSRC_ID_INVALID;
1448
1449         /* Nothing else is supposed to take place over here. */
1450         if (arg_size != 0) {
1451                 rc = EINVAL;
1452                 goto fail1;
1453         }
1454
1455         if (arg != NULL) {
1456                 rc = EINVAL;
1457                 goto fail2;
1458         }
1459
1460         ++(spec->ema_n_count_actions);
1461
1462         return (0);
1463
1464 fail2:
1465         EFSYS_PROBE(fail2);
1466 fail1:
1467         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1468         return (rc);
1469 }
1470
1471 static  __checkReturn                   efx_rc_t
1472 efx_mae_action_set_add_flag(
1473         __in                            efx_mae_actions_t *spec,
1474         __in                            size_t arg_size,
1475         __in_bcount(arg_size)           const uint8_t *arg)
1476 {
1477         efx_rc_t rc;
1478
1479         _NOTE(ARGUNUSED(spec))
1480
1481         if (arg_size != 0) {
1482                 rc = EINVAL;
1483                 goto fail1;
1484         }
1485
1486         if (arg != NULL) {
1487                 rc = EINVAL;
1488                 goto fail2;
1489         }
1490
1491         /* This action does not have any arguments, so do nothing here. */
1492
1493         return (0);
1494
1495 fail2:
1496         EFSYS_PROBE(fail2);
1497 fail1:
1498         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1499         return (rc);
1500 }
1501
1502 static  __checkReturn                   efx_rc_t
1503 efx_mae_action_set_add_mark(
1504         __in                            efx_mae_actions_t *spec,
1505         __in                            size_t arg_size,
1506         __in_bcount(arg_size)           const uint8_t *arg)
1507 {
1508         efx_rc_t rc;
1509
1510         if (arg_size != sizeof (spec->ema_mark_value)) {
1511                 rc = EINVAL;
1512                 goto fail1;
1513         }
1514
1515         if (arg == NULL) {
1516                 rc = EINVAL;
1517                 goto fail2;
1518         }
1519
1520         memcpy(&spec->ema_mark_value, arg, arg_size);
1521
1522         return (0);
1523
1524 fail2:
1525         EFSYS_PROBE(fail2);
1526 fail1:
1527         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1528         return (rc);
1529 }
1530
1531 static  __checkReturn                   efx_rc_t
1532 efx_mae_action_set_add_deliver(
1533         __in                            efx_mae_actions_t *spec,
1534         __in                            size_t arg_size,
1535         __in_bcount(arg_size)           const uint8_t *arg)
1536 {
1537         efx_rc_t rc;
1538
1539         if (arg_size != sizeof (spec->ema_deliver_mport)) {
1540                 rc = EINVAL;
1541                 goto fail1;
1542         }
1543
1544         if (arg == NULL) {
1545                 rc = EINVAL;
1546                 goto fail2;
1547         }
1548
1549         memcpy(&spec->ema_deliver_mport, arg, arg_size);
1550
1551         return (0);
1552
1553 fail2:
1554         EFSYS_PROBE(fail2);
1555 fail1:
1556         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1557         return (rc);
1558 }
1559
1560 typedef struct efx_mae_action_desc_s {
1561         /* Action specific handler */
1562         efx_rc_t        (*emad_add)(efx_mae_actions_t *,
1563                                     size_t, const uint8_t *);
1564 } efx_mae_action_desc_t;
1565
1566 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
1567         [EFX_MAE_ACTION_DECAP] = {
1568                 .emad_add = efx_mae_action_set_add_decap
1569         },
1570         [EFX_MAE_ACTION_VLAN_POP] = {
1571                 .emad_add = efx_mae_action_set_add_vlan_pop
1572         },
1573         [EFX_MAE_ACTION_VLAN_PUSH] = {
1574                 .emad_add = efx_mae_action_set_add_vlan_push
1575         },
1576         [EFX_MAE_ACTION_ENCAP] = {
1577                 .emad_add = efx_mae_action_set_add_encap
1578         },
1579         [EFX_MAE_ACTION_COUNT] = {
1580                 .emad_add = efx_mae_action_set_add_count
1581         },
1582         [EFX_MAE_ACTION_FLAG] = {
1583                 .emad_add = efx_mae_action_set_add_flag
1584         },
1585         [EFX_MAE_ACTION_MARK] = {
1586                 .emad_add = efx_mae_action_set_add_mark
1587         },
1588         [EFX_MAE_ACTION_DELIVER] = {
1589                 .emad_add = efx_mae_action_set_add_deliver
1590         }
1591 };
1592
1593 static const uint32_t efx_mae_action_ordered_map =
1594         (1U << EFX_MAE_ACTION_DECAP) |
1595         (1U << EFX_MAE_ACTION_VLAN_POP) |
1596         (1U << EFX_MAE_ACTION_VLAN_PUSH) |
1597         /*
1598          * HW will conduct action COUNT after
1599          * the matching packet has been modified by
1600          * length-affecting actions except for ENCAP.
1601          */
1602         (1U << EFX_MAE_ACTION_COUNT) |
1603         (1U << EFX_MAE_ACTION_ENCAP) |
1604         (1U << EFX_MAE_ACTION_FLAG) |
1605         (1U << EFX_MAE_ACTION_MARK) |
1606         (1U << EFX_MAE_ACTION_DELIVER);
1607
1608 /*
1609  * These actions must not be added after DELIVER, but
1610  * they can have any place among the rest of
1611  * strictly ordered actions.
1612  */
1613 static const uint32_t efx_mae_action_nonstrict_map =
1614         (1U << EFX_MAE_ACTION_COUNT) |
1615         (1U << EFX_MAE_ACTION_FLAG) |
1616         (1U << EFX_MAE_ACTION_MARK);
1617
1618 static const uint32_t efx_mae_action_repeat_map =
1619         (1U << EFX_MAE_ACTION_VLAN_POP) |
1620         (1U << EFX_MAE_ACTION_VLAN_PUSH) |
1621         (1U << EFX_MAE_ACTION_COUNT);
1622
1623 /*
1624  * Add an action to an action set.
1625  *
1626  * This has to be invoked in the desired action order.
1627  * An out-of-order action request will be turned down.
1628  */
1629 static  __checkReturn                   efx_rc_t
1630 efx_mae_action_set_spec_populate(
1631         __in                            efx_mae_actions_t *spec,
1632         __in                            efx_mae_action_t type,
1633         __in                            size_t arg_size,
1634         __in_bcount(arg_size)           const uint8_t *arg)
1635 {
1636         uint32_t action_mask;
1637         efx_rc_t rc;
1638
1639         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1640             (sizeof (efx_mae_action_ordered_map) * 8));
1641         EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1642             (sizeof (efx_mae_action_repeat_map) * 8));
1643
1644         EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
1645         EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK);
1646         EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER);
1647
1648         if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
1649                 rc = EINVAL;
1650                 goto fail1;
1651         }
1652
1653         action_mask = (1U << type);
1654
1655         if ((spec->ema_actions & action_mask) != 0) {
1656                 /* The action set already contains this action. */
1657                 if ((efx_mae_action_repeat_map & action_mask) == 0) {
1658                         /* Cannot add another non-repeatable action. */
1659                         rc = ENOTSUP;
1660                         goto fail2;
1661                 }
1662         }
1663
1664         if ((efx_mae_action_ordered_map & action_mask) != 0) {
1665                 uint32_t strict_ordered_map =
1666                     efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map;
1667                 uint32_t later_actions_mask =
1668                     strict_ordered_map & ~(action_mask | (action_mask - 1));
1669
1670                 if ((spec->ema_actions & later_actions_mask) != 0) {
1671                         /* Cannot add an action after later ordered actions. */
1672                         rc = ENOTSUP;
1673                         goto fail3;
1674                 }
1675         }
1676
1677         if (efx_mae_actions[type].emad_add != NULL) {
1678                 rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
1679                 if (rc != 0)
1680                         goto fail4;
1681         }
1682
1683         spec->ema_actions |= action_mask;
1684
1685         return (0);
1686
1687 fail4:
1688         EFSYS_PROBE(fail4);
1689 fail3:
1690         EFSYS_PROBE(fail3);
1691 fail2:
1692         EFSYS_PROBE(fail2);
1693 fail1:
1694         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1695         return (rc);
1696 }
1697
1698         __checkReturn                   efx_rc_t
1699 efx_mae_action_set_populate_decap(
1700         __in                            efx_mae_actions_t *spec)
1701 {
1702         return (efx_mae_action_set_spec_populate(spec,
1703             EFX_MAE_ACTION_DECAP, 0, NULL));
1704 }
1705
1706         __checkReturn                   efx_rc_t
1707 efx_mae_action_set_populate_vlan_pop(
1708         __in                            efx_mae_actions_t *spec)
1709 {
1710         return (efx_mae_action_set_spec_populate(spec,
1711             EFX_MAE_ACTION_VLAN_POP, 0, NULL));
1712 }
1713
1714         __checkReturn                   efx_rc_t
1715 efx_mae_action_set_populate_vlan_push(
1716         __in                            efx_mae_actions_t *spec,
1717         __in                            uint16_t tpid_be,
1718         __in                            uint16_t tci_be)
1719 {
1720         efx_mae_action_vlan_push_t action;
1721         const uint8_t *arg = (const uint8_t *)&action;
1722
1723         action.emavp_tpid_be = tpid_be;
1724         action.emavp_tci_be = tci_be;
1725
1726         return (efx_mae_action_set_spec_populate(spec,
1727             EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg));
1728 }
1729
1730         __checkReturn                   efx_rc_t
1731 efx_mae_action_set_populate_encap(
1732         __in                            efx_mae_actions_t *spec)
1733 {
1734         /*
1735          * There is no argument to pass encap. header ID, thus, one does not
1736          * need to allocate an encap. header while parsing application input.
1737          * This is useful since building an action set may be done simply to
1738          * validate a rule, whilst resource allocation usually consumes time.
1739          */
1740         return (efx_mae_action_set_spec_populate(spec,
1741             EFX_MAE_ACTION_ENCAP, 0, NULL));
1742 }
1743
1744         __checkReturn                   efx_rc_t
1745 efx_mae_action_set_populate_count(
1746         __in                            efx_mae_actions_t *spec)
1747 {
1748         /*
1749          * There is no argument to pass counter ID, thus, one does not
1750          * need to allocate a counter while parsing application input.
1751          * This is useful since building an action set may be done simply to
1752          * validate a rule, whilst resource allocation usually consumes time.
1753          */
1754         return (efx_mae_action_set_spec_populate(spec,
1755             EFX_MAE_ACTION_COUNT, 0, NULL));
1756 }
1757
1758         __checkReturn                   efx_rc_t
1759 efx_mae_action_set_populate_flag(
1760         __in                            efx_mae_actions_t *spec)
1761 {
1762         return (efx_mae_action_set_spec_populate(spec,
1763             EFX_MAE_ACTION_FLAG, 0, NULL));
1764 }
1765
1766         __checkReturn                   efx_rc_t
1767 efx_mae_action_set_populate_mark(
1768         __in                            efx_mae_actions_t *spec,
1769         __in                            uint32_t mark_value)
1770 {
1771         const uint8_t *arg = (const uint8_t *)&mark_value;
1772
1773         return (efx_mae_action_set_spec_populate(spec,
1774             EFX_MAE_ACTION_MARK, sizeof (mark_value), arg));
1775 }
1776
1777         __checkReturn                   efx_rc_t
1778 efx_mae_action_set_populate_deliver(
1779         __in                            efx_mae_actions_t *spec,
1780         __in                            const efx_mport_sel_t *mportp)
1781 {
1782         const uint8_t *arg;
1783         efx_rc_t rc;
1784
1785         if (mportp == NULL) {
1786                 rc = EINVAL;
1787                 goto fail1;
1788         }
1789
1790         arg = (const uint8_t *)&mportp->sel;
1791
1792         return (efx_mae_action_set_spec_populate(spec,
1793             EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
1794
1795 fail1:
1796         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1797         return (rc);
1798 }
1799
1800         __checkReturn                   efx_rc_t
1801 efx_mae_action_set_populate_drop(
1802         __in                            efx_mae_actions_t *spec)
1803 {
1804         efx_mport_sel_t mport;
1805         const uint8_t *arg;
1806         efx_dword_t dword;
1807
1808         EFX_POPULATE_DWORD_1(dword,
1809             MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL);
1810
1811         /*
1812          * The constructed DWORD is little-endian,
1813          * but the resulting value is meant to be
1814          * passed to MCDIs, where it will undergo
1815          * host-order to little endian conversion.
1816          */
1817         mport.sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
1818
1819         arg = (const uint8_t *)&mport.sel;
1820
1821         return (efx_mae_action_set_spec_populate(spec,
1822             EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg));
1823 }
1824
1825         __checkReturn                   boolean_t
1826 efx_mae_action_set_specs_equal(
1827         __in                            const efx_mae_actions_t *left,
1828         __in                            const efx_mae_actions_t *right)
1829 {
1830         size_t cmp_size = EFX_FIELD_OFFSET(efx_mae_actions_t, ema_rsrc);
1831
1832         /*
1833          * An action set specification consists of two parts. The first part
1834          * indicates what actions are included in the action set, as well as
1835          * extra quantitative values (in example, the number of VLAN tags to
1836          * push). The second part comprises resource IDs used by the actions.
1837          *
1838          * A resource, in example, a counter, is allocated from the hardware
1839          * by the client, and it's the client who is responsible for keeping
1840          * track of allocated resources and comparing resource IDs if needed.
1841          *
1842          * In this API, don't compare resource IDs in the two specifications.
1843          */
1844
1845         return ((memcmp(left, right, cmp_size) == 0) ? B_TRUE : B_FALSE);
1846 }
1847
1848         __checkReturn                   efx_rc_t
1849 efx_mae_match_specs_class_cmp(
1850         __in                            efx_nic_t *enp,
1851         __in                            const efx_mae_match_spec_t *left,
1852         __in                            const efx_mae_match_spec_t *right,
1853         __out                           boolean_t *have_same_classp)
1854 {
1855         efx_mae_t *maep = enp->en_maep;
1856         unsigned int field_ncaps = maep->em_max_nfields;
1857         const efx_mae_field_cap_t *field_caps;
1858         const efx_mae_mv_desc_t *desc_setp;
1859         unsigned int desc_set_nentries;
1860         const efx_mae_mv_bit_desc_t *bit_desc_setp;
1861         unsigned int bit_desc_set_nentries;
1862         boolean_t have_same_class = B_TRUE;
1863         efx_mae_field_id_t field_id;
1864         const uint8_t *mvpl;
1865         const uint8_t *mvpr;
1866         efx_rc_t rc;
1867
1868         switch (left->emms_type) {
1869         case EFX_MAE_RULE_OUTER:
1870                 field_caps = maep->em_outer_rule_field_caps;
1871                 desc_setp = __efx_mae_outer_rule_mv_desc_set;
1872                 desc_set_nentries =
1873                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1874                 bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
1875                 bit_desc_set_nentries =
1876                     EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
1877                 mvpl = left->emms_mask_value_pairs.outer;
1878                 mvpr = right->emms_mask_value_pairs.outer;
1879                 break;
1880         case EFX_MAE_RULE_ACTION:
1881                 field_caps = maep->em_action_rule_field_caps;
1882                 desc_setp = __efx_mae_action_rule_mv_desc_set;
1883                 desc_set_nentries =
1884                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1885                 bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
1886                 bit_desc_set_nentries =
1887                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
1888                 mvpl = left->emms_mask_value_pairs.action;
1889                 mvpr = right->emms_mask_value_pairs.action;
1890                 break;
1891         default:
1892                 rc = ENOTSUP;
1893                 goto fail1;
1894         }
1895
1896         if (field_caps == NULL) {
1897                 rc = EAGAIN;
1898                 goto fail2;
1899         }
1900
1901         if (left->emms_type != right->emms_type ||
1902             left->emms_prio != right->emms_prio) {
1903                 /*
1904                  * Rules of different types can never map to the same class.
1905                  *
1906                  * The FW can support some set of match criteria for one
1907                  * priority and not support the very same set for
1908                  * another priority. Thus, two rules which have
1909                  * different priorities can never map to
1910                  * the same class.
1911                  */
1912                 *have_same_classp = B_FALSE;
1913                 return (0);
1914         }
1915
1916         for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1917              ++field_id) {
1918                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1919                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1920                 const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
1921                 const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
1922                 size_t mask_size = descp->emmd_mask_size;
1923                 const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
1924                 const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
1925                 size_t value_size = descp->emmd_value_size;
1926
1927                 if (mask_size == 0)
1928                         continue; /* Skip array gap */
1929
1930                 if ((unsigned int)field_cap_id >= field_ncaps) {
1931                         /*
1932                          * The FW has not reported capability status for this
1933                          * field. It's unknown whether any difference between
1934                          * the two masks / values affects the class. The only
1935                          * case when the class must be the same is when these
1936                          * mask-value pairs match. Otherwise, report mismatch.
1937                          */
1938                         if ((memcmp(lmaskp, rmaskp, mask_size) == 0) &&
1939                             (memcmp(lvalp, rvalp, value_size) == 0))
1940                                 continue;
1941                         else
1942                                 break;
1943                 }
1944
1945                 if (field_caps[field_cap_id].emfc_mask_affects_class) {
1946                         if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
1947                                 have_same_class = B_FALSE;
1948                                 break;
1949                         }
1950                 }
1951
1952                 if (field_caps[field_cap_id].emfc_match_affects_class) {
1953                         if (memcmp(lvalp, rvalp, value_size) != 0) {
1954                                 have_same_class = B_FALSE;
1955                                 break;
1956                         }
1957                 }
1958         }
1959
1960         if (have_same_class == B_FALSE)
1961                 goto done;
1962
1963         for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
1964              ++field_id) {
1965                 const efx_mae_mv_bit_desc_t *bit_descp =
1966                     &bit_desc_setp[field_id];
1967                 efx_mae_field_cap_id_t bit_cap_id =
1968                     bit_descp->emmbd_bit_cap_id;
1969                 unsigned int byte_idx;
1970                 unsigned int bit_idx;
1971
1972                 if (bit_descp->emmbd_entry_is_valid == B_FALSE)
1973                         continue; /* Skip array gap */
1974
1975                 if ((unsigned int)bit_cap_id >= field_ncaps)
1976                         break;
1977
1978                 byte_idx =
1979                     bit_descp->emmbd_mask_ofst +
1980                     bit_descp->emmbd_mask_lbn / 8;
1981                 bit_idx =
1982                     bit_descp->emmbd_mask_lbn % 8;
1983
1984                 if (field_caps[bit_cap_id].emfc_mask_affects_class &&
1985                     (mvpl[byte_idx] & (1U << bit_idx)) !=
1986                     (mvpr[byte_idx] & (1U << bit_idx))) {
1987                         have_same_class = B_FALSE;
1988                         break;
1989                 }
1990
1991                 byte_idx =
1992                     bit_descp->emmbd_value_ofst +
1993                     bit_descp->emmbd_value_lbn / 8;
1994                 bit_idx =
1995                     bit_descp->emmbd_value_lbn % 8;
1996
1997                 if (field_caps[bit_cap_id].emfc_match_affects_class &&
1998                     (mvpl[byte_idx] & (1U << bit_idx)) !=
1999                     (mvpr[byte_idx] & (1U << bit_idx))) {
2000                         have_same_class = B_FALSE;
2001                         break;
2002                 }
2003         }
2004
2005 done:
2006         *have_same_classp = have_same_class;
2007
2008         return (0);
2009
2010 fail2:
2011         EFSYS_PROBE(fail2);
2012 fail1:
2013         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2014         return (rc);
2015 }
2016
2017         __checkReturn           efx_rc_t
2018 efx_mae_outer_rule_insert(
2019         __in                    efx_nic_t *enp,
2020         __in                    const efx_mae_match_spec_t *spec,
2021         __in                    efx_tunnel_protocol_t encap_type,
2022         __out                   efx_mae_rule_id_t *or_idp)
2023 {
2024         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2025         efx_mcdi_req_t req;
2026         EFX_MCDI_DECLARE_BUF(payload,
2027             MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2,
2028             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
2029         uint32_t encap_type_mcdi;
2030         efx_mae_rule_id_t or_id;
2031         size_t offset;
2032         efx_rc_t rc;
2033
2034         EFX_STATIC_ASSERT(sizeof (or_idp->id) ==
2035             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN);
2036
2037         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2038             MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL);
2039
2040         if (encp->enc_mae_supported == B_FALSE) {
2041                 rc = ENOTSUP;
2042                 goto fail1;
2043         }
2044
2045         if (spec->emms_type != EFX_MAE_RULE_OUTER) {
2046                 rc = EINVAL;
2047                 goto fail2;
2048         }
2049
2050         switch (encap_type) {
2051         case EFX_TUNNEL_PROTOCOL_NONE:
2052                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
2053                 break;
2054         case EFX_TUNNEL_PROTOCOL_VXLAN:
2055                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
2056                 break;
2057         case EFX_TUNNEL_PROTOCOL_GENEVE:
2058                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
2059                 break;
2060         case EFX_TUNNEL_PROTOCOL_NVGRE:
2061                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
2062                 break;
2063         default:
2064                 rc = ENOTSUP;
2065                 goto fail3;
2066         }
2067
2068         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT;
2069         req.emr_in_buf = payload;
2070         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2;
2071         req.emr_out_buf = payload;
2072         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN;
2073
2074         MCDI_IN_SET_DWORD(req,
2075             MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi);
2076
2077         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio);
2078
2079         /*
2080          * Mask-value pairs have been stored in the byte order needed for the
2081          * MCDI request and are thus safe to be copied directly to the buffer.
2082          * The library cares about byte order in efx_mae_match_spec_field_set().
2083          */
2084         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >=
2085             MAE_ENC_FIELD_PAIRS_LEN);
2086         offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST;
2087         memcpy(payload + offset, spec->emms_mask_value_pairs.outer,
2088             MAE_ENC_FIELD_PAIRS_LEN);
2089
2090         efx_mcdi_execute(enp, &req);
2091
2092         if (req.emr_rc != 0) {
2093                 rc = req.emr_rc;
2094                 goto fail4;
2095         }
2096
2097         if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) {
2098                 rc = EMSGSIZE;
2099                 goto fail5;
2100         }
2101
2102         or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
2103         if (or_id.id == EFX_MAE_RSRC_ID_INVALID) {
2104                 rc = ENOENT;
2105                 goto fail6;
2106         }
2107
2108         or_idp->id = or_id.id;
2109
2110         return (0);
2111
2112 fail6:
2113         EFSYS_PROBE(fail6);
2114 fail5:
2115         EFSYS_PROBE(fail5);
2116 fail4:
2117         EFSYS_PROBE(fail4);
2118 fail3:
2119         EFSYS_PROBE(fail3);
2120 fail2:
2121         EFSYS_PROBE(fail2);
2122 fail1:
2123         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2124         return (rc);
2125 }
2126
2127         __checkReturn           efx_rc_t
2128 efx_mae_outer_rule_remove(
2129         __in                    efx_nic_t *enp,
2130         __in                    const efx_mae_rule_id_t *or_idp)
2131 {
2132         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2133         efx_mcdi_req_t req;
2134         EFX_MCDI_DECLARE_BUF(payload,
2135             MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1),
2136             MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
2137         efx_rc_t rc;
2138
2139         if (encp->enc_mae_supported == B_FALSE) {
2140                 rc = ENOTSUP;
2141                 goto fail1;
2142         }
2143
2144         req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE;
2145         req.emr_in_buf = payload;
2146         req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1);
2147         req.emr_out_buf = payload;
2148         req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1);
2149
2150         MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id);
2151
2152         efx_mcdi_execute(enp, &req);
2153
2154         if (req.emr_rc != 0) {
2155                 rc = req.emr_rc;
2156                 goto fail2;
2157         }
2158
2159         if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LENMIN) {
2160                 rc = EMSGSIZE;
2161                 goto fail3;
2162         }
2163
2164         if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) !=
2165             or_idp->id) {
2166                 /* Firmware failed to remove the outer rule. */
2167                 rc = EAGAIN;
2168                 goto fail4;
2169         }
2170
2171         return (0);
2172
2173 fail4:
2174         EFSYS_PROBE(fail4);
2175 fail3:
2176         EFSYS_PROBE(fail3);
2177 fail2:
2178         EFSYS_PROBE(fail2);
2179 fail1:
2180         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2181         return (rc);
2182 }
2183
2184         __checkReturn                   efx_rc_t
2185 efx_mae_match_spec_outer_rule_id_set(
2186         __in                            efx_mae_match_spec_t *spec,
2187         __in                            const efx_mae_rule_id_t *or_idp)
2188 {
2189         uint32_t full_mask = UINT32_MAX;
2190         efx_rc_t rc;
2191
2192         if (spec->emms_type != EFX_MAE_RULE_ACTION) {
2193                 rc = EINVAL;
2194                 goto fail1;
2195         }
2196
2197         if (or_idp == NULL) {
2198                 rc = EINVAL;
2199                 goto fail2;
2200         }
2201
2202         rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID,
2203             sizeof (or_idp->id), (const uint8_t *)&or_idp->id,
2204             sizeof (full_mask), (const uint8_t *)&full_mask);
2205         if (rc != 0)
2206                 goto fail3;
2207
2208         return (0);
2209
2210 fail3:
2211         EFSYS_PROBE(fail3);
2212 fail2:
2213         EFSYS_PROBE(fail2);
2214 fail1:
2215         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2216         return (rc);
2217 }
2218
2219          __checkReturn                  efx_rc_t
2220 efx_mae_encap_header_alloc(
2221         __in                            efx_nic_t *enp,
2222         __in                            efx_tunnel_protocol_t encap_type,
2223         __in_bcount(header_size)        uint8_t *header_data,
2224         __in                            size_t header_size,
2225         __out                           efx_mae_eh_id_t *eh_idp)
2226 {
2227         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2228         efx_mcdi_req_t req;
2229         EFX_MCDI_DECLARE_BUF(payload,
2230             MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LENMAX_MCDI2,
2231             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN);
2232         uint32_t encap_type_mcdi;
2233         efx_mae_eh_id_t eh_id;
2234         efx_rc_t rc;
2235
2236         EFX_STATIC_ASSERT(sizeof (eh_idp->id) ==
2237             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_LEN);
2238
2239         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2240             MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
2241
2242         if (encp->enc_mae_supported == B_FALSE) {
2243                 rc = ENOTSUP;
2244                 goto fail1;
2245         }
2246
2247         switch (encap_type) {
2248         case EFX_TUNNEL_PROTOCOL_NONE:
2249                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
2250                 break;
2251         case EFX_TUNNEL_PROTOCOL_VXLAN:
2252                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
2253                 break;
2254         case EFX_TUNNEL_PROTOCOL_GENEVE:
2255                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
2256                 break;
2257         case EFX_TUNNEL_PROTOCOL_NVGRE:
2258                 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
2259                 break;
2260         default:
2261                 rc = ENOTSUP;
2262                 goto fail2;
2263         }
2264
2265         if (header_size >
2266             MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2) {
2267                 rc = EINVAL;
2268                 goto fail3;
2269         }
2270
2271         req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_ALLOC;
2272         req.emr_in_buf = payload;
2273         req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(header_size);
2274         req.emr_out_buf = payload;
2275         req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN;
2276
2277         MCDI_IN_SET_DWORD(req,
2278             MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, encap_type_mcdi);
2279
2280         memcpy(payload + MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_OFST,
2281             header_data, header_size);
2282
2283         efx_mcdi_execute(enp, &req);
2284
2285         if (req.emr_rc != 0) {
2286                 rc = req.emr_rc;
2287                 goto fail4;
2288         }
2289
2290         if (req.emr_out_length_used < MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN) {
2291                 rc = EMSGSIZE;
2292                 goto fail5;
2293         }
2294
2295         eh_id.id = MCDI_OUT_DWORD(req,
2296             MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID);
2297
2298         if (eh_id.id == EFX_MAE_RSRC_ID_INVALID) {
2299                 rc = ENOENT;
2300                 goto fail6;
2301         }
2302
2303         eh_idp->id = eh_id.id;
2304
2305         return (0);
2306
2307 fail6:
2308         EFSYS_PROBE(fail6);
2309 fail5:
2310         EFSYS_PROBE(fail5);
2311 fail4:
2312         EFSYS_PROBE(fail4);
2313 fail3:
2314         EFSYS_PROBE(fail3);
2315 fail2:
2316         EFSYS_PROBE(fail2);
2317 fail1:
2318         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2319         return (rc);
2320 }
2321
2322         __checkReturn                   efx_rc_t
2323 efx_mae_encap_header_free(
2324         __in                            efx_nic_t *enp,
2325         __in                            const efx_mae_eh_id_t *eh_idp)
2326 {
2327         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2328         efx_mcdi_req_t req;
2329         EFX_MCDI_DECLARE_BUF(payload,
2330             MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1),
2331             MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1));
2332         efx_rc_t rc;
2333
2334         if (encp->enc_mae_supported == B_FALSE) {
2335                 rc = ENOTSUP;
2336                 goto fail1;
2337         }
2338
2339         req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_FREE;
2340         req.emr_in_buf = payload;
2341         req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1);
2342         req.emr_out_buf = payload;
2343         req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1);
2344
2345         MCDI_IN_SET_DWORD(req, MAE_ENCAP_HEADER_FREE_IN_EH_ID, eh_idp->id);
2346
2347         efx_mcdi_execute(enp, &req);
2348
2349         if (req.emr_rc != 0) {
2350                 rc = req.emr_rc;
2351                 goto fail2;
2352         }
2353
2354         if (MCDI_OUT_DWORD(req, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) !=
2355             eh_idp->id) {
2356                 /* Firmware failed to remove the encap. header. */
2357                 rc = EAGAIN;
2358                 goto fail3;
2359         }
2360
2361         return (0);
2362
2363 fail3:
2364         EFSYS_PROBE(fail3);
2365 fail2:
2366         EFSYS_PROBE(fail2);
2367 fail1:
2368         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2369         return (rc);
2370 }
2371
2372         __checkReturn                   efx_rc_t
2373 efx_mae_action_set_fill_in_eh_id(
2374         __in                            efx_mae_actions_t *spec,
2375         __in                            const efx_mae_eh_id_t *eh_idp)
2376 {
2377         efx_rc_t rc;
2378
2379         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) == 0) {
2380                 /*
2381                  * The caller has not intended to have action ENCAP originally,
2382                  * hence, this attempt to indicate encap. header ID is invalid.
2383                  */
2384                 rc = EINVAL;
2385                 goto fail1;
2386         }
2387
2388         if (spec->ema_rsrc.emar_eh_id.id != EFX_MAE_RSRC_ID_INVALID) {
2389                 /* The caller attempts to indicate encap. header ID twice. */
2390                 rc = EINVAL;
2391                 goto fail2;
2392         }
2393
2394         if (eh_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2395                 rc = EINVAL;
2396                 goto fail3;
2397         }
2398
2399         spec->ema_rsrc.emar_eh_id.id = eh_idp->id;
2400
2401         return (0);
2402
2403 fail3:
2404         EFSYS_PROBE(fail3);
2405 fail2:
2406         EFSYS_PROBE(fail2);
2407 fail1:
2408         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2409         return (rc);
2410 }
2411
2412         __checkReturn                   efx_rc_t
2413 efx_mae_action_set_alloc(
2414         __in                            efx_nic_t *enp,
2415         __in                            const efx_mae_actions_t *spec,
2416         __out                           efx_mae_aset_id_t *aset_idp)
2417 {
2418         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2419         efx_mcdi_req_t req;
2420         EFX_MCDI_DECLARE_BUF(payload,
2421             MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
2422             MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
2423         efx_mae_aset_id_t aset_id;
2424         efx_rc_t rc;
2425
2426         if (encp->enc_mae_supported == B_FALSE) {
2427                 rc = ENOTSUP;
2428                 goto fail1;
2429         }
2430
2431         req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
2432         req.emr_in_buf = payload;
2433         req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
2434         req.emr_out_buf = payload;
2435         req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
2436
2437         /*
2438          * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
2439          * corresponding resource types are supported by the implementation.
2440          * Use proper resource ID assignments instead.
2441          */
2442         MCDI_IN_SET_DWORD(req,
2443             MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
2444
2445         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECAP)) != 0) {
2446                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2447                     MAE_ACTION_SET_ALLOC_IN_DECAP, 1);
2448         }
2449
2450         MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2451             MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
2452
2453         if (spec->ema_n_vlan_tags_to_push > 0) {
2454                 unsigned int outer_tag_idx;
2455
2456                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2457                     MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
2458                     spec->ema_n_vlan_tags_to_push);
2459
2460                 if (spec->ema_n_vlan_tags_to_push ==
2461                     EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
2462                         MCDI_IN_SET_WORD(req,
2463                             MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
2464                             spec->ema_vlan_push_descs[0].emavp_tpid_be);
2465                         MCDI_IN_SET_WORD(req,
2466                             MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
2467                             spec->ema_vlan_push_descs[0].emavp_tci_be);
2468                 }
2469
2470                 outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
2471
2472                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
2473                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
2474                 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
2475                     spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
2476         }
2477
2478         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
2479             spec->ema_rsrc.emar_eh_id.id);
2480         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
2481             spec->ema_rsrc.emar_counter_id.id);
2482
2483         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
2484                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2485                     MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
2486         }
2487
2488         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
2489                 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2490                     MAE_ACTION_SET_ALLOC_IN_MARK, 1);
2491
2492                 MCDI_IN_SET_DWORD(req,
2493                     MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
2494         }
2495
2496         MCDI_IN_SET_DWORD(req,
2497             MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
2498
2499         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
2500             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2501         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
2502             MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2503
2504         efx_mcdi_execute(enp, &req);
2505
2506         if (req.emr_rc != 0) {
2507                 rc = req.emr_rc;
2508                 goto fail2;
2509         }
2510
2511         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
2512                 rc = EMSGSIZE;
2513                 goto fail3;
2514         }
2515
2516         aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
2517         if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
2518                 rc = ENOENT;
2519                 goto fail4;
2520         }
2521
2522         aset_idp->id = aset_id.id;
2523
2524         return (0);
2525
2526 fail4:
2527         EFSYS_PROBE(fail4);
2528 fail3:
2529         EFSYS_PROBE(fail3);
2530 fail2:
2531         EFSYS_PROBE(fail2);
2532 fail1:
2533         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2534         return (rc);
2535 }
2536
2537         __checkReturn                   unsigned int
2538 efx_mae_action_set_get_nb_count(
2539         __in                            const efx_mae_actions_t *spec)
2540 {
2541         return (spec->ema_n_count_actions);
2542 }
2543
2544         __checkReturn                   efx_rc_t
2545 efx_mae_action_set_fill_in_counter_id(
2546         __in                            efx_mae_actions_t *spec,
2547         __in                            const efx_counter_t *counter_idp)
2548 {
2549         efx_rc_t rc;
2550
2551         if ((spec->ema_actions & (1U << EFX_MAE_ACTION_COUNT)) == 0) {
2552                 /*
2553                  * Invalid to add counter ID if spec does not have COUNT action.
2554                  */
2555                 rc = EINVAL;
2556                 goto fail1;
2557         }
2558
2559         if (spec->ema_n_count_actions != 1) {
2560                 /*
2561                  * Having multiple COUNT actions in the spec requires a counter
2562                  * list to be used. This API must only be used for a single
2563                  * counter per spec. Turn down the request as inappropriate.
2564                  */
2565                 rc = EINVAL;
2566                 goto fail2;
2567         }
2568
2569         if (spec->ema_rsrc.emar_counter_id.id != EFX_MAE_RSRC_ID_INVALID) {
2570                 /* The caller attempts to indicate counter ID twice. */
2571                 rc = EALREADY;
2572                 goto fail3;
2573         }
2574
2575         if (counter_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2576                 rc = EINVAL;
2577                 goto fail4;
2578         }
2579
2580         spec->ema_rsrc.emar_counter_id.id = counter_idp->id;
2581
2582         return (0);
2583
2584 fail4:
2585         EFSYS_PROBE(fail4);
2586 fail3:
2587         EFSYS_PROBE(fail3);
2588 fail2:
2589         EFSYS_PROBE(fail2);
2590 fail1:
2591         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2592         return (rc);
2593 }
2594
2595         __checkReturn                   efx_rc_t
2596 efx_mae_counters_alloc(
2597         __in                            efx_nic_t *enp,
2598         __in                            uint32_t n_counters,
2599         __out                           uint32_t *n_allocatedp,
2600         __out_ecount(n_counters)        efx_counter_t *countersp,
2601         __out_opt                       uint32_t *gen_countp)
2602 {
2603         EFX_MCDI_DECLARE_BUF(payload,
2604             MC_CMD_MAE_COUNTER_ALLOC_IN_LEN,
2605             MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMAX_MCDI2);
2606         efx_mae_t *maep = enp->en_maep;
2607         uint32_t n_allocated;
2608         efx_mcdi_req_t req;
2609         unsigned int i;
2610         efx_rc_t rc;
2611
2612         if (n_counters > maep->em_max_ncounters ||
2613             n_counters < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM ||
2614             n_counters > MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MAXNUM_MCDI2) {
2615                 rc = EINVAL;
2616                 goto fail1;
2617         }
2618
2619         req.emr_cmd = MC_CMD_MAE_COUNTER_ALLOC;
2620         req.emr_in_buf = payload;
2621         req.emr_in_length = MC_CMD_MAE_COUNTER_ALLOC_IN_LEN;
2622         req.emr_out_buf = payload;
2623         req.emr_out_length = MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(n_counters);
2624
2625         MCDI_IN_SET_DWORD(req, MAE_COUNTER_ALLOC_IN_REQUESTED_COUNT,
2626             n_counters);
2627
2628         efx_mcdi_execute(enp, &req);
2629
2630         if (req.emr_rc != 0) {
2631                 rc = req.emr_rc;
2632                 goto fail2;
2633         }
2634
2635         if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMIN) {
2636                 rc = EMSGSIZE;
2637                 goto fail3;
2638         }
2639
2640         n_allocated = MCDI_OUT_DWORD(req,
2641             MAE_COUNTER_ALLOC_OUT_COUNTER_ID_COUNT);
2642         if (n_allocated < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM) {
2643                 rc = EFAULT;
2644                 goto fail4;
2645         }
2646
2647         for (i = 0; i < n_allocated; i++) {
2648                 countersp[i].id = MCDI_OUT_INDEXED_DWORD(req,
2649                     MAE_COUNTER_ALLOC_OUT_COUNTER_ID, i);
2650         }
2651
2652         if (gen_countp != NULL) {
2653                 *gen_countp = MCDI_OUT_DWORD(req,
2654                                     MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT);
2655         }
2656
2657         *n_allocatedp = n_allocated;
2658
2659         return (0);
2660
2661 fail4:
2662         EFSYS_PROBE(fail4);
2663 fail3:
2664         EFSYS_PROBE(fail3);
2665 fail2:
2666         EFSYS_PROBE(fail2);
2667 fail1:
2668         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2669
2670         return (rc);
2671 }
2672
2673         __checkReturn                   efx_rc_t
2674 efx_mae_counters_free(
2675         __in                            efx_nic_t *enp,
2676         __in                            uint32_t n_counters,
2677         __out                           uint32_t *n_freedp,
2678         __in_ecount(n_counters)         const efx_counter_t *countersp,
2679         __out_opt                       uint32_t *gen_countp)
2680 {
2681         EFX_MCDI_DECLARE_BUF(payload,
2682             MC_CMD_MAE_COUNTER_FREE_IN_LENMAX_MCDI2,
2683             MC_CMD_MAE_COUNTER_FREE_OUT_LENMAX_MCDI2);
2684         efx_mae_t *maep = enp->en_maep;
2685         efx_mcdi_req_t req;
2686         uint32_t n_freed;
2687         unsigned int i;
2688         efx_rc_t rc;
2689
2690         if (n_counters > maep->em_max_ncounters ||
2691             n_counters < MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MINNUM ||
2692             n_counters >
2693             MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MAXNUM_MCDI2) {
2694                 rc = EINVAL;
2695                 goto fail1;
2696         }
2697
2698         req.emr_cmd = MC_CMD_MAE_COUNTER_FREE;
2699         req.emr_in_buf = payload;
2700         req.emr_in_length = MC_CMD_MAE_COUNTER_FREE_IN_LEN(n_counters);
2701         req.emr_out_buf = payload;
2702         req.emr_out_length = MC_CMD_MAE_COUNTER_FREE_OUT_LEN(n_counters);
2703
2704         for (i = 0; i < n_counters; i++) {
2705                 MCDI_IN_SET_INDEXED_DWORD(req,
2706                     MAE_COUNTER_FREE_IN_FREE_COUNTER_ID, i, countersp[i].id);
2707         }
2708         MCDI_IN_SET_DWORD(req, MAE_COUNTER_FREE_IN_COUNTER_ID_COUNT,
2709                           n_counters);
2710
2711         efx_mcdi_execute(enp, &req);
2712
2713         if (req.emr_rc != 0) {
2714                 rc = req.emr_rc;
2715                 goto fail2;
2716         }
2717
2718         if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_FREE_OUT_LENMIN) {
2719                 rc = EMSGSIZE;
2720                 goto fail3;
2721         }
2722
2723         n_freed = MCDI_OUT_DWORD(req, MAE_COUNTER_FREE_OUT_COUNTER_ID_COUNT);
2724
2725         if (n_freed < MC_CMD_MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID_MINNUM) {
2726                 rc = EFAULT;
2727                 goto fail4;
2728         }
2729
2730         if (gen_countp != NULL) {
2731                 *gen_countp = MCDI_OUT_DWORD(req,
2732                                     MAE_COUNTER_FREE_OUT_GENERATION_COUNT);
2733         }
2734
2735         *n_freedp = n_freed;
2736
2737         return (0);
2738
2739 fail4:
2740         EFSYS_PROBE(fail4);
2741 fail3:
2742         EFSYS_PROBE(fail3);
2743 fail2:
2744         EFSYS_PROBE(fail2);
2745 fail1:
2746         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2747
2748         return (rc);
2749 }
2750
2751         __checkReturn                   efx_rc_t
2752 efx_mae_counters_stream_start(
2753         __in                            efx_nic_t *enp,
2754         __in                            uint16_t rxq_id,
2755         __in                            uint16_t packet_size,
2756         __in                            uint32_t flags_in,
2757         __out                           uint32_t *flags_out)
2758 {
2759         efx_mcdi_req_t req;
2760         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN,
2761                              MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN);
2762         efx_rc_t rc;
2763
2764         EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_IN_ZERO_SQUASH_DISABLE ==
2765             1U << MC_CMD_MAE_COUNTERS_STREAM_START_IN_ZERO_SQUASH_DISABLE_LBN);
2766
2767         EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_OUT_USES_CREDITS ==
2768             1U << MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_LBN);
2769
2770         req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_START;
2771         req.emr_in_buf = payload;
2772         req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN;
2773         req.emr_out_buf = payload;
2774         req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN;
2775
2776         MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_QID, rxq_id);
2777         MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_PACKET_SIZE,
2778                          packet_size);
2779         MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_START_IN_FLAGS, flags_in);
2780
2781         efx_mcdi_execute(enp, &req);
2782
2783         if (req.emr_rc != 0) {
2784                 rc = req.emr_rc;
2785                 goto fail1;
2786         }
2787
2788         if (req.emr_out_length_used <
2789             MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN) {
2790                 rc = EMSGSIZE;
2791                 goto fail2;
2792         }
2793
2794         *flags_out = MCDI_OUT_DWORD(req, MAE_COUNTERS_STREAM_START_OUT_FLAGS);
2795
2796         return (0);
2797
2798 fail2:
2799         EFSYS_PROBE(fail2);
2800 fail1:
2801         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2802
2803         return (rc);
2804 }
2805
2806         __checkReturn                   efx_rc_t
2807 efx_mae_counters_stream_stop(
2808         __in                            efx_nic_t *enp,
2809         __in                            uint16_t rxq_id,
2810         __out_opt                       uint32_t *gen_countp)
2811 {
2812         efx_mcdi_req_t req;
2813         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN,
2814                              MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN);
2815         efx_rc_t rc;
2816
2817         req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_STOP;
2818         req.emr_in_buf = payload;
2819         req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN;
2820         req.emr_out_buf = payload;
2821         req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN;
2822
2823         MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_STOP_IN_QID, rxq_id);
2824
2825         efx_mcdi_execute(enp, &req);
2826
2827         if (req.emr_rc != 0) {
2828                 rc = req.emr_rc;
2829                 goto fail1;
2830         }
2831
2832         if (req.emr_out_length_used <
2833             MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN) {
2834                 rc = EMSGSIZE;
2835                 goto fail2;
2836         }
2837
2838         if (gen_countp != NULL) {
2839                 *gen_countp = MCDI_OUT_DWORD(req,
2840                             MAE_COUNTERS_STREAM_STOP_OUT_GENERATION_COUNT);
2841         }
2842
2843         return (0);
2844
2845 fail2:
2846         EFSYS_PROBE(fail2);
2847 fail1:
2848         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2849
2850         return (rc);
2851 }
2852
2853         __checkReturn                   efx_rc_t
2854 efx_mae_counters_stream_give_credits(
2855         __in                            efx_nic_t *enp,
2856         __in                            uint32_t n_credits)
2857 {
2858         efx_mcdi_req_t req;
2859         EFX_MCDI_DECLARE_BUF(payload,
2860                              MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN,
2861                              MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN);
2862         efx_rc_t rc;
2863
2864         req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS;
2865         req.emr_in_buf = payload;
2866         req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN;
2867         req.emr_out_buf = payload;
2868         req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN;
2869
2870         MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_NUM_CREDITS,
2871                          n_credits);
2872
2873         efx_mcdi_execute(enp, &req);
2874
2875         if (req.emr_rc != 0) {
2876                 rc = req.emr_rc;
2877                 goto fail1;
2878         }
2879
2880         return (0);
2881
2882 fail1:
2883         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2884
2885         return (rc);
2886 }
2887
2888         __checkReturn                   efx_rc_t
2889 efx_mae_action_set_free(
2890         __in                            efx_nic_t *enp,
2891         __in                            const efx_mae_aset_id_t *aset_idp)
2892 {
2893         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2894         efx_mcdi_req_t req;
2895         EFX_MCDI_DECLARE_BUF(payload,
2896             MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
2897             MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
2898         efx_rc_t rc;
2899
2900         if (encp->enc_mae_supported == B_FALSE) {
2901                 rc = ENOTSUP;
2902                 goto fail1;
2903         }
2904
2905         req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
2906         req.emr_in_buf = payload;
2907         req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
2908         req.emr_out_buf = payload;
2909         req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
2910
2911         MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
2912
2913         efx_mcdi_execute(enp, &req);
2914
2915         if (req.emr_rc != 0) {
2916                 rc = req.emr_rc;
2917                 goto fail2;
2918         }
2919
2920         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_FREE_OUT_LENMIN) {
2921                 rc = EMSGSIZE;
2922                 goto fail3;
2923         }
2924
2925         if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
2926             aset_idp->id) {
2927                 /* Firmware failed to free the action set. */
2928                 rc = EAGAIN;
2929                 goto fail4;
2930         }
2931
2932         return (0);
2933
2934 fail4:
2935         EFSYS_PROBE(fail4);
2936 fail3:
2937         EFSYS_PROBE(fail3);
2938 fail2:
2939         EFSYS_PROBE(fail2);
2940 fail1:
2941         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2942         return (rc);
2943 }
2944
2945         __checkReturn                   efx_rc_t
2946 efx_mae_action_rule_insert(
2947         __in                            efx_nic_t *enp,
2948         __in                            const efx_mae_match_spec_t *spec,
2949         __in                            const efx_mae_aset_list_id_t *asl_idp,
2950         __in                            const efx_mae_aset_id_t *as_idp,
2951         __out                           efx_mae_rule_id_t *ar_idp)
2952 {
2953         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2954         efx_mcdi_req_t req;
2955         EFX_MCDI_DECLARE_BUF(payload,
2956             MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2,
2957             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
2958         efx_oword_t *rule_response;
2959         efx_mae_rule_id_t ar_id;
2960         size_t offset;
2961         efx_rc_t rc;
2962
2963         EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
2964             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
2965
2966         EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2967             MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
2968
2969         if (encp->enc_mae_supported == B_FALSE) {
2970                 rc = ENOTSUP;
2971                 goto fail1;
2972         }
2973
2974         if (spec->emms_type != EFX_MAE_RULE_ACTION ||
2975             (asl_idp != NULL && as_idp != NULL) ||
2976             (asl_idp == NULL && as_idp == NULL)) {
2977                 rc = EINVAL;
2978                 goto fail2;
2979         }
2980
2981         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
2982         req.emr_in_buf = payload;
2983         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
2984         req.emr_out_buf = payload;
2985         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
2986
2987         EFX_STATIC_ASSERT(sizeof (*rule_response) <=
2988             MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
2989         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
2990         rule_response = (efx_oword_t *)(payload + offset);
2991         EFX_POPULATE_OWORD_3(*rule_response,
2992             MAE_ACTION_RULE_RESPONSE_ASL_ID,
2993             (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
2994             MAE_ACTION_RULE_RESPONSE_AS_ID,
2995             (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
2996             MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
2997
2998         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
2999
3000         /*
3001          * Mask-value pairs have been stored in the byte order needed for the
3002          * MCDI request and are thus safe to be copied directly to the buffer.
3003          */
3004         EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
3005             MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
3006         offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
3007         memcpy(payload + offset, spec->emms_mask_value_pairs.action,
3008             MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
3009
3010         efx_mcdi_execute(enp, &req);
3011
3012         if (req.emr_rc != 0) {
3013                 rc = req.emr_rc;
3014                 goto fail3;
3015         }
3016
3017         if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
3018                 rc = EMSGSIZE;
3019                 goto fail4;
3020         }
3021
3022         ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
3023         if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
3024                 rc = ENOENT;
3025                 goto fail5;
3026         }
3027
3028         ar_idp->id = ar_id.id;
3029
3030         return (0);
3031
3032 fail5:
3033         EFSYS_PROBE(fail5);
3034 fail4:
3035         EFSYS_PROBE(fail4);
3036 fail3:
3037         EFSYS_PROBE(fail3);
3038 fail2:
3039         EFSYS_PROBE(fail2);
3040 fail1:
3041         EFSYS_PROBE1(fail1, efx_rc_t, rc);
3042         return (rc);
3043 }
3044
3045         __checkReturn                   efx_rc_t
3046 efx_mae_action_rule_remove(
3047         __in                            efx_nic_t *enp,
3048         __in                            const efx_mae_rule_id_t *ar_idp)
3049 {
3050         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3051         efx_mcdi_req_t req;
3052         EFX_MCDI_DECLARE_BUF(payload,
3053             MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
3054             MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
3055         efx_rc_t rc;
3056
3057         if (encp->enc_mae_supported == B_FALSE) {
3058                 rc = ENOTSUP;
3059                 goto fail1;
3060         }
3061
3062         req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
3063         req.emr_in_buf = payload;
3064         req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
3065         req.emr_out_buf = payload;
3066         req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
3067
3068         MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
3069
3070         efx_mcdi_execute(enp, &req);
3071
3072         if (req.emr_rc != 0) {
3073                 rc = req.emr_rc;
3074                 goto fail2;
3075         }
3076
3077         if (req.emr_out_length_used <
3078             MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LENMIN) {
3079                 rc = EMSGSIZE;
3080                 goto fail3;
3081         }
3082
3083         if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
3084             ar_idp->id) {
3085                 /* Firmware failed to delete the action rule. */
3086                 rc = EAGAIN;
3087                 goto fail4;
3088         }
3089
3090         return (0);
3091
3092 fail4:
3093         EFSYS_PROBE(fail4);
3094 fail3:
3095         EFSYS_PROBE(fail3);
3096 fail2:
3097         EFSYS_PROBE(fail2);
3098 fail1:
3099         EFSYS_PROBE1(fail1, efx_rc_t, rc);
3100         return (rc);
3101 }
3102
3103 #endif /* EFSYS_OPT_MAE */