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