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