diff options
author | Atish Patra <atish.patra@wdc.com> | 2019-04-04 17:10:12 -0700 |
---|---|---|
committer | Anup Patel <anup@brainfault.org> | 2019-04-10 15:46:35 +0530 |
commit | 110eef44f08635076fe201c6516819055b8762cc (patch) | |
tree | 442c92218e4a2f010d24a18efa587401d9c4238f | |
parent | 54f31e82093969eaca9f7ebab06c92fa044dd076 (diff) |
lib: Provide a lock enabled iteration of fifo.
Implement a lock enabled iteration for fifo so that
caller can determine if next entry can be skipped or
any existing entries in fifo can be updated before enqueue.
Signed-off-by: Atish Patra <atish.patra@wdc.com>
-rw-r--r-- | include/sbi/sbi_fifo.h | 10 | ||||
-rw-r--r-- | lib/sbi_fifo.c | 74 |
2 files changed, 84 insertions, 0 deletions
diff --git a/include/sbi/sbi_fifo.h b/include/sbi/sbi_fifo.h index 3754a5e..f9e2ca9 100644 --- a/include/sbi/sbi_fifo.h +++ b/include/sbi/sbi_fifo.h @@ -23,11 +23,21 @@ struct sbi_fifo { u16 tail; }; +enum sbi_fifo_inplace_update_types { + SBI_FIFO_SKIP, + SBI_FIFO_UPDATED, + SBI_FIFO_RESET, + SBI_FIFO_UNCHANGED, +}; + int sbi_fifo_dequeue(struct sbi_fifo *fifo, void *data); int sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data); void sbi_fifo_init(struct sbi_fifo *fifo, void *queue_mem, u16 entries, u16 entry_size); bool sbi_fifo_is_empty(struct sbi_fifo *fifo); bool sbi_fifo_is_full(struct sbi_fifo *fifo); +int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in, + int (*fptr) (void *in, void *data)); +u16 sbi_fifo_avail(struct sbi_fifo *fifo); #endif diff --git a/lib/sbi_fifo.c b/lib/sbi_fifo.c index 36ff6d0..85fcff9 100644 --- a/lib/sbi_fifo.c +++ b/lib/sbi_fifo.c @@ -29,6 +29,20 @@ static inline bool __sbi_fifo_is_full(struct sbi_fifo *fifo) return (fifo->avail == fifo->num_entries) ? TRUE : FALSE; } +u16 sbi_fifo_avail(struct sbi_fifo *fifo) +{ + u16 ret; + + if (!fifo) + return 0; + + spin_lock(&fifo->qlock); + ret = fifo->avail; + spin_unlock(&fifo->qlock); + + return ret; +} + bool sbi_fifo_is_full(struct sbi_fifo *fifo) { bool ret; @@ -57,6 +71,66 @@ bool sbi_fifo_is_empty(struct sbi_fifo *fifo) return ret; } +/* Note: must be called with fifo->qlock held */ +static inline void __sbi_fifo_reset(struct sbi_fifo *fifo) +{ + fifo->avail = 0; + fifo->tail = 0; + memset(fifo->queue, 0, fifo->num_entries * fifo->entry_size); +} + +bool sbi_fifo_reset(struct sbi_fifo *fifo) +{ + if (!fifo) + return FALSE; + + spin_lock(&fifo->qlock); + __sbi_fifo_reset(fifo); + spin_unlock(&fifo->qlock); + + return TRUE; +} + +/** + * Provide a helper function to do inplace update to the fifo. + * Note: The callback function is called with lock being held. + * + * **Do not** invoke any other fifo function from callback. Otherwise, it will + * lead to deadlock. + */ +int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in, + int (*fptr)(void *in, void *data)) +{ + int i, index = 0; + int ret = SBI_FIFO_UNCHANGED; + void *entry; + + if (!fifo || !in ) + return ret; + spin_lock(&fifo->qlock); + if (__sbi_fifo_is_empty(fifo)) { + spin_unlock(&fifo->qlock); + return ret; + } + + for (i = 0; i < fifo->avail; i ++) { + index = fifo->tail + i; + if (index >= fifo->num_entries) + index = index - fifo->num_entries; + entry = (void *)fifo->queue + (u32) index * fifo->entry_size; + ret = fptr(in, entry); + if (ret == SBI_FIFO_SKIP || ret == SBI_FIFO_UPDATED) { + break; + } else if (ret == SBI_FIFO_RESET) { + __sbi_fifo_reset(fifo); + break; + } + } + spin_unlock(&fifo->qlock); + + return ret; +} + int sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data) { u32 head; |