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_mdb.c (138272B)


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