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 (7788B)


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