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