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;
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 unnecessary 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;
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 unnecessary 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;
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;
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;
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;
293 int error;
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;
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;
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