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