net/bnxt: consolidate template table processing
[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 #include "ulp_fc_mgr.h"
14
15 #define ULP_FLOW_DB_RES_DIR_BIT         31
16 #define ULP_FLOW_DB_RES_DIR_MASK        0x80000000
17 #define ULP_FLOW_DB_RES_FUNC_BITS       28
18 #define ULP_FLOW_DB_RES_FUNC_MASK       0x70000000
19 #define ULP_FLOW_DB_RES_NXT_MASK        0x0FFFFFFF
20 #define ULP_FLOW_DB_RES_FUNC_UPPER      5
21 #define ULP_FLOW_DB_RES_FUNC_NEED_LOWER 0x80
22 #define ULP_FLOW_DB_RES_FUNC_LOWER_MASK 0x1F
23
24 /* Macro to copy the nxt_resource_idx */
25 #define ULP_FLOW_DB_RES_NXT_SET(dst, src)       {(dst) |= ((src) &\
26                                          ULP_FLOW_DB_RES_NXT_MASK); }
27 #define ULP_FLOW_DB_RES_NXT_RESET(dst)  ((dst) &= ~(ULP_FLOW_DB_RES_NXT_MASK))
28
29 /*
30  * Helper function to set the bit in the active flows
31  * No validation is done in this function.
32  *
33  * flow_db [in] Ptr to flow database
34  * flow_type [in] - specify default or regular
35  * idx [in] The index to bit to be set or reset.
36  * flag [in] 1 to set and 0 to reset.
37  *
38  * returns none
39  */
40 static void
41 ulp_flow_db_active_flows_bit_set(struct bnxt_ulp_flow_db *flow_db,
42                                  enum bnxt_ulp_fdb_type flow_type,
43                                  uint32_t idx,
44                                  uint32_t flag)
45 {
46         struct bnxt_ulp_flow_tbl *f_tbl = &flow_db->flow_tbl;
47         uint32_t a_idx = idx / ULP_INDEX_BITMAP_SIZE;
48
49         if (flag) {
50                 if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR)
51                         ULP_INDEX_BITMAP_SET(f_tbl->active_reg_flows[a_idx],
52                                              idx);
53                 else
54                         ULP_INDEX_BITMAP_SET(f_tbl->active_dflt_flows[a_idx],
55                                              idx);
56         } else {
57                 if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR)
58                         ULP_INDEX_BITMAP_RESET(f_tbl->active_reg_flows[a_idx],
59                                              idx);
60                 else
61                         ULP_INDEX_BITMAP_RESET(f_tbl->active_dflt_flows[a_idx],
62                                              idx);
63         }
64 }
65
66 /*
67  * Helper function to check if given fid is active flow.
68  * No validation being done in this function.
69  *
70  * flow_db [in] Ptr to flow database
71  * flow_type [in] - specify default or regular
72  * idx [in] The index to bit to be set or reset.
73  *
74  * returns 1 on set or 0 if not set.
75  */
76 static int32_t
77 ulp_flow_db_active_flows_bit_is_set(struct bnxt_ulp_flow_db *flow_db,
78                                     enum bnxt_ulp_fdb_type flow_type,
79                                     uint32_t idx)
80 {
81         struct bnxt_ulp_flow_tbl *f_tbl = &flow_db->flow_tbl;
82         uint32_t a_idx = idx / ULP_INDEX_BITMAP_SIZE;
83
84         if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR)
85                 return ULP_INDEX_BITMAP_GET(f_tbl->active_reg_flows[a_idx],
86                                             idx);
87         else
88                 return ULP_INDEX_BITMAP_GET(f_tbl->active_dflt_flows[a_idx],
89                                             idx);
90 }
91
92 static uint8_t
93 ulp_flow_db_resource_func_get(struct ulp_fdb_resource_info *res_info)
94 {
95         uint8_t func;
96
97         func = (((res_info->nxt_resource_idx & ULP_FLOW_DB_RES_FUNC_MASK) >>
98                  ULP_FLOW_DB_RES_FUNC_BITS) << ULP_FLOW_DB_RES_FUNC_UPPER);
99         /* The reource func is split into upper and lower */
100         if (func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER)
101                 return (func | res_info->resource_func_lower);
102         return func;
103 }
104
105 /*
106  * Helper function to copy the resource params to resource info
107  *  No validation being done in this function.
108  *
109  * resource_info [out] Ptr to resource information
110  * params [in] The input params from the caller
111  * returns none
112  */
113 static void
114 ulp_flow_db_res_params_to_info(struct ulp_fdb_resource_info *resource_info,
115                                struct ulp_flow_db_res_params *params)
116 {
117         uint32_t resource_func;
118
119         resource_info->nxt_resource_idx |= ((params->direction <<
120                                       ULP_FLOW_DB_RES_DIR_BIT) &
121                                      ULP_FLOW_DB_RES_DIR_MASK);
122         resource_func = (params->resource_func >> ULP_FLOW_DB_RES_FUNC_UPPER);
123         resource_info->nxt_resource_idx |= ((resource_func <<
124                                              ULP_FLOW_DB_RES_FUNC_BITS) &
125                                             ULP_FLOW_DB_RES_FUNC_MASK);
126
127         if (params->resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) {
128                 /* Break the resource func into two parts */
129                 resource_func = (params->resource_func &
130                                  ULP_FLOW_DB_RES_FUNC_LOWER_MASK);
131                 resource_info->resource_func_lower = resource_func;
132         }
133
134         /* Store the handle as 64bit only for EM table entries */
135         if (params->resource_func != BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE &&
136             params->resource_func != BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) {
137                 resource_info->resource_hndl = (uint32_t)params->resource_hndl;
138                 resource_info->resource_type = params->resource_type;
139                 resource_info->resource_sub_type = params->resource_sub_type;
140                 resource_info->reserved = params->reserved;
141         } else {
142                 resource_info->resource_em_handle = params->resource_hndl;
143         }
144 }
145
146 /*
147  * Helper function to copy the resource params to resource info
148  *  No validation being done in this function.
149  *
150  * resource_info [in] Ptr to resource information
151  * params [out] The output params to the caller
152  *
153  * returns none
154  */
155 static void
156 ulp_flow_db_res_info_to_params(struct ulp_fdb_resource_info *resource_info,
157                                struct ulp_flow_db_res_params *params)
158 {
159         memset(params, 0, sizeof(struct ulp_flow_db_res_params));
160         params->direction = ((resource_info->nxt_resource_idx &
161                                  ULP_FLOW_DB_RES_DIR_MASK) >>
162                                  ULP_FLOW_DB_RES_DIR_BIT);
163
164         /* use the helper function to get the resource func */
165         params->resource_func = ulp_flow_db_resource_func_get(resource_info);
166
167         if (params->resource_func == BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE ||
168             params->resource_func == BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) {
169                 params->resource_hndl = resource_info->resource_em_handle;
170         } else if (params->resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) {
171                 params->resource_hndl = resource_info->resource_hndl;
172                 params->resource_type = resource_info->resource_type;
173                 params->resource_sub_type = resource_info->resource_sub_type;
174                 params->reserved = resource_info->reserved;
175         }
176 }
177
178 /*
179  * Helper function to allocate the flow table and initialize
180  * the stack for allocation operations.
181  *
182  * flow_db [in] Ptr to flow database structure
183  *
184  * Returns 0 on success or negative number on failure.
185  */
186 static int32_t
187 ulp_flow_db_alloc_resource(struct bnxt_ulp_flow_db *flow_db)
188 {
189         uint32_t                        idx = 0;
190         struct bnxt_ulp_flow_tbl        *flow_tbl;
191         uint32_t                        size;
192
193         flow_tbl = &flow_db->flow_tbl;
194
195         size = sizeof(struct ulp_fdb_resource_info) * flow_tbl->num_resources;
196         flow_tbl->flow_resources =
197                         rte_zmalloc("ulp_fdb_resource_info", size, 0);
198
199         if (!flow_tbl->flow_resources) {
200                 BNXT_TF_DBG(ERR, "Failed to alloc memory for flow table\n");
201                 return -ENOMEM;
202         }
203         size = sizeof(uint32_t) * flow_tbl->num_resources;
204         flow_tbl->flow_tbl_stack = rte_zmalloc("flow_tbl_stack", size, 0);
205         if (!flow_tbl->flow_tbl_stack) {
206                 BNXT_TF_DBG(ERR, "Failed to alloc memory flow tbl stack\n");
207                 return -ENOMEM;
208         }
209         size = (flow_tbl->num_flows / sizeof(uint64_t)) + 1;
210         size =  ULP_BYTE_ROUND_OFF_8(size);
211         flow_tbl->active_reg_flows = rte_zmalloc("active reg flows", size,
212                                                  ULP_BUFFER_ALIGN_64_BYTE);
213         if (!flow_tbl->active_reg_flows) {
214                 BNXT_TF_DBG(ERR, "Failed to alloc memory active reg flows\n");
215                 return -ENOMEM;
216         }
217
218         flow_tbl->active_dflt_flows = rte_zmalloc("active dflt flows", size,
219                                                   ULP_BUFFER_ALIGN_64_BYTE);
220         if (!flow_tbl->active_dflt_flows) {
221                 BNXT_TF_DBG(ERR, "Failed to alloc memory active dflt flows\n");
222                 return -ENOMEM;
223         }
224
225         /* Initialize the stack table. */
226         for (idx = 0; idx < flow_tbl->num_resources; idx++)
227                 flow_tbl->flow_tbl_stack[idx] = idx;
228
229         /* Ignore the first element in the list. */
230         flow_tbl->head_index = 1;
231         /* Tail points to the last entry in the list. */
232         flow_tbl->tail_index = flow_tbl->num_resources - 1;
233         return 0;
234 }
235
236 /*
237  * Helper function to deallocate the flow table.
238  *
239  * flow_db [in] Ptr to flow database structure
240  *
241  * Returns none.
242  */
243 static void
244 ulp_flow_db_dealloc_resource(struct bnxt_ulp_flow_db *flow_db)
245 {
246         struct bnxt_ulp_flow_tbl *flow_tbl = &flow_db->flow_tbl;
247
248         /* Free all the allocated tables in the flow table. */
249         if (flow_tbl->active_reg_flows) {
250                 rte_free(flow_tbl->active_reg_flows);
251                 flow_tbl->active_reg_flows = NULL;
252         }
253         if (flow_tbl->active_dflt_flows) {
254                 rte_free(flow_tbl->active_dflt_flows);
255                 flow_tbl->active_dflt_flows = NULL;
256         }
257
258         if (flow_tbl->flow_tbl_stack) {
259                 rte_free(flow_tbl->flow_tbl_stack);
260                 flow_tbl->flow_tbl_stack = NULL;
261         }
262
263         if (flow_tbl->flow_resources) {
264                 rte_free(flow_tbl->flow_resources);
265                 flow_tbl->flow_resources = NULL;
266         }
267 }
268
269 /*
270  * Helper function to add function id to the flow table
271  *
272  * flow_db [in] Ptr to flow table
273  * flow_id [in] The flow id of the flow
274  * func_id [in] The func_id to be set, for reset pass zero
275  *
276  * returns none
277  */
278 static void
279 ulp_flow_db_func_id_set(struct bnxt_ulp_flow_db *flow_db,
280                         uint32_t flow_id,
281                         uint32_t func_id)
282 {
283         /* set the function id in the function table */
284         if (flow_id < flow_db->func_id_tbl_size)
285                 flow_db->func_id_tbl[flow_id] = func_id;
286         else /* This should never happen */
287                 BNXT_TF_DBG(ERR, "Invalid flow id, flowdb corrupt\n");
288 }
289
290 /*
291  * Initialize the parent-child database. Memory is allocated in this
292  * call and assigned to the database
293  *
294  * flow_db [in] Ptr to flow table
295  * num_entries[in] - number of entries to allocate
296  *
297  * Returns 0 on success or negative number on failure.
298  */
299 static int32_t
300 ulp_flow_db_parent_tbl_init(struct bnxt_ulp_flow_db *flow_db,
301                             uint32_t num_entries)
302 {
303         struct ulp_fdb_parent_child_db *p_db;
304         uint32_t size, idx;
305
306         /* update the sizes for the allocation */
307         p_db = &flow_db->parent_child_db;
308         p_db->child_bitset_size = (flow_db->flow_tbl.num_flows /
309                                    sizeof(uint64_t)) + 1; /* size in bytes */
310         p_db->child_bitset_size = ULP_BYTE_ROUND_OFF_8(p_db->child_bitset_size);
311         p_db->entries_count = num_entries;
312
313         /* allocate the memory */
314         p_db->parent_flow_tbl = rte_zmalloc("fdb parent flow tbl",
315                                             sizeof(struct ulp_fdb_parent_info) *
316                                             p_db->entries_count, 0);
317         if (!p_db->parent_flow_tbl) {
318                 BNXT_TF_DBG(ERR,
319                             "Failed to allocate memory fdb parent flow tbl\n");
320                 return -ENOMEM;
321         }
322         size = p_db->child_bitset_size * p_db->entries_count;
323
324         /*
325          * allocate the big chunk of memory to be statically carved into
326          * child_fid_bitset pointer.
327          */
328         p_db->parent_flow_tbl_mem = rte_zmalloc("fdb parent flow tbl mem",
329                                                 size,
330                                                 ULP_BUFFER_ALIGN_64_BYTE);
331         if (!p_db->parent_flow_tbl_mem) {
332                 BNXT_TF_DBG(ERR,
333                             "Failed to allocate memory fdb parent flow mem\n");
334                 return -ENOMEM;
335         }
336
337         /* set the pointers in parent table to their offsets */
338         for (idx = 0 ; idx < p_db->entries_count; idx++) {
339                 p_db->parent_flow_tbl[idx].child_fid_bitset =
340                         (uint64_t *)&p_db->parent_flow_tbl_mem[idx *
341                         p_db->child_bitset_size];
342         }
343         /* success */
344         return 0;
345 }
346
347 /*
348  * Deinitialize the parent-child database. Memory is deallocated in
349  * this call and all flows should have been purged before this
350  * call.
351  *
352  * flow_db [in] Ptr to flow table
353  *
354  * Returns none
355  */
356 static void
357 ulp_flow_db_parent_tbl_deinit(struct bnxt_ulp_flow_db *flow_db)
358 {
359         /* free the memory related to parent child database */
360         if (flow_db->parent_child_db.parent_flow_tbl_mem) {
361                 rte_free(flow_db->parent_child_db.parent_flow_tbl_mem);
362                 flow_db->parent_child_db.parent_flow_tbl_mem = NULL;
363         }
364         if (flow_db->parent_child_db.parent_flow_tbl) {
365                 rte_free(flow_db->parent_child_db.parent_flow_tbl);
366                 flow_db->parent_child_db.parent_flow_tbl = NULL;
367         }
368 }
369
370 /*
371  * Initialize the flow database. Memory is allocated in this
372  * call and assigned to the flow database.
373  *
374  * ulp_ctxt [in] Ptr to ulp context
375  *
376  * Returns 0 on success or negative number on failure.
377  */
378 int32_t
379 ulp_flow_db_init(struct bnxt_ulp_context *ulp_ctxt)
380 {
381         struct bnxt_ulp_device_params *dparms;
382         struct bnxt_ulp_flow_tbl *flow_tbl;
383         struct bnxt_ulp_flow_db *flow_db;
384         uint32_t dev_id, num_flows;
385         enum bnxt_ulp_flow_mem_type mtype;
386
387         /* Get the dev specific number of flows that needed to be supported. */
388         if (bnxt_ulp_cntxt_dev_id_get(ulp_ctxt, &dev_id)) {
389                 BNXT_TF_DBG(ERR, "Invalid device id\n");
390                 return -EINVAL;
391         }
392
393         dparms = bnxt_ulp_device_params_get(dev_id);
394         if (!dparms) {
395                 BNXT_TF_DBG(ERR, "could not fetch the device params\n");
396                 return -ENODEV;
397         }
398
399         flow_db = rte_zmalloc("bnxt_ulp_flow_db",
400                               sizeof(struct bnxt_ulp_flow_db), 0);
401         if (!flow_db) {
402                 BNXT_TF_DBG(ERR,
403                             "Failed to allocate memory for flow table ptr\n");
404                 return -ENOMEM;
405         }
406
407         /* Attach the flow database to the ulp context. */
408         bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, flow_db);
409
410         /* Determine the number of flows based on EM type */
411         bnxt_ulp_cntxt_mem_type_get(ulp_ctxt, &mtype);
412         if (mtype == BNXT_ULP_FLOW_MEM_TYPE_INT)
413                 num_flows = dparms->int_flow_db_num_entries;
414         else
415                 num_flows = dparms->ext_flow_db_num_entries;
416
417         /* Populate the regular flow table limits. */
418         flow_tbl = &flow_db->flow_tbl;
419         flow_tbl->num_flows = num_flows + 1;
420         flow_tbl->num_resources = ((num_flows + 1) *
421                                    dparms->num_resources_per_flow);
422
423         /* Include the default flow table limits. */
424         flow_tbl->num_flows += (BNXT_FLOW_DB_DEFAULT_NUM_FLOWS + 1);
425         flow_tbl->num_resources += ((BNXT_FLOW_DB_DEFAULT_NUM_FLOWS + 1) *
426                                     BNXT_FLOW_DB_DEFAULT_NUM_RESOURCES);
427
428         /* Allocate the resource for the flow table. */
429         if (ulp_flow_db_alloc_resource(flow_db))
430                 goto error_free;
431
432         /* add 1 since we are not using index 0 for flow id */
433         flow_db->func_id_tbl_size = flow_tbl->num_flows + 1;
434         /* Allocate the function Id table */
435         flow_db->func_id_tbl = rte_zmalloc("bnxt_ulp_flow_db_func_id_table",
436                                            flow_db->func_id_tbl_size *
437                                            sizeof(uint16_t), 0);
438         if (!flow_db->func_id_tbl) {
439                 BNXT_TF_DBG(ERR,
440                             "Failed to allocate mem for flow table func id\n");
441                 goto error_free;
442         }
443         /* initialize the parent child database */
444         if (ulp_flow_db_parent_tbl_init(flow_db,
445                                         dparms->fdb_parent_flow_entries)) {
446                 BNXT_TF_DBG(ERR,
447                             "Failed to allocate mem for parent child db\n");
448                 goto error_free;
449         }
450
451         /* All good so return. */
452         BNXT_TF_DBG(INFO, "FlowDB initialized with %d flows.\n",
453                     flow_tbl->num_flows);
454         return 0;
455 error_free:
456         ulp_flow_db_deinit(ulp_ctxt);
457         return -ENOMEM;
458 }
459
460 /*
461  * Deinitialize the flow database. Memory is deallocated in
462  * this call and all flows should have been purged before this
463  * call.
464  *
465  * ulp_ctxt [in] Ptr to ulp context
466  *
467  * Returns 0 on success.
468  */
469 int32_t
470 ulp_flow_db_deinit(struct bnxt_ulp_context *ulp_ctxt)
471 {
472         struct bnxt_ulp_flow_db *flow_db;
473
474         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
475         if (!flow_db)
476                 return -EINVAL;
477
478         /* Detach the flow database from the ulp context. */
479         bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, NULL);
480
481         /* Free up all the memory. */
482         ulp_flow_db_parent_tbl_deinit(flow_db);
483         ulp_flow_db_dealloc_resource(flow_db);
484         rte_free(flow_db->func_id_tbl);
485         rte_free(flow_db);
486
487         return 0;
488 }
489
490 /*
491  * Allocate the flow database entry
492  *
493  * ulp_ctxt [in] Ptr to ulp_context
494  * flow_type [in] - specify default or regular
495  * func_id [in].function id of the ingress port
496  * fid [out] The index to the flow entry
497  *
498  * returns 0 on success and negative on failure.
499  */
500 int32_t
501 ulp_flow_db_fid_alloc(struct bnxt_ulp_context *ulp_ctxt,
502                       enum bnxt_ulp_fdb_type flow_type,
503                       uint16_t func_id,
504                       uint32_t *fid)
505 {
506         struct bnxt_ulp_flow_db *flow_db;
507         struct bnxt_ulp_flow_tbl *flow_tbl;
508
509         *fid = 0; /* Initialize fid to invalid value */
510         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
511         if (!flow_db) {
512                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
513                 return -EINVAL;
514         }
515
516         if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
517                 BNXT_TF_DBG(ERR, "Invalid flow type\n");
518                 return -EINVAL;
519         }
520
521         flow_tbl = &flow_db->flow_tbl;
522         /* check for max flows */
523         if (flow_tbl->num_flows <= flow_tbl->head_index) {
524                 BNXT_TF_DBG(ERR, "Flow database has reached max flows\n");
525                 return -ENOMEM;
526         }
527         if (flow_tbl->tail_index <= (flow_tbl->head_index + 1)) {
528                 BNXT_TF_DBG(ERR, "Flow database has reached max resources\n");
529                 return -ENOMEM;
530         }
531         *fid = flow_tbl->flow_tbl_stack[flow_tbl->head_index];
532         flow_tbl->head_index++;
533
534         /* Set the flow type */
535         ulp_flow_db_active_flows_bit_set(flow_db, flow_type, *fid, 1);
536
537         /* function id update is only valid for regular flow table */
538         if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR)
539                 ulp_flow_db_func_id_set(flow_db, *fid, func_id);
540
541         /* return success */
542         return 0;
543 }
544
545 /*
546  * Allocate the flow database entry.
547  * The params->critical_resource has to be set to 0 to allocate a new resource.
548  *
549  * ulp_ctxt [in] Ptr to ulp_context
550  * flow_type [in] Specify it is regular or default flow
551  * fid [in] The index to the flow entry
552  * params [in] The contents to be copied into resource
553  *
554  * returns 0 on success and negative on failure.
555  */
556 int32_t
557 ulp_flow_db_resource_add(struct bnxt_ulp_context *ulp_ctxt,
558                          enum bnxt_ulp_fdb_type flow_type,
559                          uint32_t fid,
560                          struct ulp_flow_db_res_params *params)
561 {
562         struct bnxt_ulp_flow_db *flow_db;
563         struct bnxt_ulp_flow_tbl *flow_tbl;
564         struct ulp_fdb_resource_info *resource, *fid_resource;
565         uint32_t idx;
566
567         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
568         if (!flow_db) {
569                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
570                 return -EINVAL;
571         }
572
573         if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
574                 BNXT_TF_DBG(ERR, "Invalid flow type\n");
575                 return -EINVAL;
576         }
577
578         flow_tbl = &flow_db->flow_tbl;
579         /* check for max flows */
580         if (fid >= flow_tbl->num_flows || !fid) {
581                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
582                 return -EINVAL;
583         }
584
585         /* check if the flow is active or not */
586         if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) {
587                 BNXT_TF_DBG(ERR, "flow does not exist\n");
588                 return -EINVAL;
589         }
590
591         /* check for max resource */
592         if ((flow_tbl->head_index + 1) >= flow_tbl->tail_index) {
593                 BNXT_TF_DBG(ERR, "Flow db has reached max resources\n");
594                 return -ENOMEM;
595         }
596         fid_resource = &flow_tbl->flow_resources[fid];
597
598         if (!params->critical_resource) {
599                 /* Not the critical_resource so allocate a resource */
600                 idx = flow_tbl->flow_tbl_stack[flow_tbl->tail_index];
601                 resource = &flow_tbl->flow_resources[idx];
602                 flow_tbl->tail_index--;
603
604                 /* Update the chain list of resource*/
605                 ULP_FLOW_DB_RES_NXT_SET(resource->nxt_resource_idx,
606                                         fid_resource->nxt_resource_idx);
607                 /* update the contents */
608                 ulp_flow_db_res_params_to_info(resource, params);
609                 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx);
610                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
611                                         idx);
612         } else {
613                 /* critical resource. Just update the fid resource */
614                 ulp_flow_db_res_params_to_info(fid_resource, params);
615         }
616
617         if (params->resource_type == TF_TBL_TYPE_ACT_STATS_64 &&
618             params->resource_sub_type ==
619             BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_INT_COUNT) {
620                 /* Store the first HW counter ID for this table */
621                 if (!ulp_fc_mgr_start_idx_isset(ulp_ctxt, params->direction))
622                         ulp_fc_mgr_start_idx_set(ulp_ctxt, params->direction,
623                                                  params->resource_hndl);
624
625                 ulp_fc_mgr_cntr_set(ulp_ctxt, params->direction,
626                                     params->resource_hndl);
627
628                 if (!ulp_fc_mgr_thread_isstarted(ulp_ctxt))
629                         ulp_fc_mgr_thread_start(ulp_ctxt);
630         }
631
632         /* all good, return success */
633         return 0;
634 }
635
636 /*
637  * Free the flow database entry.
638  * The params->critical_resource has to be set to 1 to free the first resource.
639  *
640  * ulp_ctxt [in] Ptr to ulp_context
641  * flow_type [in] Specify it is regular or default flow
642  * fid [in] The index to the flow entry
643  * params [in/out] The contents to be copied into params.
644  * Onlythe critical_resource needs to be set by the caller.
645  *
646  * Returns 0 on success and negative on failure.
647  */
648 int32_t
649 ulp_flow_db_resource_del(struct bnxt_ulp_context *ulp_ctxt,
650                          enum bnxt_ulp_fdb_type flow_type,
651                          uint32_t fid,
652                          struct ulp_flow_db_res_params *params)
653 {
654         struct bnxt_ulp_flow_db *flow_db;
655         struct bnxt_ulp_flow_tbl *flow_tbl;
656         struct ulp_fdb_resource_info *nxt_resource, *fid_resource;
657         uint32_t nxt_idx = 0;
658
659         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
660         if (!flow_db) {
661                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
662                 return -EINVAL;
663         }
664
665         if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
666                 BNXT_TF_DBG(ERR, "Invalid flow type\n");
667                 return -EINVAL;
668         }
669
670         flow_tbl = &flow_db->flow_tbl;
671         /* check for max flows */
672         if (fid >= flow_tbl->num_flows || !fid) {
673                 BNXT_TF_DBG(ERR, "Invalid flow index %x\n", fid);
674                 return -EINVAL;
675         }
676
677         /* check if the flow is active or not */
678         if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) {
679                 BNXT_TF_DBG(ERR, "flow does not exist\n");
680                 return -EINVAL;
681         }
682
683         fid_resource = &flow_tbl->flow_resources[fid];
684         if (!params->critical_resource) {
685                 /* Not the critical resource so free the resource */
686                 ULP_FLOW_DB_RES_NXT_SET(nxt_idx,
687                                         fid_resource->nxt_resource_idx);
688                 if (!nxt_idx) {
689                         /* reached end of resources */
690                         return -ENOENT;
691                 }
692                 nxt_resource = &flow_tbl->flow_resources[nxt_idx];
693
694                 /* connect the fid resource to the next resource */
695                 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx);
696                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
697                                         nxt_resource->nxt_resource_idx);
698
699                 /* update the contents to be given to caller */
700                 ulp_flow_db_res_info_to_params(nxt_resource, params);
701
702                 /* Delete the nxt_resource */
703                 memset(nxt_resource, 0, sizeof(struct ulp_fdb_resource_info));
704
705                 /* add it to the free list */
706                 flow_tbl->tail_index++;
707                 if (flow_tbl->tail_index >= flow_tbl->num_resources) {
708                         BNXT_TF_DBG(ERR, "FlowDB:Tail reached max\n");
709                         return -ENOENT;
710                 }
711                 flow_tbl->flow_tbl_stack[flow_tbl->tail_index] = nxt_idx;
712
713         } else {
714                 /* Critical resource. copy the contents and exit */
715                 ulp_flow_db_res_info_to_params(fid_resource, params);
716                 ULP_FLOW_DB_RES_NXT_SET(nxt_idx,
717                                         fid_resource->nxt_resource_idx);
718                 memset(fid_resource, 0, sizeof(struct ulp_fdb_resource_info));
719                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
720                                         nxt_idx);
721         }
722
723         /* Now that the HW Flow counter resource is deleted, reset it's
724          * corresponding slot in the SW accumulation table in the Flow Counter
725          * manager
726          */
727         if (params->resource_type == TF_TBL_TYPE_ACT_STATS_64 &&
728             params->resource_sub_type ==
729             BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_INT_COUNT) {
730                 ulp_fc_mgr_cntr_reset(ulp_ctxt, params->direction,
731                                       params->resource_hndl);
732         }
733
734         /* all good, return success */
735         return 0;
736 }
737
738 /*
739  * Free the flow database entry
740  *
741  * ulp_ctxt [in] Ptr to ulp_context
742  * flow_type [in] - specify default or regular
743  * fid [in] The index to the flow entry
744  *
745  * returns 0 on success and negative on failure.
746  */
747 int32_t
748 ulp_flow_db_fid_free(struct bnxt_ulp_context *ulp_ctxt,
749                      enum bnxt_ulp_fdb_type flow_type,
750                      uint32_t fid)
751 {
752         struct bnxt_ulp_flow_db *flow_db;
753         struct bnxt_ulp_flow_tbl *flow_tbl;
754
755         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
756         if (!flow_db) {
757                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
758                 return -EINVAL;
759         }
760
761         if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
762                 BNXT_TF_DBG(ERR, "Invalid flow type\n");
763                 return -EINVAL;
764         }
765
766         flow_tbl = &flow_db->flow_tbl;
767
768         /* check for limits of fid */
769         if (fid >= flow_tbl->num_flows || !fid) {
770                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
771                 return -EINVAL;
772         }
773
774         /* check if the flow is active or not */
775         if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) {
776                 BNXT_TF_DBG(ERR, "flow does not exist\n");
777                 return -EINVAL;
778         }
779         flow_tbl->head_index--;
780         if (!flow_tbl->head_index) {
781                 BNXT_TF_DBG(ERR, "FlowDB: Head Ptr is zero\n");
782                 return -ENOENT;
783         }
784         flow_tbl->flow_tbl_stack[flow_tbl->head_index] = fid;
785
786         /* Clear the flows bitmap */
787         ulp_flow_db_active_flows_bit_set(flow_db, flow_type, fid, 0);
788
789         if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR)
790                 ulp_flow_db_func_id_set(flow_db, fid, 0);
791
792         /* all good, return success */
793         return 0;
794 }
795
796 /*
797  * Get the flow database entry details
798  *
799  * ulp_ctxt [in] Ptr to ulp_context
800  * flow_type [in] - specify default or regular
801  * fid [in] The index to the flow entry
802  * nxt_idx [in/out] the index to the next entry
803  * params [out] The contents to be copied into params.
804  *
805  * returns 0 on success and negative on failure.
806  */
807 int32_t
808 ulp_flow_db_resource_get(struct bnxt_ulp_context *ulp_ctxt,
809                          enum bnxt_ulp_fdb_type flow_type,
810                          uint32_t fid,
811                          uint32_t *nxt_idx,
812                          struct ulp_flow_db_res_params *params)
813 {
814         struct bnxt_ulp_flow_db *flow_db;
815         struct bnxt_ulp_flow_tbl *flow_tbl;
816         struct ulp_fdb_resource_info *nxt_resource, *fid_resource;
817
818         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
819         if (!flow_db) {
820                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
821                 return -EINVAL;
822         }
823
824         if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
825                 BNXT_TF_DBG(ERR, "Invalid flow type\n");
826                 return -EINVAL;
827         }
828
829         flow_tbl = &flow_db->flow_tbl;
830
831         /* check for limits of fid */
832         if (fid >= flow_tbl->num_flows || !fid) {
833                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
834                 return -EINVAL;
835         }
836
837         /* check if the flow is active or not */
838         if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) {
839                 BNXT_TF_DBG(ERR, "flow does not exist\n");
840                 return -EINVAL;
841         }
842
843         if (!*nxt_idx) {
844                 fid_resource = &flow_tbl->flow_resources[fid];
845                 ulp_flow_db_res_info_to_params(fid_resource, params);
846                 ULP_FLOW_DB_RES_NXT_SET(*nxt_idx,
847                                         fid_resource->nxt_resource_idx);
848         } else {
849                 nxt_resource = &flow_tbl->flow_resources[*nxt_idx];
850                 ulp_flow_db_res_info_to_params(nxt_resource, params);
851                 *nxt_idx = 0;
852                 ULP_FLOW_DB_RES_NXT_SET(*nxt_idx,
853                                         nxt_resource->nxt_resource_idx);
854         }
855
856         /* all good, return success */
857         return 0;
858 }
859
860 /*
861  * Get the flow database entry iteratively
862  *
863  * flow_tbl [in] Ptr to flow table
864  * flow_type [in] - specify default or regular
865  * fid [in/out] The index to the flow entry
866  *
867  * returns 0 on success and negative on failure.
868  */
869 static int32_t
870 ulp_flow_db_next_entry_get(struct bnxt_ulp_flow_db *flow_db,
871                            enum bnxt_ulp_fdb_type flow_type,
872                            uint32_t *fid)
873 {
874         uint32_t lfid = *fid;
875         uint32_t idx, s_idx, mod_fid;
876         uint64_t bs;
877         uint64_t *active_flows;
878         struct bnxt_ulp_flow_tbl *flowtbl = &flow_db->flow_tbl;
879
880         if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR)
881                 active_flows = flowtbl->active_reg_flows;
882         else
883                 active_flows = flowtbl->active_dflt_flows;
884
885         do {
886                 /* increment the flow id to find the next valid flow id */
887                 lfid++;
888                 if (lfid >= flowtbl->num_flows)
889                         return -ENOENT;
890                 idx = lfid / ULP_INDEX_BITMAP_SIZE;
891                 mod_fid = lfid % ULP_INDEX_BITMAP_SIZE;
892                 s_idx = idx;
893                 while (!(bs = active_flows[idx])) {
894                         idx++;
895                         if ((idx * ULP_INDEX_BITMAP_SIZE) >= flowtbl->num_flows)
896                                 return -ENOENT;
897                 }
898                 /*
899                  * remove the previous bits in the bitset bs to find the
900                  * next non zero bit in the bitset. This needs to be done
901                  * only if the idx is same as he one you started.
902                  */
903                 if (s_idx == idx)
904                         bs &= (-1UL >> mod_fid);
905                 lfid = (idx * ULP_INDEX_BITMAP_SIZE) + __builtin_clzl(bs);
906                 if (*fid >= lfid) {
907                         BNXT_TF_DBG(ERR, "Flow Database is corrupt\n");
908                         return -ENOENT;
909                 }
910         } while (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type,
911                                                       lfid));
912
913         /* all good, return success */
914         *fid = lfid;
915         return 0;
916 }
917
918 /*
919  * Flush all flows in the flow database.
920  *
921  * ulp_ctxt [in] Ptr to ulp context
922  * flow_type [in] - specify default or regular
923  *
924  * returns 0 on success or negative number on failure
925  */
926 int32_t
927 ulp_flow_db_flush_flows(struct bnxt_ulp_context *ulp_ctx,
928                         enum bnxt_ulp_fdb_type flow_type)
929 {
930         uint32_t fid = 0;
931         struct bnxt_ulp_flow_db *flow_db;
932
933         if (!ulp_ctx) {
934                 BNXT_TF_DBG(ERR, "Invalid Argument\n");
935                 return -EINVAL;
936         }
937
938         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
939         if (!flow_db) {
940                 BNXT_TF_DBG(ERR, "Flow database not found\n");
941                 return -EINVAL;
942         }
943         if (bnxt_ulp_cntxt_acquire_fdb_lock(ulp_ctx)) {
944                 BNXT_TF_DBG(ERR, "Flow db lock acquire failed\n");
945                 return -EINVAL;
946         }
947
948         while (!ulp_flow_db_next_entry_get(flow_db, flow_type, &fid))
949                 ulp_mapper_resources_free(ulp_ctx, flow_type, fid);
950
951         bnxt_ulp_cntxt_release_fdb_lock(ulp_ctx);
952
953         return 0;
954 }
955
956 /*
957  * Flush all flows in the flow database that belong to a device function.
958  *
959  * ulp_ctxt [in] Ptr to ulp context
960  * func_id [in] - The port function id
961  *
962  * returns 0 on success or negative number on failure
963  */
964 int32_t
965 ulp_flow_db_function_flow_flush(struct bnxt_ulp_context *ulp_ctx,
966                                 uint16_t func_id)
967 {
968         uint32_t flow_id = 0;
969         struct bnxt_ulp_flow_db *flow_db;
970
971         if (!ulp_ctx || !func_id) {
972                 BNXT_TF_DBG(ERR, "Invalid Argument\n");
973                 return -EINVAL;
974         }
975
976         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
977         if (!flow_db) {
978                 BNXT_TF_DBG(ERR, "Flow database not found\n");
979                 return -EINVAL;
980         }
981         if (bnxt_ulp_cntxt_acquire_fdb_lock(ulp_ctx)) {
982                 BNXT_TF_DBG(ERR, "Flow db lock acquire failed\n");
983                 return -EINVAL;
984         }
985
986         while (!ulp_flow_db_next_entry_get(flow_db, BNXT_ULP_FDB_TYPE_REGULAR,
987                                            &flow_id)) {
988                 if (flow_db->func_id_tbl[flow_id] == func_id)
989                         ulp_mapper_resources_free(ulp_ctx,
990                                                   BNXT_ULP_FDB_TYPE_REGULAR,
991                                                   flow_id);
992         }
993         bnxt_ulp_cntxt_release_fdb_lock(ulp_ctx);
994         return 0;
995 }
996
997 /*
998  * Flush all flows in the flow database that are associated with the session.
999  *
1000  * ulp_ctxt [in] Ptr to ulp context
1001  *
1002  * returns 0 on success or negative number on failure
1003  */
1004 int32_t
1005 ulp_flow_db_session_flow_flush(struct bnxt_ulp_context *ulp_ctx)
1006 {
1007         /*
1008          * TBD: Tf core implementation of FW session flush shall change this
1009          * implementation.
1010          */
1011         return ulp_flow_db_flush_flows(ulp_ctx, BNXT_ULP_FDB_TYPE_REGULAR);
1012 }
1013
1014 /*
1015  * Check that flow id matches the function id or not
1016  *
1017  * ulp_ctxt [in] Ptr to ulp context
1018  * flow_db [in] Ptr to flow table
1019  * func_id [in] The func_id to be set, for reset pass zero.
1020  *
1021  * returns true on success or false on failure
1022  */
1023 bool
1024 ulp_flow_db_validate_flow_func(struct bnxt_ulp_context *ulp_ctx,
1025                                uint32_t flow_id,
1026                                uint32_t func_id)
1027 {
1028         struct bnxt_ulp_flow_db *flow_db;
1029
1030         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
1031         if (!flow_db) {
1032                 BNXT_TF_DBG(ERR, "Flow database not found\n");
1033                 return false;
1034         }
1035
1036         /* set the function id in the function table */
1037         if (flow_id < flow_db->func_id_tbl_size && func_id &&
1038             flow_db->func_id_tbl[flow_id] == func_id)
1039                 return true;
1040
1041         return false;
1042 }
1043
1044 /*
1045  * Internal api to traverse the resource list within a flow
1046  * and match a resource based on resource func and resource
1047  * sub type. This api should be used only for resources that
1048  * are unique and do not have multiple instances of resource
1049  * func and sub type combination since it will return only
1050  * the first match.
1051  */
1052 static int32_t
1053 ulp_flow_db_resource_hndl_get(struct bnxt_ulp_context *ulp_ctx,
1054                               enum bnxt_ulp_fdb_type flow_type,
1055                               uint32_t flow_id,
1056                               uint32_t resource_func,
1057                               uint32_t res_subtype,
1058                               uint64_t *res_hndl)
1059 {
1060         struct bnxt_ulp_flow_db *flow_db;
1061         struct bnxt_ulp_flow_tbl *flow_tbl;
1062         struct ulp_fdb_resource_info *fid_res;
1063         uint32_t res_id;
1064
1065         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
1066         if (!flow_db) {
1067                 BNXT_TF_DBG(ERR, "Flow database not found\n");
1068                 return -EINVAL;
1069         }
1070
1071         if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
1072                 BNXT_TF_DBG(ERR, "Invalid flow type\n");
1073                 return -EINVAL;
1074         }
1075
1076         flow_tbl = &flow_db->flow_tbl;
1077
1078         /* check for limits of fid */
1079         if (flow_id >= flow_tbl->num_flows || !flow_id) {
1080                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
1081                 return -EINVAL;
1082         }
1083
1084         /* check if the flow is active or not */
1085         if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, flow_id)) {
1086                 BNXT_TF_DBG(ERR, "flow does not exist\n");
1087                 return -EINVAL;
1088         }
1089         /* Iterate the resource to get the resource handle */
1090         res_id =  flow_id;
1091         while (res_id) {
1092                 fid_res = &flow_tbl->flow_resources[res_id];
1093                 if (ulp_flow_db_resource_func_get(fid_res) == resource_func) {
1094                         if (resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) {
1095                                 if (res_subtype == fid_res->resource_sub_type) {
1096                                         *res_hndl = fid_res->resource_hndl;
1097                                         return 0;
1098                                 }
1099
1100                         } else if (resource_func ==
1101                                    BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE ||
1102                                    resource_func ==
1103                                    BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) {
1104                                 *res_hndl = fid_res->resource_em_handle;
1105                                 return 0;
1106                         }
1107                 }
1108                 res_id = 0;
1109                 ULP_FLOW_DB_RES_NXT_SET(res_id, fid_res->nxt_resource_idx);
1110         }
1111         return -ENOENT;
1112 }
1113
1114 /*
1115  * Api to get the cfa action pointer from a flow.
1116  *
1117  * ulp_ctxt [in] Ptr to ulp context
1118  * flow_id [in] flow id
1119  * cfa_action [out] The resource handle stored in the flow database
1120  *
1121  * returns 0 on success
1122  */
1123 int32_t
1124 ulp_default_flow_db_cfa_action_get(struct bnxt_ulp_context *ulp_ctx,
1125                                    uint32_t flow_id,
1126                                    uint16_t *cfa_action)
1127 {
1128         uint8_t sub_type = BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_VFR_CFA_ACTION;
1129         uint64_t hndl;
1130         int32_t rc;
1131
1132         rc = ulp_flow_db_resource_hndl_get(ulp_ctx,
1133                                            BNXT_ULP_FDB_TYPE_DEFAULT,
1134                                            flow_id,
1135                                            BNXT_ULP_RESOURCE_FUNC_INDEX_TABLE,
1136                                            sub_type, &hndl);
1137         if (rc) {
1138                 BNXT_TF_DBG(ERR, "CFA Action ptr not found for flow id %u\n",
1139                             flow_id);
1140                 return -ENOENT;
1141         }
1142         *cfa_action = hndl;
1143         return 0;
1144 }
1145
1146 /*
1147  * Allocate the entry in the parent-child database
1148  *
1149  * ulp_ctxt [in] Ptr to ulp_context
1150  * fid [in] The flow id to the flow entry
1151  *
1152  * returns index on success and negative on failure.
1153  */
1154 int32_t
1155 ulp_flow_db_parent_flow_alloc(struct bnxt_ulp_context *ulp_ctxt,
1156                               uint32_t fid)
1157 {
1158         struct bnxt_ulp_flow_db *flow_db;
1159         struct ulp_fdb_parent_child_db *p_pdb;
1160         uint32_t idx, free_idx = 0;
1161
1162         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
1163         if (!flow_db) {
1164                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
1165                 return -EINVAL;
1166         }
1167
1168         /* check for max flows */
1169         if (fid >= flow_db->flow_tbl.num_flows || !fid) {
1170                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
1171                 return -EINVAL;
1172         }
1173
1174         p_pdb = &flow_db->parent_child_db;
1175         for (idx = 0; idx <= p_pdb->entries_count; idx++) {
1176                 if (p_pdb->parent_flow_tbl[idx].parent_fid == fid) {
1177                         BNXT_TF_DBG(ERR, "fid is already allocated\n");
1178                         return -EINVAL;
1179                 }
1180                 if (!p_pdb->parent_flow_tbl[idx].parent_fid && !free_idx)
1181                         free_idx = idx + 1;
1182         }
1183         /* no free slots */
1184         if (!free_idx) {
1185                 BNXT_TF_DBG(ERR, "parent child db is full\n");
1186                 return -ENOMEM;
1187         }
1188
1189         free_idx -= 1;
1190         /* set the Fid in the parent child */
1191         p_pdb->parent_flow_tbl[free_idx].parent_fid = fid;
1192         return free_idx;
1193 }
1194
1195 /*
1196  * Free the entry in the parent-child database
1197  *
1198  * ulp_ctxt [in] Ptr to ulp_context
1199  * fid [in] The flow id to the flow entry
1200  *
1201  * returns 0 on success and negative on failure.
1202  */
1203 int32_t
1204 ulp_flow_db_parent_flow_free(struct bnxt_ulp_context *ulp_ctxt,
1205                              uint32_t fid)
1206 {
1207         struct bnxt_ulp_flow_db *flow_db;
1208         struct ulp_fdb_parent_child_db *p_pdb;
1209         uint32_t idx;
1210
1211         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
1212         if (!flow_db) {
1213                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
1214                 return -EINVAL;
1215         }
1216
1217         /* check for max flows */
1218         if (fid >= flow_db->flow_tbl.num_flows || !fid) {
1219                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
1220                 return -EINVAL;
1221         }
1222
1223         p_pdb = &flow_db->parent_child_db;
1224         for (idx = 0; idx <= p_pdb->entries_count; idx++) {
1225                 if (p_pdb->parent_flow_tbl[idx].parent_fid == fid) {
1226                         /* free the contents */
1227                         p_pdb->parent_flow_tbl[idx].parent_fid = 0;
1228                         memset(p_pdb->parent_flow_tbl[idx].child_fid_bitset,
1229                                0, p_pdb->child_bitset_size);
1230                         return 0;
1231                 }
1232         }
1233         BNXT_TF_DBG(ERR, "parent entry not found = %x\n", fid);
1234         return -EINVAL;
1235 }
1236
1237 /*
1238  * Set or reset the child flow in the parent-child database
1239  *
1240  * ulp_ctxt [in] Ptr to ulp_context
1241  * parent_fid [in] The flow id of the parent flow entry
1242  * child_fid [in] The flow id of the child flow entry
1243  * set_flag [in] Use 1 for setting child, 0 to reset
1244  *
1245  * returns zero on success and negative on failure.
1246  */
1247 int32_t
1248 ulp_flow_db_parent_child_flow_set(struct bnxt_ulp_context *ulp_ctxt,
1249                                   uint32_t parent_fid,
1250                                   uint32_t child_fid,
1251                                   uint32_t set_flag)
1252 {
1253         struct bnxt_ulp_flow_db *flow_db;
1254         struct ulp_fdb_parent_child_db *p_pdb;
1255         uint32_t idx, a_idx;
1256         uint64_t *t;
1257
1258         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
1259         if (!flow_db) {
1260                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
1261                 return -EINVAL;
1262         }
1263
1264         /* check for fid validity */
1265         if (parent_fid >= flow_db->flow_tbl.num_flows || !parent_fid) {
1266                 BNXT_TF_DBG(ERR, "Invalid parent flow index %x\n", parent_fid);
1267                 return -EINVAL;
1268         }
1269
1270         /* check for fid validity */
1271         if (child_fid >= flow_db->flow_tbl.num_flows || !child_fid) {
1272                 BNXT_TF_DBG(ERR, "Invalid child flow index %x\n", child_fid);
1273                 return -EINVAL;
1274         }
1275
1276         p_pdb = &flow_db->parent_child_db;
1277         a_idx = child_fid / ULP_INDEX_BITMAP_SIZE;
1278         for (idx = 0; idx <= p_pdb->entries_count; idx++) {
1279                 if (p_pdb->parent_flow_tbl[idx].parent_fid == parent_fid) {
1280                         t = p_pdb->parent_flow_tbl[idx].child_fid_bitset;
1281                         if (set_flag)
1282                                 ULP_INDEX_BITMAP_SET(t[a_idx], child_fid);
1283                         else
1284                                 ULP_INDEX_BITMAP_RESET(t[a_idx], child_fid);
1285                         return 0;
1286                 }
1287         }
1288         BNXT_TF_DBG(ERR, "Unable to set the parent-child flow %x:%x\n",
1289                     parent_fid, child_fid);
1290         return -1;
1291 }
1292
1293 /*
1294  * Get the parent index from the parent-child database
1295  *
1296  * ulp_ctxt [in] Ptr to ulp_context
1297  * parent_fid [in] The flow id of the parent flow entry
1298  * parent_idx [out] The parent index of parent flow entry
1299  *
1300  * returns zero on success and negative on failure.
1301  */
1302 int32_t
1303 ulp_flow_db_parent_flow_idx_get(struct bnxt_ulp_context *ulp_ctxt,
1304                                 uint32_t parent_fid,
1305                                 uint32_t *parent_idx)
1306 {
1307         struct bnxt_ulp_flow_db *flow_db;
1308         struct ulp_fdb_parent_child_db *p_pdb;
1309         uint32_t idx;
1310
1311         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
1312         if (!flow_db) {
1313                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
1314                 return -EINVAL;
1315         }
1316
1317         /* check for fid validity */
1318         if (parent_fid >= flow_db->flow_tbl.num_flows || !parent_fid) {
1319                 BNXT_TF_DBG(ERR, "Invalid parent flow index %x\n", parent_fid);
1320                 return -EINVAL;
1321         }
1322
1323         p_pdb = &flow_db->parent_child_db;
1324         for (idx = 0; idx <= p_pdb->entries_count; idx++) {
1325                 if (p_pdb->parent_flow_tbl[idx].parent_fid == parent_fid) {
1326                         *parent_idx = idx;
1327                         return 0;
1328                 }
1329         }
1330         BNXT_TF_DBG(ERR, "Unable to get the parent flow %x\n", parent_fid);
1331         return -1;
1332 }
1333
1334 /*
1335  * Get the next child flow in the parent-child database
1336  *
1337  * ulp_ctxt [in] Ptr to ulp_context
1338  * parent_fid [in] The flow id of the parent flow entry
1339  * child_fid [in/out] The flow id of the child flow entry
1340  *
1341  * returns zero on success and negative on failure.
1342  * Pass child_fid as zero for first entry.
1343  */
1344 int32_t
1345 ulp_flow_db_parent_child_flow_next_entry_get(struct bnxt_ulp_flow_db *flow_db,
1346                                              uint32_t parent_idx,
1347                                              uint32_t *child_fid)
1348 {
1349         struct ulp_fdb_parent_child_db *p_pdb;
1350         uint32_t idx, s_idx, mod_fid;
1351         uint32_t next_fid = *child_fid;
1352         uint64_t *child_bitset;
1353         uint64_t bs;
1354
1355         /* check for fid validity */
1356         p_pdb = &flow_db->parent_child_db;
1357         if (parent_idx >= p_pdb->entries_count ||
1358             !p_pdb->parent_flow_tbl[parent_idx].parent_fid) {
1359                 BNXT_TF_DBG(ERR, "Invalid parent flow index %x\n", parent_idx);
1360                 return -EINVAL;
1361         }
1362
1363         child_bitset = p_pdb->parent_flow_tbl[parent_idx].child_fid_bitset;
1364         do {
1365                 /* increment the flow id to find the next valid flow id */
1366                 next_fid++;
1367                 if (next_fid >= flow_db->flow_tbl.num_flows)
1368                         return -ENOENT;
1369                 idx = next_fid / ULP_INDEX_BITMAP_SIZE;
1370                 mod_fid = next_fid % ULP_INDEX_BITMAP_SIZE;
1371                 s_idx = idx;
1372                 while (!(bs = child_bitset[idx])) {
1373                         idx++;
1374                         if ((idx * ULP_INDEX_BITMAP_SIZE) >=
1375                             flow_db->flow_tbl.num_flows)
1376                                 return -ENOENT;
1377                 }
1378                 /*
1379                  * remove the previous bits in the bitset bs to find the
1380                  * next non zero bit in the bitset. This needs to be done
1381                  * only if the idx is same as he one you started.
1382                  */
1383                 if (s_idx == idx)
1384                         bs &= (-1UL >> mod_fid);
1385                 next_fid = (idx * ULP_INDEX_BITMAP_SIZE) + __builtin_clzl(bs);
1386                 if (*child_fid >= next_fid) {
1387                         BNXT_TF_DBG(ERR, "Parent Child Database is corrupt\n");
1388                         return -ENOENT;
1389                 }
1390                 idx = next_fid / ULP_INDEX_BITMAP_SIZE;
1391         } while (!ULP_INDEX_BITMAP_GET(child_bitset[idx], next_fid));
1392         *child_fid = next_fid;
1393         return 0;
1394 }