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