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