All of lore.kernel.org
 help / color / mirror / Atom feed
From: Gregory Haskins <ghaskins@novell.com>
To: kvm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, ghaskins@novell.com
Subject: [PATCH v2 3/4] KVM: add io services to xinterface
Date: Fri, 02 Oct 2009 16:19:32 -0400	[thread overview]
Message-ID: <20091002201932.4014.91402.stgit@dev.haskins.net> (raw)
In-Reply-To: <20091002201159.4014.33268.stgit@dev.haskins.net>

We want to add a more efficient way to get PIO signals out of the guest,
so we add an "xioevent" interface.  This allows a client to register
for notifications when a specific MMIO/PIO address is touched by
the guest.  This is an alternative interface to ioeventfd, which is
performance limited by io-bus scaling and eventfd wait-queue based
notification mechanism.  This also has the advantage of retaining
the full PIO data payload and passing it to the recipient.

Signed-off-by: Gregory Haskins <ghaskins@novell.com>
---

 include/linux/kvm_xinterface.h |   47 ++++++++++++++++++
 virt/kvm/xinterface.c          |  106 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 153 insertions(+), 0 deletions(-)

diff --git a/include/linux/kvm_xinterface.h b/include/linux/kvm_xinterface.h
index 01f092b..684b6f8 100644
--- a/include/linux/kvm_xinterface.h
+++ b/include/linux/kvm_xinterface.h
@@ -12,6 +12,16 @@
 
 struct kvm_xinterface;
 struct kvm_xvmap;
