30a809a8d05a4fa92ae3bafe545a84896cbf59d2
[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 /*
75  * Helper function to copy the resource params to resource info
76  *  No validation being done in this function.
77  *
78  * resource_info [out] Ptr to resource information
79  * params [in] The input params from the caller
80  * returns none
81  */
82 static void
83 ulp_flow_db_res_params_to_info(struct ulp_fdb_resource_info *resource_info,
84                                struct ulp_flow_db_res_params *params)
85 {
86         uint32_t resource_func;
87
88         resource_info->nxt_resource_idx |= ((params->direction <<
89                                       ULP_FLOW_DB_RES_DIR_BIT) &
90                                      ULP_FLOW_DB_RES_DIR_MASK);
91         resource_func = (params->resource_func >> ULP_FLOW_DB_RES_FUNC_UPPER);
92         resource_info->nxt_resource_idx |= ((resource_func <<
93                                              ULP_FLOW_DB_RES_FUNC_BITS) &
94                                             ULP_FLOW_DB_RES_FUNC_MASK);
95
96         if (params->resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) {
97                 /* Break the resource func into two parts */
98                 resource_func = (params->resource_func &
99                                  ULP_FLOW_DB_RES_FUNC_LOWER_MASK);
100                 resource_info->resource_func_lower = resource_func;
101         }
102
103         /* Store the handle as 64bit only for EM table entries */
104         if (params->resource_func != BNXT_ULP_RESOURCE_FUNC_EM_TABLE) {
105                 resource_info->resource_hndl = (uint32_t)params->resource_hndl;
106                 resource_info->resource_type = params->resource_type;
107                 resource_info->resource_sub_type = params->resource_sub_type;
108                 resource_info->reserved = params->reserved;
109         } else {
110                 resource_info->resource_em_handle = params->resource_hndl;
111         }
112 }
113
114 /*
115  * Helper function to copy the resource params to resource info
116  *  No validation being done in this function.
117  *
118  * resource_info [in] Ptr to resource information
119  * params [out] The output params to the caller
120  *
121  * returns none
122  */
123 static void
124 ulp_flow_db_res_info_to_params(struct ulp_fdb_resource_info *resource_info,
125                                struct ulp_flow_db_res_params *params)
126 {
127         uint8_t resource_func_upper;
128
129         memset(params, 0, sizeof(struct ulp_flow_db_res_params));
130         params->direction = ((resource_info->nxt_resource_idx &
131                                  ULP_FLOW_DB_RES_DIR_MASK) >>
132                                  ULP_FLOW_DB_RES_DIR_BIT);
133         resource_func_upper = (((resource_info->nxt_resource_idx &
134                                 ULP_FLOW_DB_RES_FUNC_MASK) >>
135                                ULP_FLOW_DB_RES_FUNC_BITS) <<
136                                ULP_FLOW_DB_RES_FUNC_UPPER);
137
138         /* The reource func is split into upper and lower */
139         if (resource_func_upper & ULP_FLOW_DB_RES_FUNC_NEED_LOWER)
140                 params->resource_func = (resource_func_upper |
141                                          resource_info->resource_func_lower);
142         else
143                 params->resource_func = resource_func_upper;
144
145         if (params->resource_func == BNXT_ULP_RESOURCE_FUNC_EM_TABLE) {
146                 params->resource_hndl = resource_info->resource_em_handle;
147         } else if (params->resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) {
148                 params->resource_hndl = resource_info->resource_hndl;
149                 params->resource_type = resource_info->resource_type;
150                 params->resource_sub_type = resource_info->resource_sub_type;
151                 params->reserved = resource_info->reserved;
152         }
153 }
154
155 /*
156  * Helper function to allocate the flow table and initialize
157  * the stack for allocation operations.
158  *
159  * flow_db [in] Ptr to flow database structure
160  * tbl_idx [in] The index to table creation.
161  *
162  * Returns 0 on success or negative number on failure.
163  */
164 static int32_t
165 ulp_flow_db_alloc_resource(struct bnxt_ulp_flow_db *flow_db,
166                            enum bnxt_ulp_flow_db_tables tbl_idx)
167 {
168         uint32_t                        idx = 0;
169         struct bnxt_ulp_flow_tbl        *flow_tbl;
170         uint32_t                        size;
171
172         flow_tbl = &flow_db->flow_tbl[tbl_idx];
173
174         size = sizeof(struct ulp_fdb_resource_info) * flow_tbl->num_resources;
175         flow_tbl->flow_resources =
176                         rte_zmalloc("ulp_fdb_resource_info", size, 0);
177
178         if (!flow_tbl->flow_resources) {
179                 BNXT_TF_DBG(ERR, "Failed to alloc memory for flow table\n");
180                 return -ENOMEM;
181         }
182         size = sizeof(uint32_t) * flow_tbl->num_resources;
183         flow_tbl->flow_tbl_stack = rte_zmalloc("flow_tbl_stack", size, 0);
184         if (!flow_tbl->flow_tbl_stack) {
185                 BNXT_TF_DBG(ERR, "Failed to alloc memory flow tbl stack\n");
186                 return -ENOMEM;
187         }
188         size = (flow_tbl->num_flows / sizeof(uint64_t)) + 1;
189         flow_tbl->active_flow_tbl = rte_zmalloc("active flow tbl", size, 0);
190         if (!flow_tbl->active_flow_tbl) {
191                 BNXT_TF_DBG(ERR, "Failed to alloc memory active tbl\n");
192                 return -ENOMEM;
193         }
194
195         /* Initialize the stack table. */
196         for (idx = 0; idx < flow_tbl->num_resources; idx++)
197                 flow_tbl->flow_tbl_stack[idx] = idx;
198
199         /* Ignore the first element in the list. */
200         flow_tbl->head_index = 1;
201         /* Tail points to the last entry in the list. */
202         flow_tbl->tail_index = flow_tbl->num_resources - 1;
203         return 0;
204 }
205
206 /*
207  * Helper function to deallocate the flow table.
208  *
209  * flow_db [in] Ptr to flow database structure
210  * tbl_idx [in] The index to table creation.
211  *
212  * Returns none.
213  */
214 static void
215 ulp_flow_db_dealloc_resource(struct bnxt_ulp_flow_db *flow_db,
216                              enum bnxt_ulp_flow_db_tables tbl_idx)
217 {
218         struct bnxt_ulp_flow_tbl        *flow_tbl;
219
220         flow_tbl = &flow_db->flow_tbl[tbl_idx];
221
222         /* Free all the allocated tables in the flow table. */
223         if (flow_tbl->active_flow_tbl) {
224                 rte_free(flow_tbl->active_flow_tbl);
225                 flow_tbl->active_flow_tbl = NULL;
226         }
227
228         if (flow_tbl->flow_tbl_stack) {
229                 rte_free(flow_tbl->flow_tbl_stack);
230                 flow_tbl->flow_tbl_stack = NULL;
231         }
232
233         if (flow_tbl->flow_resources) {
234                 rte_free(flow_tbl->flow_resources);
235                 flow_tbl->flow_resources = NULL;
236         }
237 }
238
239 /*
240  * Helper function to add function id to the flow table
241  *
242  * flow_db [in] Ptr to flow table
243  * flow_id [in] The flow id of the flow
244  * func_id [in] The func_id to be set, for reset pass zero
245  *
246  * returns none
247  */
248 static void
249 ulp_flow_db_func_id_set(struct bnxt_ulp_flow_db *flow_db,
250                         uint32_t flow_id,
251                         uint32_t func_id)
252 {
253         /* set the function id in the function table */
254         if (flow_id < flow_db->func_id_tbl_size)
255                 flow_db->func_id_tbl[flow_id] = func_id;
256         else /* This should never happen */
257                 BNXT_TF_DBG(ERR, "Invalid flow id, flowdb corrupt\n");
258 }
259
260 /*
261  * Initialize the flow database. Memory is allocated in this
262  * call and assigned to the flow database.
263  *
264  * ulp_ctxt [in] Ptr to ulp context
265  *
266  * Returns 0 on success or negative number on failure.
267  */
268 int32_t ulp_flow_db_init(struct bnxt_ulp_context *ulp_ctxt)
269 {
270         struct bnxt_ulp_device_params           *dparms;
271         struct bnxt_ulp_flow_tbl                *flow_tbl;
272         struct bnxt_ulp_flow_db                 *flow_db;
273         uint32_t                                dev_id;
274
275         /* Get the dev specific number of flows that needed to be supported. */
276         if (bnxt_ulp_cntxt_dev_id_get(ulp_ctxt, &dev_id)) {
277                 BNXT_TF_DBG(ERR, "Invalid device id\n");
278                 return -EINVAL;
279         }
280
281         dparms = bnxt_ulp_device_params_get(dev_id);
282         if (!dparms) {
283                 BNXT_TF_DBG(ERR, "could not fetch the device params\n");
284                 return -ENODEV;
285         }
286
287         flow_db = rte_zmalloc("bnxt_ulp_flow_db",
288                               sizeof(struct bnxt_ulp_flow_db), 0);
289         if (!flow_db) {
290                 BNXT_TF_DBG(ERR,
291                             "Failed to allocate memory for flow table ptr\n");
292                 return -ENOMEM;
293         }
294
295         /* Attach the flow database to the ulp context. */
296         bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, flow_db);
297
298         /* Populate the regular flow table limits. */
299         flow_tbl = &flow_db->flow_tbl[BNXT_ULP_REGULAR_FLOW_TABLE];
300         flow_tbl->num_flows = dparms->num_flows + 1;
301         flow_tbl->num_resources = (flow_tbl->num_flows *
302                                    dparms->num_resources_per_flow);
303
304         /* Populate the default flow table limits. */
305         flow_tbl = &flow_db->flow_tbl[BNXT_ULP_DEFAULT_FLOW_TABLE];
306         flow_tbl->num_flows = BNXT_FLOW_DB_DEFAULT_NUM_FLOWS + 1;
307         flow_tbl->num_resources = (flow_tbl->num_flows *
308                                    BNXT_FLOW_DB_DEFAULT_NUM_RESOURCES);
309
310         /* Allocate the resource for the regular flow table. */
311         if (ulp_flow_db_alloc_resource(flow_db, BNXT_ULP_REGULAR_FLOW_TABLE))
312                 goto error_free;
313         if (ulp_flow_db_alloc_resource(flow_db, BNXT_ULP_DEFAULT_FLOW_TABLE))
314                 goto error_free;
315
316         /* add 1 since we are not using index 0 for flow id */
317         flow_db->func_id_tbl_size = dparms->num_flows + 1;
318         /* Allocate the function Id table */
319         flow_db->func_id_tbl = rte_zmalloc("bnxt_ulp_flow_db_func_id_table",
320                                            flow_db->func_id_tbl_size *
321                                            sizeof(uint16_t), 0);
322         if (!flow_db->func_id_tbl) {
323                 BNXT_TF_DBG(ERR,
324                             "Failed to allocate mem for flow table func id\n");
325                 goto error_free;
326         }
327         /* All good so return. */
328         return 0;
329 error_free:
330         ulp_flow_db_deinit(ulp_ctxt);
331         return -ENOMEM;
332 }
333
334 /*
335  * Deinitialize the flow database. Memory is deallocated in
336  * this call and all flows should have been purged before this
337  * call.
338  *
339  * ulp_ctxt [in] Ptr to ulp context
340  *
341  * Returns 0 on success.
342  */
343 int32_t ulp_flow_db_deinit(struct bnxt_ulp_context *ulp_ctxt)
344 {
345         struct bnxt_ulp_flow_db                 *flow_db;
346
347         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
348         if (!flow_db) {
349                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
350                 return -EINVAL;
351         }
352
353         /* Detach the flow database from the ulp context. */
354         bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, NULL);
355
356         /* Free up all the memory. */
357         ulp_flow_db_dealloc_resource(flow_db, BNXT_ULP_REGULAR_FLOW_TABLE);
358         ulp_flow_db_dealloc_resource(flow_db, BNXT_ULP_DEFAULT_FLOW_TABLE);
359         rte_free(flow_db->func_id_tbl);
360         rte_free(flow_db);
361
362         return 0;
363 }
364
365 /*
366  * Allocate the flow database entry
367  *
368  * ulp_ctxt [in] Ptr to ulp_context
369  * tbl_idx [in] Specify it is regular or default flow
370  * fid [out] The index to the flow entry
371  *
372  * returns 0 on success and negative on failure.
373  */
374 int32_t ulp_flow_db_fid_alloc(struct bnxt_ulp_context *ulp_ctxt,
375                               enum bnxt_ulp_flow_db_tables tbl_idx,
376                               uint16_t func_id,
377                               uint32_t *fid)
378 {
379         struct bnxt_ulp_flow_db *flow_db;
380         struct bnxt_ulp_flow_tbl *flow_tbl;
381
382         *fid = 0; /* Initialize fid to invalid value */
383         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
384         if (!flow_db) {
385                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
386                 return -EINVAL;
387         }
388
389         flow_tbl = &flow_db->flow_tbl[tbl_idx];
390         /* check for max flows */
391         if (flow_tbl->num_flows <= flow_tbl->head_index) {
392                 BNXT_TF_DBG(ERR, "Flow database has reached max flows\n");
393                 return -ENOMEM;
394         }
395         if (flow_tbl->tail_index <= (flow_tbl->head_index + 1)) {
396                 BNXT_TF_DBG(ERR, "Flow database has reached max resources\n");
397                 return -ENOMEM;
398         }
399         *fid = flow_tbl->flow_tbl_stack[flow_tbl->head_index];
400         flow_tbl->head_index++;
401         ulp_flow_db_active_flow_set(flow_tbl, *fid, 1);
402
403         /* The function id update is only valid for regular flow table */
404         if (tbl_idx == BNXT_ULP_REGULAR_FLOW_TABLE)
405                 ulp_flow_db_func_id_set(flow_db, *fid, func_id);
406
407         /* all good, return success */
408         return 0;
409 }
410
411 /*
412  * Allocate the flow database entry.
413  * The params->critical_resource has to be set to 0 to allocate a new resource.
414  *
415  * ulp_ctxt [in] Ptr to ulp_context
416  * tbl_idx [in] Specify it is regular or default flow
417  * fid [in] The index to the flow entry
418  * params [in] The contents to be copied into resource
419  *
420  * returns 0 on success and negative on failure.
421  */
422 int32_t ulp_flow_db_resource_add(struct bnxt_ulp_context        *ulp_ctxt,
423                                  enum bnxt_ulp_flow_db_tables   tbl_idx,
424                                  uint32_t                       fid,
425                                  struct ulp_flow_db_res_params  *params)
426 {
427         struct bnxt_ulp_flow_db         *flow_db;
428         struct bnxt_ulp_flow_tbl        *flow_tbl;
429         struct ulp_fdb_resource_info    *resource, *fid_resource;
430         uint32_t                        idx;
431
432         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
433         if (!flow_db) {
434                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
435                 return -EINVAL;
436         }
437
438         if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) {
439                 BNXT_TF_DBG(ERR, "Invalid table index\n");
440                 return -EINVAL;
441         }
442         flow_tbl = &flow_db->flow_tbl[tbl_idx];
443
444         /* check for max flows */
445         if (fid >= flow_tbl->num_flows || !fid) {
446                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
447                 return -EINVAL;
448         }
449
450         /* check if the flow is active or not */
451         if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) {
452                 BNXT_TF_DBG(ERR, "flow does not exist\n");
453                 return -EINVAL;
454         }
455
456         /* check for max resource */
457         if ((flow_tbl->head_index + 1) >= flow_tbl->tail_index) {
458                 BNXT_TF_DBG(ERR, "Flow db has reached max resources\n");
459                 return -ENOMEM;
460         }
461         fid_resource = &flow_tbl->flow_resources[fid];
462
463         if (!params->critical_resource) {
464                 /* Not the critical_resource so allocate a resource */
465                 idx = flow_tbl->flow_tbl_stack[flow_tbl->tail_index];
466                 resource = &flow_tbl->flow_resources[idx];
467                 flow_tbl->tail_index--;
468
469                 /* Update the chain list of resource*/
470                 ULP_FLOW_DB_RES_NXT_SET(resource->nxt_resource_idx,
471                                         fid_resource->nxt_resource_idx);
472                 /* update the contents */
473                 ulp_flow_db_res_params_to_info(resource, params);
474                 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx);
475                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
476                                         idx);
477         } else {
478                 /* critical resource. Just update the fid resource */
479                 ulp_flow_db_res_params_to_info(fid_resource, params);
480         }
481
482         /* all good, return success */
483         return 0;
484 }
485
486 /*
487  * Free the flow database entry.
488  * The params->critical_resource has to be set to 1 to free the first resource.
489  *
490  * ulp_ctxt [in] Ptr to ulp_context
491  * tbl_idx [in] Specify it is regular or default flow
492  * fid [in] The index to the flow entry
493  * params [in/out] The contents to be copied into params.
494  * Onlythe critical_resource needs to be set by the caller.
495  *
496  * Returns 0 on success and negative on failure.
497  */
498 int32_t ulp_flow_db_resource_del(struct bnxt_ulp_context        *ulp_ctxt,
499                                  enum bnxt_ulp_flow_db_tables   tbl_idx,
500                                  uint32_t                       fid,
501                                  struct ulp_flow_db_res_params  *params)
502 {
503         struct bnxt_ulp_flow_db         *flow_db;
504         struct bnxt_ulp_flow_tbl        *flow_tbl;
505         struct ulp_fdb_resource_info    *nxt_resource, *fid_resource;
506         uint32_t                        nxt_idx = 0;
507
508         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
509         if (!flow_db) {
510                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
511                 return -EINVAL;
512         }
513
514         if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) {
515                 BNXT_TF_DBG(ERR, "Invalid table index\n");
516                 return -EINVAL;
517         }
518         flow_tbl = &flow_db->flow_tbl[tbl_idx];
519
520         /* check for max flows */
521         if (fid >= flow_tbl->num_flows || !fid) {
522                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
523                 return -EINVAL;
524         }
525
526         /* check if the flow is active or not */
527         if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) {
528                 BNXT_TF_DBG(ERR, "flow does not exist\n");
529                 return -EINVAL;
530         }
531
532         fid_resource = &flow_tbl->flow_resources[fid];
533         if (!params->critical_resource) {
534                 /* Not the critical resource so free the resource */
535                 ULP_FLOW_DB_RES_NXT_SET(nxt_idx,
536                                         fid_resource->nxt_resource_idx);
537                 if (!nxt_idx) {
538                         /* reached end of resources */
539                         return -ENOENT;
540                 }
541                 nxt_resource = &flow_tbl->flow_resources[nxt_idx];
542
543                 /* connect the fid resource to the next resource */
544                 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx);
545                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
546                                         nxt_resource->nxt_resource_idx);
547
548                 /* update the contents to be given to caller */
549                 ulp_flow_db_res_info_to_params(nxt_resource, params);
550
551                 /* Delete the nxt_resource */
552                 memset(nxt_resource, 0, sizeof(struct ulp_fdb_resource_info));
553
554                 /* add it to the free list */
555                 flow_tbl->tail_index++;
556                 if (flow_tbl->tail_index >= flow_tbl->num_resources) {
557                         BNXT_TF_DBG(ERR, "FlowDB:Tail reached max\n");
558                         return -ENOENT;
559                 }
560                 flow_tbl->flow_tbl_stack[flow_tbl->tail_index] = nxt_idx;
561
562         } else {
563                 /* Critical resource. copy the contents and exit */
564                 ulp_flow_db_res_info_to_params(fid_resource, params);
565                 ULP_FLOW_DB_RES_NXT_SET(nxt_idx,
566                                         fid_resource->nxt_resource_idx);
567                 memset(fid_resource, 0, sizeof(struct ulp_fdb_resource_info));
568                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
569                                         nxt_idx);
570         }
571
572         /* all good, return success */
573         return 0;
574 }
575
576 /*
577  * Free the flow database entry
578  *
579  * ulp_ctxt [in] Ptr to ulp_context
580  * tbl_idx [in] Specify it is regular or default flow
581  * fid [in] The index to the flow entry
582  *
583  * returns 0 on success and negative on failure.
584  */
585 int32_t ulp_flow_db_fid_free(struct bnxt_ulp_context            *ulp_ctxt,
586                              enum bnxt_ulp_flow_db_tables       tbl_idx,
587                              uint32_t                           fid)
588 {
589         struct bnxt_ulp_flow_db         *flow_db;
590         struct bnxt_ulp_flow_tbl        *flow_tbl;
591
592         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
593         if (!flow_db) {
594                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
595                 return -EINVAL;
596         }
597
598         if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) {
599                 BNXT_TF_DBG(ERR, "Invalid table index\n");
600                 return -EINVAL;
601         }
602
603         flow_tbl = &flow_db->flow_tbl[tbl_idx];
604
605         /* check for limits of fid */
606         if (fid >= flow_tbl->num_flows || !fid) {
607                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
608                 return -EINVAL;
609         }
610
611         /* check if the flow is active or not */
612         if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) {
613                 BNXT_TF_DBG(ERR, "flow does not exist\n");
614                 return -EINVAL;
615         }
616         flow_tbl->head_index--;
617         if (!flow_tbl->head_index) {
618                 BNXT_TF_DBG(ERR, "FlowDB: Head Ptr is zero\n");
619                 return -ENOENT;
620         }
621         flow_tbl->flow_tbl_stack[flow_tbl->head_index] = fid;
622         ulp_flow_db_active_flow_set(flow_tbl, fid, 0);
623         if (tbl_idx == BNXT_ULP_REGULAR_FLOW_TABLE)
624                 ulp_flow_db_func_id_set(flow_db, fid, 0);
625
626         /* all good, return success */
627         return 0;
628 }
629
630 /*
631  * Get the flow database entry details
632  *
633  * ulp_ctxt [in] Ptr to ulp_context
634  * tbl_idx [in] Specify it is regular or default flow
635  * fid [in] The index to the flow entry
636  * nxt_idx [in/out] the index to the next entry
637  * params [out] The contents to be copied into params.
638  *
639  * returns 0 on success and negative on failure.
640  */
641 int32_t ulp_flow_db_resource_get(struct bnxt_ulp_context        *ulp_ctxt,
642                                  enum bnxt_ulp_flow_db_tables   tbl_idx,
643                                  uint32_t                       fid,
644                                  uint32_t                       *nxt_idx,
645                                  struct ulp_flow_db_res_params  *params)
646 {
647         struct bnxt_ulp_flow_db         *flow_db;
648         struct bnxt_ulp_flow_tbl        *flow_tbl;
649         struct ulp_fdb_resource_info    *nxt_resource, *fid_resource;
650
651         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
652         if (!flow_db) {
653                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
654                 return -EINVAL;
655         }
656
657         if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) {
658                 BNXT_TF_DBG(ERR, "Invalid table index\n");
659                 return -EINVAL;
660         }
661
662         flow_tbl = &flow_db->flow_tbl[tbl_idx];
663
664         /* check for limits of fid */
665         if (fid >= flow_tbl->num_flows || !fid) {
666                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
667                 return -EINVAL;
668         }
669
670         /* check if the flow is active or not */
671         if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) {
672                 BNXT_TF_DBG(ERR, "flow does not exist\n");
673                 return -EINVAL;
674         }
675
676         if (!*nxt_idx) {
677                 fid_resource = &flow_tbl->flow_resources[fid];
678                 ulp_flow_db_res_info_to_params(fid_resource, params);
679                 ULP_FLOW_DB_RES_NXT_SET(*nxt_idx,
680                                         fid_resource->nxt_resource_idx);
681         } else {
682                 nxt_resource = &flow_tbl->flow_resources[*nxt_idx];
683                 ulp_flow_db_res_info_to_params(nxt_resource, params);
684                 *nxt_idx = 0;
685                 ULP_FLOW_DB_RES_NXT_SET(*nxt_idx,
686                                         nxt_resource->nxt_resource_idx);
687         }
688
689         /* all good, return success */
690         return 0;
691 }
692
693 /*
694  * Get the flow database entry iteratively
695  *
696  * flow_tbl [in] Ptr to flow table
697  * fid [in/out] The index to the flow entry
698  *
699  * returns 0 on success and negative on failure.
700  */
701 static int32_t
702 ulp_flow_db_next_entry_get(struct bnxt_ulp_flow_tbl     *flowtbl,
703                            uint32_t                     *fid)
704 {
705         uint32_t        lfid = *fid;
706         uint32_t        idx, s_idx, mod_fid;
707         uint64_t        bs;
708
709         do {
710                 /* increment the flow id to find the next valid flow id */
711                 lfid++;
712                 if (lfid >= flowtbl->num_flows)
713                         return -ENOENT;
714                 idx = lfid / ULP_INDEX_BITMAP_SIZE;
715                 mod_fid = lfid % ULP_INDEX_BITMAP_SIZE;
716                 s_idx = idx;
717                 while (!(bs = flowtbl->active_flow_tbl[idx])) {
718                         idx++;
719                         if ((idx * ULP_INDEX_BITMAP_SIZE) >= flowtbl->num_flows)
720                                 return -ENOENT;
721                 }
722                 /*
723                  * remove the previous bits in the bitset bs to find the
724                  * next non zero bit in the bitset. This needs to be done
725                  * only if the idx is same as he one you started.
726                  */
727                 if (s_idx == idx)
728                         bs &= (-1UL >> mod_fid);
729                 lfid = (idx * ULP_INDEX_BITMAP_SIZE) + __builtin_clzl(bs);
730                 if (*fid >= lfid) {
731                         BNXT_TF_DBG(ERR, "Flow Database is corrupt\n");
732                         return -ENOENT;
733                 }
734         } while (!ulp_flow_db_active_flow_is_set(flowtbl, lfid));
735
736         /* all good, return success */
737         *fid = lfid;
738         return 0;
739 }
740
741 /*
742  * Flush all flows in the flow database.
743  *
744  * ulp_ctxt [in] Ptr to ulp context
745  * tbl_idx [in] The index to table
746  *
747  * returns 0 on success or negative number on failure
748  */
749 int32_t ulp_flow_db_flush_flows(struct bnxt_ulp_context *ulp_ctx,
750                                 uint32_t                idx)
751 {
752         uint32_t                        fid = 0;
753         struct bnxt_ulp_flow_db         *flow_db;
754         struct bnxt_ulp_flow_tbl        *flow_tbl;
755
756         if (!ulp_ctx) {
757                 BNXT_TF_DBG(ERR, "Invalid Argument\n");
758                 return -EINVAL;
759         }
760
761         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
762         if (!flow_db) {
763                 BNXT_TF_DBG(ERR, "Flow database not found\n");
764                 return -EINVAL;
765         }
766         flow_tbl = &flow_db->flow_tbl[idx];
767         while (!ulp_flow_db_next_entry_get(flow_tbl, &fid))
768                 ulp_mapper_resources_free(ulp_ctx, fid, idx);
769
770         return 0;
771 }
772
773 /*
774  * Flush all flows in the flow database that belong to a device function.
775  *
776  * ulp_ctxt [in] Ptr to ulp context
777  * tbl_idx [in] The index to table
778  *
779  * returns 0 on success or negative number on failure
780  */
781 int32_t
782 ulp_flow_db_function_flow_flush(struct bnxt_ulp_context *ulp_ctx,
783                                 uint16_t func_id)
784 {
785         uint32_t flow_id = 0;
786         struct bnxt_ulp_flow_db *flow_db;
787         struct bnxt_ulp_flow_tbl *flow_tbl;
788
789         if (!ulp_ctx || !func_id) {
790                 BNXT_TF_DBG(ERR, "Invalid Argument\n");
791                 return -EINVAL;
792         }
793
794         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
795         if (!flow_db) {
796                 BNXT_TF_DBG(ERR, "Flow database not found\n");
797                 return -EINVAL;
798         }
799         flow_tbl = &flow_db->flow_tbl[BNXT_ULP_REGULAR_FLOW_TABLE];
800         while (!ulp_flow_db_next_entry_get(flow_tbl, &flow_id)) {
801                 if (flow_db->func_id_tbl[flow_id] == func_id)
802                         ulp_mapper_resources_free(ulp_ctx, flow_id,
803                                                   BNXT_ULP_REGULAR_FLOW_TABLE);
804         }
805
806         return 0;
807 }
808
809 /*
810  * Flush all flows in the flow database that are associated with the session.
811  *
812  * ulp_ctxt [in] Ptr to ulp context
813  *
814  * returns 0 on success or negative number on failure
815  */
816 int32_t
817 ulp_flow_db_session_flow_flush(struct bnxt_ulp_context *ulp_ctx)
818 {
819         /*
820          * TBD: Tf core implementation of FW session flush shall change this
821          * implementation.
822          */
823         return ulp_flow_db_flush_flows(ulp_ctx, BNXT_ULP_REGULAR_FLOW_TABLE);
824 }
825
826 /*
827  * Check that flow id matches the function id or not
828  *
829  * ulp_ctxt [in] Ptr to ulp context
830  * flow_db [in] Ptr to flow table
831  * func_id [in] The func_id to be set, for reset pass zero.
832  *
833  * returns true on success or false on failure
834  */
835 bool
836 ulp_flow_db_validate_flow_func(struct bnxt_ulp_context *ulp_ctx,
837                                uint32_t flow_id,
838                                uint32_t func_id)
839 {
840         struct bnxt_ulp_flow_db *flow_db;
841
842         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
843         if (!flow_db) {
844                 BNXT_TF_DBG(ERR, "Flow database not found\n");
845                 return false;
846         }
847
848         /* set the function id in the function table */
849         if (flow_id < flow_db->func_id_tbl_size && func_id &&
850             flow_db->func_id_tbl[flow_id] == func_id)
851                 return true;
852
853         return false;
854 }