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
28static struct ia_css_rmgr_vbuf_handle handle_table[NUM_HANDLES];
29
30/*
31 * @brief VBUF resource pool - refpool
32 */
33static struct ia_css_rmgr_vbuf_pool refpool;
34
35/*
36 * @brief VBUF resource pool - writepool
37 */
38static struct ia_css_rmgr_vbuf_pool writepool = {
39	.copy_on_write	= true,
40};
41
42/*
43 * @brief VBUF resource pool - hmmbufferpool
44 */
45static struct ia_css_rmgr_vbuf_pool hmmbufferpool = {
46	.copy_on_write	= true,
47	.recycle	= true,
48	.size		= 32,
49};
50
51struct ia_css_rmgr_vbuf_pool *vbuf_ref = &refpool;
52struct ia_css_rmgr_vbuf_pool *vbuf_write = &writepool;
53struct ia_css_rmgr_vbuf_pool *hmm_buffer_pool = &hmmbufferpool;
54
55/*
56 * @brief Initialize the reference count (host, vbuf)
57 */
58static 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 */
69void 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 */
107void 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 */
128int 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 */
161void 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 */
196static
197void rmgr_push_handle(struct ia_css_rmgr_vbuf_pool *pool,
198		      struct ia_css_rmgr_vbuf_handle **handle)
199{
200	u32 i;
201	bool success = 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			success = true;
212			break;
213		}
214	}
215	assert(success);
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 */
224static
225void 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 */
254void 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 */
310void 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