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