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