net/bnxt: combine default and regular flows
[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         flow_tbl->active_reg_flows = rte_zmalloc("active reg flows", size, 0);
211         if (!flow_tbl->active_reg_flows) {
212                 BNXT_TF_DBG(ERR, "Failed to alloc memory active reg flows\n");
213                 return -ENOMEM;
214         }
215
216         flow_tbl->active_dflt_flows = rte_zmalloc("active dflt flows", size, 0);
217         if (!flow_tbl->active_dflt_flows) {
218                 BNXT_TF_DBG(ERR, "Failed to alloc memory active dflt flows\n");
219                 return -ENOMEM;
220         }
221
222         /* Initialize the stack table. */
223         for (idx = 0; idx < flow_tbl->num_resources; idx++)
224                 flow_tbl->flow_tbl_stack[idx] = idx;
225
226         /* Ignore the first element in the list. */
227         flow_tbl->head_index = 1;
228         /* Tail points to the last entry in the list. */
229         flow_tbl->tail_index = flow_tbl->num_resources - 1;
230         return 0;
231 }
232
233 /*
234  * Helper function to deallocate the flow table.
235  *
236  * flow_db [in] Ptr to flow database structure
237  *
238  * Returns none.
239  */
240 static void
241 ulp_flow_db_dealloc_resource(struct bnxt_ulp_flow_db *flow_db)
242 {
243         struct bnxt_ulp_flow_tbl *flow_tbl = &flow_db->flow_tbl;
244
245         /* Free all the allocated tables in the flow table. */
246         if (flow_tbl->active_reg_flows) {
247                 rte_free(flow_tbl->active_reg_flows);
248                 flow_tbl->active_reg_flows = NULL;
249         }
250         if (flow_tbl->active_dflt_flows) {
251                 rte_free(flow_tbl->active_dflt_flows);
252                 flow_tbl->active_dflt_flows = NULL;
253         }
254
255         if (flow_tbl->flow_tbl_stack) {
256                 rte_free(flow_tbl->flow_tbl_stack);
257                 flow_tbl->flow_tbl_stack = NULL;
258         }
259
260         if (flow_tbl->flow_resources) {
261                 rte_free(flow_tbl->flow_resources);
262                 flow_tbl->flow_resources = NULL;
263         }
264 }
265
266 /*
267  * Helper function to add function id to the flow table
268  *
269  * flow_db [in] Ptr to flow table
270  * flow_id [in] The flow id of the flow
271  * func_id [in] The func_id to be set, for reset pass zero
272  *
273  * returns none
274  */
275 static void
276 ulp_flow_db_func_id_set(struct bnxt_ulp_flow_db *flow_db,
277                         uint32_t flow_id,
278                         uint32_t func_id)
279 {
280         /* set the function id in the function table */
281         if (flow_id < flow_db->func_id_tbl_size)
282                 flow_db->func_id_tbl[flow_id] = func_id;
283         else /* This should never happen */
284                 BNXT_TF_DBG(ERR, "Invalid flow id, flowdb corrupt\n");
285 }
286
287 /*
288  * Initialize the flow database. Memory is allocated in this
289  * call and assigned to the flow database.
290  *
291  * ulp_ctxt [in] Ptr to ulp context
292  *
293  * Returns 0 on success or negative number on failure.
294  */
295 int32_t
296 ulp_flow_db_init(struct bnxt_ulp_context *ulp_ctxt)
297 {
298         struct bnxt_ulp_device_params *dparms;
299         struct bnxt_ulp_flow_tbl *flow_tbl;
300         struct bnxt_ulp_flow_db *flow_db;
301         uint32_t dev_id;
302
303         /* Get the dev specific number of flows that needed to be supported. */
304         if (bnxt_ulp_cntxt_dev_id_get(ulp_ctxt, &dev_id)) {
305                 BNXT_TF_DBG(ERR, "Invalid device id\n");
306                 return -EINVAL;
307         }
308
309         dparms = bnxt_ulp_device_params_get(dev_id);
310         if (!dparms) {
311                 BNXT_TF_DBG(ERR, "could not fetch the device params\n");
312                 return -ENODEV;
313         }
314
315         flow_db = rte_zmalloc("bnxt_ulp_flow_db",
316                               sizeof(struct bnxt_ulp_flow_db), 0);
317         if (!flow_db) {
318                 BNXT_TF_DBG(ERR,
319                             "Failed to allocate memory for flow table ptr\n");
320                 return -ENOMEM;
321         }
322
323         /* Attach the flow database to the ulp context. */
324         bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, flow_db);
325
326         /* Populate the regular flow table limits. */
327         flow_tbl = &flow_db->flow_tbl;
328         flow_tbl->num_flows = dparms->flow_db_num_entries + 1;
329         flow_tbl->num_resources = ((dparms->flow_db_num_entries + 1) *
330                                    dparms->num_resources_per_flow);
331
332         /* Include the default flow table limits. */
333         flow_tbl->num_flows += (BNXT_FLOW_DB_DEFAULT_NUM_FLOWS + 1);
334         flow_tbl->num_resources += ((BNXT_FLOW_DB_DEFAULT_NUM_FLOWS + 1) *
335                                     BNXT_FLOW_DB_DEFAULT_NUM_RESOURCES);
336
337         /* Allocate the resource for the flow table. */
338         if (ulp_flow_db_alloc_resource(flow_db))
339                 goto error_free;
340
341         /* add 1 since we are not using index 0 for flow id */
342         flow_db->func_id_tbl_size = flow_tbl->num_flows + 1;
343         /* Allocate the function Id table */
344         flow_db->func_id_tbl = rte_zmalloc("bnxt_ulp_flow_db_func_id_table",
345                                            flow_db->func_id_tbl_size *
346                                            sizeof(uint16_t), 0);
347         if (!flow_db->func_id_tbl) {
348                 BNXT_TF_DBG(ERR,
349                             "Failed to allocate mem for flow table func id\n");
350                 goto error_free;
351         }
352         /* All good so return. */
353         return 0;
354 error_free:
355         ulp_flow_db_deinit(ulp_ctxt);
356         return -ENOMEM;
357 }
358
359 /*
360  * Deinitialize the flow database. Memory is deallocated in
361  * this call and all flows should have been purged before this
362  * call.
363  *
364  * ulp_ctxt [in] Ptr to ulp context
365  *
366  * Returns 0 on success.
367  */
368 int32_t
369 ulp_flow_db_deinit(struct bnxt_ulp_context *ulp_ctxt)
370 {
371         struct bnxt_ulp_flow_db *flow_db;
372
373         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
374         if (!flow_db)
375                 return -EINVAL;
376
377         /* Detach the flow database from the ulp context. */
378         bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, NULL);
379
380         /* Free up all the memory. */
381         ulp_flow_db_dealloc_resource(flow_db);
382         rte_free(flow_db->func_id_tbl);
383         rte_free(flow_db);
384
385         return 0;
386 }
387
388 /*
389  * Allocate the flow database entry
390  *
391  * ulp_ctxt [in] Ptr to ulp_context
392  * flow_type [in] - specify default or regular
393  * func_id [in].function id of the ingress port
394  * fid [out] The index to the flow entry
395  *
396  * returns 0 on success and negative on failure.
397  */
398 int32_t
399 ulp_flow_db_fid_alloc(struct bnxt_ulp_context *ulp_ctxt,
400                       enum bnxt_ulp_fdb_type flow_type,
401                       uint16_t func_id,
402                       uint32_t *fid)
403 {
404         struct bnxt_ulp_flow_db *flow_db;
405         struct bnxt_ulp_flow_tbl *flow_tbl;
406
407         *fid = 0; /* Initialize fid to invalid value */
408         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
409         if (!flow_db) {
410                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
411                 return -EINVAL;
412         }
413
414         if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
415                 BNXT_TF_DBG(ERR, "Invalid flow type\n");
416                 return -EINVAL;
417         }
418
419         flow_tbl = &flow_db->flow_tbl;
420         /* check for max flows */
421         if (flow_tbl->num_flows <= flow_tbl->head_index) {
422                 BNXT_TF_DBG(ERR, "Flow database has reached max flows\n");
423                 return -ENOMEM;
424         }
425         if (flow_tbl->tail_index <= (flow_tbl->head_index + 1)) {
426                 BNXT_TF_DBG(ERR, "Flow database has reached max resources\n");
427                 return -ENOMEM;
428         }
429         *fid = flow_tbl->flow_tbl_stack[flow_tbl->head_index];
430         flow_tbl->head_index++;
431
432         /* Set the flow type */
433         ulp_flow_db_active_flows_bit_set(flow_db, flow_type, *fid, 1);
434
435         /* function id update is only valid for regular flow table */
436         if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR)
437                 ulp_flow_db_func_id_set(flow_db, *fid, func_id);
438
439         /* return success */
440         return 0;
441 }
442
443 /*
444  * Allocate the flow database entry.
445  * The params->critical_resource has to be set to 0 to allocate a new resource.
446  *
447  * ulp_ctxt [in] Ptr to ulp_context
448  * flow_type [in] Specify it is regular or default flow
449  * fid [in] The index to the flow entry
450  * params [in] The contents to be copied into resource
451  *
452  * returns 0 on success and negative on failure.
453  */
454 int32_t
455 ulp_flow_db_resource_add(struct bnxt_ulp_context *ulp_ctxt,
456                          enum bnxt_ulp_fdb_type flow_type,
457                          uint32_t fid,
458                          struct ulp_flow_db_res_params *params)
459 {
460         struct bnxt_ulp_flow_db *flow_db;
461         struct bnxt_ulp_flow_tbl *flow_tbl;
462         struct ulp_fdb_resource_info *resource, *fid_resource;
463         uint32_t idx;
464
465         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
466         if (!flow_db) {
467                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
468                 return -EINVAL;
469         }
470
471         if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
472                 BNXT_TF_DBG(ERR, "Invalid flow type\n");
473                 return -EINVAL;
474         }
475
476         flow_tbl = &flow_db->flow_tbl;
477         /* check for max flows */
478         if (fid >= flow_tbl->num_flows || !fid) {
479                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
480                 return -EINVAL;
481         }
482
483         /* check if the flow is active or not */
484         if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) {
485                 BNXT_TF_DBG(ERR, "flow does not exist\n");
486                 return -EINVAL;
487         }
488
489         /* check for max resource */
490         if ((flow_tbl->head_index + 1) >= flow_tbl->tail_index) {
491                 BNXT_TF_DBG(ERR, "Flow db has reached max resources\n");
492                 return -ENOMEM;
493         }
494         fid_resource = &flow_tbl->flow_resources[fid];
495
496         if (!params->critical_resource) {
497                 /* Not the critical_resource so allocate a resource */
498                 idx = flow_tbl->flow_tbl_stack[flow_tbl->tail_index];
499                 resource = &flow_tbl->flow_resources[idx];
500                 flow_tbl->tail_index--;
501
502                 /* Update the chain list of resource*/
503                 ULP_FLOW_DB_RES_NXT_SET(resource->nxt_resource_idx,
504                                         fid_resource->nxt_resource_idx);
505                 /* update the contents */
506                 ulp_flow_db_res_params_to_info(resource, params);
507                 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx);
508                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
509                                         idx);
510         } else {
511                 /* critical resource. Just update the fid resource */
512                 ulp_flow_db_res_params_to_info(fid_resource, params);
513         }
514
515         if (params->resource_type == TF_TBL_TYPE_ACT_STATS_64 &&
516             params->resource_sub_type ==
517             BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_INT_COUNT) {
518                 /* Store the first HW counter ID for this table */
519                 if (!ulp_fc_mgr_start_idx_isset(ulp_ctxt, params->direction))
520                         ulp_fc_mgr_start_idx_set(ulp_ctxt, params->direction,
521                                                  params->resource_hndl);
522
523                 ulp_fc_mgr_cntr_set(ulp_ctxt, params->direction,
524                                     params->resource_hndl);
525
526                 if (!ulp_fc_mgr_thread_isstarted(ulp_ctxt))
527                         ulp_fc_mgr_thread_start(ulp_ctxt);
528         }
529
530         /* all good, return success */
531         return 0;
532 }
533
534 /*
535  * Free the flow database entry.
536  * The params->critical_resource has to be set to 1 to free the first resource.
537  *
538  * ulp_ctxt [in] Ptr to ulp_context
539  * flow_type [in] Specify it is regular or default flow
540  * fid [in] The index to the flow entry
541  * params [in/out] The contents to be copied into params.
542  * Onlythe critical_resource needs to be set by the caller.
543  *
544  * Returns 0 on success and negative on failure.
545  */
546 int32_t
547 ulp_flow_db_resource_del(struct bnxt_ulp_context *ulp_ctxt,
548                          enum bnxt_ulp_fdb_type flow_type,
549                          uint32_t fid,
550                          struct ulp_flow_db_res_params *params)
551 {
552         struct bnxt_ulp_flow_db *flow_db;
553         struct bnxt_ulp_flow_tbl *flow_tbl;
554         struct ulp_fdb_resource_info *nxt_resource, *fid_resource;
555         uint32_t nxt_idx = 0;
556
557         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
558         if (!flow_db) {
559                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
560                 return -EINVAL;
561         }
562
563         if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
564                 BNXT_TF_DBG(ERR, "Invalid flow type\n");
565                 return -EINVAL;
566         }
567
568         flow_tbl = &flow_db->flow_tbl;
569         /* check for max flows */
570         if (fid >= flow_tbl->num_flows || !fid) {
571                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
572                 return -EINVAL;
573         }
574
575         /* check if the flow is active or not */
576         if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) {
577                 BNXT_TF_DBG(ERR, "flow does not exist\n");
578                 return -EINVAL;
579         }
580
581         fid_resource = &flow_tbl->flow_resources[fid];
582         if (!params->critical_resource) {
583                 /* Not the critical resource so free the resource */
584                 ULP_FLOW_DB_RES_NXT_SET(nxt_idx,
585                                         fid_resource->nxt_resource_idx);
586                 if (!nxt_idx) {
587                         /* reached end of resources */
588                         return -ENOENT;
589                 }
590                 nxt_resource = &flow_tbl->flow_resources[nxt_idx];
591
592                 /* connect the fid resource to the next resource */
593                 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx);
594                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
595                                         nxt_resource->nxt_resource_idx);
596
597                 /* update the contents to be given to caller */
598                 ulp_flow_db_res_info_to_params(nxt_resource, params);
599
600                 /* Delete the nxt_resource */
601                 memset(nxt_resource, 0, sizeof(struct ulp_fdb_resource_info));
602
603                 /* add it to the free list */
604                 flow_tbl->tail_index++;
605                 if (flow_tbl->tail_index >= flow_tbl->num_resources) {
606                         BNXT_TF_DBG(ERR, "FlowDB:Tail reached max\n");
607                         return -ENOENT;
608                 }
609                 flow_tbl->flow_tbl_stack[flow_tbl->tail_index] = nxt_idx;
610
611         } else {
612                 /* Critical resource. copy the contents and exit */
613                 ulp_flow_db_res_info_to_params(fid_resource, params);
614                 ULP_FLOW_DB_RES_NXT_SET(nxt_idx,
615                                         fid_resource->nxt_resource_idx);
616                 memset(fid_resource, 0, sizeof(struct ulp_fdb_resource_info));
617                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
618                                         nxt_idx);
619         }
620
621         /* Now that the HW Flow counter resource is deleted, reset it's
622          * corresponding slot in the SW accumulation table in the Flow Counter
623          * manager
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                 ulp_fc_mgr_cntr_reset(ulp_ctxt, params->direction,
629                                       params->resource_hndl);
630         }
631
632         /* all good, return success */
633         return 0;
634 }
635
636 /*
637  * Free the flow database entry
638  *
639  * ulp_ctxt [in] Ptr to ulp_context
640  * flow_type [in] - specify default or regular
641  * fid [in] The index to the flow entry
642  *
643  * returns 0 on success and negative on failure.
644  */
645 int32_t
646 ulp_flow_db_fid_free(struct bnxt_ulp_context *ulp_ctxt,
647                      enum bnxt_ulp_fdb_type flow_type,
648                      uint32_t fid)
649 {
650         struct bnxt_ulp_flow_db *flow_db;
651         struct bnxt_ulp_flow_tbl *flow_tbl;
652
653         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
654         if (!flow_db) {
655                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
656                 return -EINVAL;
657         }
658
659         if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
660                 BNXT_TF_DBG(ERR, "Invalid flow type\n");
661                 return -EINVAL;
662         }
663
664         flow_tbl = &flow_db->flow_tbl;
665
666         /* check for limits of fid */
667         if (fid >= flow_tbl->num_flows || !fid) {
668                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
669                 return -EINVAL;
670         }
671
672         /* check if the flow is active or not */
673         if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) {
674                 BNXT_TF_DBG(ERR, "flow does not exist\n");
675                 return -EINVAL;
676         }
677         flow_tbl->head_index--;
678         if (!flow_tbl->head_index) {
679                 BNXT_TF_DBG(ERR, "FlowDB: Head Ptr is zero\n");
680                 return -ENOENT;
681         }
682         flow_tbl->flow_tbl_stack[flow_tbl->head_index] = fid;
683
684         /* Clear the flows bitmap */
685         ulp_flow_db_active_flows_bit_set(flow_db, flow_type, fid, 0);
686
687         if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR)
688                 ulp_flow_db_func_id_set(flow_db, fid, 0);
689
690         /* all good, return success */
691         return 0;
692 }
693
694 /*
695  * Get the flow database entry details
696  *
697  * ulp_ctxt [in] Ptr to ulp_context
698  * flow_type [in] - specify default or regular
699  * fid [in] The index to the flow entry
700  * nxt_idx [in/out] the index to the next entry
701  * params [out] The contents to be copied into params.
702  *
703  * returns 0 on success and negative on failure.
704  */
705 int32_t
706 ulp_flow_db_resource_get(struct bnxt_ulp_context *ulp_ctxt,
707                          enum bnxt_ulp_fdb_type flow_type,
708                          uint32_t fid,
709                          uint32_t *nxt_idx,
710                          struct ulp_flow_db_res_params *params)
711 {
712         struct bnxt_ulp_flow_db *flow_db;
713         struct bnxt_ulp_flow_tbl *flow_tbl;
714         struct ulp_fdb_resource_info *nxt_resource, *fid_resource;
715
716         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
717         if (!flow_db) {
718                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
719                 return -EINVAL;
720         }
721
722         if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
723                 BNXT_TF_DBG(ERR, "Invalid flow type\n");
724                 return -EINVAL;
725         }
726
727         flow_tbl = &flow_db->flow_tbl;
728
729         /* check for limits of fid */
730         if (fid >= flow_tbl->num_flows || !fid) {
731                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
732                 return -EINVAL;
733         }
734
735         /* check if the flow is active or not */
736         if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) {
737                 BNXT_TF_DBG(ERR, "flow does not exist\n");
738                 return -EINVAL;
739         }
740
741         if (!*nxt_idx) {
742                 fid_resource = &flow_tbl->flow_resources[fid];
743                 ulp_flow_db_res_info_to_params(fid_resource, params);
744                 ULP_FLOW_DB_RES_NXT_SET(*nxt_idx,
745                                         fid_resource->nxt_resource_idx);
746         } else {
747                 nxt_resource = &flow_tbl->flow_resources[*nxt_idx];
748                 ulp_flow_db_res_info_to_params(nxt_resource, params);
749                 *nxt_idx = 0;
750                 ULP_FLOW_DB_RES_NXT_SET(*nxt_idx,
751                                         nxt_resource->nxt_resource_idx);
752         }
753
754         /* all good, return success */
755         return 0;
756 }
757
758 /*
759  * Get the flow database entry iteratively
760  *
761  * flow_tbl [in] Ptr to flow table
762  * flow_type [in] - specify default or regular
763  * fid [in/out] The index to the flow entry
764  *
765  * returns 0 on success and negative on failure.
766  */
767 static int32_t
768 ulp_flow_db_next_entry_get(struct bnxt_ulp_flow_db *flow_db,
769                            enum bnxt_ulp_fdb_type flow_type,
770                            uint32_t *fid)
771 {
772         uint32_t lfid = *fid;
773         uint32_t idx, s_idx, mod_fid;
774         uint64_t bs;
775         uint64_t *active_flows;
776         struct bnxt_ulp_flow_tbl *flowtbl = &flow_db->flow_tbl;
777
778         if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR)
779                 active_flows = flowtbl->active_reg_flows;
780         else
781                 active_flows = flowtbl->active_dflt_flows;
782
783         do {
784                 /* increment the flow id to find the next valid flow id */
785                 lfid++;
786                 if (lfid >= flowtbl->num_flows)
787                         return -ENOENT;
788                 idx = lfid / ULP_INDEX_BITMAP_SIZE;
789                 mod_fid = lfid % ULP_INDEX_BITMAP_SIZE;
790                 s_idx = idx;
791                 while (!(bs = active_flows[idx])) {
792                         idx++;
793                         if ((idx * ULP_INDEX_BITMAP_SIZE) >= flowtbl->num_flows)
794                                 return -ENOENT;
795                 }
796                 /*
797                  * remove the previous bits in the bitset bs to find the
798                  * next non zero bit in the bitset. This needs to be done
799                  * only if the idx is same as he one you started.
800                  */
801                 if (s_idx == idx)
802                         bs &= (-1UL >> mod_fid);
803                 lfid = (idx * ULP_INDEX_BITMAP_SIZE) + __builtin_clzl(bs);
804                 if (*fid >= lfid) {
805                         BNXT_TF_DBG(ERR, "Flow Database is corrupt\n");
806                         return -ENOENT;
807                 }
808         } while (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type,
809                                                       lfid));
810
811         /* all good, return success */
812         *fid = lfid;
813         return 0;
814 }
815
816 /*
817  * Flush all flows in the flow database.
818  *
819  * ulp_ctxt [in] Ptr to ulp context
820  * flow_type [in] - specify default or regular
821  *
822  * returns 0 on success or negative number on failure
823  */
824 int32_t
825 ulp_flow_db_flush_flows(struct bnxt_ulp_context *ulp_ctx,
826                         enum bnxt_ulp_fdb_type flow_type)
827 {
828         uint32_t fid = 0;
829         struct bnxt_ulp_flow_db *flow_db;
830
831         if (!ulp_ctx) {
832                 BNXT_TF_DBG(ERR, "Invalid Argument\n");
833                 return -EINVAL;
834         }
835
836         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
837         if (!flow_db) {
838                 BNXT_TF_DBG(ERR, "Flow database not found\n");
839                 return -EINVAL;
840         }
841         if (bnxt_ulp_cntxt_acquire_fdb_lock(ulp_ctx)) {
842                 BNXT_TF_DBG(ERR, "Flow db lock acquire failed\n");
843                 return -EINVAL;
844         }
845
846         while (!ulp_flow_db_next_entry_get(flow_db, flow_type, &fid))
847                 ulp_mapper_resources_free(ulp_ctx, flow_type, fid);
848
849         bnxt_ulp_cntxt_release_fdb_lock(ulp_ctx);
850
851         return 0;
852 }
853
854 /*
855  * Flush all flows in the flow database that belong to a device function.
856  *
857  * ulp_ctxt [in] Ptr to ulp context
858  * func_id [in] - The port function id
859  *
860  * returns 0 on success or negative number on failure
861  */
862 int32_t
863 ulp_flow_db_function_flow_flush(struct bnxt_ulp_context *ulp_ctx,
864                                 uint16_t func_id)
865 {
866         uint32_t flow_id = 0;
867         struct bnxt_ulp_flow_db *flow_db;
868
869         if (!ulp_ctx || !func_id) {
870                 BNXT_TF_DBG(ERR, "Invalid Argument\n");
871                 return -EINVAL;
872         }
873
874         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
875         if (!flow_db) {
876                 BNXT_TF_DBG(ERR, "Flow database not found\n");
877                 return -EINVAL;
878         }
879         if (bnxt_ulp_cntxt_acquire_fdb_lock(ulp_ctx)) {
880                 BNXT_TF_DBG(ERR, "Flow db lock acquire failed\n");
881                 return -EINVAL;
882         }
883
884         while (!ulp_flow_db_next_entry_get(flow_db, BNXT_ULP_FDB_TYPE_REGULAR,
885                                            &flow_id)) {
886                 if (flow_db->func_id_tbl[flow_id] == func_id)
887                         ulp_mapper_resources_free(ulp_ctx,
888                                                   BNXT_ULP_FDB_TYPE_REGULAR,
889                                                   flow_id);
890         }
891         bnxt_ulp_cntxt_release_fdb_lock(ulp_ctx);
892         return 0;
893 }
894
895 /*
896  * Flush all flows in the flow database that are associated with the session.
897  *
898  * ulp_ctxt [in] Ptr to ulp context
899  *
900  * returns 0 on success or negative number on failure
901  */
902 int32_t
903 ulp_flow_db_session_flow_flush(struct bnxt_ulp_context *ulp_ctx)
904 {
905         /*
906          * TBD: Tf core implementation of FW session flush shall change this
907          * implementation.
908          */
909         return ulp_flow_db_flush_flows(ulp_ctx, BNXT_ULP_FDB_TYPE_REGULAR);
910 }
911
912 /*
913  * Check that flow id matches the function id or not
914  *
915  * ulp_ctxt [in] Ptr to ulp context
916  * flow_db [in] Ptr to flow table
917  * func_id [in] The func_id to be set, for reset pass zero.
918  *
919  * returns true on success or false on failure
920  */
921 bool
922 ulp_flow_db_validate_flow_func(struct bnxt_ulp_context *ulp_ctx,
923                                uint32_t flow_id,
924                                uint32_t func_id)
925 {
926         struct bnxt_ulp_flow_db *flow_db;
927
928         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
929         if (!flow_db) {
930                 BNXT_TF_DBG(ERR, "Flow database not found\n");
931                 return false;
932         }
933
934         /* set the function id in the function table */
935         if (flow_id < flow_db->func_id_tbl_size && func_id &&
936             flow_db->func_id_tbl[flow_id] == func_id)
937                 return true;
938
939         return false;
940 }
941
942 /*
943  * Internal api to traverse the resource list within a flow
944  * and match a resource based on resource func and resource
945  * sub type. This api should be used only for resources that
946  * are unique and do not have multiple instances of resource
947  * func and sub type combination since it will return only
948  * the first match.
949  */
950 static int32_t
951 ulp_flow_db_resource_hndl_get(struct bnxt_ulp_context *ulp_ctx,
952                               enum bnxt_ulp_fdb_type flow_type,
953                               uint32_t flow_id,
954                               uint32_t resource_func,
955                               uint32_t res_subtype,
956                               uint64_t *res_hndl)
957 {
958         struct bnxt_ulp_flow_db *flow_db;
959         struct bnxt_ulp_flow_tbl *flow_tbl;
960         struct ulp_fdb_resource_info *fid_res;
961         uint32_t res_id;
962
963         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
964         if (!flow_db) {
965                 BNXT_TF_DBG(ERR, "Flow database not found\n");
966                 return -EINVAL;
967         }
968
969         if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
970                 BNXT_TF_DBG(ERR, "Invalid flow type\n");
971                 return -EINVAL;
972         }
973
974         flow_tbl = &flow_db->flow_tbl;
975
976         /* check for limits of fid */
977         if (flow_id >= flow_tbl->num_flows || !flow_id) {
978                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
979                 return -EINVAL;
980         }
981
982         /* check if the flow is active or not */
983         if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, flow_id)) {
984                 BNXT_TF_DBG(ERR, "flow does not exist\n");
985                 return -EINVAL;
986         }
987         /* Iterate the resource to get the resource handle */
988         res_id =  flow_id;
989         while (res_id) {
990                 fid_res = &flow_tbl->flow_resources[res_id];
991                 if (ulp_flow_db_resource_func_get(fid_res) == resource_func) {
992                         if (resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) {
993                                 if (res_subtype == fid_res->resource_sub_type) {
994                                         *res_hndl = fid_res->resource_hndl;
995                                         return 0;
996                                 }
997
998                         } else if (resource_func ==
999                                    BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE ||
1000                                    resource_func ==
1001                                    BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) {
1002                                 *res_hndl = fid_res->resource_em_handle;
1003                                 return 0;
1004                         }
1005                 }
1006                 res_id = 0;
1007                 ULP_FLOW_DB_RES_NXT_SET(res_id, fid_res->nxt_resource_idx);
1008         }
1009         return -ENOENT;
1010 }
1011
1012 /*
1013  * Api to get the cfa action pointer from a flow.
1014  *
1015  * ulp_ctxt [in] Ptr to ulp context
1016  * flow_id [in] flow id
1017  * cfa_action [out] The resource handle stored in the flow database
1018  *
1019  * returns 0 on success
1020  */
1021 int32_t
1022 ulp_default_flow_db_cfa_action_get(struct bnxt_ulp_context *ulp_ctx,
1023                                    uint32_t flow_id,
1024                                    uint16_t *cfa_action)
1025 {
1026         uint8_t sub_type = BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_VFR_CFA_ACTION;
1027         uint64_t hndl;
1028         int32_t rc;
1029
1030         rc = ulp_flow_db_resource_hndl_get(ulp_ctx,
1031                                            BNXT_ULP_FDB_TYPE_DEFAULT,
1032                                            flow_id,
1033                                            BNXT_ULP_RESOURCE_FUNC_INDEX_TABLE,
1034                                            sub_type, &hndl);
1035         if (rc) {
1036                 BNXT_TF_DBG(ERR, "CFA Action ptr not found for flow id %u\n",
1037                             flow_id);
1038                 return -ENOENT;
1039         }
1040         *cfa_action = hndl;
1041         return 0;
1042 }