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,
};
next prev 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.