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