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 *****************************************************************************/ 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 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 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 82 int ia_css_queue_enqueue(ia_css_queue_t *qhandle, uint32_t item) 83 { 84 int error = 0; 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 uncessary 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 139 int ia_css_queue_dequeue(ia_css_queue_t *qhandle, uint32_t *item) 140 { 141 int error = 0; 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 uncessary 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 194 int ia_css_queue_is_full(ia_css_queue_t *qhandle, bool *is_full) 195 { 196 int error = 0; 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 226 int ia_css_queue_get_free_space(ia_css_queue_t *qhandle, uint32_t *size) 227 { 228 int error = 0; 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 258 int ia_css_queue_get_used_space(ia_css_queue_t *qhandle, uint32_t *size) 259 { 260 int error = 0; 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 290 int ia_css_queue_peek(ia_css_queue_t *qhandle, u32 offset, uint32_t *element) 291 { 292 u32 num_elems = 0; 293 int error = 0; 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 339 int ia_css_queue_is_empty(ia_css_queue_t *qhandle, bool *is_empty) 340 { 341 int error = 0; 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 371 int ia_css_queue_get_size(ia_css_queue_t *qhandle, uint32_t *size) 372 { 373 int error = 0; 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