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 }