1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Support for Intel Camera Imaging ISP subsystem. 4 * Copyright (c) 2010-2015, Intel Corporation. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 */ 15 16 #include "hmm.h" 17 #include "ia_css_rmgr.h" 18 19 #include <type_support.h> 20 #include <assert_support.h> 21 #include <platform_support.h> /* memset */ 22 #include <ia_css_debug.h> 23 24 /* 25 * @brief VBUF resource handles 26 */ 27 #define NUM_HANDLES 1000 28 static struct ia_css_rmgr_vbuf_handle handle_table[NUM_HANDLES]; 29 30 /* 31 * @brief VBUF resource pool - refpool 32 */ 33 static struct ia_css_rmgr_vbuf_pool refpool; 34 35 /* 36 * @brief VBUF resource pool - writepool 37 */ 38 static struct ia_css_rmgr_vbuf_pool writepool = { 39 .copy_on_write = true, 40 }; 41 42 /* 43 * @brief VBUF resource pool - hmmbufferpool 44 */ 45 static struct ia_css_rmgr_vbuf_pool hmmbufferpool = { 46 .copy_on_write = true, 47 .recycle = true, 48 .size = 32, 49 }; 50 51 struct ia_css_rmgr_vbuf_pool *vbuf_ref = &refpool; 52 struct ia_css_rmgr_vbuf_pool *vbuf_write = &writepool; 53 struct ia_css_rmgr_vbuf_pool *hmm_buffer_pool = &hmmbufferpool; 54 55 /* 56 * @brief Initialize the reference count (host, vbuf) 57 */ 58 static void rmgr_refcount_init_vbuf(void) 59 { 60 /* initialize the refcount table */ 61 memset(&handle_table, 0, sizeof(handle_table)); 62 } 63 64 /* 65 * @brief Retain the reference count for a handle (host, vbuf) 66 * 67 * @param handle The pointer to the handle 68 */ 69 void ia_css_rmgr_refcount_retain_vbuf(struct ia_css_rmgr_vbuf_handle **handle) 70 { 71 int i; 72 struct ia_css_rmgr_vbuf_handle *h; 73 74 if ((!handle) || (!*handle)) { 75 IA_CSS_LOG("Invalid inputs"); 76 return; 77 } 78 /* new vbuf to count on */ 79 if ((*handle)->count == 0) { 80 h = *handle; 81 *handle = NULL; 82 for (i = 0; i < NUM_HANDLES; i++) { 83 if (handle_table[i].count == 0) { 84 *handle = &handle_table[i]; 85 break; 86 } 87 } 88 /* if the loop dus not break and *handle == NULL 89 * this is an error handle and report it. 90 */ 91 if (!*handle) { 92 ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, 93 "ia_css_i_host_refcount_retain_vbuf() failed to find empty slot!\n"); 94 return; 95 } 96 (*handle)->vptr = h->vptr; 97 (*handle)->size = h->size; 98 } 99 (*handle)->count++; 100 } 101 102 /* 103 * @brief Release the reference count for a handle (host, vbuf) 104 * 105 * @param handle The pointer to the handle 106 */ 107 void ia_css_rmgr_refcount_release_vbuf(struct ia_css_rmgr_vbuf_handle **handle) 108 { 109 if ((!handle) || ((*handle) == NULL) || (((*handle)->count) == 0)) { 110 ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, "%s invalid arguments!\n", __func__); 111 return; 112 } 113 /* decrease reference count */ 114 (*handle)->count--; 115 /* remove from admin */ 116 if ((*handle)->count == 0) { 117 (*handle)->vptr = 0x0; 118 (*handle)->size = 0; 119 *handle = NULL; 120 } 121 } 122 123 /* 124 * @brief Initialize the resource pool (host, vbuf) 125 * 126 * @param pool The pointer to the pool 127 */ 128 int ia_css_rmgr_init_vbuf(struct ia_css_rmgr_vbuf_pool *pool) 129 { 130 int err = 0; 131 size_t bytes_needed; 132 133 rmgr_refcount_init_vbuf(); 134 assert(pool); 135 if (!pool) 136 return -EINVAL; 137 /* initialize the recycle pool if used */ 138 if (pool->recycle && pool->size) { 139 /* allocate memory for storing the handles */ 140 bytes_needed = 141 sizeof(void *) * 142 pool->size; 143 pool->handles = kvmalloc(bytes_needed, GFP_KERNEL); 144 if (pool->handles) 145 memset(pool->handles, 0, bytes_needed); 146 else 147 err = -ENOMEM; 148 } else { 149 /* just in case, set the size to 0 */ 150 pool->size = 0; 151 pool->handles = NULL; 152 } 153 return err; 154 } 155 156 /* 157 * @brief Uninitialize the resource pool (host, vbuf) 158 * 159 * @param pool The pointer to the pool 160 */ 161 void ia_css_rmgr_uninit_vbuf(struct ia_css_rmgr_vbuf_pool *pool) 162 { 163 u32 i; 164 165 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s\n", __func__); 166 if (!pool) { 167 ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, "%s NULL argument\n", __func__); 168 return; 169 } 170 if (pool->handles) { 171 /* free the hmm buffers */ 172 for (i = 0; i < pool->size; i++) { 173 if (pool->handles[i]) { 174 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 175 " freeing/releasing %x (count=%d)\n", 176 pool->handles[i]->vptr, 177 pool->handles[i]->count); 178 /* free memory */ 179 hmm_free(pool->handles[i]->vptr); 180 /* remove from refcount admin */ 181 ia_css_rmgr_refcount_release_vbuf(&pool->handles[i]); 182 } 183 } 184 /* now free the pool handles list */ 185 kvfree(pool->handles); 186 pool->handles = NULL; 187 } 188 } 189 190 /* 191 * @brief Push a handle to the pool 192 * 193 * @param pool The pointer to the pool 194 * @param handle The pointer to the handle 195 */ 196 static 197 void rmgr_push_handle(struct ia_css_rmgr_vbuf_pool *pool, 198 struct ia_css_rmgr_vbuf_handle **handle) 199 { 200 u32 i; 201 bool succes = false; 202 203 assert(pool); 204 assert(pool->recycle); 205 assert(pool->handles); 206 assert(handle); 207 for (i = 0; i < pool->size; i++) { 208 if (!pool->handles[i]) { 209 ia_css_rmgr_refcount_retain_vbuf(handle); 210 pool->handles[i] = *handle; 211 succes = true; 212 break; 213 } 214 } 215 assert(succes); 216 } 217 218 /* 219 * @brief Pop a handle from the pool 220 * 221 * @param pool The pointer to the pool 222 * @param handle The pointer to the handle 223 */ 224 static 225 void rmgr_pop_handle(struct ia_css_rmgr_vbuf_pool *pool, 226 struct ia_css_rmgr_vbuf_handle **handle) 227 { 228 u32 i; 229 230 assert(pool); 231 assert(pool->recycle); 232 assert(pool->handles); 233 assert(handle); 234 assert(*handle); 235 for (i = 0; i < pool->size; i++) { 236 if ((pool->handles[i]) && 237 (pool->handles[i]->size == (*handle)->size)) { 238 *handle = pool->handles[i]; 239 pool->handles[i] = NULL; 240 /* dont release, we are returning it... 241 * ia_css_rmgr_refcount_release_vbuf(handle); 242 */ 243 return; 244 } 245 } 246 } 247 248 /* 249 * @brief Acquire a handle from the pool (host, vbuf) 250 * 251 * @param pool The pointer to the pool 252 * @param handle The pointer to the handle 253 */ 254 void ia_css_rmgr_acq_vbuf(struct ia_css_rmgr_vbuf_pool *pool, 255 struct ia_css_rmgr_vbuf_handle **handle) 256 { 257 struct ia_css_rmgr_vbuf_handle h = { 0 }; 258 259 if ((!pool) || (!handle) || (!*handle)) { 260 IA_CSS_LOG("Invalid inputs"); 261 return; 262 } 263 264 if (pool->copy_on_write) { 265 /* only one reference, reuse (no new retain) */ 266 if ((*handle)->count == 1) 267 return; 268 /* more than one reference, release current buffer */ 269 if ((*handle)->count > 1) { 270 /* store current values */ 271 h.vptr = 0x0; 272 h.size = (*handle)->size; 273 /* release ref to current buffer */ 274 ia_css_rmgr_refcount_release_vbuf(handle); 275 **handle = h; 276 } 277 /* get new buffer for needed size */ 278 if ((*handle)->vptr == 0x0) { 279 if (pool->recycle) { 280 /* try and pop from pool */ 281 rmgr_pop_handle(pool, handle); 282 } 283 if ((*handle)->vptr == 0x0) { 284 /* we need to allocate */ 285 (*handle)->vptr = hmm_alloc((*handle)->size, 286 HMM_BO_PRIVATE, 0, NULL, 0); 287 } else { 288 /* we popped a buffer */ 289 return; 290 } 291 } 292 } 293 /* Note that handle will change to an internally maintained one */ 294 ia_css_rmgr_refcount_retain_vbuf(handle); 295 } 296 297 /* 298 * @brief Release a handle to the pool (host, vbuf) 299 * 300 * @param pool The pointer to the pool 301 * @param handle The pointer to the handle 302 */ 303 void ia_css_rmgr_rel_vbuf(struct ia_css_rmgr_vbuf_pool *pool, 304 struct ia_css_rmgr_vbuf_handle **handle) 305 { 306 if ((!pool) || (!handle) || (!*handle)) { 307 IA_CSS_LOG("Invalid inputs"); 308 return; 309 } 310 /* release the handle */ 311 if ((*handle)->count == 1) { 312 if (!pool->recycle) { 313 /* non recycling pool, free mem */ 314 hmm_free((*handle)->vptr); 315 } else { 316 /* recycle to pool */ 317 rmgr_push_handle(pool, handle); 318 } 319 } 320 ia_css_rmgr_refcount_release_vbuf(handle); 321 *handle = NULL; 322 } 323