7696de2a54b9799b1e5a1cade39cc6764ad6d452
[dpdk.git] / drivers / net / bnxt / tf_ulp / ulp_flow_db.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2014-2020 Broadcom
3  * All rights reserved.
4  */
5
6 #include <rte_malloc.h>
7 #include "bnxt.h"
8 #include "bnxt_tf_common.h"
9 #include "ulp_flow_db.h"
10 #include "ulp_utils.h"
11 #include "ulp_template_struct.h"
12 #include "ulp_mapper.h"
13
14 #define ULP_FLOW_DB_RES_DIR_BIT         31
15 #define ULP_FLOW_DB_RES_DIR_MASK        0x80000000
16 #define ULP_FLOW_DB_RES_FUNC_BITS       28
17 #define ULP_FLOW_DB_RES_FUNC_MASK       0x70000000
18 #define ULP_FLOW_DB_RES_NXT_MASK        0x0FFFFFFF
19 #define ULP_FLOW_DB_RES_FUNC_UPPER      5
20 #define ULP_FLOW_DB_RES_FUNC_NEED_LOWER 0x80
21 #define ULP_FLOW_DB_RES_FUNC_LOWER_MASK 0x1F
22
23 /* Macro to copy the nxt_resource_idx */
24 #define ULP_FLOW_DB_RES_NXT_SET(dst, src)       {(dst) |= ((src) &\
25                                          ULP_FLOW_DB_RES_NXT_MASK); }
26 #define ULP_FLOW_DB_RES_NXT_RESET(dst)  ((dst) &= ~(ULP_FLOW_DB_RES_NXT_MASK))
27
28 /*
29  * Helper function to set the bit in the active flow table
30  * No validation is done in this function.
31  *
32  * flow_tbl [in] Ptr to flow table
33  * idx [in] The index to bit to be set or reset.
34  * flag [in] 1 to set and 0 to reset.
35  *
36  * returns none
37  */
38 static void
39 ulp_flow_db_active_flow_set(struct bnxt_ulp_flow_tbl    *flow_tbl,
40                             uint32_t                    idx,
41                             uint32_t                    flag)
42 {
43         uint32_t                active_index;
44
45         active_index = idx / ULP_INDEX_BITMAP_SIZE;
46         if (flag)
47                 ULP_INDEX_BITMAP_SET(flow_tbl->active_flow_tbl[active_index],
48                                      idx);
49         else
50                 ULP_INDEX_BITMAP_RESET(flow_tbl->active_flow_tbl[active_index],
51                                        idx);
52 }
53
54 /*
55  * Helper function to allocate the flow table and initialize
56  * is set.No validation being done in this function.
57  *
58  * flow_tbl [in] Ptr to flow table
59  * idx [in] The index to bit to be set or reset.
60  *
61  * returns 1 on set or 0 if not set.
62  */
63 static int32_t
64 ulp_flow_db_active_flow_is_set(struct bnxt_ulp_flow_tbl *flow_tbl,
65                                uint32_t                 idx)
66 {
67         uint32_t                active_index;
68
69         active_index = idx / ULP_INDEX_BITMAP_SIZE;
70         return ULP_INDEX_BITMAP_GET(flow_tbl->active_flow_tbl[active_index],
71                                     idx);
72 }
73
74 static uint8_t
75 ulp_flow_db_resource_func_get(struct ulp_fdb_resource_info *res_info)
76 {
77         uint8_t func;
78
79         func = (((res_info->nxt_resource_idx & ULP_FLOW_DB_RES_FUNC_MASK) >>
80                  ULP_FLOW_DB_RES_FUNC_BITS) << ULP_FLOW_DB_RES_FUNC_UPPER);
81         /* The reource func is split into upper and lower */
82         if (func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER)
83                 return (func | res_info->resource_func_lower);
84         return func;
85 }
86
87 /*
88  * Helper function to copy the resource params to resource info
89  *  No validation being done in this function.
90  *
91  * resource_info [out] Ptr to resource information
92  * params [in] The input params from the caller
93  * returns none
94  */
95 static void
96 ulp_flow_db_res_params_to_info(struct ulp_fdb_resource_info *resource_info,
97                                struct ulp_flow_db_res_params *params)
98 {
99         uint32_t resource_func;
100
101         resource_info->nxt_resource_idx |= ((params->direction <<
102                                       ULP_FLOW_DB_RES_DIR_BIT) &
103                                      ULP_FLOW_DB_RES_DIR_MASK);
104         resource_func = (params->resource_func >> ULP_FLOW_DB_RES_FUNC_UPPER);
105         resource_info->nxt_resource_idx |= ((resource_func <<
106                                              ULP_FLOW_DB_RES_FUNC_BITS) &
107                                             ULP_FLOW_DB_RES_FUNC_MASK);
108
109         if (params->resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) {
110                 /* Break the resource func into two parts */
111                 resource_func = (params->resource_func &
112                                  ULP_FLOW_DB_RES_FUNC_LOWER_MASK);
113                 resource_info->resource_func_lower = resource_func;
114         }
115
116         /* Store the handle as 64bit only for EM table entries */
117         if (params->resource_func != BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE &&
118             params->resource_func != BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) {
119                 resource_info->resource_hndl = (uint32_t)params->resource_hndl;
120                 resource_info->resource_type = params->resource_type;
121                 resource_info->resource_sub_type = params->resource_sub_type;
122                 resource_info->reserved = params->reserved;
123         } else {
124                 resource_info->resource_em_handle = params->resource_hndl;
125         }
126 }
127
128 /*
129  * Helper function to copy the resource params to resource info
130  *  No validation being done in this function.
131  *
132  * resource_info [in] Ptr to resource information
133  * params [out] The output params to the caller
134  *
135  * returns none
136  */
137 static void
138 ulp_flow_db_res_info_to_params(struct ulp_fdb_resource_info *resource_info,
139                                struct ulp_flow_db_res_params *params)
140 {
141         memset(params, 0, sizeof(struct ulp_flow_db_res_params));
142         params->direction = ((resource_info->nxt_resource_idx &
143                                  ULP_FLOW_DB_RES_DIR_MASK) >>
144                                  ULP_FLOW_DB_RES_DIR_BIT);
145
146         /* use the helper function to get the resource func */
147         params->resource_func = ulp_flow_db_resource_func_get(resource_info);
148
149         if (params->resource_func == BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE ||
150             params->resource_func == BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) {
151                 params->resource_hndl = resource_info->resource_em_handle;
152         } else if (params->resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) {
153                 params->resource_hndl = resource_info->resource_hndl;
154                 params->resource_type = resource_info->resource_type;
155                 params->resource_sub_type = resource_info->resource_sub_type;
156                 params->reserved = resource_info->reserved;
157         }
158 }
159
160 /*
161  * Helper function to allocate the flow table and initialize
162  * the stack for allocation operations.
163  *
164  * flow_db [in] Ptr to flow database structure
165  * tbl_idx [in] The index to table creation.
166  *
167  * Returns 0 on success or negative number on failure.
168  */
169 static int32_t
170 ulp_flow_db_alloc_resource(struct bnxt_ulp_flow_db *flow_db,
171                            enum bnxt_ulp_flow_db_tables tbl_idx)
172 {
173         uint32_t                        idx = 0;
174         struct bnxt_ulp_flow_tbl        *flow_tbl;
175         uint32_t                        size;
176
177         flow_tbl = &flow_db->flow_tbl[tbl_idx];
178
179         size = sizeof(struct ulp_fdb_resource_info) * flow_tbl->num_resources;
180         flow_tbl->flow_resources =
181                         rte_zmalloc("ulp_fdb_resource_info", size, 0);
182
183         if (!flow_tbl->flow_resources) {
184                 BNXT_TF_DBG(ERR, "Failed to alloc memory for flow table\n");
185                 return -ENOMEM;
186         }
187         size = sizeof(uint32_t) * flow_tbl->num_resources;
188         flow_tbl->flow_tbl_stack = rte_zmalloc("flow_tbl_stack", size, 0);
189         if (!flow_tbl->flow_tbl_stack) {
190                 BNXT_TF_DBG(ERR, "Failed to alloc memory flow tbl stack\n");
191                 return -ENOMEM;
192         }
193         size = (flow_tbl->num_flows / sizeof(uint64_t)) + 1;
194         flow_tbl->active_flow_tbl = rte_zmalloc("active flow tbl", size, 0);
195         if (!flow_tbl->active_flow_tbl) {
196                 BNXT_TF_DBG(ERR, "Failed to alloc memory active tbl\n");
197                 return -ENOMEM;
198         }
199
200         /* Initialize the stack table. */
201         for (idx = 0; idx < flow_tbl->num_resources; idx++)
202                 flow_tbl->flow_tbl_stack[idx] = idx;
203
204         /* Ignore the first element in the list. */
205         flow_tbl->head_index = 1;
206         /* Tail points to the last entry in the list. */
207         flow_tbl->tail_index = flow_tbl->num_resources - 1;
208         return 0;
209 }
210
211 /*
212  * Helper function to deallocate the flow table.
213  *
214  * flow_db [in] Ptr to flow database structure
215  * tbl_idx [in] The index to table creation.
216  *
217  * Returns none.
218  */
219 static void
220 ulp_flow_db_dealloc_resource(struct bnxt_ulp_flow_db *flow_db,
221                              enum bnxt_ulp_flow_db_tables tbl_idx)
222 {
223         struct bnxt_ulp_flow_tbl        *flow_tbl;
224
225         flow_tbl = &flow_db->flow_tbl[tbl_idx];
226
227         /* Free all the allocated tables in the flow table. */
228         if (flow_tbl->active_flow_tbl) {
229                 rte_free(flow_tbl->active_flow_tbl);
230                 flow_tbl->active_flow_tbl = NULL;
231         }
232
233         if (flow_tbl->flow_tbl_stack) {
234                 rte_free(flow_tbl->flow_tbl_stack);
235                 flow_tbl->flow_tbl_stack = NULL;
236         }
237
238         if (flow_tbl->flow_resources) {
239                 rte_free(flow_tbl->flow_resources);
240                 flow_tbl->flow_resources = NULL;
241         }
242 }
243
244 /*
245  * Helper function to add function id to the flow table
246  *
247  * flow_db [in] Ptr to flow table
248  * flow_id [in] The flow id of the flow
249  * func_id [in] The func_id to be set, for reset pass zero
250  *
251  * returns none
252  */
253 static void
254 ulp_flow_db_func_id_set(struct bnxt_ulp_flow_db *flow_db,
255                         uint32_t flow_id,
256                         uint32_t func_id)
257 {
258         /* set the function id in the function table */
259         if (flow_id < flow_db->func_id_tbl_size)
260                 flow_db->func_id_tbl[flow_id] = func_id;
261         else /* This should never happen */
262                 BNXT_TF_DBG(ERR, "Invalid flow id, flowdb corrupt\n");
263 }
264
265 /*
266  * Initialize the flow database. Memory is allocated in this
267  * call and assigned to the flow database.
268  *
269  * ulp_ctxt [in] Ptr to ulp context
270  *
271  * Returns 0 on success or negative number on failure.
272  */
273 int32_t ulp_flow_db_init(struct bnxt_ulp_context *ulp_ctxt)
274 {
275         struct bnxt_ulp_device_params           *dparms;
276         struct bnxt_ulp_flow_tbl                *flow_tbl;
277         struct bnxt_ulp_flow_db                 *flow_db;
278         uint32_t                                dev_id;
279
280         /* Get the dev specific number of flows that needed to be supported. */
281         if (bnxt_ulp_cntxt_dev_id_get(ulp_ctxt, &dev_id)) {
282                 BNXT_TF_DBG(ERR, "Invalid device id\n");
283                 return -EINVAL;
284         }
285
286         dparms = bnxt_ulp_device_params_get(dev_id);
287         if (!dparms) {
288                 BNXT_TF_DBG(ERR, "could not fetch the device params\n");
289                 return -ENODEV;
290         }
291
292         flow_db = rte_zmalloc("bnxt_ulp_flow_db",
293                               sizeof(struct bnxt_ulp_flow_db), 0);
294         if (!flow_db) {
295                 BNXT_TF_DBG(ERR,
296                             "Failed to allocate memory for flow table ptr\n");
297                 return -ENOMEM;
298         }
299
300         /* Attach the flow database to the ulp context. */
301         bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, flow_db);
302
303         /* Populate the regular flow table limits. */
304         flow_tbl = &flow_db->flow_tbl[BNXT_ULP_REGULAR_FLOW_TABLE];
305         flow_tbl->num_flows = dparms->flow_db_num_entries + 1;
306         flow_tbl->num_resources = (flow_tbl->num_flows *
307                                    dparms->num_resources_per_flow);
308
309         /* Populate the default flow table limits. */
310         flow_tbl = &flow_db->flow_tbl[BNXT_ULP_DEFAULT_FLOW_TABLE];
311         flow_tbl->num_flows = BNXT_FLOW_DB_DEFAULT_NUM_FLOWS + 1;
312         flow_tbl->num_resources = (flow_tbl->num_flows *
313                                    BNXT_FLOW_DB_DEFAULT_NUM_RESOURCES);
314
315         /* Allocate the resource for the regular flow table. */
316         if (ulp_flow_db_alloc_resource(flow_db, BNXT_ULP_REGULAR_FLOW_TABLE))
317                 goto error_free;
318         if (ulp_flow_db_alloc_resource(flow_db, BNXT_ULP_DEFAULT_FLOW_TABLE))
319                 goto error_free;
320
321         /* add 1 since we are not using index 0 for flow id */
322         flow_db->func_id_tbl_size = dparms->flow_db_num_entries + 1;
323         /* Allocate the function Id table */
324         flow_db->func_id_tbl = rte_zmalloc("bnxt_ulp_flow_db_func_id_table",
325                                            flow_db->func_id_tbl_size *
326                                            sizeof(uint16_t), 0);
327         if (!flow_db->func_id_tbl) {
328                 BNXT_TF_DBG(ERR,
329                             "Failed to allocate mem for flow table func id\n");
330                 goto error_free;
331         }
332         /* All good so return. */
333         return 0;
334 error_free:
335         ulp_flow_db_deinit(ulp_ctxt);
336         return -ENOMEM;
337 }
338
339 /*
340  * Deinitialize the flow database. Memory is deallocated in
341  * this call and all flows should have been purged before this
342  * call.
343  *
344  * ulp_ctxt [in] Ptr to ulp context
345  *
346  * Returns 0 on success.
347  */
348 int32_t ulp_flow_db_deinit(struct bnxt_ulp_context *ulp_ctxt)
349 {
350         struct bnxt_ulp_flow_db                 *flow_db;
351
352         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
353         if (!flow_db) {
354                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
355                 return -EINVAL;
356         }
357
358         /* Detach the flow database from the ulp context. */
359         bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, NULL);
360
361         /* Free up all the memory. */
362         ulp_flow_db_dealloc_resource(flow_db, BNXT_ULP_REGULAR_FLOW_TABLE);
363         ulp_flow_db_dealloc_resource(flow_db, BNXT_ULP_DEFAULT_FLOW_TABLE);
364         rte_free(flow_db->func_id_tbl);
365         rte_free(flow_db);
366
367         return 0;
368 }
369
370 /*
371  * Allocate the flow database entry
372  *
373  * ulp_ctxt [in] Ptr to ulp_context
374  * tbl_idx [in] Specify it is regular or default flow
375  * fid [out] The index to the flow entry
376  *
377  * returns 0 on success and negative on failure.
378  */
379 int32_t ulp_flow_db_fid_alloc(struct bnxt_ulp_context *ulp_ctxt,
380                               enum bnxt_ulp_flow_db_tables tbl_idx,
381                               uint16_t func_id,
382                               uint32_t *fid)
383 {
384         struct bnxt_ulp_flow_db *flow_db;
385         struct bnxt_ulp_flow_tbl *flow_tbl;
386
387         *fid = 0; /* Initialize fid to invalid value */
388         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
389         if (!flow_db) {
390                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
391                 return -EINVAL;
392         }
393
394         flow_tbl = &flow_db->flow_tbl[tbl_idx];
395         /* check for max flows */
396         if (flow_tbl->num_flows <= flow_tbl->head_index) {
397                 BNXT_TF_DBG(ERR, "Flow database has reached max flows\n");
398                 return -ENOMEM;
399         }
400         if (flow_tbl->tail_index <= (flow_tbl->head_index + 1)) {
401                 BNXT_TF_DBG(ERR, "Flow database has reached max resources\n");
402                 return -ENOMEM;
403         }
404         *fid = flow_tbl->flow_tbl_stack[flow_tbl->head_index];
405         flow_tbl->head_index++;
406         ulp_flow_db_active_flow_set(flow_tbl, *fid, 1);
407
408         /* The function id update is only valid for regular flow table */
409         if (tbl_idx == BNXT_ULP_REGULAR_FLOW_TABLE)
410                 ulp_flow_db_func_id_set(flow_db, *fid, func_id);
411
412         /* all good, return success */
413         return 0;
414 }
415
416 /*
417  * Allocate the flow database entry.
418  * The params->critical_resource has to be set to 0 to allocate a new resource.
419  *
420  * ulp_ctxt [in] Ptr to ulp_context
421  * tbl_idx [in] Specify it is regular or default flow
422  * fid [in] The index to the flow entry
423  * params [in] The contents to be copied into resource
424  *
425  * returns 0 on success and negative on failure.
426  */
427 int32_t ulp_flow_db_resource_add(struct bnxt_ulp_context        *ulp_ctxt,
428                                  enum bnxt_ulp_flow_db_tables   tbl_idx,
429                                  uint32_t                       fid,
430                                  struct ulp_flow_db_res_params  *params)
431 {
432         struct bnxt_ulp_flow_db         *flow_db;
433         struct bnxt_ulp_flow_tbl        *flow_tbl;
434         struct ulp_fdb_resource_info    *resource, *fid_resource;
435         uint32_t                        idx;
436
437         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
438         if (!flow_db) {
439                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
440                 return -EINVAL;
441         }
442
443         if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) {
444                 BNXT_TF_DBG(ERR, "Invalid table index\n");
445                 return -EINVAL;
446         }
447         flow_tbl = &flow_db->flow_tbl[tbl_idx];
448
449         /* check for max flows */
450         if (fid >= flow_tbl->num_flows || !fid) {
451                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
452                 return -EINVAL;
453         }
454
455         /* check if the flow is active or not */
456         if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) {
457                 BNXT_TF_DBG(ERR, "flow does not exist\n");
458                 return -EINVAL;
459         }
460
461         /* check for max resource */
462         if ((flow_tbl->head_index + 1) >= flow_tbl->tail_index) {
463                 BNXT_TF_DBG(ERR, "Flow db has reached max resources\n");
464                 return -ENOMEM;
465         }
466         fid_resource = &flow_tbl->flow_resources[fid];
467
468         if (!params->critical_resource) {
469                 /* Not the critical_resource so allocate a resource */
470                 idx = flow_tbl->flow_tbl_stack[flow_tbl->tail_index];
471                 resource = &flow_tbl->flow_resources[idx];
472                 flow_tbl->tail_index--;
473
474                 /* Update the chain list of resource*/
475                 ULP_FLOW_DB_RES_NXT_SET(resource->nxt_resource_idx,
476                                         fid_resource->nxt_resource_idx);
477                 /* update the contents */
478                 ulp_flow_db_res_params_to_info(resource, params);
479                 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx);
480                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
481                                         idx);
482         } else {
483                 /* critical resource. Just update the fid resource */
484                 ulp_flow_db_res_params_to_info(fid_resource, params);
485         }
486
487         /* all good, return success */
488         return 0;
489 }
490
491 /*
492  * Free the flow database entry.
493  * The params->critical_resource has to be set to 1 to free the first resource.
494  *
495  * ulp_ctxt [in] Ptr to ulp_context
496  * tbl_idx [in] Specify it is regular or default flow
497  * fid [in] The index to the flow entry
498  * params [in/out] The contents to be copied into params.
499  * Onlythe critical_resource needs to be set by the caller.
500  *
501  * Returns 0 on success and negative on failure.
502  */
503 int32_t ulp_flow_db_resource_del(struct bnxt_ulp_context        *ulp_ctxt,
504                                  enum bnxt_ulp_flow_db_tables   tbl_idx,
505                                  uint32_t                       fid,
506                                  struct ulp_flow_db_res_params  *params)
507 {
508         struct bnxt_ulp_flow_db         *flow_db;
509         struct bnxt_ulp_flow_tbl        *flow_tbl;
510         struct ulp_fdb_resource_info    *nxt_resource, *fid_resource;
511         uint32_t                        nxt_idx = 0;
512
513         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
514         if (!flow_db) {
515                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
516                 return -EINVAL;
517         }
518
519         if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) {
520                 BNXT_TF_DBG(ERR, "Invalid table index\n");
521                 return -EINVAL;
522         }
523         flow_tbl = &flow_db->flow_tbl[tbl_idx];
524
525         /* check for max flows */
526         if (fid >= flow_tbl->num_flows || !fid) {
527                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
528                 return -EINVAL;
529         }
530
531         /* check if the flow is active or not */
532         if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) {
533                 BNXT_TF_DBG(ERR, "flow does not exist\n");
534                 return -EINVAL;
535         }
536
537         fid_resource = &flow_tbl->flow_resources[fid];
538         if (!params->critical_resource) {
539                 /* Not the critical resource so free the resource */
540                 ULP_FLOW_DB_RES_NXT_SET(nxt_idx,
541                                         fid_resource->nxt_resource_idx);
542                 if (!nxt_idx) {
543                         /* reached end of resources */
544                         return -ENOENT;
545                 }
546                 nxt_resource = &flow_tbl->flow_resources[nxt_idx];
547
548                 /* connect the fid resource to the next resource */
549                 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx);
550                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
551                                         nxt_resource->nxt_resource_idx);
552
553                 /* update the contents to be given to caller */
554                 ulp_flow_db_res_info_to_params(nxt_resource, params);
555
556                 /* Delete the nxt_resource */
557                 memset(nxt_resource, 0, sizeof(struct ulp_fdb_resource_info));
558
559                 /* add it to the free list */
560                 flow_tbl->tail_index++;
561                 if (flow_tbl->tail_index >= flow_tbl->num_resources) {
562                         BNXT_TF_DBG(ERR, "FlowDB:Tail reached max\n");
563                         return -ENOENT;
564                 }
565                 flow_tbl->flow_tbl_stack[flow_tbl->tail_index] = nxt_idx;
566
567         } else {
568                 /* Critical resource. copy the contents and exit */
569                 ulp_flow_db_res_info_to_params(fid_resource, params);
570                 ULP_FLOW_DB_RES_NXT_SET(nxt_idx,
571                                         fid_resource->nxt_resource_idx);
572                 memset(fid_resource, 0, sizeof(struct ulp_fdb_resource_info));
573                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
574                                         nxt_idx);
575         }
576
577         /* all good, return success */
578         return 0;
579 }
580
581 /*
582  * Free the flow database entry
583  *
584  * ulp_ctxt [in] Ptr to ulp_context
585  * tbl_idx [in] Specify it is regular or default flow
586  * fid [in] The index to the flow entry
587  *
588  * returns 0 on success and negative on failure.
589  */
590 int32_t ulp_flow_db_fid_free(struct bnxt_ulp_context            *ulp_ctxt,
591                              enum bnxt_ulp_flow_db_tables       tbl_idx,
592                              uint32_t                           fid)
593 {
594         struct bnxt_ulp_flow_db         *flow_db;
595         struct bnxt_ulp_flow_tbl        *flow_tbl;
596
597         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
598         if (!flow_db) {
599                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
600                 return -EINVAL;
601         }
602
603         if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) {
604                 BNXT_TF_DBG(ERR, "Invalid table index\n");
605                 return -EINVAL;
606         }
607
608         flow_tbl = &flow_db->flow_tbl[tbl_idx];
609
610         /* check for limits of fid */
611         if (fid >= flow_tbl->num_flows || !fid) {
612                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
613                 return -EINVAL;
614         }
615
616         /* check if the flow is active or not */
617         if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) {
618                 BNXT_TF_DBG(ERR, "flow does not exist\n");
619                 return -EINVAL;
620         }
621         flow_tbl->head_index--;
622         if (!flow_tbl->head_index) {
623                 BNXT_TF_DBG(ERR, "FlowDB: Head Ptr is zero\n");
624                 return -ENOENT;
625         }
626         flow_tbl->flow_tbl_stack[flow_tbl->head_index] = fid;
627         ulp_flow_db_active_flow_set(flow_tbl, fid, 0);
628         if (tbl_idx == BNXT_ULP_REGULAR_FLOW_TABLE)
629                 ulp_flow_db_func_id_set(flow_db, fid, 0);
630
631         /* all good, return success */
632         return 0;
633 }
634
635 /*
636  * Get the flow database entry details
637  *
638  * ulp_ctxt [in] Ptr to ulp_context
639  * tbl_idx [in] Specify it is regular or default flow
640  * fid [in] The index to the flow entry
641  * nxt_idx [in/out] the index to the next entry
642  * params [out] The contents to be copied into params.
643  *
644  * returns 0 on success and negative on failure.
645  */
646 int32_t ulp_flow_db_resource_get(struct bnxt_ulp_context        *ulp_ctxt,
647                                  enum bnxt_ulp_flow_db_tables   tbl_idx,
648                                  uint32_t                       fid,
649                                  uint32_t                       *nxt_idx,
650                                  struct ulp_flow_db_res_params  *params)
651 {
652         struct bnxt_ulp_flow_db         *flow_db;
653         struct bnxt_ulp_flow_tbl        *flow_tbl;
654         struct ulp_fdb_resource_info    *nxt_resource, *fid_resource;
655
656         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
657         if (!flow_db) {
658                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
659                 return -EINVAL;
660         }
661
662         if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) {
663                 BNXT_TF_DBG(ERR, "Invalid table index\n");
664                 return -EINVAL;
665         }
666
667         flow_tbl = &flow_db->flow_tbl[tbl_idx];
668
669         /* check for limits of fid */
670         if (fid >= flow_tbl->num_flows || !fid) {
671                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
672                 return -EINVAL;
673         }
674
675         /* check if the flow is active or not */
676         if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) {
677                 BNXT_TF_DBG(ERR, "flow does not exist\n");
678                 return -EINVAL;
679         }
680
681         if (!*nxt_idx) {
682                 fid_resource = &flow_tbl->flow_resources[fid];
683                 ulp_flow_db_res_info_to_params(fid_resource, params);
684                 ULP_FLOW_DB_RES_NXT_SET(*nxt_idx,
685                                         fid_resource->nxt_resource_idx);
686         } else {
687                 nxt_resource = &flow_tbl->flow_resources[*nxt_idx];
688                 ulp_flow_db_res_info_to_params(nxt_resource, params);
689                 *nxt_idx = 0;
690                 ULP_FLOW_DB_RES_NXT_SET(*nxt_idx,
691                                         nxt_resource->nxt_resource_idx);
692         }
693
694         /* all good, return success */
695         return 0;
696 }
697
698 /*
699  * Get the flow database entry iteratively
700  *
701  * flow_tbl [in] Ptr to flow table
702  * fid [in/out] The index to the flow entry
703  *
704  * returns 0 on success and negative on failure.
705  */
706 static int32_t
707 ulp_flow_db_next_entry_get(struct bnxt_ulp_flow_tbl     *flowtbl,
708                            uint32_t                     *fid)
709 {
710         uint32_t        lfid = *fid;
711         uint32_t        idx, s_idx, mod_fid;
712         uint64_t        bs;
713
714         do {
715                 /* increment the flow id to find the next valid flow id */
716                 lfid++;
717                 if (lfid >= flowtbl->num_flows)
718                         return -ENOENT;
719                 idx = lfid / ULP_INDEX_BITMAP_SIZE;
720                 mod_fid = lfid % ULP_INDEX_BITMAP_SIZE;
721                 s_idx = idx;
722                 while (!(bs = flowtbl->active_flow_tbl[idx])) {
723                         idx++;
724                         if ((idx * ULP_INDEX_BITMAP_SIZE) >= flowtbl->num_flows)
725                                 return -ENOENT;
726                 }
727                 /*
728                  * remove the previous bits in the bitset bs to find the
729                  * next non zero bit in the bitset. This needs to be done
730                  * only if the idx is same as he one you started.
731                  */
732                 if (s_idx == idx)
733                         bs &= (-1UL >> mod_fid);
734                 lfid = (idx * ULP_INDEX_BITMAP_SIZE) + __builtin_clzl(bs);
735                 if (*fid >= lfid) {
736                         BNXT_TF_DBG(ERR, "Flow Database is corrupt\n");
737                         return -ENOENT;
738                 }
739         } while (!ulp_flow_db_active_flow_is_set(flowtbl, lfid));
740
741         /* all good, return success */
742         *fid = lfid;
743         return 0;
744 }
745
746 /*
747  * Flush all flows in the flow database.
748  *
749  * ulp_ctxt [in] Ptr to ulp context
750  * tbl_idx [in] The index to table
751  *
752  * returns 0 on success or negative number on failure
753  */
754 int32_t ulp_flow_db_flush_flows(struct bnxt_ulp_context *ulp_ctx,
755                                 uint32_t                idx)
756 {
757         uint32_t                        fid = 0;
758         struct bnxt_ulp_flow_db         *flow_db;
759         struct bnxt_ulp_flow_tbl        *flow_tbl;
760
761         if (!ulp_ctx) {
762                 BNXT_TF_DBG(ERR, "Invalid Argument\n");
763                 return -EINVAL;
764         }
765
766         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
767         if (!flow_db) {
768                 BNXT_TF_DBG(ERR, "Flow database not found\n");
769                 return -EINVAL;
770         }
771         flow_tbl = &flow_db->flow_tbl[idx];
772         while (!ulp_flow_db_next_entry_get(flow_tbl, &fid))
773                 ulp_mapper_resources_free(ulp_ctx, fid, idx);
774
775         return 0;
776 }
777
778 /*
779  * Flush all flows in the flow database that belong to a device function.
780  *
781  * ulp_ctxt [in] Ptr to ulp context
782  * tbl_idx [in] The index to table
783  *
784  * returns 0 on success or negative number on failure
785  */
786 int32_t
787 ulp_flow_db_function_flow_flush(struct bnxt_ulp_context *ulp_ctx,
788                                 uint16_t func_id)
789 {
790         uint32_t flow_id = 0;
791         struct bnxt_ulp_flow_db *flow_db;
792         struct bnxt_ulp_flow_tbl *flow_tbl;
793
794         if (!ulp_ctx || !func_id) {
795                 BNXT_TF_DBG(ERR, "Invalid Argument\n");
796                 return -EINVAL;
797         }
798
799         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
800         if (!flow_db) {
801                 BNXT_TF_DBG(ERR, "Flow database not found\n");
802                 return -EINVAL;
803         }
804         flow_tbl = &flow_db->flow_tbl[BNXT_ULP_REGULAR_FLOW_TABLE];
805         while (!ulp_flow_db_next_entry_get(flow_tbl, &flow_id)) {
806                 if (flow_db->func_id_tbl[flow_id] == func_id)
807                         ulp_mapper_resources_free(ulp_ctx, flow_id,
808                                                   BNXT_ULP_REGULAR_FLOW_TABLE);
809         }
810
811         return 0;
812 }
813
814 /*
815  * Flush all flows in the flow database that are associated with the session.
816  *
817  * ulp_ctxt [in] Ptr to ulp context
818  *
819  * returns 0 on success or negative number on failure
820  */
821 int32_t
822 ulp_flow_db_session_flow_flush(struct bnxt_ulp_context *ulp_ctx)
823 {
824         /*
825          * TBD: Tf core implementation of FW session flush shall change this
826          * implementation.
827          */
828         return ulp_flow_db_flush_flows(ulp_ctx, BNXT_ULP_REGULAR_FLOW_TABLE);
829 }
830
831 /*
832  * Check that flow id matches the function id or not
833  *
834  * ulp_ctxt [in] Ptr to ulp context
835  * flow_db [in] Ptr to flow table
836  * func_id [in] The func_id to be set, for reset pass zero.
837  *
838  * returns true on success or false on failure
839  */
840 bool
841 ulp_flow_db_validate_flow_func(struct bnxt_ulp_context *ulp_ctx,
842                                uint32_t flow_id,
843                                uint32_t func_id)
844 {
845         struct bnxt_ulp_flow_db *flow_db;
846
847         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
848         if (!flow_db) {
849                 BNXT_TF_DBG(ERR, "Flow database not found\n");
850                 return false;
851         }
852
853         /* set the function id in the function table */
854         if (flow_id < flow_db->func_id_tbl_size && func_id &&
855             flow_db->func_id_tbl[flow_id] == func_id)
856                 return true;
857
858         return false;
859 }
860
861 /*
862  * Internal api to traverse the resource list within a flow
863  * and match a resource based on resource func and resource
864  * sub type. This api should be used only for resources that
865  * are unique and do not have multiple instances of resource
866  * func and sub type combination since it will return only
867  * the first match.
868  */
869 static int32_t
870 ulp_flow_db_resource_hndl_get(struct bnxt_ulp_context *ulp_ctx,
871                               enum bnxt_ulp_flow_db_tables tbl_idx,
872                               uint32_t flow_id,
873                               uint32_t resource_func,
874                               uint32_t res_subtype,
875                               uint64_t *res_hndl)
876 {
877         struct bnxt_ulp_flow_db *flow_db;
878         struct bnxt_ulp_flow_tbl *flow_tbl;
879         struct ulp_fdb_resource_info *fid_res;
880         uint32_t res_id;
881
882         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
883         if (!flow_db) {
884                 BNXT_TF_DBG(ERR, "Flow database not found\n");
885                 return -EINVAL;
886         }
887
888         flow_tbl = &flow_db->flow_tbl[tbl_idx];
889
890         /* check for limits of fid */
891         if (flow_id >= flow_tbl->num_flows || !flow_id) {
892                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
893                 return -EINVAL;
894         }
895
896         /* check if the flow is active or not */
897         if (!ulp_flow_db_active_flow_is_set(flow_tbl, flow_id)) {
898                 BNXT_TF_DBG(ERR, "flow does not exist\n");
899                 return -EINVAL;
900         }
901         /* Iterate the resource to get the resource handle */
902         res_id =  flow_id;
903         while (res_id) {
904                 fid_res = &flow_tbl->flow_resources[res_id];
905                 if (ulp_flow_db_resource_func_get(fid_res) == resource_func) {
906                         if (resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) {
907                                 if (res_subtype == fid_res->resource_sub_type) {
908                                         *res_hndl = fid_res->resource_hndl;
909                                         return 0;
910                                 }
911
912                         } else if (resource_func ==
913                                    BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE ||
914                                    resource_func ==
915                                    BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) {
916                                 *res_hndl = fid_res->resource_em_handle;
917                                 return 0;
918                         }
919                 }
920                 res_id = 0;
921                 ULP_FLOW_DB_RES_NXT_SET(res_id, fid_res->nxt_resource_idx);
922         }
923         return -ENOENT;
924 }
925
926 /*
927  * Api to get the cfa action pointer from a flow.
928  *
929  * ulp_ctxt [in] Ptr to ulp context
930  * flow_id [in] flow id
931  * cfa_action [out] The resource handle stored in the flow database
932  *
933  * returns 0 on success
934  */
935 int32_t
936 ulp_default_flow_db_cfa_action_get(struct bnxt_ulp_context *ulp_ctx,
937                                    uint32_t flow_id,
938                                    uint32_t *cfa_action)
939 {
940         uint8_t sub_type = BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_VFR_CFA_ACTION;
941         uint64_t hndl;
942         int32_t rc;
943
944         rc = ulp_flow_db_resource_hndl_get(ulp_ctx,
945                                            BNXT_ULP_DEFAULT_FLOW_TABLE,
946                                            flow_id,
947                                            BNXT_ULP_RESOURCE_FUNC_INDEX_TABLE,
948                                            sub_type, &hndl);
949         if (rc) {
950                 BNXT_TF_DBG(ERR, "CFA Action ptr not found for flow id %u\n",
951                             flow_id);
952                 return -ENOENT;
953         }
954         *cfa_action = hndl;
955         return 0;
956 }
957
958 #ifdef RTE_LIBRTE_BNXT_TRUFLOW_DEBUG
959 /*
960  * Dump the entry details
961  *
962  * ulp_ctxt [in] Ptr to ulp_context
963  *
964  * returns none
965  */
966 static void ulp_flow_db_res_dump(struct ulp_fdb_resource_info   *r,
967                                  uint32_t       *nxt_res)
968 {
969         uint8_t res_func = ulp_flow_db_resource_func_get(r);
970
971         BNXT_TF_DBG(DEBUG, "Resource func = %x, nxt_resource_idx = %x\n",
972                     res_func, (ULP_FLOW_DB_RES_NXT_MASK & r->nxt_resource_idx));
973         if (res_func == BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE ||
974             res_func == BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE)
975                 BNXT_TF_DBG(DEBUG, "EM Handle = 0x%016" PRIX64 "\n",
976                             r->resource_em_handle);
977         else
978                 BNXT_TF_DBG(DEBUG, "Handle = 0x%08x\n", r->resource_hndl);
979
980         *nxt_res = 0;
981         ULP_FLOW_DB_RES_NXT_SET(*nxt_res,
982                                 r->nxt_resource_idx);
983 }
984
985 /*
986  * Dump the flow database entry details
987  *
988  * ulp_ctxt [in] Ptr to ulp_context
989  *
990  * returns none
991  */
992 int32_t ulp_flow_db_debug_dump(struct bnxt_ulp_context  *ulp_ctxt)
993 {
994         struct bnxt_ulp_flow_db         *flow_db;
995         struct bnxt_ulp_flow_tbl        *flow_tbl;
996         struct ulp_fdb_resource_info    *r;
997         uint32_t                        nxt_res = 0;
998         enum bnxt_ulp_flow_db_tables    tbl_idx;
999         uint32_t                        fid;
1000
1001         if (!ulp_ctxt || !ulp_ctxt->cfg_data) {
1002                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
1003                 return -EINVAL;
1004         }
1005         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
1006         if (!flow_db) {
1007                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
1008                 return -EINVAL;
1009         }
1010
1011         for (tbl_idx = 0; tbl_idx < BNXT_ULP_FLOW_TABLE_MAX; tbl_idx++) {
1012                 flow_tbl = &flow_db->flow_tbl[tbl_idx];
1013                 BNXT_TF_DBG(DEBUG, "Dump Tbl index = %u, flows = %u:%u\n",
1014                             tbl_idx, flow_tbl->num_flows,
1015                             flow_tbl->num_resources);
1016                 BNXT_TF_DBG(DEBUG, "Head_index = %u, Tail_index = %u\n",
1017                             flow_tbl->head_index, flow_tbl->tail_index);
1018                 for (fid = 0; fid < flow_tbl->num_flows; fid++) {
1019                         if (ulp_flow_db_active_flow_is_set(flow_tbl, fid)) {
1020                                 BNXT_TF_DBG(DEBUG, "fid = %u\n", fid);
1021                                 /* iterate the resource */
1022                                 nxt_res = fid;
1023                                 do {
1024                                         r = &flow_tbl->flow_resources[nxt_res];
1025                                         ulp_flow_db_res_dump(r, &nxt_res);
1026                                 } while (nxt_res);
1027                         }
1028                 }
1029                 BNXT_TF_DBG(DEBUG, "Done.\n");
1030         }
1031         return 0;
1032 }
1033 #endif