net/bnxt: support freeing key and action tables
[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  * Initialize the flow database. Memory is allocated in this
214  * call and assigned to the flow database.
215  *
216  * ulp_ctxt [in] Ptr to ulp context
217  *
218  * Returns 0 on success or negative number on failure.
219  */
220 int32_t ulp_flow_db_init(struct bnxt_ulp_context *ulp_ctxt)
221 {
222         struct bnxt_ulp_device_params           *dparms;
223         struct bnxt_ulp_flow_tbl                *flow_tbl;
224         struct bnxt_ulp_flow_db                 *flow_db;
225         uint32_t                                dev_id;
226
227         /* Get the dev specific number of flows that needed to be supported. */
228         if (bnxt_ulp_cntxt_dev_id_get(ulp_ctxt, &dev_id)) {
229                 BNXT_TF_DBG(ERR, "Invalid device id\n");
230                 return -EINVAL;
231         }
232
233         dparms = bnxt_ulp_device_params_get(dev_id);
234         if (!dparms) {
235                 BNXT_TF_DBG(ERR, "could not fetch the device params\n");
236                 return -ENODEV;
237         }
238
239         flow_db = rte_zmalloc("bnxt_ulp_flow_db",
240                               sizeof(struct bnxt_ulp_flow_db), 0);
241         if (!flow_db) {
242                 BNXT_TF_DBG(ERR,
243                             "Failed to allocate memory for flow table ptr\n");
244                 goto error_free;
245         }
246
247         /* Attach the flow database to the ulp context. */
248         bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, flow_db);
249
250         /* Populate the regular flow table limits. */
251         flow_tbl = &flow_db->flow_tbl[BNXT_ULP_REGULAR_FLOW_TABLE];
252         flow_tbl->num_flows = dparms->num_flows + 1;
253         flow_tbl->num_resources = (flow_tbl->num_flows *
254                                    dparms->num_resources_per_flow);
255
256         /* Populate the default flow table limits. */
257         flow_tbl = &flow_db->flow_tbl[BNXT_ULP_DEFAULT_FLOW_TABLE];
258         flow_tbl->num_flows = BNXT_FLOW_DB_DEFAULT_NUM_FLOWS + 1;
259         flow_tbl->num_resources = (flow_tbl->num_flows *
260                                    BNXT_FLOW_DB_DEFAULT_NUM_RESOURCES);
261
262         /* Allocate the resource for the regular flow table. */
263         if (ulp_flow_db_alloc_resource(flow_db, BNXT_ULP_REGULAR_FLOW_TABLE))
264                 goto error_free;
265         if (ulp_flow_db_alloc_resource(flow_db, BNXT_ULP_DEFAULT_FLOW_TABLE))
266                 goto error_free;
267
268         /* All good so return. */
269         return 0;
270 error_free:
271         ulp_flow_db_deinit(ulp_ctxt);
272         return -ENOMEM;
273 }
274
275 /*
276  * Deinitialize the flow database. Memory is deallocated in
277  * this call and all flows should have been purged before this
278  * call.
279  *
280  * ulp_ctxt [in] Ptr to ulp context
281  *
282  * Returns 0 on success.
283  */
284 int32_t ulp_flow_db_deinit(struct bnxt_ulp_context *ulp_ctxt)
285 {
286         struct bnxt_ulp_flow_db                 *flow_db;
287
288         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
289         if (!flow_db) {
290                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
291                 return -EINVAL;
292         }
293
294         /* Detach the flow database from the ulp context. */
295         bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, NULL);
296
297         /* Free up all the memory. */
298         ulp_flow_db_dealloc_resource(flow_db, BNXT_ULP_REGULAR_FLOW_TABLE);
299         ulp_flow_db_dealloc_resource(flow_db, BNXT_ULP_DEFAULT_FLOW_TABLE);
300         rte_free(flow_db);
301
302         return 0;
303 }
304
305 /*
306  * Allocate the flow database entry.
307  * The params->critical_resource has to be set to 0 to allocate a new resource.
308  *
309  * ulp_ctxt [in] Ptr to ulp_context
310  * tbl_idx [in] Specify it is regular or default flow
311  * fid [in] The index to the flow entry
312  * params [in] The contents to be copied into resource
313  *
314  * returns 0 on success and negative on failure.
315  */
316 int32_t ulp_flow_db_resource_add(struct bnxt_ulp_context        *ulp_ctxt,
317                                  enum bnxt_ulp_flow_db_tables   tbl_idx,
318                                  uint32_t                       fid,
319                                  struct ulp_flow_db_res_params  *params)
320 {
321         struct bnxt_ulp_flow_db         *flow_db;
322         struct bnxt_ulp_flow_tbl        *flow_tbl;
323         struct ulp_fdb_resource_info    *resource, *fid_resource;
324         uint32_t                        idx;
325
326         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
327         if (!flow_db) {
328                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
329                 return -EINVAL;
330         }
331
332         if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) {
333                 BNXT_TF_DBG(ERR, "Invalid table index\n");
334                 return -EINVAL;
335         }
336         flow_tbl = &flow_db->flow_tbl[tbl_idx];
337
338         /* check for max flows */
339         if (fid >= flow_tbl->num_flows || !fid) {
340                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
341                 return -EINVAL;
342         }
343
344         /* check if the flow is active or not */
345         if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) {
346                 BNXT_TF_DBG(ERR, "flow does not exist\n");
347                 return -EINVAL;
348         }
349
350         /* check for max resource */
351         if ((flow_tbl->num_flows + 1) >= flow_tbl->tail_index) {
352                 BNXT_TF_DBG(ERR, "Flow db has reached max resources\n");
353                 return -ENOMEM;
354         }
355         fid_resource = &flow_tbl->flow_resources[fid];
356
357         if (!params->critical_resource) {
358                 /* Not the critical_resource so allocate a resource */
359                 idx = flow_tbl->flow_tbl_stack[flow_tbl->tail_index];
360                 resource = &flow_tbl->flow_resources[idx];
361                 flow_tbl->tail_index--;
362
363                 /* Update the chain list of resource*/
364                 ULP_FLOW_DB_RES_NXT_SET(resource->nxt_resource_idx,
365                                         fid_resource->nxt_resource_idx);
366                 /* update the contents */
367                 ulp_flow_db_res_params_to_info(resource, params);
368                 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx);
369                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
370                                         idx);
371         } else {
372                 /* critical resource. Just update the fid resource */
373                 ulp_flow_db_res_params_to_info(fid_resource, params);
374         }
375
376         /* all good, return success */
377         return 0;
378 }
379
380 /*
381  * Free the flow database entry.
382  * The params->critical_resource has to be set to 1 to free the first resource.
383  *
384  * ulp_ctxt [in] Ptr to ulp_context
385  * tbl_idx [in] Specify it is regular or default flow
386  * fid [in] The index to the flow entry
387  * params [in/out] The contents to be copied into params.
388  * Onlythe critical_resource needs to be set by the caller.
389  *
390  * Returns 0 on success and negative on failure.
391  */
392 int32_t ulp_flow_db_resource_del(struct bnxt_ulp_context        *ulp_ctxt,
393                                  enum bnxt_ulp_flow_db_tables   tbl_idx,
394                                  uint32_t                       fid,
395                                  struct ulp_flow_db_res_params  *params)
396 {
397         struct bnxt_ulp_flow_db         *flow_db;
398         struct bnxt_ulp_flow_tbl        *flow_tbl;
399         struct ulp_fdb_resource_info    *nxt_resource, *fid_resource;
400         uint32_t                        nxt_idx = 0;
401
402         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
403         if (!flow_db) {
404                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
405                 return -EINVAL;
406         }
407
408         if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) {
409                 BNXT_TF_DBG(ERR, "Invalid table index\n");
410                 return -EINVAL;
411         }
412         flow_tbl = &flow_db->flow_tbl[tbl_idx];
413
414         /* check for max flows */
415         if (fid >= flow_tbl->num_flows || !fid) {
416                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
417                 return -EINVAL;
418         }
419
420         /* check if the flow is active or not */
421         if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) {
422                 BNXT_TF_DBG(ERR, "flow does not exist\n");
423                 return -EINVAL;
424         }
425
426         fid_resource = &flow_tbl->flow_resources[fid];
427         if (!params->critical_resource) {
428                 /* Not the critical resource so free the resource */
429                 ULP_FLOW_DB_RES_NXT_SET(nxt_idx,
430                                         fid_resource->nxt_resource_idx);
431                 if (!nxt_idx) {
432                         /* reached end of resources */
433                         return -ENOENT;
434                 }
435                 nxt_resource = &flow_tbl->flow_resources[nxt_idx];
436
437                 /* connect the fid resource to the next resource */
438                 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx);
439                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
440                                         nxt_resource->nxt_resource_idx);
441
442                 /* update the contents to be given to caller */
443                 ulp_flow_db_res_info_to_params(nxt_resource, params);
444
445                 /* Delete the nxt_resource */
446                 memset(nxt_resource, 0, sizeof(struct ulp_fdb_resource_info));
447
448                 /* add it to the free list */
449                 flow_tbl->tail_index++;
450                 if (flow_tbl->tail_index >= flow_tbl->num_resources) {
451                         BNXT_TF_DBG(ERR, "FlowDB:Tail reached max\n");
452                         return -ENOENT;
453                 }
454                 flow_tbl->flow_tbl_stack[flow_tbl->tail_index] = nxt_idx;
455
456         } else {
457                 /* Critical resource. copy the contents and exit */
458                 ulp_flow_db_res_info_to_params(fid_resource, params);
459                 ULP_FLOW_DB_RES_NXT_SET(nxt_idx,
460                                         fid_resource->nxt_resource_idx);
461                 memset(fid_resource, 0, sizeof(struct ulp_fdb_resource_info));
462                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
463                                         nxt_idx);
464         }
465
466         /* all good, return success */
467         return 0;
468 }
469
470 /*
471  * Free the flow database entry
472  *
473  * ulp_ctxt [in] Ptr to ulp_context
474  * tbl_idx [in] Specify it is regular or default flow
475  * fid [in] The index to the flow entry
476  *
477  * returns 0 on success and negative on failure.
478  */
479 int32_t ulp_flow_db_fid_free(struct bnxt_ulp_context            *ulp_ctxt,
480                              enum bnxt_ulp_flow_db_tables       tbl_idx,
481                              uint32_t                           fid)
482 {
483         struct bnxt_ulp_flow_db         *flow_db;
484         struct bnxt_ulp_flow_tbl        *flow_tbl;
485
486         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
487         if (!flow_db) {
488                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
489                 return -EINVAL;
490         }
491
492         if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) {
493                 BNXT_TF_DBG(ERR, "Invalid table index\n");
494                 return -EINVAL;
495         }
496
497         flow_tbl = &flow_db->flow_tbl[tbl_idx];
498
499         /* check for limits of fid */
500         if (fid >= flow_tbl->num_flows || !fid) {
501                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
502                 return -EINVAL;
503         }
504
505         /* check if the flow is active or not */
506         if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) {
507                 BNXT_TF_DBG(ERR, "flow does not exist\n");
508                 return -EINVAL;
509         }
510         flow_tbl->head_index--;
511         if (!flow_tbl->head_index) {
512                 BNXT_TF_DBG(ERR, "FlowDB: Head Ptr is zero\n");
513                 return -ENOENT;
514         }
515         flow_tbl->flow_tbl_stack[flow_tbl->head_index] = fid;
516         ulp_flow_db_active_flow_set(flow_tbl, fid, 0);
517
518         /* all good, return success */
519         return 0;
520 }