8780c01cc70ae05000af734ce22a7a883b10672a
[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_utils.h"
10 #include "ulp_template_struct.h"
11 #include "ulp_mapper.h"
12 #include "ulp_flow_db.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 inline enum tf_dir
93 ulp_flow_db_resource_dir_get(struct ulp_fdb_resource_info *res_info)
94 {
95         return ((res_info->nxt_resource_idx & ULP_FLOW_DB_RES_DIR_MASK) >>
96                 ULP_FLOW_DB_RES_DIR_BIT);
97 }
98
99 static uint8_t
100 ulp_flow_db_resource_func_get(struct ulp_fdb_resource_info *res_info)
101 {
102         uint8_t func;
103
104         func = (((res_info->nxt_resource_idx & ULP_FLOW_DB_RES_FUNC_MASK) >>
105                  ULP_FLOW_DB_RES_FUNC_BITS) << ULP_FLOW_DB_RES_FUNC_UPPER);
106         /* The reource func is split into upper and lower */
107         if (func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER)
108                 return (func | res_info->resource_func_lower);
109         return func;
110 }
111
112 /*
113  * Helper function to copy the resource params to resource info
114  *  No validation being done in this function.
115  *
116  * resource_info [out] Ptr to resource information
117  * params [in] The input params from the caller
118  * returns none
119  */
120 static void
121 ulp_flow_db_res_params_to_info(struct ulp_fdb_resource_info *resource_info,
122                                struct ulp_flow_db_res_params *params)
123 {
124         uint32_t resource_func;
125
126         resource_info->nxt_resource_idx |= ((params->direction <<
127                                       ULP_FLOW_DB_RES_DIR_BIT) &
128                                      ULP_FLOW_DB_RES_DIR_MASK);
129         resource_func = (params->resource_func >> ULP_FLOW_DB_RES_FUNC_UPPER);
130         resource_info->nxt_resource_idx |= ((resource_func <<
131                                              ULP_FLOW_DB_RES_FUNC_BITS) &
132                                             ULP_FLOW_DB_RES_FUNC_MASK);
133
134         if (params->resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) {
135                 /* Break the resource func into two parts */
136                 resource_func = (params->resource_func &
137                                  ULP_FLOW_DB_RES_FUNC_LOWER_MASK);
138                 resource_info->resource_func_lower = resource_func;
139         }
140
141         /* Store the handle as 64bit only for EM table entries */
142         if (params->resource_func != BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE &&
143             params->resource_func != BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) {
144                 resource_info->resource_hndl = (uint32_t)params->resource_hndl;
145                 resource_info->resource_type = params->resource_type;
146                 resource_info->resource_sub_type = params->resource_sub_type;
147                 resource_info->reserved = params->reserved;
148         } else {
149                 resource_info->resource_em_handle = params->resource_hndl;
150         }
151 }
152
153 /*
154  * Helper function to copy the resource params to resource info
155  *  No validation being done in this function.
156  *
157  * resource_info [in] Ptr to resource information
158  * params [out] The output params to the caller
159  *
160  * returns none
161  */
162 static void
163 ulp_flow_db_res_info_to_params(struct ulp_fdb_resource_info *resource_info,
164                                struct ulp_flow_db_res_params *params)
165 {
166         memset(params, 0, sizeof(struct ulp_flow_db_res_params));
167
168         /* use the helper function to get the resource func */
169         params->direction = ulp_flow_db_resource_dir_get(resource_info);
170         params->resource_func = ulp_flow_db_resource_func_get(resource_info);
171
172         if (params->resource_func == BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE ||
173             params->resource_func == BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) {
174                 params->resource_hndl = resource_info->resource_em_handle;
175         } else if (params->resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) {
176                 params->resource_hndl = resource_info->resource_hndl;
177                 params->resource_type = resource_info->resource_type;
178                 params->resource_sub_type = resource_info->resource_sub_type;
179                 params->reserved = resource_info->reserved;
180         }
181 }
182
183 /*
184  * Helper function to allocate the flow table and initialize
185  * the stack for allocation operations.
186  *
187  * flow_db [in] Ptr to flow database structure
188  *
189  * Returns 0 on success or negative number on failure.
190  */
191 static int32_t
192 ulp_flow_db_alloc_resource(struct bnxt_ulp_flow_db *flow_db)
193 {
194         uint32_t                        idx = 0;
195         struct bnxt_ulp_flow_tbl        *flow_tbl;
196         uint32_t                        size;
197
198         flow_tbl = &flow_db->flow_tbl;
199
200         size = sizeof(struct ulp_fdb_resource_info) * flow_tbl->num_resources;
201         flow_tbl->flow_resources =
202                         rte_zmalloc("ulp_fdb_resource_info", size, 0);
203
204         if (!flow_tbl->flow_resources) {
205                 BNXT_TF_DBG(ERR, "Failed to alloc memory for flow table\n");
206                 return -ENOMEM;
207         }
208         size = sizeof(uint32_t) * flow_tbl->num_resources;
209         flow_tbl->flow_tbl_stack = rte_zmalloc("flow_tbl_stack", size, 0);
210         if (!flow_tbl->flow_tbl_stack) {
211                 BNXT_TF_DBG(ERR, "Failed to alloc memory flow tbl stack\n");
212                 return -ENOMEM;
213         }
214         size = (flow_tbl->num_flows / sizeof(uint64_t)) + 1;
215         size =  ULP_BYTE_ROUND_OFF_8(size);
216         flow_tbl->active_reg_flows = rte_zmalloc("active reg flows", size,
217                                                  ULP_BUFFER_ALIGN_64_BYTE);
218         if (!flow_tbl->active_reg_flows) {
219                 BNXT_TF_DBG(ERR, "Failed to alloc memory active reg flows\n");
220                 return -ENOMEM;
221         }
222
223         flow_tbl->active_dflt_flows = rte_zmalloc("active dflt flows", size,
224                                                   ULP_BUFFER_ALIGN_64_BYTE);
225         if (!flow_tbl->active_dflt_flows) {
226                 BNXT_TF_DBG(ERR, "Failed to alloc memory active dflt flows\n");
227                 return -ENOMEM;
228         }
229
230         /* Initialize the stack table. */
231         for (idx = 0; idx < flow_tbl->num_resources; idx++)
232                 flow_tbl->flow_tbl_stack[idx] = idx;
233
234         /* Ignore the first element in the list. */
235         flow_tbl->head_index = 1;
236         /* Tail points to the last entry in the list. */
237         flow_tbl->tail_index = flow_tbl->num_resources - 1;
238         return 0;
239 }
240
241 /*
242  * Helper function to deallocate the flow table.
243  *
244  * flow_db [in] Ptr to flow database structure
245  *
246  * Returns none.
247  */
248 static void
249 ulp_flow_db_dealloc_resource(struct bnxt_ulp_flow_db *flow_db)
250 {
251         struct bnxt_ulp_flow_tbl *flow_tbl = &flow_db->flow_tbl;
252
253         /* Free all the allocated tables in the flow table. */
254         if (flow_tbl->active_reg_flows) {
255                 rte_free(flow_tbl->active_reg_flows);
256                 flow_tbl->active_reg_flows = NULL;
257         }
258         if (flow_tbl->active_dflt_flows) {
259                 rte_free(flow_tbl->active_dflt_flows);
260                 flow_tbl->active_dflt_flows = NULL;
261         }
262
263         if (flow_tbl->flow_tbl_stack) {
264                 rte_free(flow_tbl->flow_tbl_stack);
265                 flow_tbl->flow_tbl_stack = NULL;
266         }
267
268         if (flow_tbl->flow_resources) {
269                 rte_free(flow_tbl->flow_resources);
270                 flow_tbl->flow_resources = NULL;
271         }
272 }
273
274 /*
275  * Helper function to add function id to the flow table
276  *
277  * flow_db [in] Ptr to flow table
278  * flow_id [in] The flow id of the flow
279  * func_id [in] The func_id to be set, for reset pass zero
280  *
281  * returns none
282  */
283 static void
284 ulp_flow_db_func_id_set(struct bnxt_ulp_flow_db *flow_db,
285                         uint32_t flow_id,
286                         uint32_t func_id)
287 {
288         /* set the function id in the function table */
289         if (flow_id < flow_db->func_id_tbl_size)
290                 flow_db->func_id_tbl[flow_id] = func_id;
291         else /* This should never happen */
292                 BNXT_TF_DBG(ERR, "Invalid flow id, flowdb corrupt\n");
293 }
294
295 /*
296  * Initialize the parent-child database. Memory is allocated in this
297  * call and assigned to the database
298  *
299  * flow_db [in] Ptr to flow table
300  * num_entries[in] - number of entries to allocate
301  *
302  * Returns 0 on success or negative number on failure.
303  */
304 static int32_t
305 ulp_flow_db_parent_tbl_init(struct bnxt_ulp_flow_db *flow_db,
306                             uint32_t num_entries)
307 {
308         struct ulp_fdb_parent_child_db *p_db;
309         uint32_t size, idx;
310
311         if (!num_entries)
312                 return 0;
313
314         /* update the sizes for the allocation */
315         p_db = &flow_db->parent_child_db;
316         p_db->child_bitset_size = (flow_db->flow_tbl.num_flows /
317                                    sizeof(uint64_t)) + 1; /* size in bytes */
318         p_db->child_bitset_size = ULP_BYTE_ROUND_OFF_8(p_db->child_bitset_size);
319         p_db->entries_count = num_entries;
320
321         /* allocate the memory */
322         p_db->parent_flow_tbl = rte_zmalloc("fdb parent flow tbl",
323                                             sizeof(struct ulp_fdb_parent_info) *
324                                             p_db->entries_count, 0);
325         if (!p_db->parent_flow_tbl) {
326                 BNXT_TF_DBG(ERR,
327                             "Failed to allocate memory fdb parent flow tbl\n");
328                 return -ENOMEM;
329         }
330         size = p_db->child_bitset_size * p_db->entries_count;
331
332         /*
333          * allocate the big chunk of memory to be statically carved into
334          * child_fid_bitset pointer.
335          */
336         p_db->parent_flow_tbl_mem = rte_zmalloc("fdb parent flow tbl mem",
337                                                 size,
338                                                 ULP_BUFFER_ALIGN_64_BYTE);
339         if (!p_db->parent_flow_tbl_mem) {
340                 BNXT_TF_DBG(ERR,
341                             "Failed to allocate memory fdb parent flow mem\n");
342                 return -ENOMEM;
343         }
344
345         /* set the pointers in parent table to their offsets */
346         for (idx = 0 ; idx < p_db->entries_count; idx++) {
347                 p_db->parent_flow_tbl[idx].child_fid_bitset =
348                         (uint64_t *)&p_db->parent_flow_tbl_mem[idx *
349                         p_db->child_bitset_size];
350         }
351         /* success */
352         return 0;
353 }
354
355 /*
356  * Deinitialize the parent-child database. Memory is deallocated in
357  * this call and all flows should have been purged before this
358  * call.
359  *
360  * flow_db [in] Ptr to flow table
361  *
362  * Returns none
363  */
364 static void
365 ulp_flow_db_parent_tbl_deinit(struct bnxt_ulp_flow_db *flow_db)
366 {
367         /* free the memory related to parent child database */
368         if (flow_db->parent_child_db.parent_flow_tbl_mem) {
369                 rte_free(flow_db->parent_child_db.parent_flow_tbl_mem);
370                 flow_db->parent_child_db.parent_flow_tbl_mem = NULL;
371         }
372         if (flow_db->parent_child_db.parent_flow_tbl) {
373                 rte_free(flow_db->parent_child_db.parent_flow_tbl);
374                 flow_db->parent_child_db.parent_flow_tbl = NULL;
375         }
376 }
377
378 /*
379  * Initialize the flow database. Memory is allocated in this
380  * call and assigned to the flow database.
381  *
382  * ulp_ctxt [in] Ptr to ulp context
383  *
384  * Returns 0 on success or negative number on failure.
385  */
386 int32_t
387 ulp_flow_db_init(struct bnxt_ulp_context *ulp_ctxt)
388 {
389         struct bnxt_ulp_device_params *dparms;
390         struct bnxt_ulp_flow_tbl *flow_tbl;
391         struct bnxt_ulp_flow_db *flow_db;
392         uint32_t dev_id, num_flows;
393         enum bnxt_ulp_flow_mem_type mtype;
394
395         /* Get the dev specific number of flows that needed to be supported. */
396         if (bnxt_ulp_cntxt_dev_id_get(ulp_ctxt, &dev_id)) {
397                 BNXT_TF_DBG(ERR, "Invalid device id\n");
398                 return -EINVAL;
399         }
400
401         dparms = bnxt_ulp_device_params_get(dev_id);
402         if (!dparms) {
403                 BNXT_TF_DBG(ERR, "could not fetch the device params\n");
404                 return -ENODEV;
405         }
406
407         flow_db = rte_zmalloc("bnxt_ulp_flow_db",
408                               sizeof(struct bnxt_ulp_flow_db), 0);
409         if (!flow_db) {
410                 BNXT_TF_DBG(ERR,
411                             "Failed to allocate memory for flow table ptr\n");
412                 return -ENOMEM;
413         }
414
415         /* Attach the flow database to the ulp context. */
416         bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, flow_db);
417
418         /* Determine the number of flows based on EM type */
419         bnxt_ulp_cntxt_mem_type_get(ulp_ctxt, &mtype);
420         if (mtype == BNXT_ULP_FLOW_MEM_TYPE_INT)
421                 num_flows = dparms->int_flow_db_num_entries;
422         else
423                 num_flows = dparms->ext_flow_db_num_entries;
424
425         /* Populate the regular flow table limits. */
426         flow_tbl = &flow_db->flow_tbl;
427         flow_tbl->num_flows = num_flows + 1;
428         flow_tbl->num_resources = ((num_flows + 1) *
429                                    dparms->num_resources_per_flow);
430
431         /* Include the default flow table limits. */
432         flow_tbl->num_flows += (BNXT_FLOW_DB_DEFAULT_NUM_FLOWS + 1);
433         flow_tbl->num_resources += ((BNXT_FLOW_DB_DEFAULT_NUM_FLOWS + 1) *
434                                     BNXT_FLOW_DB_DEFAULT_NUM_RESOURCES);
435
436         /* Allocate the resource for the flow table. */
437         if (ulp_flow_db_alloc_resource(flow_db))
438                 goto error_free;
439
440         /* add 1 since we are not using index 0 for flow id */
441         flow_db->func_id_tbl_size = flow_tbl->num_flows + 1;
442         /* Allocate the function Id table */
443         flow_db->func_id_tbl = rte_zmalloc("bnxt_ulp_flow_db_func_id_table",
444                                            flow_db->func_id_tbl_size *
445                                            sizeof(uint16_t), 0);
446         if (!flow_db->func_id_tbl) {
447                 BNXT_TF_DBG(ERR,
448                             "Failed to allocate mem for flow table func id\n");
449                 goto error_free;
450         }
451         /* initialize the parent child database */
452         if (ulp_flow_db_parent_tbl_init(flow_db,
453                                         dparms->fdb_parent_flow_entries)) {
454                 BNXT_TF_DBG(ERR,
455                             "Failed to allocate mem for parent child db\n");
456                 goto error_free;
457         }
458
459         /* All good so return. */
460         BNXT_TF_DBG(INFO, "FlowDB initialized with %d flows.\n",
461                     flow_tbl->num_flows);
462         return 0;
463 error_free:
464         ulp_flow_db_deinit(ulp_ctxt);
465         return -ENOMEM;
466 }
467
468 /*
469  * Deinitialize the flow database. Memory is deallocated in
470  * this call and all flows should have been purged before this
471  * call.
472  *
473  * ulp_ctxt [in] Ptr to ulp context
474  *
475  * Returns 0 on success.
476  */
477 int32_t
478 ulp_flow_db_deinit(struct bnxt_ulp_context *ulp_ctxt)
479 {
480         struct bnxt_ulp_flow_db *flow_db;
481
482         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
483         if (!flow_db)
484                 return -EINVAL;
485
486         /* Detach the flow database from the ulp context. */
487         bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, NULL);
488
489         /* Free up all the memory. */
490         ulp_flow_db_parent_tbl_deinit(flow_db);
491         ulp_flow_db_dealloc_resource(flow_db);
492         rte_free(flow_db->func_id_tbl);
493         rte_free(flow_db);
494
495         return 0;
496 }
497
498 /*
499  * Allocate the flow database entry
500  *
501  * ulp_ctxt [in] Ptr to ulp_context
502  * flow_type [in] - specify default or regular
503  * func_id [in].function id of the ingress port
504  * fid [out] The index to the flow entry
505  *
506  * returns 0 on success and negative on failure.
507  */
508 int32_t
509 ulp_flow_db_fid_alloc(struct bnxt_ulp_context *ulp_ctxt,
510                       enum bnxt_ulp_fdb_type flow_type,
511                       uint16_t func_id,
512                       uint32_t *fid)
513 {
514         struct bnxt_ulp_flow_db *flow_db;
515         struct bnxt_ulp_flow_tbl *flow_tbl;
516
517         *fid = 0; /* Initialize fid to invalid value */
518         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
519         if (!flow_db) {
520                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
521                 return -EINVAL;
522         }
523
524         if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
525                 BNXT_TF_DBG(ERR, "Invalid flow type\n");
526                 return -EINVAL;
527         }
528
529         flow_tbl = &flow_db->flow_tbl;
530         /* check for max flows */
531         if (flow_tbl->num_flows <= flow_tbl->head_index) {
532                 BNXT_TF_DBG(ERR, "Flow database has reached max flows\n");
533                 return -ENOMEM;
534         }
535         if (flow_tbl->tail_index <= (flow_tbl->head_index + 1)) {
536                 BNXT_TF_DBG(ERR, "Flow database has reached max resources\n");
537                 return -ENOMEM;
538         }
539         *fid = flow_tbl->flow_tbl_stack[flow_tbl->head_index];
540         flow_tbl->head_index++;
541
542         /* Set the flow type */
543         ulp_flow_db_active_flows_bit_set(flow_db, flow_type, *fid, 1);
544
545         /* function id update is only valid for regular flow table */
546         if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR)
547                 ulp_flow_db_func_id_set(flow_db, *fid, func_id);
548
549         /* return success */
550         return 0;
551 }
552
553 /*
554  * Allocate the flow database entry.
555  * The params->critical_resource has to be set to 0 to allocate a new resource.
556  *
557  * ulp_ctxt [in] Ptr to ulp_context
558  * flow_type [in] Specify it is regular or default flow
559  * fid [in] The index to the flow entry
560  * params [in] The contents to be copied into resource
561  *
562  * returns 0 on success and negative on failure.
563  */
564 int32_t
565 ulp_flow_db_resource_add(struct bnxt_ulp_context *ulp_ctxt,
566                          enum bnxt_ulp_fdb_type flow_type,
567                          uint32_t fid,
568                          struct ulp_flow_db_res_params *params)
569 {
570         struct bnxt_ulp_flow_db *flow_db;
571         struct bnxt_ulp_flow_tbl *flow_tbl;
572         struct ulp_fdb_resource_info *resource, *fid_resource;
573         uint32_t idx;
574
575         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
576         if (!flow_db) {
577                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
578                 return -EINVAL;
579         }
580
581         if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
582                 BNXT_TF_DBG(ERR, "Invalid flow type\n");
583                 return -EINVAL;
584         }
585
586         flow_tbl = &flow_db->flow_tbl;
587         /* check for max flows */
588         if (fid >= flow_tbl->num_flows || !fid) {
589                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
590                 return -EINVAL;
591         }
592
593         /* check if the flow is active or not */
594         if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) {
595                 BNXT_TF_DBG(ERR, "flow does not exist\n");
596                 return -EINVAL;
597         }
598
599         /* check for max resource */
600         if ((flow_tbl->head_index + 1) >= flow_tbl->tail_index) {
601                 BNXT_TF_DBG(ERR, "Flow db has reached max resources\n");
602                 return -ENOMEM;
603         }
604         fid_resource = &flow_tbl->flow_resources[fid];
605
606         if (!params->critical_resource) {
607                 /* Not the critical_resource so allocate a resource */
608                 idx = flow_tbl->flow_tbl_stack[flow_tbl->tail_index];
609                 resource = &flow_tbl->flow_resources[idx];
610                 flow_tbl->tail_index--;
611
612                 /* Update the chain list of resource*/
613                 ULP_FLOW_DB_RES_NXT_SET(resource->nxt_resource_idx,
614                                         fid_resource->nxt_resource_idx);
615                 /* update the contents */
616                 ulp_flow_db_res_params_to_info(resource, params);
617                 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx);
618                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
619                                         idx);
620         } else {
621                 /* critical resource. Just update the fid resource */
622                 ulp_flow_db_res_params_to_info(fid_resource, params);
623         }
624
625         if (params->resource_type == TF_TBL_TYPE_ACT_STATS_64 &&
626             params->resource_sub_type ==
627             BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_INT_COUNT) {
628                 /* Store the first HW counter ID for this table */
629                 if (!ulp_fc_mgr_start_idx_isset(ulp_ctxt, params->direction))
630                         ulp_fc_mgr_start_idx_set(ulp_ctxt, params->direction,
631                                                  params->resource_hndl);
632
633                 ulp_fc_mgr_cntr_set(ulp_ctxt, params->direction,
634                                     params->resource_hndl);
635
636                 if (!ulp_fc_mgr_thread_isstarted(ulp_ctxt))
637                         ulp_fc_mgr_thread_start(ulp_ctxt);
638         }
639
640         /* all good, return success */
641         return 0;
642 }
643
644 /*
645  * Free the flow database entry.
646  * The params->critical_resource has to be set to 1 to free the first resource.
647  *
648  * ulp_ctxt [in] Ptr to ulp_context
649  * flow_type [in] Specify it is regular or default flow
650  * fid [in] The index to the flow entry
651  * params [in/out] The contents to be copied into params.
652  * Onlythe critical_resource needs to be set by the caller.
653  *
654  * Returns 0 on success and negative on failure.
655  */
656 int32_t
657 ulp_flow_db_resource_del(struct bnxt_ulp_context *ulp_ctxt,
658                          enum bnxt_ulp_fdb_type flow_type,
659                          uint32_t fid,
660                          struct ulp_flow_db_res_params *params)
661 {
662         struct bnxt_ulp_flow_db *flow_db;
663         struct bnxt_ulp_flow_tbl *flow_tbl;
664         struct ulp_fdb_resource_info *nxt_resource, *fid_resource;
665         uint32_t nxt_idx = 0;
666
667         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
668         if (!flow_db) {
669                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
670                 return -EINVAL;
671         }
672
673         if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
674                 BNXT_TF_DBG(ERR, "Invalid flow type\n");
675                 return -EINVAL;
676         }
677
678         flow_tbl = &flow_db->flow_tbl;
679         /* check for max flows */
680         if (fid >= flow_tbl->num_flows || !fid) {
681                 BNXT_TF_DBG(ERR, "Invalid flow index %x\n", fid);
682                 return -EINVAL;
683         }
684
685         /* check if the flow is active or not */
686         if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) {
687                 BNXT_TF_DBG(ERR, "flow does not exist\n");
688                 return -EINVAL;
689         }
690
691         fid_resource = &flow_tbl->flow_resources[fid];
692         if (!params->critical_resource) {
693                 /* Not the critical resource so free the resource */
694                 ULP_FLOW_DB_RES_NXT_SET(nxt_idx,
695                                         fid_resource->nxt_resource_idx);
696                 if (!nxt_idx) {
697                         /* reached end of resources */
698                         return -ENOENT;
699                 }
700                 nxt_resource = &flow_tbl->flow_resources[nxt_idx];
701
702                 /* connect the fid resource to the next resource */
703                 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx);
704                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
705                                         nxt_resource->nxt_resource_idx);
706
707                 /* update the contents to be given to caller */
708                 ulp_flow_db_res_info_to_params(nxt_resource, params);
709
710                 /* Delete the nxt_resource */
711                 memset(nxt_resource, 0, sizeof(struct ulp_fdb_resource_info));
712
713                 /* add it to the free list */
714                 flow_tbl->tail_index++;
715                 if (flow_tbl->tail_index >= flow_tbl->num_resources) {
716                         BNXT_TF_DBG(ERR, "FlowDB:Tail reached max\n");
717                         return -ENOENT;
718                 }
719                 flow_tbl->flow_tbl_stack[flow_tbl->tail_index] = nxt_idx;
720
721         } else {
722                 /* Critical resource. copy the contents and exit */
723                 ulp_flow_db_res_info_to_params(fid_resource, params);
724                 ULP_FLOW_DB_RES_NXT_SET(nxt_idx,
725                                         fid_resource->nxt_resource_idx);
726                 memset(fid_resource, 0, sizeof(struct ulp_fdb_resource_info));
727                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
728                                         nxt_idx);
729         }
730
731         /* Now that the HW Flow counter resource is deleted, reset it's
732          * corresponding slot in the SW accumulation table in the Flow Counter
733          * manager
734          */
735         if (params->resource_type == TF_TBL_TYPE_ACT_STATS_64 &&
736             params->resource_sub_type ==
737             BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_INT_COUNT) {
738                 ulp_fc_mgr_cntr_reset(ulp_ctxt, params->direction,
739                                       params->resource_hndl);
740         }
741
742         /* all good, return success */
743         return 0;
744 }
745
746 /*
747  * Free the flow database entry
748  *
749  * ulp_ctxt [in] Ptr to ulp_context
750  * flow_type [in] - specify default or regular
751  * fid [in] The index to the flow entry
752  *
753  * returns 0 on success and negative on failure.
754  */
755 int32_t
756 ulp_flow_db_fid_free(struct bnxt_ulp_context *ulp_ctxt,
757                      enum bnxt_ulp_fdb_type flow_type,
758                      uint32_t fid)
759 {
760         struct bnxt_ulp_flow_db *flow_db;
761         struct bnxt_ulp_flow_tbl *flow_tbl;
762
763         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
764         if (!flow_db) {
765                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
766                 return -EINVAL;
767         }
768
769         if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
770                 BNXT_TF_DBG(ERR, "Invalid flow type\n");
771                 return -EINVAL;
772         }
773
774         flow_tbl = &flow_db->flow_tbl;
775
776         /* check for limits of fid */
777         if (fid >= flow_tbl->num_flows || !fid) {
778                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
779                 return -EINVAL;
780         }
781
782         /* check if the flow is active or not */
783         if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) {
784                 BNXT_TF_DBG(ERR, "flow does not exist\n");
785                 return -EINVAL;
786         }
787         flow_tbl->head_index--;
788         if (!flow_tbl->head_index) {
789                 BNXT_TF_DBG(ERR, "FlowDB: Head Ptr is zero\n");
790                 return -ENOENT;
791         }
792         flow_tbl->flow_tbl_stack[flow_tbl->head_index] = fid;
793
794         /* Clear the flows bitmap */
795         ulp_flow_db_active_flows_bit_set(flow_db, flow_type, fid, 0);
796
797         if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR)
798                 ulp_flow_db_func_id_set(flow_db, fid, 0);
799
800         /* all good, return success */
801         return 0;
802 }
803
804 /*
805  * Get the flow database entry details
806  *
807  * ulp_ctxt [in] Ptr to ulp_context
808  * flow_type [in] - specify default or regular
809  * fid [in] The index to the flow entry
810  * nxt_idx [in/out] the index to the next entry
811  * params [out] The contents to be copied into params.
812  *
813  * returns 0 on success and negative on failure.
814  */
815 int32_t
816 ulp_flow_db_resource_get(struct bnxt_ulp_context *ulp_ctxt,
817                          enum bnxt_ulp_fdb_type flow_type,
818                          uint32_t fid,
819                          uint32_t *nxt_idx,
820                          struct ulp_flow_db_res_params *params)
821 {
822         struct bnxt_ulp_flow_db *flow_db;
823         struct bnxt_ulp_flow_tbl *flow_tbl;
824         struct ulp_fdb_resource_info *nxt_resource, *fid_resource;
825
826         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
827         if (!flow_db) {
828                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
829                 return -EINVAL;
830         }
831
832         if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
833                 BNXT_TF_DBG(ERR, "Invalid flow type\n");
834                 return -EINVAL;
835         }
836
837         flow_tbl = &flow_db->flow_tbl;
838
839         /* check for limits of fid */
840         if (fid >= flow_tbl->num_flows || !fid) {
841                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
842                 return -EINVAL;
843         }
844
845         /* check if the flow is active or not */
846         if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) {
847                 BNXT_TF_DBG(ERR, "flow does not exist\n");
848                 return -EINVAL;
849         }
850
851         if (!*nxt_idx) {
852                 fid_resource = &flow_tbl->flow_resources[fid];
853                 ulp_flow_db_res_info_to_params(fid_resource, params);
854                 ULP_FLOW_DB_RES_NXT_SET(*nxt_idx,
855                                         fid_resource->nxt_resource_idx);
856         } else {
857                 nxt_resource = &flow_tbl->flow_resources[*nxt_idx];
858                 ulp_flow_db_res_info_to_params(nxt_resource, params);
859                 *nxt_idx = 0;
860                 ULP_FLOW_DB_RES_NXT_SET(*nxt_idx,
861                                         nxt_resource->nxt_resource_idx);
862         }
863
864         /* all good, return success */
865         return 0;
866 }
867
868 /*
869  * Get the flow database entry iteratively
870  *
871  * flow_tbl [in] Ptr to flow table
872  * flow_type [in] - specify default or regular
873  * fid [in/out] The index to the flow entry
874  *
875  * returns 0 on success and negative on failure.
876  */
877 static int32_t
878 ulp_flow_db_next_entry_get(struct bnxt_ulp_flow_db *flow_db,
879                            enum bnxt_ulp_fdb_type flow_type,
880                            uint32_t *fid)
881 {
882         uint32_t lfid = *fid;
883         uint32_t idx, s_idx, mod_fid;
884         uint64_t bs;
885         uint64_t *active_flows;
886         struct bnxt_ulp_flow_tbl *flowtbl = &flow_db->flow_tbl;
887
888         if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR)
889                 active_flows = flowtbl->active_reg_flows;
890         else
891                 active_flows = flowtbl->active_dflt_flows;
892
893         do {
894                 /* increment the flow id to find the next valid flow id */
895                 lfid++;
896                 if (lfid >= flowtbl->num_flows)
897                         return -ENOENT;
898                 idx = lfid / ULP_INDEX_BITMAP_SIZE;
899                 mod_fid = lfid % ULP_INDEX_BITMAP_SIZE;
900                 s_idx = idx;
901                 while (!(bs = active_flows[idx])) {
902                         idx++;
903                         if ((idx * ULP_INDEX_BITMAP_SIZE) >= flowtbl->num_flows)
904                                 return -ENOENT;
905                 }
906                 /*
907                  * remove the previous bits in the bitset bs to find the
908                  * next non zero bit in the bitset. This needs to be done
909                  * only if the idx is same as he one you started.
910                  */
911                 if (s_idx == idx)
912                         bs &= (-1UL >> mod_fid);
913                 lfid = (idx * ULP_INDEX_BITMAP_SIZE) + __builtin_clzl(bs);
914                 if (*fid >= lfid) {
915                         BNXT_TF_DBG(ERR, "Flow Database is corrupt\n");
916                         return -ENOENT;
917                 }
918         } while (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type,
919                                                       lfid));
920
921         /* all good, return success */
922         *fid = lfid;
923         return 0;
924 }
925
926 /*
927  * Flush all flows in the flow database.
928  *
929  * ulp_ctxt [in] Ptr to ulp context
930  * flow_type [in] - specify default or regular
931  *
932  * returns 0 on success or negative number on failure
933  */
934 int32_t
935 ulp_flow_db_flush_flows(struct bnxt_ulp_context *ulp_ctx,
936                         enum bnxt_ulp_fdb_type flow_type)
937 {
938         uint32_t fid = 0;
939         struct bnxt_ulp_flow_db *flow_db;
940
941         if (!ulp_ctx) {
942                 BNXT_TF_DBG(ERR, "Invalid Argument\n");
943                 return -EINVAL;
944         }
945
946         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
947         if (!flow_db) {
948                 BNXT_TF_DBG(ERR, "Flow database not found\n");
949                 return -EINVAL;
950         }
951         if (bnxt_ulp_cntxt_acquire_fdb_lock(ulp_ctx)) {
952                 BNXT_TF_DBG(ERR, "Flow db lock acquire failed\n");
953                 return -EINVAL;
954         }
955
956         while (!ulp_flow_db_next_entry_get(flow_db, flow_type, &fid))
957                 ulp_mapper_resources_free(ulp_ctx, flow_type, fid);
958
959         bnxt_ulp_cntxt_release_fdb_lock(ulp_ctx);
960
961         return 0;
962 }
963
964 /*
965  * Flush all flows in the flow database that belong to a device function.
966  *
967  * ulp_ctxt [in] Ptr to ulp context
968  * func_id [in] - The port function id
969  *
970  * returns 0 on success or negative number on failure
971  */
972 int32_t
973 ulp_flow_db_function_flow_flush(struct bnxt_ulp_context *ulp_ctx,
974                                 uint16_t func_id)
975 {
976         uint32_t flow_id = 0;
977         struct bnxt_ulp_flow_db *flow_db;
978
979         if (!ulp_ctx || !func_id) {
980                 BNXT_TF_DBG(ERR, "Invalid Argument\n");
981                 return -EINVAL;
982         }
983
984         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
985         if (!flow_db) {
986                 BNXT_TF_DBG(ERR, "Flow database not found\n");
987                 return -EINVAL;
988         }
989         if (bnxt_ulp_cntxt_acquire_fdb_lock(ulp_ctx)) {
990                 BNXT_TF_DBG(ERR, "Flow db lock acquire failed\n");
991                 return -EINVAL;
992         }
993
994         while (!ulp_flow_db_next_entry_get(flow_db, BNXT_ULP_FDB_TYPE_REGULAR,
995                                            &flow_id)) {
996                 if (flow_db->func_id_tbl[flow_id] == func_id)
997                         ulp_mapper_resources_free(ulp_ctx,
998                                                   BNXT_ULP_FDB_TYPE_REGULAR,
999                                                   flow_id);
1000         }
1001         bnxt_ulp_cntxt_release_fdb_lock(ulp_ctx);
1002         return 0;
1003 }
1004
1005 /*
1006  * Flush all flows in the flow database that are associated with the session.
1007  *
1008  * ulp_ctxt [in] Ptr to ulp context
1009  *
1010  * returns 0 on success or negative number on failure
1011  */
1012 int32_t
1013 ulp_flow_db_session_flow_flush(struct bnxt_ulp_context *ulp_ctx)
1014 {
1015         /*
1016          * TBD: Tf core implementation of FW session flush shall change this
1017          * implementation.
1018          */
1019         return ulp_flow_db_flush_flows(ulp_ctx, BNXT_ULP_FDB_TYPE_REGULAR);
1020 }
1021
1022 /*
1023  * Check that flow id matches the function id or not
1024  *
1025  * ulp_ctxt [in] Ptr to ulp context
1026  * flow_db [in] Ptr to flow table
1027  * func_id [in] The func_id to be set, for reset pass zero.
1028  *
1029  * returns true on success or false on failure
1030  */
1031 bool
1032 ulp_flow_db_validate_flow_func(struct bnxt_ulp_context *ulp_ctx,
1033                                uint32_t flow_id,
1034                                uint32_t func_id)
1035 {
1036         struct bnxt_ulp_flow_db *flow_db;
1037
1038         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
1039         if (!flow_db) {
1040                 BNXT_TF_DBG(ERR, "Flow database not found\n");
1041                 return false;
1042         }
1043
1044         /* set the function id in the function table */
1045         if (flow_id < flow_db->func_id_tbl_size && func_id &&
1046             flow_db->func_id_tbl[flow_id] == func_id)
1047                 return true;
1048
1049         return false;
1050 }
1051
1052 /*
1053  * Internal api to traverse the resource list within a flow
1054  * and match a resource based on resource func and resource
1055  * sub type. This api should be used only for resources that
1056  * are unique and do not have multiple instances of resource
1057  * func and sub type combination since it will return only
1058  * the first match.
1059  */
1060 static int32_t
1061 ulp_flow_db_resource_params_get(struct bnxt_ulp_context *ulp_ctx,
1062                                 enum bnxt_ulp_fdb_type flow_type,
1063                                 uint32_t flow_id,
1064                                 uint32_t resource_func,
1065                                 uint32_t res_subtype,
1066                                 struct ulp_flow_db_res_params *params)
1067 {
1068         struct bnxt_ulp_flow_db *flow_db;
1069         struct bnxt_ulp_flow_tbl *flow_tbl;
1070         struct ulp_fdb_resource_info *fid_res;
1071         uint32_t res_id;
1072
1073         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
1074         if (!flow_db) {
1075                 BNXT_TF_DBG(ERR, "Flow database not found\n");
1076                 return -EINVAL;
1077         }
1078
1079         if (!params) {
1080                 BNXT_TF_DBG(ERR, "invalid argument\n");
1081                 return -EINVAL;
1082         }
1083
1084         if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
1085                 BNXT_TF_DBG(ERR, "Invalid flow type\n");
1086                 return -EINVAL;
1087         }
1088
1089         flow_tbl = &flow_db->flow_tbl;
1090
1091         /* check for limits of fid */
1092         if (flow_id >= flow_tbl->num_flows || !flow_id) {
1093                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
1094                 return -EINVAL;
1095         }
1096
1097         /* check if the flow is active or not */
1098         if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, flow_id)) {
1099                 BNXT_TF_DBG(ERR, "flow does not exist\n");
1100                 return -EINVAL;
1101         }
1102         /* Iterate the resource to get the resource handle */
1103         res_id =  flow_id;
1104         memset(params, 0, sizeof(struct ulp_flow_db_res_params));
1105         while (res_id) {
1106                 fid_res = &flow_tbl->flow_resources[res_id];
1107                 if (ulp_flow_db_resource_func_get(fid_res) == resource_func) {
1108                         if (resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) {
1109                                 if (res_subtype == fid_res->resource_sub_type) {
1110                                         ulp_flow_db_res_info_to_params(fid_res,
1111                                                                        params);
1112                                         return 0;
1113                                 }
1114
1115                         } else if (resource_func ==
1116                                    BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE ||
1117                                    resource_func ==
1118                                    BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) {
1119                                 ulp_flow_db_res_info_to_params(fid_res,
1120                                                                params);
1121                                 return 0;
1122                         }
1123                 }
1124                 res_id = 0;
1125                 ULP_FLOW_DB_RES_NXT_SET(res_id, fid_res->nxt_resource_idx);
1126         }
1127         return -ENOENT;
1128 }
1129
1130 /*
1131  * Api to get the cfa action pointer from a flow.
1132  *
1133  * ulp_ctxt [in] Ptr to ulp context
1134  * flow_id [in] flow id
1135  * cfa_action [out] The resource handle stored in the flow database
1136  *
1137  * returns 0 on success
1138  */
1139 int32_t
1140 ulp_default_flow_db_cfa_action_get(struct bnxt_ulp_context *ulp_ctx,
1141                                    uint32_t flow_id,
1142                                    uint16_t *cfa_action)
1143 {
1144         uint8_t sub_type = BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_VFR_CFA_ACTION;
1145         struct ulp_flow_db_res_params params;
1146         int32_t rc;
1147
1148         rc = ulp_flow_db_resource_params_get(ulp_ctx,
1149                                              BNXT_ULP_FDB_TYPE_DEFAULT,
1150                                              flow_id,
1151                                              BNXT_ULP_RESOURCE_FUNC_INDEX_TABLE,
1152                                              sub_type, &params);
1153         if (rc) {
1154                 BNXT_TF_DBG(ERR, "CFA Action ptr not found for flow id %u\n",
1155                             flow_id);
1156                 return -ENOENT;
1157         }
1158         *cfa_action = params.resource_hndl;
1159         return 0;
1160 }
1161
1162 /* internal validation function for parent flow tbl */
1163 static struct bnxt_ulp_flow_db *
1164 ulp_flow_db_parent_arg_validation(struct bnxt_ulp_context *ulp_ctxt,
1165                                   uint32_t fid)
1166 {
1167         struct bnxt_ulp_flow_db *flow_db;
1168
1169         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
1170         if (!flow_db) {
1171                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
1172                 return NULL;
1173         }
1174
1175         /* check for max flows */
1176         if (fid >= flow_db->flow_tbl.num_flows || !fid) {
1177                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
1178                 return NULL;
1179         }
1180
1181         /* No support for parent child db then just exit */
1182         if (!flow_db->parent_child_db.entries_count) {
1183                 BNXT_TF_DBG(ERR, "parent child db not supported\n");
1184                 return NULL;
1185         }
1186
1187         return flow_db;
1188 }
1189
1190 /*
1191  * Allocate the entry in the parent-child database
1192  *
1193  * ulp_ctxt [in] Ptr to ulp_context
1194  * fid [in] The flow id to the flow entry
1195  *
1196  * returns index on success and negative on failure.
1197  */
1198 int32_t
1199 ulp_flow_db_parent_flow_alloc(struct bnxt_ulp_context *ulp_ctxt,
1200                               uint32_t fid)
1201 {
1202         struct bnxt_ulp_flow_db *flow_db;
1203         struct ulp_fdb_parent_child_db *p_pdb;
1204         uint32_t idx, free_idx = 0;
1205
1206         /* validate the arguments */
1207         flow_db = ulp_flow_db_parent_arg_validation(ulp_ctxt, fid);
1208         if (!flow_db) {
1209                 BNXT_TF_DBG(ERR, "parent child db validation failed\n");
1210                 return -EINVAL;
1211         }
1212
1213         p_pdb = &flow_db->parent_child_db;
1214         for (idx = 0; idx < p_pdb->entries_count; idx++) {
1215                 if (p_pdb->parent_flow_tbl[idx].parent_fid == fid) {
1216                         BNXT_TF_DBG(ERR, "fid is already allocated\n");
1217                         return -EINVAL;
1218                 }
1219                 if (!p_pdb->parent_flow_tbl[idx].parent_fid && !free_idx)
1220                         free_idx = idx + 1;
1221         }
1222         /* no free slots */
1223         if (!free_idx) {
1224                 BNXT_TF_DBG(ERR, "parent child db is full\n");
1225                 return -ENOMEM;
1226         }
1227
1228         free_idx -= 1;
1229         /* set the Fid in the parent child */
1230         p_pdb->parent_flow_tbl[free_idx].parent_fid = fid;
1231         return free_idx;
1232 }
1233
1234 /*
1235  * Free the entry in the parent-child database
1236  *
1237  * ulp_ctxt [in] Ptr to ulp_context
1238  * fid [in] The flow id to the flow entry
1239  *
1240  * returns 0 on success and negative on failure.
1241  */
1242 int32_t
1243 ulp_flow_db_parent_flow_free(struct bnxt_ulp_context *ulp_ctxt,
1244                              uint32_t fid)
1245 {
1246         struct bnxt_ulp_flow_db *flow_db;
1247         struct ulp_fdb_parent_child_db *p_pdb;
1248         uint32_t idx;
1249
1250         /* validate the arguments */
1251         flow_db = ulp_flow_db_parent_arg_validation(ulp_ctxt, fid);
1252         if (!flow_db) {
1253                 BNXT_TF_DBG(ERR, "parent child db validation failed\n");
1254                 return -EINVAL;
1255         }
1256
1257         p_pdb = &flow_db->parent_child_db;
1258         for (idx = 0; idx < p_pdb->entries_count; idx++) {
1259                 if (p_pdb->parent_flow_tbl[idx].parent_fid == fid) {
1260                         /* free the contents */
1261                         p_pdb->parent_flow_tbl[idx].parent_fid = 0;
1262                         memset(p_pdb->parent_flow_tbl[idx].child_fid_bitset,
1263                                0, p_pdb->child_bitset_size);
1264                         return 0;
1265                 }
1266         }
1267         BNXT_TF_DBG(ERR, "parent entry not found = %x\n", fid);
1268         return -EINVAL;
1269 }
1270
1271 /*
1272  * Set or reset the child flow in the parent-child database
1273  *
1274  * ulp_ctxt [in] Ptr to ulp_context
1275  * parent_fid [in] The flow id of the parent flow entry
1276  * child_fid [in] The flow id of the child flow entry
1277  * set_flag [in] Use 1 for setting child, 0 to reset
1278  *
1279  * returns zero on success and negative on failure.
1280  */
1281 int32_t
1282 ulp_flow_db_parent_child_flow_set(struct bnxt_ulp_context *ulp_ctxt,
1283                                   uint32_t parent_fid,
1284                                   uint32_t child_fid,
1285                                   uint32_t set_flag)
1286 {
1287         struct bnxt_ulp_flow_db *flow_db;
1288         struct ulp_fdb_parent_child_db *p_pdb;
1289         uint32_t idx, a_idx;
1290         uint64_t *t;
1291
1292         /* validate the arguments */
1293         flow_db = ulp_flow_db_parent_arg_validation(ulp_ctxt, parent_fid);
1294         if (!flow_db) {
1295                 BNXT_TF_DBG(ERR, "parent child db validation failed\n");
1296                 return -EINVAL;
1297         }
1298
1299         /* check for fid validity */
1300         if (child_fid >= flow_db->flow_tbl.num_flows || !child_fid) {
1301                 BNXT_TF_DBG(ERR, "Invalid child flow index %x\n", child_fid);
1302                 return -EINVAL;
1303         }
1304
1305         p_pdb = &flow_db->parent_child_db;
1306         a_idx = child_fid / ULP_INDEX_BITMAP_SIZE;
1307         for (idx = 0; idx < p_pdb->entries_count; idx++) {
1308                 if (p_pdb->parent_flow_tbl[idx].parent_fid == parent_fid) {
1309                         t = p_pdb->parent_flow_tbl[idx].child_fid_bitset;
1310                         if (set_flag)
1311                                 ULP_INDEX_BITMAP_SET(t[a_idx], child_fid);
1312                         else
1313                                 ULP_INDEX_BITMAP_RESET(t[a_idx], child_fid);
1314                         return 0;
1315                 }
1316         }
1317         BNXT_TF_DBG(ERR, "Unable to set the parent-child flow %x:%x\n",
1318                     parent_fid, child_fid);
1319         return -1;
1320 }
1321
1322 /*
1323  * Get the parent index from the parent-child database
1324  *
1325  * ulp_ctxt [in] Ptr to ulp_context
1326  * parent_fid [in] The flow id of the parent flow entry
1327  * parent_idx [out] The parent index of parent flow entry
1328  *
1329  * returns zero on success and negative on failure.
1330  */
1331 int32_t
1332 ulp_flow_db_parent_flow_idx_get(struct bnxt_ulp_context *ulp_ctxt,
1333                                 uint32_t parent_fid,
1334                                 uint32_t *parent_idx)
1335 {
1336         struct bnxt_ulp_flow_db *flow_db;
1337         struct ulp_fdb_parent_child_db *p_pdb;
1338         uint32_t idx;
1339
1340         /* validate the arguments */
1341         flow_db = ulp_flow_db_parent_arg_validation(ulp_ctxt, parent_fid);
1342         if (!flow_db) {
1343                 BNXT_TF_DBG(ERR, "parent child db validation failed\n");
1344                 return -EINVAL;
1345         }
1346
1347         p_pdb = &flow_db->parent_child_db;
1348         for (idx = 0; idx < p_pdb->entries_count; idx++) {
1349                 if (p_pdb->parent_flow_tbl[idx].parent_fid == parent_fid) {
1350                         *parent_idx = idx;
1351                         return 0;
1352                 }
1353         }
1354         BNXT_TF_DBG(ERR, "Unable to get the parent flow %x\n", parent_fid);
1355         return -1;
1356 }
1357
1358 /*
1359  * Get the next child flow in the parent-child database
1360  *
1361  * ulp_ctxt [in] Ptr to ulp_context
1362  * parent_fid [in] The flow id of the parent flow entry
1363  * child_fid [in/out] The flow id of the child flow entry
1364  *
1365  * returns zero on success and negative on failure.
1366  * Pass child_fid as zero for first entry.
1367  */
1368 int32_t
1369 ulp_flow_db_parent_child_flow_next_entry_get(struct bnxt_ulp_flow_db *flow_db,
1370                                              uint32_t parent_idx,
1371                                              uint32_t *child_fid)
1372 {
1373         struct ulp_fdb_parent_child_db *p_pdb;
1374         uint32_t idx, s_idx, mod_fid;
1375         uint32_t next_fid = *child_fid;
1376         uint64_t *child_bitset;
1377         uint64_t bs;
1378
1379         /* check for fid validity */
1380         p_pdb = &flow_db->parent_child_db;
1381         if (parent_idx >= p_pdb->entries_count ||
1382             !p_pdb->parent_flow_tbl[parent_idx].parent_fid) {
1383                 BNXT_TF_DBG(ERR, "Invalid parent flow index %x\n", parent_idx);
1384                 return -EINVAL;
1385         }
1386
1387         child_bitset = p_pdb->parent_flow_tbl[parent_idx].child_fid_bitset;
1388         do {
1389                 /* increment the flow id to find the next valid flow id */
1390                 next_fid++;
1391                 if (next_fid >= flow_db->flow_tbl.num_flows)
1392                         return -ENOENT;
1393                 idx = next_fid / ULP_INDEX_BITMAP_SIZE;
1394                 mod_fid = next_fid % ULP_INDEX_BITMAP_SIZE;
1395                 s_idx = idx;
1396                 while (!(bs = child_bitset[idx])) {
1397                         idx++;
1398                         if ((idx * ULP_INDEX_BITMAP_SIZE) >=
1399                             flow_db->flow_tbl.num_flows)
1400                                 return -ENOENT;
1401                 }
1402                 /*
1403                  * remove the previous bits in the bitset bs to find the
1404                  * next non zero bit in the bitset. This needs to be done
1405                  * only if the idx is same as he one you started.
1406                  */
1407                 if (s_idx == idx)
1408                         bs &= (-1UL >> mod_fid);
1409                 next_fid = (idx * ULP_INDEX_BITMAP_SIZE) + __builtin_clzl(bs);
1410                 if (*child_fid >= next_fid) {
1411                         BNXT_TF_DBG(ERR, "Parent Child Database is corrupt\n");
1412                         return -ENOENT;
1413                 }
1414                 idx = next_fid / ULP_INDEX_BITMAP_SIZE;
1415         } while (!ULP_INDEX_BITMAP_GET(child_bitset[idx], next_fid));
1416         *child_fid = next_fid;
1417         return 0;
1418 }
1419
1420 /*
1421  * Set the counter accumulation in the parent flow
1422  *
1423  * ulp_ctxt [in] Ptr to ulp_context
1424  * parent_idx [in] The parent index of the parent flow entry
1425  *
1426  * returns index on success and negative on failure.
1427  */
1428 static int32_t
1429 ulp_flow_db_parent_flow_count_accum_set(struct bnxt_ulp_context *ulp_ctxt,
1430                                         uint32_t parent_idx)
1431 {
1432         struct bnxt_ulp_flow_db *flow_db;
1433         struct ulp_fdb_parent_child_db *p_pdb;
1434
1435         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
1436         if (!flow_db) {
1437                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
1438                 return -EINVAL;
1439         }
1440
1441         /* check for parent idx validity */
1442         p_pdb = &flow_db->parent_child_db;
1443         if (parent_idx >= p_pdb->entries_count ||
1444             !p_pdb->parent_flow_tbl[parent_idx].parent_fid) {
1445                 BNXT_TF_DBG(ERR, "Invalid parent flow index %x\n", parent_idx);
1446                 return -EINVAL;
1447         }
1448
1449         p_pdb->parent_flow_tbl[parent_idx].counter_acc = 1;
1450         return 0;
1451 }
1452
1453 /*
1454  * Get the counter accumulation in the parent flow
1455  *
1456  * ulp_ctxt [in] Ptr to ulp_context
1457  * parent_fid [in] The flow id of the parent flow entry
1458  *
1459  * returns 0 if counter accum is set else -1.
1460  */
1461 static int32_t
1462 ulp_flow_db_parent_flow_count_accum_get(struct bnxt_ulp_context *ulp_ctxt,
1463                                         uint32_t parent_fid)
1464 {
1465         struct bnxt_ulp_flow_db *flow_db;
1466         struct ulp_fdb_parent_child_db *p_pdb;
1467         uint32_t idx;
1468
1469         /* validate the arguments */
1470         flow_db = ulp_flow_db_parent_arg_validation(ulp_ctxt, parent_fid);
1471         if (!flow_db) {
1472                 BNXT_TF_DBG(ERR, "parent child db validation failed\n");
1473                 return -EINVAL;
1474         }
1475
1476         p_pdb = &flow_db->parent_child_db;
1477         for (idx = 0; idx < p_pdb->entries_count; idx++) {
1478                 if (p_pdb->parent_flow_tbl[idx].parent_fid == parent_fid) {
1479                         if (p_pdb->parent_flow_tbl[idx].counter_acc)
1480                                 return 0;
1481                         break;
1482                 }
1483         }
1484         return -1;
1485 }
1486
1487 /*
1488  * Orphan the child flow entry
1489  * This is called only for child flows that have
1490  * BNXT_ULP_RESOURCE_FUNC_CHILD_FLOW resource
1491  *
1492  * ulp_ctxt [in] Ptr to ulp_context
1493  * flow_type [in] Specify it is regular or default flow
1494  * fid [in] The index to the flow entry
1495  *
1496  * Returns 0 on success and negative on failure.
1497  */
1498 int32_t
1499 ulp_flow_db_child_flow_reset(struct bnxt_ulp_context *ulp_ctxt,
1500                              enum bnxt_ulp_fdb_type flow_type,
1501                              uint32_t fid)
1502 {
1503         struct bnxt_ulp_flow_db *flow_db;
1504         struct bnxt_ulp_flow_tbl *flow_tbl;
1505         struct ulp_fdb_resource_info *fid_res;
1506         uint32_t res_id = 0;
1507
1508         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
1509         if (!flow_db) {
1510                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
1511                 return -EINVAL;
1512         }
1513
1514         if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
1515                 BNXT_TF_DBG(ERR, "Invalid flow type\n");
1516                 return -EINVAL;
1517         }
1518
1519         flow_tbl = &flow_db->flow_tbl;
1520         /* check for max flows */
1521         if (fid >= flow_tbl->num_flows || !fid) {
1522                 BNXT_TF_DBG(ERR, "Invalid flow index %x\n", fid);
1523                 return -EINVAL;
1524         }
1525
1526         /* check if the flow is active or not */
1527         if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) {
1528                 BNXT_TF_DBG(ERR, "flow does not exist\n");
1529                 return -EINVAL;
1530         }
1531
1532         /* Iterate the resource to get the resource handle */
1533         res_id =  fid;
1534         while (res_id) {
1535                 fid_res = &flow_tbl->flow_resources[res_id];
1536                 if (ulp_flow_db_resource_func_get(fid_res) ==
1537                     BNXT_ULP_RESOURCE_FUNC_CHILD_FLOW) {
1538                         /* invalidate the resource details */
1539                         fid_res->resource_hndl = 0;
1540                         return 0;
1541                 }
1542                 res_id = 0;
1543                 ULP_FLOW_DB_RES_NXT_SET(res_id, fid_res->nxt_resource_idx);
1544         }
1545         /* failed */
1546         return -1;
1547 }
1548
1549 /*
1550  * Create parent flow in the parent flow tbl
1551  *
1552  * parms [in] Ptr to mapper params
1553  *
1554  * Returns 0 on success and negative on failure.
1555  */
1556 int32_t
1557 ulp_flow_db_parent_flow_create(struct bnxt_ulp_mapper_parms *parms)
1558 {
1559         struct ulp_flow_db_res_params fid_parms;
1560         uint32_t sub_type = BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_INT_COUNT_ACC;
1561         struct ulp_flow_db_res_params res_params;
1562         int32_t fid_idx;
1563
1564         /* create the child flow entry in parent flow table */
1565         fid_idx = ulp_flow_db_parent_flow_alloc(parms->ulp_ctx, parms->fid);
1566         if (fid_idx < 0) {
1567                 BNXT_TF_DBG(ERR, "Error in creating parent flow fid %x\n",
1568                             parms->fid);
1569                 return -1;
1570         }
1571
1572         /* Add the parent details in the resource list of the flow */
1573         memset(&fid_parms, 0, sizeof(fid_parms));
1574         fid_parms.resource_func = BNXT_ULP_RESOURCE_FUNC_PARENT_FLOW;
1575         fid_parms.resource_hndl = fid_idx;
1576         fid_parms.critical_resource = BNXT_ULP_CRITICAL_RESOURCE_NO;
1577         if (ulp_flow_db_resource_add(parms->ulp_ctx, BNXT_ULP_FDB_TYPE_REGULAR,
1578                                      parms->fid, &fid_parms)) {
1579                 BNXT_TF_DBG(ERR, "Error in adding flow res for fid %x\n",
1580                             parms->fid);
1581                 return -1;
1582         }
1583
1584         /* check of the flow has internal counter accumulation enabled */
1585         if (!ulp_flow_db_resource_params_get(parms->ulp_ctx,
1586                                              BNXT_ULP_FDB_TYPE_REGULAR,
1587                                              parms->fid,
1588                                              BNXT_ULP_RESOURCE_FUNC_INDEX_TABLE,
1589                                              sub_type,
1590                                              &res_params)) {
1591                 /* Enable the counter accumulation in parent entry */
1592                 if (ulp_flow_db_parent_flow_count_accum_set(parms->ulp_ctx,
1593                                                             fid_idx)) {
1594                         BNXT_TF_DBG(ERR, "Error in setting counter acc %x\n",
1595                                     parms->fid);
1596                         return -1;
1597                 }
1598         }
1599         return 0;
1600 }
1601
1602 /*
1603  * Create child flow in the parent flow tbl
1604  *
1605  * parms [in] Ptr to mapper params
1606  *
1607  * Returns 0 on success and negative on failure.
1608  */
1609 int32_t
1610 ulp_flow_db_child_flow_create(struct bnxt_ulp_mapper_parms *parms)
1611 {
1612         struct ulp_flow_db_res_params fid_parms;
1613         uint32_t sub_type = BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_INT_COUNT;
1614         enum bnxt_ulp_resource_func res_fun;
1615         struct ulp_flow_db_res_params res_p;
1616         uint32_t parent_fid = parms->parent_fid;
1617         int32_t rc;
1618
1619         /* create the parent flow entry in parent flow table */
1620         rc = ulp_flow_db_parent_child_flow_set(parms->ulp_ctx,
1621                                                parms->parent_fid,
1622                                                parms->fid, 1);
1623         if (rc) {
1624                 BNXT_TF_DBG(ERR, "Error in setting child fid %x\n", parms->fid);
1625                 return rc;
1626         }
1627
1628         /* Add the parent details in the resource list of the flow */
1629         memset(&fid_parms, 0, sizeof(fid_parms));
1630         fid_parms.resource_func = BNXT_ULP_RESOURCE_FUNC_CHILD_FLOW;
1631         fid_parms.resource_hndl = parms->parent_fid;
1632         fid_parms.critical_resource = BNXT_ULP_CRITICAL_RESOURCE_NO;
1633         rc  = ulp_flow_db_resource_add(parms->ulp_ctx,
1634                                        BNXT_ULP_FDB_TYPE_REGULAR,
1635                                        parms->fid, &fid_parms);
1636         if (rc) {
1637                 BNXT_TF_DBG(ERR, "Error in adding flow res for fid %x\n",
1638                             parms->fid);
1639                 return rc;
1640         }
1641
1642         /* check if accumulation count is set for parent flow */
1643         rc = ulp_flow_db_parent_flow_count_accum_get(parms->ulp_ctx,
1644                                                      parms->parent_fid);
1645         if (!rc) {
1646                 /* check if internal count action included for this flow.*/
1647                 res_fun = BNXT_ULP_RESOURCE_FUNC_INDEX_TABLE;
1648                 rc = ulp_flow_db_resource_params_get(parms->ulp_ctx,
1649                                                      BNXT_ULP_FDB_TYPE_REGULAR,
1650                                                      parms->fid,
1651                                                      res_fun,
1652                                                      sub_type,
1653                                                      &res_p);
1654                 if (!rc) {
1655                         /* update the counter manager to include parent fid */
1656                         if (ulp_fc_mgr_cntr_parent_flow_set(parms->ulp_ctx,
1657                                                             res_p.direction,
1658                                                             res_p.resource_hndl,
1659                                                             parent_fid)) {
1660                                 BNXT_TF_DBG(ERR, "Error in setting child %x\n",
1661                                             parms->fid);
1662                                 return -1;
1663                         }
1664                 }
1665         }
1666         /* return success */
1667         return 0;
1668 }
1669
1670 /*
1671  * Update the parent counters
1672  *
1673  * ulp_ctxt [in] Ptr to ulp_context
1674  * parent_fid [in] The flow id of the parent flow entry
1675  * packet_count [in] - packet count
1676  * byte_count [in] - byte count
1677  *
1678  * returns 0 on success
1679  */
1680 int32_t
1681 ulp_flow_db_parent_flow_count_update(struct bnxt_ulp_context *ulp_ctxt,
1682                                      uint32_t parent_fid,
1683                                      uint64_t packet_count,
1684                                      uint64_t byte_count)
1685 {
1686         struct bnxt_ulp_flow_db *flow_db;
1687         struct ulp_fdb_parent_child_db *p_pdb;
1688         uint32_t idx;
1689
1690         /* validate the arguments */
1691         flow_db = ulp_flow_db_parent_arg_validation(ulp_ctxt, parent_fid);
1692         if (!flow_db) {
1693                 BNXT_TF_DBG(ERR, "parent child db validation failed\n");
1694                 return -EINVAL;
1695         }
1696
1697         p_pdb = &flow_db->parent_child_db;
1698         for (idx = 0; idx < p_pdb->entries_count; idx++) {
1699                 if (p_pdb->parent_flow_tbl[idx].parent_fid == parent_fid) {
1700                         if (p_pdb->parent_flow_tbl[idx].counter_acc) {
1701                                 p_pdb->parent_flow_tbl[idx].pkt_count +=
1702                                         packet_count;
1703                                 p_pdb->parent_flow_tbl[idx].byte_count +=
1704                                         byte_count;
1705                         }
1706                         return 0;
1707                 }
1708         }
1709         return -ENOENT;
1710 }
1711
1712 /*
1713  * Get the parent accumulation counters
1714  *
1715  * ulp_ctxt [in] Ptr to ulp_context
1716  * parent_fid [in] The flow id of the parent flow entry
1717  * packet_count [out] - packet count
1718  * byte_count [out] - byte count
1719  *
1720  * returns 0 on success
1721  */
1722 int32_t
1723 ulp_flow_db_parent_flow_count_get(struct bnxt_ulp_context *ulp_ctxt,
1724                                   uint32_t parent_fid,
1725                                   uint64_t *packet_count,
1726                                   uint64_t *byte_count)
1727 {
1728         struct bnxt_ulp_flow_db *flow_db;
1729         struct ulp_fdb_parent_child_db *p_pdb;
1730         uint32_t idx;
1731
1732         /* validate the arguments */
1733         flow_db = ulp_flow_db_parent_arg_validation(ulp_ctxt, parent_fid);
1734         if (!flow_db) {
1735                 BNXT_TF_DBG(ERR, "parent child db validation failed\n");
1736                 return -EINVAL;
1737         }
1738
1739         p_pdb = &flow_db->parent_child_db;
1740         for (idx = 0; idx < p_pdb->entries_count; idx++) {
1741                 if (p_pdb->parent_flow_tbl[idx].parent_fid == parent_fid) {
1742                         if (p_pdb->parent_flow_tbl[idx].counter_acc) {
1743                                 *packet_count =
1744                                         p_pdb->parent_flow_tbl[idx].pkt_count;
1745                                 *byte_count =
1746                                         p_pdb->parent_flow_tbl[idx].byte_count;
1747                         }
1748                         return 0;
1749                 }
1750         }
1751         return -ENOENT;
1752 }
1753
1754 /*
1755  * reset the parent accumulation counters
1756  *
1757  * ulp_ctxt [in] Ptr to ulp_context
1758  *
1759  * returns none
1760  */
1761 void
1762 ulp_flow_db_parent_flow_count_reset(struct bnxt_ulp_context *ulp_ctxt)
1763 {
1764         struct bnxt_ulp_flow_db *flow_db;
1765         struct ulp_fdb_parent_child_db *p_pdb;
1766         uint32_t idx;
1767
1768         /* validate the arguments */
1769         flow_db = ulp_flow_db_parent_arg_validation(ulp_ctxt, 1);
1770         if (!flow_db) {
1771                 BNXT_TF_DBG(ERR, "parent child db validation failed\n");
1772                 return;
1773         }
1774
1775         p_pdb = &flow_db->parent_child_db;
1776         for (idx = 0; idx < p_pdb->entries_count; idx++) {
1777                 if (p_pdb->parent_flow_tbl[idx].parent_fid &&
1778                     p_pdb->parent_flow_tbl[idx].counter_acc) {
1779                         p_pdb->parent_flow_tbl[idx].pkt_count = 0;
1780                         p_pdb->parent_flow_tbl[idx].byte_count = 0;
1781                 }
1782         }
1783 }