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