Browse Source

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>
Atish Patra 5 years ago
parent
commit
110eef44f0
2 changed files with 84 additions and 0 deletions
  1. 10 0
      include/sbi/sbi_fifo.h
  2. 74 0
      lib/sbi_fifo.c

+ 10 - 0
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

+ 74 - 0
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;