+struct kvm_xioevent;
+
+enum {
+	kvm_xioevent_flag_nr_pio,
+	kvm_xioevent_flag_nr_max,
+};
+
+#define KVM_XIOEVENT_FLAG_PIO       (1 << kvm_xioevent_flag_nr_pio)
+
+#define KVM_XIOEVENT_VALID_FLAG_MASK  ((1 << kvm_xioevent_flag_nr_max) - 1)
 
 struct kvm_xinterface_ops {
 	unsigned long (*copy_to)(struct kvm_xinterface *intf,
@@ -22,6 +32,10 @@ struct kvm_xinterface_ops {
 	struct kvm_xvmap* (*vmap)(struct kvm_xinterface *intf,
 				  unsigned long gpa,
 				  unsigned long len);
+	struct kvm_xioevent* (*ioevent)(struct kvm_xinterface *intf,
+					u64 addr,
+					unsigned long len,
+					unsigned long flags);
 	void (*release)(struct kvm_xinterface *);
 };
 
@@ -109,6 +123,39 @@ kvm_xvmap_put(struct kvm_xvmap *vmap)
 	kref_put(&vmap->kref, _kvm_xvmap_release);
 }
 
+struct kvm_xioevent_ops {
+	void (*deassign)(struct kvm_xioevent *ioevent);
+};
+
+struct kvm_xioevent {
+	const struct kvm_xioevent_ops *ops;
+	struct kvm_xinterface         *intf;
+	void (*signal)(struct kvm_xioevent *ioevent, const void *val);
+	void                          *priv;
+};
+
+static inline void
+kvm_xioevent_init(struct kvm_xioevent *ioevent,
+		  const struct kvm_xioevent_ops *ops,
+		  struct kvm_xinterface *intf)
+{
+	memset(ioevent, 0, sizeof(vmap));
+	ioevent->ops = ops;
+	ioevent->intf = intf;
+
+	kvm_xinterface_get(intf);
+}
+
+static inline void
+kvm_xioevent_deassign(struct kvm_xioevent *ioevent)
+{
+	struct kvm_xinterface *intf = ioevent->intf;
+	rmb();
+
+	ioevent->ops->deassign(ioevent);
+	kvm_xinterface_put(intf);
+}
+
 struct kvm_xinterface *kvm_xinterface_bind(int fd);
 
 #endif /* __KVM_XINTERFACE_H */
diff --git a/virt/kvm/xinterface.c b/virt/kvm/xinterface.c
index 3b586c5..c356835 100644
--- a/virt/kvm/xinterface.c
+++ b/virt/kvm/xinterface.c
@@ -28,6 +28,8 @@
 #include <linux/kvm_host.h>
 #include <linux/kvm_xinterface.h>
 
+#include "iodev.h"
+
 struct _xinterface {
 	struct kvm             *kvm;
 	struct task_struct     *task;
@@ -42,6 +44,14 @@ struct _xvmap {
 	struct kvm_xvmap           vmap;
 };
 
+struct _ioevent {
+	u64                   addr;
+	int                   length;
+	struct kvm_io_bus    *bus;
+	struct kvm_io_device  dev;
+	struct kvm_xioevent   ioevent;
+};
+
 static struct _xinterface *
 to_intf(struct kvm_xinterface *intf)
 {
@@ -362,6 +372,101 @@ fail:
 	return ERR_PTR(ret);
 }
 
+/* MMIO/PIO writes trigger an event if the addr/val match */
+static int
+ioevent_write(struct kvm_io_device *dev, gpa_t addr, int len, const void *val)
+{
+	struct _ioevent *p = container_of(dev, struct _ioevent, dev);
+	struct kvm_xioevent *ioevent = &p->ioevent;
+
+	if (!(addr == p->addr && len == p->length))
+		return -EOPNOTSUPP;
+
+	if (!ioevent->signal)
+		return 0;
+
+	ioevent->signal(ioevent, val);
+	return 0;
+}
+
+static const struct kvm_io_device_ops ioevent_device_ops = {
+	.write = ioevent_write,
+};
+
+static void
+ioevent_deassign(struct kvm_xioevent *ioevent)
+{
+	struct _ioevent    *p = container_of(ioevent, struct _ioevent, ioevent);
+	struct _xinterface *_intf = to_intf(ioevent->intf);
+	struct kvm         *kvm = _intf->kvm;
+
+	kvm_io_bus_unregister_dev(kvm, p->bus, &p->dev);
+	kfree(p);
+}
+
+static const struct kvm_xioevent_ops ioevent_intf_ops = {
+	.deassign = ioevent_deassign,
+};
+
+static struct kvm_xioevent*
+xinterface_ioevent(struct kvm_xinterface *intf,
+		   u64 addr,
+		   unsigned long len,
+		   unsigned long flags)
+{
+	struct _xinterface         *_intf = to_intf(intf);
+	struct kvm                 *kvm = _intf->kvm;
+	int                         pio = flags & KVM_XIOEVENT_FLAG_PIO;
+	struct kvm_io_bus          *bus = pio ? &kvm->pio_bus : &kvm->mmio_bus;
+	struct _ioevent            *p;
+	int                         ret;
+
+	/* must be natural-word sized */
+	switch (len) {
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+		break;
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+
+	/* check for range overflow */
+	if (addr + len < addr)
+		return ERR_PTR(-EINVAL);
+
+	/* check for extra flags that we don't understand */
+	if (flags & ~KVM_XIOEVENT_VALID_FLAG_MASK)
+		return ERR_PTR(-EINVAL);
+
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	p->addr    = addr;
+	p->length  = len;
+	p->bus     = bus;
+
+	kvm_iodevice_init(&p->dev, &ioevent_device_ops);
+
+	ret = kvm_io_bus_register_dev(kvm, bus, &p->dev);
+	if (ret < 0)
+		goto fail;
+
+	kvm_xioevent_init(&p->ioevent, &ioevent_intf_ops, intf);
+
+	return &p->ioevent;
+
+fail:
+	kfree(p);
+
+	return ERR_PTR(ret);
+
+}
+
 static void
 xinterface_release(struct kvm_xinterface *intf)
 {
@@ -377,6 +482,7 @@ struct kvm_xinterface_ops _xinterface_ops = {
 	.copy_to     = xinterface_copy_to,
 	.copy_from   = xinterface_copy_from,
 	.vmap        = xinterface_vmap,
+	.ioevent     = xinterface_ioevent,
 	.release     = xinterface_release,
 };
 


  parent reply	other threads:[~2009-10-02 20:19 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-10-02 20:19 [PATCH v2 0/4] KVM: xinterface Gregory Haskins
2009-10-02 20:19 ` [PATCH v2 1/4] mm: export use_mm() and unuse_mm() to modules Gregory Haskins
2009-10-02 20:19 ` [PATCH v2 2/4] KVM: introduce "xinterface" API for external interaction with guests Gregory Haskins
2009-10-03 20:05   ` Marcelo Tosatti
2009-10-05 23:33     ` Gregory Haskins
2009-10-04 10:25   ` Avi Kivity
2009-10-05 23:57     ` Gregory Haskins
2009-10-06  9:34       ` Avi Kivity
2009-10-06 13:31         ` Gregory Haskins
2009-10-06 14:22           ` Gregory Haskins
2009-10-06 16:23             ` Avi Kivity
2009-10-06 17:00               ` Gregory Haskins
2009-10-06 17:00                 ` Gregory Haskins
2009-10-06 19:40                   ` Gregory Haskins
2009-10-07  8:11                     ` Avi Kivity
2009-10-07 12:48                       ` Gregory Haskins
2009-10-08 14:45                         ` Avi Kivity
2009-10-06 16:19           ` Avi Kivity
2009-10-06 16:58             ` Gregory Haskins
2009-10-06 18:18               ` [Alacrityvm-devel] " Ira W. Snyder
2009-10-07  5:10                 ` Amit Shah
2009-10-07  7:43                 ` Avi Kivity
2009-10-02 20:19 ` Gregory Haskins [this message]
2009-10-04 10:26   ` [PATCH v2 3/4] KVM: add io services to xinterface Avi Kivity
2009-10-02 20:19 ` [PATCH v2 4/4] KVM: add scatterlist support " Gregory Haskins
2009-10-04 10:28   ` Avi Kivity
2009-10-05 23:57     ` Gregory Haskins

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20091002201932.4014.91402.stgit@dev.haskins.net \
    --to=ghaskins@novell.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.