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