>IOQ is a generic shared-memory-queue mechanism that happens to be
>friendly
>to virtualization boundaries.  Note that it is not virtualization
>specific
>due to its flexible transport layer.
>
>Signed-off-by: Gregory Haskins <[EMAIL PROTECTED]>
>---
>
> include/linux/ioq.h |  178 +++++++++++++++++++++++++++++++++++++++++
> lib/Kconfig         |   11 +++
> lib/Makefile        |    1
> lib/ioq.c           |  219
>+++++++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 409 insertions(+), 0 deletions(-)
>
>diff --git a/include/linux/ioq.h b/include/linux/ioq.h
>new file mode 100644
>index 0000000..52f68f5
>--- /dev/null
>+++ b/include/linux/ioq.h
>@@ -0,0 +1,178 @@
>+/*
>+ * Copyright 2007 Novell.  All Rights Reserved.
>+ *
>+ * IOQ is a generic shared-memory-queue mechanism that happens to be
>friendly
>+ * to virtualization boundaries. It can be used in a variety of ways,
>though
>+ * its intended purpose is to become the low-level communication path
>for
>+ * paravirtualized drivers.  Note that it is not virtualization
>specific
>+ * due to its flexible signaling layer.
>+ *
>+ * The following are a list of key design points:
>+ *
>+ * #) All shared-memory is always allocated on explicitly one side of
>the
>+ *    link.  This typically would be the guest side in a VM/VMM
>scenario.
>+ * #) The code has the concept of "north" and "south" where north
>denotes the
>+ *    memory-owner side (e.g. guest).

Why not use the standard naming for guest/host or front/backend?

>+ * #) A IOQ is "created" on the north side (which generates a unique
>ID), and
>+ *    is "connected" on the remote side via its ID.  The facilitates
>call-path
>+ *    setup in a manner that is friendly across VM/VMM boundaries.
>+ * #) An IOQ is manipulated using an iterator idiom.
>+ * #) A "IOQ Manager" abstraction handles the translation between two
>+ *    endpoints. E.g. allocating "north" memory, signaling, translating
>+ *    addresses (e.g. GPA to PA)
>+ *
>+ * Author:
>+ *      Gregory Haskins <[EMAIL PROTECTED]>
>+ *
>+ * This file is free software; you can redistribute it and/or modify
>+ * it under the terms of version 2 of the GNU General Public License
>+ * as published by the Free Software Foundation.
>+ *
>+ * This program is distributed in the hope that it will be useful,
>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+ * GNU General Public License for more details.
>+ *
>+ * You should have received a copy of the GNU General Public License
>+ * along with this program; if not, write to the Free Software
>Foundation,
>+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
>+ */
>+
>+#ifndef _LINUX_IOQ_H
>+#define _LINUX_IOQ_H
>+
>+#include <linux/sched.h>
>+#include <linux/wait.h>
>+#include <asm/types.h>
>+
>+struct ioq_mgr;
>+
>+/*
>+ *---------
>+ * The following structures represent data that is shared across
>boundaries
>+ * which may be quite disparate from one another (e.g. Windows vs
>Linux,
>+ * 32 vs 64 bit, etc).  Therefore, care has been taken to make sure
>they
>+ * present data in a manner that is independent of the environment.
>+ *-----------
>+ */
>+typedef u64 ioq_id_t;
>+
>+struct ioq_ring_desc {
>+      u64                 cookie; /* for arbitrary use by north-side */

I didn’t see usage for cookie in downstream patches. Is it obslete?

>+      u64                 ptr;
>+      u64                 offset;

The ptr & offset can be united.
Making the ring_desc small will help keeping such an array in a single page.

>+      u64                 len;
>+      u64                 alen;

What's alen?

>+      u8                  valid;
>+      u8                  sown; /* South owned = 1, North owned = 0 */

What about no-one owns it? if you plan of using the valid field you might need
to handle complex races.

>+};
>+
>+#define IOQ_RING_MAGIC 0x47fa2fe4
>+#define IOQ_RING_VER   1
>+
>+struct ioq_ring_idx {
>+      u32                 head;    /* 0 based index to head of ptr array
>*/
>+      u32                 tail;    /* 0 based index to tail of ptr array
>*/
>+      u8                  full;

full = head==tail     ???

>+};
>+
>+struct ioq_irq {
>+      u8                  enabled;
>+      u8                  pending;
>+};
>+
>+enum ioq_locality {
>+      ioq_locality_north,
>+      ioq_locality_south,
>+};
>+
>+struct ioq_ring_head {
>+      u32                 magic;
>+      u32                 ver;
>+      ioq_id_t            id;
>+      u32                 count;
>+      u64                 ptr;     /* ptr to array of
>ioq_ring_desc[count] */
>+      struct ioq_ring_idx idx[2];
>+      struct ioq_irq      irq[2];
>+      u8                  padding[16];
>+};
>+
>+/* --- END SHARED STRUCTURES --- */
>+
>+enum ioq_idx_type {
>+      ioq_idxtype_valid,
>+      ioq_idxtype_inuse,
>+      ioq_idxtype_invalid,
>+};
>+
>+enum ioq_seek_type {
>+      ioq_seek_tail,
>+      ioq_seek_next,
>+      ioq_seek_head,
>+      ioq_seek_set
>+};
>+
>+struct ioq_iterator {
>+      struct ioq            *ioq;
>+      unsigned long          flags;
>+      int                    update;
>+      struct ioq_ring_idx   *idx;
>+      u32                    pos;
>+      struct ioq_ring_desc  *desc;
>+};
>+
>+int  ioq_iter_seek(struct ioq_iterator *iter, enum ioq_seek_type type,
>+                 long offset, int flags);
>+int  ioq_iter_push(struct ioq_iterator *iter, int flags);
>+int  ioq_iter_pop(struct ioq_iterator *iter,  int flags);
>+
>+struct ioq_notifier {
>+      void (*signal)(struct ioq_notifier*);
>+};
>+
>+struct ioq {
>+      void     (*destroy)(struct ioq *ioq);
>+      int      (*signal)(struct ioq *ioq);
>+
>+      ioq_id_t               id;
>+      enum ioq_locality      locale;
>+      struct ioq_mgr        *mgr;
>+      struct ioq_ring_head  *head_desc;
>+      struct ioq_ring_desc  *ring;
>+      wait_queue_head_t      wq;
>+      struct ioq_notifier   *notifier;

Why have a notifier in a separate structure?

>+};
>+
>+static inline void ioq_init(struct ioq *ioq)
>+{
>+      memset(ioq, 0, sizeof(*ioq));
>+      init_waitqueue_head(&ioq->wq);
>+}
>+
>+int ioq_start(struct ioq *ioq, int flags);
>+int ioq_stop(struct ioq *ioq, int flags);
>+int ioq_signal(struct ioq *ioq, int flags);
>+void ioq_wakeup(struct ioq *ioq); /* This should only be used
>internally */
>+int ioq_count(struct ioq *ioq, enum ioq_idx_type type);
>+int ioq_full(struct ioq *ioq, enum ioq_idx_type type);
>+
>+static inline int ioq_empty(struct ioq *ioq, enum ioq_idx_type type)
>+{
>+    return !ioq_count(ioq, type);
>+}
>+
>+
>+
>+#define IOQ_ITER_AUTOUPDATE (1 << 0)
>+int ioq_iter(struct ioq *ioq, struct ioq_iterator *iter,
>+           enum ioq_idx_type type, int flags);
>+
>+struct ioq_mgr {
>+      int   (*create)(struct ioq_mgr *t, struct ioq **ioq,
>+                      size_t ringsize, int flags);
>+      int   (*connect)(struct ioq_mgr *t, ioq_id_t id, struct ioq **ioq,
>+                       int flags);
>+};
>+
>+
>+#endif /* _LINUX_IOQ_H */
>diff --git a/lib/Kconfig b/lib/Kconfig
>index 2e7ae6b..65c6d5d 100644
>--- a/lib/Kconfig
>+++ b/lib/Kconfig
>@@ -124,4 +124,15 @@ config HAS_DMA
>       depends on !NO_DMA
>       default y
>
>+config IOQ
>+      boolean "IO-Queue library - Generic shared-memory queue"
>+      default n
>+      help
>+       IOQ is a generic shared-memory-queue mechanism that happens to be
>+       friendly to virtualization boundaries. It can be used in a
>variety
>+       of ways, though its intended purpose is to become the low-level
>+       communication path for paravirtualized drivers.
>+
>+       If unsure, say N
>+
> endmenu
>diff --git a/lib/Makefile b/lib/Makefile
>index c8c8e20..2bf3b5d 100644
>--- a/lib/Makefile
>+++ b/lib/Makefile
>@@ -56,6 +56,7 @@ obj-$(CONFIG_TEXTSEARCH_BM) += ts_bm.o
> obj-$(CONFIG_TEXTSEARCH_FSM) += ts_fsm.o
> obj-$(CONFIG_SMP) += percpu_counter.o
> obj-$(CONFIG_AUDIT_GENERIC) += audit.o
>+obj-$(CONFIG_IOQ) += ioq.o
>
> obj-$(CONFIG_SWIOTLB) += swiotlb.o
> obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o
>diff --git a/lib/ioq.c b/lib/ioq.c
>new file mode 100644
>index 0000000..a808047
>--- /dev/null
>+++ b/lib/ioq.c
>@@ -0,0 +1,219 @@
>+/*
>+ * Copyright 2007 Novell.  All Rights Reserved.
>+ *
>+ * See include/linux/ioq.h for documentation
>+ *
>+ * Author:
>+ *      Gregory Haskins <[EMAIL PROTECTED]>
>+ *
>+ * This file is free software; you can redistribute it and/or modify
>+ * it under the terms of version 2 of the GNU General Public License
>+ * as published by the Free Software Foundation.
>+ *
>+ * This program is distributed in the hope that it will be useful,
>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+ * GNU General Public License for more details.
>+ *
>+ * You should have received a copy of the GNU General Public License
>+ * along with this program; if not, write to the Free Software
>Foundation,
>+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
>+ */
>+
>+#include <linux/sched.h>
>+#include <linux/ioq.h>
>+#include <asm/bitops.h>
>+#include <linux/module.h>
>+
>+#ifndef NULL
>+#define NULL 0
>+#endif
>+
>+static int ioq_iter_setpos(struct ioq_iterator *iter, u32 pos)
>+{
>+      struct ioq *ioq = iter->ioq;
>+
>+      BUG_ON(pos >= ioq->head_desc->count);
>+
>+      iter->pos  = pos;
>+      iter->desc = &ioq->ring[pos];
>+
>+      return 0;
>+}
>+
>+int ioq_iter_seek(struct ioq_iterator *iter, enum ioq_seek_type type,
>+                long offset, int flags)
>+{
>+      struct ioq_ring_head *head_desc  = iter->ioq->head_desc;
>+      struct ioq_ring_idx  *idx   = iter->idx;
>+      u32 pos;
>+
>+      switch (type) {
>+      case ioq_seek_next:
>+              pos = iter->pos + 1;
>+              pos %= head_desc->count;
>+              break;
>+      case ioq_seek_tail:
>+              pos = idx->tail;
>+              break;
>+      case ioq_seek_head:
>+              pos = idx->head;
>+              break;
>+      case ioq_seek_set:
>+              if (offset >= head_desc->count)
>+                      return -1;
>+              pos = offset;
>+              break;
>+      default:
>+              return -EINVAL;
>+      }
>+
>+      return ioq_iter_setpos(iter, pos);
>+}
>+EXPORT_SYMBOL(ioq_iter_seek);
>+
>+static int ioq_ring_count(struct ioq_ring_idx *idx, int count)
>+{
>+      if (idx->full && (idx->head == idx->tail))
>+              return count;
>+      else if (idx->head >= idx->tail)
>+              return idx->head - idx->tail;
>+      else
>+              return (idx->head + count) - idx->tail;
>+}
>+
>+int ioq_iter_push(struct ioq_iterator *iter, int flags)
>+{
>+      struct ioq_ring_head *head_desc = iter->ioq->head_desc;
>+      struct ioq_ring_idx  *idx  = iter->idx;
>+      int ret = -ENOSPC;
>+
>+      /*
>+       * Its only valid to push if we are currently pointed at the head
>+       */
>+      if (iter->pos != idx->head)
>+              return -EINVAL;
>+
>+      if (ioq_ring_count(idx, head_desc->count) < head_desc->count) {
>+              idx->head++;
>+              idx->head %= head_desc->count;
>+
>+              if (idx->head == idx->tail)
>+                      idx->full = 1;
>+
>+              ret = ioq_iter_seek(iter, ioq_seek_next, 0, flags);

Instead of the above code I would call to iter_seek and do everything inside
then return a proper error code if needed.

>+
>+              if (iter->update)
>+                      ioq_signal(iter->ioq, 0);
>+      }
>+
>+      return ret;
>+}
>+EXPORT_SYMBOL(ioq_iter_push);
>+
>+int ioq_iter_pop(struct ioq_iterator *iter,  int flags)
>+{
>+      struct ioq_ring_head *head_desc = iter->ioq->head_desc;
>+      struct ioq_ring_idx  *idx  = iter->idx;
>+      int ret = -ENOSPC;
>+
>+      /*
>+       * Its only valid to pop if we are currently pointed at the tail
>+       */
>+      if (iter->pos != idx->tail)
>+              return -EINVAL;
>+
>+      if (ioq_ring_count(idx, head_desc->count) != 0) {
>+              idx->tail++;
>+              idx->tail %= head_desc->count;
>+
>+              idx->full = 0;
>+
>+              ret = ioq_iter_seek(iter, ioq_seek_next, 0, flags);
>+
>+              if (iter->update)
>+                      ioq_signal(iter->ioq, 0);
>+      }
>+
>+      return ret;
>+}
>+EXPORT_SYMBOL(ioq_iter_pop);
>+
>+int ioq_iter(struct ioq *ioq, struct ioq_iterator *iter,
>+           enum ioq_idx_type type, int flags)

