31664871ba07617aafc43ba290b4eeae92a294bb
[dpdk.git] / drivers / net / bnxt / tf_ulp / ulp_mapper.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2014-2020 Broadcom
3  * All rights reserved.
4  */
5
6 #include <rte_log.h>
7 #include "bnxt.h"
8 #include "ulp_template_db.h"
9 #include "ulp_template_struct.h"
10 #include "bnxt_tf_common.h"
11 #include "ulp_utils.h"
12 #include "bnxt_ulp.h"
13 #include "tfp.h"
14 #include "tf_ext_flow_handle.h"
15 #include "ulp_mark_mgr.h"
16 #include "ulp_flow_db.h"
17 #include "ulp_mapper.h"
18
19 int32_t
20 ulp_mapper_action_tbls_process(struct bnxt_ulp_mapper_parms *parms);
21
22 int32_t
23 ulp_mapper_class_tbls_process(struct bnxt_ulp_mapper_parms *parms);
24
25 /*
26  * Get the size of the action property for a given index.
27  *
28  * idx [in] The index for the action property
29  *
30  * returns the size of the action property.
31  */
32 static uint32_t
33 ulp_mapper_act_prop_size_get(uint32_t idx)
34 {
35         if (idx >= BNXT_ULP_ACT_PROP_IDX_LAST)
36                 return 0;
37         return ulp_act_prop_map_table[idx];
38 }
39
40 /*
41  * Get the list of result fields that implement the flow action
42  *
43  * ctxt [in] The ulp context
44  *
45  * tbl [in] A single table instance to get the key fields from
46  *
47  * num_flds [out] The number of key fields in the returned array
48  *
49  * returns array of Key fields, or NULL on error
50  */
51 static struct bnxt_ulp_mapper_class_key_field_info *
52 ulp_mapper_key_fields_get(struct bnxt_ulp_mapper_class_tbl_info *tbl,
53                           uint32_t *num_flds)
54 {
55         uint32_t idx;
56
57         if (!tbl || !num_flds)
58                 return NULL;
59
60         idx             = tbl->key_start_idx;
61         *num_flds       = tbl->key_num_fields;
62
63         /* NOTE: Need template to provide range checking define */
64         return &ulp_class_key_field_list[idx];
65 }
66
67 /*
68  * Get the list of data fields that implement the flow.
69  *
70  * ctxt [in] The ulp context
71  *
72  * tbl [in] A single table instance to get the data fields from
73  *
74  * num_flds [out] The number of data fields in the returned array.
75  *
76  * Returns array of data fields, or NULL on error.
77  */
78 static struct bnxt_ulp_mapper_result_field_info *
79 ulp_mapper_result_fields_get(struct bnxt_ulp_mapper_class_tbl_info *tbl,
80                              uint32_t *num_flds)
81 {
82         uint32_t idx;
83
84         if (!tbl || !num_flds)
85                 return NULL;
86
87         idx             = tbl->result_start_idx;
88         *num_flds       = tbl->result_num_fields;
89
90         /* NOTE: Need template to provide range checking define */
91         return &ulp_class_result_field_list[idx];
92 }
93
94 /*
95  * Get the list of result fields that implement the flow action.
96  *
97  * tbl [in] A single table instance to get the results fields
98  * from num_flds [out] The number of data fields in the returned
99  * array.
100  *
101  * Returns array of data fields, or NULL on error.
102  */
103 static struct bnxt_ulp_mapper_result_field_info *
104 ulp_mapper_act_result_fields_get(struct bnxt_ulp_mapper_act_tbl_info *tbl,
105                                  uint32_t *num_rslt_flds,
106                                  uint32_t *num_encap_flds)
107 {
108         uint32_t idx;
109
110         if (!tbl || !num_rslt_flds || !num_encap_flds)
111                 return NULL;
112
113         idx             = tbl->result_start_idx;
114         *num_rslt_flds  = tbl->result_num_fields;
115         *num_encap_flds = tbl->encap_num_fields;
116
117         /* NOTE: Need template to provide range checking define */
118         return &ulp_act_result_field_list[idx];
119 }
120
121 /*
122  * Get the list of ident fields that implement the flow
123  *
124  * tbl [in] A single table instance to get the ident fields from
125  *
126  * num_flds [out] The number of ident fields in the returned array
127  *
128  * returns array of ident fields, or NULL on error
129  */
130 static struct bnxt_ulp_mapper_ident_info *
131 ulp_mapper_ident_fields_get(struct bnxt_ulp_mapper_class_tbl_info *tbl,
132                             uint32_t *num_flds)
133 {
134         uint32_t idx;
135
136         if (!tbl || !num_flds)
137                 return NULL;
138
139         idx = tbl->ident_start_idx;
140         *num_flds = tbl->ident_nums;
141
142         /* NOTE: Need template to provide range checking define */
143         return &ulp_ident_list[idx];
144 }
145
146 static int32_t
147 ulp_mapper_ident_process(struct bnxt_ulp_mapper_parms *parms,
148                          struct bnxt_ulp_mapper_class_tbl_info *tbl,
149                          struct bnxt_ulp_mapper_ident_info *ident)
150 {
151         struct ulp_flow_db_res_params   fid_parms;
152         uint64_t id = 0;
153         int32_t idx;
154         struct tf_alloc_identifier_parms iparms = { 0 };
155         struct tf_free_identifier_parms free_parms = { 0 };
156         struct tf *tfp;
157         int rc;
158
159         tfp = bnxt_ulp_cntxt_tfp_get(parms->ulp_ctx);
160         if (!tfp) {
161                 BNXT_TF_DBG(ERR, "Failed to get tf pointer\n");
162                 return -EINVAL;
163         }
164
165         idx = ident->regfile_wr_idx;
166
167         iparms.ident_type = ident->ident_type;
168         iparms.dir = tbl->direction;
169
170         rc = tf_alloc_identifier(tfp, &iparms);
171         if (rc) {
172                 BNXT_TF_DBG(ERR, "Alloc ident %s:%d failed.\n",
173                             (iparms.dir == TF_DIR_RX) ? "RX" : "TX",
174                             iparms.ident_type);
175                 return rc;
176         }
177
178         id = (uint64_t)tfp_cpu_to_be_64(iparms.id);
179         if (!ulp_regfile_write(parms->regfile, idx, id)) {
180                 BNXT_TF_DBG(ERR, "Regfile[%d] write failed.\n", idx);
181                 rc = -EINVAL;
182                 /* Need to free the identifier, so goto error */
183                 goto error;
184         }
185
186         /* Link the resource to the flow in the flow db */
187         memset(&fid_parms, 0, sizeof(fid_parms));
188         fid_parms.direction             = tbl->direction;
189         fid_parms.resource_func = ident->resource_func;
190         fid_parms.resource_type = ident->ident_type;
191         fid_parms.resource_hndl = iparms.id;
192         fid_parms.critical_resource     = 0;
193
194         rc = ulp_flow_db_resource_add(parms->ulp_ctx,
195                                       parms->tbl_idx,
196                                       parms->fid,
197                                       &fid_parms);
198         if (rc) {
199                 BNXT_TF_DBG(ERR, "Failed to link resource to flow rc = %d\n",
200                             rc);
201                 /* Need to free the identifier, so goto error */
202                 goto error;
203         }
204
205         return 0;
206
207 error:
208         /* Need to free the identifier */
209         free_parms.dir          = tbl->direction;
210         free_parms.ident_type   = ident->ident_type;
211         free_parms.id           = iparms.id;
212
213         (void)tf_free_identifier(tfp, &free_parms);
214
215         BNXT_TF_DBG(ERR, "Ident process failed for %s:%s\n",
216                     ident->name,
217                     (tbl->direction == TF_DIR_RX) ? "RX" : "TX");
218         return rc;
219 }
220
221 static int32_t
222 ulp_mapper_result_field_process(struct bnxt_ulp_mapper_parms *parms,
223                                 struct bnxt_ulp_mapper_result_field_info *fld,
224                                 struct ulp_blob *blob)
225 {
226         uint16_t idx, size_idx;
227         uint8_t  *val = NULL;
228         uint64_t regval;
229         uint32_t val_size = 0, field_size = 0;
230
231         switch (fld->result_opcode) {
232         case BNXT_ULP_RESULT_OPC_SET_TO_CONSTANT:
233                 val = fld->result_operand;
234                 if (!ulp_blob_push(blob, val, fld->field_bit_size)) {
235                         BNXT_TF_DBG(ERR, "Failed to add field\n");
236                         return -EINVAL;
237                 }
238                 break;
239         case BNXT_ULP_RESULT_OPC_SET_TO_ACT_PROP:
240                 if (!ulp_operand_read(fld->result_operand,
241                                       (uint8_t *)&idx, sizeof(uint16_t))) {
242                         BNXT_TF_DBG(ERR, "operand read failed\n");
243                         return -EINVAL;
244                 }
245                 idx = tfp_be_to_cpu_16(idx);
246
247                 if (idx >= BNXT_ULP_ACT_PROP_IDX_LAST) {
248                         BNXT_TF_DBG(ERR, "act_prop[%d] oob\n", idx);
249                         return -EINVAL;
250                 }
251                 val = &parms->act_prop->act_details[idx];
252                 field_size = ulp_mapper_act_prop_size_get(idx);
253                 if (fld->field_bit_size < ULP_BYTE_2_BITS(field_size)) {
254                         field_size  = field_size -
255                             ((fld->field_bit_size + 7) / 8);
256                         val += field_size;
257                 }
258                 if (!ulp_blob_push(blob, val, fld->field_bit_size)) {
259                         BNXT_TF_DBG(ERR, "push field failed\n");
260                         return -EINVAL;
261                 }
262                 break;
263         case BNXT_ULP_RESULT_OPC_SET_TO_ACT_PROP_SZ:
264                 if (!ulp_operand_read(fld->result_operand,
265                                       (uint8_t *)&idx, sizeof(uint16_t))) {
266                         BNXT_TF_DBG(ERR, "operand read failed\n");
267                         return -EINVAL;
268                 }
269                 idx = tfp_be_to_cpu_16(idx);
270
271                 if (idx >= BNXT_ULP_ACT_PROP_IDX_LAST) {
272                         BNXT_TF_DBG(ERR, "act_prop[%d] oob\n", idx);
273                         return -EINVAL;
274                 }
275                 val = &parms->act_prop->act_details[idx];
276
277                 /* get the size index next */
278                 if (!ulp_operand_read(&fld->result_operand[sizeof(uint16_t)],
279                                       (uint8_t *)&size_idx, sizeof(uint16_t))) {
280                         BNXT_TF_DBG(ERR, "operand read failed\n");
281                         return -EINVAL;
282                 }
283                 size_idx = tfp_be_to_cpu_16(size_idx);
284
285                 if (size_idx >= BNXT_ULP_ACT_PROP_IDX_LAST) {
286                         BNXT_TF_DBG(ERR, "act_prop[%d] oob\n", size_idx);
287                         return -EINVAL;
288                 }
289                 memcpy(&val_size, &parms->act_prop->act_details[size_idx],
290                        sizeof(uint32_t));
291                 val_size = tfp_be_to_cpu_32(val_size);
292                 val_size = ULP_BYTE_2_BITS(val_size);
293                 ulp_blob_push_encap(blob, val, val_size);
294                 break;
295         case BNXT_ULP_RESULT_OPC_SET_TO_REGFILE:
296                 if (!ulp_operand_read(fld->result_operand,
297                                       (uint8_t *)&idx, sizeof(uint16_t))) {
298                         BNXT_TF_DBG(ERR, "operand read failed\n");
299                         return -EINVAL;
300                 }
301
302                 idx = tfp_be_to_cpu_16(idx);
303                 /* Uninitialized regfile entries return 0 */
304                 if (!ulp_regfile_read(parms->regfile, idx, &regval)) {
305                         BNXT_TF_DBG(ERR, "regfile[%d] read oob\n", idx);
306                         return -EINVAL;
307                 }
308
309                 val = ulp_blob_push_64(blob, &regval, fld->field_bit_size);
310                 if (!val) {
311                         BNXT_TF_DBG(ERR, "push field failed\n");
312                         return -EINVAL;
313                 }
314                 break;
315         default:
316                 return -EINVAL;
317         }
318
319         return 0;
320 }
321
322 /* Function to alloc action record and set the table. */
323 static int32_t
324 ulp_mapper_keymask_field_process(struct bnxt_ulp_mapper_parms *parms,
325                                  struct bnxt_ulp_mapper_class_key_field_info *f,
326                                  struct ulp_blob *blob,
327                                  uint8_t is_key)
328 {
329         uint64_t regval;
330         uint16_t idx, bitlen;
331         uint32_t opcode;
332         uint8_t *operand;
333         struct ulp_regfile *regfile = parms->regfile;
334         uint8_t *val = NULL;
335         struct bnxt_ulp_mapper_class_key_field_info *fld = f;
336         uint32_t field_size;
337
338         if (is_key) {
339                 operand = fld->spec_operand;
340                 opcode  = fld->spec_opcode;
341         } else {
342                 operand = fld->mask_operand;
343                 opcode  = fld->mask_opcode;
344         }
345
346         bitlen = fld->field_bit_size;
347
348         switch (opcode) {
349         case BNXT_ULP_SPEC_OPC_SET_TO_CONSTANT:
350                 val = operand;
351                 if (!ulp_blob_push(blob, val, bitlen)) {
352                         BNXT_TF_DBG(ERR, "push to key blob failed\n");
353                         return -EINVAL;
354                 }
355                 break;
356         case BNXT_ULP_SPEC_OPC_ADD_PAD:
357                 if (!ulp_blob_pad_push(blob, bitlen)) {
358                         BNXT_TF_DBG(ERR, "Pad too large for blob\n");
359                         return -EINVAL;
360                 }
361
362                 break;
363         case BNXT_ULP_SPEC_OPC_SET_TO_HDR_FIELD:
364                 if (!ulp_operand_read(operand, (uint8_t *)&idx,
365                                       sizeof(uint16_t))) {
366                         BNXT_TF_DBG(ERR, "key operand read failed.\n");
367                         return -EINVAL;
368                 }
369                 idx = tfp_be_to_cpu_16(idx);
370                 if (is_key)
371                         val = parms->hdr_field[idx].spec;
372                 else
373                         val = parms->hdr_field[idx].mask;
374
375                 /*
376                  * Need to account for how much data was pushed to the header
377                  * field vs how much is to be inserted in the key/mask.
378                  */
379                 field_size = parms->hdr_field[idx].size;
380                 if (bitlen < ULP_BYTE_2_BITS(field_size)) {
381                         field_size  = field_size - ((bitlen + 7) / 8);
382                         val += field_size;
383                 }
384
385                 if (!ulp_blob_push(blob, val, bitlen)) {
386                         BNXT_TF_DBG(ERR, "push to key blob failed\n");
387                         return -EINVAL;
388                 }
389                 break;
390         case BNXT_ULP_SPEC_OPC_SET_TO_REGFILE:
391                 if (!ulp_operand_read(operand, (uint8_t *)&idx,
392                                       sizeof(uint16_t))) {
393                         BNXT_TF_DBG(ERR, "key operand read failed.\n");
394                         return -EINVAL;
395                 }
396                 idx = tfp_be_to_cpu_16(idx);
397
398                 if (!ulp_regfile_read(regfile, idx, &regval)) {
399                         BNXT_TF_DBG(ERR, "regfile[%d] read failed.\n",
400                                     idx);
401                         return -EINVAL;
402                 }
403
404                 val = ulp_blob_push_64(blob, &regval, bitlen);
405                 if (!val) {
406                         BNXT_TF_DBG(ERR, "push to key blob failed\n");
407                         return -EINVAL;
408                 }
409         default:
410                 break;
411         }
412
413         return 0;
414 }
415
416 /* Function to alloc action record and set the table. */
417 static int32_t
418 ulp_mapper_action_alloc_and_set(struct bnxt_ulp_mapper_parms *parms,
419                                 struct ulp_blob *blob)
420 {
421         struct ulp_flow_db_res_params           fid_parms;
422         struct tf_alloc_tbl_entry_parms         alloc_parms = { 0 };
423         struct tf_free_tbl_entry_parms          free_parms = { 0 };
424         struct bnxt_ulp_mapper_act_tbl_info     *atbls = parms->atbls;
425         int32_t                                 rc = 0;
426         int32_t trc;
427         uint64_t                                idx;
428
429         /* Set the allocation parameters for the table*/
430         alloc_parms.dir = atbls->direction;
431         alloc_parms.type = atbls->table_type;
432         alloc_parms.search_enable = atbls->srch_b4_alloc;
433         alloc_parms.result = ulp_blob_data_get(blob,
434                                                &alloc_parms.result_sz_in_bytes);
435         if (!alloc_parms.result) {
436                 BNXT_TF_DBG(ERR, "blob is not populated\n");
437                 return -EINVAL;
438         }
439
440         rc = tf_alloc_tbl_entry(parms->tfp, &alloc_parms);
441         if (rc) {
442                 BNXT_TF_DBG(ERR, "table type= [%d] dir = [%s] alloc failed\n",
443                             alloc_parms.type,
444                             (alloc_parms.dir == TF_DIR_RX) ? "RX" : "TX");
445                 return rc;
446         }
447
448         /* Need to calculate the idx for the result record */
449         /*
450          * TBD: Need to get the stride from tflib instead of having to
451          * understand the construction of the pointer
452          */
453         uint64_t tmpidx = alloc_parms.idx;
454
455         if (atbls->table_type == TF_TBL_TYPE_EXT)
456                 tmpidx = (alloc_parms.idx * TF_ACTION_RECORD_SZ) >> 4;
457         else
458                 tmpidx = alloc_parms.idx;
459
460         idx = tfp_cpu_to_be_64(tmpidx);
461
462         /* Store the allocated index for future use in the regfile */
463         rc = ulp_regfile_write(parms->regfile, atbls->regfile_wr_idx, idx);
464         if (!rc) {
465                 BNXT_TF_DBG(ERR, "regfile[%d] write failed\n",
466                             atbls->regfile_wr_idx);
467                 rc = -EINVAL;
468                 goto error;
469         }
470
471         /*
472          * The set_tbl_entry API if search is not enabled or searched entry
473          * is not found.
474          */
475         if (!atbls->srch_b4_alloc || !alloc_parms.hit) {
476                 struct tf_set_tbl_entry_parms set_parm = { 0 };
477                 uint16_t        length;
478
479                 set_parm.dir    = atbls->direction;
480                 set_parm.type   = atbls->table_type;
481                 set_parm.idx    = alloc_parms.idx;
482                 set_parm.data   = ulp_blob_data_get(blob, &length);
483                 set_parm.data_sz_in_bytes = length / 8;
484
485                 if (set_parm.type == TF_TBL_TYPE_EXT)
486                         bnxt_ulp_cntxt_tbl_scope_id_get(parms->ulp_ctx,
487                                                         &set_parm.tbl_scope_id);
488                 else
489                         set_parm.tbl_scope_id = 0;
490
491                 /* set the table entry */
492                 rc = tf_set_tbl_entry(parms->tfp, &set_parm);
493                 if (rc) {
494                         BNXT_TF_DBG(ERR, "table[%d][%s][%d] set failed\n",
495                                     set_parm.type,
496                                     (set_parm.dir == TF_DIR_RX) ? "RX" : "TX",
497                                     set_parm.idx);
498                         goto error;
499                 }
500         }
501
502         /* Link the resource to the flow in the flow db */
503         memset(&fid_parms, 0, sizeof(fid_parms));
504         fid_parms.direction             = atbls->direction;
505         fid_parms.resource_func         = atbls->resource_func;
506         fid_parms.resource_type         = atbls->table_type;
507         fid_parms.resource_hndl         = alloc_parms.idx;
508         fid_parms.critical_resource     = 0;
509
510         rc = ulp_flow_db_resource_add(parms->ulp_ctx,
511                                       parms->tbl_idx,
512                                       parms->fid,
513                                       &fid_parms);
514         if (rc) {
515                 BNXT_TF_DBG(ERR, "Failed to link resource to flow rc = %d\n",
516                             rc);
517                 rc = -EINVAL;
518                 goto error;
519         }
520
521         return 0;
522 error:
523
524         free_parms.dir  = alloc_parms.dir;
525         free_parms.type = alloc_parms.type;
526         free_parms.idx  = alloc_parms.idx;
527
528         trc = tf_free_tbl_entry(parms->tfp, &free_parms);
529         if (trc)
530                 BNXT_TF_DBG(ERR, "Failed to free table entry on failure\n");
531
532         return rc;
533 }
534
535 /*
536  * Function to process the action Info. Iterate through the list
537  * action info templates and process it.
538  */
539 static int32_t
540 ulp_mapper_action_info_process(struct bnxt_ulp_mapper_parms *parms,
541                                struct bnxt_ulp_mapper_act_tbl_info *tbl)
542 {
543         struct ulp_blob                                 blob;
544         struct bnxt_ulp_mapper_result_field_info        *flds, *fld;
545         uint32_t                                        num_flds = 0;
546         uint32_t                                        encap_flds = 0;
547         uint32_t                                        i;
548         int32_t                                         rc;
549         uint16_t                                        bit_size;
550
551         if (!tbl || !parms->act_prop || !parms->act_bitmap || !parms->regfile)
552                 return -EINVAL;
553
554         /* use the max size if encap is enabled */
555         if (tbl->encap_num_fields)
556                 bit_size = BNXT_ULP_FLMP_BLOB_SIZE_IN_BITS;
557         else
558                 bit_size = tbl->result_bit_size;
559         if (!ulp_blob_init(&blob, bit_size, parms->order)) {
560                 BNXT_TF_DBG(ERR, "action blob init failed\n");
561                 return -EINVAL;
562         }
563
564         flds = ulp_mapper_act_result_fields_get(tbl, &num_flds, &encap_flds);
565         if (!flds || !num_flds) {
566                 BNXT_TF_DBG(ERR, "Template undefined for action\n");
567                 return -EINVAL;
568         }
569
570         for (i = 0; i < (num_flds + encap_flds); i++) {
571                 fld = &flds[i];
572                 rc = ulp_mapper_result_field_process(parms,
573                                                      fld,
574                                                      &blob);
575                 if (rc) {
576                         BNXT_TF_DBG(ERR, "Action field failed\n");
577                         return rc;
578                 }
579                 /* set the swap index if 64 bit swap is enabled */
580                 if (parms->encap_byte_swap && encap_flds) {
581                         if ((i + 1) == num_flds)
582                                 ulp_blob_encap_swap_idx_set(&blob);
583                         /* if 64 bit swap is enabled perform the 64bit swap */
584                         if ((i + 1) == (num_flds + encap_flds))
585                                 ulp_blob_perform_encap_swap(&blob);
586                 }
587         }
588
589         rc = ulp_mapper_action_alloc_and_set(parms, &blob);
590         return rc;
591 }
592
593 static int32_t
594 ulp_mapper_tcam_tbl_process(struct bnxt_ulp_mapper_parms *parms,
595                             struct bnxt_ulp_mapper_class_tbl_info *tbl)
596 {
597         struct bnxt_ulp_mapper_class_key_field_info     *kflds;
598         struct ulp_blob key, mask, data;
599         uint32_t i, num_kflds;
600         struct tf *tfp;
601         int32_t rc, trc;
602         struct tf_alloc_tcam_entry_parms aparms         = { 0 };
603         struct tf_set_tcam_entry_parms sparms           = { 0 };
604         struct ulp_flow_db_res_params   fid_parms       = { 0 };
605         struct tf_free_tcam_entry_parms free_parms      = { 0 };
606         uint32_t hit = 0;
607         uint16_t tmplen = 0;
608
609         tfp = bnxt_ulp_cntxt_tfp_get(parms->ulp_ctx);
610         if (!tfp) {
611                 BNXT_TF_DBG(ERR, "Failed to get truflow pointer\n");
612                 return -EINVAL;
613         }
614
615         kflds = ulp_mapper_key_fields_get(tbl, &num_kflds);
616         if (!kflds || !num_kflds) {
617                 BNXT_TF_DBG(ERR, "Failed to get key fields\n");
618                 return -EINVAL;
619         }
620
621         if (!ulp_blob_init(&key, tbl->key_bit_size, parms->order) ||
622             !ulp_blob_init(&mask, tbl->key_bit_size, parms->order) ||
623             !ulp_blob_init(&data, tbl->result_bit_size, parms->order)) {
624                 BNXT_TF_DBG(ERR, "blob inits failed.\n");
625                 return -EINVAL;
626         }
627
628         /* create the key/mask */
629         /*
630          * NOTE: The WC table will require some kind of flag to handle the
631          * mode bits within the key/mask
632          */
633         for (i = 0; i < num_kflds; i++) {
634                 /* Setup the key */
635                 rc = ulp_mapper_keymask_field_process(parms, &kflds[i],
636                                                       &key, 1);
637                 if (rc) {
638                         BNXT_TF_DBG(ERR, "Key field set failed.\n");
639                         return rc;
640                 }
641
642                 /* Setup the mask */
643                 rc = ulp_mapper_keymask_field_process(parms, &kflds[i],
644                                                       &mask, 0);
645                 if (rc) {
646                         BNXT_TF_DBG(ERR, "Mask field set failed.\n");
647                         return rc;
648                 }
649         }
650
651         aparms.dir              = tbl->direction;
652         aparms.tcam_tbl_type    = tbl->table_type;
653         aparms.search_enable    = tbl->srch_b4_alloc;
654         aparms.key_sz_in_bits   = tbl->key_bit_size;
655         aparms.key              = ulp_blob_data_get(&key, &tmplen);
656         if (tbl->key_bit_size != tmplen) {
657                 BNXT_TF_DBG(ERR, "Key len (%d) != Expected (%d)\n",
658                             tmplen, tbl->key_bit_size);
659                 return -EINVAL;
660         }
661
662         aparms.mask             = ulp_blob_data_get(&mask, &tmplen);
663         if (tbl->key_bit_size != tmplen) {
664                 BNXT_TF_DBG(ERR, "Mask len (%d) != Expected (%d)\n",
665                             tmplen, tbl->key_bit_size);
666                 return -EINVAL;
667         }
668
669         aparms.priority         = tbl->priority;
670
671         /*
672          * All failures after this succeeds require the entry to be freed.
673          * cannot return directly on failure, but needs to goto error
674          */
675         rc = tf_alloc_tcam_entry(tfp, &aparms);
676         if (rc) {
677                 BNXT_TF_DBG(ERR, "tcam alloc failed rc=%d.\n", rc);
678                 return rc;
679         }
680
681         hit = aparms.hit;
682
683         /* Build the result */
684         if (!tbl->srch_b4_alloc || !hit) {
685                 struct bnxt_ulp_mapper_result_field_info *dflds;
686                 struct bnxt_ulp_mapper_ident_info *idents;
687                 uint32_t num_dflds, num_idents;
688
689                 /* Alloc identifiers */
690                 idents = ulp_mapper_ident_fields_get(tbl, &num_idents);
691
692                 for (i = 0; i < num_idents; i++) {
693                         rc = ulp_mapper_ident_process(parms, tbl, &idents[i]);
694
695                         /* Already logged the error, just return */
696                         if (rc)
697                                 goto error;
698                 }
699
700                 /* Create the result data blob */
701                 dflds = ulp_mapper_result_fields_get(tbl, &num_dflds);
702                 if (!dflds || !num_dflds) {
703                         BNXT_TF_DBG(ERR, "Failed to get data fields.\n");
704                         rc = -EINVAL;
705                         goto error;
706                 }
707
708                 for (i = 0; i < num_dflds; i++) {
709                         rc = ulp_mapper_result_field_process(parms,
710                                                              &dflds[i],
711                                                              &data);
712                         if (rc) {
713                                 BNXT_TF_DBG(ERR, "Failed to set data fields\n");
714                                 goto error;
715                         }
716                 }
717
718                 sparms.dir              = aparms.dir;
719                 sparms.tcam_tbl_type    = aparms.tcam_tbl_type;
720                 sparms.idx              = aparms.idx;
721                 /* Already verified the key/mask lengths */
722                 sparms.key              = ulp_blob_data_get(&key, &tmplen);
723                 sparms.mask             = ulp_blob_data_get(&mask, &tmplen);
724                 sparms.key_sz_in_bits   = tbl->key_bit_size;
725                 sparms.result           = ulp_blob_data_get(&data, &tmplen);
726
727                 if (tbl->result_bit_size != tmplen) {
728                         BNXT_TF_DBG(ERR, "Result len (%d) != Expected (%d)\n",
729                                     tmplen, tbl->result_bit_size);
730                         rc = -EINVAL;
731                         goto error;
732                 }
733                 sparms.result_sz_in_bits = tbl->result_bit_size;
734
735                 rc = tf_set_tcam_entry(tfp, &sparms);
736                 if (rc) {
737                         BNXT_TF_DBG(ERR, "tcam[%d][%s][%d] write failed.\n",
738                                     sparms.tcam_tbl_type,
739                                     (sparms.dir == TF_DIR_RX) ? "RX" : "TX",
740                                     sparms.idx);
741                         goto error;
742                 }
743         } else {
744                 BNXT_TF_DBG(ERR, "Not supporting search before alloc now\n");
745                 rc = -EINVAL;
746                 goto error;
747         }
748
749         /* Link the resource to the flow in the flow db */
750         fid_parms.direction = tbl->direction;
751         fid_parms.resource_func = tbl->resource_func;
752         fid_parms.resource_type = tbl->table_type;
753         fid_parms.critical_resource = tbl->critical_resource;
754         fid_parms.resource_hndl = aparms.idx;
755
756         rc = ulp_flow_db_resource_add(parms->ulp_ctx,
757                                       parms->tbl_idx,
758                                       parms->fid,
759                                       &fid_parms);
760         if (rc) {
761                 BNXT_TF_DBG(ERR, "Failed to link resource to flow rc = %d\n",
762                             rc);
763                 /* Need to free the identifier, so goto error */
764                 goto error;
765         }
766
767         return 0;
768 error:
769         free_parms.dir                  = tbl->direction;
770         free_parms.tcam_tbl_type        = tbl->table_type;
771         free_parms.idx                  = aparms.idx;
772         trc = tf_free_tcam_entry(tfp, &free_parms);
773         if (trc)
774                 BNXT_TF_DBG(ERR, "Failed to free tcam[%d][%d][%d] on failure\n",
775                             tbl->table_type, tbl->direction, aparms.idx);
776
777         return rc;
778 }
779
780 static int32_t
781 ulp_mapper_em_tbl_process(struct bnxt_ulp_mapper_parms *parms,
782                           struct bnxt_ulp_mapper_class_tbl_info *tbl)
783 {
784         struct bnxt_ulp_mapper_class_key_field_info     *kflds;
785         struct bnxt_ulp_mapper_result_field_info *dflds;
786         struct ulp_blob key, data;
787         uint32_t i, num_kflds, num_dflds;
788         uint16_t tmplen;
789         struct tf *tfp = bnxt_ulp_cntxt_tfp_get(parms->ulp_ctx);
790         struct ulp_rte_act_prop  *a_prop = parms->act_prop;
791         struct ulp_flow_db_res_params   fid_parms = { 0 };
792         struct tf_insert_em_entry_parms iparms = { 0 };
793         struct tf_delete_em_entry_parms free_parms = { 0 };
794         int32_t trc;
795         int32_t rc = 0;
796
797         kflds = ulp_mapper_key_fields_get(tbl, &num_kflds);
798         if (!kflds || !num_kflds) {
799                 BNXT_TF_DBG(ERR, "Failed to get key fields\n");
800                 return -EINVAL;
801         }
802
803         /* Initialize the key/result blobs */
804         if (!ulp_blob_init(&key, tbl->blob_key_bit_size, parms->order) ||
805             !ulp_blob_init(&data, tbl->result_bit_size, parms->order)) {
806                 BNXT_TF_DBG(ERR, "blob inits failed.\n");
807                 return -EINVAL;
808         }
809
810         /* create the key */
811         for (i = 0; i < num_kflds; i++) {
812                 /* Setup the key */
813                 rc = ulp_mapper_keymask_field_process(parms, &kflds[i],
814                                                       &key, 1);
815                 if (rc) {
816                         BNXT_TF_DBG(ERR, "Key field set failed.\n");
817                         return rc;
818                 }
819         }
820
821         /*
822          * TBD: Normally should process identifiers in case of using recycle or
823          * loopback.  Not supporting recycle for now.
824          */
825
826         /* Create the result data blob */
827         dflds = ulp_mapper_result_fields_get(tbl, &num_dflds);
828         if (!dflds || !num_dflds) {
829                 BNXT_TF_DBG(ERR, "Failed to get data fields.\n");
830                 return -EINVAL;
831         }
832
833         for (i = 0; i < num_dflds; i++) {
834                 struct bnxt_ulp_mapper_result_field_info *fld;
835
836                 fld = &dflds[i];
837
838                 rc = ulp_mapper_result_field_process(parms,
839                                                      fld,
840                                                      &data);
841                 if (rc) {
842                         BNXT_TF_DBG(ERR, "Failed to set data fields.\n");
843                         return rc;
844                 }
845         }
846
847         rc = bnxt_ulp_cntxt_tbl_scope_id_get(parms->ulp_ctx,
848                                              &iparms.tbl_scope_id);
849         if (rc) {
850                 BNXT_TF_DBG(ERR, "Failed to get table scope rc=%d\n", rc);
851                 return rc;
852         }
853
854         /*
855          * NOTE: the actual blob size will differ from the size in the tbl
856          * entry due to the padding.
857          */
858         iparms.dup_check                = 0;
859         iparms.dir                      = tbl->direction;
860         iparms.mem                      = tbl->mem;
861         iparms.key                      = ulp_blob_data_get(&key, &tmplen);
862         iparms.key_sz_in_bits           = tbl->key_bit_size;
863         iparms.em_record                = ulp_blob_data_get(&data, &tmplen);
864         iparms.em_record_sz_in_bits     = tbl->result_bit_size;
865
866         rc = tf_insert_em_entry(tfp, &iparms);
867         if (rc) {
868                 BNXT_TF_DBG(ERR, "Failed to insert em entry rc=%d.\n", rc);
869                 return rc;
870         }
871
872         if (tbl->mark_enable &&
873             ULP_BITMAP_ISSET(parms->act_bitmap->bits,
874                              BNXT_ULP_ACTION_BIT_MARK)) {
875                 uint32_t val, mark, gfid, flag;
876                 /* TBD: Need to determine if GFID is enabled globally */
877                 if (sizeof(val) != BNXT_ULP_ACT_PROP_SZ_MARK) {
878                         BNXT_TF_DBG(ERR, "Mark size (%d) != expected (%zu)\n",
879                                     BNXT_ULP_ACT_PROP_SZ_MARK, sizeof(val));
880                         rc = -EINVAL;
881                         goto error;
882                 }
883
884                 memcpy(&val,
885                        &a_prop->act_details[BNXT_ULP_ACT_PROP_IDX_MARK],
886                        sizeof(val));
887
888                 mark = tfp_be_to_cpu_32(val);
889
890                 TF_GET_GFID_FROM_FLOW_ID(iparms.flow_id, gfid);
891                 TF_GET_FLAG_FROM_FLOW_ID(iparms.flow_id, flag);
892
893                 rc = ulp_mark_db_mark_add(parms->ulp_ctx,
894                                           (flag == TF_GFID_TABLE_EXTERNAL),
895                                           gfid,
896                                           mark);
897                 if (rc) {
898                         BNXT_TF_DBG(ERR, "Failed to add mark to flow\n");
899                         goto error;
900                 }
901
902                 /*
903                  * Link the mark resource to the flow in the flow db
904                  * The mark is never the critical resource, so it is 0.
905                  */
906                 memset(&fid_parms, 0, sizeof(fid_parms));
907                 fid_parms.direction     = tbl->direction;
908                 fid_parms.resource_func = BNXT_ULP_RESOURCE_FUNC_HW_FID;
909                 fid_parms.resource_type = tbl->table_type;
910                 fid_parms.resource_hndl = iparms.flow_id;
911                 fid_parms.critical_resource = 0;
912
913                 rc = ulp_flow_db_resource_add(parms->ulp_ctx,
914                                               parms->tbl_idx,
915                                               parms->fid,
916                                               &fid_parms);
917                 if (rc) {
918                         BNXT_TF_DBG(ERR, "Fail to link res to flow rc = %d\n",
919                                     rc);
920                         /* Need to free the identifier, so goto error */
921                         goto error;
922                 }
923         }
924
925         /* Link the EM resource to the flow in the flow db */
926         memset(&fid_parms, 0, sizeof(fid_parms));
927         fid_parms.direction             = tbl->direction;
928         fid_parms.resource_func         = tbl->resource_func;
929         fid_parms.resource_type         = tbl->table_type;
930         fid_parms.critical_resource     = tbl->critical_resource;
931         fid_parms.resource_hndl         = iparms.flow_handle;
932
933         rc = ulp_flow_db_resource_add(parms->ulp_ctx,
934                                       parms->tbl_idx,
935                                       parms->fid,
936                                       &fid_parms);
937         if (rc) {
938                 BNXT_TF_DBG(ERR, "Fail to link res to flow rc = %d\n",
939                             rc);
940                 /* Need to free the identifier, so goto error */
941                 goto error;
942         }
943
944         return 0;
945 error:
946         free_parms.dir          = iparms.dir;
947         free_parms.mem          = iparms.mem;
948         free_parms.tbl_scope_id = iparms.tbl_scope_id;
949         free_parms.flow_handle  = iparms.flow_handle;
950
951         trc = tf_delete_em_entry(tfp, &free_parms);
952         if (trc)
953                 BNXT_TF_DBG(ERR, "Failed to delete EM entry on failed add\n");
954
955         return rc;
956 }
957
958 static int32_t
959 ulp_mapper_index_tbl_process(struct bnxt_ulp_mapper_parms *parms,
960                              struct bnxt_ulp_mapper_class_tbl_info *tbl)
961 {
962         struct bnxt_ulp_mapper_result_field_info *flds;
963         struct ulp_flow_db_res_params   fid_parms;
964         struct ulp_blob data;
965         uint64_t idx;
966         uint16_t tmplen;
967         uint32_t i, num_flds;
968         int32_t rc = 0, trc = 0;
969         struct tf_alloc_tbl_entry_parms aparms = { 0 };
970         struct tf_set_tbl_entry_parms   sparms = { 0 };
971         struct tf_free_tbl_entry_parms  free_parms = { 0 };
972
973         struct tf *tfp = bnxt_ulp_cntxt_tfp_get(parms->ulp_ctx);
974
975         if (!ulp_blob_init(&data, tbl->result_bit_size, parms->order)) {
976                 BNXT_TF_DBG(ERR, "Failed initial index table blob\n");
977                 return -EINVAL;
978         }
979
980         flds = ulp_mapper_result_fields_get(tbl, &num_flds);
981         if (!flds || !num_flds) {
982                 BNXT_TF_DBG(ERR, "Template undefined for action\n");
983                 return -EINVAL;
984         }
985
986         for (i = 0; i < num_flds; i++) {
987                 rc = ulp_mapper_result_field_process(parms,
988                                                      &flds[i],
989                                                      &data);
990                 if (rc) {
991                         BNXT_TF_DBG(ERR, "data field failed\n");
992                         return rc;
993                 }
994         }
995
996         aparms.dir              = tbl->direction;
997         aparms.type             = tbl->table_type;
998         aparms.search_enable    = tbl->srch_b4_alloc;
999         aparms.result           = ulp_blob_data_get(&data, &tmplen);
1000         aparms.result_sz_in_bytes = ULP_SZ_BITS2BYTES(tbl->result_bit_size);
1001
1002         /* All failures after the alloc succeeds require a free */
1003         rc = tf_alloc_tbl_entry(tfp, &aparms);
1004         if (rc) {
1005                 BNXT_TF_DBG(ERR, "Alloc table[%d][%s] failed rc=%d\n",
1006                             tbl->table_type,
1007                             (tbl->direction == TF_DIR_RX) ? "RX" : "TX",
1008                             rc);
1009                 return rc;
1010         }
1011
1012         /* Always storing values in Regfile in BE */
1013         idx = tfp_cpu_to_be_64(aparms.idx);
1014         rc = ulp_regfile_write(parms->regfile, tbl->regfile_wr_idx, idx);
1015         if (!rc) {
1016                 BNXT_TF_DBG(ERR, "Write regfile[%d] failed\n",
1017                             tbl->regfile_wr_idx);
1018                 goto error;
1019         }
1020
1021         if (!tbl->srch_b4_alloc) {
1022                 sparms.dir              = tbl->direction;
1023                 sparms.type             = tbl->table_type;
1024                 sparms.data             = ulp_blob_data_get(&data, &tmplen);
1025                 sparms.data_sz_in_bytes =
1026                         ULP_SZ_BITS2BYTES(tbl->result_bit_size);
1027                 sparms.idx              = aparms.idx;
1028
1029                 rc = tf_set_tbl_entry(tfp, &sparms);
1030                 if (rc) {
1031                         BNXT_TF_DBG(ERR, "Set table[%d][%s][%d] failed rc=%d\n",
1032                                     tbl->table_type,
1033                                     (tbl->direction == TF_DIR_RX) ? "RX" : "TX",
1034                                     sparms.idx,
1035                                     rc);
1036
1037                         goto error;
1038                 }
1039         }
1040
1041         /* Link the resource to the flow in the flow db */
1042         memset(&fid_parms, 0, sizeof(fid_parms));
1043         fid_parms.direction     = tbl->direction;
1044         fid_parms.resource_func = tbl->resource_func;
1045         fid_parms.resource_type = tbl->table_type;
1046         fid_parms.resource_hndl = aparms.idx;
1047         fid_parms.critical_resource     = 0;
1048
1049         rc = ulp_flow_db_resource_add(parms->ulp_ctx,
1050                                       parms->tbl_idx,
1051                                       parms->fid,
1052                                       &fid_parms);
1053         if (rc) {
1054                 BNXT_TF_DBG(ERR, "Failed to link resource to flow rc = %d\n",
1055                             rc);
1056                 goto error;
1057         }
1058
1059         return rc;
1060 error:
1061         /*
1062          * Free the allocated resource since we failed to either
1063          * write to the entry or link the flow
1064          */
1065         free_parms.dir  = tbl->direction;
1066         free_parms.type = tbl->table_type;
1067         free_parms.idx  = aparms.idx;
1068
1069         trc = tf_free_tbl_entry(tfp, &free_parms);
1070         if (trc)
1071                 BNXT_TF_DBG(ERR, "Failed to free tbl entry on failure\n");
1072
1073         return rc;
1074 }
1075
1076 /*
1077  * Function to process the action template. Iterate through the list
1078  * action info templates and process it.
1079  */
1080 int32_t
1081 ulp_mapper_action_tbls_process(struct bnxt_ulp_mapper_parms *parms)
1082 {
1083         uint32_t        i;
1084         int32_t         rc = 0;
1085
1086         if (!parms->atbls || !parms->num_atbls) {
1087                 BNXT_TF_DBG(ERR, "No action tables for template[%d][%d].\n",
1088                             parms->dev_id, parms->act_tid);
1089                 return -EINVAL;
1090         }
1091
1092         for (i = 0; i < parms->num_atbls; i++) {
1093                 rc = ulp_mapper_action_info_process(parms, &parms->atbls[i]);
1094                 if (rc)
1095                         return rc;
1096         }
1097
1098         return rc;
1099 }
1100
1101 /* Create the classifier table entries for a flow. */
1102 int32_t
1103 ulp_mapper_class_tbls_process(struct bnxt_ulp_mapper_parms *parms)
1104 {
1105         uint32_t        i;
1106         int32_t         rc = 0;
1107
1108         if (!parms)
1109                 return -EINVAL;
1110
1111         if (!parms->ctbls || !parms->num_ctbls) {
1112                 BNXT_TF_DBG(ERR, "No class tables for template[%d][%d].\n",
1113                             parms->dev_id, parms->class_tid);
1114                 return -EINVAL;
1115         }
1116
1117         for (i = 0; i < parms->num_ctbls; i++) {
1118                 struct bnxt_ulp_mapper_class_tbl_info *tbl = &parms->ctbls[i];
1119
1120                 switch (tbl->resource_func) {
1121                 case BNXT_ULP_RESOURCE_FUNC_TCAM_TABLE:
1122                         rc = ulp_mapper_tcam_tbl_process(parms, tbl);
1123                         break;
1124                 case BNXT_ULP_RESOURCE_FUNC_EM_TABLE:
1125                         rc = ulp_mapper_em_tbl_process(parms, tbl);
1126                         break;
1127                 case BNXT_ULP_RESOURCE_FUNC_INDEX_TABLE:
1128                         rc = ulp_mapper_index_tbl_process(parms, tbl);
1129                         break;
1130                 default:
1131                         BNXT_TF_DBG(ERR, "Unexpected class resource %d\n",
1132                                     tbl->resource_func);
1133                         return -EINVAL;
1134                 }
1135
1136                 if (rc) {
1137                         BNXT_TF_DBG(ERR, "Resource type %d failed\n",
1138                                     tbl->resource_func);
1139                         return rc;
1140                 }
1141         }
1142
1143         return rc;
1144 }