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