ioq_iter_init ?

>+{
>+      BUG_ON((type < 0) || (type >= ioq_idxtype_invalid));
>+
>+      iter->ioq        = ioq;
>+      iter->flags      = 0;
>+      iter->update     = (flags & IOQ_ITER_AUTOUPDATE);
>+      iter->idx        = &ioq->head_desc->idx[type];
>+      iter->pos        = -1;
>+      iter->desc       = NULL;
>+
>+      return 0;
>+}
>+EXPORT_SYMBOL(ioq_iter);
>+
>+int ioq_start(struct ioq *ioq, int flags)
>+{
>+      struct ioq_irq *irq = &ioq->head_desc->irq[ioq->locale];
>+
>+      irq->enabled = 1;
>+      if (irq->pending)
>+              ioq_wakeup(ioq);
>+
>+      return 0;
>+}
>+EXPORT_SYMBOL(ioq_start);
>+
>+int ioq_stop(struct ioq *ioq, int flags)
>+{
>+      struct ioq_irq *irq = &ioq->head_desc->irq[ioq->locale];
>+
>+      irq->enabled = 0;
>+
>+      return 0;
>+}
>+EXPORT_SYMBOL(ioq_stop);
>+
>+int ioq_signal(struct ioq *ioq, int flags)
>+{
>+      /* Load the irq structure from the other locale */
>+      struct ioq_irq *irq = &ioq->head_desc->irq[!ioq->locale];
>+
>+      irq->pending = 1;
>+      if (irq->enabled)
>+              ioq->signal(ioq);
>+
>+      return 0;
>+}
>+EXPORT_SYMBOL(ioq_signal);
>+
>+int ioq_count(struct ioq *ioq, enum ioq_idx_type type)
>+{
>+      BUG_ON((type < 0) || (type >= ioq_idxtype_invalid));
>+
>+      return ioq_ring_count(&ioq->head_desc->idx[type], ioq->head_desc-
>>count);
>+}
>+EXPORT_SYMBOL(ioq_count);
>+
>+int ioq_full(struct ioq *ioq, enum ioq_idx_type type)
>+{
>+      BUG_ON((type < 0) || (type >= ioq_idxtype_invalid));
>+
>+      return ioq->head_desc->idx[type].full;
>+}
>+EXPORT_SYMBOL(ioq_full);
>+
>+void ioq_wakeup(struct ioq *ioq)
>+{
>+      struct ioq_irq *irq = &ioq->head_desc->irq[ioq->locale];
>+
>+      irq->pending = 0;
>+
>+      wake_up(&ioq->wq);
>+      if (ioq->notifier)
>+              ioq->notifier->signal(ioq->notifier);
>+}
>+EXPORT_SYMBOL(ioq_wakeup);

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to