idxres_afl.c (119182B)
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: Aligned Indexed resource management, using banked lists 8 */ 9 10 /* 11 * Older versions of this code imposed a lock on created lists. This seems 12 * wasteful because list management should only occur at times where the 13 * applicable resources (including the list) are protected by a lock at a 14 * higher level in the code. 15 * 16 * Set _SHR_AIDXRES_SELF_LOCKING to TRUE to impose a lock on created lists. 17 * Doing this was the default behaviour for a long time, but it uses more 18 * resources and takes longer to manipulate lists due to the locking overhead. 19 * 20 * Set _SHR_AIDXRES_SELF_LOCKING to FALSE to not do this. Not doing it will 21 * avoid setting up a lock, and skip the overhead of tracking the lock, 22 * reducing resource usage marginally. 23 */ 24 #define _SHR_AIDXRES_SELF_LOCKING FALSE 25 26 /* 27 * Please see the idxres_fl.c file for a description of the banked lists 28 * concept and implementation. This module enhances that to provide some 29 * additional features. Concepts that are applicable to both models are not 30 * discussed here -- only the enhancements. 31 * 32 * This is an implementation of a high-speed doubly-linked-list based free 33 * list manager. This implmentation, while a little more expensive in both 34 * memory and time than the one in idxres_fl, adds certain additional 35 * features that are necessary in some places: 36 * 37 * * Allocation of contiguous blocks. Blocks of elements can be allocated 38 * contiguously rather than sparsely (as the set of elements operation both 39 * here and in the other module implements). 40 * 41 * * Alignment of blocks. Blocks of elements are aligned to either the power 42 * of two elements that is the size of the block, or the next power of two 43 * up if the block is not an even power of two elements in size. 44 * 45 * The overall performance drops slightly (from all case O(1) to a typical 46 * case of O(p), where p is the power to which two must be raised that is 47 * equal to the largest block size supported by the list; if you prefer, it 48 * can be expressed as O(log2(maxBlockSize)) instead), and the memory 49 * requirements increase substantially (4 times the size of the other module 50 * for the main list plus sublist overhead (about 2 times the internal list 51 * overhead of the other module) plus some minor additional overhead for the 52 * entire list). What this means is that you probably don't want to use this 53 * sort of list to manage a resource that neither needs contiguous blocks nor 54 * needs aligned blocks (use the other module in this case). 55 * 56 * Variable block size is supported and managed without massive time overhead 57 * by the use of sublists to keep track of the various sized free blocks. In 58 * order to keep memory use down, free block lists are only provided for 59 * blocks that contain an integral power of two elements and are properly 60 * aligned to their power of two (this also maintains alignment). Since free 61 * blocks are always sized as aligned power-of-two elements, there are p (as 62 * defined above) sublists. This has the upshot that larger maximum block 63 * sizes will increase the total size in memory of the list. 64 * 65 * Also, the 'scaling' feature is removed; it was believed to be useful in 66 * the other module because if you always allocated blocks of some constant 67 * size, you could just use the other module with scaling enabled. Here, the 68 * caller specifies the exact block size and non-power-of-two block sizes are 69 * supported just as well as power-of-two block sizes. It is therefore not 70 * considered helpful for this module (actually, it's somewhat confusing in 71 * this case), and not supported here. The other module supported using any 72 * value that was covered by a scaled element when freeing it; this module 73 * requires that the first element of a block be provided when freeing (this 74 * could be changed but it would make the free operation an O(max_blocksize) 75 * instead of O(log2(max_blocksize)) operation. 76 * 77 * Blocks are allocated using a method approximating best-fit: they are 78 * placed in a smallest necessary free block. Here, necessary is defined as 79 * being the exact size of the block if it is an integral power of two, or 80 * the next integral power of two up if it is not. If there are no free 81 * blocks of the necessary size, a larger one will be split so to generate at 82 * least one block of the necessary size. When splitting blocks to obtain 83 * blocks of the necessary size, the lower portion is returned to the proper 84 * free sublist(s). Any elements left over from the necessary size (this 85 * only happens if the request is for a block that is not an integral power 86 * of two elements) will be returned to the appropriate free sublist(s), and 87 * these will be the higher numbered elements of the necessary block. 88 * 89 * Blocks are freed by combining them with appropriate neighbouring blocks, 90 * breaking the resulting block into the largest possible blocks (if the 91 * resulting block is not an integral power of two elements in size), and 92 * returning the result of that to the appropriate free sublist(s). 93 * Appropriate in this context is used to indicate that a block would combine 94 * with the to-be-freed block in such a way as to preserve alignment of the 95 * combined block, to increase the size of the blocks into which the result 96 * will be broken down, and to not cross bank boundaries. 97 * 98 * The maximum block power-of-two is specified at list creation time, and can 99 * be up to the number of bits used to represent elements within a bank (that 100 * is, 7 if in byte mode, 15 in doublebyte mode, and 31 in quadbyte mode). 101 * 102 * Memory overhead, as mentioned above, is somewhat higher, and performance 103 * is a little lower, than the single element allocator. You have to trade 104 * something for the ability to manage contiguous blocks and maintain 105 * alignment for blocks... 106 * 107 * 8 16 32 108 * ---------------- ------------- ------------- ------------- 109 * Create Linear(n+p+b) Linear(n+p+b) Linear(n+p+b) 110 * Destroy Linear(n+p+b) Linear(n+p+b) Linear(n+p+b) 111 * Allocate Linear(p+e) Linear(p+e) Linear(p+e) 112 * Free Linear(p+e) Linear(p+e) Linear(p+e) 113 * Status Constant(1) Constant(1) Constant(1) 114 * Reserve Linear(p+e) Linear(p+e) Linear(p+e) 115 * BlockReserve Linear(p+e) Linear(p+e) Linear(p+e) 116 * ---------------- ------------- ------------- ------------- 117 * Size of element 4 8 16 118 * Needed banks (n/128) (n/32768) 1 119 * Max 'p' value 7 15 31 120 * List overhead 52 52 52 121 * Sublist overhead 8+8*b+2*b 8+8*b+4*b 8+8*b+8*b 122 * ---------------- ------------- ------------- ------------- 123 * 124 * In the table above, 'n' is the number of elements total in the list, 'p' 125 * is log2(maxBlockSize), 'b' is the number of banks, and 'e' is the number 126 * of elements in the block being manipulated. 127 * 128 * Note that 'linear' is true for a given list on the performance side: the 129 * values for 'n', 'p', 'b' are set at list creation time, so they will not 130 * vary within a list, but they can vary between lists, and the value 'e' is 131 * specific to a particular call. 132 * 133 * The size data are expressed in bytes, assuming the compiler and platform 134 * pack arrays and records. The list overhead does not include the actual 135 * mutex: it assumes the mutex handle is a pointer to some indetermintate 136 * size object somewhere else. 137 * 138 * Reserve is still somewhat more expensive in terms of time and complexity 139 * than alloc/free, but this is because it has to touch each element in 140 * question multiple times and potentially has to insert and remove blocks to 141 * multiple sublists on each side of the reserved blocks. Blockreserve is 142 * marginally better on time than reserve because it is limited to valid 143 * blocks (so it inherently has a limit for 'e'). It is also useful in that 144 * it reserves the elements as blocks rather than individual. 145 */ 146 147 #include <shared/bsl.h> 148 #include <soc/drv.h> 149 #include <bcm/error.h> 150 #include <shared/idxres_afl.h> 151 152 #ifndef AIDXLIST_BASE 153 154 #if defined(BCM_ESW_SUPPORT) && (defined(BCM_KATANA_SUPPORT) || \ 155 defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)) 156 #define AIDXLIST_BASE 16 157 #else /* defined(BCM_ESW_SUPPORT) && (defined(BCM_KATANA_SUPPORT) || \ 158 defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)) */ 159 #define AIDXLIST_BASE 8 160 #endif /* defined(BCM_ESW_SUPPORT) && (defined(BCM_KATANA_SUPPORT) || \ 161 defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)) */ 162 163 #endif 164 #undef AIDXRES_BITS_ENTRY 165 #if (32 == AIDXLIST_BASE) 166 typedef uint32 _aidxres_list_entry_t; /* an element in a list bank */ 167 #define AIDXRES_FINAL_ENTRY (0xFFFFFFFF) /* final used entry */ 168 #define AIDXRES_USED_ENTRY (0xFFFFFFFE) /* other used entries */ 169 #define AIDXRES_FIRST_ENTRY (0xFFFFFFF1) /* first used entry */ 170 #define AIDXRES_MAX_ENTRY (0x7FFFFFFF) /* max entry value */ 171 #define AIDXRES_BITS_ENTRY (31) /* usable bits per entry */ 172 #define AIDXRES_MAX_BANK (0) /* max bank value */ 173 #define AIDXRES_FORMAT_ENTRY "%08X" /* format for dumping entry */ 174 #define AIDXRES_FORMAT_MASK (0x00) /* mask for entries per line */ 175 #define AIDXRES_BFORMAT_MASK (0x01) /* mask for bnk ent per line */ 176 #endif 177 #if (16 == AIDXLIST_BASE) 178 typedef uint16 _aidxres_list_entry_t; /* an element in a list bank */ 179 #define AIDXRES_FINAL_ENTRY (0xFFFF) /* final used entry */ 180 #define AIDXRES_USED_ENTRY (0xFFFE) /* other used entries */ 181 #define AIDXRES_FIRST_ENTRY (0xFFF1) /* first used entry */ 182 #define AIDXRES_MAX_ENTRY (0x7FFF) /* max entry value */ 183 #define AIDXRES_BITS_ENTRY (15) /* usable bits per entry */ 184 #define AIDXRES_MAX_BANK (0xFFFFul) /* max bank value */ 185 #define AIDXRES_FORMAT_ENTRY "%04X" /* format for dumping entry */ 186 #define AIDXRES_FORMAT_MASK (0x00) /* mask for entries per line */ 187 #define AIDXRES_BFORMAT_MASK (0x01) /* mask for bnk ent per line */ 188 #endif 189 #if (8 == AIDXLIST_BASE) 190 typedef uint8 _aidxres_list_entry_t; /* an element in a list bank */ 191 #define AIDXRES_FINAL_ENTRY (0xFF) /* final used entry */ 192 #define AIDXRES_USED_ENTRY (0xFE) /* other used entries */ 193 #define AIDXRES_FIRST_ENTRY (0xF1) /* first used entry */ 194 #define AIDXRES_MAX_ENTRY (0x7F) /* max entry value */ 195 #define AIDXRES_BITS_ENTRY (7) /* usable bits per entry */ 196 #define AIDXRES_MAX_BANK (0xFFFFFFul) /* max bank value */ 197 #define AIDXRES_FORMAT_ENTRY "%02X" /* format for dumping entry */ 198 #define AIDXRES_FORMAT_MASK (0x01) /* mask for entries per line */ 199 #define AIDXRES_BFORMAT_MASK (0x01) /* mask for bnk ent per line */ 200 #endif 201 /* 202 * Note 4 bits per entry is meant for debugging and testing only; it is more 203 * expensive than 8 bits per entry for total memory allocation and also more 204 * expensive in terms of total processor time, plus it limits the block size 205 * to a maximum of eight elements, but it does make it easier to visualise the 206 * list when debugging. 207 */ 208 #if (4 == AIDXLIST_BASE) 209 typedef uint8 _aidxres_list_entry_t; /* an element in a list bank */ 210 #define AIDXRES_FINAL_ENTRY (0xF) /* final used entry */ 211 #define AIDXRES_USED_ENTRY (0xE) /* other used entries */ 212 #define AIDXRES_FIRST_ENTRY (0xA) /* first used entry */ 213 #define AIDXRES_MAX_ENTRY (0x7) /* max entry value */ 214 #define AIDXRES_BITS_ENTRY (3) /* usable bits per entry */ 215 #define AIDXRES_MAX_BANK (0xFFFFFFFul) /* max bank value */ 216 #define AIDXRES_FORMAT_ENTRY "%01X" /* format for dumping entry */ 217 #define AIDXRES_FORMAT_MASK (0x01) /* mask for entries per line */ 218 #define AIDXRES_BFORMAT_MASK (0x01) /* mask for bnk ent per line */ 219 #endif 220 /* 221 * This just makes sure a valid IDXLIST_BASE is selected above. 222 */ 223 #ifndef AIDXRES_BITS_ENTRY 224 #error AIDXLIST_BASE must be one of: 8; 16; 32. 225 #endif 226 /* 227 * Additional macros using the constants defined in the sections above. These 228 * are not unique per storage size of list entry. 229 */ 230 #define AIDXRES_FINAL_BANK (0xFFFFFFFF) 231 #define AIDXRES_USED_BANK (0xFFFFFFFE) 232 #define AIDXRES_FIRST_BANK (0xFFFFFFF1) 233 234 /* 235 * There are n sublists, where 2^n is the largest single block of elements 236 * that can be allocated by that list. Each sublist contains lists of blocks 237 * that are 2^m elements long, where m is the number of that sublist. 238 * 239 * There are e elements per block, where e is some power of two, so that 2^b 240 * is equal to e. The value n, above, must be equal to or less than the 241 * value of b here. In short, the largest allocation unit must be equal to 242 * or smaller than a single block. 243 * 244 * Each block contains n element sublists. Each of these sublists contains 245 * lists of blocks of elements (first element of a block only) that are of 246 * length and alignment 2^n (as above, where n is the sublist number). 247 */ 248 249 /* 250 * This is a single entry in the list. Since we're keeping alignment and 251 * supporting contiguous allocations larger than one element, we need to know 252 * more about a given element than we need for the simpler case (idxres_fl). 253 * 254 * elem_count indicates the number of elements in a block, but is only 255 * guaranteed to be correct for the first element in a block. For allocated 256 * blocks (not in a sublist), the final element also has the count. Other 257 * elements in a block will have garbage for count. 258 * 259 * sublist indicates which sublist if the element is in a sublist, otherwise 260 * it is AIDXRES_FIRST_ENTRY for the first element in a block, 261 * AIDXRES_USED_ENTRY for the intervening elements in a blocks, and 262 * AIDXRES_FINAL_ENTRY for the final element in a block. 263 * 264 * pref and next are pointers to the previous and next elements in the 265 * sublist, or are garbage for elements not in a sublist. 266 */ 267 typedef struct _aidxres_list_elemdesc_s { 268 _aidxres_list_entry_t elem_count; /* elems in this block */ 269 _aidxres_list_entry_t sublist; /* which sublist */ 270 _aidxres_list_entry_t prev; /* previous element */ 271 _aidxres_list_entry_t next; /* next element */ 272 } _aidxres_list_elemdesc_t; 273 274 /* 275 * There are several lists now -- one for each possible size of block. This 276 * structure contains the data needed to check the list and get/put a block of 277 * elements from/to the list. The data for a single bank is made up of a 278 * bunch of these (one for each power of two less than or equal to the power 279 * of two needed to represent the max block size for the list, rounding up). 280 */ 281 typedef struct _aidxres_list_bank_sublist_s { 282 _aidxres_list_entry_t free_count; /* elements this list */ 283 _aidxres_list_entry_t head; /* head of this list */ 284 } _aidxres_list_bank_sublist_t; 285 286 /* 287 * This structure is how banks participate in sublists. One of these exists 288 * per bank per sublist. 289 */ 290 typedef struct _aidxres_list_bank_s { 291 shr_aidxres_element_t prev; /* previous bank in list */ 292 shr_aidxres_element_t next; /* next bank in list */ 293 } _aidxres_list_bank_t; 294 295 /* 296 * This specifies how [bank,sublist] is converted to [index]. 297 */ 298 #define AIDXRES_BANK_SUBLIST(list,bank,sublist) (((bank)*((list)->sublist_count))+(sublist)) 299 300 /* 301 * This structure describes the list of banks participating in a specific list 302 * of blocks of a specific number of elements. The head is actually the bank 303 * number of the head, not the whole element number. 304 */ 305 typedef struct _aidxres_list_sublist_s { 306 shr_aidxres_element_t free_count; /* elements this list*/ 307 shr_aidxres_element_t head; /* head of this list */ 308 } _aidxres_list_sublist_t; 309 310 /* 311 * This structure describes the entire list. Note that the data pointer does 312 * not point to another memory block; the entire structure is part of the one 313 * large block of memory -- the index, the bank descriptors, and the bank 314 * data are all in the single alloc cell. 315 * 316 * This is here instead of the .h file because we don't want it manipulated 317 * by functions that should be calling the API provided here. 318 */ 319 typedef struct _shr_aidxres_list_s { 320 #if _SHR_AIDXRES_SELF_LOCKING 321 sal_mutex_t lock; /* lock for this list */ 322 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 323 shr_aidxres_element_t first; /* low elem mgd by list */ 324 shr_aidxres_element_t last; /* high elem mgd by list */ 325 shr_aidxres_element_t valid_low; /* low valid element */ 326 shr_aidxres_element_t valid_high; /* high valid element */ 327 shr_aidxres_element_t free_count; /* free elements */ 328 shr_aidxres_element_t alloc_count; /* allocated elements */ 329 shr_aidxres_element_t sublist_count; /* number of sublists */ 330 shr_aidxres_element_t bank_max; /* maximum bank */ 331 shr_aidxres_element_t bank_rem_max; /* final bank max elem */ 332 _aidxres_list_bank_t *bank_list; /* bank list pointer */ 333 _aidxres_list_bank_sublist_t *bank_sublist; /* bank sublist pointer */ 334 _aidxres_list_elemdesc_t *element; /* element pointer */ 335 _aidxres_list_sublist_t sublist[1]; /* sublist information */ 336 /* a sublist descriptor exists for each sublist */ 337 /* a bank descriptor exists for each bank */ 338 /* a bank sublist descriptor exists for each sublist in each bank */ 339 /* an element exists for each element in the list */ 340 } _aidxres_list_t; 341 #define AIDXRES_ELEMENT_BNK(element) ((element) >> AIDXRES_BITS_ENTRY) 342 #define AIDXRES_ELEMENT_IDX(element) ((element) & AIDXRES_MAX_ENTRY) 343 #define AIDXRES_ELEMENT_NUM(bank, entry) (((bank) << AIDXRES_BITS_ENTRY)+(entry)) 344 345 /* 346 * Generally, AIDXRES_DEBUG and AIDXRES_DEBUG_VERBOSE should NOT be defined. 347 * These switch on some debuging information (with AIDXRES_DEBUG_VERBOSE 348 * including state dumps very often). 349 * 350 * The lists are not traversed by the dump function; I didn't want them to be 351 * traversed (that can be done by hand in the output, but you can also check 352 * for crosslinks and other problems this way). 353 */ 354 #undef AIDXRES_DEBUG 355 #undef AIDXRES_DEBUG_VERBOSE 356 357 /* 358 * Define AIDXRES_SANITY_CHECKING to enable deep sanity checks of lists. 359 * If it is not defined, the checks will never be performed. If it is 360 * defined, the checks will only be performed as below (minimal additional 361 * overhead under normal conditions in this case). 362 * 363 * The sanity check checks the list to be sure things are intact. The bank 364 * sublists are first checked for loops (this involves a traversal of each 365 * of the bank sublists). Each bank then has its element sublists checked for 366 * loops and element count accuracy (an accumulator is kept for overall 367 * element count accuracy checking), and then any blocks that do not appear on 368 * the bank sublists will be checked to be sure they look correct. Finally, 369 * the overall element counts will be verified. 370 * 371 * Even if AIDXRES_SANITY_CHECKING is defined, the value of the variable 372 * _aidxres_sanity_settings, defined below (and also see the defines in the 373 * header file for _AIDXRES_SANITY_POINT_* and _AIDXRES_SANITY_FUNC_*) will 374 * control when the checks are actually performed. Futhermore, a dump can 375 * be performed of a list should the checks fail. Without the checks enabled 376 * the various points where the checks would be performed will only suffer 377 * the penalty of a test+branch. _AIDXRES_DEFAULT_SANITY here sets the 378 * default value of _aidxres_sanity_settings, which can be manipulated by 379 * other code, such as the example 'afl paranoia' command on some devices. 380 */ 381 #undef AIDXRES_SANITY_CHECKING 382 #if 0 383 #define _AIDXRES_DEFAULT_SANITY \ 384 (_AIDXRES_SANITY_POINT_ENTRY | \ 385 _AIDXRES_SANITY_POINT_RETURN | \ 386 _AIDXRES_SANITY_FUNC_ALLOC | \ 387 _AIDXRES_SANITY_FUNC_FREE | \ 388 _AIDXRES_SANITY_FUNC_CREATE | \ 389 _AIDXRES_SANITY_DUMP_FAULTS) 390 #else 391 #define _AIDXRES_DEFAULT_SANITY 0 392 #endif 393 394 /* 395 * Implementation of the diagnostic and sanity checking features 396 */ 397 #ifdef AIDXRES_DEBUG 398 #define AIDXRES_DUMP(stuff) bsl_printf stuff 399 #ifdef AIDXRES_DEBUG_VERBOSE 400 #define AIDXRES_DUMP_LIST(list) _aidxres_dump_list(list) 401 #else /* def AIDXRES_DEBUG_VERBOSE */ 402 #define AIDXRES_DUMP_LIST(list) 403 #endif /* def AIDXRES_DEBUG_VERBOSE */ 404 #else /* def AIDXRES_DEBUG */ 405 #define AIDXRES_DUMP(stuff) 406 #define AIDXRES_DUMP_LIST(list) 407 #endif /* def AIDXRES_DEBUG */ 408 #if defined(AIDXRES_DEBUG_VERBOSE) || defined(AIDXRES_SANITY_CHECKING) 409 static void 410 _aidxres_dump_list(const shr_aidxres_list_handle_t list){ 411 unsigned int _sublist; 412 unsigned int _bank; 413 unsigned int _offset; 414 unsigned int _index; 415 unsigned int _max; 416 LOG_CLI((BSL_META("Resource list attributes\n"))); 417 LOG_CLI((BSL_META(" first = %08X last = %08X low = %08X high = %08X\n"), 418 list->first, 419 list->last, 420 list->valid_low, 421 list->valid_high)); 422 LOG_CLI((BSL_META(" free = %08X alloc = %08X bMax = %08X bRMax = %08X\n"), 423 list->free_count, 424 list->alloc_count, 425 list->bank_max, 426 list->bank_rem_max)); 427 LOG_CLI((BSL_META(" sCnt = %08X"), 428 list->sublist_count)); 429 for (_sublist = 0; _sublist < list->sublist_count; _sublist++) { 430 LOG_CLI((BSL_META("\nFree banks sublist %02X"), _sublist)); 431 LOG_CLI((BSL_META(" head=%08X free=%08X"), 432 list->sublist[_sublist].head, 433 list->sublist[_sublist].free_count)); 434 for (_bank = 0; _bank <= list->bank_max; _bank++) { 435 if (0 == (_bank & AIDXRES_BFORMAT_MASK)) { 436 LOG_CLI((BSL_META("\n bank # %08X :"), _bank)); 437 } 438 _index = AIDXRES_BANK_SUBLIST(list, _bank, _sublist); 439 LOG_CLI((BSL_META(" p=%08X n=%08X"), 440 list->bank_list[_index].prev, 441 list->bank_list[_index].next)); 442 } 443 } 444 for (_bank = 0; _bank <= list->bank_max; _bank++) { 445 LOG_CLI((BSL_META("\nBank %08X\n"),_bank)); 446 for (_sublist = 0; _sublist < list->sublist_count; _sublist++) { 447 _index = AIDXRES_BANK_SUBLIST(list, _bank, _sublist); 448 LOG_CLI((BSL_META(" sublist %02X : head=" 449 AIDXRES_FORMAT_ENTRY 450 " free=" 451 AIDXRES_FORMAT_ENTRY 452 "\n"), 453 _sublist, 454 list->bank_sublist[_index].head, 455 list->bank_sublist[_index].free_count)); 456 } 457 if (_bank < list->bank_max) { 458 _max = AIDXRES_MAX_ENTRY; 459 } else { 460 _max = list->bank_rem_max; 461 } 462 for (_offset = 0; _offset <= _max; _offset++) { 463 _index = AIDXRES_ELEMENT_NUM(_bank, _offset); 464 if (0 == (_offset & AIDXRES_FORMAT_MASK)) { 465 LOG_CLI((BSL_META("\n elem # %08X [" 466 AIDXRES_FORMAT_ENTRY 467 "] :"), 468 _index + list->first, 469 AIDXRES_ELEMENT_IDX(_index))); 470 } 471 LOG_CLI((BSL_META(" e=" 472 AIDXRES_FORMAT_ENTRY 473 " s=" 474 AIDXRES_FORMAT_ENTRY 475 " p=" 476 AIDXRES_FORMAT_ENTRY 477 " n=" 478 AIDXRES_FORMAT_ENTRY, 479 list->element[_index].elem_count, 480 list->element[_index].sublist, 481 list->element[_index].prev, 482 list->element[_index].next); 483 } 484 } 485 LOG_CLI((BSL_META("\n"))); 486 } 487 #endif /* defined(AIDXRES_DEBUG_VERBOSE) || defined(AIDXRES_SANITY_CHECKING) */ 488 /* NOT static */ uint32 _aidxres_sanity_settings = _AIDXRES_DEFAULT_SANITY; 489 #ifdef AIDXRES_SANITY_CHECKING 490 static int 491 _aidxres_list_bank_check(const shr_aidxres_list_handle_t list, 492 shr_aidxres_element_t bank, 493 SHR_BITDCL *buffer, 494 shr_aidxres_element_t *totalFree) 495 { 496 int result = BCM_E_NONE; 497 int abort = FALSE; 498 _aidxres_list_entry_t elems; 499 _aidxres_list_entry_t free; 500 _aidxres_list_entry_t elem; 501 _aidxres_list_entry_t offs; 502 _aidxres_list_entry_t last; 503 _aidxres_list_entry_t which; 504 _aidxres_list_elemdesc_t *elemDesc; 505 shr_aidxres_element_t sublist; 506 _aidxres_list_bank_sublist_t *bankSublist; 507 508 /* some initial setup work */ 509 elemDesc = &(list->element[AIDXRES_ELEMENT_NUM(bank, 0)]); 510 if (bank < list->bank_max) { 511 elems = AIDXRES_MAX_ENTRY + 1; 512 } else { 513 elems = list->bank_rem_max + 1; 514 } 515 SHR_BITCLR_RANGE(buffer, 0, elems); 516 /* scan each sublist for free elements */ 517 for (sublist = 0; sublist < list->sublist_count; sublist++) { 518 bankSublist = &(list->bank_sublist[AIDXRES_BANK_SUBLIST(list, bank, sublist)]); 519 free = 0; 520 elem = bankSublist->head; 521 last = AIDXRES_FIRST_ENTRY; 522 if (elem < elems) { 523 if (elemDesc[elem].prev != AIDXRES_FIRST_ENTRY) { 524 LOG_CLI((BSL_META("aidxres %p element %08X bank %08X sublist %02X" 525 " head " AIDXRES_FORMAT_ENTRY " prev invalid: " 526 AIDXRES_FORMAT_ENTRY "\n"), 527 (void*)list, 528 AIDXRES_ELEMENT_NUM(bank, elem) + list->first, 529 bank, 530 sublist, 531 elem, 532 elemDesc[elem].prev)); 533 result = BCM_E_INTERNAL; 534 abort = TRUE; 535 } 536 } else if (elem != AIDXRES_FINAL_ENTRY) { 537 LOG_CLI((BSL_META("aidxres %p bank %08X sublist %02X head " 538 AIDXRES_FORMAT_ENTRY " should be " 539 AIDXRES_FORMAT_ENTRY " or < " 540 AIDXRES_FORMAT_ENTRY "\n"), 541 (void*)list, 542 bank, 543 sublist, 544 elem, 545 AIDXRES_FINAL_ENTRY, 546 elems)); 547 elem = AIDXRES_FINAL_ENTRY; 548 result = BCM_E_INTERNAL; 549 abort = TRUE; 550 } 551 while ((!abort) && (elem <= AIDXRES_MAX_ENTRY)) { 552 if (last != elemDesc[elem].prev) { 553 LOG_CLI((BSL_META("aidxres %p element %08X..%08X bank %08X sublist" 554 " %02X prev " AIDXRES_FORMAT_ENTRY " should be " 555 AIDXRES_FORMAT_ENTRY "\n"), 556 (void*)list, 557 AIDXRES_ELEMENT_NUM(bank, elem) + list->first, 558 AIDXRES_ELEMENT_NUM(bank, elem) + list->first + elemDesc[elem].elem_count - 1, 559 bank, 560 sublist, 561 elemDesc[elem].prev, 562 last)); 563 result = BCM_E_INTERNAL; 564 } 565 if ((1u << sublist) != elemDesc[elem].elem_count) { 566 LOG_CLI((BSL_META("aidxres %p element %08X..%08X bank %08X sublist" 567 " %02X block size %u should be %u\n"), 568 (void*)list, 569 AIDXRES_ELEMENT_NUM(bank, elem) + list->first, 570 AIDXRES_ELEMENT_NUM(bank, elem) + list->first + elemDesc[elem].elem_count - 1, 571 bank, 572 sublist, 573 elemDesc[elem].elem_count, 574 1u << sublist)); 575 result = BCM_E_INTERNAL; 576 elem = AIDXRES_FINAL_ENTRY; 577 abort = TRUE; 578 break; 579 } 580 if ((1u << sublist) + elem > elems) { 581 LOG_CLI((BSL_META("aidxres %p element %08X..%08X bank %08X sublist" 582 " %02X extends past end of bank " 583 AIDXRES_FORMAT_ENTRY "\n"), 584 (void*)list, 585 AIDXRES_ELEMENT_NUM(bank, elem) + list->first, 586 AIDXRES_ELEMENT_NUM(bank, elem) + list->first + elemDesc[elem].elem_count - 1, 587 bank, 588 sublist, 589 elems)); 590 result = BCM_E_INTERNAL; 591 } 592 if ((elemDesc[elem].next >= elems) && 593 (elemDesc[elem].next != AIDXRES_FINAL_ENTRY)) { 594 LOG_CLI((BSL_META("aidxres %p element %08X..%08X bank %08X sublist" 595 " %02X next " AIDXRES_FORMAT_ENTRY " should be " 596 AIDXRES_FORMAT_ENTRY " or < " 597 AIDXRES_FORMAT_ENTRY "\n"), 598 (void*)list, 599 AIDXRES_ELEMENT_NUM(bank, elem) + list->first, 600 AIDXRES_ELEMENT_NUM(bank, elem) + list->first + elemDesc[elem].elem_count - 1, 601 bank, 602 sublist, 603 elemDesc[elem].next, 604 AIDXRES_FINAL_ENTRY, 605 elems)); 606 result = BCM_E_INTERNAL; 607 elem = AIDXRES_FINAL_ENTRY; 608 abort = TRUE; 609 break; 610 } 611 for (offs = 0; offs < elemDesc[elem].elem_count; offs++) { 612 if (sublist != elemDesc[elem + offs].sublist) { 613 LOG_CLI((BSL_META("aidxres %p element %08X..%08X bank %08X" 614 " sublist %02X offset %u sublist " 615 AIDXRES_FORMAT_ENTRY " should be " 616 AIDXRES_FORMAT_ENTRY "\n"), 617 (void*)list, 618 AIDXRES_ELEMENT_NUM(bank, elem) + list->first, 619 AIDXRES_ELEMENT_NUM(bank, elem) + list->first + elemDesc[elem].elem_count - 1, 620 bank, 621 sublist, 622 offs, 623 elemDesc[elem + offs].sublist, 624 sublist)); 625 result = BCM_E_INTERNAL; 626 } 627 if (SHR_BITGET(buffer, elem + offs)) { 628 LOG_CLI((BSL_META("aidxres %p element %08X..%08X bank %08X elem " 629 AIDXRES_FORMAT_ENTRY " already encountered\n"), 630 (void*)list, 631 AIDXRES_ELEMENT_NUM(bank, elem + offs) + list->first, 632 AIDXRES_ELEMENT_NUM(bank, elem + offs) + list->first + (free - 1), 633 bank, 634 elem + offs)); 635 result = BCM_E_INTERNAL; 636 abort = TRUE; 637 break; 638 } 639 SHR_BITSET(buffer, elem + offs); 640 if (offs > 0) { 641 if (elemDesc[elem].elem_count - 1 == offs) { 642 which = AIDXRES_FINAL_ENTRY; 643 } else { 644 which = AIDXRES_USED_ENTRY; 645 } 646 if (which != elemDesc[elem + offs].elem_count) { 647 LOG_CLI((BSL_META("aidxres %p element %08X..%08X bank %08X" 648 " sublist %02X offset %u elem_count " 649 AIDXRES_FORMAT_ENTRY " should be " 650 AIDXRES_FORMAT_ENTRY "\n"), 651 (void*)list, 652 AIDXRES_ELEMENT_NUM(bank, elem) + list->first, 653 AIDXRES_ELEMENT_NUM(bank, elem) + list->first + elemDesc[elem].elem_count - 1, 654 bank, 655 sublist, 656 offs, 657 elemDesc[elem + offs].elem_count, 658 which)); 659 result = BCM_E_INTERNAL; 660 } 661 } /* if (offs > 0) */ 662 } /* for (offs = 0; offs < elemDesc[elem].elem_count; offs++) */ 663 free += elemDesc[elem].elem_count; 664 last = elem; 665 elem = elemDesc[elem].next; 666 } /* while (elem <= AIDXRES_MAX_ENTRY) */ 667 if ((elem != AIDXRES_FINAL_ENTRY) && (last != AIDXRES_FINAL_ENTRY)) { 668 LOG_CLI((BSL_META("aidxres %p element %08X bank %08X sublist %02X tail " 669 AIDXRES_FORMAT_ENTRY " next invalid: " 670 AIDXRES_FORMAT_ENTRY "\n"), 671 (void*)list, 672 AIDXRES_ELEMENT_NUM(bank, elem) + list->first, 673 bank, 674 sublist, 675 last, 676 elem)); 677 result = BCM_E_INTERNAL; 678 } 679 if ((!abort) && (free != bankSublist->free_count)) { 680 LOG_CLI((BSL_META("aidxres %p bank %08X sublist %02X count " 681 AIDXRES_FORMAT_ENTRY " incorrect, counted " 682 AIDXRES_FORMAT_ENTRY "\n"), 683 (void*)list, 684 bank, 685 sublist, 686 bankSublist->free_count, 687 free)); 688 result = BCM_E_INTERNAL; 689 } 690 totalFree[sublist] += free; 691 } /* for (sublist = 0; sublist < list->sublist_count; sublist++) */ 692 /* 693 * Scan allocated elements for consistency, but we can only do this if the 694 * list consistency check went okay (since we will not otherwise know 695 * which elements are not in lists). 696 */ 697 if (!abort) { 698 for (elem = 0; elem < elems; /* incr deliberately */) { 699 if (SHR_BITGET(buffer, elem)) { 700 /* element was already found in a sublist */ 701 elem++; 702 } else { /* if (SHR_BITGET(buffer, elem)) */ 703 /* element not checked yet */ 704 free = elemDesc[elem].elem_count; 705 for (offs = 0; offs < free; offs++) { 706 if (SHR_BITGET(buffer, elem + offs)) { 707 LOG_CLI((BSL_META("aidxres %p allocated element %08X..%08X" 708 " bank %08X elem " AIDXRES_FORMAT_ENTRY 709 " already encountered\n"), 710 (void*)list, 711 AIDXRES_ELEMENT_NUM(bank, elem + offs) + list->first, 712 AIDXRES_ELEMENT_NUM(bank, elem + offs) + list->first + (free - 1), 713 bank, 714 elem + offs)); 715 result = BCM_E_INTERNAL; 716 } 717 SHR_BITSET(buffer, elem + offs); 718 if (0 == offs) { 719 last = AIDXRES_FIRST_ENTRY; 720 } else if ((free - 1) == offs) { 721 last = AIDXRES_FINAL_ENTRY; 722 if (free != elemDesc[elem + offs].elem_count) { 723 LOG_CLI((BSL_META("aidxres %p allocated element" 724 " %08X..%08X bank %08X elem " 725 AIDXRES_FORMAT_ENTRY " elem_count " 726 AIDXRES_FORMAT_ENTRY " should be " 727 AIDXRES_FORMAT_ENTRY "\n"), 728 (void*)list, 729 AIDXRES_ELEMENT_NUM(bank, elem + offs) + list->first, 730 AIDXRES_ELEMENT_NUM(bank, elem + offs) + list->first + (free - 1), 731 bank, 732 elem + offs, 733 elemDesc[elem + offs].sublist, 734 free)); 735 result = BCM_E_INTERNAL; 736 } 737 } else { 738 last = AIDXRES_USED_ENTRY; 739 } 740 if (last != elemDesc[elem + offs].sublist) { 741 LOG_CLI((BSL_META("aidxres %p allocated element %08X..%08X" 742 " bank %08X elem " AIDXRES_FORMAT_ENTRY 743 " sublist " AIDXRES_FORMAT_ENTRY 744 " should be " AIDXRES_FORMAT_ENTRY "\n"), 745 (void*)list, 746 AIDXRES_ELEMENT_NUM(bank, elem + offs) + list->first, 747 AIDXRES_ELEMENT_NUM(bank, elem + offs) + list->first + (free - 1), 748 bank, 749 elem + offs, 750 elemDesc[elem + offs].sublist, 751 last)); 752 result = BCM_E_INTERNAL; 753 } 754 } /* for (offs = 0; offs < free; offs++) */ 755 /* skip to end of this block */ 756 elem += free; 757 } /* if (SHR_BITGET(buffer, elem)) */ 758 } /* for (elem = 0; elem <= AIDXRES_MAX_ENTRY;) */ 759 } /* if (!abort) */ 760 return result; 761 } 762 static int 763 _aidxres_list_check(const shr_aidxres_list_handle_t list) 764 { 765 int result = BCM_E_NONE; 766 int tmpRes; 767 SHR_BITDCL *buffer; 768 shr_aidxres_element_t bslcurr; 769 shr_aidxres_element_t bank; 770 shr_aidxres_element_t prevBank; 771 shr_aidxres_element_t *totalFree; 772 shr_aidxres_element_t sublist; 773 774 if (list->bank_max > AIDXRES_MAX_ENTRY) { 775 bslcurr = SHR_BITALLOCSIZE(list->bank_max + 1); 776 } else { 777 /* don't ask me about implied signed division */ 778 bslcurr = SHR_BITALLOCSIZE(AIDXRES_MAX_ENTRY) + sizeof(SHR_BITDCL); 779 } 780 buffer = sal_alloc(bslcurr, "aidx list cycle checking"); 781 if (NULL == buffer) { 782 LOG_CLI((BSL_META("aidxres %p unable to validate (c): not enough memory\n"), 783 (void*)list)); 784 return BCM_E_NONE; 785 } 786 totalFree = sal_alloc(sizeof(shr_aidxres_element_t) * list->sublist_count, 787 "aidx free count checking"); 788 if (NULL == totalFree) { 789 LOG_CLI((BSL_META("aidxres %p unable to validate (f): not enough memory\n"), 790 (void*)list)); 791 sal_free(buffer); 792 return BCM_E_NONE; 793 } 794 sal_memset(totalFree, 0x00, sizeof(shr_aidxres_element_t) * list->sublist_count); 795 for (sublist = 0; sublist < list->sublist_count; sublist++) { 796 SHR_BITCLR_RANGE(buffer, 0, list->bank_max + 1); 797 bank = list->sublist[sublist].head; 798 if (list->bank_max >= bank) { 799 /* the initial bank is valid; traverse the list */ 800 bslcurr = AIDXRES_BANK_SUBLIST(list, bank, sublist); 801 prevBank = AIDXRES_FIRST_BANK; 802 while (bank < AIDXRES_FIRST_BANK) { 803 if (SHR_BITGET(buffer, bank)) { 804 LOG_CLI((BSL_META("aidxres %p sublist %02X bank %08X has" 805 " already been encountered\n"), 806 (void*)list, 807 sublist, 808 bank)); 809 result = BCM_E_INTERNAL; 810 break; 811 } 812 if (list->bank_list[bslcurr].prev != prevBank) { 813 LOG_CLI((BSL_META("aidxres %p sublist %02X bank %08X prev %08X" 814 " should be %08X\n"), 815 (void*)list, 816 sublist, 817 bank, 818 list->bank_list[bslcurr].prev, 819 prevBank)); 820 result = BCM_E_INTERNAL; 821 } 822 SHR_BITSET(buffer, bank); 823 prevBank = bank; 824 bank = list->bank_list[bslcurr].next; 825 if ((bank > list->bank_max) && (AIDXRES_FINAL_BANK != bank)) { 826 LOG_CLI((BSL_META("aidxres %p sublist %02X bank %08X next %08X" 827 " should be %08X or < %08X\n"), 828 (void*)list, 829 sublist, 830 prevBank, 831 bank, 832 AIDXRES_FINAL_BANK, 833 list->bank_max + 1)); 834 result = BCM_E_INTERNAL; 835 break; 836 } 837 bslcurr = AIDXRES_BANK_SUBLIST(list, bank, sublist); 838 } /* (bank < AIDXRES_FIRST_BANK) */ 839 } else if ((AIDXRES_FINAL_BANK != bank) && (list->bank_max < bank)) { 840 LOG_CLI((BSL_META("aidxres %p sublist %02X first bank %08X should be" 841 " either %08X or < %08X\n"), 842 (void*)list, 843 sublist, 844 bank, 845 AIDXRES_FINAL_BANK, 846 list->bank_max + 1)); 847 result = BCM_E_INTERNAL; 848 } 849 for (bank = 0; bank <= list->bank_max; bank++) { 850 if (!SHR_BITGET(buffer, bank)) { 851 /* only check unvisited banks (no free elems this sublist) */ 852 bslcurr = AIDXRES_BANK_SUBLIST(list, bank, sublist); 853 if (AIDXRES_USED_BANK != list->bank_list[bslcurr].prev) { 854 LOG_CLI((BSL_META("aidxres %p sublist %02X empty bank %08X prev" 855 " %08X should be %08X\n"), 856 (void*)list, 857 sublist, 858 bank, 859 list->bank_list[bslcurr].prev, 860 AIDXRES_USED_BANK)); 861 } 862 if (AIDXRES_USED_BANK != list->bank_list[bslcurr].next) { 863 LOG_CLI((BSL_META("aidxres %p sublist %02X empty bank %08X next" 864 " %08X should be %08X\n"), 865 (void*)list, 866 sublist, 867 bank, 868 list->bank_list[bslcurr].next, 869 AIDXRES_USED_BANK)); 870 } 871 } /* if (!SHR_BITGET(buffer, bank)) */ 872 } /* for (bank = 0; bank <= list->bank_mak; bank++) */ 873 } 874 for (bank = 0; bank <= list->bank_max; bank++) { 875 tmpRes = _aidxres_list_bank_check(list, bank, buffer, totalFree); 876 if (BCM_E_NONE != tmpRes) { 877 result = tmpRes; 878 } 879 } 880 for (sublist = 0; sublist < list->sublist_count; sublist++) { 881 if (list->sublist[sublist].free_count != totalFree[sublist]) { 882 LOG_CLI((BSL_META("aidxres %p sublist %02X free count %08X incorrect;" 883 " counted %08X\n"), 884 (void*)list, 885 sublist, 886 list->sublist[sublist].free_count, 887 totalFree[sublist])); 888 result = BCM_E_INTERNAL; 889 } 890 } 891 sal_free(totalFree); 892 sal_free(buffer); 893 if ((BCM_E_NONE != result) && 894 (_aidxres_sanity_settings & _AIDXRES_SANITY_DUMP_FAULTS)) { 895 LOG_CLI((BSL_META("aidxres %p appears corrupt; dumping it\n"), (void*)list)); 896 _aidxres_dump_list(list); 897 } 898 return result; 899 } 900 #endif /* def AIDXRES_SANITY_CHECKING */ 901 902 /* 903 * Function 904 * _add_block_to_sublist 905 * Purpose 906 * Prepare a block and insert it into the specified sublist, then be sure 907 * the bank is also in the sublist. 908 * Parameters 909 * (in) shr_aidxres_list_handle_t list = list to manipulate 910 * (in) shr_aidxres_element_t first = first element of block 911 * (in) shr_aidxres_element_t sublist = sublist for insertion 912 * Returns 913 * (void) 914 * Notes 915 * No locking or parameter checking is performed. This is used internally 916 * for alloc class and free class operations. Does not combine adjacent 917 * blocks either across sublists or within a sublist, as this may be 918 * called during alloc as well as free. 919 */ 920 static void 921 _add_block_to_sublist(shr_aidxres_list_handle_t list, 922 shr_aidxres_element_t first, 923 shr_aidxres_element_t sublist) { 924 shr_aidxres_element_t bslcurr; /* working [bank,sublist] index */ 925 shr_aidxres_element_t bank; /* working bank */ 926 shr_aidxres_element_t count; /* working elements in block */ 927 _aidxres_list_entry_t firstidx; /* working new first element index */ 928 _aidxres_list_entry_t previdx; /* working prev first elem index */ 929 930 AIDXRES_DUMP(("_add_block_to_sublist(*,%08X,%02X) called\n", 931 first, 932 sublist)); 933 /* figure out how big the block is and adjust free size */ 934 count = 1 << sublist; 935 AIDXRES_DUMP(("_add_block_to_sublist: count = %08X\n",count)); 936 AIDXRES_DUMP(("_add_block_to_sublist: sublist free = %08X\n", 937 list->sublist[sublist].free_count)); 938 list->sublist[sublist].free_count += count; 939 AIDXRES_DUMP(("_add_block_to_sublist: sublist free = %08X\n", 940 list->sublist[sublist].free_count)); 941 /* figure out which bank */ 942 bank = AIDXRES_ELEMENT_BNK(first); 943 firstidx = AIDXRES_ELEMENT_IDX(first); 944 /* compute the index for the bank and sublist information */ 945 bslcurr = AIDXRES_BANK_SUBLIST(list, bank, sublist); 946 /* adjust elements free this bank */ 947 list->bank_sublist[bslcurr].free_count += count; 948 /* Set element count in first element */ 949 list->element[first].elem_count = count; 950 /* Set previous and next first element pointers in first element */ 951 list->element[first].prev = AIDXRES_FIRST_ENTRY; 952 previdx = list->bank_sublist[bslcurr].head; 953 list->element[first].next = previdx; 954 /* adjust former first element to point to this as new first element */ 955 if (previdx <= AIDXRES_MAX_ENTRY) { 956 list->element[AIDXRES_ELEMENT_NUM(bank,previdx)].prev = firstidx; 957 } 958 /* Insert this block to the sublist */ 959 list->bank_sublist[bslcurr].head = firstidx; 960 /* Mark the block as not in use */ 961 #ifdef AIDXRES_SANITY_CHECKING 962 firstidx = 1; 963 previdx = count; 964 #endif /* def AIDXRES_SANITY_CHECKING */ 965 while (count) { 966 list->element[first].sublist = sublist; 967 #ifdef AIDXRES_SANITY_CHECKING 968 if (1 < firstidx) { 969 if (previdx == firstidx) { 970 list->element[first].elem_count = AIDXRES_FINAL_ENTRY; 971 } else { 972 list->element[first].elem_count = AIDXRES_USED_ENTRY; 973 } 974 } 975 firstidx++; 976 #endif /* def AIDXRES_SANITY_CHECKING */ 977 first++; 978 count--; 979 } 980 /* Be sure the bank is in the sublist */ 981 if (AIDXRES_USED_BANK == list->bank_list[bslcurr].next) { 982 /* bank is not already in this sublist; add it */ 983 /* for this bank, next points to prior head & prev is BOL */ 984 list->bank_list[bslcurr].prev = AIDXRES_FIRST_BANK; 985 list->bank_list[bslcurr].next = list->sublist[sublist].head; 986 if (list->sublist[sublist].head < AIDXRES_MAX_BANK) { 987 /* make prior head bank's prev point to this bank */ 988 list->bank_list[AIDXRES_BANK_SUBLIST(list, 989 list->sublist[sublist].head, 990 sublist)].prev = bank; 991 } 992 /* make this bank head of the list */ 993 list->sublist[sublist].head = bank; 994 } 995 } 996 997 /* 998 * Function 999 * _remove_first_from_sublist 1000 * Purpose 1001 * Remove the first block from a sublist in preparation for allocate. 1002 * Parameters 1003 * (in) shr_aidxres_list_handle_t list = list to manipulate 1004 * (in) shr_aidxres_element_t sublist = sublist to manipulate 1005 * (out) shr_aidxres_element_t *element = place to put grabbed first elem 1006 * Returns 1007 * (void) 1008 * Notes 1009 * No locking or parameter checking is performed. This is used internally 1010 * for alloc class operations. Will remove a bank from the sublist if 1011 * there are no more appropriate blocks in that bank. Does not prepare 1012 * the block for return to the caller, as it may be fragmented first. 1013 */ 1014 static void 1015 _remove_first_from_sublist(shr_aidxres_list_handle_t list, 1016 shr_aidxres_element_t sublist, 1017 shr_aidxres_element_t *element) 1018 { 1019 shr_aidxres_element_t bslcurr; /* working [bank,sublist] index */ 1020 shr_aidxres_element_t bank; /* working bank number */ 1021 shr_aidxres_element_t count; /* working elements in block */ 1022 1023 AIDXRES_DUMP(("_remove_first_from_sublist(*,%02X,*) called\n",sublist)); 1024 /* figure out how big the block is and adjust free size */ 1025 count = 1 << sublist; 1026 AIDXRES_DUMP(("_remove_first_from_sublist: count = %08X\n",count)); 1027 AIDXRES_DUMP(("_remove_first_from_sublist: sublist free = %08X\n", 1028 list->sublist[sublist].free_count)); 1029 list->sublist[sublist].free_count -= count; 1030 AIDXRES_DUMP(("_remove_first_from_sublist: sublist free = %08X\n", 1031 list->sublist[sublist].free_count)); 1032 /* get the first bank that has an element in this list */ 1033 bank = list->sublist[sublist].head; 1034 /* compute the index for the bank and sublist information */ 1035 bslcurr = AIDXRES_BANK_SUBLIST(list, bank, sublist); 1036 /* get first element of first block of first bank of the sublist */ 1037 *element = AIDXRES_ELEMENT_NUM(bank, list->bank_sublist[bslcurr].head); 1038 /* update this bank's sublist */ 1039 list->bank_sublist[bslcurr].head = list->element[*element].next; 1040 list->bank_sublist[bslcurr].free_count -= count; 1041 if (list->bank_sublist[bslcurr].head <= AIDXRES_MAX_ENTRY) { 1042 list->element[AIDXRES_ELEMENT_NUM(bank,list->bank_sublist[bslcurr].head)].prev = AIDXRES_FIRST_ENTRY; 1043 } 1044 if (0 == list->bank_sublist[bslcurr].free_count) { 1045 /* this bank has no more elements in this sublist; remove it */ 1046 /* point head of sublist to next bank in sublist */ 1047 list->sublist[sublist].head = list->bank_list[bslcurr].next; 1048 /* set new head's prev pointer to indicate first bank */ 1049 if (list->sublist[sublist].head < AIDXRES_MAX_BANK) { 1050 list->bank_list[AIDXRES_BANK_SUBLIST(list, 1051 list->sublist[sublist].head, 1052 sublist)].prev = AIDXRES_FIRST_BANK; 1053 } 1054 /* set this bank's next and prev to indicate it has no blks this lst */ 1055 list->bank_list[bslcurr].prev = AIDXRES_USED_BANK; 1056 list->bank_list[bslcurr].next = AIDXRES_USED_BANK; 1057 } 1058 AIDXRES_DUMP(("_remove_first_from_sublist(*,%02X,&(%08X)) returning\n", 1059 sublist, 1060 *element)); 1061 } 1062 1063 /* 1064 * Function 1065 * _remove_block_from_sublist 1066 * Purpose 1067 * Remove a specific block from a sublist during defragmentation 1068 * Parameters 1069 * (in) shr_aidxres_list_handle_t list = list to manipulate 1070 * (in) shr_aidxres_element_t first = first element of block 1071 * (in) shr_aidxres_element_t sublist = sublist for insertion 1072 * Returns 1073 * (void) 1074 * Notes 1075 * No locking or parameter checking is performed. This is used internally 1076 * for free class operations (specifically during defragmentation). Will 1077 * remove a bank from the sublist if there are no more appropriate blocks 1078 * in that bank. 1079 */ 1080 static void 1081 _remove_block_from_sublist(shr_aidxres_list_handle_t list, 1082 shr_aidxres_element_t first, 1083 shr_aidxres_element_t sublist) { 1084 shr_aidxres_element_t bslcurr; /* working [bank,sublist] index */ 1085 shr_aidxres_element_t bank; /* working bank number */ 1086 shr_aidxres_element_t count; /* working elements in block */ 1087 1088 AIDXRES_DUMP(("_remove_block_from_sublist(*,%08X,%02X) called\n", 1089 first, 1090 sublist)); 1091 /* figure out how big the block is and adjust free size */ 1092 count = 1 << sublist; 1093 list->sublist[sublist].free_count -= count; 1094 /* compute the index for the bank and sublist information */ 1095 bank = AIDXRES_ELEMENT_BNK(first); 1096 bslcurr = AIDXRES_BANK_SUBLIST(list, bank, sublist); 1097 /* remove this block from its sublist */ 1098 if (AIDXRES_FIRST_ENTRY != list->element[first].prev) { 1099 /* there is something in the bank before this block, point to after */ 1100 list->element[AIDXRES_ELEMENT_NUM(bank, list->element[first].prev)].next = 1101 list->element[first].next; 1102 } else { 1103 /* adjust head of list to point to after this block */ 1104 list->bank_sublist[bslcurr].head = list->element[first].next; 1105 } 1106 if (AIDXRES_FINAL_ENTRY != list->element[first].next) { 1107 /* there is something in the bank after this block, point to before */ 1108 list->element[AIDXRES_ELEMENT_NUM(bank, list->element[first].next)].prev = 1109 list->element[first].prev; 1110 } 1111 /* adjust elements free this bank */ 1112 list->bank_sublist[bslcurr].free_count -= count; 1113 /* remove this bank from the sublist if appropriate */ 1114 if (0 == list->bank_sublist[bslcurr].free_count) { 1115 /* this bank has no more blocks on this sublist; remove it */ 1116 if (AIDXRES_FIRST_BANK == list->bank_list[bslcurr].prev) { 1117 /* this is the first bank; update head to skip it */ 1118 list->sublist[sublist].head = list->bank_list[bslcurr].next; 1119 } else { 1120 /* this is not the first bank; update prev to skip it */ 1121 list->bank_list[AIDXRES_BANK_SUBLIST(list, 1122 list->bank_list[bslcurr].prev, 1123 sublist)].next = 1124 list->bank_list[bslcurr].next; 1125 } 1126 if (AIDXRES_FINAL_BANK != list->bank_list[bslcurr].next) { 1127 /* this is not the last bank; udpate the following's prev value */ 1128 list->bank_list[AIDXRES_BANK_SUBLIST(list, 1129 list->bank_list[bslcurr].next, 1130 sublist)].prev = 1131 list->bank_list[bslcurr].prev; 1132 } 1133 /* set this bank's next and prev to indicate it has no blks this lst */ 1134 list->bank_list[bslcurr].prev = AIDXRES_USED_BANK; 1135 list->bank_list[bslcurr].next = AIDXRES_USED_BANK; 1136 } 1137 AIDXRES_DUMP(("_remove_block_from_sublist(*,%08X,%02X) returning\n", 1138 first, 1139 sublist)); 1140 } 1141 1142 /* 1143 * 1144 * Function 1145 * _prep_block_for_alloc 1146 * Purpose 1147 * Prepare a block to be returned to the caller after successful alloc. 1148 * Parameters 1149 * (in) shr_aidxres_list_handle_t list = list to manipulate 1150 * (in) shr_aidxres_element_t first = first element of block 1151 * (in) shr_aidxres_element_t count = number of elements in block 1152 * Returns 1153 * (void) 1154 * Notes 1155 * No locking or parameter checking is performed. This is used internally 1156 * for alloc class and free class operations. Assumes caller removes the 1157 * block from the sublist. 1158 */ 1159 static void 1160 _prep_block_for_alloc(shr_aidxres_list_handle_t list, 1161 shr_aidxres_element_t first, 1162 shr_aidxres_element_t count) { 1163 _aidxres_list_entry_t remain; /* remaining element count */ 1164 1165 AIDXRES_DUMP(("_prep_block_for_alloc(*,%08X,%08X) called\n", 1166 first, 1167 count)); 1168 /* Set element count in first element */ 1169 list->element[first].elem_count = count; 1170 /* Mark the block as in use */ 1171 list->element[first].sublist = AIDXRES_FIRST_ENTRY; 1172 remain = count - 1; 1173 first++; 1174 while (remain > 1) { 1175 list->element[first].sublist = AIDXRES_USED_ENTRY; 1176 remain--; 1177 first++; 1178 } 1179 /* specially tag final element if it's not first element */ 1180 if (remain) { 1181 list->element[first].sublist = AIDXRES_FINAL_ENTRY; 1182 list->element[first].elem_count = count; 1183 } 1184 AIDXRES_DUMP(("_prep_block_for_alloc: returning\n")); 1185 } 1186 1187 /* 1188 * Function 1189 * _shr_aidxres_list_alloc 1190 * Purpose 1191 * Allocate the next available block of appropriate size from a list 1192 * Parameters 1193 * (in) shr_aidxres_list_handle_t list = list from which to allocate 1194 * (in) shr_aidxres_element_t count = number of elements in block 1195 * (out) shr_aidxres_element_t *element = where to put alloced block base 1196 * Returns 1197 * BCM_E_NONE if element allocated successfully 1198 * BCM_E_* as appropriate otherwise 1199 * Notes 1200 * No locking or parameter checking is performed. This is used internally 1201 * for alloc and alloc_set operations. 1202 * This will always allocate a block aligned to the size of the request if 1203 * it is a power of two, or to the next greater power of two elements, and 1204 * it will return any remaning elements to the appropriate sublists. 1205 */ 1206 static int 1207 _shr_aidxres_list_alloc(shr_aidxres_list_handle_t list, 1208 shr_aidxres_element_t count, 1209 shr_aidxres_element_t *element) 1210 { 1211 int result; /* value to be returned to caller */ 1212 #ifdef AIDXRES_SANITY_CHECKING 1213 int auxRes; /* aux result for sanity checking */ 1214 #endif /* def AIDXRES_SANITY_CHECKING */ 1215 shr_aidxres_element_t blkbase; /* working block base element number */ 1216 shr_aidxres_element_t temp; /* scratchpad element count/number */ 1217 _aidxres_list_entry_t sublist; /* working sublist number */ 1218 _aidxres_list_entry_t bias; /* working bias of returned block */ 1219 _aidxres_list_entry_t actual; /* actual size of acquired block */ 1220 _aidxres_list_entry_t needed; /* needed size of block */ 1221 1222 AIDXRES_DUMP(("_shr_aidxres_list_alloc(*,%08X,*) called\n",count)); 1223 #ifdef AIDXRES_SANITY_CHECKING 1224 if ((_aidxres_sanity_settings & (_AIDXRES_SANITY_POINT_ENTRY | 1225 _AIDXRES_SANITY_FUNC_ALLOC)) == 1226 (_AIDXRES_SANITY_POINT_ENTRY | _AIDXRES_SANITY_FUNC_ALLOC)) { 1227 auxRes = _aidxres_list_check(list); 1228 if (BCM_E_NONE != auxRes) { 1229 return auxRes; 1230 } 1231 } 1232 #endif /* def AIDXRES_SANITY_CHECKING */ 1233 1234 /* check some argument validity */ 1235 if (!count) { 1236 /* count is zero; that's not allowed */ 1237 return BCM_E_PARAM; 1238 } 1239 1240 /* be optimistic about results */ 1241 result = BCM_E_NONE; 1242 1243 /* decide which sublist needs to be used for this block */ 1244 AIDXRES_DUMP(("_shr_aidxres_list_alloc: search for best fit sublist\n")); 1245 for (temp = 1, needed = 1, sublist = 0; 1246 ((temp < count) && temp); 1247 temp = temp << 1, needed = needed << 1, sublist++) { 1248 /* do nothing; the loop iterator and condition do the work here */ 1249 } 1250 /* at this point, 'needed' indicates the smallest block for the alloc */ 1251 actual = needed; 1252 /* make sure the decided sublist is valid */ 1253 if (temp && (sublist < list->sublist_count)) { 1254 /* sublist is valid here, so block size is okay */ 1255 while ((sublist < list->sublist_count) && 1256 (!(list->sublist[sublist].free_count))) { 1257 /* this sublist has no free entries; try the next one up */ 1258 sublist++; 1259 temp = temp << 1; 1260 actual = actual << 1; 1261 } 1262 if ((!temp) || (sublist >= list->sublist_count)) { 1263 /* no free blocks large enough */ 1264 result = BCM_E_RESOURCE; 1265 } 1266 } else { 1267 /* block is too big */ 1268 result = BCM_E_PARAM; 1269 } 1270 1271 /* if we found a usable sublist, get a block from it */ 1272 if (BCM_E_NONE == result) { 1273 AIDXRES_DUMP(("_shr_aidxres_list_alloc: get first from sublist %02X\n", 1274 sublist)); 1275 /* okay; we have a sublist with large enough elements */ 1276 /* get first block from that sublist */ 1277 _remove_first_from_sublist(list, sublist, &blkbase); 1278 /* determine how high to bias returned block within actual block */ 1279 AIDXRES_DUMP(("_shr_aidxres_list_alloc: place requested block\n")); 1280 bias = (actual - count) & (~(needed -1)); 1281 /* set returned element number */ 1282 *element = blkbase + bias + list->first; 1283 /* check need for fragmentation of the block */ 1284 if (actual != count) { 1285 /* attach lower subblocks to appropriate lists */ 1286 if (actual != needed) { 1287 /* 1288 * The block was bigger than the minimum size for the alloc 1289 * request; since the alloc request came out of the top 1290 * portion of the block, we must fragment and return the 1291 * lower portion. 1292 */ 1293 AIDXRES_DUMP(("_shr_aidxres_list_alloc: alloc block is too big;" 1294 " return lower part to appropriate sublists\n")); 1295 /* block was bigger than needed */ 1296 /* return first part to free list */ 1297 temp = blkbase; 1298 do { 1299 /* subblock is half the size of the last/original one */ 1300 /* take largest subblocks and work down */ 1301 sublist--; 1302 actual = actual >> 1; 1303 _add_block_to_sublist(list, temp, sublist); 1304 temp += actual; 1305 } while (actual > needed); 1306 } 1307 /* move to end of allocated block */ 1308 AIDXRES_DUMP(("_shr_aidxres_list_alloc: return leftover space" 1309 " (%08X) at top (%08X) to appropriate sublists\n", 1310 needed - count, 1311 bias + count)); 1312 temp = blkbase + bias + count; 1313 /* compute elements remaining above allocated block */ 1314 needed -= count; 1315 sublist = 0; 1316 actual = 1; 1317 while (needed) { 1318 /* 1319 * The request was for a block that was not an even power of 1320 * two elements long. We need to fragment the remainder of 1321 * the block and return those fragments to the free list. 1322 */ 1323 if (needed & actual) { 1324 /* we can slice off this much of it properly */ 1325 _add_block_to_sublist(list, temp, sublist); 1326 temp += actual; 1327 needed -= actual; 1328 } else { 1329 actual = actual << 1; 1330 sublist++; 1331 } 1332 } /* while (needed) */ 1333 } /* if (actual != count) */ 1334 /* adjust final free and alloc counts */ 1335 list->free_count -= count; 1336 list->alloc_count += count; 1337 1338 /* prepare returned block */ 1339 _prep_block_for_alloc(list, blkbase + bias, count); 1340 } /* if (BCM_E_NONE == result) */ 1341 1342 /* debugging */ 1343 AIDXRES_DUMP_LIST(list); 1344 #ifdef AIDXRES_SANITY_CHECKING 1345 if ((_aidxres_sanity_settings & (_AIDXRES_SANITY_POINT_RETURN | 1346 _AIDXRES_SANITY_FUNC_ALLOC)) == 1347 (_AIDXRES_SANITY_POINT_RETURN | _AIDXRES_SANITY_FUNC_ALLOC)) { 1348 auxRes = _aidxres_list_check(list); 1349 if (BCM_E_NONE != auxRes) { 1350 return auxRes; 1351 } 1352 } 1353 #endif /* def AIDXRES_SANITY_CHECKING */ 1354 1355 /* return the actual result */ 1356 return result; 1357 } 1358 1359 /* 1360 * Function 1361 * _shr_aidxres_list_free 1362 * Purpose 1363 * Free a block back to a list 1364 * Parameters 1365 * (in) shr_aidxres_list_handle_t list = list from which block was alloced 1366 * (in) shr_aidxres_element_t = first element in block to free 1367 * Returns 1368 * BCM_E_NONE if element freed successfully 1369 * BCM_E_* as appropriate otherwise 1370 * Notes 1371 * Freeing an entry already in the list is checked, as well as freeing an 1372 * entry outside of the list-managed range. 1373 * No locking and limited parameter checking is performed. This is used 1374 * internally for alloc and alloc_set operations. 1375 * This will automatically defragment the resource list by combining 1376 * contiguous blocks into larger ones if possible, at least up to the 1377 * largest supported block for the list. 1378 */ 1379 static int 1380 _shr_aidxres_list_free(shr_aidxres_list_handle_t list, 1381 shr_aidxres_element_t element) 1382 { 1383 shr_aidxres_element_t sublist; /* working sublist number */ 1384 _aidxres_list_entry_t submask; /* working sublist bit value mask */ 1385 shr_aidxres_element_t currCnt; /* working count */ 1386 shr_aidxres_element_t count; /* number of elements in block */ 1387 shr_aidxres_element_t min; /* minimum element number this block */ 1388 _aidxres_list_entry_t max; /* maximum element number this block */ 1389 _aidxres_list_entry_t offset; /* working offset in bank this block */ 1390 shr_aidxres_element_t next; /* working element number next block */ 1391 #ifdef AIDXRES_SANITY_CHECKING 1392 int result; 1393 #endif /* def AIDXRES_SANITY_CHECKING */ 1394 1395 AIDXRES_DUMP(("_shr_aidxres_list_free(*,%08X) called\n",element)); 1396 #ifdef AIDXRES_SANITY_CHECKING 1397 if ((_aidxres_sanity_settings & (_AIDXRES_SANITY_POINT_ENTRY | 1398 _AIDXRES_SANITY_FUNC_FREE)) == 1399 (_AIDXRES_SANITY_POINT_ENTRY | _AIDXRES_SANITY_FUNC_FREE)) { 1400 result = _aidxres_list_check(list); 1401 if (BCM_E_NONE != result) { 1402 return result; 1403 } 1404 } 1405 #endif /* def AIDXRES_SANITY_CHECKING */ 1406 1407 /* validate parameters */ 1408 if ((element < list->valid_low) || 1409 (element > list->valid_high)) { 1410 /* completely invalid parameters */ 1411 return BCM_E_PARAM; 1412 } 1413 1414 /* further validation */ 1415 if ((element < list->first) || 1416 (element > list->last)) { 1417 /* trying to free elments not managed by the list */ 1418 return BCM_E_RESOURCE; 1419 } 1420 1421 /* remove bias on entry number */ 1422 element -= list->first; 1423 1424 /* validation that we can free the entry */ 1425 AIDXRES_DUMP(("_shr_aidxres_list_free: verify element is allocated\n")); 1426 if (AIDXRES_FIRST_ENTRY > list->element[element].sublist) { 1427 /* this element isn't a member of an allocated block */ 1428 return BCM_E_RESOURCE; 1429 } 1430 AIDXRES_DUMP(("_shr_aidxres_list_free: verify element is first\n")); 1431 if (AIDXRES_FIRST_ENTRY != list->element[element].sublist) { 1432 /* this element is not first element of an allocated block */ 1433 return BCM_E_PARAM; 1434 } 1435 1436 /* determine parameters for this block */ 1437 count = list->element[element].elem_count; 1438 AIDXRES_DUMP(("_shr_aidxres_list_free: block is %08X elements\n",count)); 1439 1440 /* figure out the maximum offset value within a block */ 1441 max = (1 << (list->sublist_count - 1)) - 1; 1442 /* offset is within the block, not within the bank */ 1443 offset = AIDXRES_ELEMENT_IDX(element) & max; 1444 /* compute minimum element number to be in this block */ 1445 min = element & (~max); 1446 /* now adjust max if we're too close to bank end in last bank */ 1447 if (AIDXRES_ELEMENT_BNK(element) == list->bank_max) { 1448 /* in last bank; allowed elements may be limited due to bank size */ 1449 if ((AIDXRES_ELEMENT_IDX(element) + max) >= list->bank_rem_max) { 1450 /* we'd touch end of list; strip it down */ 1451 max &= list->bank_rem_max; 1452 } 1453 } 1454 AIDXRES_DUMP(("_shr_aidxres_list_free: offset = %08X; max = %08X;" 1455 " min = %08X\n", 1456 offset, 1457 max, 1458 min)); 1459 1460 /* adjust final free and alloc counts */ 1461 list->free_count += count; 1462 list->alloc_count -= count; 1463 1464 /* 1465 * First we should try to collect free blocks that are downwardly 1466 * adjacent, and combine them to make a larger block if the resulting 1467 * block would remain correctly aligned for its new size. 1468 */ 1469 while ((element > min) && 1470 (AIDXRES_FIRST_ENTRY > 1471 (sublist = list->element[element - 1].sublist)) && 1472 (sublist < BYTES2BITS(sizeof(currCnt))) && 1473 (count <= (currCnt = 1 << sublist)) && 1474 (0 == ((offset - currCnt) & currCnt)) 1475 ) { 1476 AIDXRES_DUMP(("_shr_aidxres_list_free: collect downwardly adjacent" 1477 " %08X at %08X [" 1478 AIDXRES_FORMAT_ENTRY 1479 "]\n", 1480 currCnt, 1481 element - currCnt, 1482 offset - currCnt)); 1483 /* add the block below to this block */ 1484 _remove_block_from_sublist(list, element - currCnt, sublist); 1485 offset -= currCnt; 1486 element -= currCnt; 1487 count += currCnt; 1488 } 1489 1490 /* 1491 * Now we need to collect upwardly adjacent blocks, as long as the 1492 * combined block is still correctly aligned for the new size. 1493 */ 1494 AIDXRES_DUMP(("next = %08X, element[%08X].sublist = %02X, count = %08X\n", 1495 element + count, 1496 element + count, 1497 list->element[element + count].sublist, 1498 count)); 1499 while ((max >= offset + count) && 1500 (0 == (offset & count)) && 1501 (AIDXRES_FIRST_ENTRY > (sublist = list->element[(next = element + count)].sublist)) && 1502 (sublist < BYTES2BITS(sizeof(currCnt))) 1503 ) { 1504 currCnt = 1 << sublist; 1505 AIDXRES_DUMP(("_shr_aidxres_list_free: collect upwardly adjacent" 1506 " %08X at %08X [" 1507 AIDXRES_FORMAT_ENTRY 1508 "]\n", 1509 currCnt, 1510 next, 1511 offset + count)); 1512 /* add the block above to this block */ 1513 _remove_block_from_sublist(list, next, sublist); 1514 count += currCnt; 1515 } 1516 1517 /* 1518 * Finally, at this point, we've combined the block to be freed with 1519 * anything that makes sense (that is, might end up reducing the number of 1520 * fragments that we would have in this bank after we're done freeing this 1521 * block). Refragment this collected block into the proper lists (it's 1522 * quite possible that it is only one fragment at this point due to the 1523 * size being a power of two and the alignment being proper, but it's also 1524 * possible that it's not a power of two in size and therefore needs to be 1525 * fragmented again). 1526 */ 1527 AIDXRES_DUMP(("_shr_aidxres_list_free: add defragged block to sublist\n")); 1528 sublist = list->sublist_count - 1; 1529 submask = 1 << sublist; 1530 while (count) { 1531 if (count & submask) { 1532 /* we have a block of this size; put it on the proper list */ 1533 _add_block_to_sublist(list, element, sublist); 1534 element += submask; 1535 count -= submask; 1536 } else { 1537 sublist--; 1538 submask = submask >> 1; 1539 } 1540 } 1541 1542 /* debugging */ 1543 AIDXRES_DUMP_LIST(list); 1544 #ifdef AIDXRES_SANITY_CHECKING 1545 if ((_aidxres_sanity_settings & (_AIDXRES_SANITY_POINT_RETURN | 1546 _AIDXRES_SANITY_FUNC_FREE)) == 1547 (_AIDXRES_SANITY_POINT_RETURN | _AIDXRES_SANITY_FUNC_FREE)) { 1548 result = _aidxres_list_check(list); 1549 if (BCM_E_NONE != result) { 1550 return result; 1551 } 1552 } 1553 #endif /* def AIDXRES_SANITY_CHECKING */ 1554 1555 /* return the actual result */ 1556 return BCM_E_NONE; 1557 } 1558 1559 /* 1560 * Function 1561 * shr_aidxres_list_create 1562 * Purpose 1563 * Create an aligned/contiguous_blocked banked free list 1564 * Parameters 1565 * (out) shr_aidxres_list_handle_t *list = place to put list handle 1566 * (in) shr_aidxres_element_t first = number of first entry to manage 1567 * (in) shr_aidxres_element_t last = number of last entry to manage 1568 * (in) shr_aidxres_element_t validLow = low valid entry value 1569 * (in) shr_aidxres_element_t validHigh = high valid entry value 1570 * (in) shr_aidxres_element_t block_factor = max block power of two 1571 * (in) char *name = name for the list (used for sal_alloc) 1572 * Returns 1573 * BCM_E_NONE if list created successfully 1574 * BCM_E_* as appropriate otherwise 1575 * Notes 1576 * The validLow and validHigh values are used to specify the valid range 1577 * of entries for querying 'free/used' status of an entry; any value not 1578 * in this range is considered an invalid argument, but values that are 1579 * not between first and last will be permanently 'used' and not allowed 1580 * by the free operation nor ever provided by the allocate operation. 1581 * The blocking factor is the actual power of two that is to be used when 1582 * computing maximum block size. Blocks will be able to be manipulated up 1583 * to 2^blocking_factor, but note that blocking_factor must be less than 1584 * or equal to the number of bits used for bank index (so in 8b mode, this 1585 * must be 7 or less, in 16b mode it must be 15 or less, and in 32b mode 1586 * it must be 31 or less). 1587 */ 1588 int 1589 shr_aidxres_list_create(shr_aidxres_list_handle_t *list, 1590 shr_aidxres_element_t first, 1591 shr_aidxres_element_t last, 1592 shr_aidxres_element_t valid_low, 1593 shr_aidxres_element_t valid_high, 1594 shr_aidxres_element_t block_factor, 1595 char *name) 1596 { 1597 shr_aidxres_list_handle_t work_list; /* working list */ 1598 shr_aidxres_element_t banks; /* banks in this list */ 1599 shr_aidxres_element_t count; /* elements in this list */ 1600 shr_aidxres_element_t element; /* working element number */ 1601 shr_aidxres_element_t block_size;/* max block size in elements */ 1602 #ifdef AIDXRES_SANITY_CHECKING 1603 int result; 1604 #endif /* def AIDXRES_SANITY_CHECKING */ 1605 1606 /* 1607 * Constant initialisers are used rather than setting each field 1608 * individually during init since this is usually faster and smaller. 1609 * They're in this function because this is the only place we use them. 1610 */ 1611 const _aidxres_list_sublist_t s_init = {0, 1612 AIDXRES_FINAL_BANK}; 1613 const _aidxres_list_bank_t bl_init = {AIDXRES_USED_BANK, 1614 AIDXRES_USED_BANK}; 1615 const _aidxres_list_bank_sublist_t bs_init = {0, 1616 AIDXRES_FINAL_ENTRY}; 1617 const _aidxres_list_elemdesc_t e_init = {1, 1618 AIDXRES_USED_ENTRY, 1619 AIDXRES_USED_ENTRY, 1620 AIDXRES_USED_ENTRY}; 1621 1622 AIDXRES_DUMP(("shr_aidxres_list_create(*,%08X,%08X,%08X,%08X,%02X," 1623 "(\"%s\") called\n", 1624 first, 1625 last, 1626 valid_low, 1627 valid_high, 1628 block_factor, 1629 name)); 1630 /* check parameter validity */ 1631 if ((valid_low > first) || 1632 (valid_high < last) || 1633 (first > last) || 1634 (block_factor > AIDXRES_BITS_ENTRY) || 1635 #if AIDXRES_MAX_BANK 1636 ((((AIDXRES_MAX_BANK + 1) << AIDXRES_BITS_ENTRY) - 1) < (valid_high - valid_low)) 1637 #else 1638 (AIDXRES_MAX_ENTRY < (valid_high - valid_low)) 1639 #endif 1640 ) { 1641 /* something's not valid on input */ 1642 return BCM_E_PARAM; 1643 } 1644 1645 /* compute the parameters for the memory block */ 1646 count = last - first + 1; 1647 #if AIDXRES_MAX_BANK 1648 banks = (count + AIDXRES_MAX_ENTRY) >> AIDXRES_BITS_ENTRY; 1649 if ((AIDXRES_MAX_BANK+1) < banks) { 1650 /* it's too big still */ 1651 return BCM_E_PARAM; 1652 } 1653 #else 1654 banks = 1; 1655 #endif 1656 1657 /* this is zero based index but we need a one based count from here on */ 1658 block_factor++; 1659 1660 /* try to allocate enough space for the list */ 1661 1662 AIDXRES_DUMP(("shr_aidxres_list_create: Allocate %d byte cell for %s.\n", 1663 ((sizeof(_aidxres_list_t) - sizeof(_aidxres_list_sublist_t)) + 1664 (block_factor * (sizeof(_aidxres_list_sublist_t))) + 1665 ((banks * block_factor) * ((sizeof(_aidxres_list_bank_t)) + sizeof(_aidxres_list_bank_sublist_t))) + 1666 (count * sizeof(_aidxres_list_elemdesc_t))), 1667 name)); 1668 work_list = sal_alloc(((sizeof(_aidxres_list_t) - sizeof(_aidxres_list_sublist_t)) + 1669 (block_factor * (sizeof(_aidxres_list_sublist_t))) + 1670 ((banks * block_factor) * ((sizeof(_aidxres_list_bank_t)) + sizeof(_aidxres_list_bank_sublist_t))) + 1671 (count * sizeof(_aidxres_list_elemdesc_t))), 1672 name); 1673 if (!work_list) { 1674 /* unable to allocate the needed memory */ 1675 (*list) = NULL; 1676 return BCM_E_MEMORY; 1677 } 1678 1679 #if _SHR_AIDXRES_SELF_LOCKING 1680 /* create and then take the mutex */ 1681 AIDXRES_DUMP(("shr_aidxres_list_create: Create mutex/lock for %s\n",name)); 1682 work_list->lock = sal_mutex_create(name); 1683 if (!(work_list->lock)) { 1684 /* unable to create the lock */ 1685 sal_free(work_list); 1686 (*list) = NULL; 1687 return BCM_E_RESOURCE; 1688 } 1689 AIDXRES_DUMP(("shr_aidxres_list_create: take lock for %s\n",name)); 1690 if (sal_mutex_take(work_list->lock, sal_mutex_FOREVER)) { 1691 /* Cound not obtain lock */ 1692 sal_mutex_destroy(work_list->lock); 1693 sal_free(work_list); 1694 (*list) = NULL; 1695 return BCM_E_INTERNAL; 1696 } 1697 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 1698 1699 /* initialise the list root */ 1700 AIDXRES_DUMP(("shr_aidxres_list_create: Initialise list parameters\n")); 1701 work_list->first = first; 1702 work_list->last = last; 1703 work_list->valid_low = valid_low; 1704 work_list->valid_high = valid_high; 1705 work_list->free_count = count; 1706 work_list->alloc_count = 0; 1707 work_list->sublist_count = block_factor; 1708 work_list->bank_max = banks - 1; 1709 work_list->bank_rem_max = (count - 1) & AIDXRES_MAX_ENTRY; 1710 1711 /* 1712 * There is a set of linked lists of banks; one per sublist. These lists 1713 * link the banks together that have free blocks of the appropriate size 1714 * for each sublist (so a bank will be 'in use' on one of these lists if 1715 * it has no free blocks of the appropriate size fo the sublist). 1716 * 1717 * This follows the array of sublist descriptors at the end of the fixed 1718 * length part of the list descriptor, so it points to the byte after the 1719 * final element of the sublist descriptor array. 1720 */ 1721 work_list->bank_list = (_aidxres_list_bank_t*) 1722 (((uint8*)work_list) + 1723 (sizeof(_aidxres_list_t) - sizeof(_aidxres_list_sublist_t)) + 1724 (sizeof(_aidxres_list_sublist_t) * block_factor)); 1725 1726 /* 1727 * There is a set of linked list descriptors, one per sublist per bank. 1728 * These descriptors specify which blocks in each bank are on each 1729 * sublist, and provide access to further such blocks. 1730 * 1731 * This follows the linked lists of banks per sublist, above, so it points 1732 * to the byte after the final element in those lists. 1733 */ 1734 work_list->bank_sublist = (_aidxres_list_bank_sublist_t*) 1735 (((uint8*)(work_list->bank_list)) + 1736 (sizeof(_aidxres_list_bank_t) * 1737 (banks * block_factor))); 1738 1739 /* 1740 * There is a set of element descriptors, one per element. These are 1741 * connected in linked lists per sublist within each bank (they do not 1742 * cross bank boundaries). 1743 * 1744 * This follows the set of bank sublist descriptors. 1745 */ 1746 work_list->element = (_aidxres_list_elemdesc_t*) 1747 (((uint8*)(work_list->bank_sublist)) + 1748 (sizeof(_aidxres_list_bank_sublist_t) * 1749 (banks * block_factor))); 1750 1751 /* debugging */ 1752 AIDXRES_DUMP_LIST(work_list); 1753 1754 /* initialise the sublist information */ 1755 AIDXRES_DUMP(("shr_aidxres_list_create: initialise sublist data (%02X)\n", 1756 block_factor)); 1757 for (element = 0; element < block_factor; element++) { 1758 work_list->sublist[element] = s_init; 1759 } 1760 1761 /* initialise the bank sublist information */ 1762 AIDXRES_DUMP(("shr_aidxres_list_create: initialise bank sublist data" 1763 " (%08X)\n", 1764 banks * block_factor)); 1765 for (element = banks * block_factor; element > 0; /* don't decr here! */) { 1766 element--; /* decrement must come here */ 1767 work_list->bank_sublist[element] = bs_init; 1768 work_list->bank_list[element] = bl_init; 1769 } 1770 1771 /* initialise the bank internal lists */ 1772 AIDXRES_DUMP(("shr_aidxres_list_create: initialise bank elements data" 1773 " (%08X)\n", 1774 count)); 1775 for (element = count; element > 0; /* don't decrement here! */) { 1776 element--; /* decrement must come here */ 1777 work_list->element[element] = e_init; 1778 } 1779 1780 /* debugging */ 1781 AIDXRES_DUMP_LIST(work_list); 1782 1783 /* 1784 * Place the elements into blocks, preferring to make the blocks as large 1785 * as possible, but collecting remnants into smaller blocks as needed. 1786 * 1787 * In general, all but the last bank of elements should be in largest 1788 * possible blocks, and the last bank should have no more than one block 1789 * of each size smaller than the largest possible (unless it is also 1790 * exactly the largest size, in which case it's same as other banks). 1791 */ 1792 AIDXRES_DUMP(("shr_aidxres_list_create:" 1793 " place elements into free blocks\n")); 1794 block_factor--; /* need original value here */ 1795 block_size = 1 << block_factor; 1796 element = 0; 1797 while (count) { 1798 /* there are more elements to be assigned to lists */ 1799 if (count >= block_size) { 1800 /* there's a block of this size; add that block */ 1801 AIDXRES_DUMP(("shr_aidxres_list_create: put %08X of %08X elements" 1802 " into block\n", 1803 block_size, 1804 count)); 1805 _add_block_to_sublist(work_list, element, block_factor); 1806 element += block_size; 1807 count -= block_size; 1808 } else { /* if (count >= block_size) */ 1809 /* no block of this size; try a smaller one */ 1810 block_factor--; 1811 block_size = block_size >> 1; 1812 } /* if (count >= block_size) */ 1813 } /* while (count) */ 1814 1815 /* debugging */ 1816 AIDXRES_DUMP_LIST(work_list); 1817 #ifdef AIDXRES_SANITY_CHECKING 1818 if ((_aidxres_sanity_settings & (_AIDXRES_SANITY_POINT_RETURN | 1819 _AIDXRES_SANITY_FUNC_CREATE)) == 1820 (_AIDXRES_SANITY_POINT_RETURN | _AIDXRES_SANITY_FUNC_CREATE)) { 1821 result = _aidxres_list_check(work_list); 1822 if (BCM_E_NONE != result) { 1823 return result; 1824 } 1825 } 1826 #endif /* def AIDXRES_SANITY_CHECKING */ 1827 1828 #if _SHR_AIDXRES_SELF_LOCKING 1829 /* release the lock now */ 1830 AIDXRES_DUMP(("shr_aidxres_list_create: release lock\n")); 1831 if (sal_mutex_give(work_list->lock)) { 1832 /* could not release lock */ 1833 sal_mutex_destroy(work_list->lock); 1834 sal_free(work_list); 1835 (*list) = NULL; 1836 return BCM_E_INTERNAL; 1837 } 1838 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 1839 1840 /* all done */ 1841 AIDXRES_DUMP(("shr_aidxres_list_create: return\n")); 1842 (*list) = work_list; 1843 return BCM_E_NONE; 1844 } 1845 1846 /* 1847 * Function 1848 * shr_aidxres_list_destroy 1849 * Purpose 1850 * Destroy a list 1851 * Parameters 1852 * (in) shr_aidxres_list_handle_t list = the list handle 1853 * Returns 1854 * BCM_E_NONE if list created successfully 1855 * BCM_E_* as appropriate otherwise 1856 * Notes 1857 * This destroys the list, but does not claim the semaphore first, so the 1858 * caller must take care not to destroy the list while it's being used. 1859 * It is possible that some OSes will not permit the destruction of a lock 1860 * that is in use, so maybe that at least helps. It is also willing to 1861 * destroy the list even if there are still allocated entries. 1862 */ 1863 int 1864 shr_aidxres_list_destroy(shr_aidxres_list_handle_t list) 1865 { 1866 shr_aidxres_element_t block_factor; 1867 shr_aidxres_element_t banks; 1868 shr_aidxres_element_t count; 1869 1870 AIDXRES_DUMP(("shr_aidxres_list_destroy(*) called\n")); 1871 /* check parameter validity */ 1872 if (!list) { 1873 return BCM_E_PARAM; 1874 } 1875 1876 #if _SHR_AIDXRES_SELF_LOCKING 1877 /* destroy the semaphore */ 1878 AIDXRES_DUMP(("shr_aidxres_list_destroy: destroy lock\n")); 1879 sal_mutex_destroy(list->lock); 1880 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 1881 1882 /* cache some data about the list */ 1883 block_factor = list->sublist_count; 1884 banks = list->bank_max + 1; 1885 count = (list->last - list->first) + 1; 1886 1887 /* poison the list */ 1888 1889 AIDXRES_DUMP(("shr_aidxres_list_destroy: obliterate list data (%d" 1890 " bytes)\n", 1891 ((sizeof(_aidxres_list_t) - sizeof(_aidxres_list_sublist_t)) + 1892 (block_factor * (sizeof(_aidxres_list_sublist_t))) + 1893 ((banks * block_factor) * ((sizeof(_aidxres_list_bank_t)) + sizeof(_aidxres_list_bank_sublist_t))) + 1894 (count * sizeof(_aidxres_list_elemdesc_t))))); 1895 sal_memset(list, 1896 0x00, 1897 ((sizeof(_aidxres_list_t) - sizeof(_aidxres_list_sublist_t)) + 1898 (block_factor * (sizeof(_aidxres_list_sublist_t))) + 1899 ((banks * block_factor) * ((sizeof(_aidxres_list_bank_t)) + sizeof(_aidxres_list_bank_sublist_t))) + 1900 (count * sizeof(_aidxres_list_elemdesc_t)))); 1901 1902 /* now free the list */ 1903 AIDXRES_DUMP(("shr_aidxres_list_destroy: free list memory cell\n")); 1904 sal_free(list); 1905 1906 /* all done */ 1907 AIDXRES_DUMP(("shr_aidxres_list_destroy: return\n")); 1908 return BCM_E_NONE; 1909 } 1910 1911 /* 1912 * Function 1913 * shr_aidxres_list_alloc 1914 * Purpose 1915 * Allocate the next available single element from a list 1916 * Parameters 1917 * (in) shr_aidxres_list_handle_t list = list from which to allocate 1918 * (out) shr_aidxres_element_t *element = where to put alloced elem num 1919 * Returns 1920 * BCM_E_NONE if element allocated successfully 1921 * BCM_E_* as appropriate otherwise 1922 * Notes 1923 * As for the idxres list alloc call, this returns *one* element. 1924 */ 1925 int 1926 shr_aidxres_list_alloc(shr_aidxres_list_handle_t list, 1927 shr_aidxres_element_t *element) 1928 { 1929 int result; /* value to be returned to caller */ 1930 1931 /* validate parameters */ 1932 if (!list) { 1933 return BCM_E_PARAM; 1934 } 1935 1936 #if _SHR_AIDXRES_SELF_LOCKING 1937 AIDXRES_DUMP(("shr_aidxres_list_alloc: take lock\n")); 1938 /* claim the lock for the list */ 1939 if (sal_mutex_take(list->lock, sal_mutex_FOREVER)) { 1940 /* Cound not obtain lock */ 1941 return BCM_E_INTERNAL; 1942 } 1943 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 1944 1945 /* allocate an element */ 1946 result = _shr_aidxres_list_alloc(list, 1, element); 1947 1948 #if _SHR_AIDXRES_SELF_LOCKING 1949 AIDXRES_DUMP(("shr_aidxres_list_alloc: release lock\n")); 1950 /* release the lock for the list */ 1951 if (sal_mutex_give(list->lock)) { 1952 /* could not release lock */ 1953 return BCM_E_INTERNAL; 1954 } 1955 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 1956 1957 /* return the actual result */ 1958 return result; 1959 } 1960 1961 /* 1962 * Function 1963 * shr_aidxres_list_alloc_set 1964 * Purpose 1965 * Allocate a set of the next available single elements from a list 1966 * Parameters 1967 * (in) shr_aidxres_list_handle_t list = list from which to allocate 1968 * (in) shr_aidxres_element_t count = number of elements to allocate 1969 * (out) shr_aidxres_element_t *elements = ptr to array for alloced elems 1970 * (out) shr_aidxres_element_t *done = ptr to number of successful allocs 1971 * Returns 1972 * BCM_E_NONE if element allocated successfully 1973 * BCM_E_* as appropriate otherwise 1974 * Notes 1975 * This uses the same function as shr_idxres_list_alloc, except that it 1976 * verifies that there are enough elements free to fulfill the request 1977 * before it tries to allocate any of them. It is still possible that an 1978 * error prevents completion, however, so if the result is not success, 1979 * the done value must be verified (and any elements that were done that 1980 * can not be used must be freed). 1981 * The set is NOT guaranteed to be contiguous. 1982 * The set consists of count *one* element blocks. 1983 */ 1984 int 1985 shr_aidxres_list_alloc_set(shr_aidxres_list_handle_t list, 1986 shr_aidxres_element_t count, 1987 shr_aidxres_element_t *elements, 1988 shr_aidxres_element_t *done) 1989 { 1990 int result; /* value to be returned to caller */ 1991 1992 /* validate parameters */ 1993 if ((!list) || (!elements) || (!done)) { 1994 return BCM_E_PARAM; 1995 } 1996 1997 /* set initial conditions */ 1998 (*done) = 0; 1999 result = BCM_E_NONE; 2000 2001 #if _SHR_AIDXRES_SELF_LOCKING 2002 AIDXRES_DUMP(("shr_aidxres_list_alloc_set: take lock\n")); 2003 /* claim the lock for the list */ 2004 if (sal_mutex_take(list->lock, sal_mutex_FOREVER)) { 2005 /* Cound not obtain lock */ 2006 return BCM_E_INTERNAL; 2007 } 2008 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 2009 2010 /* make sure we have enough free elements */ 2011 if (list->free_count < count) { 2012 /* not enough free elements to comply */ 2013 result = BCM_E_RESOURCE; 2014 } 2015 2016 /* allocate elements */ 2017 while ((0 < count) && (BCM_E_NONE == result)) { 2018 /* allocate this element */ 2019 result = _shr_aidxres_list_alloc(list, 1, elements); 2020 if (BCM_E_NONE == result) { 2021 /* success; update accounting */ 2022 elements++; 2023 count--; 2024 (*done)++; 2025 } 2026 } 2027 2028 #if _SHR_AIDXRES_SELF_LOCKING 2029 AIDXRES_DUMP(("shr_aidxres_list_alloc_set: release lock\n")); 2030 /* release the lock for the list */ 2031 if (sal_mutex_give(list->lock)) { 2032 /* could not release lock */ 2033 return BCM_E_INTERNAL; 2034 } 2035 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 2036 2037 /* return the actual result */ 2038 return result; 2039 } 2040 2041 /* 2042 * Function 2043 * shr_aidxres_list_alloc_block 2044 * Purpose 2045 * Allocate a block (of specified count) of elements from a list 2046 * Parameters 2047 * (in) shr_aidxres_list_handle_t list = list from which to allocate 2048 * (in) shr_aidxres_element_t count = size of block, in elements 2049 * (out) shr_aidxres_element_t *element = where to put alloced elem num 2050 * Returns 2051 * int = BCM_E_NONE if element allocated successfully 2052 * BCM_E_* as appropriate otherwise 2053 * Notes 2054 * The block is guaranteed to be aligned to the next power of two into 2055 * which it fits, and will be contiguous. 2056 */ 2057 int 2058 shr_aidxres_list_alloc_block(shr_aidxres_list_handle_t list, 2059 shr_aidxres_element_t count, 2060 shr_aidxres_element_t *element) 2061 { 2062 int result; /* value to be returned to caller */ 2063 2064 /* validate parameters */ 2065 if (!list) { 2066 return BCM_E_PARAM; 2067 } 2068 2069 #if _SHR_AIDXRES_SELF_LOCKING 2070 AIDXRES_DUMP(("shr_aidxres_list_alloc_block: take lock\n")); 2071 /* claim the lock for the list */ 2072 if (sal_mutex_take(list->lock, sal_mutex_FOREVER)) { 2073 /* Cound not obtain lock */ 2074 return BCM_E_INTERNAL; 2075 } 2076 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 2077 2078 /* allocate an element */ 2079 result = _shr_aidxres_list_alloc(list, count, element); 2080 2081 #if _SHR_AIDXRES_SELF_LOCKING 2082 AIDXRES_DUMP(("shr_aidxres_list_alloc_block: release lock\n")); 2083 /* release the lock for the list */ 2084 if (sal_mutex_give(list->lock)) { 2085 /* could not release lock */ 2086 return BCM_E_INTERNAL; 2087 } 2088 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 2089 2090 /* return the actual result */ 2091 return result; 2092 } 2093 2094 /* 2095 * Function 2096 * shr_aidxres_list_free 2097 * Purpose 2098 * Free an element or block of elements back to a list 2099 * Parameters 2100 * (in) shr_aidxres_list_handle_t list = list from which elem was alloced 2101 * (in) shr_aidxres_element_t element = element number to free 2102 * (or first element in block) 2103 * Returns 2104 * BCM_E_NONE if element freed successfully 2105 * BCM_E_* as appropriate otherwise 2106 * Notes 2107 * Freeing an entry already in the list is checked, as well as freeing an 2108 * entry outside of the list-managed range. Elements can be freed using 2109 * either free call, no matter which alloc call was used to obtain them. 2110 */ 2111 int 2112 shr_aidxres_list_free(shr_aidxres_list_handle_t list, 2113 shr_aidxres_element_t element) 2114 { 2115 int result; /* value to be returned to caller */ 2116 2117 /* validate parameters */ 2118 if (!list) { 2119 /* completely invalid parameters */ 2120 return BCM_E_PARAM; 2121 } 2122 2123 #if _SHR_AIDXRES_SELF_LOCKING 2124 AIDXRES_DUMP(("shr_aidxres_list_free: take lock\n")); 2125 /* claim the lock for the list */ 2126 if (sal_mutex_take(list->lock, sal_mutex_FOREVER)) { 2127 /* Cound not obtain lock */ 2128 return BCM_E_INTERNAL; 2129 } 2130 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 2131 2132 result = _shr_aidxres_list_free(list, element); 2133 2134 #if _SHR_AIDXRES_SELF_LOCKING 2135 AIDXRES_DUMP(("shr_aidxres_list_free: release lock\n")); 2136 /* release the lock for the list */ 2137 if (sal_mutex_give(list->lock)) { 2138 /* could not release lock */ 2139 return BCM_E_INTERNAL; 2140 } 2141 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 2142 2143 /* return the actual result */ 2144 return result; 2145 } 2146 2147 /* 2148 * Function 2149 * shr_aidxres_list_free_set 2150 * Purpose 2151 * Free a set of elements back to a list 2152 * Parameters 2153 * (in) shr_aidxres_list_handle_t list = list to which to free 2154 * (in) shr_aidxres_element_t count = number of elements to free 2155 * (in) shr_aidxres_element_t *elements = ptr to array for elems to free 2156 * (out) shr_aidxres_element_t *done = ptr to number of successful frees 2157 * Returns 2158 * BCM_E_NONE if element allocated successfully 2159 * BCM_E_* as appropriate otherwise 2160 * Notes 2161 * This uses the same function as shr_idxres_list_free. It is possible 2162 * that an error prevents completion, so if the result is not success, the 2163 * done value must be verified (and any elements that were not done that 2164 * can not be reused must still be freed). Elements can be freed using 2165 * either free call, no matter which alloc method was used to obtain them. 2166 */ 2167 int 2168 shr_aidxres_list_free_set(shr_aidxres_list_handle_t list, 2169 shr_aidxres_element_t count, 2170 shr_aidxres_element_t *elements, 2171 shr_aidxres_element_t *done) 2172 { 2173 int result; /* value to be returned to caller */ 2174 2175 /* validate parameters */ 2176 if ((!list) || (!elements) || (!done)) { 2177 return BCM_E_PARAM; 2178 } 2179 2180 /* set initial conditions */ 2181 (*done) = 0; 2182 result = BCM_E_NONE; 2183 2184 #if _SHR_AIDXRES_SELF_LOCKING 2185 AIDXRES_DUMP(("shr_aidxres_list_free_set: take lock\n")); 2186 /* claim the lock for the list */ 2187 if (sal_mutex_take(list->lock, sal_mutex_FOREVER)) { 2188 /* Cound not obtain lock */ 2189 return BCM_E_INTERNAL; 2190 } 2191 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 2192 2193 /* free elements */ 2194 while ((0 < count) && (BCM_E_NONE == result)) { 2195 /* free this element */ 2196 result = _shr_aidxres_list_free(list, *elements); 2197 if (BCM_E_NONE == result) { 2198 /* success; update accounting */ 2199 elements++; 2200 count--; 2201 (*done)++; 2202 } 2203 } 2204 2205 #if _SHR_AIDXRES_SELF_LOCKING 2206 AIDXRES_DUMP(("shr_aidxres_list_free_set: release lock\n")); 2207 /* release the lock for the list */ 2208 if (sal_mutex_give(list->lock)) { 2209 /* could not release lock */ 2210 return BCM_E_INTERNAL; 2211 } 2212 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 2213 2214 /* return the actual result */ 2215 return result; 2216 } 2217 2218 /* 2219 * Function 2220 * shr_idxres_list_state 2221 * Purpose 2222 * Get status of the list itself 2223 * Parameters 2224 * (in) shr_aidxres_list_handle_t list = list to check 2225 * (out) shr_aidxres_element_t *first = buffer for first value 2226 * (out) shr_aidxres_element_t *last = buffer for last value 2227 * (out) shr_aidxres_element_t *valid_low = buffer for valid_low value 2228 * (out) shr_aidxres_element_t *valid_high = buffer for valid_high value 2229 * (out) shr_aidxres_element_t *free_count = buffer for free_count value 2230 * (out) shr_aidxres_element_t *alloc_count = buffer for alloc_count value 2231 * (out) shr_aidxres_element_t *largest_free = buff for largest free value 2232 * (out) shr_aidxres_element_t *block_factor = buffer for block factor val 2233 * Returns 2234 * BCM_E_NONE if successful 2235 * BCM_E_* as appropriate otherwise 2236 * Notes 2237 * If you don't want to fetch a specific attribute of the list, pass 2238 * NULL for the pointer to that attribute's location. 2239 * There is no set function for these items; most are set at creation of 2240 * list and the others are current state of list. 2241 * Largest free is the largest number of elements that a block can contain 2242 * and still have the alloc request fulfilled on this list. 2243 */ 2244 int 2245 shr_aidxres_list_state(shr_aidxres_list_handle_t list, 2246 shr_aidxres_element_t *first, 2247 shr_aidxres_element_t *last, 2248 shr_aidxres_element_t *valid_low, 2249 shr_aidxres_element_t *valid_high, 2250 shr_aidxres_element_t *free_count, 2251 shr_aidxres_element_t *alloc_count, 2252 shr_aidxres_element_t *largest_free, 2253 shr_aidxres_element_t *block_factor) 2254 { 2255 _aidxres_list_entry_t sublist; 2256 2257 if (!list) { 2258 /* the list has to be valid */ 2259 return BCM_E_PARAM; 2260 } 2261 2262 /* Return the values requested by the caller */ 2263 if (first) { 2264 (*first) = list->first; 2265 } 2266 if (last) { 2267 (*last) = list->last; 2268 } 2269 if (valid_low) { 2270 (*valid_low) = list->valid_low; 2271 } 2272 if (valid_high) { 2273 (*valid_high) = list->valid_high; 2274 } 2275 if (free_count) { 2276 (*free_count) = list->free_count; 2277 } 2278 if (alloc_count) { 2279 (*alloc_count) = list->alloc_count; 2280 } 2281 if (block_factor) { 2282 (*block_factor) = list->sublist_count - 1; 2283 } 2284 2285 /* compute the values requested by the caller & return them */ 2286 if (largest_free) { 2287 *largest_free = 0; 2288 if (list->free_count) { 2289 /* there are free elements; scan the sublists */ 2290 for (sublist = 0; sublist < (list->sublist_count); sublist++) { 2291 /* check sublists in increasing order of block size */ 2292 if (list->sublist[sublist].free_count) { 2293 /* this sublist has at least one free block; keep it */ 2294 *largest_free = 1 << sublist; 2295 } 2296 } /* for (iterate sublists in increasing order) */ 2297 } /* if (list->free_count) */ 2298 } /* if (largest_free) */ 2299 2300 /* indicate success to the caller */ 2301 return BCM_E_NONE; 2302 } 2303 2304 /* 2305 * Function 2306 * shr_aidxres_list_elem_state 2307 * Purpose 2308 * See if an element is currently in use 2309 * Parameters 2310 * (in) shr_aidxres_list_handle_t list = list to check 2311 * (in) shr_aidxres_element_t element = element number to check 2312 * Returns 2313 * BCM_E_EXISTS if element is in use 2314 * BCM_E_NOT_FOUND if element is not in use 2315 * BCM_E_* as appropriate otherwise 2316 * Notes 2317 * This function ALWAYS returns an error (never BCM_E_NONE). 2318 */ 2319 int 2320 shr_aidxres_list_elem_state(shr_aidxres_list_handle_t list, 2321 shr_aidxres_element_t element) 2322 { 2323 /* validate parameters */ 2324 if ((!list) || 2325 (element < list->valid_low) || 2326 (element > list->valid_high)) { 2327 /* completely invalid parameters */ 2328 return BCM_E_PARAM; 2329 } 2330 2331 /* further validation */ 2332 if ((element < list->first) || 2333 (element > list->last)) { 2334 /* getting state for elments not managed by the list (in use) */ 2335 return BCM_E_EXISTS; 2336 } 2337 2338 /* remove bias on entry number */ 2339 element -= list->first; 2340 2341 /* get the element state and parse it */ 2342 if (AIDXRES_FIRST_ENTRY <= list->element[element].sublist) { 2343 /* this element is a member of an allocated block */ 2344 return BCM_E_EXISTS; 2345 } 2346 if (list->sublist_count <= list->element[element].sublist) { 2347 /* there's a problem with this element (invalid sublist) */ 2348 return BCM_E_INTERNAL; 2349 } 2350 /* it's on a valid sublist, so it's not in use */ 2351 return BCM_E_NOT_FOUND; 2352 } 2353 2354 /* 2355 * Function 2356 * shr_aidxres_list_block_state 2357 * Purpose 2358 * See if an element is currently in use 2359 * Parameters 2360 * (in) shr_aidxres_list_handle_t list = list to check 2361 * (in) shr_aidxres_element_t element = element number to check 2362 * (in) shr_aidxres_element_t size = elements in expected block 2363 * Returns 2364 * BCM_E_EMPTY if none of the elements are in use 2365 * BCM_E_FULL if all of the elements are in use 2366 * BCM_E_CONFIG if elements are in use but block(s) do not match 2367 * BCM_E_EXISTS if some of the elements are in use but not all of them 2368 * BCM_E_PARAM if any of the elements is not valid 2369 * BCM_E_* as appropriate otherwise 2370 * Notes 2371 * This function ALWAYS returns an error (never BCM_E_NONE). 2372 */ 2373 int 2374 shr_aidxres_list_block_state(shr_aidxres_list_handle_t list, 2375 shr_aidxres_element_t element, 2376 shr_aidxres_element_t size) 2377 { 2378 shr_aidxres_element_t index; 2379 int result = BCM_E_EMPTY; 2380 2381 /* validate parameters */ 2382 if ((!list) || 2383 (element < list->valid_low) || 2384 (element + size > list->valid_high)) { 2385 /* completely invalid parameters */ 2386 return BCM_E_PARAM; 2387 } 2388 if ((element + size < list->first) || 2389 (element > list->last)) { 2390 /* entire requested block is not managed by the list (so in use) */ 2391 /* no way to tell anything about blocks in this space */ 2392 return BCM_E_FULL; 2393 } 2394 if (((element < list->first) && 2395 (element + size >= list->first)) || 2396 ((element <= list->last) && 2397 (element + size > list->last))) { 2398 /* block spans a managed boundary; inconsistent block contents */ 2399 return BCM_E_CONFIG; 2400 } 2401 2402 /* remove bias on entry number */ 2403 element -= list->first; 2404 2405 #if _SHR_AIDXRES_SELF_LOCKING 2406 /* claim the lock for the list */ 2407 if (sal_mutex_take(list->lock, sal_mutex_FOREVER)) { 2408 /* Cound not obtain lock */ 2409 return BCM_E_INTERNAL; 2410 } 2411 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 2412 2413 /* see if the block is as specified */ 2414 if (AIDXRES_FIRST_ENTRY == list->element[element].sublist) { 2415 /* element specified is first of block */ 2416 if (size == list->element[element].elem_count) { 2417 /* block is expected size */ 2418 result = BCM_E_FULL; 2419 } else { 2420 /* block is not expected size */ 2421 result = BCM_E_CONFIG; 2422 } 2423 } else if (AIDXRES_FIRST_ENTRY < list->element[element].sublist) { 2424 /* element is allocated but not the first element in the block */ 2425 result = BCM_E_CONFIG; 2426 } else if (list->sublist_count <= list->element[element].sublist) { 2427 /* corruption */ 2428 result = BCM_E_INTERNAL; 2429 } else { 2430 /* checked the first element and it is free; scan the rest */ 2431 for (index = 1; index < size; index++) { 2432 if (AIDXRES_FIRST_ENTRY <= list->element[element + index].sublist) { 2433 /* this element is allocated */ 2434 result = BCM_E_EXISTS; 2435 } else if (list->sublist_count <= list->element[element + index].sublist) { 2436 /* corruption */ 2437 result = BCM_E_INTERNAL; 2438 break; 2439 } 2440 } 2441 } 2442 2443 #if _SHR_AIDXRES_SELF_LOCKING 2444 /* release the lock for the list */ 2445 if (sal_mutex_give(list->lock)) { 2446 /* could not release lock */ 2447 return BCM_E_INTERNAL; 2448 } 2449 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 2450 return result; 2451 } 2452 2453 /* 2454 * Function 2455 * shr_aidxres_list_reserve 2456 * Purpose 2457 * Reserve a range of elements in a list 2458 * Parameters 2459 * (in) shr_aidxres_list_handle_t list = list handle 2460 * (in) shr_aidxres_element_t first = first entry to reserve 2461 * (in) shr_aidxres_element_t last = last entry to reserve 2462 * Returns 2463 * bcm_error_t = BCM_E_NONE if elements reserved successfully 2464 * BCM_E_* as appropriate otherwise 2465 * Notes 2466 * This is truly an inefficient way to manage top and bottom reservations 2467 * unless they are not known at list creation time, as this does not do 2468 * anything to adjust the physical size of the list's workspace; it merely 2469 * takes the requested range out of the available elements. 2470 * Elements reserved in this manner can be returned using free; they are 2471 * allocated as elements instead of blocks. 2472 */ 2473 int 2474 shr_aidxres_list_reserve(shr_aidxres_list_handle_t list, 2475 shr_aidxres_element_t first, 2476 shr_aidxres_element_t last) 2477 { 2478 bcm_error_t result; /* value to be returned to caller */ 2479 shr_aidxres_element_t curr_elem; /* working current element address */ 2480 shr_aidxres_element_t first_elem; /* first element of current block */ 2481 shr_aidxres_element_t last_elem; /* last element of current block */ 2482 _aidxres_list_entry_t sublist; /* sublist number for this block */ 2483 _aidxres_list_entry_t blk_size; /* how big is this block */ 2484 _aidxres_list_entry_t blk_mask; /* bits within this block */ 2485 2486 AIDXRES_DUMP(("shr_aidxres_list_reserve(*,%08X,%08X) called\n", 2487 first, 2488 last)); 2489 /* validate parameters */ 2490 if ((!list) || 2491 (first < list->valid_low) || 2492 (last > list->valid_high) || 2493 (last < first)) { 2494 return BCM_E_PARAM; 2495 } 2496 2497 /* ensure the requrested range is entirely allocatable */ 2498 if ((first < list->first) || 2499 (last > list->last)) { 2500 return BCM_E_RESOURCE; 2501 } 2502 2503 #if _SHR_AIDXRES_SELF_LOCKING 2504 /* claim the lock for the list */ 2505 AIDXRES_DUMP(("shr_aidxres_list_reserve: take lock\n")); 2506 if (sal_mutex_take(list->lock, sal_mutex_FOREVER)) { 2507 /* Cound not obtain lock */ 2508 return BCM_E_INTERNAL; 2509 } 2510 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 2511 2512 /* remove bias on range */ 2513 first -= list->first; 2514 last -= list->first; 2515 2516 /* scan the entire range to ensure availability */ 2517 result = BCM_E_NONE; 2518 AIDXRES_DUMP(("shr_aidxres_list_reserve: checking that elements %08X..%08X" 2519 " are free\n", 2520 first, 2521 last)); 2522 for (curr_elem = first; curr_elem <= last; curr_elem++) { 2523 if (AIDXRES_FIRST_ENTRY <= list->element[curr_elem].sublist) { 2524 /* at least one element is not available */ 2525 result = BCM_E_RESOURCE; 2526 break; 2527 } 2528 } 2529 2530 /* if all is well so far, reserve the entries in question */ 2531 if (BCM_E_NONE == result) { 2532 /* need to reserve the entries */ 2533 for (curr_elem = first; curr_elem <= last; /* no incr here */ ) { 2534 sublist = list->element[curr_elem].sublist; 2535 blk_size = 1 << sublist; 2536 blk_mask = blk_size - 1; 2537 /* claim this block */ 2538 first_elem = curr_elem & (~blk_mask); 2539 last_elem = first_elem + blk_mask; 2540 AIDXRES_DUMP(("shr_aidxres_list_reserve: claiming block with" 2541 " elements %08X..%08X\n", 2542 first_elem, 2543 last_elem)); 2544 _remove_block_from_sublist(list, first_elem, sublist); 2545 /* free any unwanted low elements */ 2546 blk_size = curr_elem - first_elem; 2547 while (blk_size) { 2548 sublist--; 2549 blk_mask = 1 << sublist; 2550 AIDXRES_DUMP(("shr_aidxres_list_reserve: try to return %08X of" 2551 " %08X lead-in elements at %08X\n", 2552 blk_mask, 2553 blk_size, 2554 first_elem)); 2555 if (blk_size & blk_mask) { 2556 _add_block_to_sublist(list, first_elem, sublist); 2557 blk_size = blk_size - blk_mask; 2558 first_elem = first_elem + blk_mask; 2559 } 2560 } /* while (blk_size) */ 2561 /* set any wanted elements as in use */ 2562 AIDXRES_DUMP(("shr_aidxres_list_reserve: marking wanted elements" 2563 " %08X..%08X as in use\n", 2564 curr_elem, 2565 (last<last_elem)?last:last_elem)); 2566 while ((curr_elem <= last) && (curr_elem <= last_elem)) { 2567 list->element[curr_elem].elem_count = 1; 2568 list->element[curr_elem].sublist = AIDXRES_FIRST_ENTRY; 2569 curr_elem++; 2570 } /* while ((curr_elem <= last) && (curr_elem <= last_elem)) */ 2571 /* free any unwanted high elements */ 2572 blk_size = last_elem - curr_elem + 1; 2573 sublist = 0; 2574 while (blk_size) { 2575 blk_mask = 1 << sublist; 2576 AIDXRES_DUMP(("shr_aidxres_list_reserve: try to return %08X of" 2577 " %08X lead-out elements at %08X\n", 2578 blk_mask, 2579 blk_size, 2580 curr_elem)); 2581 if (blk_size & blk_mask) { 2582 _add_block_to_sublist(list, curr_elem, sublist); 2583 blk_size = blk_size - blk_mask; 2584 curr_elem = curr_elem + blk_mask; 2585 } 2586 sublist++; 2587 } /* while (blk_size) */ 2588 } /* for (curr_elem = first; curr_elem <= last;) */ 2589 /* adjust list metadata */ 2590 AIDXRES_DUMP(("shr_aidxres_list_reserve: adjust list allocated and" 2591 " free counts\n")); 2592 list->alloc_count += last - first + 1; 2593 list->free_count -= last - first + 1; 2594 } /* if (BCM_E_NONE == result) */ 2595 2596 #if _SHR_AIDXRES_SELF_LOCKING 2597 /* release the lock for the list */ 2598 AIDXRES_DUMP(("shr_aidxres_list_reserve: release lock\n")); 2599 if (sal_mutex_give(list->lock)) { 2600 /* could not release lock */ 2601 return BCM_E_INTERNAL; 2602 } 2603 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 2604 2605 /* debugging */ 2606 AIDXRES_DUMP_LIST(list); 2607 2608 /* return the actual result */ 2609 return result; 2610 } 2611 2612 /* 2613 * Function 2614 * shr_aidxres_list_reserve_block 2615 * Purpose 2616 * Reserve a block in a list 2617 * Parameters 2618 * (in) shr_aidxres_list_handle_t list = list handle 2619 * (in) shr_aidxres_element_t first = first element in block to reserve 2620 * (in) shr_aidxres_element_t count = number of elements in block 2621 * Returns 2622 * bcm_error_t = BCM_E_NONE if elements reserved successfully 2623 * BCM_E_* as appropriate otherwise 2624 * Notes 2625 * This is truly an inefficient way to manage top and bottom reservations 2626 * unless they are not known at list creation time, as this does not do 2627 * anything to adjust the physical size of the list's workspace; it merely 2628 * takes the requested range out of the available elements. 2629 * Elements reserved in this manner can be returned using free; they are 2630 * allocated a a single block. 2631 * The block to be reserved must satisfy all allocation rules for blocks 2632 * (for example, alignment and size) that apply to the list. 2633 */ 2634 int 2635 shr_aidxres_list_reserve_block(shr_aidxres_list_handle_t list, 2636 shr_aidxres_element_t first, 2637 shr_aidxres_element_t count) 2638 { 2639 bcm_error_t result; /* value to be returned to caller */ 2640 shr_aidxres_element_t curr_elem; /* working current element address */ 2641 shr_aidxres_element_t first_elem; /* first element of current block */ 2642 shr_aidxres_element_t last_elem; /* last element of current block */ 2643 shr_aidxres_element_t last; /* last element of block to reserve */ 2644 _aidxres_list_entry_t sublist; /* sublist number for this block */ 2645 _aidxres_list_entry_t blk_size; /* how big is this block */ 2646 _aidxres_list_entry_t blk_mask; /* bits within this block */ 2647 2648 last = (first + count - 1); 2649 AIDXRES_DUMP(("shr_aidxres_list_reserve_block(*,%08X,%08X) called\n", 2650 first, 2651 count)); 2652 /* validate parameters */ 2653 if ((!list) || 2654 (first < list->valid_low) || 2655 (last > list->valid_high) || 2656 (count > ((uint32)1 << (list->sublist_count - 1)))) { 2657 return BCM_E_PARAM; 2658 } 2659 2660 /* ensure the requrested range is entirely allocatable */ 2661 if ((first < list->first) || 2662 (last > list->last)) { 2663 return BCM_E_RESOURCE; 2664 } 2665 2666 /* remove bias on range */ 2667 first -= list->first; 2668 last -= list->first; 2669 2670 /* verify block alignment */ 2671 AIDXRES_DUMP(("shr_aidxres_list_reserve_block: verify block legality\n")); 2672 sublist = 0; 2673 blk_mask = 1; 2674 while (blk_mask < count) { 2675 sublist++; 2676 blk_mask = blk_mask << 1; 2677 } 2678 AIDXRES_DUMP(("shr_aidxres_list_reserve_block: sublist %02x, mask %08X\n", 2679 sublist, 2680 blk_mask)); 2681 if (first & (blk_mask - 1)) { 2682 /* the block is not aligned properly */ 2683 return BCM_E_PARAM; 2684 } 2685 2686 #if _SHR_AIDXRES_SELF_LOCKING 2687 /* claim the lock for the list */ 2688 AIDXRES_DUMP(("shr_aidxres_list_reserve_block: take lock\n")); 2689 if (sal_mutex_take(list->lock, sal_mutex_FOREVER)) { 2690 /* Cound not obtain lock */ 2691 return BCM_E_INTERNAL; 2692 } 2693 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 2694 2695 /* scan the entire range to ensure availability */ 2696 result = BCM_E_NONE; 2697 AIDXRES_DUMP(("shr_aidxres_list_reserve_block: checking that elements %08X..%08X" 2698 " are free\n", 2699 first, 2700 last)); 2701 for (curr_elem = first; curr_elem <= last; curr_elem++) { 2702 if (AIDXRES_FIRST_ENTRY <= list->element[curr_elem].sublist) { 2703 /* at least one element is not available */ 2704 result = BCM_E_RESOURCE; 2705 break; 2706 } 2707 } 2708 2709 /* if all is well so far, reserve the entries in question */ 2710 if (BCM_E_NONE == result) { 2711 /* need to reserve the entries */ 2712 for (curr_elem = first; curr_elem <= last; /* no incr here */ ) { 2713 sublist = list->element[curr_elem].sublist; 2714 blk_size = 1 << sublist; 2715 blk_mask = blk_size - 1; 2716 /* claim this block */ 2717 first_elem = curr_elem & (~blk_mask); 2718 last_elem = first_elem + blk_mask; 2719 AIDXRES_DUMP(("shr_aidxres_list_reserve_block: claiming block with" 2720 " elements %08X..%08X\n", 2721 first_elem, 2722 last_elem)); 2723 _remove_block_from_sublist(list, first_elem, sublist); 2724 /* free any unwanted low elements */ 2725 blk_size = curr_elem - first_elem; 2726 while (blk_size) { 2727 sublist--; 2728 blk_mask = 1 << sublist; 2729 AIDXRES_DUMP(("shr_aidxres_list_reserve_block: try to return" 2730 " %08X of %08X lead-in elements at %08X\n", 2731 blk_mask, 2732 blk_size, 2733 first_elem)); 2734 if (blk_size & blk_mask) { 2735 _add_block_to_sublist(list, first_elem, sublist); 2736 blk_size = blk_size - blk_mask; 2737 first_elem = first_elem + blk_mask; 2738 } 2739 } /* while (blk_size) */ 2740 /* don't bother labelling here; use block label below */ 2741 curr_elem = ((last<last_elem)?last:last_elem) + 1; 2742 /* free any unwanted high elements */ 2743 blk_size = last_elem - curr_elem + 1; 2744 sublist = 0; 2745 while (blk_size) { 2746 blk_mask = 1 << sublist; 2747 AIDXRES_DUMP(("shr_aidxres_list_reserve_block: try to return" 2748 " %08X of %08X lead-out elements at %08X\n", 2749 blk_mask, 2750 blk_size, 2751 curr_elem)); 2752 if (blk_size & blk_mask) { 2753 _add_block_to_sublist(list, curr_elem, sublist); 2754 blk_size = blk_size - blk_mask; 2755 curr_elem = curr_elem + blk_mask; 2756 } 2757 sublist++; 2758 } /* while (blk_size) */ 2759 } /* for (curr_elem = first; curr_elem <= last;) */ 2760 /* mark the requested block as in use */ 2761 AIDXRES_DUMP(("shr_aidxres_list_reserve_block: marking block containing" 2762 " elements %08X..%08X as in use\n", 2763 first, 2764 last)); 2765 _prep_block_for_alloc(list, first, count); 2766 /* adjust list metadata */ 2767 AIDXRES_DUMP(("shr_aidxres_list_reserve_block: adjust list allocated" 2768 " and free counts\n")); 2769 list->alloc_count += count; 2770 list->free_count -= count; 2771 } /* if (BCM_E_NONE == result) */ 2772 2773 #if _SHR_AIDXRES_SELF_LOCKING 2774 /* release the lock for the list */ 2775 AIDXRES_DUMP(("shr_aidxres_list_reserve_block: release lock\n")); 2776 if (sal_mutex_give(list->lock)) { 2777 /* could not release lock */ 2778 return BCM_E_INTERNAL; 2779 } 2780 #endif /* _SHR_AIDXRES_SELF_LOCKING */ 2781 2782 /* debugging */ 2783 AIDXRES_DUMP_LIST(list); 2784 2785 /* return the actual result */ 2786 return result; 2787 } 2788 2789