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