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 */
rmgr_refcount_init_vbuf(void)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 */
ia_css_rmgr_refcount_retain_vbuf(struct ia_css_rmgr_vbuf_handle ** handle)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 */
ia_css_rmgr_refcount_release_vbuf(struct ia_css_rmgr_vbuf_handle ** handle)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 */
ia_css_rmgr_init_vbuf(struct ia_css_rmgr_vbuf_pool * pool)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 */
ia_css_rmgr_uninit_vbuf(struct ia_css_rmgr_vbuf_pool * pool)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
rmgr_push_handle(struct ia_css_rmgr_vbuf_pool * pool,struct ia_css_rmgr_vbuf_handle ** handle)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
rmgr_pop_handle(struct ia_css_rmgr_vbuf_pool * pool,struct ia_css_rmgr_vbuf_handle ** handle)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 */
ia_css_rmgr_acq_vbuf(struct ia_css_rmgr_vbuf_pool * pool,struct ia_css_rmgr_vbuf_handle ** handle)254 void ia_css_rmgr_acq_vbuf(struct ia_css_rmgr_vbuf_pool *pool,
255 struct ia_css_rmgr_vbuf_handle **handle)
256 {
257 if ((!pool) || (!handle) || (!*handle)) {
258 IA_CSS_LOG("Invalid inputs");
259 return;
260 }
261
262 if (pool->copy_on_write) {
263 struct ia_css_rmgr_vbuf_handle *new_handle;
264 struct ia_css_rmgr_vbuf_handle h = { 0 };
265
266 /* only one reference, reuse (no new retain) */
267 if ((*handle)->count == 1)
268 return;
269 /* more than one reference, release current buffer */
270 if ((*handle)->count > 1) {
271 /* store current values */
272 h.vptr = 0x0;
273 h.size = (*handle)->size;
274 /* release ref to current buffer */
275 ia_css_rmgr_refcount_release_vbuf(handle);
276 new_handle = &h;
277 } else {
278 new_handle = *handle;
279 }
280 /* get new buffer for needed size */
281 if (new_handle->vptr == 0x0) {
282 if (pool->recycle) {
283 /* try and pop from pool */
284 rmgr_pop_handle(pool, &new_handle);
285 }
286 if (new_handle->vptr == 0x0) {
287 /* we need to allocate */
288 new_handle->vptr = hmm_alloc(new_handle->size);
289 } else {
290 /* we popped a buffer */
291 *handle = new_handle;
292 return;
293 }
294 }
295 /* Note that new_handle will change to an internally maintained one */
296 ia_css_rmgr_refcount_retain_vbuf(&new_handle);
297 *handle = new_handle;
298 return;
299 }
300 /* Note that handle will change to an internally maintained one */
301 ia_css_rmgr_refcount_retain_vbuf(handle);
302 }
303
304 /*
305 * @brief Release a handle to the pool (host, vbuf)
306 *
307 * @param pool The pointer to the pool
308 * @param handle The pointer to the handle
309 */
ia_css_rmgr_rel_vbuf(struct ia_css_rmgr_vbuf_pool * pool,struct ia_css_rmgr_vbuf_handle ** handle)310 void ia_css_rmgr_rel_vbuf(struct ia_css_rmgr_vbuf_pool *pool,
311 struct ia_css_rmgr_vbuf_handle **handle)
312 {
313 if ((!pool) || (!handle) || (!*handle)) {
314 IA_CSS_LOG("Invalid inputs");
315 return;
316 }
317 /* release the handle */
318 if ((*handle)->count == 1) {
319 if (!pool->recycle) {
320 /* non recycling pool, free mem */
321 hmm_free((*handle)->vptr);
322 } else {
323 /* recycle to pool */
324 rmgr_push_handle(pool, handle);
325 }
326 }
327 ia_css_rmgr_refcount_release_vbuf(handle);
328 *handle = NULL;
329 }
330