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