xref: /dpdk/drivers/net/bnxt/tf_core/v3/tfc_cpm.c (revision 80317ff6adfde7f618a100098e068ad5512e8e22)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019-2021 Broadcom
3  * All rights reserved.
4  */
5 #include <rte_malloc.h>
6 
7 #include "bnxt.h"
8 #include "tfc.h"
9 #include "tfc_cpm.h"
10 
11 /*
12  * Per pool entry
13  */
14 struct cpm_pool_entry {
15 	bool valid;
16 	struct tfc_cmm *cmm;
17 	uint32_t used_count;
18 	bool all_used;
19 	struct cpm_pool_use *pool_use;
20 };
21 
22 /*
23  * Pool use list entry
24  */
25 struct cpm_pool_use {
26 	uint16_t pool_id;
27 	struct cpm_pool_use *prev;
28 	struct cpm_pool_use *next;
29 };
30 
31 /*
32  * tfc_cpm
33  *
34  * This is the main CPM data struct
35  */
36 struct tfc_cpm {
37 	struct cpm_pool_entry *pools;
38 	uint16_t available_pool_id; /* pool with highest use count, i.e. most used entries */
39 	bool pool_valid; /* pool has free entries */
40 	uint32_t pool_size; /* number of entries in each pool */
41 	uint32_t max_pools; /* maximum number of pools */
42 	uint32_t next_index; /* search index */
43 	struct cpm_pool_use *pool_use_list; /* Ordered list of pool usage */
44 };
45 
46 #define CPM_DEBUG 0
47 
48 #if (CPM_DEBUG == 1)
49 static void show_list(char *str, struct tfc_cpm *cpm)
50 {
51 	struct cpm_pool_use *pu = cpm->pool_use_list;
52 
53 	PMD_DRV_LOG_LINE("%s - ", str);
54 
55 	while (pu != NULL) {
56 		PMD_DRV_LOG_LINE("PU(%p) id:%d(u:%d au:%d) p:0x%p n:0x%p",
57 				 pu,
58 				 pu->pool_id,
59 				 cpm->pools[pu->pool_id].used_count,
60 				 cpm->pools[pu->pool_id].all_used,
61 				 pu->prev,
62 				 pu->next);
63 
64 		pu = pu->next;
65 	}
66 }
67 #endif
68 
69 static int cpm_insert_pool_id(struct tfc_cpm *cpm, uint16_t pool_id)
70 {
71 	struct cpm_pool_entry *pool = &cpm->pools[pool_id];
72 	struct cpm_pool_use *pool_use = cpm->pool_use_list;
73 	struct cpm_pool_use *new_pool_use;
74 	struct cpm_pool_use *prev = NULL;
75 
76 	if (!pool->valid) {
77 		PMD_DRV_LOG_LINE(ERR, "Pool ID:0x%x is invalid", pool_id);
78 		return -EINVAL;
79 	}
80 
81 	/* Find where in insert new entry */
82 	while (pool_use != NULL) {
83 		if (cpm->pools[pool_use->pool_id].valid &&
84 			cpm->pools[pool_use->pool_id].used_count >
85 			pool->used_count) {
86 			pool_use = pool_use->next;
87 			prev =	pool_use;
88 		} else {
89 			break;
90 		}
91 	}
92 
93 	/* Alloc new entry */
94 	new_pool_use = rte_zmalloc("tf", sizeof(struct cpm_pool_use), 0);
95 	new_pool_use->pool_id = pool_id;
96 	new_pool_use->prev = NULL;
97 	new_pool_use->next = NULL;
98 	pool->pool_use = new_pool_use;
99 
100 	if (pool_use == NULL) { /* Empty list */
101 		cpm->pool_use_list = new_pool_use;
102 	} else if (prev == NULL) { /* Start of list */
103 		cpm->pool_use_list = new_pool_use;
104 		new_pool_use->next = pool_use;
105 		pool_use->prev = new_pool_use;
106 	} else { /* Within list */
107 		prev->next = new_pool_use;
108 		new_pool_use->next = pool_use;
109 		new_pool_use->prev = prev;
110 	}
111 
112 	cpm->available_pool_id = cpm->pool_use_list->pool_id;
113 	cpm->pool_valid = true;
114 #if (CPM_DEBUG == 1)
115 	show_list("Insert", cpm);
116 #endif
117 	return 0;
118 }
119 
120 static int cpm_sort_pool_id(struct tfc_cpm *cpm, uint16_t pool_id)
121 {
122 	struct cpm_pool_entry *pool = &cpm->pools[pool_id];
123 	struct cpm_pool_use *pool_use = pool->pool_use;
124 	struct cpm_pool_use *prev, *next;
125 
126 	/*
127 	 * Does entry need to move up, down or stay where it is?
128 	 *
129 	 * The list is ordered by:
130 	 *	  Head:	 - Most used, but not full
131 	 *			 - ....next most used but not full
132 	 *			 - least used
133 	 *	  Tail:	 - All used
134 	 */
135 	while (1) {
136 		if (pool_use->prev != NULL &&
137 			cpm->pools[pool_use->prev->pool_id].valid &&
138 			!pool->all_used &&
139 			(cpm->pools[pool_use->prev->pool_id].all_used ||
140 			 cpm->pools[pool_use->prev->pool_id].used_count <
141 			 pool->used_count)) {
142 			/* Move up */
143 			prev = pool_use->prev;
144 			pool_use->prev->next = pool_use->next;
145 			if (pool_use->next != NULL) /* May be at the end of the list */
146 				pool_use->next->prev = pool_use->prev;
147 			pool_use->next = pool_use->prev;
148 
149 			if (pool_use->prev->prev != NULL) {
150 				pool_use->prev->prev->next = pool_use;
151 				pool_use->prev = pool_use->prev->prev;
152 			} else {
153 				/* Moved to head of the list */
154 				pool_use->prev->prev = pool_use;
155 				pool_use->prev = NULL;
156 				cpm->pool_use_list = pool_use;
157 			}
158 
159 			prev->prev = pool_use;
160 		} else if (pool_use->next != NULL &&
161 				   cpm->pools[pool_use->next->pool_id].valid &&
162 				   (pool->all_used ||
163 					(!cpm->pools[pool_use->next->pool_id].all_used &&
164 					 (cpm->pools[pool_use->next->pool_id].used_count >
165 					  pool->used_count)))) {
166 			/* Move down */
167 			next = pool_use->next;
168 			pool_use->next->prev = pool_use->prev;
169 			if (pool_use->prev != NULL) /* May be at the start of the list */
170 				pool_use->prev->next = pool_use->next;
171 			else
172 				cpm->pool_use_list = pool_use->next;
173 
174 			pool_use->prev = pool_use->next;
175 
176 			if (pool_use->next->next != NULL) {
177 				pool_use->next->next->prev = pool_use;
178 				pool_use->next = pool_use->next->next;
179 			} else {
180 				/* Moved to end of the list */
181 				pool_use->next->next = pool_use;
182 				pool_use->next = NULL;
183 			}
184 
185 			next->next = pool_use;
186 		} else {
187 			/* Nothing to do */
188 			break;
189 		}
190 #if (CPM_DEBUG == 1)
191 		show_list("Sort", cpm);
192 #endif
193 	}
194 
195 	if (cpm->pools[cpm->pool_use_list->pool_id].all_used) {
196 		cpm->available_pool_id = TFC_CPM_INVALID_POOL_ID;
197 		cpm->pool_valid = false;
198 	} else {
199 		cpm->available_pool_id = cpm->pool_use_list->pool_id;
200 		cpm->pool_valid = true;
201 	}
202 
203 	return 0;
204 }
205 
206 int tfc_cpm_open(struct tfc_cpm **cpm, uint32_t max_pools)
207 {
208 	/* Allocate CPM struct */
209 	*cpm = rte_zmalloc("tf", sizeof(struct tfc_cpm), 0);
210 	if (*cpm == NULL) {
211 		PMD_DRV_LOG_LINE(ERR, "cpm alloc error %s", strerror(ENOMEM));
212 		*cpm = NULL;
213 		return -ENOMEM;
214 	}
215 
216 	/* Allocate CPM pools array */
217 	(*cpm)->pools = rte_zmalloc("tf", sizeof(struct cpm_pool_entry) * max_pools, 0);
218 	if ((*cpm)->pools == NULL) {
219 		PMD_DRV_LOG_LINE(ERR, "pools alloc error %s", strerror(ENOMEM));
220 		rte_free(*cpm);
221 		*cpm = NULL;
222 
223 		return -ENOMEM;
224 	}
225 
226 	/* Init pool entries by setting all fields to zero */
227 	memset((*cpm)->pools, 0, sizeof(struct cpm_pool_entry) * max_pools);
228 
229 	/* Init remaining CPM fields */
230 	(*cpm)->pool_valid = false;
231 	(*cpm)->available_pool_id = 0;
232 	(*cpm)->max_pools = max_pools;
233 	(*cpm)->pool_use_list = NULL;
234 
235 	return	0;
236 }
237 
238 int tfc_cpm_close(struct tfc_cpm *cpm)
239 {
240 	struct cpm_pool_use *current;
241 	struct cpm_pool_use *next;
242 
243 	if (cpm == NULL) {
244 		PMD_DRV_LOG_LINE(ERR, "CPM is NULL");
245 		return -EINVAL;
246 	}
247 
248 	/* Free pool_use_list */
249 	current = cpm->pool_use_list;
250 	while (current != NULL) {
251 		next = current->next;
252 		rte_free(current);
253 		current = next;
254 	}
255 
256 	/* Free pools */
257 	rte_free(cpm->pools);
258 
259 	/* Free CPM */
260 	rte_free(cpm);
261 
262 	return 0;
263 }
264 
265 int tfc_cpm_set_pool_size(struct tfc_cpm *cpm, uint32_t pool_sz_in_records)
266 {
267 	if (cpm == NULL) {
268 		PMD_DRV_LOG_LINE(ERR, "CPM is NULL");
269 		return -EINVAL;
270 	}
271 
272 	cpm->pool_size = pool_sz_in_records;
273 	return 0;
274 }
275 
276 int tfc_cpm_get_pool_size(struct tfc_cpm *cpm, uint32_t *pool_sz_in_records)
277 {
278 	if (cpm == NULL) {
279 		PMD_DRV_LOG_LINE(ERR, "CPM is NULL");
280 		return -EINVAL;
281 	}
282 
283 	*pool_sz_in_records = cpm->pool_size;
284 	return 0;
285 }
286 
287 int tfc_cpm_set_cmm_inst(struct tfc_cpm *cpm, uint16_t pool_id, struct tfc_cmm *cmm)
288 {
289 	struct cpm_pool_entry *pool;
290 
291 	if (cpm == NULL) {
292 		PMD_DRV_LOG_LINE(ERR, "CPM is NULL");
293 		return -EINVAL;
294 	}
295 
296 	pool = &cpm->pools[pool_id];
297 
298 	if (pool->valid && cmm != NULL) {
299 		PMD_DRV_LOG_LINE(ERR, "Pool ID:0x%x is already in use", pool_id);
300 		return -EINVAL;
301 	}
302 
303 	pool->cmm = cmm;
304 	pool->used_count = 0;
305 	pool->all_used = false;
306 	pool->pool_use = NULL;
307 
308 	if (cmm == NULL) {
309 		pool->valid = false;
310 	} else {
311 		pool->valid = true;
312 		cpm_insert_pool_id(cpm, pool_id);
313 	}
314 
315 	return 0;
316 }
317 
318 int tfc_cpm_get_cmm_inst(struct tfc_cpm *cpm, uint16_t pool_id, struct tfc_cmm **cmm)
319 {
320 	struct cpm_pool_entry *pool;
321 
322 	if (cpm == NULL) {
323 		PMD_DRV_LOG_LINE(ERR, "CPM is NULL");
324 		return -EINVAL;
325 	}
326 
327 	pool = &cpm->pools[pool_id];
328 
329 	if (!pool->valid) {
330 		PMD_DRV_LOG_LINE(ERR, "Pool ID:0x%x is not valid", pool_id);
331 		return -EINVAL;
332 	}
333 
334 	*cmm = pool->cmm;
335 	return 0;
336 }
337 
338 int tfc_cpm_get_avail_pool(struct tfc_cpm *cpm, uint16_t *pool_id)
339 {
340 	if (cpm == NULL) {
341 		PMD_DRV_LOG_LINE(ERR, "CPM is NULL");
342 		return -EINVAL;
343 	}
344 
345 	if (!cpm->pool_valid)
346 		return -EINVAL;
347 
348 	*pool_id = cpm->available_pool_id;
349 
350 	return 0;
351 }
352 
353 int tfc_cpm_set_usage(struct tfc_cpm *cpm, uint16_t pool_id, uint32_t used_count, bool all_used)
354 {
355 	struct cpm_pool_entry *pool;
356 
357 	if (cpm == NULL) {
358 		PMD_DRV_LOG_LINE(ERR, "CPM is NULL");
359 		return -EINVAL;
360 	}
361 
362 	pool = &cpm->pools[pool_id];
363 
364 	if (!pool->valid) {
365 		PMD_DRV_LOG_LINE(ERR, "Pool ID:0x%x is invalid", pool_id);
366 		return -EINVAL;
367 	}
368 
369 	if (used_count > cpm->pool_size) {
370 		PMD_DRV_LOG_LINE(ERR,
371 				 "Number of entries(%d) exceeds pool_size(%d)",
372 				 used_count, cpm->pool_size);
373 		return -EINVAL;
374 	}
375 
376 	pool->all_used = all_used;
377 	pool->used_count = used_count;
378 
379 	/* Update ordered list of pool_ids */
380 	cpm_sort_pool_id(cpm, pool_id);
381 
382 	return 0;
383 }
384 int tfc_cpm_srchm_by_configured_pool(struct tfc_cpm *cpm, enum cfa_srch_mode srch_mode,
385 				    uint16_t *pool_id, struct tfc_cmm **cmm)
386 {
387 	uint32_t i;
388 
389 	if (cpm == NULL) {
390 		PMD_DRV_LOG_LINE(ERR, "CPM is NULL");
391 		return -EINVAL;
392 	}
393 
394 	if (!pool_id) {
395 		PMD_DRV_LOG_LINE(ERR, "pool_id ptr is NULL");
396 		return -EINVAL;
397 	}
398 
399 	if (!cmm) {
400 		PMD_DRV_LOG_LINE(ERR, "cmm ptr is NULL");
401 		return -EINVAL;
402 	}
403 	*pool_id = TFC_CPM_INVALID_POOL_ID;
404 	*cmm = NULL;
405 
406 	if (srch_mode == CFA_SRCH_MODE_FIRST)
407 		cpm->next_index = 0;
408 
409 	for (i = cpm->next_index; i < cpm->max_pools; i++) {
410 		if (cpm->pools[i].cmm) {
411 			*pool_id = i;
412 			*cmm = cpm->pools[i].cmm;
413 			cpm->next_index = i + 1;
414 			return 0;
415 		}
416 	}
417 	cpm->next_index = cpm->max_pools;
418 	return -ENOENT;
419 }
420