2018-08-07 02:14:37 -05:00
|
|
|
/*
|
2021-01-28 10:38:47 -06:00
|
|
|
* Copyright 2007-2020 Broadcom Inc. All rights reserved.
|
|
|
|
*
|
|
|
|
* Permission is granted to use, copy, modify and/or distribute this
|
|
|
|
* software under either one of the licenses below.
|
|
|
|
*
|
|
|
|
* License Option 1: GPL
|
2018-08-07 02:14:37 -05:00
|
|
|
*
|
2018-08-23 14:05:14 -05:00
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License, version 2, as
|
|
|
|
* published by the Free Software Foundation (the "GPL").
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License version 2 (GPLv2) for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* version 2 (GPLv2) along with this source code.
|
2021-01-28 10:38:47 -06:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* License Option 2: Broadcom Open Network Switch APIs (OpenNSA) license
|
|
|
|
*
|
|
|
|
* This software is governed by the Broadcom Open Network Switch APIs license:
|
|
|
|
* https://www.broadcom.com/products/ethernet-connectivity/software/opennsa
|
2018-08-07 02:14:37 -05:00
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* $Id: mpool.c,v 1.18 Broadcom SDK $
|
|
|
|
* $Copyright: (c) 2005 Broadcom Corp.
|
|
|
|
* All Rights Reserved.$
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <mpool.h>
|
|
|
|
|
|
|
|
#ifdef __KERNEL__
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Abstractions used when compiling for Linux kernel mode.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <lkm.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We cannot use the linux kernel SAL for MALLOC/FREE because
|
|
|
|
* the current implementation of sal_alloc() allocates memory
|
|
|
|
* out of an mpool created by this module...
|
|
|
|
*/
|
|
|
|
#define MALLOC(x) kmalloc(x, GFP_ATOMIC)
|
|
|
|
#define FREE(x) kfree(x)
|
|
|
|
|
|
|
|
static spinlock_t _mpool_lock;
|
|
|
|
#define MPOOL_LOCK_INIT() spin_lock_init(&_mpool_lock)
|
|
|
|
#define MPOOL_LOCK() unsigned long flags; spin_lock_irqsave(&_mpool_lock, flags)
|
|
|
|
#define MPOOL_UNLOCK() spin_unlock_irqrestore(&_mpool_lock, flags)
|
|
|
|
|
|
|
|
#else /* !__KERNEL__*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Abstractions used when compiling for Linux user mode.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sal/core/sync.h>
|
|
|
|
|
|
|
|
#define MALLOC(x) malloc(x)
|
|
|
|
#define FREE(x) free(x)
|
|
|
|
|
|
|
|
static sal_sem_t _mpool_lock;
|
|
|
|
#define MPOOL_LOCK_INIT() _mpool_lock = sal_sem_create("mpool_lock", 1, 1)
|
|
|
|
#define MPOOL_LOCK() sal_sem_take(_mpool_lock, sal_sem_FOREVER)
|
|
|
|
#define MPOOL_UNLOCK() sal_sem_give(_mpool_lock)
|
|
|
|
|
|
|
|
#endif /* __KERNEL__ */
|
|
|
|
|
|
|
|
/* Allow external override for system cache line size */
|
|
|
|
#ifndef BCM_CACHE_LINE_BYTES
|
|
|
|
#ifdef L1_CACHE_BYTES
|
|
|
|
#define BCM_CACHE_LINE_BYTES L1_CACHE_BYTES
|
|
|
|
#else
|
|
|
|
#define BCM_CACHE_LINE_BYTES 128 /* Should be fine on most platforms */
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2019-12-19 00:26:34 -06:00
|
|
|
#define MPOOL_BUF_SIZE 1024
|
2021-01-28 10:38:47 -06:00
|
|
|
#define MPOOL_BUF_ALLOC_COUNT_MAX 128
|
2019-12-19 00:26:34 -06:00
|
|
|
|
2018-08-07 02:14:37 -05:00
|
|
|
typedef struct mpool_mem_s {
|
|
|
|
unsigned char *address;
|
|
|
|
int size;
|
2019-12-19 00:26:34 -06:00
|
|
|
struct mpool_mem_s *prev;
|
2018-08-07 02:14:37 -05:00
|
|
|
struct mpool_mem_s *next;
|
|
|
|
} mpool_mem_t;
|
|
|
|
|
2021-01-28 10:38:47 -06:00
|
|
|
static int _mpool_count;
|
2019-12-19 00:26:34 -06:00
|
|
|
static int _buf_alloc_count;
|
|
|
|
static mpool_mem_t *mpool_buf[MPOOL_BUF_ALLOC_COUNT_MAX];
|
|
|
|
static mpool_mem_t *free_list;
|
|
|
|
|
2021-01-28 10:38:47 -06:00
|
|
|
static mpool_mem_t *
|
|
|
|
_mpool_buf_create(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
mpool_mem_t *ptr;
|
|
|
|
|
|
|
|
if (_buf_alloc_count == MPOOL_BUF_ALLOC_COUNT_MAX) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
mpool_buf[_buf_alloc_count] = MALLOC((sizeof(mpool_mem_t) * MPOOL_BUF_SIZE));
|
|
|
|
if (!mpool_buf[_buf_alloc_count]) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = mpool_buf[_buf_alloc_count];
|
|
|
|
for (i = 0; i < MPOOL_BUF_SIZE - 1; i++) {
|
|
|
|
ptr[i].next = &ptr[i+1];
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr[MPOOL_BUF_SIZE - 1].next = NULL;
|
|
|
|
|
|
|
|
if (free_list) {
|
|
|
|
free_list->next = &ptr[0];
|
|
|
|
} else {
|
|
|
|
free_list = &ptr[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
_buf_alloc_count++;
|
|
|
|
return ptr;
|
|
|
|
}
|
2019-12-19 00:26:34 -06:00
|
|
|
|
2018-08-07 02:14:37 -05:00
|
|
|
/*
|
|
|
|
* Function: mpool_init
|
|
|
|
*
|
|
|
|
* Purpose:
|
|
|
|
* Initialize mpool lock.
|
|
|
|
* Parameters:
|
|
|
|
* None
|
|
|
|
* Returns:
|
|
|
|
* Always 0
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
mpool_init(void)
|
|
|
|
{
|
2021-01-28 10:38:47 -06:00
|
|
|
int i;
|
|
|
|
|
2018-08-07 02:14:37 -05:00
|
|
|
MPOOL_LOCK_INIT();
|
2021-01-28 10:38:47 -06:00
|
|
|
_buf_alloc_count = 0;
|
|
|
|
_mpool_count = 0;
|
|
|
|
for (i = 0; i < MPOOL_BUF_ALLOC_COUNT_MAX; i++) {
|
|
|
|
mpool_buf[i] = NULL;
|
|
|
|
}
|
|
|
|
free_list = NULL;
|
2018-08-07 02:14:37 -05:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef TRACK_DMA_USAGE
|
|
|
|
static int _dma_mem_used = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Function: mpool_alloc
|
|
|
|
*
|
|
|
|
* Purpose:
|
|
|
|
* Allocate memory block from mpool.
|
|
|
|
* Parameters:
|
|
|
|
* pool - mpool handle (from mpool_create)
|
|
|
|
* size - size of memory block to allocate
|
|
|
|
* Returns:
|
|
|
|
* Pointer to allocated memory block or NULL if allocation fails.
|
|
|
|
*/
|
|
|
|
void *
|
|
|
|
mpool_alloc(mpool_handle_t pool, int size)
|
|
|
|
{
|
|
|
|
mpool_mem_t *ptr = pool, *newptr = NULL;
|
|
|
|
int mod;
|
|
|
|
|
|
|
|
MPOOL_LOCK();
|
|
|
|
|
2019-12-19 00:26:34 -06:00
|
|
|
if (size < BCM_CACHE_LINE_BYTES) {
|
|
|
|
size = BCM_CACHE_LINE_BYTES;
|
|
|
|
}
|
|
|
|
|
2018-08-07 02:14:37 -05:00
|
|
|
mod = size & (BCM_CACHE_LINE_BYTES - 1);
|
2021-01-28 10:38:47 -06:00
|
|
|
if (mod != 0) {
|
2018-08-07 02:14:37 -05:00
|
|
|
size += (BCM_CACHE_LINE_BYTES - mod);
|
|
|
|
}
|
|
|
|
while (ptr && ptr->next) {
|
|
|
|
if (ptr->next->address - (ptr->address + ptr->size) >= size) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ptr = ptr->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(ptr && ptr->next)) {
|
|
|
|
MPOOL_UNLOCK();
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-12-19 00:26:34 -06:00
|
|
|
|
2021-01-28 10:38:47 -06:00
|
|
|
if (!free_list && !_mpool_buf_create()) {
|
|
|
|
MPOOL_UNLOCK();
|
|
|
|
return NULL;
|
2018-08-07 02:14:37 -05:00
|
|
|
}
|
2019-12-19 00:26:34 -06:00
|
|
|
|
|
|
|
newptr = free_list;
|
|
|
|
free_list = free_list->next;
|
2018-08-07 02:14:37 -05:00
|
|
|
|
|
|
|
newptr->address = ptr->address + ptr->size;
|
|
|
|
newptr->size = size;
|
|
|
|
newptr->next = ptr->next;
|
2019-12-19 00:26:34 -06:00
|
|
|
newptr->prev = ptr;
|
|
|
|
ptr->next->prev = newptr;
|
2018-08-07 02:14:37 -05:00
|
|
|
ptr->next = newptr;
|
|
|
|
#ifdef TRACK_DMA_USAGE
|
|
|
|
_dma_mem_used += size;
|
|
|
|
#endif
|
|
|
|
|
2019-12-19 00:26:34 -06:00
|
|
|
MPOOL_UNLOCK();
|
2018-08-07 02:14:37 -05:00
|
|
|
return newptr->address;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Function: mpool_free
|
|
|
|
*
|
|
|
|
* Purpose:
|
|
|
|
* Free memory block allocated from mpool..
|
|
|
|
* Parameters:
|
|
|
|
* pool - mpool handle (from mpool_create)
|
|
|
|
* addr - address of memory block to free
|
|
|
|
* Returns:
|
|
|
|
* Nothing
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
mpool_free(mpool_handle_t pool, void *addr)
|
|
|
|
{
|
|
|
|
unsigned char *address = (unsigned char *)addr;
|
2019-12-19 00:26:34 -06:00
|
|
|
mpool_mem_t *head = pool, *ptr = NULL;
|
2018-08-07 02:14:37 -05:00
|
|
|
|
|
|
|
MPOOL_LOCK();
|
2019-12-19 00:26:34 -06:00
|
|
|
|
|
|
|
if (!(head && head->prev)) {
|
|
|
|
MPOOL_UNLOCK();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = head->prev->prev;
|
|
|
|
|
|
|
|
while (ptr && (ptr != head)) {
|
|
|
|
if (ptr->address == address) {
|
2018-08-07 02:14:37 -05:00
|
|
|
#ifdef TRACK_DMA_USAGE
|
2019-12-19 00:26:34 -06:00
|
|
|
_dma_mem_used -= ptr->size;
|
2018-08-07 02:14:37 -05:00
|
|
|
#endif
|
2019-12-19 00:26:34 -06:00
|
|
|
ptr->prev->next = ptr->next;
|
|
|
|
ptr->next->prev = ptr->prev;
|
|
|
|
ptr->next = free_list;
|
|
|
|
free_list = ptr;
|
2018-08-07 02:14:37 -05:00
|
|
|
break;
|
|
|
|
}
|
2019-12-19 00:26:34 -06:00
|
|
|
ptr = ptr->prev;
|
2018-08-07 02:14:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
MPOOL_UNLOCK();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Function: mpool_create
|
|
|
|
*
|
|
|
|
* Purpose:
|
|
|
|
* Create and initialize mpool control structures.
|
|
|
|
* Parameters:
|
|
|
|
* base_ptr - pointer to mpool memory block
|
|
|
|
* size - total size of mpool memory block
|
|
|
|
* Returns:
|
|
|
|
* mpool handle
|
|
|
|
* Notes
|
|
|
|
* The mpool handle returned must be used for subsequent
|
|
|
|
* memory allocations from the mpool.
|
|
|
|
*/
|
|
|
|
mpool_handle_t
|
|
|
|
mpool_create(void *base_ptr, int size)
|
|
|
|
{
|
|
|
|
mpool_mem_t *head, *tail;
|
|
|
|
int mod = (int)(((unsigned long)base_ptr) & (BCM_CACHE_LINE_BYTES - 1));
|
|
|
|
|
|
|
|
MPOOL_LOCK();
|
|
|
|
|
2021-01-28 10:38:47 -06:00
|
|
|
if (!free_list || !(free_list->next)) {
|
|
|
|
if (!_mpool_buf_create()) {
|
|
|
|
MPOOL_UNLOCK();
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-12-19 00:26:34 -06:00
|
|
|
}
|
|
|
|
|
2018-08-07 02:14:37 -05:00
|
|
|
if (mod) {
|
|
|
|
base_ptr = (char*)base_ptr + (BCM_CACHE_LINE_BYTES - mod);
|
|
|
|
size -= (BCM_CACHE_LINE_BYTES - mod);
|
|
|
|
}
|
|
|
|
size &= ~(BCM_CACHE_LINE_BYTES - 1);
|
|
|
|
|
2019-12-19 00:26:34 -06:00
|
|
|
head = free_list;
|
|
|
|
free_list = free_list->next;
|
|
|
|
tail = free_list;
|
|
|
|
free_list = free_list->next;
|
|
|
|
|
2018-08-07 02:14:37 -05:00
|
|
|
head->size = tail->size = 0;
|
|
|
|
head->address = base_ptr;
|
|
|
|
tail->address = head->address + size;
|
2019-12-19 00:26:34 -06:00
|
|
|
head->prev = tail;
|
2018-08-07 02:14:37 -05:00
|
|
|
head->next = tail;
|
2019-12-19 00:26:34 -06:00
|
|
|
tail->prev = head;
|
2018-08-07 02:14:37 -05:00
|
|
|
tail->next = NULL;
|
2021-01-28 10:38:47 -06:00
|
|
|
_mpool_count++;
|
2018-08-07 02:14:37 -05:00
|
|
|
|
|
|
|
MPOOL_UNLOCK();
|
|
|
|
return head;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Function: mpool_destroy
|
|
|
|
*
|
|
|
|
* Purpose:
|
|
|
|
* Free mpool control structures.
|
|
|
|
* Parameters:
|
|
|
|
* pool - mpool handle (from mpool_create)
|
|
|
|
* Returns:
|
|
|
|
* Always 0
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
mpool_destroy(mpool_handle_t pool)
|
|
|
|
{
|
2019-12-19 00:26:34 -06:00
|
|
|
int i;
|
2021-01-28 10:38:47 -06:00
|
|
|
mpool_mem_t *head = pool;
|
2019-12-19 00:26:34 -06:00
|
|
|
|
2018-08-07 02:14:37 -05:00
|
|
|
MPOOL_LOCK();
|
|
|
|
|
2021-01-28 10:38:47 -06:00
|
|
|
if (!(head && head->prev)) {
|
2019-12-19 00:26:34 -06:00
|
|
|
MPOOL_UNLOCK();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-01-28 10:38:47 -06:00
|
|
|
head->prev->next = free_list;
|
|
|
|
free_list = head;
|
|
|
|
_mpool_count--;
|
|
|
|
|
|
|
|
if (_mpool_count == 0) {
|
|
|
|
for (i = 0; i < MPOOL_BUF_ALLOC_COUNT_MAX; i++) {
|
|
|
|
if (mpool_buf[i]) {
|
|
|
|
FREE(mpool_buf[i]);
|
|
|
|
mpool_buf[i] = NULL;
|
|
|
|
}
|
2019-12-19 00:26:34 -06:00
|
|
|
}
|
2021-01-28 10:38:47 -06:00
|
|
|
free_list = NULL;
|
2018-08-07 02:14:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
MPOOL_UNLOCK();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Function: mpool_usage
|
|
|
|
*
|
|
|
|
* Purpose:
|
|
|
|
* Report total sum of allocated mpool memory.
|
|
|
|
* Parameters:
|
|
|
|
* pool - mpool handle (from mpool_create)
|
|
|
|
* Returns:
|
|
|
|
* Number of bytes currently allocated using mpool_alloc.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
mpool_usage(mpool_handle_t pool)
|
|
|
|
{
|
|
|
|
int usage = 0;
|
|
|
|
mpool_mem_t *ptr;
|
|
|
|
|
|
|
|
MPOOL_LOCK();
|
|
|
|
|
|
|
|
for (ptr = pool; ptr; ptr = ptr->next) {
|
2019-12-19 00:26:34 -06:00
|
|
|
usage += ptr->size;
|
2018-08-07 02:14:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
MPOOL_UNLOCK();
|
|
|
|
|
|
|
|
return usage;
|
|
|
|
}
|