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