xref: /dpdk/drivers/net/bnxt/tf_ulp/ulp_flow_db.c (revision c14ef1ec)
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 flow table
31  * No validation is done in this function.
32  *
33  * flow_tbl [in] Ptr to flow table
34  * idx [in] The index to bit to be set or reset.
35  * flag [in] 1 to set and 0 to reset.
36  *
37  * returns none
38  */
39 static void
40 ulp_flow_db_active_flow_set(struct bnxt_ulp_flow_tbl	*flow_tbl,
41 			    uint32_t			idx,
42 			    uint32_t			flag)
43 {
44 	uint32_t		active_index;
45 
46 	active_index = idx / ULP_INDEX_BITMAP_SIZE;
47 	if (flag)
48 		ULP_INDEX_BITMAP_SET(flow_tbl->active_flow_tbl[active_index],
49 				     idx);
50 	else
51 		ULP_INDEX_BITMAP_RESET(flow_tbl->active_flow_tbl[active_index],
52 				       idx);
53 }
54 
55 /*
56  * Helper function to allocate the flow table and initialize
57  * is set.No validation being done in this function.
58  *
59  * flow_tbl [in] Ptr to flow table
60  * idx [in] The index to bit to be set or reset.
61  *
62  * returns 1 on set or 0 if not set.
63  */
64 static int32_t
65 ulp_flow_db_active_flow_is_set(struct bnxt_ulp_flow_tbl	*flow_tbl,
66 			       uint32_t			idx)
67 {
68 	uint32_t		active_index;
69 
70 	active_index = idx / ULP_INDEX_BITMAP_SIZE;
71 	return ULP_INDEX_BITMAP_GET(flow_tbl->active_flow_tbl[active_index],
72 				    idx);
73 }
74 
75 static uint8_t
76 ulp_flow_db_resource_func_get(struct ulp_fdb_resource_info *res_info)
77 {
78 	uint8_t func;
79 
80 	func = (((res_info->nxt_resource_idx & ULP_FLOW_DB_RES_FUNC_MASK) >>
81 		 ULP_FLOW_DB_RES_FUNC_BITS) << ULP_FLOW_DB_RES_FUNC_UPPER);
82 	/* The reource func is split into upper and lower */
83 	if (func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER)
84 		return (func | res_info->resource_func_lower);
85 	return func;
86 }
87 
88 /*
89  * Helper function to copy the resource params to resource info
90  *  No validation being done in this function.
91  *
92  * resource_info [out] Ptr to resource information
93  * params [in] The input params from the caller
94  * returns none
95  */
96 static void
97 ulp_flow_db_res_params_to_info(struct ulp_fdb_resource_info *resource_info,
98 			       struct ulp_flow_db_res_params *params)
99 {
100 	uint32_t resource_func;
101 
102 	resource_info->nxt_resource_idx |= ((params->direction <<
103 				      ULP_FLOW_DB_RES_DIR_BIT) &
104 				     ULP_FLOW_DB_RES_DIR_MASK);
105 	resource_func = (params->resource_func >> ULP_FLOW_DB_RES_FUNC_UPPER);
106 	resource_info->nxt_resource_idx |= ((resource_func <<
107 					     ULP_FLOW_DB_RES_FUNC_BITS) &
108 					    ULP_FLOW_DB_RES_FUNC_MASK);
109 
110 	if (params->resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) {
111 		/* Break the resource func into two parts */
112 		resource_func = (params->resource_func &
113 				 ULP_FLOW_DB_RES_FUNC_LOWER_MASK);
114 		resource_info->resource_func_lower = resource_func;
115 	}
116 
117 	/* Store the handle as 64bit only for EM table entries */
118 	if (params->resource_func != BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE &&
119 	    params->resource_func != BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) {
120 		resource_info->resource_hndl = (uint32_t)params->resource_hndl;
121 		resource_info->resource_type = params->resource_type;
122 		resource_info->resource_sub_type = params->resource_sub_type;
123 		resource_info->reserved = params->reserved;
124 	} else {
125 		resource_info->resource_em_handle = params->resource_hndl;
126 	}
127 }
128 
129 /*
130  * Helper function to copy the resource params to resource info
131  *  No validation being done in this function.
132  *
133  * resource_info [in] Ptr to resource information
134  * params [out] The output params to the caller
135  *
136  * returns none
137  */
138 static void
139 ulp_flow_db_res_info_to_params(struct ulp_fdb_resource_info *resource_info,
140 			       struct ulp_flow_db_res_params *params)
141 {
142 	memset(params, 0, sizeof(struct ulp_flow_db_res_params));
143 	params->direction = ((resource_info->nxt_resource_idx &
144 				 ULP_FLOW_DB_RES_DIR_MASK) >>
145 				 ULP_FLOW_DB_RES_DIR_BIT);
146 
147 	/* use the helper function to get the resource func */
148 	params->resource_func = ulp_flow_db_resource_func_get(resource_info);
149 
150 	if (params->resource_func == BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE ||
151 	    params->resource_func == BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) {
152 		params->resource_hndl = resource_info->resource_em_handle;
153 	} else if (params->resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) {
154 		params->resource_hndl = resource_info->resource_hndl;
155 		params->resource_type = resource_info->resource_type;
156 		params->resource_sub_type = resource_info->resource_sub_type;
157 		params->reserved = resource_info->reserved;
158 	}
159 }
160 
161 /*
162  * Helper function to allocate the flow table and initialize
163  * the stack for allocation operations.
164  *
165  * flow_db [in] Ptr to flow database structure
166  * tbl_idx [in] The index to table creation.
167  *
168  * Returns 0 on success or negative number on failure.
169  */
170 static int32_t
171 ulp_flow_db_alloc_resource(struct bnxt_ulp_flow_db *flow_db,
172 			   enum bnxt_ulp_flow_db_tables tbl_idx)
173 {
174 	uint32_t			idx = 0;
175 	struct bnxt_ulp_flow_tbl	*flow_tbl;
176 	uint32_t			size;
177 
178 	flow_tbl = &flow_db->flow_tbl[tbl_idx];
179 
180 	size = sizeof(struct ulp_fdb_resource_info) * flow_tbl->num_resources;
181 	flow_tbl->flow_resources =
182 			rte_zmalloc("ulp_fdb_resource_info", size, 0);
183 
184 	if (!flow_tbl->flow_resources) {
185 		BNXT_TF_DBG(ERR, "Failed to alloc memory for flow table\n");
186 		return -ENOMEM;
187 	}
188 	size = sizeof(uint32_t) * flow_tbl->num_resources;
189 	flow_tbl->flow_tbl_stack = rte_zmalloc("flow_tbl_stack", size, 0);
190 	if (!flow_tbl->flow_tbl_stack) {
191 		BNXT_TF_DBG(ERR, "Failed to alloc memory flow tbl stack\n");
192 		return -ENOMEM;
193 	}
194 	size = (flow_tbl->num_flows / sizeof(uint64_t)) + 1;
195 	flow_tbl->active_flow_tbl = rte_zmalloc("active flow tbl", size, 0);
196 	if (!flow_tbl->active_flow_tbl) {
197 		BNXT_TF_DBG(ERR, "Failed to alloc memory active tbl\n");
198 		return -ENOMEM;
199 	}
200 
201 	/* Initialize the stack table. */
202 	for (idx = 0; idx < flow_tbl->num_resources; idx++)
203 		flow_tbl->flow_tbl_stack[idx] = idx;
204 
205 	/* Ignore the first element in the list. */
206 	flow_tbl->head_index = 1;
207 	/* Tail points to the last entry in the list. */
208 	flow_tbl->tail_index = flow_tbl->num_resources - 1;
209 	return 0;
210 }
211 
212 /*
213  * Helper function to deallocate the flow table.
214  *
215  * flow_db [in] Ptr to flow database structure
216  * tbl_idx [in] The index to table creation.
217  *
218  * Returns none.
219  */
220 static void
221 ulp_flow_db_dealloc_resource(struct bnxt_ulp_flow_db *flow_db,
222 			     enum bnxt_ulp_flow_db_tables tbl_idx)
223 {
224 	struct bnxt_ulp_flow_tbl	*flow_tbl;
225 
226 	flow_tbl = &flow_db->flow_tbl[tbl_idx];
227 
228 	/* Free all the allocated tables in the flow table. */
229 	if (flow_tbl->active_flow_tbl) {
230 		rte_free(flow_tbl->active_flow_tbl);
231 		flow_tbl->active_flow_tbl = NULL;
232 	}
233 
234 	if (flow_tbl->flow_tbl_stack) {
235 		rte_free(flow_tbl->flow_tbl_stack);
236 		flow_tbl->flow_tbl_stack = NULL;
237 	}
238 
239 	if (flow_tbl->flow_resources) {
240 		rte_free(flow_tbl->flow_resources);
241 		flow_tbl->flow_resources = NULL;
242 	}
243 }
244 
245 /*
246  * Helper function to add function id to the flow table
247  *
248  * flow_db [in] Ptr to flow table
249  * flow_id [in] The flow id of the flow
250  * func_id [in] The func_id to be set, for reset pass zero
251  *
252  * returns none
253  */
254 static void
255 ulp_flow_db_func_id_set(struct bnxt_ulp_flow_db *flow_db,
256 			uint32_t flow_id,
257 			uint32_t func_id)
258 {
259 	/* set the function id in the function table */
260 	if (flow_id < flow_db->func_id_tbl_size)
261 		flow_db->func_id_tbl[flow_id] = func_id;
262 	else /* This should never happen */
263 		BNXT_TF_DBG(ERR, "Invalid flow id, flowdb corrupt\n");
264 }
265 
266 /*
267  * Initialize the flow database. Memory is allocated in this
268  * call and assigned to the flow database.
269  *
270  * ulp_ctxt [in] Ptr to ulp context
271  *
272  * Returns 0 on success or negative number on failure.
273  */
274 int32_t	ulp_flow_db_init(struct bnxt_ulp_context *ulp_ctxt)
275 {
276 	struct bnxt_ulp_device_params		*dparms;
277 	struct bnxt_ulp_flow_tbl		*flow_tbl;
278 	struct bnxt_ulp_flow_db			*flow_db;
279 	uint32_t				dev_id;
280 
281 	/* Get the dev specific number of flows that needed to be supported. */
282 	if (bnxt_ulp_cntxt_dev_id_get(ulp_ctxt, &dev_id)) {
283 		BNXT_TF_DBG(ERR, "Invalid device id\n");
284 		return -EINVAL;
285 	}
286 
287 	dparms = bnxt_ulp_device_params_get(dev_id);
288 	if (!dparms) {
289 		BNXT_TF_DBG(ERR, "could not fetch the device params\n");
290 		return -ENODEV;
291 	}
292 
293 	flow_db = rte_zmalloc("bnxt_ulp_flow_db",
294 			      sizeof(struct bnxt_ulp_flow_db), 0);
295 	if (!flow_db) {
296 		BNXT_TF_DBG(ERR,
297 			    "Failed to allocate memory for flow table ptr\n");
298 		return -ENOMEM;
299 	}
300 
301 	/* Attach the flow database to the ulp context. */
302 	bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, flow_db);
303 
304 	/* Populate the regular flow table limits. */
305 	flow_tbl = &flow_db->flow_tbl[BNXT_ULP_REGULAR_FLOW_TABLE];
306 	flow_tbl->num_flows = dparms->flow_db_num_entries + 1;
307 	flow_tbl->num_resources = (flow_tbl->num_flows *
308 				   dparms->num_resources_per_flow);
309 
310 	/* Populate the default flow table limits. */
311 	flow_tbl = &flow_db->flow_tbl[BNXT_ULP_DEFAULT_FLOW_TABLE];
312 	flow_tbl->num_flows = BNXT_FLOW_DB_DEFAULT_NUM_FLOWS + 1;
313 	flow_tbl->num_resources = (flow_tbl->num_flows *
314 				   BNXT_FLOW_DB_DEFAULT_NUM_RESOURCES);
315 
316 	/* Allocate the resource for the regular flow table. */
317 	if (ulp_flow_db_alloc_resource(flow_db, BNXT_ULP_REGULAR_FLOW_TABLE))
318 		goto error_free;
319 	if (ulp_flow_db_alloc_resource(flow_db, BNXT_ULP_DEFAULT_FLOW_TABLE))
320 		goto error_free;
321 
322 	/* add 1 since we are not using index 0 for flow id */
323 	flow_db->func_id_tbl_size = dparms->flow_db_num_entries + 1;
324 	/* Allocate the function Id table */
325 	flow_db->func_id_tbl = rte_zmalloc("bnxt_ulp_flow_db_func_id_table",
326 					   flow_db->func_id_tbl_size *
327 					   sizeof(uint16_t), 0);
328 	if (!flow_db->func_id_tbl) {
329 		BNXT_TF_DBG(ERR,
330 			    "Failed to allocate mem for flow table func id\n");
331 		goto error_free;
332 	}
333 	/* All good so return. */
334 	return 0;
335 error_free:
336 	ulp_flow_db_deinit(ulp_ctxt);
337 	return -ENOMEM;
338 }
339 
340 /*
341  * Deinitialize the flow database. Memory is deallocated in
342  * this call and all flows should have been purged before this
343  * call.
344  *
345  * ulp_ctxt [in] Ptr to ulp context
346  *
347  * Returns 0 on success.
348  */
349 int32_t	ulp_flow_db_deinit(struct bnxt_ulp_context *ulp_ctxt)
350 {
351 	struct bnxt_ulp_flow_db			*flow_db;
352 
353 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
354 	if (!flow_db) {
355 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
356 		return -EINVAL;
357 	}
358 
359 	/* Detach the flow database from the ulp context. */
360 	bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, NULL);
361 
362 	/* Free up all the memory. */
363 	ulp_flow_db_dealloc_resource(flow_db, BNXT_ULP_REGULAR_FLOW_TABLE);
364 	ulp_flow_db_dealloc_resource(flow_db, BNXT_ULP_DEFAULT_FLOW_TABLE);
365 	rte_free(flow_db->func_id_tbl);
366 	rte_free(flow_db);
367 
368 	return 0;
369 }
370 
371 /*
372  * Allocate the flow database entry
373  *
374  * ulp_ctxt [in] Ptr to ulp_context
375  * tbl_idx [in] Specify it is regular or default flow
376  * fid [out] The index to the flow entry
377  *
378  * returns 0 on success and negative on failure.
379  */
380 int32_t ulp_flow_db_fid_alloc(struct bnxt_ulp_context *ulp_ctxt,
381 			      enum bnxt_ulp_flow_db_tables tbl_idx,
382 			      uint16_t func_id,
383 			      uint32_t *fid)
384 {
385 	struct bnxt_ulp_flow_db *flow_db;
386 	struct bnxt_ulp_flow_tbl *flow_tbl;
387 
388 	*fid = 0; /* Initialize fid to invalid value */
389 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
390 	if (!flow_db) {
391 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
392 		return -EINVAL;
393 	}
394 
395 	flow_tbl = &flow_db->flow_tbl[tbl_idx];
396 	/* check for max flows */
397 	if (flow_tbl->num_flows <= flow_tbl->head_index) {
398 		BNXT_TF_DBG(ERR, "Flow database has reached max flows\n");
399 		return -ENOMEM;
400 	}
401 	if (flow_tbl->tail_index <= (flow_tbl->head_index + 1)) {
402 		BNXT_TF_DBG(ERR, "Flow database has reached max resources\n");
403 		return -ENOMEM;
404 	}
405 	*fid = flow_tbl->flow_tbl_stack[flow_tbl->head_index];
406 	flow_tbl->head_index++;
407 	ulp_flow_db_active_flow_set(flow_tbl, *fid, 1);
408 
409 	/* The function id update is only valid for regular flow table */
410 	if (tbl_idx == BNXT_ULP_REGULAR_FLOW_TABLE)
411 		ulp_flow_db_func_id_set(flow_db, *fid, func_id);
412 
413 	/* all good, return success */
414 	return 0;
415 }
416 
417 /*
418  * Allocate the flow database entry.
419  * The params->critical_resource has to be set to 0 to allocate a new 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] The contents to be copied into resource
425  *
426  * returns 0 on success and negative on failure.
427  */
428 int32_t	ulp_flow_db_resource_add(struct bnxt_ulp_context	*ulp_ctxt,
429 				 enum bnxt_ulp_flow_db_tables	tbl_idx,
430 				 uint32_t			fid,
431 				 struct ulp_flow_db_res_params	*params)
432 {
433 	struct bnxt_ulp_flow_db		*flow_db;
434 	struct bnxt_ulp_flow_tbl	*flow_tbl;
435 	struct ulp_fdb_resource_info	*resource, *fid_resource;
436 	uint32_t			idx;
437 
438 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
439 	if (!flow_db) {
440 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
441 		return -EINVAL;
442 	}
443 
444 	if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) {
445 		BNXT_TF_DBG(ERR, "Invalid table index\n");
446 		return -EINVAL;
447 	}
448 	flow_tbl = &flow_db->flow_tbl[tbl_idx];
449 
450 	/* check for max flows */
451 	if (fid >= flow_tbl->num_flows || !fid) {
452 		BNXT_TF_DBG(ERR, "Invalid flow index\n");
453 		return -EINVAL;
454 	}
455 
456 	/* check if the flow is active or not */
457 	if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) {
458 		BNXT_TF_DBG(ERR, "flow does not exist\n");
459 		return -EINVAL;
460 	}
461 
462 	/* check for max resource */
463 	if ((flow_tbl->head_index + 1) >= flow_tbl->tail_index) {
464 		BNXT_TF_DBG(ERR, "Flow db has reached max resources\n");
465 		return -ENOMEM;
466 	}
467 	fid_resource = &flow_tbl->flow_resources[fid];
468 
469 	if (!params->critical_resource) {
470 		/* Not the critical_resource so allocate a resource */
471 		idx = flow_tbl->flow_tbl_stack[flow_tbl->tail_index];
472 		resource = &flow_tbl->flow_resources[idx];
473 		flow_tbl->tail_index--;
474 
475 		/* Update the chain list of resource*/
476 		ULP_FLOW_DB_RES_NXT_SET(resource->nxt_resource_idx,
477 					fid_resource->nxt_resource_idx);
478 		/* update the contents */
479 		ulp_flow_db_res_params_to_info(resource, params);
480 		ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx);
481 		ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
482 					idx);
483 	} else {
484 		/* critical resource. Just update the fid resource */
485 		ulp_flow_db_res_params_to_info(fid_resource, params);
486 	}
487 
488 	if (params->resource_type == TF_TBL_TYPE_ACT_STATS_64 &&
489 	    params->resource_sub_type ==
490 	    BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_INT_COUNT) {
491 		/* Store the first HW counter ID for this table */
492 		if (!ulp_fc_mgr_start_idx_isset(ulp_ctxt, params->direction))
493 			ulp_fc_mgr_start_idx_set(ulp_ctxt, params->direction,
494 						 params->resource_hndl);
495 
496 		ulp_fc_mgr_cntr_set(ulp_ctxt, params->direction,
497 				    params->resource_hndl);
498 
499 		if (!ulp_fc_mgr_thread_isstarted(ulp_ctxt))
500 			ulp_fc_mgr_thread_start(ulp_ctxt);
501 	}
502 
503 	/* all good, return success */
504 	return 0;
505 }
506 
507 /*
508  * Free the flow database entry.
509  * The params->critical_resource has to be set to 1 to free the first resource.
510  *
511  * ulp_ctxt [in] Ptr to ulp_context
512  * tbl_idx [in] Specify it is regular or default flow
513  * fid [in] The index to the flow entry
514  * params [in/out] The contents to be copied into params.
515  * Onlythe critical_resource needs to be set by the caller.
516  *
517  * Returns 0 on success and negative on failure.
518  */
519 int32_t	ulp_flow_db_resource_del(struct bnxt_ulp_context	*ulp_ctxt,
520 				 enum bnxt_ulp_flow_db_tables	tbl_idx,
521 				 uint32_t			fid,
522 				 struct ulp_flow_db_res_params	*params)
523 {
524 	struct bnxt_ulp_flow_db		*flow_db;
525 	struct bnxt_ulp_flow_tbl	*flow_tbl;
526 	struct ulp_fdb_resource_info	*nxt_resource, *fid_resource;
527 	uint32_t			nxt_idx = 0;
528 
529 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
530 	if (!flow_db) {
531 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
532 		return -EINVAL;
533 	}
534 
535 	if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) {
536 		BNXT_TF_DBG(ERR, "Invalid table index\n");
537 		return -EINVAL;
538 	}
539 	flow_tbl = &flow_db->flow_tbl[tbl_idx];
540 
541 	/* check for max flows */
542 	if (fid >= flow_tbl->num_flows || !fid) {
543 		BNXT_TF_DBG(ERR, "Invalid flow index\n");
544 		return -EINVAL;
545 	}
546 
547 	/* check if the flow is active or not */
548 	if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) {
549 		BNXT_TF_DBG(ERR, "flow does not exist\n");
550 		return -EINVAL;
551 	}
552 
553 	fid_resource = &flow_tbl->flow_resources[fid];
554 	if (!params->critical_resource) {
555 		/* Not the critical resource so free the resource */
556 		ULP_FLOW_DB_RES_NXT_SET(nxt_idx,
557 					fid_resource->nxt_resource_idx);
558 		if (!nxt_idx) {
559 			/* reached end of resources */
560 			return -ENOENT;
561 		}
562 		nxt_resource = &flow_tbl->flow_resources[nxt_idx];
563 
564 		/* connect the fid resource to the next resource */
565 		ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx);
566 		ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
567 					nxt_resource->nxt_resource_idx);
568 
569 		/* update the contents to be given to caller */
570 		ulp_flow_db_res_info_to_params(nxt_resource, params);
571 
572 		/* Delete the nxt_resource */
573 		memset(nxt_resource, 0, sizeof(struct ulp_fdb_resource_info));
574 
575 		/* add it to the free list */
576 		flow_tbl->tail_index++;
577 		if (flow_tbl->tail_index >= flow_tbl->num_resources) {
578 			BNXT_TF_DBG(ERR, "FlowDB:Tail reached max\n");
579 			return -ENOENT;
580 		}
581 		flow_tbl->flow_tbl_stack[flow_tbl->tail_index] = nxt_idx;
582 
583 	} else {
584 		/* Critical resource. copy the contents and exit */
585 		ulp_flow_db_res_info_to_params(fid_resource, params);
586 		ULP_FLOW_DB_RES_NXT_SET(nxt_idx,
587 					fid_resource->nxt_resource_idx);
588 		memset(fid_resource, 0, sizeof(struct ulp_fdb_resource_info));
589 		ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
590 					nxt_idx);
591 	}
592 
593 	/* Now that the HW Flow counter resource is deleted, reset it's
594 	 * corresponding slot in the SW accumulation table in the Flow Counter
595 	 * manager
596 	 */
597 	if (params->resource_type == TF_TBL_TYPE_ACT_STATS_64 &&
598 	    params->resource_sub_type ==
599 	    BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_INT_COUNT) {
600 		ulp_fc_mgr_cntr_reset(ulp_ctxt, params->direction,
601 				      params->resource_hndl);
602 	}
603 
604 	/* all good, return success */
605 	return 0;
606 }
607 
608 /*
609  * Free the flow database entry
610  *
611  * ulp_ctxt [in] Ptr to ulp_context
612  * tbl_idx [in] Specify it is regular or default flow
613  * fid [in] The index to the flow entry
614  *
615  * returns 0 on success and negative on failure.
616  */
617 int32_t	ulp_flow_db_fid_free(struct bnxt_ulp_context		*ulp_ctxt,
618 			     enum bnxt_ulp_flow_db_tables	tbl_idx,
619 			     uint32_t				fid)
620 {
621 	struct bnxt_ulp_flow_db		*flow_db;
622 	struct bnxt_ulp_flow_tbl	*flow_tbl;
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 	flow_tbl->head_index--;
649 	if (!flow_tbl->head_index) {
650 		BNXT_TF_DBG(ERR, "FlowDB: Head Ptr is zero\n");
651 		return -ENOENT;
652 	}
653 	flow_tbl->flow_tbl_stack[flow_tbl->head_index] = fid;
654 	ulp_flow_db_active_flow_set(flow_tbl, fid, 0);
655 	if (tbl_idx == BNXT_ULP_REGULAR_FLOW_TABLE)
656 		ulp_flow_db_func_id_set(flow_db, fid, 0);
657 
658 	/* all good, return success */
659 	return 0;
660 }
661 
662 /*
663  * Get the flow database entry details
664  *
665  * ulp_ctxt [in] Ptr to ulp_context
666  * tbl_idx [in] Specify it is regular or default flow
667  * fid [in] The index to the flow entry
668  * nxt_idx [in/out] the index to the next entry
669  * params [out] The contents to be copied into params.
670  *
671  * returns 0 on success and negative on failure.
672  */
673 int32_t	ulp_flow_db_resource_get(struct bnxt_ulp_context	*ulp_ctxt,
674 				 enum bnxt_ulp_flow_db_tables	tbl_idx,
675 				 uint32_t			fid,
676 				 uint32_t			*nxt_idx,
677 				 struct ulp_flow_db_res_params	*params)
678 {
679 	struct bnxt_ulp_flow_db		*flow_db;
680 	struct bnxt_ulp_flow_tbl	*flow_tbl;
681 	struct ulp_fdb_resource_info	*nxt_resource, *fid_resource;
682 
683 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
684 	if (!flow_db) {
685 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
686 		return -EINVAL;
687 	}
688 
689 	if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) {
690 		BNXT_TF_DBG(ERR, "Invalid table index\n");
691 		return -EINVAL;
692 	}
693 
694 	flow_tbl = &flow_db->flow_tbl[tbl_idx];
695 
696 	/* check for limits of fid */
697 	if (fid >= flow_tbl->num_flows || !fid) {
698 		BNXT_TF_DBG(ERR, "Invalid flow index\n");
699 		return -EINVAL;
700 	}
701 
702 	/* check if the flow is active or not */
703 	if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) {
704 		BNXT_TF_DBG(ERR, "flow does not exist\n");
705 		return -EINVAL;
706 	}
707 
708 	if (!*nxt_idx) {
709 		fid_resource = &flow_tbl->flow_resources[fid];
710 		ulp_flow_db_res_info_to_params(fid_resource, params);
711 		ULP_FLOW_DB_RES_NXT_SET(*nxt_idx,
712 					fid_resource->nxt_resource_idx);
713 	} else {
714 		nxt_resource = &flow_tbl->flow_resources[*nxt_idx];
715 		ulp_flow_db_res_info_to_params(nxt_resource, params);
716 		*nxt_idx = 0;
717 		ULP_FLOW_DB_RES_NXT_SET(*nxt_idx,
718 					nxt_resource->nxt_resource_idx);
719 	}
720 
721 	/* all good, return success */
722 	return 0;
723 }
724 
725 /*
726  * Get the flow database entry iteratively
727  *
728  * flow_tbl [in] Ptr to flow table
729  * fid [in/out] The index to the flow entry
730  *
731  * returns 0 on success and negative on failure.
732  */
733 static int32_t
734 ulp_flow_db_next_entry_get(struct bnxt_ulp_flow_tbl	*flowtbl,
735 			   uint32_t			*fid)
736 {
737 	uint32_t	lfid = *fid;
738 	uint32_t	idx, s_idx, mod_fid;
739 	uint64_t	bs;
740 
741 	do {
742 		/* increment the flow id to find the next valid flow id */
743 		lfid++;
744 		if (lfid >= flowtbl->num_flows)
745 			return -ENOENT;
746 		idx = lfid / ULP_INDEX_BITMAP_SIZE;
747 		mod_fid = lfid % ULP_INDEX_BITMAP_SIZE;
748 		s_idx = idx;
749 		while (!(bs = flowtbl->active_flow_tbl[idx])) {
750 			idx++;
751 			if ((idx * ULP_INDEX_BITMAP_SIZE) >= flowtbl->num_flows)
752 				return -ENOENT;
753 		}
754 		/*
755 		 * remove the previous bits in the bitset bs to find the
756 		 * next non zero bit in the bitset. This needs to be done
757 		 * only if the idx is same as he one you started.
758 		 */
759 		if (s_idx == idx)
760 			bs &= (-1UL >> mod_fid);
761 		lfid = (idx * ULP_INDEX_BITMAP_SIZE) + __builtin_clzl(bs);
762 		if (*fid >= lfid) {
763 			BNXT_TF_DBG(ERR, "Flow Database is corrupt\n");
764 			return -ENOENT;
765 		}
766 	} while (!ulp_flow_db_active_flow_is_set(flowtbl, lfid));
767 
768 	/* all good, return success */
769 	*fid = lfid;
770 	return 0;
771 }
772 
773 /*
774  * Flush all flows in the flow database.
775  *
776  * ulp_ctxt [in] Ptr to ulp context
777  * tbl_idx [in] The index to table
778  *
779  * returns 0 on success or negative number on failure
780  */
781 int32_t	ulp_flow_db_flush_flows(struct bnxt_ulp_context *ulp_ctx,
782 				uint32_t		idx)
783 {
784 	uint32_t			fid = 0;
785 	struct bnxt_ulp_flow_db		*flow_db;
786 	struct bnxt_ulp_flow_tbl	*flow_tbl;
787 
788 	if (!ulp_ctx) {
789 		BNXT_TF_DBG(ERR, "Invalid Argument\n");
790 		return -EINVAL;
791 	}
792 
793 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
794 	if (!flow_db) {
795 		BNXT_TF_DBG(ERR, "Flow database not found\n");
796 		return -EINVAL;
797 	}
798 	flow_tbl = &flow_db->flow_tbl[idx];
799 	while (!ulp_flow_db_next_entry_get(flow_tbl, &fid))
800 		ulp_mapper_resources_free(ulp_ctx, fid, idx);
801 
802 	return 0;
803 }
804 
805 /*
806  * Flush all flows in the flow database that belong to a device function.
807  *
808  * ulp_ctxt [in] Ptr to ulp context
809  * tbl_idx [in] The index to table
810  *
811  * returns 0 on success or negative number on failure
812  */
813 int32_t
814 ulp_flow_db_function_flow_flush(struct bnxt_ulp_context *ulp_ctx,
815 				uint16_t func_id)
816 {
817 	uint32_t flow_id = 0;
818 	struct bnxt_ulp_flow_db *flow_db;
819 	struct bnxt_ulp_flow_tbl *flow_tbl;
820 
821 	if (!ulp_ctx || !func_id) {
822 		BNXT_TF_DBG(ERR, "Invalid Argument\n");
823 		return -EINVAL;
824 	}
825 
826 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
827 	if (!flow_db) {
828 		BNXT_TF_DBG(ERR, "Flow database not found\n");
829 		return -EINVAL;
830 	}
831 	flow_tbl = &flow_db->flow_tbl[BNXT_ULP_REGULAR_FLOW_TABLE];
832 	while (!ulp_flow_db_next_entry_get(flow_tbl, &flow_id)) {
833 		if (flow_db->func_id_tbl[flow_id] == func_id)
834 			ulp_mapper_resources_free(ulp_ctx, flow_id,
835 						  BNXT_ULP_REGULAR_FLOW_TABLE);
836 	}
837 
838 	return 0;
839 }
840 
841 /*
842  * Flush all flows in the flow database that are associated with the session.
843  *
844  * ulp_ctxt [in] Ptr to ulp context
845  *
846  * returns 0 on success or negative number on failure
847  */
848 int32_t
849 ulp_flow_db_session_flow_flush(struct bnxt_ulp_context *ulp_ctx)
850 {
851 	/*
852 	 * TBD: Tf core implementation of FW session flush shall change this
853 	 * implementation.
854 	 */
855 	return ulp_flow_db_flush_flows(ulp_ctx, BNXT_ULP_REGULAR_FLOW_TABLE);
856 }
857 
858 /*
859  * Check that flow id matches the function id or not
860  *
861  * ulp_ctxt [in] Ptr to ulp context
862  * flow_db [in] Ptr to flow table
863  * func_id [in] The func_id to be set, for reset pass zero.
864  *
865  * returns true on success or false on failure
866  */
867 bool
868 ulp_flow_db_validate_flow_func(struct bnxt_ulp_context *ulp_ctx,
869 			       uint32_t flow_id,
870 			       uint32_t func_id)
871 {
872 	struct bnxt_ulp_flow_db *flow_db;
873 
874 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
875 	if (!flow_db) {
876 		BNXT_TF_DBG(ERR, "Flow database not found\n");
877 		return false;
878 	}
879 
880 	/* set the function id in the function table */
881 	if (flow_id < flow_db->func_id_tbl_size && func_id &&
882 	    flow_db->func_id_tbl[flow_id] == func_id)
883 		return true;
884 
885 	return false;
886 }
887 
888 /*
889  * Internal api to traverse the resource list within a flow
890  * and match a resource based on resource func and resource
891  * sub type. This api should be used only for resources that
892  * are unique and do not have multiple instances of resource
893  * func and sub type combination since it will return only
894  * the first match.
895  */
896 static int32_t
897 ulp_flow_db_resource_hndl_get(struct bnxt_ulp_context *ulp_ctx,
898 			      enum bnxt_ulp_flow_db_tables tbl_idx,
899 			      uint32_t flow_id,
900 			      uint32_t resource_func,
901 			      uint32_t res_subtype,
902 			      uint64_t *res_hndl)
903 {
904 	struct bnxt_ulp_flow_db *flow_db;
905 	struct bnxt_ulp_flow_tbl *flow_tbl;
906 	struct ulp_fdb_resource_info *fid_res;
907 	uint32_t res_id;
908 
909 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
910 	if (!flow_db) {
911 		BNXT_TF_DBG(ERR, "Flow database not found\n");
912 		return -EINVAL;
913 	}
914 
915 	flow_tbl = &flow_db->flow_tbl[tbl_idx];
916 
917 	/* check for limits of fid */
918 	if (flow_id >= flow_tbl->num_flows || !flow_id) {
919 		BNXT_TF_DBG(ERR, "Invalid flow index\n");
920 		return -EINVAL;
921 	}
922 
923 	/* check if the flow is active or not */
924 	if (!ulp_flow_db_active_flow_is_set(flow_tbl, flow_id)) {
925 		BNXT_TF_DBG(ERR, "flow does not exist\n");
926 		return -EINVAL;
927 	}
928 	/* Iterate the resource to get the resource handle */
929 	res_id =  flow_id;
930 	while (res_id) {
931 		fid_res = &flow_tbl->flow_resources[res_id];
932 		if (ulp_flow_db_resource_func_get(fid_res) == resource_func) {
933 			if (resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) {
934 				if (res_subtype == fid_res->resource_sub_type) {
935 					*res_hndl = fid_res->resource_hndl;
936 					return 0;
937 				}
938 
939 			} else if (resource_func ==
940 				   BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE ||
941 				   resource_func ==
942 				   BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) {
943 				*res_hndl = fid_res->resource_em_handle;
944 				return 0;
945 			}
946 		}
947 		res_id = 0;
948 		ULP_FLOW_DB_RES_NXT_SET(res_id, fid_res->nxt_resource_idx);
949 	}
950 	return -ENOENT;
951 }
952 
953 /*
954  * Api to get the cfa action pointer from a flow.
955  *
956  * ulp_ctxt [in] Ptr to ulp context
957  * flow_id [in] flow id
958  * cfa_action [out] The resource handle stored in the flow database
959  *
960  * returns 0 on success
961  */
962 int32_t
963 ulp_default_flow_db_cfa_action_get(struct bnxt_ulp_context *ulp_ctx,
964 				   uint32_t flow_id,
965 				   uint16_t *cfa_action)
966 {
967 	uint8_t sub_type = BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_VFR_CFA_ACTION;
968 	uint64_t hndl;
969 	int32_t rc;
970 
971 	rc = ulp_flow_db_resource_hndl_get(ulp_ctx,
972 					   BNXT_ULP_DEFAULT_FLOW_TABLE,
973 					   flow_id,
974 					   BNXT_ULP_RESOURCE_FUNC_INDEX_TABLE,
975 					   sub_type, &hndl);
976 	if (rc) {
977 		BNXT_TF_DBG(ERR, "CFA Action ptr not found for flow id %u\n",
978 			    flow_id);
979 		return -ENOENT;
980 	}
981 	*cfa_action = hndl;
982 	return 0;
983 }
984 
985 #ifdef RTE_LIBRTE_BNXT_TRUFLOW_DEBUG
986 /*
987  * Dump the entry details
988  *
989  * ulp_ctxt [in] Ptr to ulp_context
990  *
991  * returns none
992  */
993 static void ulp_flow_db_res_dump(struct ulp_fdb_resource_info	*r,
994 				 uint32_t	*nxt_res)
995 {
996 	uint8_t res_func = ulp_flow_db_resource_func_get(r);
997 
998 	BNXT_TF_DBG(DEBUG, "Resource func = %x, nxt_resource_idx = %x\n",
999 		    res_func, (ULP_FLOW_DB_RES_NXT_MASK & r->nxt_resource_idx));
1000 	if (res_func == BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE ||
1001 	    res_func == BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE)
1002 		BNXT_TF_DBG(DEBUG, "EM Handle = 0x%016" PRIX64 "\n",
1003 			    r->resource_em_handle);
1004 	else
1005 		BNXT_TF_DBG(DEBUG, "Handle = 0x%08x\n", r->resource_hndl);
1006 
1007 	*nxt_res = 0;
1008 	ULP_FLOW_DB_RES_NXT_SET(*nxt_res,
1009 				r->nxt_resource_idx);
1010 }
1011 
1012 /*
1013  * Dump the flow database entry details
1014  *
1015  * ulp_ctxt [in] Ptr to ulp_context
1016  *
1017  * returns none
1018  */
1019 int32_t	ulp_flow_db_debug_dump(struct bnxt_ulp_context	*ulp_ctxt)
1020 {
1021 	struct bnxt_ulp_flow_db		*flow_db;
1022 	struct bnxt_ulp_flow_tbl	*flow_tbl;
1023 	struct ulp_fdb_resource_info	*r;
1024 	uint32_t			nxt_res = 0;
1025 	enum bnxt_ulp_flow_db_tables	tbl_idx;
1026 	uint32_t			fid;
1027 
1028 	if (!ulp_ctxt || !ulp_ctxt->cfg_data) {
1029 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
1030 		return -EINVAL;
1031 	}
1032 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
1033 	if (!flow_db) {
1034 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
1035 		return -EINVAL;
1036 	}
1037 
1038 	for (tbl_idx = 0; tbl_idx < BNXT_ULP_FLOW_TABLE_MAX; tbl_idx++) {
1039 		flow_tbl = &flow_db->flow_tbl[tbl_idx];
1040 		BNXT_TF_DBG(DEBUG, "Dump Tbl index = %u, flows = %u:%u\n",
1041 			    tbl_idx, flow_tbl->num_flows,
1042 			    flow_tbl->num_resources);
1043 		BNXT_TF_DBG(DEBUG, "Head_index = %u, Tail_index = %u\n",
1044 			    flow_tbl->head_index, flow_tbl->tail_index);
1045 		for (fid = 0; fid < flow_tbl->num_flows; fid++) {
1046 			if (ulp_flow_db_active_flow_is_set(flow_tbl, fid)) {
1047 				BNXT_TF_DBG(DEBUG, "fid = %u\n", fid);
1048 				/* iterate the resource */
1049 				nxt_res = fid;
1050 				do {
1051 					r = &flow_tbl->flow_resources[nxt_res];
1052 					ulp_flow_db_res_dump(r, &nxt_res);
1053 				} while (nxt_res);
1054 			}
1055 		}
1056 		BNXT_TF_DBG(DEBUG, "Done.\n");
1057 	}
1058 	return 0;
1059 }
1060 #endif
1061