blob: 3da0309148a3e38bd0c75469aad371ef5b9e3eec [file] [log] [blame]
/******************************************************************************
*
* This file is provided under a dual license. When you use or
* distribute this software, you may choose to be licensed under
* version 2 of the GNU General Public License ("GPLv2 License")
* or BSD License.
*
* GPLv2 License
*
* Copyright(C) 2017 MediaTek Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* 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 http://www.gnu.org/licenses/gpl-2.0.html for more details.
*
* BSD LICENSE
*
* Copyright(C) 2017 MediaTek Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
/*! \file prealloc.c
* \brief memory preallocation module
*
* This file contains all implementations of memory preallocation module
*/
/*******************************************************************************
* C O M P I L E R F L A G S
********************************************************************************
*/
/*******************************************************************************
* E X T E R N A L R E F E R E N C E S
********************************************************************************
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include "precomp.h"
/*******************************************************************************
* C O N S T A N T S
********************************************************************************
*/
/*******************************************************************************
* D A T A T Y P E S
********************************************************************************
*/
/*
* ----------------- ---------------- ----------
* | PRE_MEM_BLOCK |-pItemArray->| PRE_MEM_ITEM |-pvBuffer->| Memory |
* |---------------| |--------------| ----------
* | PRE_MEM_BLOCK |->... | PRE_MEM_ITEM |-pvBuffer->----------
* |---------------| |--------------| | Memory |
* . . ----------
* . .
* . .
*/
struct PRE_MEM_ITEM {
PVOID pvBuffer;
};
struct PRE_MEM_BLOCK {
PUCHAR pucName;
struct PRE_MEM_ITEM *pItemArray;
UINT_32 u4Count;
UINT_32 u4Size;
UINT_32 u4KmallocFlags;
UINT_32 u4Curr;
};
/*******************************************************************************
* P U B L I C D A T A
********************************************************************************
*/
/*******************************************************************************
* P R I V A T E D A T A
********************************************************************************
*/
static INT_32 blockCount;
static struct PRE_MEM_BLOCK arMemBlocks[MEM_ID_NUM];
/*******************************************************************************
* M A C R O S
********************************************************************************
*/
/*******************************************************************************
* F U N C T I O N D E C L A R A T I O N S
********************************************************************************
*/
/*******************************************************************************
* F U N C T I O N S
********************************************************************************
*/
/*----------------------------------------------------------------------------*/
/*!
* \brief export function for memory preallocation
*
* \param[in] memId memory id.
*
* \retval void pointer to the memory address
*/
/*----------------------------------------------------------------------------*/
PVOID preallocGetMem(enum ENUM_MEM_ID memId)
{
struct PRE_MEM_BLOCK *block = NULL;
UINT_32 curr = 0, count = 0;
PUCHAR name = NULL;
/* check memId exist */
if (memId < 0 || memId >= MEM_ID_NUM) {
MP_Err("request wrong memId %d", memId);
return NULL;
}
block = &arMemBlocks[memId];
curr = block->u4Curr;
count = block->u4Count;
name = block->pucName;
block->u4Curr = (curr + 1) % count; /* point to next */
/* return request memory address */
MP_Info("request [%s], return [%d]\n", name, curr);
return block->pItemArray[curr].pvBuffer;
}
EXPORT_SYMBOL(preallocGetMem);
static void preallocFree(void)
{
INT_32 i = 0, j = 0;
struct PRE_MEM_BLOCK *block = NULL;
struct PRE_MEM_ITEM *items = NULL;
PVOID memory = NULL;
for (i = 0; i < MEM_ID_NUM; i++) {
block = &arMemBlocks[i];
MP_Info("free [%d], block name=\"%s\" count=%d size=%d\n",
i, block->pucName, block->u4Count, block->u4Size);
items = block->pItemArray;
if (items == NULL)
continue;
/* free memory */
for (j = 0; j < block->u4Count; j++) {
memory = items[j].pvBuffer;
MP_Info(" - [%d] memory 0x%p\n", j, memory);
kfree(memory);
}
/* free items */
MP_Info(" - items 0x%p\n", items);
kfree(items);
memset(block, 0, sizeof(*block));
}
}
static int preallocAlloc(void)
{
INT_32 i = 0, j = 0;
struct PRE_MEM_BLOCK *block = NULL;
struct PRE_MEM_ITEM *items = NULL;
PVOID memory = NULL;
for (i = 0; i < MEM_ID_NUM; i++) {
block = &arMemBlocks[i];
MP_Info("allocate [%d] block name=\"%s\" count=%d size=%d\n",
i, block->pucName, block->u4Count, block->u4Size);
/* allocate u4Count items */
items = kcalloc(block->u4Count, sizeof(*items), GFP_KERNEL);
if (items == NULL) {
MP_Err("allocate [%d] items failed\n", i);
goto fail;
}
MP_Info(" + items 0x%p\n", items);
block->pItemArray = items;
for (j = 0; j < block->u4Count; j++) {
/* allocate u4Size memory */
memory = kmalloc(block->u4Size, block->u4KmallocFlags);
if (memory == NULL) {
MP_Err("allocate [%d][%d] memory failed\n", i, j);
goto fail;
}
MP_Info(" + [%d] memory 0x%p\n", j, memory);
items[j].pvBuffer = memory;
}
}
return 0;
fail:
preallocFree();
return -ENOMEM;
}
static void preallocAddBlock(enum ENUM_MEM_ID memId,
PUCHAR name, UINT_32 count, UINT_32 size, UINT_32 kmallocFlags)
{
if (memId != blockCount) {
MP_Err("memId %d != index %d\n", memId, blockCount);
return;
}
arMemBlocks[blockCount].pucName = name;
arMemBlocks[blockCount].pItemArray = NULL;
arMemBlocks[blockCount].u4Count = count;
arMemBlocks[blockCount].u4Size = size;
arMemBlocks[blockCount].u4KmallocFlags = kmallocFlags;
arMemBlocks[blockCount].u4Curr = 0;
blockCount++;
}
static int __init preallocInit(void)
{
blockCount = 0;
/* ADD BLOCK START, follow the sequence of ENUM_MEM_ID */
preallocAddBlock(MEM_ID_NIC_ADAPTER, "NIC ADAPTER MEMORY",
1, MGT_BUFFER_SIZE,
GFP_KERNEL);
#if defined(_HIF_USB)
preallocAddBlock(MEM_ID_TX_CMD, "TX CMD",
USB_REQ_TX_CMD_CNT, USB_TX_CMD_BUF_SIZE,
GFP_KERNEL);
#if CFG_USB_TX_AGG
preallocAddBlock(MEM_ID_TX_DATA, "TX AGG DATA",
(USB_TC_NUM * USB_REQ_TX_DATA_CNT), USB_TX_DATA_BUFF_SIZE,
GFP_KERNEL);
#else
preallocAddBlock(MEM_ID_TX_DATA, "TX DATA",
USB_REQ_TX_DATA_CNT, USB_TX_DATA_BUFF_SIZE,
GFP_KERNEL);
#endif
preallocAddBlock(MEM_ID_RX_EVENT, "RX EVENT",
USB_REQ_RX_EVENT_CNT, USB_RX_EVENT_BUF_SIZE,
GFP_KERNEL);
preallocAddBlock(MEM_ID_RX_DATA, "RX DATA",
USB_REQ_RX_DATA_CNT, USB_RX_DATA_BUF_SIZE,
GFP_KERNEL);
#endif
/* ADD BLOCK END */
return preallocAlloc();
}
static void __exit preallocExit(void)
{
preallocFree();
}
module_init(preallocInit);
module_exit(preallocExit);