idxres_mdb.c (138272B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * Module: Indexed Resource management, MDB model 8 */ 9 10 #include <shared/bsl.h> 11 12 #include <sal/types.h> 13 #include <shared/error.h> 14 #include <shared/idxres_mdb.h> 15 16 17 #include <soc/cm.h> 18 #include <soc/drv.h> 19 20 /* 21 * This resource manager divides an indexed resource into elements, collecting 22 * those elements into banks (to reduce the space required to represent a 23 * single element). It tracks lists of free elements and user defined lists 24 * of elements. 25 * 26 * The bank size is configurable in powers of two elements, up to 32768 27 * elements per bank. Blocks can not cross bank boundaries. Useful bank 28 * sizes that are supported are 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 29 * and 32768; there may be good argument for smaller banks (such as finer 30 * grains when using the 'low' and 'high' alloc methods), but there is a 31 * certain amount of base overhead per bank (plus a certain amount per list 32 * per bank, whether the list is a user list or a free list), so it seems that 33 * banks should be as large as reasonable for the purpose. Also, there is 34 * likely to be a bank size that seems 'most optimal' or, at least, 'least 35 * pessimal' for a given maximum block size -- for example, 4096 element 36 * banks provides the least waste for the case of largest block = 132 elems. 37 * 38 * The free lists include a required single-element block list, and arbitrary 39 * element count block lists (up to the bank size). These are arbitrary 40 * instead of power of two in order to improve efficiency in cases where 41 * element counts are likely (for example) to be a bit larger than the nearest 42 * power of two. Again, using 132 element largest blocks as an example, and 43 * knowing (or just assuming) that some other likely sizes are 1, 2, 3, 4, 5, 44 * 16, 28, 50, and 98, you might choose those as the free list block sizes. 45 * It should be pointed out though, that if using the join on alloc feature, 46 * higher efficiency can be obtained by also having some free lists for block 47 * sizes in excess of the largest expected block (so maybe add 256, 512, 1024, 48 * and 2048 element block free lists if using 2048 or 4096 element banks), 49 * though this may have minimal impact if not using the join on alloc feature. 50 * 51 * The user lists can contain blocks of any size that is desired by the user 52 * (within the constraint that any single block must exist entirely within a 53 * single bank), but the user lists are NOT sorted, NOR are they ordered. It 54 * is absolutely NOT guaranteed that blocks will appear in a traversal of a 55 * user list in anything even vaguely resembling the order in which those 56 * blocks were added to the user list (most likely they will not). This is 57 * due to the way the lists are stored (the compressed form of the elements). 58 * 59 * Blocks are not required to be in a list. It is perfectly reasonable that 60 * the user lists have special meaning and the general case is that allocated 61 * blocks are floating (as long as the user knows about them). However, there 62 * is no 'non-list', so blocks that are not in a list will not have 63 * predecessors or successors, nor will any list information be associated 64 * with the block. 65 */ 66 67 /***************************************************************************** 68 * 69 * Implementation 70 * 71 * All of this stuff is private to this module; most of it has been written to 72 * assume everything is perfect and acceptable (to improve performance). 73 * 74 * Functions in this section are generally very simple in their actual nature, 75 * and mostly commit entire operations (no partial updates or leakage). 76 * 77 * Block base is zero-based for these functions. 78 */ 79 80 81 #define _MDB_BLOCK_END 0xFFFF /* last block this bank this list */ 82 #define _MDB_BLOCK_NOT_HEAD 0xFFFE /* element is not head of a block */ 83 #define _MDB_BLOCK_NOT_IN_LIST 0xFFFD /* block is not in a list */ 84 #define _MDB_BLOCK_INVALID 0xFFF0 /* first invalid offset */ 85 #define _MDB_BANK_END 0xFFFF /* last bank in list */ 86 #define _MDB_BANK_NOT_PRESENT 0xFFFE /* bank not present in list */ 87 88 #define _MDB_VALID_CHECK(_mdb) \ 89 if (!(_mdb)) { \ 90 LOG_ERROR(BSL_LS_SOC_COMMON, \ 91 (BSL_META("NULL is not a valid handle\n"))); \ 92 return _SHR_E_PARAM; \ 93 } 94 #define _MDB_LOCK_TAKE(_mdb) \ 95 if ((_mdb)->lock) { \ 96 if (sal_mutex_take((_mdb)->lock,sal_mutex_FOREVER)) { \ 97 LOG_ERROR(BSL_LS_SOC_COMMON, \ 98 (BSL_META("unable to take mdb %08X lock\n"), \ 99 PTR_TO_INT(_mdb))); \ 100 return _SHR_E_INTERNAL; \ 101 } \ 102 } 103 #define _MDB_LOCK_GIVE(_mdb) \ 104 if ((_mdb)->lock) { \ 105 if (sal_mutex_give((_mdb)->lock)) { \ 106 LOG_ERROR(BSL_LS_SOC_COMMON, \ 107 (BSL_META("unable to release mdb %08X lock\n"), \ 108 PTR_TO_INT(_mdb))); \ 109 return _SHR_E_INTERNAL; \ 110 } \ 111 } 112 113 /* 114 * This describes a single element. The fields have different meanings 115 * depending upon whether the element is the head of a block or one of the 116 * other elements in a block (blocks of one element only have a head). 117 * 118 * For the head element: 119 * List indicates the list to which the block belongs. 120 * Count indicates the number of elements in the block. 121 * Next points to the next block in the list on this page. 122 * Prev points to the previous block in the list on this page. 123 * 124 * For non-head and non-tail elements: 125 * List indicates the element is not a head element. 126 * Count is zero. 127 * Next is reserved. 128 * Prev is reserved. 129 * 130 * For the tail element: 131 * List indicates the element is not a head element. 132 * Count indicates the number of elements in the block. 133 * Next is reserved. 134 * Prev is reserved. 135 * 136 * This layout basically means that manipulation of blocks is most efficient 137 * when it is done with the head element; any other element means that a 138 * second read (or more generally a search) must be performed to find the head 139 * element of the block. This behaviour reduces the updates necessary by not 140 * requiring blocks to be aligned to a power of two elements that is equal to 141 * or larger than the number of elements in the block, and should not impact 142 * performance in the general case, as the head element in a block is the 143 * element which serves as the handle for that block. 144 * 145 * The extension of the tail element containing accurate count information is 146 * to improve performance of the 'join downward' alloc/free features. 147 */ 148 /* Alignment is 64b */ 149 typedef struct shr_mdb_elem_desc_s { 150 shr_mdb_elem_bank_index_t list; /* list of which block is a member */ 151 shr_mdb_elem_bank_index_t count; /* elements in this block */ 152 shr_mdb_elem_bank_index_t next; /* next block this list-bank */ 153 shr_mdb_elem_bank_index_t prev; /* prev block this list-bank */ 154 } shr_mdb_elem_desc_t; 155 156 /* 157 * This describes a page within a single list. Lists are divivded into 158 * sublists per bank, so that allocation can be reasonably fast when it is 159 * requested that the allocation be performed preferring low or high element 160 * rather than fastest available fit. 161 * 162 * For a bank that is in a list: 163 * Head is the head of the first block in this bank on the list. 164 * Tail is the head of the last block in this bank on the list. 165 * Elems is the number of elements in this bank on the list. 166 * Blocks is the number of blocks in this bank on the list. 167 * Next is the next bank participating in this list. 168 * Prev is the previous bank participating in this list. 169 * 170 * For a bank that is not in a list: 171 * Head is reserved. 172 * Tail is reserved. 173 * Elems is zero. 174 * Blocks is zero. 175 * Next is reserved. 176 * Prev is reserved. 177 */ 178 /* Alignment is 96b */ 179 typedef struct shr_mdb_list_bank_desc_s { 180 shr_mdb_elem_bank_index_t head; /* first block this list-bank */ 181 shr_mdb_elem_bank_index_t tail; /* last block this list-bank */ 182 shr_mdb_elem_bank_index_t elems; /* elements this list-bank */ 183 shr_mdb_elem_bank_index_t blocks; /* blocks this list-bank */ 184 shr_mdb_bank_index_t next; /* next bank this list */ 185 shr_mdb_bank_index_t prev; /* previous bank this list */ 186 } shr_mdb_list_bank_desc_t; 187 188 /* 189 * This describes a list, as it covers the whole space. Each list is always 190 * assumed to exist at this level, even if it contains no elements. 191 * 192 * For a free list: 193 * Elems is the number of elements in the list. 194 * Blocks is the number of blocks in the list. 195 * Head is the first bank in the list. 196 * Tail is the last bank in the list. 197 * ElemsBlock is the number of elements per block on this list. 198 * Reserved is reserved (used for alignment). 199 * 200 * For a user list: 201 * Elems is the number of elements in the list. 202 * Blocks is the number of blocks in the list. 203 * Head is the first bank in the list. 204 * Tail is the last bank in the list. 205 * ElemsBlock is reserved. 206 * Reserved is reserved (used for alignment). 207 */ 208 /* Alignment is 96b */ 209 typedef struct shr_mdb_list_desc_s { 210 shr_mdb_elem_index_t elems; /* elements in this list */ 211 shr_mdb_elem_index_t blocks; /* blocks in this list */ 212 shr_mdb_bank_index_t head; /* first bank this list */ 213 shr_mdb_bank_index_t tail; /* last bank this list */ 214 shr_mdb_elem_bank_index_t elemsBlock; /* elements per block this list */ 215 shr_mdb_elem_bank_index_t reserved; /* for alignment */ 216 } shr_mdb_list_desc_t; 217 218 /* 219 * This describes the entire resource. 220 * 221 * Lock is the handle of the lock for the whole thing. If this is NULL, it 222 * means that the caller asked that it be constructed without a lock, and is 223 * therefore responsible for its protection. Otherwise, the specified lock 224 * will be taken before any access or manipulation, and freed immediately 225 * afterward. 226 * 227 * Low is the minimum element ID in this resource. Internally, element 228 * numbers start with zero, but this allows an external bias to be applied. 229 * 230 * Count is the number of elements in the resource. 231 * 232 * FreeLists is the number of free lists being used for allocation. Free list 233 * zero contains blocks of exactly one single element; other free lists 234 * contain only blocks of exactly the number of elements specified for that 235 * free list. 236 * 237 * UserLists is the number of user lists in this resource. These can be used 238 * for any purpose the user wants, and can contain blocks of any size that is 239 * supported by the resource. 240 * 241 * Lists is the total number of lists -- it is merely FreeLists and UserLists 242 * added together. This is kept for performance. 243 * 244 * Banks is the number of banks in this resource. This will be 245 * ceil(count/(2^bankShift)). 246 * 247 * BankShift is the shift distance for the number of elements in a bank (which 248 * will always be an integral power of two, except the last bank). 249 * 250 * BankMask is ~(1<<bankShift)-1, used as a mask for the bank number part of 251 * an element ID (after rebiasing), or inverted for use as a mask for the 252 * element offset within the bank. This is kept for performance. 253 * 254 * LastBankSize if the number of elements left over after all of the whole 255 * banks. If zero, it means that all of the elements fit in an integral 256 * number of banks; if nonzero, the final bank has the specified number of 257 * elements (will always be < 2^bankShift). 258 * 259 * AllocPref is the current alloc/free preferences. 260 * 261 * List is a pointer to the information for the lists (see above). 262 * 263 * ListBank is a pointer to the information for the banks within the lists 264 * (see above). 265 * 266 * Elem is a pointer to the element descriptors (see above). 267 * 268 * Note that the list descriptors, list-bank descriptors, and element 269 * descriptors follow the rest of the mdb_list_t, in the same alloc cell. 270 * This means it's a fairly large alloc cell. 271 */ 272 typedef struct shr_mdb_list_s { 273 sal_mutex_t lock; /* lock for this resource map */ 274 shr_mdb_elem_index_t low; /* lowest elem number as exposed */ 275 shr_mdb_elem_index_t count; /* number of elements */ 276 shr_mdb_elem_index_t freeLists; /* number of free lists */ 277 shr_mdb_elem_index_t userLists; /* number of user lists */ 278 shr_mdb_elem_index_t lists; /* total number of lists */ 279 shr_mdb_elem_index_t banks; /* number of banks */ 280 shr_mdb_elem_index_t bankShift; /* bank shift distance */ 281 shr_mdb_elem_index_t bankMask; /* bank bits maxk */ 282 shr_mdb_elem_index_t lastBankSize; /* elements in last bank */ 283 shr_mdb_alloc_pref_t allocPref; /* alloc/free preferences */ 284 shr_mdb_list_desc_t *list; /* pointer to list descriptors */ 285 shr_mdb_list_bank_desc_t *listBank; /* pointer to list-bank descriptors */ 286 shr_mdb_elem_desc_t *elem; /* pointer to element descriptors */ 287 /* list descriptors follow */ 288 /* list-bank descriptors follow */ 289 /* element descriptors follow */ 290 } shr_mdb_list_t; 291 292 #define _MDB_BANK_FROM_ELEM(_res,_elem) \ 293 (((_elem) & (_res).bankMask) >> (_res).bankShift) 294 295 #define _MDB_OFFS_FROM_ELEM(_res,_elem) \ 296 ((_elem) & (~((_res).bankMask))) 297 298 #define _MDB_ELEM_FROM_BANK_OFFS(_res,_bank,_offs) \ 299 ((_offs) | ((_bank) << (_res).bankShift)) 300 301 #define _MDB_LIST_FROM_USERLIST(_res,_userlist) \ 302 ((_userlist) + (_res).freeLists) 303 304 #define _MDB_LIST_BANK_INDEX(_res,_list,_bank) \ 305 ((_list) + ((_bank) * (_res).lists)) 306 307 #define _MDB_ELEM_BANK_DESC(_res,_bank,_offs) \ 308 ((_res).elem[_MDB_ELEM_FROM_BANK_OFFS(_res, _bank, _offs)]) 309 310 #define _MDB_LIST_BANK_DESC(_res,_list,_bank) \ 311 ((_res).listBank[_MDB_LIST_BANK_INDEX(_res, _list, _bank)]) 312 313 /* 314 * Function 315 * _mdb_block_prep 316 * Purpose 317 * Prepare a block of elements. This rewrites either the head or the entire 318 * block so that the block is ready for use or list insertion. The block 319 * must not be a member of a list. 320 * Arguments 321 * (in) shr_mdb_list_handle_t list = pointer to the list info (modified) 322 * (in) shr_mdb_elem_index_t head = head element of the block 323 * (in) shr_mdb_elem_bank_index_t count = elements in this block 324 * Return 325 * void 326 * Notes 327 * Assumes all arguments are valid. 328 */ 329 static void 330 _mdb_block_prep(shr_mdb_list_handle_t res, 331 shr_mdb_elem_index_t head, 332 shr_mdb_elem_bank_index_t count) 333 { 334 shr_mdb_elem_desc_t elem; 335 336 LOG_DEBUG(BSL_LS_SOC_COMMON, 337 (BSL_META("(%08X,%08X,%d)\n"), 338 PTR_TO_INT(res), 339 head, 340 count)); 341 342 /* prepare head element */ 343 elem.list = _MDB_BLOCK_NOT_IN_LIST; 344 elem.count = count; 345 elem.prev = _MDB_BLOCK_END; 346 elem.next = _MDB_BLOCK_END; 347 res->elem[head] = elem; 348 if (count > 1) { 349 /* prepare tail element */ 350 elem.list = _MDB_BLOCK_NOT_HEAD; 351 res->elem[head + count - 1] = elem; 352 /* prepare any middle elements */ 353 for (elem.count = 0, head++; 354 count > 2; 355 head++, count--) { 356 res->elem[head] = elem; 357 } 358 } /* if (count) */ 359 } 360 361 /* 362 * Function 363 * _mdb_block_join 364 * Purpose 365 * Join two blocks into one. The blocks must not be members of any list. 366 * The blocks must be strictly adjacent. 367 * Arguments 368 * (in) shr_mdb_list_handle_t list = pointer to the list info (modified) 369 * (in) shr_mdb_elem_index_t headLow = head element of the low block 370 * (in) shr_mdb_elem_index_t headHigh = head element of the high block 371 * Return 372 * void 373 * Notes 374 * Assumes all arguments are valid. 375 */ 376 static void 377 _mdb_block_join(shr_mdb_list_handle_t res, 378 shr_mdb_elem_index_t headLow, 379 shr_mdb_elem_index_t headHigh) 380 { 381 shr_mdb_elem_bank_index_t count = res->elem[headLow].count; 382 shr_mdb_elem_bank_index_t newCount; 383 shr_mdb_elem_index_t headTemp; 384 385 LOG_DEBUG(BSL_LS_SOC_COMMON, 386 (BSL_META("(%08X,%08X,%08X)\n"), 387 PTR_TO_INT(res), 388 headLow, 389 headHigh)); 390 391 /* ensure joined blocks are in the expected order */ 392 if (headLow > headHigh) { 393 headTemp = headLow; 394 headLow = headHigh; 395 headHigh = headTemp; 396 } 397 /* compute new joined block length & update head element */ 398 newCount = res->elem[headLow].count + res->elem[headHigh].count; 399 /* remove old first block tail element */ 400 res->elem[headLow + count - 1].count = 0; 401 /* remove old second block head element */ 402 res->elem[headHigh].list = _MDB_BLOCK_NOT_HEAD; 403 res->elem[headHigh].count = 0; 404 /* update new joined block head element */ 405 res->elem[headLow].count = newCount; 406 /* update new joined block tail element */ 407 res->elem[headLow + newCount - 1].count = newCount; 408 } 409 410 /* 411 * Function 412 * _mdb_block_split_size 413 * Purpose 414 * Split a block into two blocks, one of them a specified size. The block 415 * must not be a member of a list. 416 * Arguments 417 * (in) shr_mdb_list_handle_t list = pointer to the list info (modified) 418 * (in) shr_mdb_elem_index_t head = head element of the original block 419 * (in) shr_mdb_elem_bank_index_t count = number of elements to split off 420 * (in) int high = TRUE to split off from high end, FALSE for low end 421 * (out) shr_mdb_elem_index_t *newBlock = where to put split block head 422 * (out) shr_mdb_elem_index_t *extra = where to put remainder block head 423 * Return 424 * void 425 * Notes 426 * Assumes all arguments are valid. 427 */ 428 static void 429 _mdb_block_split_size(shr_mdb_list_handle_t res, 430 shr_mdb_elem_index_t head, 431 shr_mdb_elem_bank_index_t count, 432 int high, 433 shr_mdb_elem_index_t *newBlock, 434 shr_mdb_elem_index_t *extra) 435 { 436 shr_mdb_elem_bank_index_t oldCount = res->elem[head].count; 437 438 LOG_DEBUG(BSL_LS_SOC_COMMON, 439 (BSL_META("(%08X,%08X,%d,%s,*,*) enter\n"), 440 PTR_TO_INT(res), 441 head, 442 count, 443 high?"High":"Low")); 444 445 /* split the block based upon high or low becoming the requested size */ 446 if (high) { 447 /* high end of block becomes the requested size */ 448 *newBlock = head + oldCount - count; 449 *extra = head; 450 } else { 451 /* low end of block becomes the requested size */ 452 *newBlock = head; 453 *extra = head + count; 454 } 455 /* set new block head and tail */ 456 res->elem[*newBlock].list = _MDB_BLOCK_NOT_IN_LIST; 457 res->elem[*newBlock].count = count; 458 res->elem[*newBlock + count - 1].count = count; 459 /* set leftover block head and tail */ 460 res->elem[*extra].list = _MDB_BLOCK_NOT_IN_LIST; 461 res->elem[*extra].count = oldCount - count; 462 res->elem[*extra + (oldCount - count) - 1].count = oldCount - count; 463 464 LOG_DEBUG(BSL_LS_SOC_COMMON, 465 (BSL_META("(%08X,%08X,%d,%s,&(%08X),&(%08X)) leave\n"), 466 PTR_TO_INT(res), 467 head, 468 count, 469 high?"High":"Low", 470 *newBlock, 471 *extra)); 472 } 473 474 /* 475 * Function 476 * _mdb_block_split_point 477 * Purpose 478 * Split a block into two blocks, at a specific point. The block must not 479 * be a member of a list, and must include elements below AND at the split 480 * point (so 'second' must be strictly greater than 'head' and still fall 481 * within the block at 'head'). The block will be split so the original 482 * head is the head element of the lower block and second will be the head 483 * of the upper block, after the call. 484 * Arguments 485 * (in) shr_mdb_list_handle_t list = pointer to the list info (modified) 486 * (in) shr_mdb_elem_index_t head = head element of the original block 487 * (in) shr_mdb_elem_index_t second = head element of second sub block 488 * Return 489 * void 490 * Notes 491 * Assumes all arguments are valid. 492 */ 493 static void 494 _mdb_block_split_point(shr_mdb_list_handle_t res, 495 shr_mdb_elem_index_t head, 496 shr_mdb_elem_index_t second) 497 { 498 shr_mdb_elem_bank_index_t oldCount = res->elem[head].count; 499 shr_mdb_elem_bank_index_t newCount = second - head; 500 shr_mdb_elem_bank_index_t auxCount = oldCount - newCount; 501 502 LOG_DEBUG(BSL_LS_SOC_COMMON, 503 (BSL_META("(%08X,%08X,%08X) enter\n"), 504 PTR_TO_INT(res), 505 head, 506 second)); 507 508 /* set lower block head and tail */ 509 res->elem[head].count = newCount; 510 res->elem[second - 1].count = newCount; 511 /* set upper block head and tail */ 512 res->elem[second].list = _MDB_BLOCK_NOT_IN_LIST; 513 res->elem[second].count = oldCount - newCount; 514 res->elem[second + auxCount - 1].count = oldCount - newCount; 515 } 516 517 /* 518 * Function 519 * _mdb_list_insert 520 * Purpose 521 * Insert a block of elements to a list. This assumes the block has already 522 * been prepared, and merely updates the list membership information for the 523 * bank in which the block resides and for the block in question. It will 524 * add the bank to those in the list if the bank is not already 525 * participating in the list. 526 * Arguments 527 * (in) shr_mdb_list_handle_t list = pointer to the list info (modified) 528 * (in) shr_mdb_elem_index_t head = head element of the block 529 * (in) shr_mdb_elem_index_t list = the list on which the block is to be put 530 * Return 531 * void 532 * Notes 533 * Assumes all arguments are valid. 534 */ 535 static void 536 _mdb_list_insert(shr_mdb_list_handle_t res, 537 shr_mdb_elem_index_t head, 538 shr_mdb_elem_bank_index_t list) 539 { 540 shr_mdb_list_bank_desc_t *listBank; 541 shr_mdb_elem_desc_t *thisElem; 542 shr_mdb_elem_bank_index_t bank; 543 shr_mdb_elem_bank_index_t offs; 544 545 LOG_DEBUG(BSL_LS_SOC_COMMON, 546 (BSL_META("(%08X,%08X,%04X)\n"), 547 PTR_TO_INT(res), 548 head, 549 list)); 550 551 /* resolve some things about the block's head element */ 552 bank = _MDB_BANK_FROM_ELEM(*res, head); 553 offs = _MDB_OFFS_FROM_ELEM(*res, head); 554 thisElem = &(res->elem[head]); 555 listBank = &_MDB_LIST_BANK_DESC(*res, list, bank); 556 /* set the block as being on this list */ 557 thisElem->list = list; 558 /* link this block into this bank of this list */ 559 thisElem->prev = _MDB_BLOCK_END; 560 thisElem->next = listBank->head; 561 listBank->head = offs; 562 if (listBank->blocks) { 563 /* not the first block this list this bank */ 564 /* set up backlink */ 565 _MDB_ELEM_BANK_DESC(*res, bank, thisElem->next).prev = offs; 566 } else { 567 /* the first block this list this bank */ 568 /* set up tail */ 569 listBank->tail = offs; 570 /* add this bank to the list */ 571 listBank->next = res->list[list].head; 572 listBank->prev = _MDB_BANK_END; 573 res->list[list].head = bank; 574 if (res->list[list].blocks) { 575 /* not the first block this list */ 576 /* set up backlink */ 577 _MDB_LIST_BANK_DESC(*res, list, listBank->next).prev = bank; 578 } else { 579 /* first block this list; set up tail */ 580 res->list[list].tail = bank; 581 } 582 } 583 /* account for this block on this list (bank and total) */ 584 listBank->elems += thisElem->count; 585 res->list[list].elems += thisElem->count; 586 listBank->blocks++; 587 res->list[list].blocks++; 588 } 589 590 /* 591 * Function 592 * _mdb_block_list_remove 593 * Purpose 594 * Remove a block of elements from a list. This will merely update the 595 * block's membership information and delink if from its list. It will also 596 * remove the affected bank from the list if there are no more blocks in the 597 * list on that page. The block must be a member of some list. 598 * Arguments 599 * (in) shr_mdb_list_handle_t list = pointer to the list info (modified) 600 * (in) shr_mdb_elem_index_t head = head element of the block 601 * Return 602 * void 603 * Notes 604 * Assumes all arguments are valid. 605 */ 606 static void 607 _mdb_list_remove(shr_mdb_list_handle_t res, 608 shr_mdb_elem_index_t head) 609 { 610 shr_mdb_list_bank_desc_t *listBank; 611 shr_mdb_elem_desc_t *thisElem; 612 shr_mdb_elem_bank_index_t bank; 613 shr_mdb_elem_bank_index_t list; 614 615 LOG_DEBUG(BSL_LS_SOC_COMMON, 616 (BSL_META("(%08X,%08X)\n"), 617 PTR_TO_INT(res), 618 head)); 619 620 /* resolve some things about the block's head element */ 621 bank = _MDB_BANK_FROM_ELEM(*res, head); 622 thisElem = &(res->elem[head]); 623 list = thisElem->list; 624 listBank = &_MDB_LIST_BANK_DESC(*res, list, bank); 625 /* set the block as not being on a list */ 626 thisElem->list = _MDB_BLOCK_NOT_IN_LIST; 627 /* account for this block on this list (bank and total) */ 628 listBank->elems -= thisElem->count; 629 res->list[list].elems -= thisElem->count; 630 listBank->blocks--; 631 res->list[list].blocks--; 632 /* unlink this block from this bank of this list */ 633 if (_MDB_BLOCK_INVALID > thisElem->next) { 634 /* not the last block in this bank of the list */ 635 _MDB_ELEM_BANK_DESC(*res, bank, thisElem->next).prev = thisElem->prev; 636 } else { 637 /* the last block in this bank of the list */ 638 listBank->tail = thisElem->prev; 639 } 640 if (_MDB_BLOCK_INVALID > thisElem->prev) { 641 /* not the first block in this bank of the list */ 642 _MDB_ELEM_BANK_DESC(*res, bank, thisElem->prev).next = thisElem->next; 643 } else { 644 /* the first block in this bank of the list */ 645 listBank->head = thisElem->next; 646 } 647 thisElem->prev = _MDB_BLOCK_END; 648 thisElem->next = _MDB_BLOCK_END; 649 /* unlink this bank from the list if appropriate */ 650 if (!listBank->blocks) { 651 /* this bank contains no more blocks; unlink it */ 652 if (_MDB_BLOCK_INVALID > listBank->next) { 653 /* not the last bank in this list */ 654 _MDB_LIST_BANK_DESC(*res, list, listBank->next).prev = listBank->prev; 655 } else { 656 /* the last bank in this list */ 657 res->list[list].tail = listBank->prev; 658 } 659 if (_MDB_BLOCK_INVALID > listBank->prev) { 660 /* not the first bank in this list */ 661 _MDB_LIST_BANK_DESC(*res, list, listBank->prev).next = listBank->next; 662 } else { 663 /* the first bank in this list */ 664 res->list[list].head = listBank->next; 665 } 666 listBank->prev = _MDB_BANK_END; 667 listBank->next = _MDB_BANK_END; 668 } 669 } 670 671 /* 672 * Function 673 * _mdb_block_frag_and_free 674 * Purpose 675 * Fragment a block into the largest possible fragments (up to the size of 676 * the block as provided) and place those subblocks on their respective free 677 * lists. The block must not be a member of any list (but the subblocks 678 * will all be members of the proper free lists afterward). 679 * Arguments 680 * (in) shr_mdb_list_handle_t list = pointer to the list info (modified) 681 * (in) shr_mdb_elem_index_t head = head element of block to free 682 * Return 683 * void 684 * Notes 685 * Assumes all arguments are valid. 686 */ 687 static void 688 _mdb_block_frag_and_free(shr_mdb_list_handle_t res, 689 shr_mdb_elem_index_t head) 690 { 691 shr_mdb_elem_bank_index_t freeList = res->freeLists - 1; 692 shr_mdb_elem_bank_index_t count = res->elem[head].count; 693 shr_mdb_elem_bank_index_t elemsBlock = res->list[freeList].elemsBlock; 694 shr_mdb_elem_index_t newFree; 695 shr_mdb_elem_index_t oldHead = head; 696 shr_mdb_elem_index_t newHead; 697 698 LOG_DEBUG(BSL_LS_SOC_COMMON, 699 (BSL_META("(%08X,%08X)\n"), 700 PTR_TO_INT(res), 701 head)); 702 703 /* split the block into largest possible free subblocks */ 704 while (count) { 705 /* while we have elements to free */ 706 LOG_DEBUG(BSL_LS_SOC_COMMON, 707 (BSL_META("mdb %08X: block at %08X has %d elements;" 708 " freelist = %d\n"), 709 PTR_TO_INT(res), 710 oldHead, 711 count, 712 freeList)); 713 if (count > elemsBlock) { 714 /* block size > list block size; fragment it */ 715 _mdb_block_split_size(res, 716 oldHead, 717 elemsBlock, 718 res->allocPref & shr_mdb_free_block_high, 719 &newFree, 720 &newHead); 721 /* insert the proper fragment to this free list */ 722 _mdb_list_insert(res, newFree, freeList); 723 /* compute size of remaining fragment */ 724 count -= elemsBlock; 725 /* adjust to use remaining fragment next iteration */ 726 oldHead = newHead; 727 } else if (count == elemsBlock) { 728 /* block size == list block size; finish up here */ 729 _mdb_list_insert(res, oldHead, freeList); 730 count = 0; 731 } else { 732 /* block size < list block size; move to next list down */ 733 freeList--; 734 elemsBlock = res->list[freeList].elemsBlock; 735 } 736 } /* while ((count) && (_SHR_E_NONE == result)) */ 737 } 738 739 /* 740 * Function 741 * _mdb_block_defrag 742 * Purpose 743 * Join a block with adjacent blocks that are on free lists to form the 744 * largest possible contiguous free block within the bank. 745 * Arguments 746 * (in) shr_mdb_list_handle_t list = pointer to the list info (modified) 747 * (in/out) shr_mdb_elem_index_t *head = (in) ptr to head elem of orig blk 748 * (out) updated to block's head elem 749 * (in) shr_mdb_alloc_pref_t override = override join preferences 750 * Return 751 * void 752 * Notes 753 * Assumes all arguments are valid. 754 * The value at head is updated to reflect the actual head element of the 755 * final coalesced block. 756 * Will not expand the block in such a way as to cause it to cross banks. 757 * There is an override to force defrag to apply; this is because there are 758 * some places where it is assumed that defrag works in a certain way. 759 */ 760 static void 761 _mdb_block_defrag(shr_mdb_list_handle_t res, 762 shr_mdb_elem_index_t *head, 763 shr_mdb_alloc_pref_t override) 764 { 765 shr_mdb_elem_index_t nextBlock; 766 shr_mdb_elem_bank_index_t count; 767 shr_mdb_elem_bank_index_t offs; 768 shr_mdb_alloc_pref_t pref = res->allocPref | override; 769 770 LOG_DEBUG(BSL_LS_SOC_COMMON, 771 (BSL_META("(%08X,&(%08X)) enter\n"), 772 PTR_TO_INT(res), 773 *head)); 774 775 offs = _MDB_OFFS_FROM_ELEM(*res, *head); 776 if (pref & shr_mdb_join_low) { 777 /* try to collect free blocks into one by going downward in bank */ 778 while (offs) { 779 count = res->elem[(*head) - 1].count; 780 nextBlock = (*head) - count; 781 if (res->elem[nextBlock].list >= res->freeLists) { 782 /* the next block isn't on a free list; finsihed going down */ 783 break; 784 } 785 LOG_DEBUG(BSL_LS_SOC_COMMON, 786 (BSL_META("join downward to %08X (%d elements)\n"), 787 nextBlock, 788 count)); 789 offs -= count; 790 /* get the block from its free list */ 791 _mdb_list_remove(res, nextBlock); 792 /* join the block to the existing block */ 793 _mdb_block_join(res, nextBlock, *head); 794 /* update start of new bigger block */ 795 *head = nextBlock; 796 } /* while (offs) */ 797 } /* if (res->allocPref & _mdb_join_low) */ 798 if ((pref & shr_mdb_join_high) || 799 (!(pref & (shr_mdb_join_low | shr_mdb_join_high)))) { 800 /* try to collect free blocks into one by going upward in bank */ 801 count = res->elem[*head].count; 802 LOG_DEBUG(BSL_LS_SOC_COMMON, 803 (BSL_META("current %08X count %d next %08X mask %08X\n"), 804 *head, 805 count, 806 *head + count, 807 res->bankMask)); 808 while (((offs + count) <= (~(res->bankMask))) && 809 ((*head + count) < res->count)) { 810 nextBlock = *head + count; 811 if (res->elem[nextBlock].list >= res->freeLists) { 812 /* the next block isn't on a free list; finished going up */ 813 break; 814 } 815 LOG_DEBUG(BSL_LS_SOC_COMMON, 816 (BSL_META("join upward to %08X (%d elements)\n"), 817 nextBlock, 818 res->elem[nextBlock].count)); 819 /* get the block from its free list */ 820 _mdb_list_remove(res, nextBlock); 821 /* join the block to the existing block */ 822 _mdb_block_join(res, *head, nextBlock); 823 /* update number of elements in the block */ 824 count = res->elem[*head].count; 825 } /* while ((offs + count) <= res->bankMask) */ 826 } /* if (alloc_join_high mode or neither that nor alloc_join_low mode) */ 827 828 LOG_DEBUG(BSL_LS_SOC_COMMON, 829 (BSL_META("(%08X,&(%08X)) leave\n"), 830 PTR_TO_INT(res), 831 *head)); 832 } 833 834 /* 835 * Function 836 * _mdb_block_head_get 837 * Purpose 838 * Given an arbitrary element in a block, find the element that is the head 839 * of that block. 840 * Arguments 841 * (in) shr_mdb_list_handle_t list = pointer to the list info (modified) 842 * (in/out) shr_mdb_elem_index_t *head = (in) ptr to some elem of a block 843 * (out) updated to block's head elem 844 * Return 845 * void 846 * Notes 847 * Assumes all arguments are valid. 848 * The value at head is updated to reflect the actual head element. 849 */ 850 static void 851 _mdb_block_head_get(shr_mdb_list_handle_t res, 852 shr_mdb_elem_index_t *head) 853 { 854 shr_mdb_elem_index_t currBlock; 855 856 LOG_DEBUG(BSL_LS_SOC_COMMON, 857 (BSL_META("(%08X,&(%08X)) enter\n"), 858 PTR_TO_INT(res), 859 *head)); 860 861 if (_MDB_BLOCK_NOT_HEAD != res->elem[*head].list) { 862 /* element is the head, so just return now */ 863 LOG_DEBUG(BSL_LS_SOC_COMMON, 864 (BSL_META("(%08X,&(%08X)) early leave (head, %d)\n"), 865 PTR_TO_INT(res), 866 *head, 867 res->elem[*head].count)); 868 return; 869 } 870 if (0 != res->elem[*head].count) { 871 /* element isn't head, but count is nonzero, so must be tail */ 872 *head -= (res->elem[*head].count - 1); 873 LOG_DEBUG(BSL_LS_SOC_COMMON, 874 (BSL_META("(%08X,&(%08X)) early leave (tail, %d)\n"), 875 PTR_TO_INT(res), 876 *head, 877 res->elem[*head].count)); 878 return; 879 } 880 /* 881 * Instead of starting with the current element and searching backwards 882 * until we reach the block's head, we'll just look for a block that 883 * contains the specified element, and return its head, starting at the 884 * beginning of the bank containing the element. 885 * 886 * The hope here is that the typical block is many elements. 887 */ 888 for (currBlock = ((*head) & (res->bankMask)); 889 ((currBlock < res->count) && 890 ((currBlock + res->elem[currBlock].count) < res->count) && 891 (currBlock < (*head)) && 892 ((currBlock + res->elem[currBlock].count) < (*head))); 893 currBlock += res->elem[currBlock].count) { 894 /* just search; don't do anything */ 895 LOG_DEBUG(BSL_LS_SOC_COMMON, 896 (BSL_META("mdb %08X: block at %08X length %d\n"), 897 PTR_TO_INT(res), 898 currBlock, 899 res->elem[currBlock].count)); 900 } 901 *head = currBlock; 902 903 LOG_DEBUG(BSL_LS_SOC_COMMON, 904 (BSL_META("(%08X,&(%08X)) leave\n"), 905 PTR_TO_INT(res), 906 *head)); 907 } 908 909 910 /***************************************************************************** 911 * 912 * Support 913 * 914 * A lot of functions that are used when implementing the API calls. These 915 * functions verify input arguments, and use the implementation calls to 916 * actually do most of the work. 917 * 918 * These calls may do early returns, but will avoid leaks and partial update 919 * conditions that could cause problems. 920 * 921 * Block base is as exposed to the caller for these functions, but may be used 922 * as internally. 923 */ 924 925 /* 926 * Function 927 * _shr_mdb_block_alloc 928 * Purpose 929 * Allocate a contiguous block of the specified number of elements. 930 * Arguments 931 * (in) shr_mdb_list_handle_t res = pointer to the list info (modified) 932 * (out) shr_mdb_elem_index_t *head = where to put the head of the block 933 * (in) shr_mdb_elem_bank_index_t count = number of elements in block 934 * Return 935 * bcm_error_t cast as int 936 * _SHR_E_NONE if successful 937 * _SHR_E_* otherwise as appropriate 938 * Notes 939 */ 940 static int 941 _shr_mdb_block_alloc(shr_mdb_list_handle_t res, 942 shr_mdb_elem_index_t *head, 943 shr_mdb_elem_bank_index_t count) 944 { 945 shr_mdb_list_bank_desc_t *listBank = NULL; 946 shr_mdb_elem_bank_index_t baseList; 947 shr_mdb_elem_bank_index_t list; 948 shr_mdb_elem_bank_index_t offs; 949 shr_mdb_elem_index_t bank; 950 shr_mdb_elem_index_t block = ~0; 951 shr_mdb_elem_index_t extra = ~0; 952 int result = _SHR_E_RESOURCE; 953 954 LOG_DEBUG(BSL_LS_SOC_COMMON, 955 (BSL_META("(%08X,*,%d) enter\n"), 956 PTR_TO_INT(res), 957 count)); 958 959 /* make sure we can actually alloc the requested block */ 960 if (count > res->list[res->freeLists - 1].elemsBlock) { 961 /* the request is larger than the largest supported block */ 962 LOG_ERROR(BSL_LS_SOC_COMMON, 963 (BSL_META("mdb %08X: count %d exceeds largest block %d\n"), 964 PTR_TO_INT(res), 965 count, 966 res->list[res->freeLists - 1].elemsBlock)); 967 return _SHR_E_PARAM; 968 } 969 /* find the free list with the smallest acceptable blocks */ 970 for (baseList = 0; 971 (baseList < res->freeLists) && 972 (res->list[baseList].elemsBlock < count); 973 baseList++) { 974 /* don't do anything but iterate for the desired list */ 975 } 976 LOG_DEBUG(BSL_LS_SOC_COMMON, 977 (BSL_META("mdb %08X: looking for free block >= %d elements\n"), 978 PTR_TO_INT(res), 979 res->list[baseList].elemsBlock)); 980 /* allocate an initial block */ 981 switch (res->allocPref & shr_mdb_alloc_bank_mask) { 982 case shr_mdb_alloc_bank_first: 983 /* using first method; get the first block that's big enough */ 984 LOG_DEBUG(BSL_LS_SOC_COMMON, 985 (BSL_META("mdb %08X: using '%s' alloc mode\n"), 986 PTR_TO_INT(res), 987 "first")); 988 /* this method effectively searches all banks at the same time */ 989 /* find a list with some available blocks */ 990 for (list = baseList; 991 list < res->freeLists; 992 list++) { 993 if (res->list[list].blocks) { 994 /* this list has some blocks */ 995 result = _SHR_E_NONE; 996 break; 997 } 998 } 999 if (_SHR_E_NONE == result) { 1000 /* found a list with some large enough blocks; get first block */ 1001 bank = res->list[list].head; 1002 offs = _MDB_LIST_BANK_DESC(*res, list, bank).head; 1003 block = (bank << res->bankShift) | offs; 1004 /* take the block out of its list */ 1005 _mdb_list_remove(res, block); 1006 } 1007 break; 1008 case shr_mdb_alloc_bank_low: 1009 /* using low method; search banks low to high */ 1010 LOG_DEBUG(BSL_LS_SOC_COMMON, 1011 (BSL_META("mdb %08X: using '%s' alloc mode\n"), 1012 PTR_TO_INT(res), 1013 "low")); 1014 for (bank = 0; 1015 bank < res->banks; 1016 bank++) { 1017 /* check for any list with acceptable blocks in this bank */ 1018 for (list = baseList; 1019 list < res->freeLists; 1020 list++) { 1021 listBank = &_MDB_LIST_BANK_DESC(*res, list, bank); 1022 if (listBank->blocks) { 1023 /* this list has some blocks */ 1024 result = _SHR_E_NONE; 1025 break; 1026 } 1027 } 1028 if (_SHR_E_NONE == result) { 1029 /* we found a bank and list with an acceptable block */ 1030 offs = listBank->head; 1031 block = (bank << res->bankShift) | offs; 1032 /* take the block out of its list */ 1033 _mdb_list_remove(res, block); 1034 break; 1035 } 1036 } 1037 break; 1038 case shr_mdb_alloc_bank_high: 1039 /* using high method; search banks high to low */ 1040 LOG_DEBUG(BSL_LS_SOC_COMMON, 1041 (BSL_META("mdb %08X: using '%s' alloc mode\n"), 1042 PTR_TO_INT(res), 1043 "high")); 1044 bank = res->banks; 1045 do { 1046 bank--; 1047 /* check for any list with acceptable blocks in this bank */ 1048 for (list = baseList; 1049 list < res->freeLists; 1050 list++) { 1051 listBank = &_MDB_LIST_BANK_DESC(*res, list, bank); 1052 if (listBank->blocks) { 1053 /* this list has some blocks */ 1054 result = _SHR_E_NONE; 1055 break; 1056 } 1057 } 1058 if (_SHR_E_NONE == result) { 1059 /* we found a bank and list with an acceptable block */ 1060 offs = listBank->head; 1061 block = (bank << res->bankShift) | offs; 1062 /* take the block out of its list */ 1063 _mdb_list_remove(res, block); 1064 break; 1065 } 1066 } while (bank > 0); 1067 break; 1068 default: 1069 /* should never see this; it's not valid */ 1070 LOG_ERROR(BSL_LS_SOC_COMMON, 1071 (BSL_META("mdb %08X: unknown alloc mode: %d\n"), 1072 PTR_TO_INT(res), 1073 res->allocPref & shr_mdb_alloc_bank_mask)); 1074 result = _SHR_E_INTERNAL; 1075 } 1076 if (_SHR_E_NONE == result) { 1077 /* was able to find an acceptable block somewhere */ 1078 LOG_DEBUG(BSL_LS_SOC_COMMON, 1079 (BSL_META("mdb %08X: found suitable block at %08X (%d elements)\n"), 1080 PTR_TO_INT(res), 1081 block + res->low, 1082 res->elem[block].count)); 1083 if (res->allocPref & shr_mdb_join_alloc) { 1084 /* need to join adjacent free blocks on alloc */ 1085 _mdb_block_defrag(res, &block, 0); 1086 } 1087 if (res->elem[block].count > count) { 1088 /* need to break the user request off this block & free the rest */ 1089 _mdb_block_split_size(res, 1090 block, 1091 count, 1092 res->allocPref & shr_mdb_alloc_block_high, 1093 &block, 1094 &extra); 1095 /* dispose of the 'extra' part */ 1096 _mdb_block_frag_and_free(res, extra); 1097 } 1098 *head = block + res->low; 1099 } 1100 1101 LOG_DEBUG(BSL_LS_SOC_COMMON, 1102 (BSL_META("(%08X,%d,&(%08X)) return %d (%s)\n"), 1103 PTR_TO_INT(res), 1104 count, 1105 *head, 1106 result, 1107 _SHR_ERRMSG(result))); 1108 return result; 1109 } 1110 1111 /* 1112 * Function 1113 * _shr_mdb_block_free 1114 * Purpose 1115 * Free a block of elements that is not in a list. 1116 * Arguments 1117 * (in) shr_mdb_list_handle_t res = pointer to the list info (modified) 1118 * (in) shr_mdb_elem_index_t head = the head element of the block to free 1119 * Return 1120 * bcm_error_t cast as int 1121 * _SHR_E_NONE if successful 1122 * _SHR_E_* otherwise as appropriate 1123 * Notes 1124 */ 1125 static int 1126 _shr_mdb_block_free(shr_mdb_list_handle_t res, 1127 shr_mdb_elem_index_t head) 1128 { 1129 shr_mdb_elem_index_t block; 1130 1131 LOG_DEBUG(BSL_LS_SOC_COMMON, 1132 (BSL_META("(%08X,%08X)\n"), 1133 PTR_TO_INT(res), 1134 head)); 1135 1136 /* make sure the arguments are acceptable */ 1137 block = head - res->low; 1138 if ((head < res->low) || (block >= res->count)) { 1139 LOG_ERROR(BSL_LS_SOC_COMMON, 1140 (BSL_META("mdb %08X: invalid block at %08X can not be freed\n"), 1141 PTR_TO_INT(res), 1142 head)); 1143 /* don't ask me why, but BCM likes NOT_FOUND for INVALID_ID */ 1144 return _SHR_E_NOT_FOUND; 1145 } 1146 if (res->elem[block].list < res->freeLists) { 1147 /* this block is already free */ 1148 LOG_ERROR(BSL_LS_SOC_COMMON, 1149 (BSL_META("mdb %08X: block at %08X is already free\n"), 1150 PTR_TO_INT(res), 1151 head)); 1152 return _SHR_E_NOT_FOUND; 1153 } 1154 if (_MDB_BLOCK_NOT_IN_LIST != res->elem[block].list) { 1155 /* this block is in a user list */ 1156 LOG_ERROR(BSL_LS_SOC_COMMON, 1157 (BSL_META("mdb %08X: block at %08X is in a list\n"), 1158 PTR_TO_INT(res), 1159 head)); 1160 return _SHR_E_BUSY; 1161 } 1162 if ((res->allocPref & shr_mdb_join_free) || 1163 (!(res->allocPref & (shr_mdb_join_alloc | shr_mdb_join_free)))) { 1164 /* need to join adjacent free blocks on free */ 1165 _mdb_block_defrag(res, &block, 0); 1166 } 1167 /* free the block */ 1168 _mdb_block_frag_and_free(res, block); 1169 1170 LOG_DEBUG(BSL_LS_SOC_COMMON, 1171 (BSL_META("(%08X,%08X) return %d (%s)\n"), 1172 PTR_TO_INT(res), 1173 head, 1174 _SHR_E_NONE, 1175 _SHR_ERRMSG(_SHR_E_NONE))); 1176 return _SHR_E_NONE; 1177 } 1178 1179 /* 1180 * Function 1181 * _mdb_block_size_get 1182 * Purpose 1183 * Get number of elements in a block 1184 * Arguments 1185 * (in) shr_mdb_list_handle_t res = pointer to the list information 1186 * (in) shr_mdb_elem_index_t block = head element of block 1187 * (out) shr_mdb_elem_bank_index_t *count = where to put the count 1188 * Return 1189 * bcm_error_t cast as int 1190 * _SHR_E_NONE if successful 1191 * _SHR_E_* otherwise as appropriate 1192 * Notes 1193 */ 1194 static int 1195 _mdb_block_size_get(shr_mdb_list_handle_t res, 1196 shr_mdb_elem_index_t head, 1197 shr_mdb_elem_bank_index_t *count) 1198 { 1199 shr_mdb_elem_index_t block; 1200 1201 LOG_DEBUG(BSL_LS_SOC_COMMON, 1202 (BSL_META("(%08X,%08X,*) enter\n"), 1203 PTR_TO_INT(res), 1204 head)); 1205 1206 /* bias the block to internal value */ 1207 block = head - res->low; 1208 /* make sure the block is valid */ 1209 if ((head < res->low) || (block >= res->count)) { 1210 LOG_ERROR(BSL_LS_SOC_COMMON, 1211 (BSL_META("mdb %08X: element %08X is not valid\n"), 1212 PTR_TO_INT(res), 1213 head)); 1214 /* don't ask me why, but BCM likes NOT_FOUND for INVALID_ID */ 1215 return _SHR_E_NOT_FOUND; 1216 } 1217 /* make sure we have the block's head */ 1218 _mdb_block_head_get(res, &block); 1219 /* make sure the block is not free */ 1220 if (res->freeLists > res->elem[block].list) { 1221 LOG_ERROR(BSL_LS_SOC_COMMON, 1222 (BSL_META("mdb %08X: block at %08X..%08X is free\n"), 1223 PTR_TO_INT(res), 1224 block + res->low, 1225 block + res->elem[block].count + res->low - 1)); 1226 return _SHR_E_NOT_FOUND; 1227 } 1228 /* okay, return the count on which the block belongs, biased */ 1229 *count = res->elem[block].count; 1230 1231 LOG_DEBUG(BSL_LS_SOC_COMMON, 1232 (BSL_META("(%08X,%08X,&(%d)) return %d (%s)\n"), 1233 PTR_TO_INT(res), 1234 head, 1235 *count, 1236 _SHR_E_NONE, 1237 _SHR_ERRMSG(_SHR_E_NONE))); 1238 return _SHR_E_NONE; 1239 } 1240 1241 /* 1242 * Function 1243 * _shr_mdb_elems_reserve 1244 * Purpose 1245 * Reserve specific elements. These elements will be allocated as single 1246 * element, and can be freed one at a time by using the free call above. 1247 * The specified elements can span banks. Will ensure all of the requested 1248 * elements are free before reserving any of them. 1249 * Arguments 1250 * (in) shr_mdb_list_handle_t res = pointer to the list info (modified) 1251 * (in) shr_mdb_elem_index_t head = the lowest element to reserve 1252 * (in) shr_mdb_elem_index_t count = the number of elements to reserve 1253 * Return 1254 * bcm_error_t cast as int 1255 * _SHR_E_NONE if successful 1256 * _SHR_E_* otherwise as appropriate 1257 * Notes 1258 */ 1259 static int 1260 _shr_mdb_elems_reserve(shr_mdb_list_handle_t res, 1261 shr_mdb_elem_index_t head, 1262 shr_mdb_elem_index_t count) 1263 { 1264 shr_mdb_elem_index_t currElem; 1265 shr_mdb_elem_index_t currCount = count; 1266 shr_mdb_elem_index_t baseElem; 1267 shr_mdb_elem_index_t tempElem; 1268 shr_mdb_elem_index_t block; 1269 shr_mdb_elem_desc_t elem; 1270 1271 LOG_DEBUG(BSL_LS_SOC_COMMON, 1272 (BSL_META("(%08X,%08X,%d) enter\n"), 1273 PTR_TO_INT(res), 1274 head, 1275 count)); 1276 1277 /* make sure the arguments are acceptable */ 1278 block = head - res->low; 1279 if ((head < res->low) || 1280 ((head + count - res->low) > res->count)) { 1281 /* head or count places part or all of the block outside range */ 1282 LOG_ERROR(BSL_LS_SOC_COMMON, 1283 (BSL_META("mdb %08X: can not reserve %d elements at %08X since" 1284 " the range contains invalid elements\n"), 1285 PTR_TO_INT(res), 1286 count, 1287 head)); 1288 /* don't ask me why, but BCM likes NOT_FOUND for INVALID_ID */ 1289 return _SHR_E_NOT_FOUND; 1290 } 1291 if (!count) { 1292 /* do nothing? */ 1293 LOG_ERROR(BSL_LS_SOC_COMMON, 1294 (BSL_META("mdb %08X: can not reserve zero element range\n"), 1295 PTR_TO_INT(res))); 1296 return _SHR_E_PARAM; 1297 } 1298 /* find the head of the first block in the range */ 1299 currElem = block; 1300 _mdb_block_head_get(res, &currElem); 1301 baseElem = currElem; 1302 /* make sure each block touched by the range is free */ 1303 while (currElem < block + count) { 1304 if (res->elem[currElem].list >= res->freeLists) { 1305 /* this block is not free */ 1306 LOG_ERROR(BSL_LS_SOC_COMMON, 1307 (BSL_META("mdb %08X: can't reserve in-use block" 1308 " at %08X\n"), 1309 PTR_TO_INT(res), 1310 currElem)); 1311 return _SHR_E_RESOURCE; 1312 } 1313 currElem += res->elem[currElem].count; 1314 } /* while (currElem < head + count) */ 1315 /* set up a singly-allocated not-in-list element description */ 1316 elem.list = _MDB_BLOCK_NOT_IN_LIST; 1317 elem.count = 1; 1318 elem.next = _MDB_BLOCK_END; 1319 elem.prev = _MDB_BLOCK_END; 1320 /* start with the first block touched */ 1321 currElem = baseElem; 1322 /* singly-allocate all participating elements */ 1323 while (currElem < (block + count)) { 1324 /* keep this block's size */ 1325 currCount = res->elem[currElem].count; 1326 /* remove this block from its free list */ 1327 _mdb_list_remove(res, currElem); 1328 if (block > currElem) { 1329 LOG_DEBUG(BSL_LS_SOC_COMMON, 1330 (BSL_META("mdb %08X: break off low elements" 1331 " %08X..%08X\n"), 1332 PTR_TO_INT(res), 1333 currElem + res->low, 1334 head - 1)); 1335 /* break off unwanted low elements */ 1336 _mdb_block_split_point(res, currElem, block); 1337 /* adjust the current block size accordingly */ 1338 currCount = res->elem[block].count; 1339 /* join unwanted low elements with neighbours */ 1340 _mdb_block_defrag(res, &currElem, 0); 1341 /* return unwanted low elements to the free pool */ 1342 _mdb_block_frag_and_free(res, currElem); 1343 /* now point to the elements we kept */ 1344 currElem = block; 1345 } 1346 if ((currElem + currCount) > (block + count)) { 1347 LOG_DEBUG(BSL_LS_SOC_COMMON, 1348 (BSL_META("mdb %08X: break off high elements" 1349 " %08X..%08X\n"), 1350 PTR_TO_INT(res), 1351 head + count, 1352 currElem + currCount - 1 + res->low)); 1353 /* break off unwanted high elements */ 1354 tempElem = block + count; 1355 _mdb_block_split_point(res, currElem, tempElem); 1356 /* adjust the current block size accordingly */ 1357 currCount = res->elem[currElem].count; 1358 /* join unwanted high elements with neighbours */ 1359 _mdb_block_defrag(res, &tempElem, 0); 1360 /* return unwanted high elements to the free pool */ 1361 _mdb_block_frag_and_free(res, tempElem); 1362 } 1363 while (currCount > 0) { 1364 /* set this element as being allocated singly */ 1365 res->elem[currElem] = elem; 1366 currCount--; 1367 currElem++; 1368 } 1369 } /* while (currElem < head + count) */ 1370 1371 LOG_DEBUG(BSL_LS_SOC_COMMON, 1372 (BSL_META("(%08X,%08X,%d) return %d (%s)\n"), 1373 PTR_TO_INT(res), 1374 head, 1375 count, 1376 _SHR_E_NONE, 1377 _SHR_ERRMSG(_SHR_E_NONE))); 1378 return _SHR_E_NONE; 1379 } 1380 1381 /* 1382 * Function 1383 * _shr_mdb_elems_collect 1384 * Purpose 1385 * Collect a set of single-element blocks into a large single block. 1386 * Arguments 1387 * (in) shr_mdb_list_handle_t res = pointer to the list info (modified) 1388 * (in) shr_mdb_elem_index_t head = the lowest element to reserve 1389 * (in) shr_mdb_elem_bank_index_t count = the number of elements to reserve 1390 * Return 1391 * bcm_error_t cast as int 1392 * _SHR_E_NONE if successful 1393 * _SHR_E_* otherwise as appropriate 1394 * Notes 1395 */ 1396 static int 1397 _shr_mdb_elems_collect(shr_mdb_list_handle_t res, 1398 shr_mdb_elem_index_t head, 1399 shr_mdb_elem_bank_index_t count) 1400 { 1401 shr_mdb_elem_index_t currElem; 1402 shr_mdb_elem_index_t block; 1403 1404 LOG_DEBUG(BSL_LS_SOC_COMMON, 1405 (BSL_META("(%08X,%08X,%d) enter\n"), 1406 PTR_TO_INT(res), 1407 head, 1408 count)); 1409 1410 /* make sure the arguments are acceptable */ 1411 block = head - res->low; 1412 if ((head < res->low) || ((head + count - res->low) > res->count)) { 1413 /* head or count places part or all of the block outside range */ 1414 LOG_ERROR(BSL_LS_SOC_COMMON, 1415 (BSL_META("mdb %08X: can not collect %d elements at %08X since" 1416 " the range contains invalid elements\n"), 1417 PTR_TO_INT(res), 1418 count, 1419 head)); 1420 /* don't ask me why, but BCM likes NOT_FOUND for INVALID_ID */ 1421 return _SHR_E_NOT_FOUND; 1422 } 1423 if (!count) { 1424 /* do nothing? */ 1425 LOG_ERROR(BSL_LS_SOC_COMMON, 1426 (BSL_META("mdb %08X: can not reserve zero element range\n"), 1427 PTR_TO_INT(res))); 1428 return _SHR_E_PARAM; 1429 } 1430 /* make sure all elements are in the same bank */ 1431 if ((_MDB_OFFS_FROM_ELEM(*res, block) + count) > ((~(res->bankMask)) + 1)) { 1432 LOG_ERROR(BSL_LS_SOC_COMMON, 1433 (BSL_META("mdb %08X: %d element block at %08X" 1434 " would span banks\n"), 1435 PTR_TO_INT(res), 1436 count, 1437 head)); 1438 /* don't ask me why, but BCM likes NOT_FOUND for INVALID_ID */ 1439 return _SHR_E_PARAM; 1440 } 1441 /* make sure each element is free and is a single-element block */ 1442 for (currElem = block; 1443 currElem < block + count; 1444 currElem++) { 1445 if (res->elem[currElem].list == _MDB_BLOCK_NOT_HEAD) { 1446 /* non-head elements do not exist in one-element blocks */ 1447 LOG_ERROR(BSL_LS_SOC_COMMON, 1448 (BSL_META("mdb %08X: can't collect non-single-element" 1449 " block at %08X\n"), 1450 PTR_TO_INT(res), 1451 currElem + res->low)); 1452 return _SHR_E_PARAM; 1453 } 1454 if (res->elem[currElem].list < res->freeLists) { 1455 /* this block is already free */ 1456 LOG_ERROR(BSL_LS_SOC_COMMON, 1457 (BSL_META("mdb %08X: can't collect free" 1458 " block at %08X\n"), 1459 PTR_TO_INT(res), 1460 currElem + res->low)); 1461 return _SHR_E_NOT_FOUND; 1462 } 1463 if (res->elem[currElem].list != _MDB_BLOCK_NOT_IN_LIST) { 1464 /* the block is in a list */ 1465 LOG_ERROR(BSL_LS_SOC_COMMON, 1466 (BSL_META("mdb %08X: can't collect block at %08X since" 1467 " it is in a list\n"), 1468 PTR_TO_INT(res), 1469 currElem + res->low)); 1470 return _SHR_E_BUSY; 1471 } 1472 if (res->elem[currElem].count != 1) { 1473 /* the block size is not one */ 1474 LOG_ERROR(BSL_LS_SOC_COMMON, 1475 (BSL_META("mdb %08X: can't collect %d-element" 1476 " block at %08X\n"), 1477 PTR_TO_INT(res), 1478 res->elem[currElem].count, 1479 currElem + res->low)); 1480 return _SHR_E_PARAM; 1481 } 1482 } 1483 /* prepare the newly gathered block */ 1484 _mdb_block_prep(res, block, count); 1485 1486 LOG_DEBUG(BSL_LS_SOC_COMMON, 1487 (BSL_META("(%08X,%08X,%d) return %d (%s)\n"), 1488 PTR_TO_INT(res), 1489 head, 1490 count, 1491 _SHR_E_NONE, 1492 _SHR_ERRMSG(_SHR_E_NONE))); 1493 return _SHR_E_NONE; 1494 } 1495 1496 /* 1497 * Function 1498 * _shr_mdb_elems_unreserve 1499 * Purpose 1500 * Unreserve specific elements. These elements will be gathered into blocks 1501 * and then freed. Can be used on any group of contiguous single-element 1502 * blocks, but will not work against larger blocks (use free instead). This 1503 * was meant specifically as a faster way to undo a reserve call, though 1504 * free could be called instead against every element in the reserved set. 1505 * Makes sure the element set looks as expected before freeing any elements. 1506 * Arguments 1507 * (in) shr_mdb_list_handle_t res = pointer to the list info (modified) 1508 * (in) shr_mdb_elem_index_t head = the lowest element to reserve 1509 * (in) shr_mdb_elem_index_t count = the number of elements to reserve 1510 * Return 1511 * bcm_error_t cast as int 1512 * _SHR_E_NONE if successful 1513 * _SHR_E_* otherwise as appropriate 1514 * Notes 1515 */ 1516 static int 1517 _shr_mdb_elems_unreserve(shr_mdb_list_handle_t res, 1518 shr_mdb_elem_index_t head, 1519 shr_mdb_elem_index_t count) 1520 { 1521 shr_mdb_elem_index_t currElem; 1522 shr_mdb_elem_index_t currCount = count; 1523 shr_mdb_elem_index_t block; 1524 shr_mdb_elem_bank_index_t offs; 1525 1526 LOG_DEBUG(BSL_LS_SOC_COMMON, 1527 (BSL_META("(%08X,%08X,%d) enter\n"), 1528 PTR_TO_INT(res), 1529 head, 1530 count)); 1531 1532 /* make sure the arguments are acceptable */ 1533 block = head - res->low; 1534 if ((head < res->low) || ((head + count - res->low) > res->count)) { 1535 /* head or count places part or all of the block outside range */ 1536 LOG_ERROR(BSL_LS_SOC_COMMON, 1537 (BSL_META("mdb %08X: can not unreserve %d elements at" 1538 " %08X since the range contains invalid elements\n"), 1539 PTR_TO_INT(res), 1540 count, 1541 head)); 1542 /* don't ask me why, but BCM likes NOT_FOUND for INVALID_ID */ 1543 return _SHR_E_NOT_FOUND; 1544 } 1545 if (!count) { 1546 /* do nothing? */ 1547 LOG_ERROR(BSL_LS_SOC_COMMON, 1548 (BSL_META("mdb %08X: can not reserve zero element range\n"), 1549 PTR_TO_INT(res))); 1550 return _SHR_E_PARAM; 1551 } 1552 /* make sure each element is free and is a single-element block */ 1553 for (currElem = block; 1554 currElem < block + count; 1555 currElem++) { 1556 if (res->elem[currElem].list == _MDB_BLOCK_NOT_HEAD) { 1557 /* non-head elements do not exist in one-element blocks */ 1558 LOG_ERROR(BSL_LS_SOC_COMMON, 1559 (BSL_META("mdb %08X: can't unreserve non-single-element" 1560 " block at %08X\n"), 1561 PTR_TO_INT(res), 1562 currElem + res->low)); 1563 return _SHR_E_PARAM; 1564 } 1565 if (res->elem[currElem].list < res->freeLists) { 1566 /* this block is already free */ 1567 LOG_ERROR(BSL_LS_SOC_COMMON, 1568 (BSL_META("mdb %08X: can't unreserve free" 1569 " block at %08X\n"), 1570 PTR_TO_INT(res), 1571 currElem + res->low)); 1572 return _SHR_E_NOT_FOUND; 1573 } 1574 if (res->elem[currElem].list != _MDB_BLOCK_NOT_IN_LIST) { 1575 /* the block is in a list */ 1576 LOG_ERROR(BSL_LS_SOC_COMMON, 1577 (BSL_META("mdb %08X: can't unreserve block at %08X since" 1578 " it is in a list\n"), 1579 PTR_TO_INT(res), 1580 currElem + res->low)); 1581 return _SHR_E_BUSY; 1582 } 1583 if (res->elem[currElem].count != 1) { 1584 /* the block size is not one */ 1585 LOG_ERROR(BSL_LS_SOC_COMMON, 1586 (BSL_META("mdb %08X: can't unreserve %d-element" 1587 " block at %08X\n"), 1588 PTR_TO_INT(res), 1589 res->elem[currElem].count, 1590 currElem + res->low)); 1591 return _SHR_E_PARAM; 1592 } 1593 } 1594 /* gather the elements into largest blocks possible and free them */ 1595 while (count > 0) { 1596 currElem = block; 1597 offs = _MDB_OFFS_FROM_ELEM(*res, currElem); 1598 currCount = (res->bankMask + 1) - offs; 1599 if (currCount > count) { 1600 currCount = count; 1601 } 1602 /* prepare the newly gathered block */ 1603 _mdb_block_prep(res, currElem, currCount); 1604 /* defragment the block into neighbours */ 1605 if ((res->allocPref & shr_mdb_join_free) || 1606 (!(res->allocPref & (shr_mdb_join_alloc | shr_mdb_join_free)))) { 1607 /* need to join adjacent free blocks on free */ 1608 _mdb_block_defrag(res, &currElem, 0); 1609 } 1610 /* free the block */ 1611 _mdb_block_frag_and_free(res, currElem); 1612 /* go to the next bank */ 1613 block += currCount; 1614 count -= currCount; 1615 } 1616 1617 LOG_DEBUG(BSL_LS_SOC_COMMON, 1618 (BSL_META("(%08X,%08X,%d) return %d (%s)\n"), 1619 PTR_TO_INT(res), 1620 head, 1621 count, 1622 _SHR_E_NONE, 1623 _SHR_ERRMSG(_SHR_E_NONE))); 1624 return _SHR_E_NONE; 1625 } 1626 1627 /* 1628 * Function 1629 * _shr_mdb_block_alloc_id 1630 * Purpose 1631 * Allocate a block at a specific starting point. 1632 * Arguments 1633 * (in) shr_mdb_list_handle_t res = pointer to the list info (modified) 1634 * (in) shr_mdb_elem_index_t head = the lowest element to allocate 1635 * (in) shr_mdb_elem_bank_index_t count = the number of elements to allocate 1636 * Return 1637 * bcm_error_t cast as int 1638 * _SHR_E_NONE if successful 1639 * _SHR_E_* otherwise as appropriate 1640 * Notes 1641 */ 1642 static int 1643 _shr_mdb_block_alloc_id(shr_mdb_list_handle_t res, 1644 shr_mdb_elem_index_t head, 1645 shr_mdb_elem_bank_index_t count) 1646 { 1647 shr_mdb_elem_index_t currElem; 1648 shr_mdb_elem_index_t block; 1649 1650 LOG_DEBUG(BSL_LS_SOC_COMMON, 1651 (BSL_META("(%08X,%08X,%d) enter\n"), 1652 PTR_TO_INT(res), 1653 head, 1654 count)); 1655 1656 /* make sure the arguments are acceptable */ 1657 block = head - res->low; 1658 if ((head < res->low) || 1659 ((head + count - res->low) > res->count)) { 1660 /* head or count places part or all of the block outside range */ 1661 LOG_ERROR(BSL_LS_SOC_COMMON, 1662 (BSL_META("mdb %08X: can not alloc %d elements at %08X since" 1663 " the range contains invalid elements\n"), 1664 PTR_TO_INT(res), 1665 count, 1666 head)); 1667 /* don't ask me why, but BCM likes NOT_FOUND for INVALID_ID */ 1668 return _SHR_E_NOT_FOUND; 1669 } 1670 if (!count) { 1671 /* do nothing? */ 1672 LOG_ERROR(BSL_LS_SOC_COMMON, 1673 (BSL_META("mdb %08X: can not reserve zero element range\n"), 1674 PTR_TO_INT(res))); 1675 return _SHR_E_PARAM; 1676 } 1677 /* find the head of the first block in the range */ 1678 currElem = block; 1679 _mdb_block_head_get(res, &currElem); 1680 /* make sure it's free */ 1681 if (res->freeLists <= res->elem[currElem].list) { 1682 LOG_ERROR(BSL_LS_SOC_COMMON, 1683 (BSL_META("mdb %08X: can not allocate %d elements at %08X since" 1684 " the range does not begin within a free block\n"), 1685 PTR_TO_INT(res), 1686 count, 1687 head)); 1688 return _SHR_E_RESOURCE; 1689 } 1690 /* take it off its free list */ 1691 _mdb_list_remove(res, currElem); 1692 /* defragment around this block to get it as large as possible */ 1693 /* override to force defrag upward because that is assumed here */ 1694 _mdb_block_defrag(res, &currElem, shr_mdb_join_high); 1695 /* make sure the free block is big enough */ 1696 if ((currElem > block) || 1697 ((currElem + res->elem[currElem].count) < (block + count))) { 1698 /* the block starts too high or ends too low; put it back & give up */ 1699 _mdb_block_frag_and_free(res, currElem); 1700 LOG_ERROR(BSL_LS_SOC_COMMON, 1701 (BSL_META("mdb %08X: unable to alloc %d elements at %08X" 1702 " because at least some part of it was not free\n"), 1703 PTR_TO_INT(res), 1704 count, 1705 head)); 1706 return _SHR_E_RESOURCE; 1707 } 1708 /* trim off any unwanted space below the desired block */ 1709 if (block > currElem) { 1710 /* there are elements before the desired start; get rid of them */ 1711 _mdb_block_split_point(res, currElem, block); 1712 _mdb_block_frag_and_free(res, currElem); 1713 } 1714 /* trim off any unwanted space above the desired block */ 1715 if (res->elem[block].count > count) { 1716 /* there are elements after the desired end; get rid of them */ 1717 _mdb_block_split_point(res, block, block + count); 1718 _mdb_block_frag_and_free(res, block + count); 1719 } 1720 1721 LOG_DEBUG(BSL_LS_SOC_COMMON, 1722 (BSL_META("(%08X,%08X,%d) return %d (%s)\n"), 1723 PTR_TO_INT(res), 1724 head, 1725 count, 1726 _SHR_E_NONE, 1727 _SHR_ERRMSG(_SHR_E_NONE))); 1728 return _SHR_E_NONE; 1729 } 1730 1731 /* 1732 * Function 1733 * _mdb_user_list_insert 1734 * Purpose 1735 * Insert a block to a user list. 1736 * Arguments 1737 * (in) shr_mdb_list_handle_t res = pointer to the list information 1738 * (in) shr_mdb_elem_bank_index_t list = the list on which to insert 1739 * (in) shr_mdb_elem_index_t head = head element of block 1740 * Return 1741 * bcm_error_t cast as int 1742 * _SHR_E_NONE if successful 1743 * _SHR_E_* otherwise as appropriate 1744 * Notes 1745 */ 1746 static int 1747 _mdb_user_list_insert(shr_mdb_list_handle_t res, 1748 shr_mdb_elem_bank_index_t list, 1749 shr_mdb_elem_index_t head) 1750 { 1751 shr_mdb_elem_index_t block; 1752 1753 LOG_DEBUG(BSL_LS_SOC_COMMON, 1754 (BSL_META("(%08X,%d,%08X) enter\n"), 1755 PTR_TO_INT(res), 1756 list, 1757 head)); 1758 1759 /* bias the block to internal value */ 1760 block = head - res->low; 1761 /* make sure the block and list are valid */ 1762 if (list >= res->userLists) { 1763 LOG_ERROR(BSL_LS_SOC_COMMON, 1764 (BSL_META("mdb %08X: list %d is not valid\n"), 1765 PTR_TO_INT(res), 1766 list)); 1767 /* don't ask me why, but BCM likes NOT_FOUND for INVALID_ID */ 1768 return _SHR_E_NOT_FOUND; 1769 } 1770 if ((head < res->low) || (block >= res->count)) { 1771 LOG_ERROR(BSL_LS_SOC_COMMON, 1772 (BSL_META("mdb %08X: element %08X is not valid\n"), 1773 PTR_TO_INT(res), 1774 head)); 1775 /* don't ask me why, but BCM likes NOT_FOUND for INVALID_ID */ 1776 return _SHR_E_NOT_FOUND; 1777 } 1778 /* make sure we have the block's head */ 1779 _mdb_block_head_get(res, &block); 1780 /* make sure the block is not free */ 1781 if (res->freeLists > res->elem[block].list) { 1782 LOG_ERROR(BSL_LS_SOC_COMMON, 1783 (BSL_META("mdb %08X: block at %08X..%08X is free\n"), 1784 PTR_TO_INT(res), 1785 block + res->low, 1786 block + res->elem[block].count + res->low - 1)); 1787 return _SHR_E_NOT_FOUND; 1788 } 1789 /* make sure the block isn't already in a list */ 1790 if (_MDB_BLOCK_NOT_IN_LIST != res->elem[block].list) { 1791 LOG_ERROR(BSL_LS_SOC_COMMON, 1792 (BSL_META("mdb %08X: block at %08X..%08X in list %d\n"), 1793 PTR_TO_INT(res), 1794 block + res->low, 1795 block + res->elem[block].count + res->low - 1, 1796 res->elem[block].list - res->freeLists)); 1797 return _SHR_E_BUSY; 1798 } 1799 /* looks okay; insert the block to the list */ 1800 _mdb_list_insert(res, block, list + res->freeLists); 1801 1802 LOG_DEBUG(BSL_LS_SOC_COMMON, 1803 (BSL_META("(%08X,%d,%08X) return %d (%s)\n"), 1804 PTR_TO_INT(res), 1805 list, 1806 head, 1807 _SHR_E_NONE, 1808 _SHR_ERRMSG(_SHR_E_NONE))); 1809 return _SHR_E_NONE; 1810 } 1811 1812 /* 1813 * Function 1814 * _mdb_user_list_remove 1815 * Purpose 1816 * Remove a block from its list 1817 * Arguments 1818 * (in) shr_mdb_list_handle_t res = pointer to the list information 1819 * (in) shr_mdb_elem_index_t head = head element of block 1820 * Return 1821 * bcm_error_t cast as int 1822 * _SHR_E_NONE if successful 1823 * _SHR_E_* otherwise as appropriate 1824 * Notes 1825 */ 1826 static int 1827 _mdb_user_list_remove(shr_mdb_list_handle_t res, 1828 shr_mdb_elem_index_t head) 1829 { 1830 shr_mdb_elem_index_t block; 1831 1832 LOG_DEBUG(BSL_LS_SOC_COMMON, 1833 (BSL_META("(%08X,%08X) enter\n"), 1834 PTR_TO_INT(res), 1835 head)); 1836 1837 /* bias the block to internal value */ 1838 block = head - res->low; 1839 /* make sure the block is valid */ 1840 if ((head < res->low) || (block >= res->count)) { 1841 LOG_ERROR(BSL_LS_SOC_COMMON, 1842 (BSL_META("mdb %08X: element %08X is not valid\n"), 1843 PTR_TO_INT(res), 1844 head)); 1845 /* don't ask me why, but BCM likes NOT_FOUND for INVALID_ID */ 1846 return _SHR_E_NOT_FOUND; 1847 } 1848 /* make sure we have the block's head */ 1849 _mdb_block_head_get(res, &block); 1850 /* make sure the block is not free */ 1851 if (res->freeLists > res->elem[block].list) { 1852 LOG_ERROR(BSL_LS_SOC_COMMON, 1853 (BSL_META("mdb %08X: block at %08X..%08X is free\n"), 1854 PTR_TO_INT(res), 1855 block + res->low, 1856 block + res->elem[block].count + res->low - 1)); 1857 return _SHR_E_NOT_FOUND; 1858 } 1859 /* make sure the block is already in a list */ 1860 if (_MDB_BLOCK_NOT_IN_LIST == res->elem[block].list) { 1861 LOG_ERROR(BSL_LS_SOC_COMMON, 1862 (BSL_META("mdb %08X: block at %08X..%08X not in a list\n"), 1863 PTR_TO_INT(res), 1864 block + res->low, 1865 block + res->elem[block].count + res->low - 1)); 1866 return _SHR_E_EMPTY; 1867 } 1868 /* looks okay; insert the block to the list */ 1869 _mdb_list_remove(res, block); 1870 1871 LOG_DEBUG(BSL_LS_SOC_COMMON, 1872 (BSL_META("(%08X,%08X) return %d (%s)\n"), 1873 PTR_TO_INT(res), 1874 head, 1875 _SHR_E_NONE, 1876 _SHR_ERRMSG(_SHR_E_NONE))); 1877 return _SHR_E_NONE; 1878 } 1879 1880 /* 1881 * Function 1882 * _mdb_user_list_get 1883 * Purpose 1884 * Get user list of which a block is a member. 1885 * Arguments 1886 * (in) shr_mdb_list_handle_t res = pointer to the list information 1887 * (in) shr_mdb_elem_index_t block = head element of block 1888 * (out) shr_mdb_elem_bank_index_t *list = where to put the list 1889 * Return 1890 * bcm_error_t cast as int 1891 * _SHR_E_NONE if successful 1892 * _SHR_E_* otherwise as appropriate 1893 * Notes 1894 */ 1895 static int 1896 _mdb_user_list_get(shr_mdb_list_handle_t res, 1897 shr_mdb_elem_index_t head, 1898 shr_mdb_elem_bank_index_t *list) 1899 { 1900 shr_mdb_elem_index_t block; 1901 1902 LOG_DEBUG(BSL_LS_SOC_COMMON, 1903 (BSL_META("(%08X,%08X,*) enter\n"), 1904 PTR_TO_INT(res), 1905 head)); 1906 1907 /* bias the block to internal value */ 1908 block = head - res->low; 1909 /* make sure the block is valid */ 1910 if ((head < res->low) || (block >= res->count)) { 1911 LOG_ERROR(BSL_LS_SOC_COMMON, 1912 (BSL_META("mdb %08X: element %08X is not valid\n"), 1913 PTR_TO_INT(res), 1914 head)); 1915 /* don't ask me why, but BCM likes NOT_FOUND for INVALID_ID */ 1916 return _SHR_E_NOT_FOUND; 1917 } 1918 /* make sure we have the block's head */ 1919 _mdb_block_head_get(res, &block); 1920 /* make sure the block is not free */ 1921 if (res->freeLists > res->elem[block].list) { 1922 LOG_ERROR(BSL_LS_SOC_COMMON, 1923 (BSL_META("mdb %08X: block at %08X..%08X is free\n"), 1924 PTR_TO_INT(res), 1925 block + res->low, 1926 block + res->elem[block].count + res->low - 1)); 1927 return _SHR_E_NOT_FOUND; 1928 } 1929 /* make sure the block is already in a list */ 1930 if (_MDB_BLOCK_NOT_IN_LIST == res->elem[block].list) { 1931 LOG_ERROR(BSL_LS_SOC_COMMON, 1932 (BSL_META("mdb %08X: block at %08X..%08X not in a list\n"), 1933 PTR_TO_INT(res), 1934 block + res->low, 1935 block + res->elem[block].count + res->low - 1)); 1936 return _SHR_E_EMPTY; 1937 } 1938 /* okay, return the list on which the block belongs, biased */ 1939 *list = res->elem[block].list - res->freeLists; 1940 1941 LOG_DEBUG(BSL_LS_SOC_COMMON, 1942 (BSL_META("(%08X,%08X,&(%d)) return %d (%s)\n"), 1943 PTR_TO_INT(res), 1944 head, 1945 *list, 1946 _SHR_E_NONE, 1947 _SHR_ERRMSG(_SHR_E_NONE))); 1948 return _SHR_E_NONE; 1949 } 1950 1951 /* 1952 * Function 1953 * _mdb_user_list_head 1954 * Purpose 1955 * Get first block in specified user list. 1956 * Arguments 1957 * (in) shr_mdb_list_handle_t res = pointer to the list information 1958 * (in) shr_mdb_elem_bank_index_t list = the list whose head is to be fetched 1959 * (in) shr_mdb_elem_index_t *head = where to put head element of head block 1960 * Return 1961 * bcm_error_t cast as int 1962 * _SHR_E_NONE if successful 1963 * _SHR_E_* otherwise as appropriate 1964 * Notes 1965 */ 1966 static int 1967 _mdb_user_list_head(shr_mdb_list_handle_t res, 1968 shr_mdb_elem_bank_index_t list, 1969 shr_mdb_elem_index_t *head) 1970 { 1971 shr_mdb_elem_bank_index_t bank; 1972 shr_mdb_elem_bank_index_t offs; 1973 1974 LOG_DEBUG(BSL_LS_SOC_COMMON, 1975 (BSL_META("(%08X,%d,*) enter\n"), 1976 PTR_TO_INT(res), 1977 list)); 1978 1979 if (list >= res->userLists) { 1980 LOG_ERROR(BSL_LS_SOC_COMMON, 1981 (BSL_META("mdb %08X: there is no list %d\n"), 1982 PTR_TO_INT(res), 1983 list)); 1984 /* don't ask me why, but BCM likes NOT_FOUND for INVALID_ID */ 1985 return _SHR_E_NOT_FOUND; 1986 } 1987 bank = res->list[list + res->freeLists].head; 1988 if (_MDB_BANK_END == bank) { 1989 /* there are no banks on this list */ 1990 LOG_ERROR(BSL_LS_SOC_COMMON, 1991 (BSL_META("mdb %08X: list %d has no member blocks\n"), 1992 PTR_TO_INT(res), 1993 list)); 1994 return _SHR_E_EMPTY; 1995 } 1996 offs = _MDB_LIST_BANK_DESC(*res, list + res->freeLists, bank).head; 1997 *head = _MDB_ELEM_FROM_BANK_OFFS(*res, bank, offs); 1998 1999 LOG_DEBUG(BSL_LS_SOC_COMMON, 2000 (BSL_META("(%08X,%d,&(%08X)) return %d (%s)\n"), 2001 PTR_TO_INT(res), 2002 list, 2003 *head, 2004 _SHR_E_NONE, 2005 _SHR_ERRMSG(_SHR_E_NONE))); 2006 return _SHR_E_NONE; 2007 } 2008 2009 /* 2010 * Function 2011 * _mdb_user_list_tail 2012 * Purpose 2013 * Get last block in specified list. 2014 * Arguments 2015 * (in) shr_mdb_list_handle_t res = pointer to the list information 2016 * (in) shr_mdb_elem_bank_index_t list = the list whose tail is to be fetched 2017 * (in) shr_mdb_elem_index_t *tail = where to put head element of tail block 2018 * Return 2019 * bcm_error_t cast as int 2020 * _SHR_E_NONE if successful 2021 * _SHR_E_* otherwise as appropriate 2022 * Notes 2023 */ 2024 static int 2025 _mdb_user_list_tail(shr_mdb_list_handle_t res, 2026 shr_mdb_elem_bank_index_t list, 2027 shr_mdb_elem_index_t *tail) 2028 { 2029 shr_mdb_elem_bank_index_t bank; 2030 shr_mdb_elem_bank_index_t offs; 2031 2032 LOG_DEBUG(BSL_LS_SOC_COMMON, 2033 (BSL_META("(%08X,%d,*) enter\n"), 2034 PTR_TO_INT(res), 2035 list)); 2036 2037 if (list >= res->userLists) { 2038 LOG_ERROR(BSL_LS_SOC_COMMON, 2039 (BSL_META("mdb %08X: there is no list %d\n"), 2040 PTR_TO_INT(res), 2041 list)); 2042 /* don't ask me why, but BCM likes NOT_FOUND for INVALID_ID */ 2043 return _SHR_E_NOT_FOUND; 2044 } 2045 bank = res->list[list + res->freeLists].tail; 2046 if (_MDB_BANK_END == bank) { 2047 /* there are no banks on this list */ 2048 LOG_ERROR(BSL_LS_SOC_COMMON, 2049 (BSL_META("mdb %08X: list %d has no member blocks\n"), 2050 PTR_TO_INT(res), 2051 list)); 2052 return _SHR_E_EMPTY; 2053 } 2054 offs = _MDB_LIST_BANK_DESC(*res, list + res->freeLists, bank).tail; 2055 *tail = _MDB_ELEM_FROM_BANK_OFFS(*res, bank, offs); 2056 2057 LOG_DEBUG(BSL_LS_SOC_COMMON, 2058 (BSL_META("(%08X,%d,&(%08X)) return %d (%s)\n"), 2059 PTR_TO_INT(res), 2060 list, 2061 *tail, 2062 _SHR_E_NONE, 2063 _SHR_ERRMSG(_SHR_E_NONE))); 2064 return _SHR_E_NONE; 2065 } 2066 2067 /* 2068 * Function 2069 * _mdb_list_pred 2070 * Purpose 2071 * Get the block that is the predecessor to the provided one, on the same 2072 * list. 2073 * Arguments 2074 * (in) shr_mdb_list_handle_t res = pointer to the list information 2075 * (in) shr_mdb_elem_index_t current = block whose predecessor is to be found 2076 * (in) shr_mdb_elem_index_t *pred = where to put predecessor block 2077 * Return 2078 * bcm_error_t cast as int 2079 * _SHR_E_NONE if successful 2080 * _SHR_E_* otherwise as appropriate 2081 * Notes 2082 */ 2083 static int 2084 _mdb_list_pred(shr_mdb_list_handle_t res, 2085 shr_mdb_elem_index_t current, 2086 shr_mdb_elem_index_t *pred) 2087 { 2088 shr_mdb_elem_index_t block; 2089 shr_mdb_elem_bank_index_t bank; 2090 shr_mdb_elem_desc_t *thisElem; 2091 shr_mdb_elem_bank_index_t offs; 2092 2093 LOG_DEBUG(BSL_LS_SOC_COMMON, 2094 (BSL_META("(%08X,%08X,*) enter\n"), 2095 PTR_TO_INT(res), 2096 current)); 2097 2098 /* bias the block to internal value */ 2099 block = current - res->low; 2100 /* make sure the block is valid */ 2101 if ((current < res->low) || (block >= res->count)) { 2102 LOG_ERROR(BSL_LS_SOC_COMMON, 2103 (BSL_META("mdb %08X: element %08X is not valid\n"), 2104 PTR_TO_INT(res), 2105 current)); 2106 /* don't ask me why, but BCM likes NOT_FOUND for INVALID_ID */ 2107 return _SHR_E_NOT_FOUND; 2108 } 2109 /* make sure we have the block's head */ 2110 _mdb_block_head_get(res, &block); 2111 thisElem = &(res->elem[block]); 2112 #if 0 2113 /* make sure the block is not free */ 2114 if (res->freeLists > thisElem->list) { 2115 LOG_ERROR(BSL_LS_SOC_COMMON, 2116 (BSL_META("mdb %08X: block at %08X..%08X is free\n"), 2117 PTR_TO_INT(res), 2118 block + res->low, 2119 block + thisElem->count + res->low - 1)); 2120 return _SHR_E_NOT_FOUND; 2121 } 2122 #endif 2123 /* make sure the block is already in a list */ 2124 if (_MDB_BLOCK_NOT_IN_LIST == thisElem->list) { 2125 LOG_ERROR(BSL_LS_SOC_COMMON, 2126 (BSL_META("mdb %08X: block at %08X..%08X not in a list\n"), 2127 PTR_TO_INT(res), 2128 block + res->low, 2129 block + thisElem->count + res->low - 1)); 2130 return _SHR_E_EMPTY; 2131 } 2132 bank = _MDB_BANK_FROM_ELEM(*res, current); 2133 offs = thisElem->prev; 2134 2135 if (_MDB_BLOCK_END == offs) { 2136 /* need to go to previous bank in this list */ 2137 bank = _MDB_LIST_BANK_DESC(*res, thisElem->list, bank).prev; 2138 if (_MDB_BANK_END == bank) { 2139 /* can't go past beginning of list */ 2140 LOG_ERROR(BSL_LS_SOC_COMMON, 2141 (BSL_META("mdb %08X: block at %08X is head of list %d\n"), 2142 PTR_TO_INT(res), 2143 current, 2144 thisElem->list)); 2145 return _SHR_E_NOT_FOUND; 2146 } 2147 offs = _MDB_LIST_BANK_DESC(*res, thisElem->list, bank).tail; 2148 } 2149 *pred = _MDB_ELEM_FROM_BANK_OFFS(*res, bank, offs); 2150 2151 LOG_DEBUG(BSL_LS_SOC_COMMON, 2152 (BSL_META("(%08X,%08X,&(%08X)) return %d (%s)\n"), 2153 PTR_TO_INT(res), 2154 current, 2155 *pred, 2156 _SHR_E_NONE, 2157 _SHR_ERRMSG(_SHR_E_NONE))); 2158 return _SHR_E_NONE; 2159 } 2160 2161 /* 2162 * Function 2163 * _mdb_list_succ 2164 * Purpose 2165 * Get the block that is the successor to the provided one, on the same 2166 * list. 2167 * Arguments 2168 * (in) shr_mdb_list_handle_t res = pointer to the list information 2169 * (in) shr_mdb_elem_index_t current = block whose successor is to be found 2170 * (in) shr_mdb_elem_index_t *succ = where to put successor block 2171 * Return 2172 * bcm_error_t cast as int 2173 * _SHR_E_NONE if successful 2174 * _SHR_E_* otherwise as appropriate 2175 * Notes 2176 */ 2177 static int 2178 _mdb_list_succ(shr_mdb_list_handle_t res, 2179 shr_mdb_elem_index_t current, 2180 shr_mdb_elem_index_t *succ) 2181 { 2182 shr_mdb_elem_index_t block; 2183 shr_mdb_elem_bank_index_t bank; 2184 shr_mdb_elem_desc_t *thisElem; 2185 shr_mdb_elem_bank_index_t offs; 2186 2187 LOG_DEBUG(BSL_LS_SOC_COMMON, 2188 (BSL_META("(%08X,%08X,*) enter\n"), 2189 PTR_TO_INT(res), 2190 current)); 2191 2192 /* bias the block to internal value */ 2193 block = current - res->low; 2194 /* make sure the block is valid */ 2195 if ((current < res->low) || (block >= res->count)) { 2196 LOG_ERROR(BSL_LS_SOC_COMMON, 2197 (BSL_META("mdb %08X: element %08X is not valid\n"), 2198 PTR_TO_INT(res), 2199 current)); 2200 /* don't ask me why, but BCM likes NOT_FOUND for INVALID_ID */ 2201 return _SHR_E_NOT_FOUND; 2202 } 2203 /* make sure we have the block's head */ 2204 _mdb_block_head_get(res, &block); 2205 thisElem = &(res->elem[block]); 2206 #if 0 2207 /* make sure the block is not free */ 2208 if (res->freeLists > thisElem->list) { 2209 LOG_ERROR(BSL_LS_SOC_COMMON, 2210 (BSL_META("mdb %08X: block at %08X..%08X is free\n"), 2211 PTR_TO_INT(res), 2212 block + res->low, 2213 block + thisElem->count + res->low - 1)); 2214 return _SHR_E_NOT_FOUND; 2215 } 2216 #endif 2217 /* make sure the block is already in a list */ 2218 if (_MDB_BLOCK_NOT_IN_LIST == thisElem->list) { 2219 LOG_ERROR(BSL_LS_SOC_COMMON, 2220 (BSL_META("mdb %08X: block at %08X..%08X not in a list\n"), 2221 PTR_TO_INT(res), 2222 block + res->low, 2223 block + thisElem->count + res->low - 1)); 2224 return _SHR_E_EMPTY; 2225 } 2226 bank = _MDB_BANK_FROM_ELEM(*res, current); 2227 offs = thisElem->next; 2228 2229 if (_MDB_BLOCK_END == offs) { 2230 /* need to go to previous bank in this list */ 2231 bank = _MDB_LIST_BANK_DESC(*res, thisElem->list, bank).next; 2232 if (_MDB_BANK_END == bank) { 2233 /* can't go past beginning of list */ 2234 LOG_ERROR(BSL_LS_SOC_COMMON, 2235 (BSL_META("mdb %08X: block at %08X is head of list %d\n"), 2236 PTR_TO_INT(res), 2237 current, 2238 thisElem->list)); 2239 return _SHR_E_NOT_FOUND; 2240 } 2241 offs = _MDB_LIST_BANK_DESC(*res, thisElem->list, bank).head; 2242 } 2243 *succ = _MDB_ELEM_FROM_BANK_OFFS(*res, bank, offs); 2244 2245 LOG_DEBUG(BSL_LS_SOC_COMMON, 2246 (BSL_META("(%08X,%08X,&(%08X)) return %d (%s)\n"), 2247 PTR_TO_INT(res), 2248 current, 2249 *succ, 2250 _SHR_E_NONE, 2251 _SHR_ERRMSG(_SHR_E_NONE))); 2252 return _SHR_E_NONE; 2253 } 2254 2255 /* 2256 * Function 2257 * _mdb_user_list_purge 2258 * Purpose 2259 * Free all blocks in a user list 2260 * Arguments 2261 * (in) shr_mdb_list_handle_t res = pointer to the list information 2262 * (in) shr_mdb_elem_index_t list = the list to be freed 2263 * Return 2264 * bcm_error_t cast as int 2265 * _SHR_E_NONE if successful 2266 * _SHR_E_* otherwise as appropriate 2267 * Notes 2268 */ 2269 static int 2270 _mdb_user_list_purge(shr_mdb_list_handle_t res, 2271 shr_mdb_elem_bank_index_t list) 2272 { 2273 shr_mdb_elem_bank_index_t bank; 2274 shr_mdb_elem_bank_index_t nextBank; 2275 shr_mdb_elem_bank_index_t offs; 2276 shr_mdb_elem_bank_index_t nextOffs; 2277 shr_mdb_elem_bank_index_t listNum = list + res->freeLists; 2278 shr_mdb_list_bank_desc_t *thisBank; 2279 shr_mdb_elem_index_t elem; 2280 2281 LOG_DEBUG(BSL_LS_SOC_COMMON, 2282 (BSL_META("(%08X,%d) enter\n"), 2283 PTR_TO_INT(res), 2284 list)); 2285 2286 /* make sure arguments are valid */ 2287 if (list >= res->userLists) { 2288 LOG_ERROR(BSL_LS_SOC_COMMON, 2289 (BSL_META("mdb %08X: there is no list %d\n"), 2290 PTR_TO_INT(res), 2291 list)); 2292 /* don't ask me why, but BCM likes NOT_FOUND for INVALID_ID */ 2293 return _SHR_E_NOT_FOUND; 2294 } 2295 /* make sure there are blocks on the specified list */ 2296 nextBank = res->list[listNum].head; 2297 if (_MDB_BANK_END == nextBank) { 2298 /* there are no banks on this list (but it's NOT an error!) */ 2299 LOG_DEBUG(BSL_LS_SOC_COMMON, 2300 (BSL_META("mdb %08X: user list %d has no member blocks\n"), 2301 PTR_TO_INT(res), 2302 list)); 2303 return _SHR_E_NONE; 2304 } 2305 /* go through all banks in this list */ 2306 while (_MDB_BANK_END != nextBank) { 2307 bank = nextBank; 2308 thisBank = &(_MDB_LIST_BANK_DESC(*res, listNum, bank)); 2309 nextBank = thisBank->next; 2310 nextOffs = thisBank->head; 2311 LOG_DEBUG(BSL_LS_SOC_COMMON, 2312 (BSL_META("mdb %08X: user list %d has blocks in bank %04X," 2313 " head %04X\n"), 2314 PTR_TO_INT(res), 2315 list, 2316 bank, 2317 nextOffs)); 2318 /* go through all blocks in this bank of this list */ 2319 while (_MDB_BLOCK_END != nextOffs) { 2320 offs = nextOffs; 2321 elem = _MDB_ELEM_FROM_BANK_OFFS(*res, bank, offs); 2322 nextOffs = res->elem[elem].next; 2323 LOG_DEBUG(BSL_LS_SOC_COMMON, 2324 (BSL_META("mdb %08X: list %d has block to free at" 2325 " %04X:%04X (%08X, list %04X, size %04X," 2326 " next %04X)\n"), 2327 PTR_TO_INT(res), 2328 list + res->freeLists, 2329 bank, 2330 offs, 2331 elem, 2332 res->elem[elem].list, 2333 res->elem[elem].count, 2334 nextOffs)); 2335 /* remove this block from the list */ 2336 _mdb_list_remove(res, elem); 2337 /* defragment the block into neighbours */ 2338 if ((res->allocPref & shr_mdb_join_free) || 2339 (!(res->allocPref & (shr_mdb_join_alloc | 2340 shr_mdb_join_free)))) { 2341 /* need to join adjacent free blocks on free */ 2342 _mdb_block_defrag(res, &elem, 0); 2343 } 2344 /* put the block on appropriate free lists */ 2345 _mdb_block_frag_and_free(res, elem); 2346 } /* while (_MDB_BLOCK_END != nextOffs) */ 2347 } /* while (_MDB_BANK_END != nextBank) */ 2348 2349 LOG_DEBUG(BSL_LS_SOC_COMMON, 2350 (BSL_META("(%08X,%d) return %d (%s)\n"), 2351 PTR_TO_INT(res), 2352 list, 2353 _SHR_E_NONE, 2354 _SHR_ERRMSG(_SHR_E_NONE))); 2355 return _SHR_E_NONE; 2356 } 2357 2358 2359 /***************************************************************************** 2360 * 2361 * Interface 2362 * 2363 * Functions exposed to be called. These take/release the lock where 2364 * appropriate, do some argument filtering, &c. They rely upon the support or 2365 * implementation sections for the real work (except in the case of create, 2366 * which does a lot of accounting prep that is required before the internal 2367 * and support functions will work. 2368 * 2369 * These just deal with locking and obvious (such as null pointer) validation, 2370 * and use the support or implementation functions to do the work (mostly). 2371 */ 2372 2373 /* 2374 * Function 2375 * shr_mdb_create 2376 * 2377 * Purpose 2378 * Create an mdb type indexed resource management object, given the 2379 * specified parameters for the object. 2380 * 2381 * Elements per bank will be rounded up to the next integral power of two, 2382 * and that must be <=32768. 2383 * 2384 * A free list of block size = 1 is obligatory (and implied); additional 2385 * free lists (as specified by freeLists) have their block sizes given in an 2386 * array pointed to by freeCnts. 2387 * 2388 * FreeCnts entries must be in strictly increasing order, and the largest 2389 * must be less than or equal to bankSize. The largest freeCnts entry will 2390 * be the largest block that can be allocated, so at least one freeCnts 2391 * entry must be greater than or equal to the largest block you will need. 2392 * Ideally, freeCnts entries will tend to be the most commonly used block 2393 * sizes, plus possibly some larger block sizes for more efficient 2394 * management of free space. 2395 * 2396 * UserLists specifies the number of user lists that will be included. 2397 * These allow in-place use of the existing management memory to track lists 2398 * of blocks for whatever purpose is necessary, and allow any size block, 2399 * but these lists will be unsorted and unordered. 2400 * 2401 * Arguments 2402 * (out) shr_mdb_list_handle_t *handle = where to put the handle 2403 * (in) shr_mdb_elem_bank_index_t bankSize = elements per bank 2404 * (in) shr_mdb_elem_bank_index_t freeLists = number of additional free lists 2405 * (in) shr_mdb_elem_bank_index_t *freeCnts = free lists elements per block 2406 * (in) shr_mdb_elem_bank_index_t userLists = number of user lists 2407 * (in) shr_mdb_elem_index_t first = lowest element number to manage 2408 * (in) shr_mdb_elem_index_t last = highest element number to manage 2409 * (in) int lock = TRUE if should be a lock; FALSE if caller will protect 2410 * 2411 * Return 2412 * bcm_error_t cast as int 2413 * _SHR_E_NONE if successful 2414 * _SHR_E_* otherwise as appropriate 2415 * 2416 * Notes 2417 * none 2418 */ 2419 int 2420 shr_mdb_create(shr_mdb_list_handle_t *handle, 2421 shr_mdb_elem_bank_index_t bankSize, 2422 shr_mdb_elem_bank_index_t freeLists, 2423 shr_mdb_elem_bank_index_t *freeCnts, 2424 shr_mdb_elem_bank_index_t userLists, 2425 shr_mdb_elem_index_t first, 2426 shr_mdb_elem_index_t last, 2427 int lock) 2428 { 2429 shr_mdb_list_handle_t tempList; 2430 shr_mdb_list_bank_desc_t bankList; 2431 unsigned int size; 2432 unsigned int shift; 2433 unsigned int banks; 2434 unsigned int lastBankSize; 2435 unsigned int elems; 2436 unsigned int lists; 2437 unsigned int bank; 2438 unsigned int list; 2439 int result; 2440 2441 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2442 (BSL_META("(*,%d,%d,*,%d,%d,%d,%s) enter\n"), 2443 bankSize, 2444 freeLists, 2445 userLists, 2446 first, 2447 last, 2448 lock?"Lock":"NoLock")); 2449 2450 /* validate the arguments */ 2451 for (size = 16, shift = 4; 2452 size && (size < bankSize); 2453 size <<= 1, shift++) { 2454 /* find the lowest power of two >= requested bank size */ 2455 /* but don't make it less than 16 */ 2456 } 2457 if (!size || (32768 < size)) { 2458 /* the requested bank size is too large */ 2459 LOG_ERROR(BSL_LS_SOC_COMMON, 2460 (BSL_META("requested bank size %d is too large\n"), 2461 bankSize)); 2462 return _SHR_E_PARAM; 2463 } 2464 if (last <= first) { 2465 /* there are too few elements (one, zero, or negative) to bother */ 2466 LOG_ERROR(BSL_LS_SOC_COMMON, 2467 (BSL_META("range has negative, zero, or one element\n"))); 2468 return _SHR_E_PARAM; 2469 } 2470 if ((freeLists + userLists) > 255) { 2471 /* there are too many lists */ 2472 LOG_ERROR(BSL_LS_SOC_COMMON, 2473 (BSL_META("there are too many lists (free+user = %d, which is" 2474 " > 255)\n"), 2475 freeLists + userLists)); 2476 return _SHR_E_PARAM; 2477 } 2478 if (!handle) { 2479 /* there's no place to put the handle */ 2480 LOG_ERROR(BSL_LS_SOC_COMMON, 2481 (BSL_META("NULL pointer for out argument\n"))); 2482 return _SHR_E_PARAM; 2483 } 2484 /* keep the decided bank size */ 2485 bankSize = size; 2486 /* how many elements total */ 2487 elems = (last - first) + 1; 2488 /* determine how many banks are needed */ 2489 banks = elems / bankSize; 2490 lastBankSize = elems - (banks * bankSize); 2491 if (lastBankSize) { 2492 /* need partial last bank */ 2493 banks++; 2494 } else { 2495 /* last bank is full size */ 2496 lastBankSize = bankSize; 2497 } 2498 if (banks > 0xFFF0) { 2499 /* there are too many banks */ 2500 LOG_ERROR(BSL_LS_SOC_COMMON, 2501 (BSL_META("there are too many banks (%d)\n"), 2502 banks)); 2503 return _SHR_E_PARAM; 2504 } 2505 LOG_DEBUG(BSL_LS_SOC_COMMON, 2506 (BSL_META("%u elements, bankSize %u -> %u banks with" 2507 " last bank having %u elements\n"), 2508 elems, 2509 bankSize, 2510 banks, 2511 lastBankSize)); 2512 /* how many lists total (free + user) */ 2513 lists = userLists + freeLists + 1; 2514 /* figure out how much memory is needed */ 2515 size = ((elems * sizeof(shr_mdb_elem_desc_t)) + /* elements */ 2516 (banks * lists * (sizeof(shr_mdb_list_bank_desc_t))) +/* bnk lst */ 2517 (lists * sizeof(shr_mdb_list_desc_t)) + /* lists */ 2518 (sizeof(shr_mdb_list_t))); /* top level */ 2519 /* try to allocate it */ 2520 LOG_DEBUG(BSL_LS_SOC_COMMON, 2521 (BSL_META("allocate %d bytes for descriptor\n"), 2522 size)); 2523 tempList = sal_alloc(size, "mdb_management"); 2524 if (!tempList) { 2525 LOG_ERROR(BSL_LS_SOC_COMMON, 2526 (BSL_META("unable to allocate %d bytes for descriptor\n"), 2527 size)); 2528 return _SHR_E_MEMORY; 2529 } 2530 /* looks good so far */ 2531 result = _SHR_E_NONE; 2532 /* prepare it */ 2533 if (lock) { 2534 LOG_DEBUG(BSL_LS_SOC_COMMON, 2535 (BSL_META("create lock\n"))); 2536 tempList->lock = sal_mutex_create("mdb_management_lock"); 2537 if (!(tempList->lock)) { 2538 LOG_ERROR(BSL_LS_SOC_COMMON, 2539 (BSL_META("unable to create lock\n"))); 2540 result = _SHR_E_RESOURCE; 2541 } 2542 } else { 2543 tempList->lock = NULL; 2544 } 2545 LOG_DEBUG(BSL_LS_SOC_COMMON, 2546 (BSL_META("prepare top-level descriptor\n"))); 2547 tempList->low = first; 2548 tempList->count = elems; 2549 tempList->freeLists = freeLists + 1; 2550 tempList->userLists = userLists; 2551 tempList->lists = lists; 2552 tempList->banks = banks; 2553 tempList->bankShift = shift; 2554 tempList->bankMask = ~(bankSize - 1); 2555 tempList->lastBankSize = lastBankSize; 2556 tempList->allocPref = (shr_mdb_alloc_bank_first | 2557 shr_mdb_alloc_block_high | 2558 shr_mdb_free_block_high | 2559 shr_mdb_join_alloc_and_free | 2560 shr_mdb_join_high_and_low); 2561 tempList->list = (shr_mdb_list_desc_t*)(&(tempList[1])); 2562 tempList->listBank = (shr_mdb_list_bank_desc_t*)(&(tempList->list[lists])); 2563 tempList->elem = (shr_mdb_elem_desc_t*)(&(tempList->listBank[banks * lists])); 2564 if (_SHR_E_NONE == result) { 2565 /* prepare list descriptors */ 2566 LOG_DEBUG(BSL_LS_SOC_COMMON, 2567 (BSL_META("prepare list descriptors\n"))); 2568 bankList.blocks = 0; 2569 bankList.elems = 0; 2570 bankList.head = _MDB_BLOCK_END; 2571 bankList.tail = _MDB_BLOCK_END; 2572 bankList.next = _MDB_BANK_END; 2573 bankList.prev = _MDB_BANK_END; 2574 for (list = 0; list < lists; list++) { 2575 tempList->list[list].blocks = 0; 2576 tempList->list[list].elems = 0; 2577 tempList->list[list].head = _MDB_BANK_END; 2578 tempList->list[list].tail = _MDB_BANK_END; 2579 if (0 == list) { 2580 LOG_DEBUG(BSL_LS_SOC_COMMON, 2581 (BSL_META("obligatory free list %d:" 2582 " blocks of 1 element\n"), 2583 list)); 2584 tempList->list[list].elemsBlock = 1; 2585 } else if (list <= freeLists) { 2586 LOG_DEBUG(BSL_LS_SOC_COMMON, 2587 (BSL_META("additional free list %d:" 2588 " blocks of %d elements\n"), 2589 list, 2590 freeCnts[list - 1])); 2591 tempList->list[list].elemsBlock = freeCnts[list - 1]; 2592 if (tempList->list[list].elemsBlock <= 2593 tempList->list[list - 1].elemsBlock) { 2594 LOG_ERROR(BSL_LS_SOC_COMMON, 2595 (BSL_META("block size in user specified free lists" 2596 " is not strictly increasing\n"))); 2597 result = _SHR_E_PARAM; 2598 break; 2599 } 2600 if (tempList->list[list].elemsBlock > bankSize) { 2601 LOG_ERROR(BSL_LS_SOC_COMMON, 2602 (BSL_META("block size %d exceeds bank size %d\n"), 2603 tempList->list[list].elemsBlock, 2604 bankSize)); 2605 result = _SHR_E_PARAM; 2606 break; 2607 } 2608 } else { 2609 LOG_DEBUG(BSL_LS_SOC_COMMON, 2610 (BSL_META("user list %d\n"), 2611 list - (freeLists + 1))); 2612 tempList->list[list].elemsBlock = 0; 2613 } 2614 for (bank = 0; bank < banks; bank++) { 2615 _MDB_LIST_BANK_DESC(*tempList, list, bank) = bankList; 2616 } 2617 } 2618 } /* if (_SHR_E_NONE == result) */ 2619 /* prepare element descriptors */ 2620 if (_SHR_E_NONE == result) { 2621 LOG_DEBUG(BSL_LS_SOC_COMMON, 2622 (BSL_META("prepare element descriptors (%d banks)\n"), 2623 tempList->banks)); 2624 for (bank = 0; bank < (banks - 1); bank++) { 2625 _mdb_block_prep(tempList, 2626 _MDB_ELEM_FROM_BANK_OFFS(*tempList, bank, 0), 2627 bankSize); 2628 } 2629 _mdb_block_prep(tempList, 2630 _MDB_ELEM_FROM_BANK_OFFS(*tempList, bank, 0), 2631 tempList->lastBankSize); 2632 /* assign elements to appropriate free lists */ 2633 LOG_DEBUG(BSL_LS_SOC_COMMON, 2634 (BSL_META("assign elements to appropriate free lists\n"))); 2635 for (bank = 0; bank < banks; bank++) { 2636 _mdb_block_frag_and_free(tempList, 2637 _MDB_ELEM_FROM_BANK_OFFS(*tempList, 2638 bank, 2639 0)); 2640 } 2641 } /* if (_SHR_E_NONE == result) */ 2642 if (_SHR_E_NONE == result) { 2643 *handle = tempList; 2644 } else { 2645 /* something went wrong */ 2646 if (tempList) { 2647 /* but we allocated the memory cell */ 2648 if (tempList->lock) { 2649 /* and we somehow got a lock */ 2650 sal_mutex_destroy(tempList->lock); 2651 } 2652 sal_free(tempList); 2653 } 2654 } 2655 2656 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2657 (BSL_META("(&(%08X),%d,%d,*,%d,%d,%d,%s) return %d (%s)\n"), 2658 PTR_TO_INT(*handle), 2659 bankSize, 2660 freeLists, 2661 userLists, 2662 first, 2663 last, 2664 lock?"Lock":"NoLock", 2665 result, 2666 _SHR_ERRMSG(result))); 2667 return result; 2668 } 2669 2670 /* 2671 * Function 2672 * shr_mdb_destroy 2673 * 2674 * Purpose 2675 * Destroy and mdb type indexed resource management object, given the object 2676 * handle. 2677 * 2678 * Arguments 2679 * (in) shr_mdb_list_handle_t handle = the handle 2680 * 2681 * Return 2682 * bcm_error_t cast as int 2683 * _SHR_E_NONE if successful 2684 * _SHR_E_* otherwise as appropriate 2685 * 2686 * Notes 2687 * Must not be called concurrently with any other operation on same object. 2688 */ 2689 int 2690 shr_mdb_destroy(shr_mdb_list_handle_t handle) 2691 { 2692 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2693 (BSL_META("(%08X) enter\n"), 2694 PTR_TO_INT(handle))); 2695 2696 if (!handle) { 2697 LOG_ERROR(BSL_LS_SOC_COMMON, 2698 (BSL_META("NULL handle is not acceptable\n"))); 2699 return _SHR_E_PARAM; 2700 } 2701 if (handle->lock) { 2702 /* we have a lock; get rid of it */ 2703 sal_mutex_destroy(handle->lock); 2704 } 2705 /* overwrite the top level information */ 2706 sal_memset(handle, 0, sizeof(shr_mdb_list_t)); 2707 /* free it */ 2708 sal_free(handle); 2709 2710 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2711 (BSL_META("(%08X) return %d (%s)\n"), 2712 PTR_TO_INT(handle), 2713 _SHR_E_NONE, 2714 _SHR_ERRMSG(_SHR_E_NONE))); 2715 return _SHR_E_NONE; 2716 } 2717 2718 /* 2719 * Function 2720 * shr_mdb_reserve 2721 * 2722 * Purpose 2723 * Resevere elements directly. 2724 * 2725 * Arguments 2726 * (in) shr_mdb_list_handle_t handle = the handle 2727 * (in) shr_mdb_elem_index_t first = the first element to reserve 2728 * (in) shr_mdb_elem_index_t last = the last element to reserve 2729 * 2730 * Return 2731 * bcm_error_t cast as int 2732 * _SHR_E_NONE if successful 2733 * _SHR_E_* otherwise as appropriate 2734 * 2735 * Notes 2736 * Elements to be reserved must be free, else the call will fail. 2737 */ 2738 int 2739 shr_mdb_reserve(shr_mdb_list_handle_t handle, 2740 shr_mdb_elem_index_t first, 2741 shr_mdb_elem_index_t last) 2742 { 2743 int result; 2744 2745 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2746 (BSL_META("(%08X,%08X,%08X) enter\n"), 2747 PTR_TO_INT(handle), 2748 first, 2749 last)); 2750 2751 _MDB_VALID_CHECK(handle); 2752 if (first > last) { 2753 LOG_ERROR(BSL_LS_SOC_COMMON, 2754 (BSL_META("first %08X is greater than last %08X\n"), 2755 first, 2756 last)); 2757 return _SHR_E_PARAM; 2758 } 2759 _MDB_LOCK_TAKE(handle); 2760 result = _shr_mdb_elems_reserve(handle, first, (last - first) + 1); 2761 _MDB_LOCK_GIVE(handle); 2762 2763 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2764 (BSL_META("(%08X,%08X,%08X) return %d (%s)\n"), 2765 PTR_TO_INT(handle), 2766 first, 2767 last, 2768 result, 2769 _SHR_ERRMSG(result))); 2770 return result; 2771 } 2772 2773 /* 2774 * Function 2775 * shr_mdb_unreserve 2776 * 2777 * Purpose 2778 * Unresevere elements directly. 2779 * 2780 * Arguments 2781 * (in) shr_mdb_list_handle_t handle = the handle 2782 * (in) shr_mdb_elem_index_t first = the first element to unreserve 2783 * (in) shr_mdb_elem_index_t last = the last element to unreserve 2784 * 2785 * Return 2786 * bcm_error_t cast as int 2787 * _SHR_E_NONE if successful 2788 * _SHR_E_* otherwise as appropriate 2789 * 2790 * Notes 2791 * Elements to be unreserved must be singly allocated, else it will fail. 2792 */ 2793 int 2794 shr_mdb_unreserve(shr_mdb_list_handle_t handle, 2795 shr_mdb_elem_index_t first, 2796 shr_mdb_elem_index_t last) 2797 { 2798 int result; 2799 2800 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2801 (BSL_META("(%08X,%08X,%08X) enter\n"), 2802 PTR_TO_INT(handle), 2803 first, 2804 last)); 2805 2806 _MDB_VALID_CHECK(handle); 2807 if (first > last) { 2808 LOG_ERROR(BSL_LS_SOC_COMMON, 2809 (BSL_META("first %08X is greater than last %08X\n"), 2810 first, 2811 last)); 2812 return _SHR_E_PARAM; 2813 } 2814 _MDB_LOCK_TAKE(handle); 2815 result = _shr_mdb_elems_unreserve(handle, first, (last - first) + 1); 2816 _MDB_LOCK_GIVE(handle); 2817 2818 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2819 (BSL_META("(%08X,%08X,%08X) return %d (%s)\n"), 2820 PTR_TO_INT(handle), 2821 first, 2822 last, 2823 result, 2824 _SHR_ERRMSG(result))); 2825 return result; 2826 } 2827 2828 /* 2829 * Function 2830 * shr_mdb_reserve_to_block 2831 * 2832 * Purpose 2833 * Convert a set of reserved elements to a usable block. This is meant to 2834 * be used in case a reserved range must be converted into a standard block, 2835 * and it must be done so in-place. 2836 * 2837 * Arguments 2838 * (in) shr_mdb_list_handle_t handle = the handle 2839 * (in) shr_mdb_elem_index_t first = the first element to convert 2840 * (in) shr_mdb_elem_index_t last = the last element to convert 2841 * 2842 * Return 2843 * bcm_error_t cast as int 2844 * _SHR_E_NONE if successful 2845 * _SHR_E_* otherwise as appropriate 2846 * 2847 * Notes 2848 * Elements must be singly allocated, else it will fail. 2849 */ 2850 int 2851 shr_mdb_reserve_to_block(shr_mdb_list_handle_t handle, 2852 shr_mdb_elem_index_t first, 2853 shr_mdb_elem_index_t last) 2854 { 2855 int result; 2856 2857 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2858 (BSL_META("(%08X,%08X,%08X) enter\n"), 2859 PTR_TO_INT(handle), 2860 first, 2861 last)); 2862 2863 _MDB_VALID_CHECK(handle); 2864 if (first > last) { 2865 LOG_ERROR(BSL_LS_SOC_COMMON, 2866 (BSL_META("first %08X is greater than last %08X\n"), 2867 first, 2868 last)); 2869 return _SHR_E_PARAM; 2870 } 2871 _MDB_LOCK_TAKE(handle); 2872 result = _shr_mdb_elems_collect(handle, first, (last - first) + 1); 2873 _MDB_LOCK_GIVE(handle); 2874 2875 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2876 (BSL_META("(%08X,%08X,%08X) return %d (%s)\n"), 2877 PTR_TO_INT(handle), 2878 first, 2879 last, 2880 result, 2881 _SHR_ERRMSG(result))); 2882 return result; 2883 } 2884 2885 /* 2886 * Function 2887 * shr_mdb_alloc 2888 * 2889 * Purpose 2890 * Allocate a block of elements. 2891 * 2892 * Arguments 2893 * (in) shr_mdb_list_handle_t handle = the handle 2894 * (out) shr_mdb_elem_index_t *block = where to put the block 2895 * (in) shr_mdb_elem_bank_index_t count = number of elements 2896 * 2897 * Return 2898 * bcm_error_t cast as int 2899 * _SHR_E_NONE if successful 2900 * _SHR_E_* otherwise as appropriate 2901 * 2902 * Notes 2903 * none 2904 */ 2905 int 2906 shr_mdb_alloc(shr_mdb_list_handle_t handle, 2907 shr_mdb_elem_index_t *block, 2908 shr_mdb_elem_bank_index_t count) 2909 { 2910 int result; 2911 2912 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2913 (BSL_META("(%08X,*,%d) enter\n"), 2914 PTR_TO_INT(handle), 2915 count)); 2916 2917 _MDB_VALID_CHECK(handle); 2918 if (!block) { 2919 LOG_ERROR(BSL_LS_SOC_COMMON, 2920 (BSL_META("NULL is unacceptable as block pointer\n"))); 2921 return _SHR_E_PARAM; 2922 } 2923 _MDB_LOCK_TAKE(handle); 2924 result = _shr_mdb_block_alloc(handle, block, count); 2925 _MDB_LOCK_GIVE(handle); 2926 2927 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2928 (BSL_META("(%08X,&(%08X),%d) return %d (%s)\n"), 2929 PTR_TO_INT(handle), 2930 *block, 2931 count, 2932 result, 2933 _SHR_ERRMSG(result))); 2934 return result; 2935 } 2936 2937 /* 2938 * Function 2939 * shr_mdb_alloc_id 2940 * 2941 * Purpose 2942 * Allocate a specific block of elements. 2943 * 2944 * Arguments 2945 * (in) shr_mdb_list_handle_t handle = the handle 2946 * (in) shr_mdb_elem_index_t block = the block 2947 * (in) shr_mdb_elem_bank_index_t count = number of elements 2948 * 2949 * Return 2950 * bcm_error_t cast as int 2951 * _SHR_E_NONE if successful 2952 * _SHR_E_* otherwise as appropriate 2953 * 2954 * Notes 2955 * none 2956 */ 2957 int 2958 shr_mdb_alloc_id(shr_mdb_list_handle_t handle, 2959 shr_mdb_elem_index_t block, 2960 shr_mdb_elem_bank_index_t count) 2961 { 2962 int result; 2963 2964 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2965 (BSL_META("(%08X,%08X,%d) enter\n"), 2966 PTR_TO_INT(handle), 2967 block, 2968 count)); 2969 2970 _MDB_VALID_CHECK(handle); 2971 _MDB_LOCK_TAKE(handle); 2972 result = _shr_mdb_block_alloc_id(handle, block, count); 2973 _MDB_LOCK_GIVE(handle); 2974 2975 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2976 (BSL_META("(%08X,%08X,%d) return %d (%s)\n"), 2977 PTR_TO_INT(handle), 2978 block, 2979 count, 2980 result, 2981 _SHR_ERRMSG(result))); 2982 return result; 2983 } 2984 2985 /* 2986 * Function 2987 * shr_mdb_free 2988 * 2989 * Purpose 2990 * Free a block of elements. 2991 * 2992 * Arguments 2993 * (in) shr_mdb_list_handle_t handle = the handle 2994 * (in) shr_mdb_elem_index_t block = the block 2995 * 2996 * Return 2997 * bcm_error_t cast as int 2998 * _SHR_E_NONE if successful 2999 * _SHR_E_* otherwise as appropriate 3000 * 3001 * Notes 3002 * none 3003 */ 3004 int 3005 shr_mdb_free(shr_mdb_list_handle_t handle, 3006 shr_mdb_elem_index_t block) 3007 { 3008 int result; 3009 3010 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3011 (BSL_META("(%08X,%08X) enter\n"), 3012 PTR_TO_INT(handle), 3013 block)); 3014 3015 _MDB_VALID_CHECK(handle); 3016 _MDB_LOCK_TAKE(handle); 3017 result = _shr_mdb_block_free(handle, block); 3018 _MDB_LOCK_GIVE(handle); 3019 3020 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3021 (BSL_META("(%08X,%08X) return %d (%s)\n"), 3022 PTR_TO_INT(handle), 3023 block, 3024 result, 3025 _SHR_ERRMSG(result))); 3026 return result; 3027 } 3028 3029 /* 3030 * Function 3031 * shr_mdb_block_size_get 3032 * 3033 * Purpose 3034 * Get the number of elements in a particular block. 3035 * 3036 * Arguments 3037 * (in) shr_mdb_list_handle_t handle = the handle 3038 * (in) shr_mdb_elem_index_t *block = the block to check 3039 * (out) shr_mdb_elem_bank_index_t *count = where to put the count 3040 * 3041 * Return 3042 * bcm_error_t cast as int 3043 * _SHR_E_NONE if successful 3044 * _SHR_E_* otherwise as appropriate 3045 * 3046 * Notes 3047 * none 3048 */ 3049 int 3050 shr_mdb_block_size_get(shr_mdb_list_handle_t handle, 3051 shr_mdb_elem_index_t block, 3052 shr_mdb_elem_bank_index_t *count) 3053 { 3054 int result; 3055 3056 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3057 (BSL_META("(%08X,%08X,*) enter\n"), 3058 PTR_TO_INT(handle), 3059 block)); 3060 3061 _MDB_VALID_CHECK(handle); 3062 if (!count) { 3063 LOG_ERROR(BSL_LS_SOC_COMMON, 3064 (BSL_META("NULL is unacceptable as count pointer\n"))); 3065 return _SHR_E_PARAM; 3066 } 3067 _MDB_LOCK_TAKE(handle); 3068 result = _mdb_block_size_get(handle, block, count); 3069 _MDB_LOCK_GIVE(handle); 3070 3071 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3072 (BSL_META("(%08X,%08X,&(%d)) return %d (%s)\n"), 3073 PTR_TO_INT(handle), 3074 block, 3075 *count, 3076 result, 3077 _SHR_ERRMSG(result))); 3078 return result; 3079 } 3080 3081 /* 3082 * Function 3083 * shr_mdb_list_insert 3084 * 3085 * Purpose 3086 * Insert a block of elements to a user list. 3087 * 3088 * Arguments 3089 * (in) shr_mdb_list_handle_t handle = the handle 3090 * (in) shr_mdb_elem_bank_index_t list = the user list on which to insert 3091 * (in) shr_mdb_elem_index_t block = the block 3092 * 3093 * Return 3094 * bcm_error_t cast as int 3095 * _SHR_E_NONE if successful 3096 * _SHR_E_* otherwise as appropriate 3097 * 3098 * Notes 3099 * none 3100 */ 3101 int 3102 shr_mdb_list_insert(shr_mdb_list_handle_t handle, 3103 shr_mdb_elem_bank_index_t list, 3104 shr_mdb_elem_index_t block) 3105 { 3106 int result; 3107 3108 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3109 (BSL_META("(%08X,%d,%08X) enter\n"), 3110 PTR_TO_INT(handle), 3111 list, 3112 block)); 3113 3114 _MDB_VALID_CHECK(handle); 3115 _MDB_LOCK_TAKE(handle); 3116 result = _mdb_user_list_insert(handle, list, block); 3117 _MDB_LOCK_GIVE(handle); 3118 3119 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3120 (BSL_META("(%08X,%d,%08X) return %d (%s)\n"), 3121 PTR_TO_INT(handle), 3122 list, 3123 block, 3124 result, 3125 _SHR_ERRMSG(result))); 3126 return result; 3127 } 3128 3129 /* 3130 * Function 3131 * shr_mdb_list_remove 3132 * 3133 * Purpose 3134 * Insert a block of elements to a user list. 3135 * 3136 * Arguments 3137 * (in) shr_mdb_list_handle_t handle = the handle 3138 * (in) shr_mdb_elem_index_t block = the block 3139 * 3140 * Return 3141 * bcm_error_t cast as int 3142 * _SHR_E_NONE if successful 3143 * _SHR_E_* otherwise as appropriate 3144 * 3145 * Notes 3146 * none 3147 */ 3148 int 3149 shr_mdb_list_remove(shr_mdb_list_handle_t handle, 3150 shr_mdb_elem_index_t block) 3151 { 3152 int result; 3153 3154 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3155 (BSL_META("(%08X,%08X) enter\n"), 3156 PTR_TO_INT(handle), 3157 block)); 3158 3159 _MDB_VALID_CHECK(handle); 3160 _MDB_LOCK_TAKE(handle); 3161 result = _mdb_user_list_remove(handle, block); 3162 _MDB_LOCK_GIVE(handle); 3163 3164 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3165 (BSL_META("(%08X,%08X) return %d (%s)\n"), 3166 PTR_TO_INT(handle), 3167 block, 3168 result, 3169 _SHR_ERRMSG(result))); 3170 return result; 3171 } 3172 3173 /* 3174 * Function 3175 * shr_mdb_list_get 3176 * 3177 * Purpose 3178 * Get the user list to which a block belongs. 3179 * 3180 * Arguments 3181 * (in) shr_mdb_list_handle_t handle = the handle 3182 * (in) shr_mdb_elem_index_t *block = the block to check 3183 * (out) shr_mdb_elem_bank_index_t *list = where to put the user list 3184 * 3185 * Return 3186 * bcm_error_t cast as int 3187 * _SHR_E_NONE if successful 3188 * _SHR_E_* otherwise as appropriate 3189 * 3190 * Notes 3191 * none 3192 */ 3193 int 3194 shr_mdb_list_get(shr_mdb_list_handle_t handle, 3195 shr_mdb_elem_index_t block, 3196 shr_mdb_elem_bank_index_t *list) 3197 { 3198 int result; 3199 3200 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3201 (BSL_META("(%08X,%08X,*) enter\n"), 3202 PTR_TO_INT(handle), 3203 block)); 3204 3205 _MDB_VALID_CHECK(handle); 3206 if (!list) { 3207 LOG_ERROR(BSL_LS_SOC_COMMON, 3208 (BSL_META("NULL is unacceptable as list pointer\n"))); 3209 return _SHR_E_PARAM; 3210 } 3211 _MDB_LOCK_TAKE(handle); 3212 result = _mdb_user_list_get(handle, block, list); 3213 _MDB_LOCK_GIVE(handle); 3214 3215 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3216 (BSL_META("(%08X,%08X,&(%d)) return %d (%s)\n"), 3217 PTR_TO_INT(handle), 3218 block, 3219 *list, 3220 result, 3221 _SHR_ERRMSG(result))); 3222 return result; 3223 } 3224 3225 /* 3226 * Function 3227 * shr_mdb_list_head 3228 * 3229 * Purpose 3230 * Get the head block of a user list. 3231 * 3232 * Arguments 3233 * (in) shr_mdb_list_handle_t handle = the handle 3234 * (in) shr_mdb_elem_bank_index_t list = the user list on which to insert 3235 * (in) shr_mdb_elem_index_t *head = where to put the head 3236 * 3237 * Return 3238 * bcm_error_t cast as int 3239 * _SHR_E_NONE if successful 3240 * _SHR_E_* otherwise as appropriate 3241 * 3242 * Notes 3243 * none 3244 */ 3245 int 3246 shr_mdb_list_head(shr_mdb_list_handle_t handle, 3247 shr_mdb_elem_bank_index_t list, 3248 shr_mdb_elem_index_t *head) 3249 { 3250 int result; 3251 3252 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3253 (BSL_META("(%08X,%d,*) enter\n"), 3254 PTR_TO_INT(handle), 3255 list)); 3256 3257 _MDB_VALID_CHECK(handle); 3258 if (!head) { 3259 LOG_ERROR(BSL_LS_SOC_COMMON, 3260 (BSL_META("NULL is unacceptable as head pointer\n"))); 3261 return _SHR_E_PARAM; 3262 } 3263 _MDB_LOCK_TAKE(handle); 3264 result = _mdb_user_list_head(handle, list, head); 3265 _MDB_LOCK_GIVE(handle); 3266 3267 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3268 (BSL_META("(%08X,%d,&(%08X)) return %d (%s)\n"), 3269 PTR_TO_INT(handle), 3270 list, 3271 *head, 3272 result, 3273 _SHR_ERRMSG(result))); 3274 return result; 3275 } 3276 3277 /* 3278 * Function 3279 * shr_mdb_list_tail 3280 * 3281 * Purpose 3282 * Get the tail block of a user list. 3283 * 3284 * Arguments 3285 * (in) shr_mdb_list_handle_t handle = the handle 3286 * (in) shr_mdb_elem_bank_index_t list = the user list on which to insert 3287 * (in) shr_mdb_elem_index_t *tail = where to put the tail 3288 * 3289 * Return 3290 * bcm_error_t cast as int 3291 * _SHR_E_NONE if successful 3292 * _SHR_E_* otherwise as appropriate 3293 * 3294 * Notes 3295 * none 3296 */ 3297 int 3298 shr_mdb_list_tail(shr_mdb_list_handle_t handle, 3299 shr_mdb_elem_bank_index_t list, 3300 shr_mdb_elem_index_t *tail) 3301 { 3302 int result; 3303 3304 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3305 (BSL_META("(%08X,%d,*) enter\n"), 3306 PTR_TO_INT(handle), 3307 list)); 3308 3309 _MDB_VALID_CHECK(handle); 3310 if (!tail) { 3311 LOG_ERROR(BSL_LS_SOC_COMMON, 3312 (BSL_META("NULL is unacceptable as tail pointer\n"))); 3313 return _SHR_E_PARAM; 3314 } 3315 _MDB_LOCK_TAKE(handle); 3316 result = _mdb_user_list_tail(handle, list, tail); 3317 _MDB_LOCK_GIVE(handle); 3318 3319 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3320 (BSL_META("(%08X,%d,&(%08X)) return %d (%s)\n"), 3321 PTR_TO_INT(handle), 3322 list, 3323 *tail, 3324 result, 3325 _SHR_ERRMSG(result))); 3326 return result; 3327 } 3328 3329 /* 3330 * Function 3331 * shr_mdb_list_pred 3332 * 3333 * Purpose 3334 * Get the predecessor of a block in its list. 3335 * 3336 * Arguments 3337 * (in) shr_mdb_list_handle_t handle = the handle 3338 * (in) shr_mdb_elem_index_t block = the block 3339 * (in) shr_mdb_elem_index_t *pred = where to put the predecessor 3340 * 3341 * Return 3342 * bcm_error_t cast as int 3343 * _SHR_E_NONE if successful 3344 * _SHR_E_* otherwise as appropriate 3345 * 3346 * Notes 3347 * none 3348 */ 3349 int 3350 shr_mdb_list_pred(shr_mdb_list_handle_t handle, 3351 shr_mdb_elem_index_t block, 3352 shr_mdb_elem_index_t *pred) 3353 { 3354 int result; 3355 3356 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3357 (BSL_META("(%08X,%08X,*) enter\n"), 3358 PTR_TO_INT(handle), 3359 block)); 3360 3361 _MDB_VALID_CHECK(handle); 3362 if (!pred) { 3363 LOG_ERROR(BSL_LS_SOC_COMMON, 3364 (BSL_META("NULL is unacceptable as predecessor pointer\n"))); 3365 return _SHR_E_PARAM; 3366 } 3367 _MDB_LOCK_TAKE(handle); 3368 result = _mdb_list_pred(handle, block, pred); 3369 _MDB_LOCK_GIVE(handle); 3370 3371 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3372 (BSL_META("(%08X,%08X,&(%08X)) return %d (%s)\n"), 3373 PTR_TO_INT(handle), 3374 block, 3375 *pred, 3376 result, 3377 _SHR_ERRMSG(result))); 3378 return result; 3379 } 3380 3381 /* 3382 * Function 3383 * shr_mdb_list_succ 3384 * 3385 * Purpose 3386 * Get the successor of a block in its list. 3387 * 3388 * Arguments 3389 * (in) shr_mdb_list_handle_t handle = the handle 3390 * (in) shr_mdb_elem_index_t block = the block 3391 * (in) shr_mdb_elem_index_t *succ = where to put the successor 3392 * 3393 * Return 3394 * bcm_error_t cast as int 3395 * _SHR_E_NONE if successful 3396 * _SHR_E_* otherwise as appropriate 3397 * 3398 * Notes 3399 * none 3400 */ 3401 int 3402 shr_mdb_list_succ(shr_mdb_list_handle_t handle, 3403 shr_mdb_elem_index_t block, 3404 shr_mdb_elem_index_t *succ) 3405 { 3406 int result; 3407 3408 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3409 (BSL_META("(%08X,%08X,*) enter\n"), 3410 PTR_TO_INT(handle), 3411 block)); 3412 3413 _MDB_VALID_CHECK(handle); 3414 if (!succ) { 3415 LOG_ERROR(BSL_LS_SOC_COMMON, 3416 (BSL_META("NULL is unacceptable as predecessor pointer\n"))); 3417 return _SHR_E_PARAM; 3418 } 3419 _MDB_LOCK_TAKE(handle); 3420 result = _mdb_list_succ(handle, block, succ); 3421 _MDB_LOCK_GIVE(handle); 3422 3423 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3424 (BSL_META("(%08X,%08X,&(%08X)) return %d (%s)\n"), 3425 PTR_TO_INT(handle), 3426 block, 3427 *succ, 3428 result, 3429 _SHR_ERRMSG(result))); 3430 return result; 3431 } 3432 3433 /* 3434 * Function 3435 * shr_mdb_list_purge 3436 * 3437 * Purpose 3438 * Free all blocks on the user list. 3439 * 3440 * Arguments 3441 * (in) shr_mdb_list_handle_t handle = the handle 3442 * (in) shr_mdb_elem_bank_index_t list = the list to purge 3443 * 3444 * Return 3445 * bcm_error_t cast as int 3446 * _SHR_E_NONE if successful 3447 * _SHR_E_* otherwise as appropriate 3448 * 3449 * Notes 3450 * none 3451 */ 3452 int 3453 shr_mdb_list_purge(shr_mdb_list_handle_t handle, 3454 shr_mdb_elem_bank_index_t list) 3455 { 3456 int result; 3457 3458 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3459 (BSL_META("(%08X,%d) enter\n"), 3460 PTR_TO_INT(handle), 3461 list)); 3462 3463 _MDB_VALID_CHECK(handle); 3464 _MDB_LOCK_TAKE(handle); 3465 result = _mdb_user_list_purge(handle, list); 3466 _MDB_LOCK_GIVE(handle); 3467 3468 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3469 (BSL_META("(%08X,%d) return %d (%s)\n"), 3470 PTR_TO_INT(handle), 3471 list, 3472 result, 3473 _SHR_ERRMSG(result))); 3474 return result; 3475 } 3476 3477 /* 3478 * Function 3479 * shr_mdb_block_info 3480 * 3481 * Purpose 3482 * Get information about a block 3483 * 3484 * Arguments 3485 * (in) shr_mdb_list_handle_t handle = the handle 3486 * (in) shr_mdb_elem_index_t block = an element in the block 3487 * (out) shr_mdb_block_info_t *blockInfo = ptr to where to put list info 3488 * 3489 * Return 3490 * bcm_error_t cast as int 3491 * _SHR_E_NONE if successful 3492 * _SHR_E_* otherwise as appropriate 3493 * 3494 * Notes 3495 * This only supports allocated blocks, not free blocks. 3496 */ 3497 int 3498 shr_mdb_block_info(shr_mdb_list_handle_t handle, 3499 shr_mdb_elem_index_t block, 3500 shr_mdb_block_info_t *blockInfo) 3501 { 3502 int result = _SHR_E_NONE; 3503 shr_mdb_elem_index_t head; 3504 3505 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3506 (BSL_META("(%08X,%08X,*) enter\n"), 3507 PTR_TO_INT(handle), 3508 block)); 3509 3510 if (!blockInfo) { 3511 LOG_ERROR(BSL_LS_SOC_COMMON, 3512 (BSL_META("NULL pointer unacceptable for" 3513 " outbound argument\n"))); 3514 return _SHR_E_PARAM; 3515 } 3516 _MDB_VALID_CHECK(handle); 3517 _MDB_LOCK_TAKE(handle); 3518 3519 head = block - handle->low; 3520 if ((block < handle->low) || 3521 (head >= handle->count)) { 3522 LOG_ERROR(BSL_LS_SOC_COMMON, 3523 (BSL_META("element %08X is not valid\n"), 3524 block)); 3525 /* don't ask me why, but BCM likes NOT_FOUND for INVALID_ID */ 3526 result = _SHR_E_NOT_FOUND; 3527 } 3528 if (_SHR_E_NONE == result) { 3529 /* find the head of the block */ 3530 _mdb_block_head_get(handle, &head); 3531 if (handle->elem[head].list < handle->freeLists) { 3532 /* this thing is free; still an error */ 3533 LOG_ERROR(BSL_LS_SOC_COMMON, 3534 (BSL_META("element %08X is free\n"), 3535 block)); 3536 result = _SHR_E_NOT_FOUND; 3537 } 3538 } 3539 if (_SHR_E_NONE == result) { 3540 /* fill in the data for the block */ 3541 blockInfo->head = head + handle->low; 3542 blockInfo->list = handle->elem[head].list; 3543 blockInfo->size = handle->elem[head].count; 3544 } 3545 3546 _MDB_LOCK_GIVE(handle); 3547 3548 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3549 (BSL_META("(%08X,%d,&{%d,%d,%d}) return %d (%s)\n"), 3550 PTR_TO_INT(handle), 3551 block, 3552 blockInfo->head, 3553 blockInfo->list, 3554 blockInfo->size, 3555 result, 3556 _SHR_ERRMSG(result))); 3557 return result; 3558 } 3559 3560 /* 3561 * Function 3562 * shr_mdb_block_check_all 3563 * 3564 * Purpose 3565 * Find out whether a group of elements is free, used by a single block, 3566 * used by more than one block, or a combination of free and used. 3567 * 3568 * Arguments 3569 * (in) shr_mdb_list_handle_t handle = the handle 3570 * (in) shr_mdb_elem_index_t first = first element to check 3571 * (in) shr_mdb_elem_bank_index_t count = number of elements to check 3572 * 3573 * Return 3574 * bcm_error_t cast as int 3575 * _SHR_E_EMPTY if none of the elements are in use 3576 * _SHR_E_FULL if all of the elements are in use 3577 * _SHR_E_CONFIG if elements are in use but block(s) do not match 3578 * _SHR_E_EXISTS if some of the elements are in use but not all of them 3579 * _SHR_E_PARAM if any of the elements is not valid 3580 * _SHR_E_* otherwise as appropriate 3581 * 3582 * Notes 3583 * _SHR_E_NONE is not returned here. 3584 */ 3585 int 3586 shr_mdb_block_check_all(shr_mdb_list_handle_t handle, 3587 shr_mdb_elem_index_t first, 3588 shr_mdb_elem_bank_index_t count) 3589 { 3590 int result = _SHR_E_NONE; 3591 shr_mdb_elem_index_t head; 3592 shr_mdb_elem_bank_index_t dist; 3593 3594 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3595 (BSL_META("(%08X,%08X,%d) enter\n"), 3596 PTR_TO_INT(handle), 3597 first, 3598 count)); 3599 3600 _MDB_VALID_CHECK(handle); 3601 _MDB_LOCK_TAKE(handle); 3602 head = first - handle->low; 3603 if ((first < handle->low) || 3604 ((head + count) > handle->count)) { 3605 LOG_ERROR(BSL_LS_SOC_COMMON, 3606 (BSL_META("element range %08X..%08X is not valid\n"), 3607 first, 3608 count)); 3609 /* for this function, we specifically want _SHR_E_PARAM */ 3610 result = _SHR_E_PARAM; 3611 } 3612 if (_SHR_E_NONE == result) { 3613 /* find the head of the block */ 3614 _mdb_block_head_get(handle, &head); 3615 if (handle->elem[head].list < handle->freeLists) { 3616 /* this block is free */ 3617 result = _SHR_E_EMPTY; 3618 /* scan to at least end of specified block */ 3619 dist = 0; 3620 do { 3621 dist += handle->elem[head].count; 3622 head += handle->elem[head].count; 3623 if (handle->elem[head].list >= handle->freeLists) { 3624 /* this block is not free */ 3625 LOG_ERROR(BSL_LS_SOC_COMMON, 3626 (BSL_META("block including element %08X (%d elems)" 3627 " is partially free and partially used\n"), 3628 first, 3629 count)); 3630 result = _SHR_E_EXISTS; 3631 break; 3632 } 3633 } while (dist < count); 3634 } else { /* if (handle->elem[head].list < handle->freeLists) */ 3635 /* this block is in use */ 3636 if (((head + handle->low) == first) && 3637 (count == handle->elem[head].count)) { 3638 /* block is as caller expected it to be */ 3639 result = _SHR_E_FULL; 3640 } else { 3641 /* block exists but not as caller expected it to be */ 3642 LOG_ERROR(BSL_LS_SOC_COMMON, 3643 (BSL_META("block including element %08X (%d elems)" 3644 " actually starts at %08X with %d elems\n"), 3645 first, 3646 count, 3647 head + handle->low, 3648 handle->elem[head].count)); 3649 result = _SHR_E_CONFIG; 3650 } 3651 } /* if (handle->elem[head].list < handle->freeLists) */ 3652 } /* if (_SHR_E_NONE == result) */ 3653 3654 _MDB_LOCK_GIVE(handle); 3655 3656 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3657 (BSL_META("(%08X,%08X,%d) return %d (%s)\n"), 3658 PTR_TO_INT(handle), 3659 first, 3660 count, 3661 result, 3662 _SHR_ERRMSG(result))); 3663 return result; 3664 } 3665 3666 /* 3667 * Function 3668 * shr_mdb_list_info 3669 * 3670 * Purpose 3671 * Get information about a list (user or free) 3672 * 3673 * Arguments 3674 * (in) shr_mdb_list_handle_t handle = the handle 3675 * (in) shr_mdb_elem_bank_index_t list = the list to check 3676 * (in) int free = TRUE to query a free list, FALSE for a user list 3677 * (out) shr_mdb_list_info_t *listInfo = ptr to where to put list info 3678 * 3679 * Return 3680 * bcm_error_t cast as int 3681 * _SHR_E_NONE if successful 3682 * _SHR_E_* otherwise as appropriate 3683 * 3684 * Notes 3685 * none 3686 */ 3687 int 3688 shr_mdb_list_info(shr_mdb_list_handle_t handle, 3689 shr_mdb_elem_bank_index_t list, 3690 int free, 3691 shr_mdb_list_info_t *listInfo) 3692 { 3693 int result = _SHR_E_NONE; 3694 3695 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3696 (BSL_META("(%08X,%d,%s,*) enter\n"), 3697 PTR_TO_INT(handle), 3698 list, 3699 free?"Free":"User")); 3700 3701 if (!listInfo) { 3702 LOG_ERROR(BSL_LS_SOC_COMMON, 3703 (BSL_META("NULL pointer unacceptable for" 3704 " outbound argument\n"))); 3705 return _SHR_E_PARAM; 3706 } 3707 _MDB_VALID_CHECK(handle); 3708 _MDB_LOCK_TAKE(handle); 3709 3710 if (free) { 3711 if (list >= handle->freeLists) { 3712 LOG_ERROR(BSL_LS_SOC_COMMON, 3713 (BSL_META("there are not %d free lists\n"), 3714 list)); 3715 /* don't ask me why, but BCM likes NOT_FOUND for INVALID_ID */ 3716 result = _SHR_E_NOT_FOUND; 3717 } 3718 } else { 3719 if (list >= handle->userLists) { 3720 LOG_ERROR(BSL_LS_SOC_COMMON, 3721 (BSL_META("there are not %d user lists\n"), 3722 list)); 3723 /* don't ask me why, but BCM likes NOT_FOUND for INVALID_ID */ 3724 result = _SHR_E_NOT_FOUND; 3725 } 3726 list += handle->freeLists; 3727 } 3728 if (_SHR_E_NONE == result) { 3729 /* fill in the details about the list */ 3730 listInfo->block_size = handle->list[list].elemsBlock; 3731 listInfo->blocks = handle->list[list].blocks; 3732 listInfo->elements = handle->list[list].elems; 3733 } 3734 3735 _MDB_LOCK_GIVE(handle); 3736 3737 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3738 (BSL_META("(%08X,%d,%s,*) return %d (%s)\n"), 3739 PTR_TO_INT(handle), 3740 list, 3741 free?"Free":"User", 3742 result, 3743 _SHR_ERRMSG(result))); 3744 return result; 3745 } 3746 3747 /* 3748 * Function 3749 * shr_mdb_info 3750 * 3751 * Purpose 3752 * Get information about an mdb object 3753 * 3754 * Arguments 3755 * (in) shr_mdb_list_handle_t handle = the handle 3756 * (out) shr_mdb_list_info_t *mdbInfo = where to put mdb information 3757 * 3758 * Return 3759 * bcm_error_t cast as int 3760 * _SHR_E_NONE if successful 3761 * _SHR_E_* otherwise as appropriate 3762 * 3763 * Notes 3764 * none 3765 */ 3766 int 3767 shr_mdb_info(shr_mdb_list_handle_t handle, 3768 shr_mdb_info_t *mdbInfo) 3769 { 3770 shr_mdb_elem_bank_index_t list; 3771 3772 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3773 (BSL_META("(%08X,*) enter\n"), 3774 PTR_TO_INT(handle))); 3775 3776 if (!mdbInfo) { 3777 LOG_ERROR(BSL_LS_SOC_COMMON, 3778 (BSL_META("NULL pointer unacceptable for" 3779 " outbound argument\n"))); 3780 return _SHR_E_PARAM; 3781 } 3782 _MDB_VALID_CHECK(handle); 3783 _MDB_LOCK_TAKE(handle); 3784 3785 mdbInfo->first = handle->low; 3786 mdbInfo->last = handle->low + handle->count - 1; 3787 mdbInfo->free_lists = handle->freeLists; 3788 mdbInfo->user_lists = handle->userLists; 3789 mdbInfo->bank_size = 1 << handle->bankShift; 3790 mdbInfo->lock = !(!(handle->lock)); 3791 mdbInfo->free_blocks = 0; 3792 mdbInfo->free_elems = 0; 3793 for (list = 0; list < handle->freeLists; list++) { 3794 mdbInfo->free_blocks += handle->list[list].blocks; 3795 mdbInfo->free_elems += handle->list[list].elems; 3796 } 3797 3798 _MDB_LOCK_GIVE(handle); 3799 3800 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3801 (BSL_META("(%08X,*) return %d (%s)\n"), 3802 PTR_TO_INT(handle), 3803 _SHR_E_NONE, 3804 _SHR_ERRMSG(_SHR_E_NONE))); 3805 return _SHR_E_NONE; 3806 } 3807 3808 /* 3809 * Function 3810 * shr_mdb_allocmode_get 3811 * 3812 * Purpose 3813 * Get an mdb object's current allocation mode 3814 * 3815 * Arguments 3816 * (in) shr_mdb_list_handle_t handle = the handle 3817 * (out) shr_mdb_alloc_pref_t *allocmode = where to put alloc mode 3818 * 3819 * Return 3820 * bcm_error_t cast as int 3821 * _SHR_E_NONE if successful 3822 * _SHR_E_* otherwise as appropriate 3823 * 3824 * Notes 3825 * none 3826 */ 3827 int 3828 shr_mdb_allocmode_get(shr_mdb_list_handle_t handle, 3829 shr_mdb_alloc_pref_t *allocmode) 3830 { 3831 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3832 (BSL_META("(%08X,*) enter\n"), 3833 PTR_TO_INT(handle))); 3834 3835 if (!allocmode) { 3836 LOG_ERROR(BSL_LS_SOC_COMMON, 3837 (BSL_META("NULL pointer unacceptable for" 3838 " outbound argument\n"))); 3839 return _SHR_E_PARAM; 3840 } 3841 _MDB_VALID_CHECK(handle); 3842 _MDB_LOCK_TAKE(handle); 3843 3844 *allocmode = handle->allocPref; 3845 3846 _MDB_LOCK_GIVE(handle); 3847 3848 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3849 (BSL_META("(%08X,&(%08X)) return %d (%s)\n"), 3850 PTR_TO_INT(handle), 3851 *allocmode, 3852 _SHR_E_NONE, 3853 _SHR_ERRMSG(_SHR_E_NONE))); 3854 return _SHR_E_NONE; 3855 } 3856 3857 /* 3858 * Function 3859 * shr_mdb_allocmode_set 3860 * 3861 * Purpose 3862 * Set an mdb object's current allocation mode 3863 * 3864 * Arguments 3865 * (in) shr_mdb_list_handle_t handle = the handle 3866 * (in) shr_mdb_alloc_pref_t allocmode = new alloc mode 3867 * 3868 * Return 3869 * bcm_error_t cast as int 3870 * _SHR_E_NONE if successful 3871 * _SHR_E_* otherwise as appropriate 3872 * 3873 * Notes 3874 * none 3875 */ 3876 int 3877 shr_mdb_allocmode_set(shr_mdb_list_handle_t handle, 3878 shr_mdb_alloc_pref_t allocmode) 3879 { 3880 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3881 (BSL_META("(%08X,*) enter\n"), 3882 PTR_TO_INT(handle))); 3883 3884 /* verify the arguments */ 3885 switch (allocmode & shr_mdb_alloc_bank_mask) { 3886 case shr_mdb_alloc_bank_first: 3887 case shr_mdb_alloc_bank_high: 3888 case shr_mdb_alloc_bank_low: 3889 /* all of these are good */ 3890 break; 3891 default: 3892 LOG_ERROR(BSL_LS_SOC_COMMON, 3893 (BSL_META("invalid alloc mechanism %d\n"), 3894 allocmode & shr_mdb_alloc_bank_mask)); 3895 return _SHR_E_PARAM; 3896 } 3897 if (!(allocmode & shr_mdb_join_alloc_and_free)) { 3898 LOG_ERROR(BSL_LS_SOC_COMMON, 3899 (BSL_META("must join on free, alloc, or both\n"))); 3900 return _SHR_E_PARAM; 3901 } 3902 if (!(allocmode & shr_mdb_join_high_and_low)) { 3903 LOG_ERROR(BSL_LS_SOC_COMMON, 3904 (BSL_META("must join high, low, or both\n"))); 3905 return _SHR_E_PARAM; 3906 } 3907 if (allocmode & (~(shr_mdb_alloc_bank_mask | 3908 shr_mdb_alloc_block_high | 3909 shr_mdb_free_block_high | 3910 shr_mdb_join_alloc_and_free | 3911 shr_mdb_join_high_and_low))) { 3912 LOG_ERROR(BSL_LS_SOC_COMMON, 3913 (BSL_META("invalid bits are set in allocmode (%08X)\n"), 3914 allocmode & (~(shr_mdb_alloc_bank_mask | 3915 shr_mdb_alloc_block_high | 3916 shr_mdb_free_block_high | 3917 shr_mdb_join_alloc_and_free | 3918 shr_mdb_join_high_and_low)))); 3919 return _SHR_E_PARAM; 3920 } 3921 3922 _MDB_VALID_CHECK(handle); 3923 _MDB_LOCK_TAKE(handle); 3924 3925 handle->allocPref = allocmode; 3926 3927 _MDB_LOCK_GIVE(handle); 3928 3929 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3930 (BSL_META("(%08X,&(%08X)) return %d (%s)\n"), 3931 PTR_TO_INT(handle), 3932 allocmode, 3933 _SHR_E_NONE, 3934 _SHR_ERRMSG(_SHR_E_NONE))); 3935 return _SHR_E_NONE; 3936 } 3937 3938 /* 3939 * Function 3940 * shr_mdb_all_free_to_user_list 3941 * 3942 * Purpose 3943 * Collect all free blocks and place them on a specific user list 3944 * 3945 * Arguments 3946 * (in) shr_mdb_list_handle_t handle = the handle 3947 * (in) shr_mdb_elem_bank_index_t list = the target user list 3948 * 3949 * Return 3950 * bcm_error_t cast as int 3951 * _SHR_E_NONE if successful 3952 * _SHR_E_* otherwise as appropriate 3953 * 3954 * Notes 3955 * none 3956 */ 3957 int 3958 shr_mdb_all_free_to_user_list(shr_mdb_list_handle_t handle, 3959 shr_mdb_elem_bank_index_t userList) 3960 { 3961 int result = _SHR_E_NONE; 3962 shr_mdb_elem_bank_index_t list; 3963 shr_mdb_elem_bank_index_t offs; 3964 shr_mdb_elem_index_t bank; 3965 shr_mdb_elem_index_t block = ~0; 3966 3967 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3968 (BSL_META("(%08X,%d) enter\n"), 3969 PTR_TO_INT(handle), 3970 userList)); 3971 3972 _MDB_VALID_CHECK(handle); 3973 _MDB_LOCK_TAKE(handle); 3974 3975 if (userList < handle->userLists) { 3976 /* for each free list */ 3977 for (list = 0; 3978 list < handle->freeLists; 3979 list++) { 3980 /* while the free list contains blocks */ 3981 while (handle->list[list].blocks) { 3982 /* find the first block on this list */ 3983 bank = handle->list[list].head; 3984 offs = _MDB_LIST_BANK_DESC(*handle, list, bank).head; 3985 block = (bank << handle->bankShift) | offs; 3986 /* take the block out of its list */ 3987 _mdb_list_remove(handle, block); 3988 _mdb_list_insert(handle, block, userList + handle->freeLists); 3989 } /* while (the free list has blocks) */ 3990 } /* for (each free list) */ 3991 } else { 3992 LOG_ERROR(BSL_LS_SOC_COMMON, 3993 (BSL_META("user list %d invalid for mdb %08X\n"), 3994 userList, 3995 PTR_TO_INT(handle))); 3996 result = _SHR_E_PARAM; 3997 } 3998 3999 _MDB_LOCK_GIVE(handle); 4000 4001 LOG_VERBOSE(BSL_LS_SOC_COMMON, 4002 (BSL_META("(%08X,%d) return %d (%s)\n"), 4003 PTR_TO_INT(handle), 4004 userList, 4005 result, 4006 _SHR_ERRMSG(result))); 4007 return result; 4008 } 4009 4010 4011 4012 4013 4014