123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- /****************************************************************************
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2020 VeriSilicon Holdings Co., Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- *****************************************************************************
- *
- * The GPL License (GPL)
- *
- * Copyright (c) 2020 VeriSilicon Holdings Co., Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program;
- *
- *****************************************************************************
- *
- * Note: This software is released under dual MIT and GPL licenses. A
- * recipient may use this file under the terms of either the MIT license or
- * GPL License. If you wish to use only one license not the other, you can
- * indicate your decision by deleting one of the above license notices in your
- * version of this file.
- *
- *****************************************************************************/
- #include "cma.h"
- #ifdef __KERNEL__
- struct block_list {
- struct block_list *next;
- u64 base_addr;
- u64 size;
- };
- struct cma_mem_context {
- u64 base;
- u64 size;
- u64 align;
- struct block_list free_blocks;
- struct block_list used_blocks;
- };
- static struct cma_mem_context *g_cma_mem_ctx;
- static inline void add_free_blocks(struct block_list *free_item);
- static inline void add_used_blocks(struct block_list *used_item);
- struct mutex viv_cma_mutex;
- int vsi_cma_init(u64 base, u64 size, u64 align)
- {
- struct block_list *item = NULL;
- pr_debug("enter %s\n", __func__);
- if (!size || (size <= align))
- return -EINVAL;
- g_cma_mem_ctx = kzalloc(sizeof(struct cma_mem_context), GFP_KERNEL);
- memset(g_cma_mem_ctx, 0, sizeof(*g_cma_mem_ctx));
- g_cma_mem_ctx->base = (base + align - 1) & ~(align - 1);
- g_cma_mem_ctx->size = size - (g_cma_mem_ctx->base - base);
- g_cma_mem_ctx->align = align;
- pr_debug("addr:0x%llx, size:0x%llx, alignment:0x%llx.\n",
- g_cma_mem_ctx->base, g_cma_mem_ctx->size,
- g_cma_mem_ctx->align);
- item = kzalloc(sizeof(struct block_list), GFP_KERNEL);
- if (!item) {
- kzfree(g_cma_mem_ctx);
- g_cma_mem_ctx = NULL;
- return -ENOMEM;
- }
- item->next = NULL;
- item->base_addr = g_cma_mem_ctx->base;
- item->size = g_cma_mem_ctx->size;
- g_cma_mem_ctx->free_blocks.next = item;
- g_cma_mem_ctx->used_blocks.next = NULL;
- mutex_init(&viv_cma_mutex);
- return 0;
- }
- int vsi_cma_release(void)
- {
- int result = 0;
- struct block_list *item, *pFree;
- if (!g_cma_mem_ctx->free_blocks.next
- || g_cma_mem_ctx->free_blocks.next->next
- || g_cma_mem_ctx->used_blocks.next) {
- pr_err("Warning memory is not free.\n");
- }
- item = g_cma_mem_ctx->free_blocks.next;
- while (item) {
- pFree = item;
- item = item->next;
- /* kzfree(pFree); */
- }
- kzfree(g_cma_mem_ctx);
- g_cma_mem_ctx = NULL;
- mutex_destroy(&viv_cma_mutex);
- return result;
- }
- u64 vsi_cma_alloc(u64 size)
- {
- u64 addr = ~0U;
- struct block_list *item;
- struct block_list *found;
- mutex_lock(&viv_cma_mutex);
- if (!size || (size > g_cma_mem_ctx->size)) {
- mutex_unlock(&viv_cma_mutex);
- return ~0U;
- }
- pr_debug("enter %s\n", __func__);
- pr_debug
- ("addr:0x%llx, size:0x%llx, alignment:0x%llx, reqsize:0x%llx.\n",
- g_cma_mem_ctx->base, g_cma_mem_ctx->size, g_cma_mem_ctx->align,
- size);
- size += g_cma_mem_ctx->align - 1;
- size &= ~(g_cma_mem_ctx->align - 1);
- /*TODO: need to lock this block */
- item = &g_cma_mem_ctx->free_blocks;
- while (item->next && (item->next->size < size))
- item = item->next;
- found = item->next;
- if (found) {
- item->next = found->next;
- if ((found->size - size) >= g_cma_mem_ctx->align) {
- item = kzalloc(sizeof(struct block_list), GFP_KERNEL);
- if (item) {
- item->base_addr = found->base_addr + size;
- item->size = found->size - size;
- found->size = size;
- pr_debug("new free block: base_addr=0x%llx,\n",
- item->base_addr);
- add_free_blocks(item);
- }
- }
- pr_debug("new used block: base_addr=0x%llx, size=0x%llx \n",
- found->base_addr, found->size);
- add_used_blocks(found);
- addr = found->base_addr;
- }
- pr_debug("block allocated: base_addr=0x%llx\n", addr);
- mutex_unlock(&viv_cma_mutex);
- return addr;
- }
- void vsi_cma_free(u64 addr)
- {
- pr_debug("enter %s\n", __func__);
- pr_debug("block to free: base_addr=0x%llx\n", addr);
- mutex_lock(&viv_cma_mutex);
- if (addr) {
- /*TODO: need to lock this block */
- struct block_list *item, *free_item;
- item = &g_cma_mem_ctx->used_blocks;
- while (item->next && (item->next->base_addr != addr))
- item = item->next;
- free_item = item->next;
- item->next = free_item->next;
- if (((item->base_addr + item->size) != free_item->base_addr) ||
- ((free_item->base_addr + item->size) != ((free_item->next) ?
- free_item->next->base_addr :
- (g_cma_mem_ctx->base
- +
- g_cma_mem_ctx->size)))) {
- struct block_list *loc_item;
- struct block_list *pre_item = NULL;
- struct block_list *success_item = NULL;
- loc_item = &g_cma_mem_ctx->free_blocks;
- while (loc_item->next) {
- if ((loc_item->next->base_addr +
- loc_item->next->size) ==
- free_item->base_addr) {
- pre_item = loc_item;
- }
- if ((free_item->base_addr + free_item->size) ==
- loc_item->next->base_addr) {
- success_item = loc_item;
- }
- loc_item = loc_item->next;
- }
- if (success_item) {
- loc_item = success_item->next;
- free_item->size += loc_item->size;
- success_item->next = loc_item->next;
- kzfree(loc_item);
- }
- if (pre_item) {
- loc_item = pre_item->next;
- free_item->base_addr = loc_item->base_addr;
- free_item->size += loc_item->size;
- pre_item->next = loc_item->next;
- kzfree(loc_item);
- }
- } else {
- pr_err("no adjacent block free\n");
- }
- add_free_blocks(free_item);
- }
- mutex_unlock(&viv_cma_mutex);
- }
- static inline void add_free_blocks(struct block_list *free_item)
- {
- struct block_list *item;
- item = &g_cma_mem_ctx->free_blocks;
- while (item->next && (item->next->size < free_item->size))
- item = item->next;
- free_item->next = item->next;
- item->next = free_item;
- item = &g_cma_mem_ctx->free_blocks;
- while (item->next)
- item = item->next;
- }
- static inline void add_used_blocks(struct block_list *used_item)
- {
- struct block_list *item;
- item = &g_cma_mem_ctx->used_blocks;
- while (item->next && (item->next->base_addr < used_item->base_addr))
- item = item->next;
- used_item->next = item->next;
- item->next = used_item;
- item = &g_cma_mem_ctx->used_blocks;
- while (item->next)
- item = item->next;
- }
- #endif
|