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 }