common/sfc_efx/base: add match specs class comparison API
[dpdk.git] / drivers / common / sfc_efx / base / efx_mae.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2019 Xilinx, Inc. All rights reserved.
4  * All rights reserved.
5  */
6
7 #include "efx.h"
8 #include "efx_impl.h"
9
10
11 #if EFSYS_OPT_MAE
12
13 static  __checkReturn                   efx_rc_t
14 efx_mae_get_capabilities(
15         __in                            efx_nic_t *enp)
16 {
17         efx_mcdi_req_t req;
18         EFX_MCDI_DECLARE_BUF(payload,
19             MC_CMD_MAE_GET_CAPS_IN_LEN,
20             MC_CMD_MAE_GET_CAPS_OUT_LEN);
21         struct efx_mae_s *maep = enp->en_maep;
22         efx_rc_t rc;
23
24         req.emr_cmd = MC_CMD_MAE_GET_CAPS;
25         req.emr_in_buf = payload;
26         req.emr_in_length = MC_CMD_MAE_GET_CAPS_IN_LEN;
27         req.emr_out_buf = payload;
28         req.emr_out_length = MC_CMD_MAE_GET_CAPS_OUT_LEN;
29
30         efx_mcdi_execute(enp, &req);
31
32         if (req.emr_rc != 0) {
33                 rc = req.emr_rc;
34                 goto fail1;
35         }
36
37         if (req.emr_out_length_used < MC_CMD_MAE_GET_CAPS_OUT_LEN) {
38                 rc = EMSGSIZE;
39                 goto fail2;
40         }
41
42         maep->em_max_n_action_prios =
43             MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ACTION_PRIOS);
44
45         maep->em_max_nfields =
46             MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT);
47
48         return (0);
49
50 fail2:
51         EFSYS_PROBE(fail2);
52 fail1:
53         EFSYS_PROBE1(fail1, efx_rc_t, rc);
54         return (rc);
55 }
56
57 static  __checkReturn                   efx_rc_t
58 efx_mae_get_action_rule_caps(
59         __in                            efx_nic_t *enp,
60         __in                            unsigned int field_ncaps,
61         __out_ecount(field_ncaps)       efx_mae_field_cap_t *field_caps)
62 {
63         efx_mcdi_req_t req;
64         EFX_MCDI_DECLARE_BUF(payload,
65             MC_CMD_MAE_GET_AR_CAPS_IN_LEN,
66             MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2);
67         unsigned int mcdi_field_ncaps;
68         unsigned int i;
69         efx_rc_t rc;
70
71         if (MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps) >
72             MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2) {
73                 rc = EINVAL;
74                 goto fail1;
75         }
76
77         req.emr_cmd = MC_CMD_MAE_GET_AR_CAPS;
78         req.emr_in_buf = payload;
79         req.emr_in_length = MC_CMD_MAE_GET_AR_CAPS_IN_LEN;
80         req.emr_out_buf = payload;
81         req.emr_out_length = MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps);
82
83         efx_mcdi_execute(enp, &req);
84
85         if (req.emr_rc != 0) {
86                 rc = req.emr_rc;
87                 goto fail2;
88         }
89
90         mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_OR_CAPS_OUT_COUNT);
91
92         if (req.emr_out_length_used <
93             MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(mcdi_field_ncaps)) {
94                 rc = EMSGSIZE;
95                 goto fail3;
96         }
97
98         if (mcdi_field_ncaps > field_ncaps) {
99                 rc = EMSGSIZE;
100                 goto fail4;
101         }
102
103         for (i = 0; i < mcdi_field_ncaps; ++i) {
104                 uint32_t match_flag;
105                 uint32_t mask_flag;
106
107                 field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req,
108                     MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
109                     MAE_FIELD_FLAGS_SUPPORT_STATUS);
110
111                 match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
112                     MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
113                     MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS);
114
115                 field_caps[i].emfc_match_affects_class =
116                     (match_flag != 0) ? B_TRUE : B_FALSE;
117
118                 mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
119                     MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
120                     MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS);
121
122                 field_caps[i].emfc_mask_affects_class =
123                     (mask_flag != 0) ? B_TRUE : B_FALSE;
124         }
125
126         return (0);
127
128 fail4:
129         EFSYS_PROBE(fail4);
130 fail3:
131         EFSYS_PROBE(fail3);
132 fail2:
133         EFSYS_PROBE(fail2);
134 fail1:
135         EFSYS_PROBE1(fail1, efx_rc_t, rc);
136         return (rc);
137 }
138
139         __checkReturn                   efx_rc_t
140 efx_mae_init(
141         __in                            efx_nic_t *enp)
142 {
143         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
144         efx_mae_field_cap_t *ar_fcaps;
145         size_t ar_fcaps_size;
146         efx_mae_t *maep;
147         efx_rc_t rc;
148
149         if (encp->enc_mae_supported == B_FALSE) {
150                 rc = ENOTSUP;
151                 goto fail1;
152         }
153
154         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*maep), maep);
155         if (maep == NULL) {
156                 rc = ENOMEM;
157                 goto fail2;
158         }
159
160         enp->en_maep = maep;
161
162         rc = efx_mae_get_capabilities(enp);
163         if (rc != 0)
164                 goto fail3;
165
166         ar_fcaps_size = maep->em_max_nfields * sizeof (*ar_fcaps);
167         EFSYS_KMEM_ALLOC(enp->en_esip, ar_fcaps_size, ar_fcaps);
168         if (ar_fcaps == NULL) {
169                 rc = ENOMEM;
170                 goto fail4;
171         }
172
173         maep->em_action_rule_field_caps_size = ar_fcaps_size;
174         maep->em_action_rule_field_caps = ar_fcaps;
175
176         rc = efx_mae_get_action_rule_caps(enp, maep->em_max_nfields, ar_fcaps);
177         if (rc != 0)
178                 goto fail5;
179
180         return (0);
181
182 fail5:
183         EFSYS_PROBE(fail5);
184         EFSYS_KMEM_FREE(enp->en_esip, ar_fcaps_size, ar_fcaps);
185 fail4:
186         EFSYS_PROBE(fail4);
187 fail3:
188         EFSYS_PROBE(fail3);
189         EFSYS_KMEM_FREE(enp->en_esip, sizeof (struct efx_mae_s), enp->en_maep);
190         enp->en_maep = NULL;
191 fail2:
192         EFSYS_PROBE(fail2);
193 fail1:
194         EFSYS_PROBE1(fail1, efx_rc_t, rc);
195         return (rc);
196 }
197
198                                         void
199 efx_mae_fini(
200         __in                            efx_nic_t *enp)
201 {
202         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
203         efx_mae_t *maep = enp->en_maep;
204
205         if (encp->enc_mae_supported == B_FALSE)
206                 return;
207
208         EFSYS_KMEM_FREE(enp->en_esip, maep->em_action_rule_field_caps_size,
209             maep->em_action_rule_field_caps);
210         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*maep), maep);
211         enp->en_maep = NULL;
212 }
213
214         __checkReturn                   efx_rc_t
215 efx_mae_get_limits(
216         __in                            efx_nic_t *enp,
217         __out                           efx_mae_limits_t *emlp)
218 {
219         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
220         struct efx_mae_s *maep = enp->en_maep;
221         efx_rc_t rc;
222
223         if (encp->enc_mae_supported == B_FALSE) {
224                 rc = ENOTSUP;
225                 goto fail1;
226         }
227
228         emlp->eml_max_n_action_prios = maep->em_max_n_action_prios;
229
230         return (0);
231
232 fail1:
233         EFSYS_PROBE1(fail1, efx_rc_t, rc);
234         return (rc);
235 }
236
237         __checkReturn                   efx_rc_t
238 efx_mae_match_spec_init(
239         __in                            efx_nic_t *enp,
240         __in                            efx_mae_rule_type_t type,
241         __in                            uint32_t prio,
242         __out                           efx_mae_match_spec_t **specp)
243 {
244         efx_mae_match_spec_t *spec;
245         efx_rc_t rc;
246
247         switch (type) {
248         case EFX_MAE_RULE_ACTION:
249                 break;
250         default:
251                 rc = ENOTSUP;
252                 goto fail1;
253         }
254
255         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
256         if (spec == NULL) {
257                 rc = ENOMEM;
258                 goto fail2;
259         }
260
261         spec->emms_type = type;
262         spec->emms_prio = prio;
263
264         *specp = spec;
265
266         return (0);
267
268 fail2:
269         EFSYS_PROBE(fail2);
270 fail1:
271         EFSYS_PROBE1(fail1, efx_rc_t, rc);
272         return (rc);
273 }
274
275                                         void
276 efx_mae_match_spec_fini(
277         __in                            efx_nic_t *enp,
278         __in                            efx_mae_match_spec_t *spec)
279 {
280         EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
281 }
282
283 /* Named identifiers which are valid indices to efx_mae_field_cap_t */
284 typedef enum efx_mae_field_cap_id_e {
285         EFX_MAE_FIELD_CAP_NIDS
286 } efx_mae_field_cap_id_t;
287
288 typedef enum efx_mae_field_endianness_e {
289         EFX_MAE_FIELD_LE = 0,
290         EFX_MAE_FIELD_BE,
291
292         EFX_MAE_FIELD_ENDIANNESS_NTYPES
293 } efx_mae_field_endianness_t;
294
295 /*
296  * The following structure is a means to describe an MAE field.
297  * The information in it is meant to be used internally by
298  * APIs for addressing a given field in a mask-value pairs
299  * structure and for validation purposes.
300  */
301 typedef struct efx_mae_mv_desc_s {
302         efx_mae_field_cap_id_t          emmd_field_cap_id;
303
304         size_t                          emmd_value_size;
305         size_t                          emmd_value_offset;
306         size_t                          emmd_mask_size;
307         size_t                          emmd_mask_offset;
308
309         efx_mae_field_endianness_t      emmd_endianness;
310 } efx_mae_mv_desc_t;
311
312 /* Indices to this array are provided by efx_mae_field_id_t */
313 static const efx_mae_mv_desc_t __efx_mae_action_rule_mv_desc_set[] = {
314 };
315
316 #define EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit)              \
317             ((_mask)[(_bit) / (_mask_page_nbits)] &                     \
318                     (1ULL << ((_bit) & ((_mask_page_nbits) - 1))))
319
320 static inline                           boolean_t
321 efx_mask_is_prefix(
322         __in                            size_t mask_nbytes,
323         __in_bcount(mask_nbytes)        const uint8_t *maskp)
324 {
325         boolean_t prev_bit_is_set = B_TRUE;
326         unsigned int i;
327
328         for (i = 0; i < 8 * mask_nbytes; ++i) {
329                 boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i);
330
331                 if (!prev_bit_is_set && bit_is_set)
332                         return B_FALSE;
333
334                 prev_bit_is_set = bit_is_set;
335         }
336
337         return B_TRUE;
338 }
339
340 static inline                           boolean_t
341 efx_mask_is_all_ones(
342         __in                            size_t mask_nbytes,
343         __in_bcount(mask_nbytes)        const uint8_t *maskp)
344 {
345         unsigned int i;
346         uint8_t t = ~0;
347
348         for (i = 0; i < mask_nbytes; ++i)
349                 t &= maskp[i];
350
351         return (t == (uint8_t)(~0));
352 }
353
354 static inline                           boolean_t
355 efx_mask_is_all_zeros(
356         __in                            size_t mask_nbytes,
357         __in_bcount(mask_nbytes)        const uint8_t *maskp)
358 {
359         unsigned int i;
360         uint8_t t = 0;
361
362         for (i = 0; i < mask_nbytes; ++i)
363                 t |= maskp[i];
364
365         return (t == 0);
366 }
367
368         __checkReturn                   boolean_t
369 efx_mae_match_spec_is_valid(
370         __in                            efx_nic_t *enp,
371         __in                            const efx_mae_match_spec_t *spec)
372 {
373         efx_mae_t *maep = enp->en_maep;
374         unsigned int field_ncaps = maep->em_max_nfields;
375         const efx_mae_field_cap_t *field_caps;
376         const efx_mae_mv_desc_t *desc_setp;
377         unsigned int desc_set_nentries;
378         boolean_t is_valid = B_TRUE;
379         efx_mae_field_id_t field_id;
380         const uint8_t *mvp;
381
382         switch (spec->emms_type) {
383         case EFX_MAE_RULE_ACTION:
384                 field_caps = maep->em_action_rule_field_caps;
385                 desc_setp = __efx_mae_action_rule_mv_desc_set;
386                 desc_set_nentries =
387                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
388                 mvp = spec->emms_mask_value_pairs.action;
389                 break;
390         default:
391                 return (B_FALSE);
392         }
393
394         if (field_caps == NULL)
395                 return (B_FALSE);
396
397         for (field_id = 0; field_id < desc_set_nentries; ++field_id) {
398                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
399                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
400                 const uint8_t *m_buf = mvp + descp->emmd_mask_offset;
401                 size_t m_size = descp->emmd_mask_size;
402
403                 if (m_size == 0)
404                         continue; /* Skip array gap */
405
406                 if (field_cap_id >= field_ncaps)
407                         break;
408
409                 switch (field_caps[field_cap_id].emfc_support) {
410                 case MAE_FIELD_SUPPORTED_MATCH_MASK:
411                         is_valid = B_TRUE;
412                         break;
413                 case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
414                         is_valid = efx_mask_is_prefix(m_size, m_buf);
415                         break;
416                 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
417                         is_valid = (efx_mask_is_all_ones(m_size, m_buf) ||
418                             efx_mask_is_all_zeros(m_size, m_buf));
419                         break;
420                 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
421                         is_valid = efx_mask_is_all_ones(m_size, m_buf);
422                         break;
423                 case MAE_FIELD_SUPPORTED_MATCH_NEVER:
424                 case MAE_FIELD_UNSUPPORTED:
425                 default:
426                         is_valid = efx_mask_is_all_zeros(m_size, m_buf);
427                         break;
428                 }
429
430                 if (is_valid == B_FALSE)
431                         break;
432         }
433
434         return (is_valid);
435 }
436
437         __checkReturn                   efx_rc_t
438 efx_mae_match_specs_class_cmp(
439         __in                            efx_nic_t *enp,
440         __in                            const efx_mae_match_spec_t *left,
441         __in                            const efx_mae_match_spec_t *right,
442         __out                           boolean_t *have_same_classp)
443 {
444         efx_mae_t *maep = enp->en_maep;
445         unsigned int field_ncaps = maep->em_max_nfields;
446         const efx_mae_field_cap_t *field_caps;
447         const efx_mae_mv_desc_t *desc_setp;
448         unsigned int desc_set_nentries;
449         boolean_t have_same_class = B_TRUE;
450         efx_mae_field_id_t field_id;
451         const uint8_t *mvpl;
452         const uint8_t *mvpr;
453         efx_rc_t rc;
454
455         switch (left->emms_type) {
456         case EFX_MAE_RULE_ACTION:
457                 field_caps = maep->em_action_rule_field_caps;
458                 desc_setp = __efx_mae_action_rule_mv_desc_set;
459                 desc_set_nentries =
460                     EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
461                 mvpl = left->emms_mask_value_pairs.action;
462                 mvpr = right->emms_mask_value_pairs.action;
463                 break;
464         default:
465                 rc = ENOTSUP;
466                 goto fail1;
467         }
468
469         if (field_caps == NULL) {
470                 rc = EAGAIN;
471                 goto fail2;
472         }
473
474         if (left->emms_type != right->emms_type ||
475             left->emms_prio != right->emms_prio) {
476                 /*
477                  * Rules of different types can never map to the same class.
478                  *
479                  * The FW can support some set of match criteria for one
480                  * priority and not support the very same set for
481                  * another priority. Thus, two rules which have
482                  * different priorities can never map to
483                  * the same class.
484                  */
485                 *have_same_classp = B_FALSE;
486                 return (0);
487         }
488
489         for (field_id = 0; field_id < desc_set_nentries; ++field_id) {
490                 const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
491                 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
492
493                 if (descp->emmd_mask_size == 0)
494                         continue; /* Skip array gap */
495
496                 if (field_cap_id >= field_ncaps)
497                         break;
498
499                 if (field_caps[field_cap_id].emfc_mask_affects_class) {
500                         const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
501                         const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
502                         size_t mask_size = descp->emmd_mask_size;
503
504                         if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
505                                 have_same_class = B_FALSE;
506                                 break;
507                         }
508                 }
509
510                 if (field_caps[field_cap_id].emfc_match_affects_class) {
511                         const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
512                         const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
513                         size_t value_size = descp->emmd_value_size;
514
515                         if (memcmp(lvalp, rvalp, value_size) != 0) {
516                                 have_same_class = B_FALSE;
517                                 break;
518                         }
519                 }
520         }
521
522         *have_same_classp = have_same_class;
523
524         return (0);
525
526 fail2:
527         EFSYS_PROBE(fail2);
528 fail1:
529         EFSYS_PROBE1(fail1, efx_rc_t, rc);
530         return (rc);
531 }
532
533 #endif /* EFSYS_OPT_MAE */