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