xref: /dpdk/drivers/net/bnxt/tf_ulp/ulp_flow_db.c (revision 0f27fe09)
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_utils.h"
10 #include "ulp_template_struct.h"
11 #include "ulp_mapper.h"
12 #include "ulp_flow_db.h"
13 #include "ulp_fc_mgr.h"
14 
15 #define ULP_FLOW_DB_RES_DIR_BIT		31
16 #define ULP_FLOW_DB_RES_DIR_MASK	0x80000000
17 #define ULP_FLOW_DB_RES_FUNC_BITS	28
18 #define ULP_FLOW_DB_RES_FUNC_MASK	0x70000000
19 #define ULP_FLOW_DB_RES_NXT_MASK	0x0FFFFFFF
20 #define ULP_FLOW_DB_RES_FUNC_UPPER	5
21 #define ULP_FLOW_DB_RES_FUNC_NEED_LOWER	0x80
22 #define ULP_FLOW_DB_RES_FUNC_LOWER_MASK	0x1F
23 
24 /* Macro to copy the nxt_resource_idx */
25 #define ULP_FLOW_DB_RES_NXT_SET(dst, src)	{(dst) |= ((src) &\
26 					 ULP_FLOW_DB_RES_NXT_MASK); }
27 #define ULP_FLOW_DB_RES_NXT_RESET(dst)	((dst) &= ~(ULP_FLOW_DB_RES_NXT_MASK))
28 
29 /*
30  * Helper function to set the bit in the active flows
31  * No validation is done in this function.
32  *
33  * flow_db [in] Ptr to flow database
34  * flow_type [in] - specify default or regular
35  * idx [in] The index to bit to be set or reset.
36  * flag [in] 1 to set and 0 to reset.
37  *
38  * returns none
39  */
40 static void
41 ulp_flow_db_active_flows_bit_set(struct bnxt_ulp_flow_db *flow_db,
42 				 enum bnxt_ulp_fdb_type flow_type,
43 				 uint32_t idx,
44 				 uint32_t flag)
45 {
46 	struct bnxt_ulp_flow_tbl *f_tbl = &flow_db->flow_tbl;
47 	uint32_t a_idx = idx / ULP_INDEX_BITMAP_SIZE;
48 
49 	if (flag) {
50 		if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR)
51 			ULP_INDEX_BITMAP_SET(f_tbl->active_reg_flows[a_idx],
52 					     idx);
53 		else
54 			ULP_INDEX_BITMAP_SET(f_tbl->active_dflt_flows[a_idx],
55 					     idx);
56 	} else {
57 		if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR)
58 			ULP_INDEX_BITMAP_RESET(f_tbl->active_reg_flows[a_idx],
59 					       idx);
60 		else
61 			ULP_INDEX_BITMAP_RESET(f_tbl->active_dflt_flows[a_idx],
62 					       idx);
63 	}
64 }
65 
66 /*
67  * Helper function to check if given fid is active flow.
68  * No validation being done in this function.
69  *
70  * flow_db [in] Ptr to flow database
71  * flow_type [in] - specify default or regular
72  * idx [in] The index to bit to be set or reset.
73  *
74  * returns 1 on set or 0 if not set.
75  */
76 static int32_t
77 ulp_flow_db_active_flows_bit_is_set(struct bnxt_ulp_flow_db *flow_db,
78 				    enum bnxt_ulp_fdb_type flow_type,
79 				    uint32_t idx)
80 {
81 	struct bnxt_ulp_flow_tbl *f_tbl = &flow_db->flow_tbl;
82 	uint32_t a_idx = idx / ULP_INDEX_BITMAP_SIZE;
83 
84 	if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR)
85 		return ULP_INDEX_BITMAP_GET(f_tbl->active_reg_flows[a_idx],
86 					    idx);
87 	else
88 		return ULP_INDEX_BITMAP_GET(f_tbl->active_dflt_flows[a_idx],
89 					    idx);
90 }
91 
92 static inline enum tf_dir
93 ulp_flow_db_resource_dir_get(struct ulp_fdb_resource_info *res_info)
94 {
95 	return ((res_info->nxt_resource_idx & ULP_FLOW_DB_RES_DIR_MASK) >>
96 		ULP_FLOW_DB_RES_DIR_BIT);
97 }
98 
99 static uint8_t
100 ulp_flow_db_resource_func_get(struct ulp_fdb_resource_info *res_info)
101 {
102 	uint8_t func;
103 
104 	func = (((res_info->nxt_resource_idx & ULP_FLOW_DB_RES_FUNC_MASK) >>
105 		 ULP_FLOW_DB_RES_FUNC_BITS) << ULP_FLOW_DB_RES_FUNC_UPPER);
106 	/* The reource func is split into upper and lower */
107 	if (func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER)
108 		return (func | res_info->resource_func_lower);
109 	return func;
110 }
111 
112 /*
113  * Helper function to copy the resource params to resource info
114  *  No validation being done in this function.
115  *
116  * resource_info [out] Ptr to resource information
117  * params [in] The input params from the caller
118  * returns none
119  */
120 static void
121 ulp_flow_db_res_params_to_info(struct ulp_fdb_resource_info *resource_info,
122 			       struct ulp_flow_db_res_params *params)
123 {
124 	uint32_t resource_func;
125 
126 	resource_info->nxt_resource_idx |= ((params->direction <<
127 				      ULP_FLOW_DB_RES_DIR_BIT) &
128 				     ULP_FLOW_DB_RES_DIR_MASK);
129 	resource_func = (params->resource_func >> ULP_FLOW_DB_RES_FUNC_UPPER);
130 	resource_info->nxt_resource_idx |= ((resource_func <<
131 					     ULP_FLOW_DB_RES_FUNC_BITS) &
132 					    ULP_FLOW_DB_RES_FUNC_MASK);
133 
134 	if (params->resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) {
135 		/* Break the resource func into two parts */
136 		resource_func = (params->resource_func &
137 				 ULP_FLOW_DB_RES_FUNC_LOWER_MASK);
138 		resource_info->resource_func_lower = resource_func;
139 	}
140 
141 	/* Store the handle as 64bit only for EM table entries */
142 	if (params->resource_func != BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE &&
143 	    params->resource_func != BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) {
144 		resource_info->resource_hndl = (uint32_t)params->resource_hndl;
145 		resource_info->resource_type = params->resource_type;
146 		resource_info->resource_sub_type = params->resource_sub_type;
147 		resource_info->reserved = params->reserved;
148 	} else {
149 		resource_info->resource_em_handle = params->resource_hndl;
150 	}
151 }
152 
153 /*
154  * Helper function to copy the resource params to resource info
155  *  No validation being done in this function.
156  *
157  * resource_info [in] Ptr to resource information
158  * params [out] The output params to the caller
159  *
160  * returns none
161  */
162 static void
163 ulp_flow_db_res_info_to_params(struct ulp_fdb_resource_info *resource_info,
164 			       struct ulp_flow_db_res_params *params)
165 {
166 	memset(params, 0, sizeof(struct ulp_flow_db_res_params));
167 
168 	/* use the helper function to get the resource func */
169 	params->direction = ulp_flow_db_resource_dir_get(resource_info);
170 	params->resource_func = ulp_flow_db_resource_func_get(resource_info);
171 
172 	if (params->resource_func == BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE ||
173 	    params->resource_func == BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) {
174 		params->resource_hndl = resource_info->resource_em_handle;
175 	} else if (params->resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) {
176 		params->resource_hndl = resource_info->resource_hndl;
177 		params->resource_type = resource_info->resource_type;
178 		params->resource_sub_type = resource_info->resource_sub_type;
179 		params->reserved = resource_info->reserved;
180 	}
181 }
182 
183 /*
184  * Helper function to allocate the flow table and initialize
185  * the stack for allocation operations.
186  *
187  * flow_db [in] Ptr to flow database structure
188  *
189  * Returns 0 on success or negative number on failure.
190  */
191 static int32_t
192 ulp_flow_db_alloc_resource(struct bnxt_ulp_flow_db *flow_db)
193 {
194 	uint32_t			idx = 0;
195 	struct bnxt_ulp_flow_tbl	*flow_tbl;
196 	uint32_t			size;
197 
198 	flow_tbl = &flow_db->flow_tbl;
199 
200 	size = sizeof(struct ulp_fdb_resource_info) * flow_tbl->num_resources;
201 	flow_tbl->flow_resources =
202 			rte_zmalloc("ulp_fdb_resource_info", size, 0);
203 
204 	if (!flow_tbl->flow_resources) {
205 		BNXT_TF_DBG(ERR, "Failed to alloc memory for flow table\n");
206 		return -ENOMEM;
207 	}
208 	size = sizeof(uint32_t) * flow_tbl->num_resources;
209 	flow_tbl->flow_tbl_stack = rte_zmalloc("flow_tbl_stack", size, 0);
210 	if (!flow_tbl->flow_tbl_stack) {
211 		BNXT_TF_DBG(ERR, "Failed to alloc memory flow tbl stack\n");
212 		return -ENOMEM;
213 	}
214 	size = (flow_tbl->num_flows / sizeof(uint64_t)) + 1;
215 	size =  ULP_BYTE_ROUND_OFF_8(size);
216 	flow_tbl->active_reg_flows = rte_zmalloc("active reg flows", size,
217 						 ULP_BUFFER_ALIGN_64_BYTE);
218 	if (!flow_tbl->active_reg_flows) {
219 		BNXT_TF_DBG(ERR, "Failed to alloc memory active reg flows\n");
220 		return -ENOMEM;
221 	}
222 
223 	flow_tbl->active_dflt_flows = rte_zmalloc("active dflt flows", size,
224 						  ULP_BUFFER_ALIGN_64_BYTE);
225 	if (!flow_tbl->active_dflt_flows) {
226 		BNXT_TF_DBG(ERR, "Failed to alloc memory active dflt flows\n");
227 		return -ENOMEM;
228 	}
229 
230 	/* Initialize the stack table. */
231 	for (idx = 0; idx < flow_tbl->num_resources; idx++)
232 		flow_tbl->flow_tbl_stack[idx] = idx;
233 
234 	/* Ignore the first element in the list. */
235 	flow_tbl->head_index = 1;
236 	/* Tail points to the last entry in the list. */
237 	flow_tbl->tail_index = flow_tbl->num_resources - 1;
238 	return 0;
239 }
240 
241 /*
242  * Helper function to deallocate the flow table.
243  *
244  * flow_db [in] Ptr to flow database structure
245  *
246  * Returns none.
247  */
248 static void
249 ulp_flow_db_dealloc_resource(struct bnxt_ulp_flow_db *flow_db)
250 {
251 	struct bnxt_ulp_flow_tbl *flow_tbl = &flow_db->flow_tbl;
252 
253 	/* Free all the allocated tables in the flow table. */
254 	if (flow_tbl->active_reg_flows) {
255 		rte_free(flow_tbl->active_reg_flows);
256 		flow_tbl->active_reg_flows = NULL;
257 	}
258 	if (flow_tbl->active_dflt_flows) {
259 		rte_free(flow_tbl->active_dflt_flows);
260 		flow_tbl->active_dflt_flows = NULL;
261 	}
262 
263 	if (flow_tbl->flow_tbl_stack) {
264 		rte_free(flow_tbl->flow_tbl_stack);
265 		flow_tbl->flow_tbl_stack = NULL;
266 	}
267 
268 	if (flow_tbl->flow_resources) {
269 		rte_free(flow_tbl->flow_resources);
270 		flow_tbl->flow_resources = NULL;
271 	}
272 }
273 
274 /*
275  * Helper function to add function id to the flow table
276  *
277  * flow_db [in] Ptr to flow table
278  * flow_id [in] The flow id of the flow
279  * func_id [in] The func_id to be set, for reset pass zero
280  *
281  * returns none
282  */
283 static void
284 ulp_flow_db_func_id_set(struct bnxt_ulp_flow_db *flow_db,
285 			uint32_t flow_id,
286 			uint32_t func_id)
287 {
288 	/* set the function id in the function table */
289 	if (flow_id < flow_db->func_id_tbl_size)
290 		flow_db->func_id_tbl[flow_id] = func_id;
291 	else /* This should never happen */
292 		BNXT_TF_DBG(ERR, "Invalid flow id, flowdb corrupt\n");
293 }
294 
295 /*
296  * Initialize the parent-child database. Memory is allocated in this
297  * call and assigned to the database
298  *
299  * flow_db [in] Ptr to flow table
300  * num_entries[in] - number of entries to allocate
301  *
302  * Returns 0 on success or negative number on failure.
303  */
304 static int32_t
305 ulp_flow_db_parent_tbl_init(struct bnxt_ulp_flow_db *flow_db,
306 			    uint32_t num_entries)
307 {
308 	struct ulp_fdb_parent_child_db *p_db;
309 	uint32_t size, idx;
310 
311 	if (!num_entries)
312 		return 0;
313 
314 	/* update the sizes for the allocation */
315 	p_db = &flow_db->parent_child_db;
316 	p_db->child_bitset_size = (flow_db->flow_tbl.num_flows /
317 				   sizeof(uint64_t)) + 1; /* size in bytes */
318 	p_db->child_bitset_size = ULP_BYTE_ROUND_OFF_8(p_db->child_bitset_size);
319 	p_db->entries_count = num_entries;
320 
321 	/* allocate the memory */
322 	p_db->parent_flow_tbl = rte_zmalloc("fdb parent flow tbl",
323 					    sizeof(struct ulp_fdb_parent_info) *
324 					    p_db->entries_count, 0);
325 	if (!p_db->parent_flow_tbl) {
326 		BNXT_TF_DBG(ERR,
327 			    "Failed to allocate memory fdb parent flow tbl\n");
328 		return -ENOMEM;
329 	}
330 	size = p_db->child_bitset_size * p_db->entries_count;
331 
332 	/*
333 	 * allocate the big chunk of memory to be statically carved into
334 	 * child_fid_bitset pointer.
335 	 */
336 	p_db->parent_flow_tbl_mem = rte_zmalloc("fdb parent flow tbl mem",
337 						size,
338 						ULP_BUFFER_ALIGN_64_BYTE);
339 	if (!p_db->parent_flow_tbl_mem) {
340 		BNXT_TF_DBG(ERR,
341 			    "Failed to allocate memory fdb parent flow mem\n");
342 		return -ENOMEM;
343 	}
344 
345 	/* set the pointers in parent table to their offsets */
346 	for (idx = 0 ; idx < p_db->entries_count; idx++) {
347 		p_db->parent_flow_tbl[idx].child_fid_bitset =
348 			(uint64_t *)&p_db->parent_flow_tbl_mem[idx *
349 			p_db->child_bitset_size];
350 	}
351 	/* success */
352 	return 0;
353 }
354 
355 /*
356  * Deinitialize the parent-child database. Memory is deallocated in
357  * this call and all flows should have been purged before this
358  * call.
359  *
360  * flow_db [in] Ptr to flow table
361  *
362  * Returns none
363  */
364 static void
365 ulp_flow_db_parent_tbl_deinit(struct bnxt_ulp_flow_db *flow_db)
366 {
367 	/* free the memory related to parent child database */
368 	if (flow_db->parent_child_db.parent_flow_tbl_mem) {
369 		rte_free(flow_db->parent_child_db.parent_flow_tbl_mem);
370 		flow_db->parent_child_db.parent_flow_tbl_mem = NULL;
371 	}
372 	if (flow_db->parent_child_db.parent_flow_tbl) {
373 		rte_free(flow_db->parent_child_db.parent_flow_tbl);
374 		flow_db->parent_child_db.parent_flow_tbl = NULL;
375 	}
376 }
377 
378 /*
379  * Initialize the flow database. Memory is allocated in this
380  * call and assigned to the flow database.
381  *
382  * ulp_ctxt [in] Ptr to ulp context
383  *
384  * Returns 0 on success or negative number on failure.
385  */
386 int32_t
387 ulp_flow_db_init(struct bnxt_ulp_context *ulp_ctxt)
388 {
389 	struct bnxt_ulp_device_params *dparms;
390 	struct bnxt_ulp_flow_tbl *flow_tbl;
391 	struct bnxt_ulp_flow_db *flow_db;
392 	uint32_t dev_id, num_flows;
393 	enum bnxt_ulp_flow_mem_type mtype;
394 
395 	/* Get the dev specific number of flows that needed to be supported. */
396 	if (bnxt_ulp_cntxt_dev_id_get(ulp_ctxt, &dev_id)) {
397 		BNXT_TF_DBG(ERR, "Invalid device id\n");
398 		return -EINVAL;
399 	}
400 
401 	dparms = bnxt_ulp_device_params_get(dev_id);
402 	if (!dparms) {
403 		BNXT_TF_DBG(ERR, "could not fetch the device params\n");
404 		return -ENODEV;
405 	}
406 
407 	flow_db = rte_zmalloc("bnxt_ulp_flow_db",
408 			      sizeof(struct bnxt_ulp_flow_db), 0);
409 	if (!flow_db) {
410 		BNXT_TF_DBG(ERR,
411 			    "Failed to allocate memory for flow table ptr\n");
412 		return -ENOMEM;
413 	}
414 
415 	/* Attach the flow database to the ulp context. */
416 	bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, flow_db);
417 
418 	/* Determine the number of flows based on EM type */
419 	bnxt_ulp_cntxt_mem_type_get(ulp_ctxt, &mtype);
420 	if (mtype == BNXT_ULP_FLOW_MEM_TYPE_INT)
421 		num_flows = dparms->int_flow_db_num_entries;
422 	else
423 		num_flows = dparms->ext_flow_db_num_entries;
424 
425 	/* Populate the regular flow table limits. */
426 	flow_tbl = &flow_db->flow_tbl;
427 	flow_tbl->num_flows = num_flows + 1;
428 	flow_tbl->num_resources = ((num_flows + 1) *
429 				   dparms->num_resources_per_flow);
430 
431 	/* Include the default flow table limits. */
432 	flow_tbl->num_flows += (BNXT_FLOW_DB_DEFAULT_NUM_FLOWS + 1);
433 	flow_tbl->num_resources += ((BNXT_FLOW_DB_DEFAULT_NUM_FLOWS + 1) *
434 				    BNXT_FLOW_DB_DEFAULT_NUM_RESOURCES);
435 
436 	/* Allocate the resource for the flow table. */
437 	if (ulp_flow_db_alloc_resource(flow_db))
438 		goto error_free;
439 
440 	/* add 1 since we are not using index 0 for flow id */
441 	flow_db->func_id_tbl_size = flow_tbl->num_flows + 1;
442 	/* Allocate the function Id table */
443 	flow_db->func_id_tbl = rte_zmalloc("bnxt_ulp_flow_db_func_id_table",
444 					   flow_db->func_id_tbl_size *
445 					   sizeof(uint16_t), 0);
446 	if (!flow_db->func_id_tbl) {
447 		BNXT_TF_DBG(ERR,
448 			    "Failed to allocate mem for flow table func id\n");
449 		goto error_free;
450 	}
451 	/* initialize the parent child database */
452 	if (ulp_flow_db_parent_tbl_init(flow_db,
453 					dparms->fdb_parent_flow_entries)) {
454 		BNXT_TF_DBG(ERR,
455 			    "Failed to allocate mem for parent child db\n");
456 		goto error_free;
457 	}
458 
459 	/* All good so return. */
460 	BNXT_TF_DBG(INFO, "FlowDB initialized with %d flows.\n",
461 		    flow_tbl->num_flows);
462 	return 0;
463 error_free:
464 	ulp_flow_db_deinit(ulp_ctxt);
465 	return -ENOMEM;
466 }
467 
468 /*
469  * Deinitialize the flow database. Memory is deallocated in
470  * this call and all flows should have been purged before this
471  * call.
472  *
473  * ulp_ctxt [in] Ptr to ulp context
474  *
475  * Returns 0 on success.
476  */
477 int32_t
478 ulp_flow_db_deinit(struct bnxt_ulp_context *ulp_ctxt)
479 {
480 	struct bnxt_ulp_flow_db *flow_db;
481 
482 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
483 	if (!flow_db)
484 		return -EINVAL;
485 
486 	/* Detach the flow database from the ulp context. */
487 	bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, NULL);
488 
489 	/* Free up all the memory. */
490 	ulp_flow_db_parent_tbl_deinit(flow_db);
491 	ulp_flow_db_dealloc_resource(flow_db);
492 	rte_free(flow_db->func_id_tbl);
493 	rte_free(flow_db);
494 
495 	return 0;
496 }
497 
498 /*
499  * Allocate the flow database entry
500  *
501  * ulp_ctxt [in] Ptr to ulp_context
502  * flow_type [in] - specify default or regular
503  * func_id [in].function id of the ingress port
504  * fid [out] The index to the flow entry
505  *
506  * returns 0 on success and negative on failure.
507  */
508 int32_t
509 ulp_flow_db_fid_alloc(struct bnxt_ulp_context *ulp_ctxt,
510 		      enum bnxt_ulp_fdb_type flow_type,
511 		      uint16_t func_id,
512 		      uint32_t *fid)
513 {
514 	struct bnxt_ulp_flow_db *flow_db;
515 	struct bnxt_ulp_flow_tbl *flow_tbl;
516 
517 	*fid = 0; /* Initialize fid to invalid value */
518 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
519 	if (!flow_db) {
520 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
521 		return -EINVAL;
522 	}
523 
524 	if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
525 		BNXT_TF_DBG(ERR, "Invalid flow type\n");
526 		return -EINVAL;
527 	}
528 
529 	flow_tbl = &flow_db->flow_tbl;
530 	/* check for max flows */
531 	if (flow_tbl->num_flows <= flow_tbl->head_index) {
532 		BNXT_TF_DBG(ERR, "Flow database has reached max flows\n");
533 		return -ENOMEM;
534 	}
535 	if (flow_tbl->tail_index <= (flow_tbl->head_index + 1)) {
536 		BNXT_TF_DBG(ERR, "Flow database has reached max resources\n");
537 		return -ENOMEM;
538 	}
539 	*fid = flow_tbl->flow_tbl_stack[flow_tbl->head_index];
540 	flow_tbl->head_index++;
541 
542 	/* Set the flow type */
543 	ulp_flow_db_active_flows_bit_set(flow_db, flow_type, *fid, 1);
544 
545 	/* function id update is only valid for regular flow table */
546 	if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR)
547 		ulp_flow_db_func_id_set(flow_db, *fid, func_id);
548 
549 	/* return success */
550 	return 0;
551 }
552 
553 /*
554  * Allocate the flow database entry.
555  * The params->critical_resource has to be set to 0 to allocate a new resource.
556  *
557  * ulp_ctxt [in] Ptr to ulp_context
558  * flow_type [in] Specify it is regular or default flow
559  * fid [in] The index to the flow entry
560  * params [in] The contents to be copied into resource
561  *
562  * returns 0 on success and negative on failure.
563  */
564 int32_t
565 ulp_flow_db_resource_add(struct bnxt_ulp_context *ulp_ctxt,
566 			 enum bnxt_ulp_fdb_type flow_type,
567 			 uint32_t fid,
568 			 struct ulp_flow_db_res_params *params)
569 {
570 	struct bnxt_ulp_flow_db *flow_db;
571 	struct bnxt_ulp_flow_tbl *flow_tbl;
572 	struct ulp_fdb_resource_info *resource, *fid_resource;
573 	uint32_t idx;
574 
575 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
576 	if (!flow_db) {
577 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
578 		return -EINVAL;
579 	}
580 
581 	if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
582 		BNXT_TF_DBG(ERR, "Invalid flow type\n");
583 		return -EINVAL;
584 	}
585 
586 	flow_tbl = &flow_db->flow_tbl;
587 	/* check for max flows */
588 	if (fid >= flow_tbl->num_flows || !fid) {
589 		BNXT_TF_DBG(ERR, "Invalid flow index\n");
590 		return -EINVAL;
591 	}
592 
593 	/* check if the flow is active or not */
594 	if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) {
595 		BNXT_TF_DBG(ERR, "flow does not exist\n");
596 		return -EINVAL;
597 	}
598 
599 	/* check for max resource */
600 	if ((flow_tbl->head_index + 1) >= flow_tbl->tail_index) {
601 		BNXT_TF_DBG(ERR, "Flow db has reached max resources\n");
602 		return -ENOMEM;
603 	}
604 	fid_resource = &flow_tbl->flow_resources[fid];
605 
606 	if (!params->critical_resource) {
607 		/* Not the critical_resource so allocate a resource */
608 		idx = flow_tbl->flow_tbl_stack[flow_tbl->tail_index];
609 		resource = &flow_tbl->flow_resources[idx];
610 		flow_tbl->tail_index--;
611 
612 		/* Update the chain list of resource*/
613 		ULP_FLOW_DB_RES_NXT_SET(resource->nxt_resource_idx,
614 					fid_resource->nxt_resource_idx);
615 		/* update the contents */
616 		ulp_flow_db_res_params_to_info(resource, params);
617 		ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx);
618 		ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
619 					idx);
620 	} else {
621 		/* critical resource. Just update the fid resource */
622 		ulp_flow_db_res_params_to_info(fid_resource, params);
623 	}
624 
625 	if (params->resource_type == TF_TBL_TYPE_ACT_STATS_64 &&
626 	    params->resource_sub_type ==
627 	    BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_INT_COUNT) {
628 		/* Store the first HW counter ID for this table */
629 		if (!ulp_fc_mgr_start_idx_isset(ulp_ctxt, params->direction))
630 			ulp_fc_mgr_start_idx_set(ulp_ctxt, params->direction,
631 						 params->resource_hndl);
632 
633 		ulp_fc_mgr_cntr_set(ulp_ctxt, params->direction,
634 				    params->resource_hndl);
635 
636 		if (!ulp_fc_mgr_thread_isstarted(ulp_ctxt))
637 			ulp_fc_mgr_thread_start(ulp_ctxt);
638 	}
639 
640 	/* all good, return success */
641 	return 0;
642 }
643 
644 /*
645  * Free the flow database entry.
646  * The params->critical_resource has to be set to 1 to free the first resource.
647  *
648  * ulp_ctxt [in] Ptr to ulp_context
649  * flow_type [in] Specify it is regular or default flow
650  * fid [in] The index to the flow entry
651  * params [in/out] The contents to be copied into params.
652  * Onlythe critical_resource needs to be set by the caller.
653  *
654  * Returns 0 on success and negative on failure.
655  */
656 int32_t
657 ulp_flow_db_resource_del(struct bnxt_ulp_context *ulp_ctxt,
658 			 enum bnxt_ulp_fdb_type flow_type,
659 			 uint32_t fid,
660 			 struct ulp_flow_db_res_params *params)
661 {
662 	struct bnxt_ulp_flow_db *flow_db;
663 	struct bnxt_ulp_flow_tbl *flow_tbl;
664 	struct ulp_fdb_resource_info *nxt_resource, *fid_resource;
665 	uint32_t nxt_idx = 0;
666 
667 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
668 	if (!flow_db) {
669 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
670 		return -EINVAL;
671 	}
672 
673 	if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
674 		BNXT_TF_DBG(ERR, "Invalid flow type\n");
675 		return -EINVAL;
676 	}
677 
678 	flow_tbl = &flow_db->flow_tbl;
679 	/* check for max flows */
680 	if (fid >= flow_tbl->num_flows || !fid) {
681 		BNXT_TF_DBG(ERR, "Invalid flow index %x\n", fid);
682 		return -EINVAL;
683 	}
684 
685 	/* check if the flow is active or not */
686 	if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) {
687 		BNXT_TF_DBG(ERR, "flow does not exist\n");
688 		return -EINVAL;
689 	}
690 
691 	fid_resource = &flow_tbl->flow_resources[fid];
692 	if (!params->critical_resource) {
693 		/* Not the critical resource so free the resource */
694 		ULP_FLOW_DB_RES_NXT_SET(nxt_idx,
695 					fid_resource->nxt_resource_idx);
696 		if (!nxt_idx) {
697 			/* reached end of resources */
698 			return -ENOENT;
699 		}
700 		nxt_resource = &flow_tbl->flow_resources[nxt_idx];
701 
702 		/* connect the fid resource to the next resource */
703 		ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx);
704 		ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
705 					nxt_resource->nxt_resource_idx);
706 
707 		/* update the contents to be given to caller */
708 		ulp_flow_db_res_info_to_params(nxt_resource, params);
709 
710 		/* Delete the nxt_resource */
711 		memset(nxt_resource, 0, sizeof(struct ulp_fdb_resource_info));
712 
713 		/* add it to the free list */
714 		flow_tbl->tail_index++;
715 		if (flow_tbl->tail_index >= flow_tbl->num_resources) {
716 			BNXT_TF_DBG(ERR, "FlowDB:Tail reached max\n");
717 			return -ENOENT;
718 		}
719 		flow_tbl->flow_tbl_stack[flow_tbl->tail_index] = nxt_idx;
720 
721 	} else {
722 		/* Critical resource. copy the contents and exit */
723 		ulp_flow_db_res_info_to_params(fid_resource, params);
724 		ULP_FLOW_DB_RES_NXT_SET(nxt_idx,
725 					fid_resource->nxt_resource_idx);
726 		memset(fid_resource, 0, sizeof(struct ulp_fdb_resource_info));
727 		ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx,
728 					nxt_idx);
729 	}
730 
731 	/* Now that the HW Flow counter resource is deleted, reset it's
732 	 * corresponding slot in the SW accumulation table in the Flow Counter
733 	 * manager
734 	 */
735 	if (params->resource_type == TF_TBL_TYPE_ACT_STATS_64 &&
736 	    params->resource_sub_type ==
737 	    BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_INT_COUNT) {
738 		ulp_fc_mgr_cntr_reset(ulp_ctxt, params->direction,
739 				      params->resource_hndl);
740 	}
741 
742 	/* all good, return success */
743 	return 0;
744 }
745 
746 /*
747  * Free the flow database entry
748  *
749  * ulp_ctxt [in] Ptr to ulp_context
750  * flow_type [in] - specify default or regular
751  * fid [in] The index to the flow entry
752  *
753  * returns 0 on success and negative on failure.
754  */
755 int32_t
756 ulp_flow_db_fid_free(struct bnxt_ulp_context *ulp_ctxt,
757 		     enum bnxt_ulp_fdb_type flow_type,
758 		     uint32_t fid)
759 {
760 	struct bnxt_ulp_flow_db *flow_db;
761 	struct bnxt_ulp_flow_tbl *flow_tbl;
762 
763 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
764 	if (!flow_db) {
765 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
766 		return -EINVAL;
767 	}
768 
769 	if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
770 		BNXT_TF_DBG(ERR, "Invalid flow type\n");
771 		return -EINVAL;
772 	}
773 
774 	flow_tbl = &flow_db->flow_tbl;
775 
776 	/* check for limits of fid */
777 	if (fid >= flow_tbl->num_flows || !fid) {
778 		BNXT_TF_DBG(ERR, "Invalid flow index\n");
779 		return -EINVAL;
780 	}
781 
782 	/* check if the flow is active or not */
783 	if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) {
784 		BNXT_TF_DBG(ERR, "flow does not exist\n");
785 		return -EINVAL;
786 	}
787 	flow_tbl->head_index--;
788 	if (!flow_tbl->head_index) {
789 		BNXT_TF_DBG(ERR, "FlowDB: Head Ptr is zero\n");
790 		return -ENOENT;
791 	}
792 	flow_tbl->flow_tbl_stack[flow_tbl->head_index] = fid;
793 
794 	/* Clear the flows bitmap */
795 	ulp_flow_db_active_flows_bit_set(flow_db, flow_type, fid, 0);
796 
797 	if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR)
798 		ulp_flow_db_func_id_set(flow_db, fid, 0);
799 
800 	/* all good, return success */
801 	return 0;
802 }
803 
804 /*
805  * Get the flow database entry details
806  *
807  * ulp_ctxt [in] Ptr to ulp_context
808  * flow_type [in] - specify default or regular
809  * fid [in] The index to the flow entry
810  * nxt_idx [in/out] the index to the next entry
811  * params [out] The contents to be copied into params.
812  *
813  * returns 0 on success and negative on failure.
814  */
815 int32_t
816 ulp_flow_db_resource_get(struct bnxt_ulp_context *ulp_ctxt,
817 			 enum bnxt_ulp_fdb_type flow_type,
818 			 uint32_t fid,
819 			 uint32_t *nxt_idx,
820 			 struct ulp_flow_db_res_params *params)
821 {
822 	struct bnxt_ulp_flow_db *flow_db;
823 	struct bnxt_ulp_flow_tbl *flow_tbl;
824 	struct ulp_fdb_resource_info *nxt_resource, *fid_resource;
825 
826 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
827 	if (!flow_db) {
828 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
829 		return -EINVAL;
830 	}
831 
832 	if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
833 		BNXT_TF_DBG(ERR, "Invalid flow type\n");
834 		return -EINVAL;
835 	}
836 
837 	flow_tbl = &flow_db->flow_tbl;
838 
839 	/* check for limits of fid */
840 	if (fid >= flow_tbl->num_flows || !fid) {
841 		BNXT_TF_DBG(ERR, "Invalid flow index\n");
842 		return -EINVAL;
843 	}
844 
845 	/* check if the flow is active or not */
846 	if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) {
847 		BNXT_TF_DBG(ERR, "flow does not exist\n");
848 		return -EINVAL;
849 	}
850 
851 	if (!*nxt_idx) {
852 		fid_resource = &flow_tbl->flow_resources[fid];
853 		ulp_flow_db_res_info_to_params(fid_resource, params);
854 		ULP_FLOW_DB_RES_NXT_SET(*nxt_idx,
855 					fid_resource->nxt_resource_idx);
856 	} else {
857 		nxt_resource = &flow_tbl->flow_resources[*nxt_idx];
858 		ulp_flow_db_res_info_to_params(nxt_resource, params);
859 		*nxt_idx = 0;
860 		ULP_FLOW_DB_RES_NXT_SET(*nxt_idx,
861 					nxt_resource->nxt_resource_idx);
862 	}
863 
864 	/* all good, return success */
865 	return 0;
866 }
867 
868 /*
869  * Get the flow database entry iteratively
870  *
871  * flow_tbl [in] Ptr to flow table
872  * flow_type [in] - specify default or regular
873  * fid [in/out] The index to the flow entry
874  *
875  * returns 0 on success and negative on failure.
876  */
877 static int32_t
878 ulp_flow_db_next_entry_get(struct bnxt_ulp_flow_db *flow_db,
879 			   enum bnxt_ulp_fdb_type flow_type,
880 			   uint32_t *fid)
881 {
882 	uint32_t lfid = *fid;
883 	uint32_t idx, s_idx, mod_fid;
884 	uint64_t bs;
885 	uint64_t *active_flows;
886 	struct bnxt_ulp_flow_tbl *flowtbl = &flow_db->flow_tbl;
887 
888 	if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR)
889 		active_flows = flowtbl->active_reg_flows;
890 	else
891 		active_flows = flowtbl->active_dflt_flows;
892 
893 	do {
894 		/* increment the flow id to find the next valid flow id */
895 		lfid++;
896 		if (lfid >= flowtbl->num_flows)
897 			return -ENOENT;
898 		idx = lfid / ULP_INDEX_BITMAP_SIZE;
899 		mod_fid = lfid % ULP_INDEX_BITMAP_SIZE;
900 		s_idx = idx;
901 		while (!(bs = active_flows[idx])) {
902 			idx++;
903 			if ((idx * ULP_INDEX_BITMAP_SIZE) >= flowtbl->num_flows)
904 				return -ENOENT;
905 		}
906 		/*
907 		 * remove the previous bits in the bitset bs to find the
908 		 * next non zero bit in the bitset. This needs to be done
909 		 * only if the idx is same as he one you started.
910 		 */
911 		if (s_idx == idx)
912 			bs &= (-1UL >> mod_fid);
913 		lfid = (idx * ULP_INDEX_BITMAP_SIZE) + __builtin_clzl(bs);
914 		if (*fid >= lfid) {
915 			BNXT_TF_DBG(ERR, "Flow Database is corrupt\n");
916 			return -ENOENT;
917 		}
918 	} while (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type,
919 						      lfid));
920 
921 	/* all good, return success */
922 	*fid = lfid;
923 	return 0;
924 }
925 
926 /*
927  * Flush all flows in the flow database.
928  *
929  * ulp_ctxt [in] Ptr to ulp context
930  * flow_type [in] - specify default or regular
931  *
932  * returns 0 on success or negative number on failure
933  */
934 int32_t
935 ulp_flow_db_flush_flows(struct bnxt_ulp_context *ulp_ctx,
936 			enum bnxt_ulp_fdb_type flow_type)
937 {
938 	uint32_t fid = 0;
939 	struct bnxt_ulp_flow_db *flow_db;
940 
941 	if (!ulp_ctx) {
942 		BNXT_TF_DBG(ERR, "Invalid Argument\n");
943 		return -EINVAL;
944 	}
945 
946 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
947 	if (!flow_db) {
948 		BNXT_TF_DBG(ERR, "Flow database not found\n");
949 		return -EINVAL;
950 	}
951 	if (bnxt_ulp_cntxt_acquire_fdb_lock(ulp_ctx)) {
952 		BNXT_TF_DBG(ERR, "Flow db lock acquire failed\n");
953 		return -EINVAL;
954 	}
955 
956 	while (!ulp_flow_db_next_entry_get(flow_db, flow_type, &fid))
957 		ulp_mapper_resources_free(ulp_ctx, flow_type, fid);
958 
959 	bnxt_ulp_cntxt_release_fdb_lock(ulp_ctx);
960 
961 	return 0;
962 }
963 
964 /*
965  * Flush all flows in the flow database that belong to a device function.
966  *
967  * ulp_ctxt [in] Ptr to ulp context
968  * func_id [in] - The port function id
969  *
970  * returns 0 on success or negative number on failure
971  */
972 int32_t
973 ulp_flow_db_function_flow_flush(struct bnxt_ulp_context *ulp_ctx,
974 				uint16_t func_id)
975 {
976 	uint32_t flow_id = 0;
977 	struct bnxt_ulp_flow_db *flow_db;
978 
979 	if (!ulp_ctx || !func_id) {
980 		BNXT_TF_DBG(ERR, "Invalid Argument\n");
981 		return -EINVAL;
982 	}
983 
984 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
985 	if (!flow_db) {
986 		BNXT_TF_DBG(ERR, "Flow database not found\n");
987 		return -EINVAL;
988 	}
989 	if (bnxt_ulp_cntxt_acquire_fdb_lock(ulp_ctx)) {
990 		BNXT_TF_DBG(ERR, "Flow db lock acquire failed\n");
991 		return -EINVAL;
992 	}
993 
994 	while (!ulp_flow_db_next_entry_get(flow_db, BNXT_ULP_FDB_TYPE_REGULAR,
995 					   &flow_id)) {
996 		if (flow_db->func_id_tbl[flow_id] == func_id)
997 			ulp_mapper_resources_free(ulp_ctx,
998 						  BNXT_ULP_FDB_TYPE_REGULAR,
999 						  flow_id);
1000 	}
1001 	bnxt_ulp_cntxt_release_fdb_lock(ulp_ctx);
1002 	return 0;
1003 }
1004 
1005 /*
1006  * Flush all flows in the flow database that are associated with the session.
1007  *
1008  * ulp_ctxt [in] Ptr to ulp context
1009  *
1010  * returns 0 on success or negative number on failure
1011  */
1012 int32_t
1013 ulp_flow_db_session_flow_flush(struct bnxt_ulp_context *ulp_ctx)
1014 {
1015 	/*
1016 	 * TBD: Tf core implementation of FW session flush shall change this
1017 	 * implementation.
1018 	 */
1019 	return ulp_flow_db_flush_flows(ulp_ctx, BNXT_ULP_FDB_TYPE_REGULAR);
1020 }
1021 
1022 /*
1023  * Check that flow id matches the function id or not
1024  *
1025  * ulp_ctxt [in] Ptr to ulp context
1026  * flow_db [in] Ptr to flow table
1027  * func_id [in] The func_id to be set, for reset pass zero.
1028  *
1029  * returns true on success or false on failure
1030  */
1031 bool
1032 ulp_flow_db_validate_flow_func(struct bnxt_ulp_context *ulp_ctx,
1033 			       uint32_t flow_id,
1034 			       uint32_t func_id)
1035 {
1036 	struct bnxt_ulp_flow_db *flow_db;
1037 
1038 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
1039 	if (!flow_db) {
1040 		BNXT_TF_DBG(ERR, "Flow database not found\n");
1041 		return false;
1042 	}
1043 
1044 	/* set the function id in the function table */
1045 	if (flow_id < flow_db->func_id_tbl_size && func_id &&
1046 	    flow_db->func_id_tbl[flow_id] == func_id)
1047 		return true;
1048 
1049 	return false;
1050 }
1051 
1052 /*
1053  * Internal api to traverse the resource list within a flow
1054  * and match a resource based on resource func and resource
1055  * sub type. This api should be used only for resources that
1056  * are unique and do not have multiple instances of resource
1057  * func and sub type combination since it will return only
1058  * the first match.
1059  */
1060 static int32_t
1061 ulp_flow_db_resource_hndl_get(struct bnxt_ulp_context *ulp_ctx,
1062 			      enum bnxt_ulp_fdb_type flow_type,
1063 			      uint32_t flow_id,
1064 			      uint32_t resource_func,
1065 			      uint32_t res_subtype,
1066 			      uint64_t *res_hndl)
1067 {
1068 	struct bnxt_ulp_flow_db *flow_db;
1069 	struct bnxt_ulp_flow_tbl *flow_tbl;
1070 	struct ulp_fdb_resource_info *fid_res;
1071 	uint32_t res_id;
1072 
1073 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx);
1074 	if (!flow_db) {
1075 		BNXT_TF_DBG(ERR, "Flow database not found\n");
1076 		return -EINVAL;
1077 	}
1078 
1079 	if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
1080 		BNXT_TF_DBG(ERR, "Invalid flow type\n");
1081 		return -EINVAL;
1082 	}
1083 
1084 	flow_tbl = &flow_db->flow_tbl;
1085 
1086 	/* check for limits of fid */
1087 	if (flow_id >= flow_tbl->num_flows || !flow_id) {
1088 		BNXT_TF_DBG(ERR, "Invalid flow index\n");
1089 		return -EINVAL;
1090 	}
1091 
1092 	/* check if the flow is active or not */
1093 	if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, flow_id)) {
1094 		BNXT_TF_DBG(ERR, "flow does not exist\n");
1095 		return -EINVAL;
1096 	}
1097 	/* Iterate the resource to get the resource handle */
1098 	res_id =  flow_id;
1099 	while (res_id) {
1100 		fid_res = &flow_tbl->flow_resources[res_id];
1101 		if (ulp_flow_db_resource_func_get(fid_res) == resource_func) {
1102 			if (resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) {
1103 				if (res_subtype == fid_res->resource_sub_type) {
1104 					*res_hndl = fid_res->resource_hndl;
1105 					return 0;
1106 				}
1107 
1108 			} else if (resource_func ==
1109 				   BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE ||
1110 				   resource_func ==
1111 				   BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) {
1112 				*res_hndl = fid_res->resource_em_handle;
1113 				return 0;
1114 			}
1115 		}
1116 		res_id = 0;
1117 		ULP_FLOW_DB_RES_NXT_SET(res_id, fid_res->nxt_resource_idx);
1118 	}
1119 	return -ENOENT;
1120 }
1121 
1122 /*
1123  * Api to get the cfa action pointer from a flow.
1124  *
1125  * ulp_ctxt [in] Ptr to ulp context
1126  * flow_id [in] flow id
1127  * cfa_action [out] The resource handle stored in the flow database
1128  *
1129  * returns 0 on success
1130  */
1131 int32_t
1132 ulp_default_flow_db_cfa_action_get(struct bnxt_ulp_context *ulp_ctx,
1133 				   uint32_t flow_id,
1134 				   uint16_t *cfa_action)
1135 {
1136 	uint8_t sub_type = BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_VFR_CFA_ACTION;
1137 	uint64_t hndl;
1138 	int32_t rc;
1139 
1140 	rc = ulp_flow_db_resource_hndl_get(ulp_ctx,
1141 					   BNXT_ULP_FDB_TYPE_DEFAULT,
1142 					   flow_id,
1143 					   BNXT_ULP_RESOURCE_FUNC_INDEX_TABLE,
1144 					   sub_type, &hndl);
1145 	if (rc) {
1146 		BNXT_TF_DBG(ERR, "CFA Action ptr not found for flow id %u\n",
1147 			    flow_id);
1148 		return -ENOENT;
1149 	}
1150 	*cfa_action = hndl;
1151 	return 0;
1152 }
1153 
1154 /*
1155  * Allocate the entry in the parent-child database
1156  *
1157  * ulp_ctxt [in] Ptr to ulp_context
1158  * fid [in] The flow id to the flow entry
1159  *
1160  * returns index on success and negative on failure.
1161  */
1162 int32_t
1163 ulp_flow_db_parent_flow_alloc(struct bnxt_ulp_context *ulp_ctxt,
1164 			      uint32_t fid)
1165 {
1166 	struct bnxt_ulp_flow_db *flow_db;
1167 	struct ulp_fdb_parent_child_db *p_pdb;
1168 	uint32_t idx, free_idx = 0;
1169 
1170 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
1171 	if (!flow_db) {
1172 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
1173 		return -EINVAL;
1174 	}
1175 
1176 	/* check for max flows */
1177 	if (fid >= flow_db->flow_tbl.num_flows || !fid) {
1178 		BNXT_TF_DBG(ERR, "Invalid flow index\n");
1179 		return -EINVAL;
1180 	}
1181 
1182 	/* No support for parent child db then just exit */
1183 	if (!flow_db->parent_child_db.entries_count) {
1184 		BNXT_TF_DBG(ERR, "parent child db not supported\n");
1185 		return -EINVAL;
1186 	}
1187 
1188 	p_pdb = &flow_db->parent_child_db;
1189 	for (idx = 0; idx <= p_pdb->entries_count; idx++) {
1190 		if (p_pdb->parent_flow_tbl[idx].parent_fid == fid) {
1191 			BNXT_TF_DBG(ERR, "fid is already allocated\n");
1192 			return -EINVAL;
1193 		}
1194 		if (!p_pdb->parent_flow_tbl[idx].parent_fid && !free_idx)
1195 			free_idx = idx + 1;
1196 	}
1197 	/* no free slots */
1198 	if (!free_idx) {
1199 		BNXT_TF_DBG(ERR, "parent child db is full\n");
1200 		return -ENOMEM;
1201 	}
1202 
1203 	free_idx -= 1;
1204 	/* set the Fid in the parent child */
1205 	p_pdb->parent_flow_tbl[free_idx].parent_fid = fid;
1206 	return free_idx;
1207 }
1208 
1209 /*
1210  * Free the entry in the parent-child database
1211  *
1212  * ulp_ctxt [in] Ptr to ulp_context
1213  * fid [in] The flow id to the flow entry
1214  *
1215  * returns 0 on success and negative on failure.
1216  */
1217 int32_t
1218 ulp_flow_db_parent_flow_free(struct bnxt_ulp_context *ulp_ctxt,
1219 			     uint32_t fid)
1220 {
1221 	struct bnxt_ulp_flow_db *flow_db;
1222 	struct ulp_fdb_parent_child_db *p_pdb;
1223 	uint32_t idx;
1224 
1225 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
1226 	if (!flow_db) {
1227 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
1228 		return -EINVAL;
1229 	}
1230 
1231 	/* check for max flows */
1232 	if (fid >= flow_db->flow_tbl.num_flows || !fid) {
1233 		BNXT_TF_DBG(ERR, "Invalid flow index\n");
1234 		return -EINVAL;
1235 	}
1236 
1237 	/* No support for parent child db then just exit */
1238 	if (!flow_db->parent_child_db.entries_count) {
1239 		BNXT_TF_DBG(ERR, "parent child db not supported\n");
1240 		return -EINVAL;
1241 	}
1242 
1243 	p_pdb = &flow_db->parent_child_db;
1244 	for (idx = 0; idx <= p_pdb->entries_count; idx++) {
1245 		if (p_pdb->parent_flow_tbl[idx].parent_fid == fid) {
1246 			/* free the contents */
1247 			p_pdb->parent_flow_tbl[idx].parent_fid = 0;
1248 			memset(p_pdb->parent_flow_tbl[idx].child_fid_bitset,
1249 			       0, p_pdb->child_bitset_size);
1250 			return 0;
1251 		}
1252 	}
1253 	BNXT_TF_DBG(ERR, "parent entry not found = %x\n", fid);
1254 	return -EINVAL;
1255 }
1256 
1257 /*
1258  * Set or reset the child flow in the parent-child database
1259  *
1260  * ulp_ctxt [in] Ptr to ulp_context
1261  * parent_fid [in] The flow id of the parent flow entry
1262  * child_fid [in] The flow id of the child flow entry
1263  * set_flag [in] Use 1 for setting child, 0 to reset
1264  *
1265  * returns zero on success and negative on failure.
1266  */
1267 int32_t
1268 ulp_flow_db_parent_child_flow_set(struct bnxt_ulp_context *ulp_ctxt,
1269 				  uint32_t parent_fid,
1270 				  uint32_t child_fid,
1271 				  uint32_t set_flag)
1272 {
1273 	struct bnxt_ulp_flow_db *flow_db;
1274 	struct ulp_fdb_parent_child_db *p_pdb;
1275 	uint32_t idx, a_idx;
1276 	uint64_t *t;
1277 
1278 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
1279 	if (!flow_db) {
1280 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
1281 		return -EINVAL;
1282 	}
1283 
1284 	/* check for fid validity */
1285 	if (parent_fid >= flow_db->flow_tbl.num_flows || !parent_fid) {
1286 		BNXT_TF_DBG(ERR, "Invalid parent flow index %x\n", parent_fid);
1287 		return -EINVAL;
1288 	}
1289 
1290 	/* check for fid validity */
1291 	if (child_fid >= flow_db->flow_tbl.num_flows || !child_fid) {
1292 		BNXT_TF_DBG(ERR, "Invalid child flow index %x\n", child_fid);
1293 		return -EINVAL;
1294 	}
1295 
1296 	/* No support for parent child db then just exit */
1297 	if (!flow_db->parent_child_db.entries_count) {
1298 		BNXT_TF_DBG(ERR, "parent child db not supported\n");
1299 		return -EINVAL;
1300 	}
1301 
1302 	p_pdb = &flow_db->parent_child_db;
1303 	a_idx = child_fid / ULP_INDEX_BITMAP_SIZE;
1304 	for (idx = 0; idx <= p_pdb->entries_count; idx++) {
1305 		if (p_pdb->parent_flow_tbl[idx].parent_fid == parent_fid) {
1306 			t = p_pdb->parent_flow_tbl[idx].child_fid_bitset;
1307 			if (set_flag)
1308 				ULP_INDEX_BITMAP_SET(t[a_idx], child_fid);
1309 			else
1310 				ULP_INDEX_BITMAP_RESET(t[a_idx], child_fid);
1311 			return 0;
1312 		}
1313 	}
1314 	BNXT_TF_DBG(ERR, "Unable to set the parent-child flow %x:%x\n",
1315 		    parent_fid, child_fid);
1316 	return -1;
1317 }
1318 
1319 /*
1320  * Get the parent index from the parent-child database
1321  *
1322  * ulp_ctxt [in] Ptr to ulp_context
1323  * parent_fid [in] The flow id of the parent flow entry
1324  * parent_idx [out] The parent index of parent flow entry
1325  *
1326  * returns zero on success and negative on failure.
1327  */
1328 int32_t
1329 ulp_flow_db_parent_flow_idx_get(struct bnxt_ulp_context *ulp_ctxt,
1330 				uint32_t parent_fid,
1331 				uint32_t *parent_idx)
1332 {
1333 	struct bnxt_ulp_flow_db *flow_db;
1334 	struct ulp_fdb_parent_child_db *p_pdb;
1335 	uint32_t idx;
1336 
1337 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
1338 	if (!flow_db) {
1339 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
1340 		return -EINVAL;
1341 	}
1342 
1343 	/* check for fid validity */
1344 	if (parent_fid >= flow_db->flow_tbl.num_flows || !parent_fid) {
1345 		BNXT_TF_DBG(ERR, "Invalid parent flow index %x\n", parent_fid);
1346 		return -EINVAL;
1347 	}
1348 
1349 	/* No support for parent child db then just exit */
1350 	if (!flow_db->parent_child_db.entries_count) {
1351 		BNXT_TF_DBG(ERR, "parent child db not supported\n");
1352 		return -EINVAL;
1353 	}
1354 
1355 	p_pdb = &flow_db->parent_child_db;
1356 	for (idx = 0; idx <= p_pdb->entries_count; idx++) {
1357 		if (p_pdb->parent_flow_tbl[idx].parent_fid == parent_fid) {
1358 			*parent_idx = idx;
1359 			return 0;
1360 		}
1361 	}
1362 	BNXT_TF_DBG(ERR, "Unable to get the parent flow %x\n", parent_fid);
1363 	return -1;
1364 }
1365 
1366 /*
1367  * Get the next child flow in the parent-child database
1368  *
1369  * ulp_ctxt [in] Ptr to ulp_context
1370  * parent_fid [in] The flow id of the parent flow entry
1371  * child_fid [in/out] The flow id of the child flow entry
1372  *
1373  * returns zero on success and negative on failure.
1374  * Pass child_fid as zero for first entry.
1375  */
1376 int32_t
1377 ulp_flow_db_parent_child_flow_next_entry_get(struct bnxt_ulp_flow_db *flow_db,
1378 					     uint32_t parent_idx,
1379 					     uint32_t *child_fid)
1380 {
1381 	struct ulp_fdb_parent_child_db *p_pdb;
1382 	uint32_t idx, s_idx, mod_fid;
1383 	uint32_t next_fid = *child_fid;
1384 	uint64_t *child_bitset;
1385 	uint64_t bs;
1386 
1387 	/* check for fid validity */
1388 	p_pdb = &flow_db->parent_child_db;
1389 	if (parent_idx >= p_pdb->entries_count ||
1390 	    !p_pdb->parent_flow_tbl[parent_idx].parent_fid) {
1391 		BNXT_TF_DBG(ERR, "Invalid parent flow index %x\n", parent_idx);
1392 		return -EINVAL;
1393 	}
1394 
1395 	child_bitset = p_pdb->parent_flow_tbl[parent_idx].child_fid_bitset;
1396 	do {
1397 		/* increment the flow id to find the next valid flow id */
1398 		next_fid++;
1399 		if (next_fid >= flow_db->flow_tbl.num_flows)
1400 			return -ENOENT;
1401 		idx = next_fid / ULP_INDEX_BITMAP_SIZE;
1402 		mod_fid = next_fid % ULP_INDEX_BITMAP_SIZE;
1403 		s_idx = idx;
1404 		while (!(bs = child_bitset[idx])) {
1405 			idx++;
1406 			if ((idx * ULP_INDEX_BITMAP_SIZE) >=
1407 			    flow_db->flow_tbl.num_flows)
1408 				return -ENOENT;
1409 		}
1410 		/*
1411 		 * remove the previous bits in the bitset bs to find the
1412 		 * next non zero bit in the bitset. This needs to be done
1413 		 * only if the idx is same as he one you started.
1414 		 */
1415 		if (s_idx == idx)
1416 			bs &= (-1UL >> mod_fid);
1417 		next_fid = (idx * ULP_INDEX_BITMAP_SIZE) + __builtin_clzl(bs);
1418 		if (*child_fid >= next_fid) {
1419 			BNXT_TF_DBG(ERR, "Parent Child Database is corrupt\n");
1420 			return -ENOENT;
1421 		}
1422 		idx = next_fid / ULP_INDEX_BITMAP_SIZE;
1423 	} while (!ULP_INDEX_BITMAP_GET(child_bitset[idx], next_fid));
1424 	*child_fid = next_fid;
1425 	return 0;
1426 }
1427 
1428 /*
1429  * Orphan the child flow entry
1430  * This is called only for child flows that have
1431  * BNXT_ULP_RESOURCE_FUNC_CHILD_FLOW resource
1432  *
1433  * ulp_ctxt [in] Ptr to ulp_context
1434  * flow_type [in] Specify it is regular or default flow
1435  * fid [in] The index to the flow entry
1436  *
1437  * Returns 0 on success and negative on failure.
1438  */
1439 int32_t
1440 ulp_flow_db_child_flow_reset(struct bnxt_ulp_context *ulp_ctxt,
1441 			     enum bnxt_ulp_fdb_type flow_type,
1442 			     uint32_t fid)
1443 {
1444 	struct bnxt_ulp_flow_db *flow_db;
1445 	struct bnxt_ulp_flow_tbl *flow_tbl;
1446 	struct ulp_fdb_resource_info *fid_res;
1447 	uint32_t res_id = 0;
1448 
1449 	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
1450 	if (!flow_db) {
1451 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
1452 		return -EINVAL;
1453 	}
1454 
1455 	if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) {
1456 		BNXT_TF_DBG(ERR, "Invalid flow type\n");
1457 		return -EINVAL;
1458 	}
1459 
1460 	flow_tbl = &flow_db->flow_tbl;
1461 	/* check for max flows */
1462 	if (fid >= flow_tbl->num_flows || !fid) {
1463 		BNXT_TF_DBG(ERR, "Invalid flow index %x\n", fid);
1464 		return -EINVAL;
1465 	}
1466 
1467 	/* check if the flow is active or not */
1468 	if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) {
1469 		BNXT_TF_DBG(ERR, "flow does not exist\n");
1470 		return -EINVAL;
1471 	}
1472 
1473 	/* Iterate the resource to get the resource handle */
1474 	res_id =  fid;
1475 	while (res_id) {
1476 		fid_res = &flow_tbl->flow_resources[res_id];
1477 		if (ulp_flow_db_resource_func_get(fid_res) ==
1478 		    BNXT_ULP_RESOURCE_FUNC_CHILD_FLOW) {
1479 			/* invalidate the resource details */
1480 			fid_res->resource_hndl = 0;
1481 			return 0;
1482 		}
1483 		res_id = 0;
1484 		ULP_FLOW_DB_RES_NXT_SET(res_id, fid_res->nxt_resource_idx);
1485 	}
1486 	/* failed */
1487 	return -1;
1488 }
1489 
1490 /*
1491  * Create parent flow in the parent flow tbl
1492  *
1493  * parms [in] Ptr to mapper params
1494  *
1495  * Returns 0 on success and negative on failure.
1496  */
1497 int32_t
1498 ulp_flow_db_parent_flow_create(struct bnxt_ulp_mapper_parms *parms)
1499 {
1500 	struct ulp_flow_db_res_params fid_parms;
1501 	int32_t fid_idx;
1502 
1503 	/* create the child flow entry in parent flow table */
1504 	fid_idx = ulp_flow_db_parent_flow_alloc(parms->ulp_ctx, parms->fid);
1505 	if (fid_idx < 0) {
1506 		BNXT_TF_DBG(ERR, "Error in creating parent flow fid %x\n",
1507 			    parms->fid);
1508 		return -1;
1509 	}
1510 
1511 	/* Add the parent details in the resource list of the flow */
1512 	memset(&fid_parms, 0, sizeof(fid_parms));
1513 	fid_parms.resource_func	= BNXT_ULP_RESOURCE_FUNC_PARENT_FLOW;
1514 	fid_parms.resource_hndl	= fid_idx;
1515 	fid_parms.critical_resource = BNXT_ULP_CRITICAL_RESOURCE_NO;
1516 	if (ulp_flow_db_resource_add(parms->ulp_ctx, BNXT_ULP_FDB_TYPE_REGULAR,
1517 				     parms->fid, &fid_parms)) {
1518 		BNXT_TF_DBG(ERR, "Error in adding flow res for fid %x\n",
1519 			    parms->fid);
1520 		return -1;
1521 	}
1522 	return 0;
1523 }
1524 
1525 /*
1526  * Create child flow in the parent flow tbl
1527  *
1528  * parms [in] Ptr to mapper params
1529  *
1530  * Returns 0 on success and negative on failure.
1531  */
1532 int32_t
1533 ulp_flow_db_child_flow_create(struct bnxt_ulp_mapper_parms *parms)
1534 {
1535 	struct ulp_flow_db_res_params fid_parms;
1536 	int32_t rc;
1537 
1538 	/* create the parent flow entry in parent flow table */
1539 	rc = ulp_flow_db_parent_child_flow_set(parms->ulp_ctx,
1540 					       parms->parent_fid,
1541 					       parms->fid, 1);
1542 	if (rc) {
1543 		BNXT_TF_DBG(ERR, "Error in setting child fid %x\n", parms->fid);
1544 		return -1;
1545 	}
1546 
1547 	/* Add the parent details in the resource list of the flow */
1548 	memset(&fid_parms, 0, sizeof(fid_parms));
1549 	fid_parms.resource_func	= BNXT_ULP_RESOURCE_FUNC_CHILD_FLOW;
1550 	fid_parms.resource_hndl	= parms->parent_fid;
1551 	fid_parms.critical_resource = BNXT_ULP_CRITICAL_RESOURCE_NO;
1552 	if (ulp_flow_db_resource_add(parms->ulp_ctx, BNXT_ULP_FDB_TYPE_REGULAR,
1553 				     parms->fid, &fid_parms)) {
1554 		BNXT_TF_DBG(ERR, "Error in adding flow res for fid %x\n",
1555 			    parms->fid);
1556 		return -1;
1557 	}
1558 	return 0;
1559 }
1560