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