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