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

mpool.c (7257B)


      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 
      8 #include <mpool.h>
      9 
     10 #ifdef __KERNEL__
     11 
     12 /* 
     13  * Abstractions used when compiling for Linux kernel mode. 
     14  */
     15 
     16 #include <lkm.h>
     17 
     18 /*
     19  * We cannot use the linux kernel SAL for MALLOC/FREE because 
     20  * the current implementation of sal_alloc() allocates memory 
     21  * out of an mpool created by this module...
     22  */
     23 #define MALLOC(x) kmalloc(x, GFP_ATOMIC)
     24 #define FREE(x) kfree(x)
     25 
     26 static spinlock_t _mpool_lock;
     27 #define MPOOL_LOCK_INIT() spin_lock_init(&_mpool_lock)
     28 #define MPOOL_LOCK() unsigned long flags; spin_lock_irqsave(&_mpool_lock, flags)
     29 #define MPOOL_UNLOCK() spin_unlock_irqrestore(&_mpool_lock, flags)
     30 
     31 #else /* !__KERNEL__*/
     32 
     33 /* 
     34  * Abstractions used when compiling for Linux user mode. 
     35  */
     36 
     37 #include <stdlib.h>
     38 #include <sal/core/sync.h>
     39 
     40 #define MALLOC(x) malloc(x)
     41 #define FREE(x) free(x)
     42 
     43 static sal_sem_t _mpool_lock;
     44 #define MPOOL_LOCK_INIT() _mpool_lock = sal_sem_create("mpool_lock", 1, 1)
     45 #define MPOOL_LOCK() sal_sem_take(_mpool_lock, sal_sem_FOREVER)
     46 #define MPOOL_UNLOCK() sal_sem_give(_mpool_lock)
     47 
     48 #endif /* __KERNEL__ */
     49 
     50 /* Allow external override for system cache line size */
     51 #ifndef BCM_CACHE_LINE_BYTES
     52 #ifdef L1_CACHE_BYTES
     53 #define BCM_CACHE_LINE_BYTES L1_CACHE_BYTES
     54 #else
     55 #define BCM_CACHE_LINE_BYTES 128 /* Should be fine on most platforms */
     56 #endif
     57 #endif
     58 
     59 #define MPOOL_BUF_SIZE               1024
     60 #define MPOOL_BUF_ALLOC_COUNT_MAX      16
     61 
     62 typedef struct mpool_mem_s {
     63     unsigned char *address;
     64     int size;
     65     struct mpool_mem_s *prev;
     66     struct mpool_mem_s *next;
     67 } mpool_mem_t;
     68 
     69 static int _buf_alloc_count;
     70 static mpool_mem_t *mpool_buf[MPOOL_BUF_ALLOC_COUNT_MAX];
     71 static mpool_mem_t *free_list;
     72 
     73 #define ALLOC_INIT_MPOOL_BUF(ptr) \
     74         ptr = MALLOC((sizeof(mpool_mem_t) * MPOOL_BUF_SIZE)); \
     75         if (ptr) { \
     76             int i; \
     77             for (i = 0; i < MPOOL_BUF_SIZE - 1; i++) { \
     78                 ptr[i].next = &ptr[i+1]; \
     79             } \
     80             ptr[MPOOL_BUF_SIZE - 1].next = NULL; \
     81             free_list = &ptr[0]; \
     82         }
     83 
     84 /*
     85  * Function: mpool_init
     86  *
     87  * Purpose:
     88  *    Initialize mpool lock.
     89  * Parameters:
     90  *    None
     91  * Returns:
     92  *    Always 0
     93  */
     94 int 
     95 mpool_init(void)
     96 {
     97     MPOOL_LOCK_INIT();
     98     return 0;
     99 }
    100 
    101 #ifdef TRACK_DMA_USAGE
    102 static int _dma_mem_used = 0;
    103 #endif
    104 
    105 /*
    106  * Function: mpool_alloc
    107  *
    108  * Purpose:
    109  *    Allocate memory block from mpool.
    110  * Parameters:
    111  *    pool - mpool handle (from mpool_create)
    112  *    size - size of memory block to allocate
    113  * Returns:
    114  *    Pointer to allocated memory block or NULL if allocation fails.
    115  */
    116 void *
    117 mpool_alloc(mpool_handle_t pool, int size)
    118 {
    119     mpool_mem_t *ptr = pool, *newptr = NULL;
    120     int mod;
    121 
    122     MPOOL_LOCK();
    123 
    124     if (size < BCM_CACHE_LINE_BYTES) {
    125         size = BCM_CACHE_LINE_BYTES;
    126     }
    127 
    128     mod = size & (BCM_CACHE_LINE_BYTES - 1);
    129     if (mod != 0 ) {
    130         size += (BCM_CACHE_LINE_BYTES - mod);
    131     }
    132     while (ptr && ptr->next) {
    133         if (ptr->next->address - (ptr->address + ptr->size) >= size) {
    134             break;
    135         }
    136         ptr = ptr->next;
    137     }
    138   
    139     if (!(ptr && ptr->next)) {
    140         MPOOL_UNLOCK();
    141         return NULL;
    142     }
    143 
    144     if (!free_list) {
    145         if (_buf_alloc_count == MPOOL_BUF_ALLOC_COUNT_MAX) {
    146             MPOOL_UNLOCK();
    147             return NULL;
    148         }
    149 
    150         ALLOC_INIT_MPOOL_BUF(mpool_buf[_buf_alloc_count]);
    151 
    152         if (mpool_buf[_buf_alloc_count] == NULL) {
    153             MPOOL_UNLOCK();
    154             return NULL;
    155         }
    156 
    157         _buf_alloc_count++;
    158     }
    159 
    160     newptr = free_list;
    161     free_list = free_list->next;
    162   
    163     newptr->address = ptr->address + ptr->size;
    164     newptr->size = size;
    165     newptr->next = ptr->next;
    166     newptr->prev = ptr;
    167     ptr->next->prev = newptr;
    168     ptr->next = newptr;
    169 #ifdef TRACK_DMA_USAGE
    170     _dma_mem_used += size;
    171 #endif
    172 
    173     MPOOL_UNLOCK();
    174     return newptr->address;
    175 }
    176 
    177 
    178 /*
    179  * Function: mpool_free
    180  *
    181  * Purpose:
    182  *    Free memory block allocated from mpool..
    183  * Parameters:
    184  *    pool - mpool handle (from mpool_create)
    185  *    addr - address of memory block to free
    186  * Returns:
    187  *    Nothing
    188  */
    189 void 
    190 mpool_free(mpool_handle_t pool, void *addr)
    191 {
    192     unsigned char *address = (unsigned char *)addr;  
    193     mpool_mem_t *head = pool, *ptr = NULL;
    194 
    195     MPOOL_LOCK();
    196 
    197     if (!(head && head->prev)) {
    198         MPOOL_UNLOCK();
    199         return;
    200     }
    201 
    202     ptr = head->prev->prev;
    203 
    204     while (ptr && (ptr != head)) {
    205         if (ptr->address == address) {
    206 #ifdef TRACK_DMA_USAGE
    207             _dma_mem_used -= ptr->size;
    208 #endif
    209             ptr->prev->next = ptr->next;
    210             ptr->next->prev = ptr->prev;
    211             ptr->next = free_list;
    212             free_list = ptr;
    213             break;
    214         }
    215         ptr = ptr->prev;
    216     }
    217 
    218     MPOOL_UNLOCK();
    219 }
    220 
    221 /*
    222  * Function: mpool_create
    223  *
    224  * Purpose:
    225  *    Create and initialize mpool control structures.
    226  * Parameters:
    227  *    base_ptr - pointer to mpool memory block
    228  *    size - total size of mpool memory block
    229  * Returns:
    230  *    mpool handle
    231  * Notes
    232  *    The mpool handle returned must be used for subsequent
    233  *    memory allocations from the mpool.
    234  */
    235 mpool_handle_t
    236 mpool_create(void *base_ptr, int size)
    237 {
    238     mpool_mem_t *head, *tail;
    239     int mod = (int)(((unsigned long)base_ptr) & (BCM_CACHE_LINE_BYTES - 1));
    240     int i;
    241 
    242     MPOOL_LOCK();
    243 
    244     for (i = 0; i < MPOOL_BUF_ALLOC_COUNT_MAX; i++) {
    245         mpool_buf[i] = NULL;
    246     }
    247 
    248     _buf_alloc_count = 0;
    249 
    250     ALLOC_INIT_MPOOL_BUF(mpool_buf[_buf_alloc_count]);
    251 
    252     if (mpool_buf[_buf_alloc_count] == NULL) {
    253         MPOOL_UNLOCK();
    254         return NULL;
    255     }
    256 
    257     _buf_alloc_count++;
    258 
    259     if (mod) {
    260         base_ptr = (char*)base_ptr + (BCM_CACHE_LINE_BYTES - mod);
    261         size -= (BCM_CACHE_LINE_BYTES - mod);
    262     }
    263     size &= ~(BCM_CACHE_LINE_BYTES - 1);
    264 
    265     head = free_list;
    266     free_list = free_list->next;
    267     tail = free_list;
    268     free_list = free_list->next;
    269 
    270     head->size = tail->size = 0;
    271     head->address = base_ptr;
    272     tail->address = head->address + size;
    273     head->prev = tail;
    274     head->next = tail;
    275     tail->prev = head;
    276     tail->next = NULL;
    277 
    278     MPOOL_UNLOCK();
    279     return head;
    280 }
    281 
    282 /*
    283  * Function: mpool_destroy
    284  *
    285  * Purpose:
    286  *    Free mpool control structures.
    287  * Parameters:
    288  *    pool - mpool handle (from mpool_create)
    289  * Returns:
    290  *    Always 0
    291  */
    292 int
    293 mpool_destroy(mpool_handle_t pool)
    294 {
    295     int i;
    296 
    297     MPOOL_LOCK();
    298 
    299     if ((mpool_mem_t *)pool != mpool_buf[0]) {
    300         MPOOL_UNLOCK();
    301         return 0;
    302     }
    303 
    304     for (i = 0; i < MPOOL_BUF_ALLOC_COUNT_MAX; i++) {
    305         if (mpool_buf[i]) {
    306             FREE(mpool_buf[i]);
    307             mpool_buf[i] = NULL;
    308         }
    309     }
    310 
    311     MPOOL_UNLOCK();
    312 
    313     return 0;
    314 }
    315 
    316 /*
    317  * Function: mpool_usage
    318  *
    319  * Purpose:
    320  *    Report total sum of allocated mpool memory.
    321  * Parameters:
    322  *    pool - mpool handle (from mpool_create)
    323  * Returns:
    324  *    Number of bytes currently allocated using mpool_alloc.
    325  */
    326 int
    327 mpool_usage(mpool_handle_t pool)
    328 {
    329     int usage = 0;
    330     mpool_mem_t *ptr;
    331 
    332     MPOOL_LOCK();
    333 
    334     for (ptr = pool; ptr; ptr = ptr->next) {
    335         usage += ptr->size;
    336     }
    337 
    338     MPOOL_UNLOCK();
    339 
    340     return usage;
    341 }