| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Support for Intel Camera Imaging ISP subsystem. |
| * Copyright (c) 2010-2015, Intel Corporation. |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms and conditions of the GNU General Public License, |
| * version 2, as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope 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. |
| */ |
| |
| #include "hmm.h" |
| #include "ia_css_rmgr.h" |
| |
| #include <type_support.h> |
| #include <assert_support.h> |
| #include <platform_support.h> /* memset */ |
| #include <ia_css_debug.h> |
| |
| /* |
| * @brief VBUF resource handles |
| */ |
| #define NUM_HANDLES 1000 |
| static struct ia_css_rmgr_vbuf_handle handle_table[NUM_HANDLES]; |
| |
| /* |
| * @brief VBUF resource pool - refpool |
| */ |
| static struct ia_css_rmgr_vbuf_pool refpool; |
| |
| /* |
| * @brief VBUF resource pool - writepool |
| */ |
| static struct ia_css_rmgr_vbuf_pool writepool = { |
| .copy_on_write = true, |
| }; |
| |
| /* |
| * @brief VBUF resource pool - hmmbufferpool |
| */ |
| static struct ia_css_rmgr_vbuf_pool hmmbufferpool = { |
| .copy_on_write = true, |
| .recycle = true, |
| .size = 32, |
| }; |
| |
| struct ia_css_rmgr_vbuf_pool *vbuf_ref = &refpool; |
| struct ia_css_rmgr_vbuf_pool *vbuf_write = &writepool; |
| struct ia_css_rmgr_vbuf_pool *hmm_buffer_pool = &hmmbufferpool; |
| |
| /* |
| * @brief Initialize the reference count (host, vbuf) |
| */ |
| static void rmgr_refcount_init_vbuf(void) |
| { |
| /* initialize the refcount table */ |
| memset(&handle_table, 0, sizeof(handle_table)); |
| } |
| |
| /* |
| * @brief Retain the reference count for a handle (host, vbuf) |
| * |
| * @param handle The pointer to the handle |
| */ |
| void ia_css_rmgr_refcount_retain_vbuf(struct ia_css_rmgr_vbuf_handle **handle) |
| { |
| int i; |
| struct ia_css_rmgr_vbuf_handle *h; |
| |
| if ((!handle) || (!*handle)) { |
| IA_CSS_LOG("Invalid inputs"); |
| return; |
| } |
| /* new vbuf to count on */ |
| if ((*handle)->count == 0) { |
| h = *handle; |
| *handle = NULL; |
| for (i = 0; i < NUM_HANDLES; i++) { |
| if (handle_table[i].count == 0) { |
| *handle = &handle_table[i]; |
| break; |
| } |
| } |
| /* if the loop dus not break and *handle == NULL |
| * this is an error handle and report it. |
| */ |
| if (!*handle) { |
| ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, |
| "ia_css_i_host_refcount_retain_vbuf() failed to find empty slot!\n"); |
| return; |
| } |
| (*handle)->vptr = h->vptr; |
| (*handle)->size = h->size; |
| } |
| (*handle)->count++; |
| } |
| |
| /* |
| * @brief Release the reference count for a handle (host, vbuf) |
| * |
| * @param handle The pointer to the handle |
| */ |
| void ia_css_rmgr_refcount_release_vbuf(struct ia_css_rmgr_vbuf_handle **handle) |
| { |
| if ((!handle) || ((*handle) == NULL) || (((*handle)->count) == 0)) { |
| ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, "%s invalid arguments!\n", __func__); |
| return; |
| } |
| /* decrease reference count */ |
| (*handle)->count--; |
| /* remove from admin */ |
| if ((*handle)->count == 0) { |
| (*handle)->vptr = 0x0; |
| (*handle)->size = 0; |
| *handle = NULL; |
| } |
| } |
| |
| /* |
| * @brief Initialize the resource pool (host, vbuf) |
| * |
| * @param pool The pointer to the pool |
| */ |
| int ia_css_rmgr_init_vbuf(struct ia_css_rmgr_vbuf_pool *pool) |
| { |
| int err = 0; |
| size_t bytes_needed; |
| |
| rmgr_refcount_init_vbuf(); |
| assert(pool); |
| if (!pool) |
| return -EINVAL; |
| /* initialize the recycle pool if used */ |
| if (pool->recycle && pool->size) { |
| /* allocate memory for storing the handles */ |
| bytes_needed = |
| sizeof(void *) * |
| pool->size; |
| pool->handles = kvmalloc(bytes_needed, GFP_KERNEL); |
| if (pool->handles) |
| memset(pool->handles, 0, bytes_needed); |
| else |
| err = -ENOMEM; |
| } else { |
| /* just in case, set the size to 0 */ |
| pool->size = 0; |
| pool->handles = NULL; |
| } |
| return err; |
| } |
| |
| /* |
| * @brief Uninitialize the resource pool (host, vbuf) |
| * |
| * @param pool The pointer to the pool |
| */ |
| void ia_css_rmgr_uninit_vbuf(struct ia_css_rmgr_vbuf_pool *pool) |
| { |
| u32 i; |
| |
| ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s\n", __func__); |
| if (!pool) { |
| ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, "%s NULL argument\n", __func__); |
| return; |
| } |
| if (pool->handles) { |
| /* free the hmm buffers */ |
| for (i = 0; i < pool->size; i++) { |
| if (pool->handles[i]) { |
| ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, |
| " freeing/releasing %x (count=%d)\n", |
| pool->handles[i]->vptr, |
| pool->handles[i]->count); |
| /* free memory */ |
| hmm_free(pool->handles[i]->vptr); |
| /* remove from refcount admin */ |
| ia_css_rmgr_refcount_release_vbuf(&pool->handles[i]); |
| } |
| } |
| /* now free the pool handles list */ |
| kvfree(pool->handles); |
| pool->handles = NULL; |
| } |
| } |
| |
| /* |
| * @brief Push a handle to the pool |
| * |
| * @param pool The pointer to the pool |
| * @param handle The pointer to the handle |
| */ |
| static |
| void rmgr_push_handle(struct ia_css_rmgr_vbuf_pool *pool, |
| struct ia_css_rmgr_vbuf_handle **handle) |
| { |
| u32 i; |
| bool succes = false; |
| |
| assert(pool); |
| assert(pool->recycle); |
| assert(pool->handles); |
| assert(handle); |
| for (i = 0; i < pool->size; i++) { |
| if (!pool->handles[i]) { |
| ia_css_rmgr_refcount_retain_vbuf(handle); |
| pool->handles[i] = *handle; |
| succes = true; |
| break; |
| } |
| } |
| assert(succes); |
| } |
| |
| /* |
| * @brief Pop a handle from the pool |
| * |
| * @param pool The pointer to the pool |
| * @param handle The pointer to the handle |
| */ |
| static |
| void rmgr_pop_handle(struct ia_css_rmgr_vbuf_pool *pool, |
| struct ia_css_rmgr_vbuf_handle **handle) |
| { |
| u32 i; |
| |
| assert(pool); |
| assert(pool->recycle); |
| assert(pool->handles); |
| assert(handle); |
| assert(*handle); |
| for (i = 0; i < pool->size; i++) { |
| if ((pool->handles[i]) && |
| (pool->handles[i]->size == (*handle)->size)) { |
| *handle = pool->handles[i]; |
| pool->handles[i] = NULL; |
| /* dont release, we are returning it... |
| * ia_css_rmgr_refcount_release_vbuf(handle); |
| */ |
| return; |
| } |
| } |
| } |
| |
| /* |
| * @brief Acquire a handle from the pool (host, vbuf) |
| * |
| * @param pool The pointer to the pool |
| * @param handle The pointer to the handle |
| */ |
| void ia_css_rmgr_acq_vbuf(struct ia_css_rmgr_vbuf_pool *pool, |
| struct ia_css_rmgr_vbuf_handle **handle) |
| { |
| struct ia_css_rmgr_vbuf_handle h; |
| |
| if ((!pool) || (!handle) || (!*handle)) { |
| IA_CSS_LOG("Invalid inputs"); |
| return; |
| } |
| |
| if (pool->copy_on_write) { |
| /* only one reference, reuse (no new retain) */ |
| if ((*handle)->count == 1) |
| return; |
| /* more than one reference, release current buffer */ |
| if ((*handle)->count > 1) { |
| /* store current values */ |
| h.vptr = 0x0; |
| h.size = (*handle)->size; |
| /* release ref to current buffer */ |
| ia_css_rmgr_refcount_release_vbuf(handle); |
| *handle = &h; |
| } |
| /* get new buffer for needed size */ |
| if ((*handle)->vptr == 0x0) { |
| if (pool->recycle) { |
| /* try and pop from pool */ |
| rmgr_pop_handle(pool, handle); |
| } |
| if ((*handle)->vptr == 0x0) { |
| /* we need to allocate */ |
| (*handle)->vptr = hmm_alloc((*handle)->size, |
| HMM_BO_PRIVATE, 0, NULL, 0); |
| } else { |
| /* we popped a buffer */ |
| return; |
| } |
| } |
| } |
| /* Note that handle will change to an internally maintained one */ |
| ia_css_rmgr_refcount_retain_vbuf(handle); |
| } |
| |
| /* |
| * @brief Release a handle to the pool (host, vbuf) |
| * |
| * @param pool The pointer to the pool |
| * @param handle The pointer to the handle |
| */ |
| void ia_css_rmgr_rel_vbuf(struct ia_css_rmgr_vbuf_pool *pool, |
| struct ia_css_rmgr_vbuf_handle **handle) |
| { |
| if ((!pool) || (!handle) || (!*handle)) { |
| IA_CSS_LOG("Invalid inputs"); |
| return; |
| } |
| /* release the handle */ |
| if ((*handle)->count == 1) { |
| if (!pool->recycle) { |
| /* non recycling pool, free mem */ |
| hmm_free((*handle)->vptr); |
| } else { |
| /* recycle to pool */ |
| rmgr_push_handle(pool, handle); |
| } |
| } |
| ia_css_rmgr_refcount_release_vbuf(handle); |
| *handle = NULL; |
| } |