net/bnxt: support alloc and program key and act 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  *
308  * ulp_ctxt [in] Ptr to ulp_context
309  * tbl_idx [in] Specify it is regular or default flow
310  * fid [out] The index to the flow entry
311  *
312  * returns 0 on success and negative on failure.
313  */
314 int32_t ulp_flow_db_fid_alloc(struct bnxt_ulp_context           *ulp_ctxt,
315                               enum bnxt_ulp_flow_db_tables      tbl_idx,
316                               uint32_t                          *fid)
317 {
318         struct bnxt_ulp_flow_db         *flow_db;
319         struct bnxt_ulp_flow_tbl        *flow_tbl;
320
321         *fid = 0; /* Initialize fid to invalid value */
322         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
323         if (!flow_db) {
324                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
325                 return -EINVAL;
326         }
327
328         flow_tbl = &flow_db->flow_tbl[tbl_idx];
329         /* check for max flows */
330         if (flow_tbl->num_flows <= flow_tbl->head_index) {
331                 BNXT_TF_DBG(ERR, "Flow database has reached max flows\n");
332                 return -ENOMEM;
333         }
334         *fid = flow_tbl->flow_tbl_stack[flow_tbl->head_index];
335         flow_tbl->head_index++;
336         ulp_flow_db_active_flow_set(flow_tbl, *fid, 1);
337
338         /* all good, return success */
339         return 0;
340 }
341
342 /*
343  * Allocate the flow database entry.
344  * The params->critical_resource has to be set to 0 to allocate a new resource.
345  *
346  * ulp_ctxt [in] Ptr to ulp_context
347  * tbl_idx [in] Specify it is regular or default flow
348  * fid [in] The index to the flow entry
349  * params [in] The contents to be copied into resource
350  *
351  * returns 0 on success and negative on failure.
352  */
353 int32_t ulp_flow_db_resource_add(struct bnxt_ulp_context        *ulp_ctxt,
354                                  enum bnxt_ulp_flow_db_tables   tbl_idx,
355                                  uint32_t                       fid,
356                                  struct ulp_flow_db_res_params  *params)
357 {
358         struct bnxt_ulp_flow_db         *flow_db;
359         struct bnxt_ulp_flow_tbl        *flow_tbl;
360         struct ulp_fdb_resource_info    *resource, *fid_resource;
361         uint32_t                        idx;
362
363         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
364         if (!flow_db) {
365                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
366                 return -EINVAL;
367         }
368
369         if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) {
370                 BNXT_TF_DBG(ERR, "Invalid table index\n");
371                 return -EINVAL;
372         }
373         flow_tbl = &flow_db->flow_tbl[tbl_idx];
374
375         /* check for max flows */
376         if (fid >= flow_tbl->num_flows || !fid) {
377                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
378                 return -EINVAL;
379         }
380
381         /* check if the flow is active or not */
382         if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) {
383                 BNXT_TF_DBG(ERR, "flow does not exist\n");
384                 return -EINVAL;
385         }
386
387         /* check for max resource */
388         if ((flow_tbl->num_flows + 1) >= flow_tbl->tail_index) {
389                 BNXT_TF_DBG(ERR, "Flow db has reached max resources\n");
390                 return -ENOMEM;
391         }
392         fid_resource = &flow_tbl->flow_resources[fid];
393
394         if (!params->critical_resource) {
395                 /* Not the critical_resource so allocate a resource */
396                 idx = flow_tbl->flow_tbl_stack[flow_tbl->tail_index];
397                 resource = &flow_tbl->flow_resources[idx];
398                 flow_tbl->tail_index--;
399
400                 /* Update the chain list of resource*/
401                 ULP_FLOW_DB_RES_NXT_SET(resource->nxt_resource_idx,
402                                         fid_resource->nxt_resource_idx);
403                 /* update the contents */
404                 ulp_flow_db_res_params_to_info(resource, params);
405                 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx);
406                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
407                                         idx);
408         } else {
409                 /* critical resource. Just update the fid resource */
410                 ulp_flow_db_res_params_to_info(fid_resource, params);
411         }
412
413         /* all good, return success */
414         return 0;
415 }
416
417 /*
418  * Free the flow database entry.
419  * The params->critical_resource has to be set to 1 to free the first resource.
420  *
421  * ulp_ctxt [in] Ptr to ulp_context
422  * tbl_idx [in] Specify it is regular or default flow
423  * fid [in] The index to the flow entry
424  * params [in/out] The contents to be copied into params.
425  * Onlythe critical_resource needs to be set by the caller.
426  *
427  * Returns 0 on success and negative on failure.
428  */
429 int32_t ulp_flow_db_resource_del(struct bnxt_ulp_context        *ulp_ctxt,
430                                  enum bnxt_ulp_flow_db_tables   tbl_idx,
431                                  uint32_t                       fid,
432                                  struct ulp_flow_db_res_params  *params)
433 {
434         struct bnxt_ulp_flow_db         *flow_db;
435         struct bnxt_ulp_flow_tbl        *flow_tbl;
436         struct ulp_fdb_resource_info    *nxt_resource, *fid_resource;
437         uint32_t                        nxt_idx = 0;
438
439         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
440         if (!flow_db) {
441                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
442                 return -EINVAL;
443         }
444
445         if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) {
446                 BNXT_TF_DBG(ERR, "Invalid table index\n");
447                 return -EINVAL;
448         }
449         flow_tbl = &flow_db->flow_tbl[tbl_idx];
450
451         /* check for max flows */
452         if (fid >= flow_tbl->num_flows || !fid) {
453                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
454                 return -EINVAL;
455         }
456
457         /* check if the flow is active or not */
458         if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) {
459                 BNXT_TF_DBG(ERR, "flow does not exist\n");
460                 return -EINVAL;
461         }
462
463         fid_resource = &flow_tbl->flow_resources[fid];
464         if (!params->critical_resource) {
465                 /* Not the critical resource so free the resource */
466                 ULP_FLOW_DB_RES_NXT_SET(nxt_idx,
467                                         fid_resource->nxt_resource_idx);
468                 if (!nxt_idx) {
469                         /* reached end of resources */
470                         return -ENOENT;
471                 }
472                 nxt_resource = &flow_tbl->flow_resources[nxt_idx];
473
474                 /* connect the fid resource to the next resource */
475                 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx);
476                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
477                                         nxt_resource->nxt_resource_idx);
478
479                 /* update the contents to be given to caller */
480                 ulp_flow_db_res_info_to_params(nxt_resource, params);
481
482                 /* Delete the nxt_resource */
483                 memset(nxt_resource, 0, sizeof(struct ulp_fdb_resource_info));
484
485                 /* add it to the free list */
486                 flow_tbl->tail_index++;
487                 if (flow_tbl->tail_index >= flow_tbl->num_resources) {
488                         BNXT_TF_DBG(ERR, "FlowDB:Tail reached max\n");
489                         return -ENOENT;
490                 }
491                 flow_tbl->flow_tbl_stack[flow_tbl->tail_index] = nxt_idx;
492
493         } else {
494                 /* Critical resource. copy the contents and exit */
495                 ulp_flow_db_res_info_to_params(fid_resource, params);
496                 ULP_FLOW_DB_RES_NXT_SET(nxt_idx,
497                                         fid_resource->nxt_resource_idx);
498                 memset(fid_resource, 0, sizeof(struct ulp_fdb_resource_info));
499                 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
500                                         nxt_idx);
501         }
502
503         /* all good, return success */
504         return 0;
505 }
506
507 /*
508  * Free the flow database entry
509  *
510  * ulp_ctxt [in] Ptr to ulp_context
511  * tbl_idx [in] Specify it is regular or default flow
512  * fid [in] The index to the flow entry
513  *
514  * returns 0 on success and negative on failure.
515  */
516 int32_t ulp_flow_db_fid_free(struct bnxt_ulp_context            *ulp_ctxt,
517                              enum bnxt_ulp_flow_db_tables       tbl_idx,
518                              uint32_t                           fid)
519 {
520         struct bnxt_ulp_flow_db         *flow_db;
521         struct bnxt_ulp_flow_tbl        *flow_tbl;
522
523         flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
524         if (!flow_db) {
525                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
526                 return -EINVAL;
527         }
528
529         if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) {
530                 BNXT_TF_DBG(ERR, "Invalid table index\n");
531                 return -EINVAL;
532         }
533
534         flow_tbl = &flow_db->flow_tbl[tbl_idx];
535
536         /* check for limits of fid */
537         if (fid >= flow_tbl->num_flows || !fid) {
538                 BNXT_TF_DBG(ERR, "Invalid flow index\n");
539                 return -EINVAL;
540         }
541
542         /* check if the flow is active or not */
543         if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) {
544                 BNXT_TF_DBG(ERR, "flow does not exist\n");
545                 return -EINVAL;
546         }
547         flow_tbl->head_index--;
548         if (!flow_tbl->head_index) {
549                 BNXT_TF_DBG(ERR, "FlowDB: Head Ptr is zero\n");
550                 return -ENOENT;
551         }
552         flow_tbl->flow_tbl_stack[flow_tbl->head_index] = fid;
553         ulp_flow_db_active_flow_set(flow_tbl, fid, 0);
554
555         /* all good, return success */
556         return 0;
557 }