openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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