1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Support for Intel Camera Imaging ISP subsystem.
4  * Copyright (c) 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 "ia_css_queue.h"
17 #include <math_support.h>
18 #include <ia_css_circbuf.h>
19 #include <ia_css_circbuf_desc.h>
20 #include "queue_access.h"
21 
22 /*****************************************************************************
23  * Queue Public APIs
24  *****************************************************************************/
ia_css_queue_local_init(ia_css_queue_t * qhandle,ia_css_queue_local_t * desc)25 int ia_css_queue_local_init(
26     ia_css_queue_t *qhandle,
27     ia_css_queue_local_t *desc)
28 {
29 	if (NULL == qhandle || NULL == desc
30 	    || NULL == desc->cb_elems || NULL == desc->cb_desc) {
31 		/* Invalid parameters, return error*/
32 		return -EINVAL;
33 	}
34 
35 	/* Mark the queue as Local */
36 	qhandle->type = IA_CSS_QUEUE_TYPE_LOCAL;
37 
38 	/* Create a local circular buffer queue*/
39 	ia_css_circbuf_create(&qhandle->desc.cb_local,
40 			      desc->cb_elems,
41 			      desc->cb_desc);
42 
43 	return 0;
44 }
45 
ia_css_queue_remote_init(ia_css_queue_t * qhandle,ia_css_queue_remote_t * desc)46 int ia_css_queue_remote_init(
47     ia_css_queue_t *qhandle,
48     ia_css_queue_remote_t *desc)
49 {
50 	if (NULL == qhandle || NULL == desc) {
51 		/* Invalid parameters, return error*/
52 		return -EINVAL;
53 	}
54 
55 	/* Mark the queue as remote*/
56 	qhandle->type = IA_CSS_QUEUE_TYPE_REMOTE;
57 
58 	/* Copy over the local queue descriptor*/
59 	qhandle->location = desc->location;
60 	qhandle->proc_id = desc->proc_id;
61 	qhandle->desc.remote.cb_desc_addr = desc->cb_desc_addr;
62 	qhandle->desc.remote.cb_elems_addr = desc->cb_elems_addr;
63 
64 	/* If queue is remote, we let the local processor
65 	 * do its init, before using it. This is just to get us
66 	 * started, we can remove this restriction as we go ahead
67 	 */
68 
69 	return 0;
70 }
71 
ia_css_queue_uninit(ia_css_queue_t * qhandle)72 int ia_css_queue_uninit(
73     ia_css_queue_t *qhandle)
74 {
75 	if (!qhandle)
76 		return -EINVAL;
77 
78 	/* Load the required queue object */
79 	if (qhandle->type == IA_CSS_QUEUE_TYPE_LOCAL) {
80 		/* Local queues are created. Destroy it*/
81 		ia_css_circbuf_destroy(&qhandle->desc.cb_local);
82 	}
83 
84 	return 0;
85 }
86 
ia_css_queue_enqueue(ia_css_queue_t * qhandle,uint32_t item)87 int ia_css_queue_enqueue(
88     ia_css_queue_t *qhandle,
89     uint32_t item)
90 {
91 	int error = 0;
92 
93 	if (!qhandle)
94 		return -EINVAL;
95 
96 	/* 1. Load the required queue object */
97 	if (qhandle->type == IA_CSS_QUEUE_TYPE_LOCAL) {
98 		/* Directly de-ref the object and
99 		 * operate on the queue
100 		 */
101 		if (ia_css_circbuf_is_full(&qhandle->desc.cb_local)) {
102 			/* Cannot push the element. Return*/
103 			return -ENOBUFS;
104 		}
105 
106 		/* Push the element*/
107 		ia_css_circbuf_push(&qhandle->desc.cb_local, item);
108 	} else if (qhandle->type == IA_CSS_QUEUE_TYPE_REMOTE) {
109 		ia_css_circbuf_desc_t cb_desc;
110 		ia_css_circbuf_elem_t cb_elem;
111 		u32 ignore_desc_flags = QUEUE_IGNORE_STEP_FLAG;
112 
113 		/* a. Load the queue cb_desc from remote */
114 		QUEUE_CB_DESC_INIT(&cb_desc);
115 		error = ia_css_queue_load(qhandle, &cb_desc, ignore_desc_flags);
116 		if (error != 0)
117 			return error;
118 
119 		/* b. Operate on the queue */
120 		if (ia_css_circbuf_desc_is_full(&cb_desc))
121 			return -ENOBUFS;
122 
123 		cb_elem.val = item;
124 
125 		error = ia_css_queue_item_store(qhandle, cb_desc.end, &cb_elem);
126 		if (error != 0)
127 			return error;
128 
129 		cb_desc.end = (cb_desc.end + 1) % cb_desc.size;
130 
131 		/* c. Store the queue object */
132 		/* Set only fields requiring update with
133 		 * valid value. Avoids uncessary calls
134 		 * to load/store functions
135 		 */
136 		ignore_desc_flags = QUEUE_IGNORE_SIZE_START_STEP_FLAGS;
137 
138 		error = ia_css_queue_store(qhandle, &cb_desc, ignore_desc_flags);
139 		if (error != 0)
140 			return error;
141 	}
142 
143 	return 0;
144 }
145 
ia_css_queue_dequeue(ia_css_queue_t * qhandle,uint32_t * item)146 int ia_css_queue_dequeue(
147     ia_css_queue_t *qhandle,
148     uint32_t *item)
149 {
150 	int error = 0;
151 
152 	if (!qhandle || NULL == item)
153 		return -EINVAL;
154 
155 	/* 1. Load the required queue object */
156 	if (qhandle->type == IA_CSS_QUEUE_TYPE_LOCAL) {
157 		/* Directly de-ref the object and
158 		 * operate on the queue
159 		 */
160 		if (ia_css_circbuf_is_empty(&qhandle->desc.cb_local)) {
161 			/* Nothing to pop. Return empty queue*/
162 			return -ENODATA;
163 		}
164 
165 		*item = ia_css_circbuf_pop(&qhandle->desc.cb_local);
166 	} else if (qhandle->type == IA_CSS_QUEUE_TYPE_REMOTE) {
167 		/* a. Load the queue from remote */
168 		ia_css_circbuf_desc_t cb_desc;
169 		ia_css_circbuf_elem_t cb_elem;
170 		u32 ignore_desc_flags = QUEUE_IGNORE_STEP_FLAG;
171 
172 		QUEUE_CB_DESC_INIT(&cb_desc);
173 
174 		error = ia_css_queue_load(qhandle, &cb_desc, ignore_desc_flags);
175 		if (error != 0)
176 			return error;
177 
178 		/* b. Operate on the queue */
179 		if (ia_css_circbuf_desc_is_empty(&cb_desc))
180 			return -ENODATA;
181 
182 		error = ia_css_queue_item_load(qhandle, cb_desc.start, &cb_elem);
183 		if (error != 0)
184 			return error;
185 
186 		*item = cb_elem.val;
187 
188 		cb_desc.start = OP_std_modadd(cb_desc.start, 1, cb_desc.size);
189 
190 		/* c. Store the queue object */
191 		/* Set only fields requiring update with
192 		 * valid value. Avoids uncessary calls
193 		 * to load/store functions
194 		 */
195 		ignore_desc_flags = QUEUE_IGNORE_SIZE_END_STEP_FLAGS;
196 		error = ia_css_queue_store(qhandle, &cb_desc, ignore_desc_flags);
197 		if (error != 0)
198 			return error;
199 	}
200 	return 0;
201 }
202 
ia_css_queue_is_full(ia_css_queue_t * qhandle,bool * is_full)203 int ia_css_queue_is_full(
204     ia_css_queue_t *qhandle,
205     bool *is_full)
206 {
207 	int error = 0;
208 
209 	if ((!qhandle) || (!is_full))
210 		return -EINVAL;
211 
212 	/* 1. Load the required queue object */
213 	if (qhandle->type == IA_CSS_QUEUE_TYPE_LOCAL) {
214 		/* Directly de-ref the object and
215 		 * operate on the queue
216 		 */
217 		*is_full = ia_css_circbuf_is_full(&qhandle->desc.cb_local);
218 		return 0;
219 	} else if (qhandle->type == IA_CSS_QUEUE_TYPE_REMOTE) {
220 		/* a. Load the queue from remote */
221 		ia_css_circbuf_desc_t cb_desc;
222 		u32 ignore_desc_flags = QUEUE_IGNORE_STEP_FLAG;
223 
224 		QUEUE_CB_DESC_INIT(&cb_desc);
225 		error = ia_css_queue_load(qhandle, &cb_desc, ignore_desc_flags);
226 		if (error != 0)
227 			return error;
228 
229 		/* b. Operate on the queue */
230 		*is_full = ia_css_circbuf_desc_is_full(&cb_desc);
231 		return 0;
232 	}
233 
234 	return -EINVAL;
235 }
236 
ia_css_queue_get_free_space(ia_css_queue_t * qhandle,uint32_t * size)237 int ia_css_queue_get_free_space(
238     ia_css_queue_t *qhandle,
239     uint32_t *size)
240 {
241 	int error = 0;
242 
243 	if ((!qhandle) || (!size))
244 		return -EINVAL;
245 
246 	/* 1. Load the required queue object */
247 	if (qhandle->type == IA_CSS_QUEUE_TYPE_LOCAL) {
248 		/* Directly de-ref the object and
249 		 * operate on the queue
250 		 */
251 		*size = ia_css_circbuf_get_free_elems(&qhandle->desc.cb_local);
252 		return 0;
253 	} else if (qhandle->type == IA_CSS_QUEUE_TYPE_REMOTE) {
254 		/* a. Load the queue from remote */
255 		ia_css_circbuf_desc_t cb_desc;
256 		u32 ignore_desc_flags = QUEUE_IGNORE_STEP_FLAG;
257 
258 		QUEUE_CB_DESC_INIT(&cb_desc);
259 		error = ia_css_queue_load(qhandle, &cb_desc, ignore_desc_flags);
260 		if (error != 0)
261 			return error;
262 
263 		/* b. Operate on the queue */
264 		*size = ia_css_circbuf_desc_get_free_elems(&cb_desc);
265 		return 0;
266 	}
267 
268 	return -EINVAL;
269 }
270 
ia_css_queue_get_used_space(ia_css_queue_t * qhandle,uint32_t * size)271 int ia_css_queue_get_used_space(
272     ia_css_queue_t *qhandle,
273     uint32_t *size)
274 {
275 	int error = 0;
276 
277 	if ((!qhandle) || (!size))
278 		return -EINVAL;
279 
280 	/* 1. Load the required queue object */
281 	if (qhandle->type == IA_CSS_QUEUE_TYPE_LOCAL) {
282 		/* Directly de-ref the object and
283 		 * operate on the queue
284 		 */
285 		*size = ia_css_circbuf_get_num_elems(&qhandle->desc.cb_local);
286 		return 0;
287 	} else if (qhandle->type == IA_CSS_QUEUE_TYPE_REMOTE) {
288 		/* a. Load the queue from remote */
289 		ia_css_circbuf_desc_t cb_desc;
290 		u32 ignore_desc_flags = QUEUE_IGNORE_STEP_FLAG;
291 
292 		QUEUE_CB_DESC_INIT(&cb_desc);
293 		error = ia_css_queue_load(qhandle, &cb_desc, ignore_desc_flags);
294 		if (error != 0)
295 			return error;
296 
297 		/* b. Operate on the queue */
298 		*size = ia_css_circbuf_desc_get_num_elems(&cb_desc);
299 		return 0;
300 	}
301 
302 	return -EINVAL;
303 }
304 
ia_css_queue_peek(ia_css_queue_t * qhandle,u32 offset,uint32_t * element)305 int ia_css_queue_peek(
306     ia_css_queue_t *qhandle,
307     u32 offset,
308     uint32_t *element)
309 {
310 	u32 num_elems = 0;
311 	int error = 0;
312 
313 	if ((!qhandle) || (!element))
314 		return -EINVAL;
315 
316 	/* 1. Load the required queue object */
317 	if (qhandle->type == IA_CSS_QUEUE_TYPE_LOCAL) {
318 		/* Directly de-ref the object and
319 		 * operate on the queue
320 		 */
321 		/* Check if offset is valid */
322 		num_elems = ia_css_circbuf_get_num_elems(&qhandle->desc.cb_local);
323 		if (offset > num_elems)
324 			return -EINVAL;
325 
326 		*element = ia_css_circbuf_peek_from_start(&qhandle->desc.cb_local, (int)offset);
327 		return 0;
328 	} else if (qhandle->type == IA_CSS_QUEUE_TYPE_REMOTE) {
329 		/* a. Load the queue from remote */
330 		ia_css_circbuf_desc_t cb_desc;
331 		ia_css_circbuf_elem_t cb_elem;
332 		u32 ignore_desc_flags = QUEUE_IGNORE_STEP_FLAG;
333 
334 		QUEUE_CB_DESC_INIT(&cb_desc);
335 
336 		error =  ia_css_queue_load(qhandle, &cb_desc, ignore_desc_flags);
337 		if (error != 0)
338 			return error;
339 
340 		/* Check if offset is valid */
341 		num_elems = ia_css_circbuf_desc_get_num_elems(&cb_desc);
342 		if (offset > num_elems)
343 			return -EINVAL;
344 
345 		offset = OP_std_modadd(cb_desc.start, offset, cb_desc.size);
346 		error = ia_css_queue_item_load(qhandle, (uint8_t)offset, &cb_elem);
347 		if (error != 0)
348 			return error;
349 
350 		*element = cb_elem.val;
351 		return 0;
352 	}
353 
354 	return -EINVAL;
355 }
356 
ia_css_queue_is_empty(ia_css_queue_t * qhandle,bool * is_empty)357 int ia_css_queue_is_empty(
358     ia_css_queue_t *qhandle,
359     bool *is_empty)
360 {
361 	int error = 0;
362 
363 	if ((!qhandle) || (!is_empty))
364 		return -EINVAL;
365 
366 	/* 1. Load the required queue object */
367 	if (qhandle->type == IA_CSS_QUEUE_TYPE_LOCAL) {
368 		/* Directly de-ref the object and
369 		 * operate on the queue
370 		 */
371 		*is_empty = ia_css_circbuf_is_empty(&qhandle->desc.cb_local);
372 		return 0;
373 	} else if (qhandle->type == IA_CSS_QUEUE_TYPE_REMOTE) {
374 		/* a. Load the queue from remote */
375 		ia_css_circbuf_desc_t cb_desc;
376 		u32 ignore_desc_flags = QUEUE_IGNORE_STEP_FLAG;
377 
378 		QUEUE_CB_DESC_INIT(&cb_desc);
379 		error = ia_css_queue_load(qhandle, &cb_desc, ignore_desc_flags);
380 		if (error != 0)
381 			return error;
382 
383 		/* b. Operate on the queue */
384 		*is_empty = ia_css_circbuf_desc_is_empty(&cb_desc);
385 		return 0;
386 	}
387 
388 	return -EINVAL;
389 }
390 
ia_css_queue_get_size(ia_css_queue_t * qhandle,uint32_t * size)391 int ia_css_queue_get_size(
392     ia_css_queue_t *qhandle,
393     uint32_t *size)
394 {
395 	int error = 0;
396 
397 	if ((!qhandle) || (!size))
398 		return -EINVAL;
399 
400 	/* 1. Load the required queue object */
401 	if (qhandle->type == IA_CSS_QUEUE_TYPE_LOCAL) {
402 		/* Directly de-ref the object and
403 		 * operate on the queue
404 		 */
405 		/* Return maximum usable capacity */
406 		*size = ia_css_circbuf_get_size(&qhandle->desc.cb_local);
407 	} else if (qhandle->type == IA_CSS_QUEUE_TYPE_REMOTE) {
408 		/* a. Load the queue from remote */
409 		ia_css_circbuf_desc_t cb_desc;
410 		u32 ignore_desc_flags = QUEUE_IGNORE_START_END_STEP_FLAGS;
411 
412 		QUEUE_CB_DESC_INIT(&cb_desc);
413 
414 		error = ia_css_queue_load(qhandle, &cb_desc, ignore_desc_flags);
415 		if (error != 0)
416 			return error;
417 
418 		/* Return maximum usable capacity */
419 		*size = cb_desc.size;
420 	}
421 
422 	return 0;
423 }
424