aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAtish Patra <atish.patra@wdc.com>2019-04-04 17:10:12 -0700
committerAnup Patel <anup@brainfault.org>2019-04-10 15:46:35 +0530
commit110eef44f08635076fe201c6516819055b8762cc (patch)
tree442c92218e4a2f010d24a18efa587401d9c4238f
parent54f31e82093969eaca9f7ebab06c92fa044dd076 (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.h10
-rw-r--r--lib/sbi_fifo.c74
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;