Signed-off-by: Gregory Haskins <[EMAIL PROTECTED]>
---

 drivers/kvm/Kconfig       |   16 ++
 drivers/kvm/Makefile      |    2 
 drivers/kvm/ioq.h         |   39 +++++
 drivers/kvm/ioq_guest.c   |  196 +++++++++++++++++++++++
 drivers/kvm/pvbus.h       |   63 +++++++
 drivers/kvm/pvbus_guest.c |  382 +++++++++++++++++++++++++++++++++++++++++++++
 include/linux/kvm.h       |    4 
 7 files changed, 701 insertions(+), 1 deletions(-)

diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig
index 445c6e4..d17ce96 100644
--- a/drivers/kvm/Kconfig
+++ b/drivers/kvm/Kconfig
@@ -41,4 +41,20 @@ config KVM_AMD
          Provides support for KVM on AMD processors equipped with the AMD-V
          (SVM) extensions.
 
+config KVM_GUEST
+       bool "KVM Guest support"
+       depends on X86
+       default n
+ 
+config KVM_PVBUS_GUEST
+        tristate "Paravirtualized Bus (PVBUS) support"
+        depends on KVM_GUEST
+        select IOQ
+        select PVBUS
+        ---help---
+       PVBUS is an infrastructure for generic PV drivers to take advantage
+       of an underlying hypervisor without having to understand the details
+       of the hypervisor itself.  You only need this option if you plan to
+       run this kernel as a KVM guest.
+
 endif # VIRTUALIZATION
diff --git a/drivers/kvm/Makefile b/drivers/kvm/Makefile
index c0a789f..cd621fc 100644
--- a/drivers/kvm/Makefile
+++ b/drivers/kvm/Makefile
@@ -8,3 +8,5 @@ kvm-intel-objs = vmx.o
 obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
 kvm-amd-objs = svm.o
 obj-$(CONFIG_KVM_AMD) += kvm-amd.o
+kvm-pvbus-objs := ioq_guest.o pvbus_guest.o
+obj-$(CONFIG_KVM_PVBUS_GUEST) += kvm-pvbus.o
\ No newline at end of file
diff --git a/drivers/kvm/ioq.h b/drivers/kvm/ioq.h
new file mode 100644
index 0000000..7e955f1
--- /dev/null
+++ b/drivers/kvm/ioq.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#ifndef _KVM_IOQ_H_
+#define _KVM_IOQ_H_
+
+#include <linux/ioq.h>
+
+#define IOQHC_REGISTER   1
+#define IOQHC_UNREGISTER  2
+#define IOQHC_SIGNAL     3
+
+struct ioq_register {
+       ioq_id_t id;
+       u32      irq;
+       u64      ring;
+};
+
+
+#endif /* _KVM_IOQ_H_ */
diff --git a/drivers/kvm/ioq_guest.c b/drivers/kvm/ioq_guest.c
new file mode 100644
index 0000000..5f16390
--- /dev/null
+++ b/drivers/kvm/ioq_guest.c
@@ -0,0 +1,196 @@
+/*
+ * 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/interrupt.h>
+#include <linux/ioq.h>
+#include <asm/hypercall.h>
+
+#include "ioq.h"
+#include "kvm.h"
+
+struct kvmguest_ioq {
+       struct ioq            ioq;
+       int                   irq;
+};
+
+struct kvmguest_ioq* to_ioq(struct ioq *ioq)
+{
+       return container_of(ioq, struct kvmguest_ioq, ioq);
+}
+
+static int ioq_hypercall(unsigned long nr, void *data)
+{
+       return hypercall(2, __NR_hypercall_ioq, nr, __pa(data));
+}
+
+/*
+ * ------------------
+ * interrupt handler
+ * ------------------
+ */
+irqreturn_t kvmguest_ioq_intr(int irq, void *dev)
+{
+       struct kvmguest_ioq *_ioq = to_ioq(dev);
+
+       ioq_wakeup(&_ioq->ioq);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * ------------------
+ * ioq implementation
+ * ------------------
+ */
+
+static int kvmguest_ioq_signal(struct ioq *ioq)
+{
+       return ioq_hypercall(IOQHC_SIGNAL, &ioq->id);
+}
+
+static void kvmguest_ioq_destroy(struct ioq *ioq)
+{
+       struct kvmguest_ioq *_ioq = to_ioq(ioq);
+       int ret;
+
+       ret = ioq_hypercall(IOQHC_UNREGISTER, &ioq->id);
+       BUG_ON (ret < 0);
+
+       free_irq(_ioq->irq, NULL);
+       destroy_irq(_ioq->irq);
+
+       kfree(_ioq->ioq.ring);
+       kfree(_ioq->ioq.head_desc);
+       kfree(_ioq);
+}
+
+/*
+ * ------------------
+ * ioqmgr implementation
+ * ------------------
+ */
+static int kvmguest_ioq_register(struct kvmguest_ioq *ioq, ioq_id_t id,
+                                int irq, void *ring)
+{
+       struct ioq_register data = {
+               .id   = id,
+               .irq  = irq,
+               .ring = (u64)__pa(ring),
+       };
+
+       return ioq_hypercall(IOQHC_REGISTER, &data);
+}
+
+static int kvmguest_ioq_create(struct ioq_mgr *t, struct ioq **ioq,
+                               size_t ringsize, int flags)
+{
+       struct kvmguest_ioq  *_ioq      = NULL;
+       struct ioq_ring_head *head_desc = NULL;
+       void                 *ring      = NULL;
+       size_t ringlen = sizeof(struct ioq_ring_desc) * ringsize;
+       int ret = -ENOMEM;
+
+       _ioq = kzalloc(sizeof(*_ioq), GFP_KERNEL);
+       if (!_ioq)
+               goto error;
+
+       head_desc = kzalloc(sizeof(*head_desc), GFP_KERNEL | GFP_DMA);
+       if (!head_desc)
+               goto error;
+
+       ring = kzalloc(ringlen, GFP_KERNEL | GFP_DMA);
+       if (!ring)
+               goto error;
+
+       head_desc->magic     = IOQ_RING_MAGIC;
+       head_desc->ver       = IOQ_RING_VER;
+       head_desc->id        = (ioq_id_t)_ioq;
+       head_desc->count     = ringsize;
+       head_desc->ptr       = (u64)__pa(ring);
+
+       /* Dynamically assign a free IRQ to this resource */
+       _ioq->irq            = create_irq();
+
+       ioq_init(&_ioq->ioq);
+
+       _ioq->ioq.signal     = kvmguest_ioq_signal;
+       _ioq->ioq.destroy    = kvmguest_ioq_destroy;
+
+       _ioq->ioq.id         = head_desc->id;
+       _ioq->ioq.locale     = ioq_locality_north;
+       _ioq->ioq.mgr        = t;
+       _ioq->ioq.head_desc  = head_desc;
+       _ioq->ioq.ring       = ring;
+
+       ret = request_irq(_ioq->irq, kvmguest_ioq_intr, 0, "KVM-IOQ", _ioq);
+       if (ret < 0)
+               goto error;
+
+       ret = kvmguest_ioq_register(_ioq, _ioq->ioq.id, _ioq->irq, ring);
+       if (ret < 0)
+               goto error;
+
+       *ioq = &_ioq->ioq;
+
+       return 0;
+
+ error:
+       if (_ioq)
+               kfree(_ioq);
+       if (head_desc)
+               kfree(head_desc);
+       if (ring)
+               kfree(ring);
+
+       return ret;
+}
+
+static int kvmguest_ioq_connect(struct ioq_mgr *t, ioq_id_t id,
+                                struct ioq **ioq, int flags)
+{
+       /* You cannot connect to queues on the guest */
+       return -EINVAL;
+
+}
+
+int kvmguest_ioqmgr_alloc(struct ioq_mgr **mgr)
+{
+       struct ioq_mgr *_mgr = kzalloc(sizeof(*_mgr), GFP_KERNEL);
+       if (!_mgr)
+               return -ENOMEM;
+
+       _mgr->create  = kvmguest_ioq_create;
+       _mgr->connect = kvmguest_ioq_connect;
+
+       *mgr = _mgr;
+
+       return 0;
+}
+
+void kvmguest_ioqmgr_free(struct ioq_mgr *mgr)
+{
+       kfree(mgr);
+}
+
+
+
+
diff --git a/drivers/kvm/pvbus.h b/drivers/kvm/pvbus.h
new file mode 100644
index 0000000..3241ef0
--- /dev/null
+++ b/drivers/kvm/pvbus.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2007 Novell.  All Rights Reserved.
+ *
+ * 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 _KVM_PVBUS_H
+#define _KVM_PVBUS_H
+
+#include <linux/ioq.h>
+
+#define KVM_PVBUS_OP_REGISTER   1
+#define KVM_PVBUS_OP_UNREGISTER 2
+#define KVM_PVBUS_OP_CALL       3
+
+struct pvbus_register_params {
+       ioq_id_t qid;
+};
+
+struct pvbus_call_params {
+       u64 inst;
+       u32 func;
+       u64 data;
+       u64 len;
+};
+
+#define KVM_PVBUS_EVENT_ADD  1
+#define KVM_PVBUS_EVENT_DROP 2
+
+#define PVBUS_MAX_NAME 128
+
+struct pvbus_add_event {
+       char name[PVBUS_MAX_NAME];
+       u64  id;
+};
+
+struct pvbus_drop_event {
+       u64 id;
+};
+
+struct pvbus_event {
+       u32 eventid;
+       union {
+               struct pvbus_add_event  add;
+               struct pvbus_drop_event drop;
+       }data;
+};
+
+#endif /* _KVM_PVBUS_H */
diff --git a/drivers/kvm/pvbus_guest.c b/drivers/kvm/pvbus_guest.c
new file mode 100644
index 0000000..56c3b50
--- /dev/null
+++ b/drivers/kvm/pvbus_guest.c
@@ -0,0 +1,382 @@
+/*
+ * Copyright 2007 Novell.  All Rights Reserved.
+ *
+ * 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/module.h>
+#include <linux/pvbus.h>
+#include <linux/kvm_para.h>
+#include <linux/kvm.h>
+#include <linux/mm.h>
+#include <linux/ioq.h>
+#include <linux/interrupt.h>
+
+#include <asm/hypercall.h>
+
+#include "pvbus.h"
+
+MODULE_AUTHOR ("Gregory Haskins");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1");
+
+int kvmguest_ioqmgr_alloc(struct ioq_mgr **mgr);
+void kvmguest_ioqmgr_free(struct ioq_mgr *mgr);
+
+static int kvm_pvbus_hypercall(unsigned long nr, void *data, unsigned long len)
+{
+       return hypercall(3, __NR_hypercall_pvbus, nr, __pa(data), len);
+}
+
+/*
+ * This is the vm-syscall address - to be patched by the host to
+ * VMCALL (Intel) or VMMCALL (AMD), depending on the CPU model:
+ */
+asm (
+       "       .globl hypercall_addr                   \n"
+       "       .align 4                                \n"
+       "       hypercall_addr:                         \n"
+       "               movl $-38, %eax                 \n"
+       "               ret                             \n"
+);
+
+extern unsigned char hypercall_addr[6];
+
+#ifndef CONFIG_X86_64
+static DEFINE_PER_CPU(struct kvm_vcpu_para_state, para_state);
+#endif
+
+static int __init kvm_pvbus_probe(void)
+{
+       struct page *hypercall_addr_page;
+       struct kvm_vcpu_para_state *para_state;
+
+#ifdef CONFIG_X86_64
+       struct page *pstate_page;
+       if ((pstate_page = alloc_page(GFP_KERNEL)) == NULL)
+               return -ENOMEM;
+       para_state = (struct kvm_vcpu_para_state*)page_address(pstate_page);
+#else
+       para_state =  &per_cpu(para_state, cpu);
+#endif
+       /*
+        * Try to write to a magic MSR (which is invalid on any real CPU),
+        * and thus signal to KVM that we wish to entering para-virtualized
+        * mode:
+        */
+       para_state->guest_version = KVM_PARA_API_VERSION;
+       para_state->host_version = -1;
+       para_state->size = sizeof(*para_state);
+       para_state->ret = -1;
+
+       hypercall_addr_page = vmalloc_to_page(hypercall_addr);
+       para_state->hypercall_gpa = page_to_pfn(hypercall_addr_page)
+               << PAGE_SHIFT | offset_in_page(hypercall_addr);
+       printk(KERN_DEBUG "kvm guest: hypercall gpa is 0x%lx\n",
+              (long)para_state->hypercall_gpa);
+
+       if (wrmsr_safe(MSR_KVM_API_MAGIC, __pa(para_state), 0)) {
+               printk(KERN_INFO "KVM guest: WRMSR probe failed.\n");
+               return -1;
+       }
+
+       printk(KERN_DEBUG "kvm guest: host returned %d\n",
+              para_state->ret);
+       printk(KERN_DEBUG "kvm guest: host version: %d\n",
+              para_state->host_version);
+       printk(KERN_DEBUG "kvm guest: syscall entry: %02x %02x %02x %02x\n",
+                       hypercall_addr[0], hypercall_addr[1],
+                       hypercall_addr[2], hypercall_addr[3]);
+
+       if (para_state->ret) {
+               printk(KERN_ERR "kvm guest: host refused registration.\n");
+               return -1;
+       }
+
+       return 0;
+
+}
+
+struct kvm_pvbus {
+       int                   connected;
+       struct ioq_mgr       *ioqmgr;
+       struct ioq           *ioq;
+       struct ioq_notifier   ioqn;
+       struct tasklet_struct task;
+};
+
+static struct kvm_pvbus kvm_pvbus;
+
+struct kvm_pvbus_device {
+       struct pvbus_device pvbdev;
+       char   name[PVBUS_MAX_NAME];
+};
+
+static int kvm_pvbus_createqueue(struct pvbus_device *dev, struct ioq **ioq,
+                                size_t ringsize, int flags)
+{
+       struct ioq_mgr *ioqmgr = kvm_pvbus.ioqmgr;
+
+       return ioqmgr->create(ioqmgr, ioq, ringsize, flags);
+}
+
+static int kvm_pvbus_call(struct pvbus_device *dev, u32 func, void *data,
+                         size_t len, int flags)
+{
+       struct pvbus_call_params params = {
+               .inst = dev->id,
+               .func = func,
+               .data = (u64)__pa(data),
+               .len  = len,
+       };
+
+       return kvm_pvbus_hypercall(KVM_PVBUS_OP_CALL, &params, sizeof(params));
+}
+
+static void kvm_pvbus_add_event(struct pvbus_add_event *event)
+{
+       int ret;
+       struct kvm_pvbus_device *new = kzalloc(sizeof(*new), GFP_KERNEL);
+       if (!new) {
+               printk("KVM_PVBUS: Out of memory on add_event\n");
+               return;
+       }
+
+       memcpy(new->name, event->name, PVBUS_MAX_NAME);
+       new->pvbdev.name        = new->name;
+       new->pvbdev.id          = event->id;
+       new->pvbdev.createqueue = kvm_pvbus_createqueue;
+       new->pvbdev.call        = kvm_pvbus_call;
+
+       sprintf(new->pvbdev.dev.bus_id, "%lld", event->id);
+
+       ret = pvbus_device_register(&new->pvbdev);
+       BUG_ON(ret < 0);
+}
+
+static void kvm_pvbus_drop_event(struct pvbus_drop_event *event)
+{
+#if 0 /* FIXME */
+       int ret = pvbus_device_unregister(event->id);
+       BUG_ON(ret < 0);
+#endif
+}
+
+/* INTR-Layer2: Invoked whenever layer 1 schedules our tasklet */
+static void kvm_pvbus_intr_l2(unsigned long _data)
+{
+       struct ioq_iterator iter;
+       int ret;
+
+       /* We want to iterate on the tail of the in-use index */
+       ret = ioq_iter_init(kvm_pvbus.ioq, &iter, ioq_idxtype_inuse, 0);
+       BUG_ON(ret < 0);
+
+       ret = ioq_iter_seek(&iter, ioq_seek_tail, 0, 0);
+       BUG_ON(ret < 0);
+
+       /*
+        * The EOM is indicated by finding a packet that is still owned by
+        * the south side.
+       *
+       * FIXME: This in theory could run indefinitely if the host keeps
+       * feeding us events since there is nothing like a NAPI budget.  We
+       * might need to address that
+        */
+       while (!iter.desc->sown) {
+              struct ioq_ring_desc *desc  = iter.desc;
+              struct pvbus_event   *event = (struct pvbus_event*)desc->cookie;
+
+              switch (event->eventid) {
+              case KVM_PVBUS_EVENT_ADD:
+                      kvm_pvbus_add_event(&event->data.add);
+                      break;
+              case KVM_PVBUS_EVENT_DROP:
+                      kvm_pvbus_drop_event(&event->data.drop);
+                      break;
+              default:
+                      printk(KERN_WARNING "KVM_PVBUS: Unexpected event %d\n",
+                             event->eventid);
+                      break;
+              };
+
+              memset(event, 0, sizeof(*event));
+
+              mb();
+              desc->sown = 1; /* give ownership back to the south */
+              mb();
+
+               /* Advance the in-use tail */
+               ret = ioq_iter_pop(&iter, 0);
+               BUG_ON(ret < 0);
+       }
+
+       /* And let the south side know that we changed the rx-queue */
+       ioq_signal(kvm_pvbus.ioq, 0);
+}
+
+/* INTR-Layer1: Invoked whenever the host issues an ioq_signal() */
+static void kvm_pvbus_intr_l1(struct ioq_notifier *ioqn)
+{
+       tasklet_schedule(&kvm_pvbus.task);
+}
+
+static int __init kvm_pvbus_register(void)
+{
+       struct pvbus_register_params params = {
+               .qid = kvm_pvbus.ioq->id,
+       };
+
+       return kvm_pvbus_hypercall(KVM_PVBUS_OP_REGISTER,
+                                  &params, sizeof(params)); 
+}
+
+static int __init kvm_pvbus_setup_ring(void) 
+{
+       struct ioq *ioq = kvm_pvbus.ioq;
+       struct ioq_iterator iter;
+       int ret;
+
+       /*
+        * We want to iterate on the "valid" index.  By default the iterator
+        * will not "autoupdate" which means it will not hypercall the host
+        * with our changes.  This is good, because we are really just
+        * initializing stuff here anyway.  Note that you can always manually
+        * signal the host with ioq_signal() if the autoupdate feature is not
+        * used.
+        */
+       ret = ioq_iter_init(ioq, &iter, ioq_idxtype_valid, 0);
+       BUG_ON(ret < 0);
+
+       /*
+        * Seek to the head of the valid index (which should be our first
+        * item since the queue is brand-new)
+        */
+       ret = ioq_iter_seek(&iter, ioq_seek_head, 0, 0);
+       BUG_ON(ret < 0);
+
+       /*
+        * Now populate each descriptor with an empty pvbus_event and mark it
+       * valid
+        */
+       while (!iter.desc->valid) {
+              struct pvbus_event   *event;
+              size_t                len  = sizeof(*event);
+              struct ioq_ring_desc *desc = iter.desc;
+
+              event = kzalloc(sizeof(*event), GFP_KERNEL);
+              if (!event)
+                      return -ENOMEM;
+
+              desc->cookie = (u64)event;
+              desc->ptr    = (u64)__pa(event);
+              desc->len    = len; /* total length  */
+              desc->alen   = 0;   /* actual length - filled in by host */
+              
+              /*
+               * We don't need any barriers here because the ring is not used
+               * yet
+               */
+              desc->valid  = 1;
+              desc->sown   = 1;   /* give ownership to the south */
+
+               /*
+                * This push operation will simultaneously advance the
+                * valid-head index and increment our position in the queue
+                * by one.
+                */
+               ret = ioq_iter_push(&iter, 0);
+               BUG_ON(ret < 0);
+       }
+
+       return 0;
+}
+
+int __init kvm_pvbus_init(void)
+{
+       struct ioq_mgr *ioqmgr = NULL;
+       int             ret;
+
+       memset(&kvm_pvbus, 0, sizeof(kvm_pvbus));
+
+       ret = kvm_pvbus_probe();
+       if (ret < 0)
+               return ret;
+
+       kvm_pvbus.connected = 1;
+
+       /* Allocate an IOQ-manager to use for all operations */
+       ret = kvmguest_ioqmgr_alloc(&ioqmgr);
+       if (ret < 0) {
+               printk(KERN_ERR "KVM_PVBUS: Could not create ioqmgr\n");
+               return ret;
+       }
+
+       kvm_pvbus.ioqmgr = ioqmgr;
+
+       /* Now allocate an IOQ to use for hotplug notification */
+       ret = ioqmgr->create(ioqmgr, &kvm_pvbus.ioq, 32, 0);
+       if (ret < 0) {
+               printk(KERN_ERR "KVM_PVBUS: Cound not create hotplug ioq\n");
+               goto out_fail;
+       }
+
+       ret = kvm_pvbus_setup_ring();
+       if (ret < 0) {
+               printk(KERN_ERR "KVM_PVBUS: Cound not setup ring\n");
+               goto out_fail;
+       }
+
+       /* Setup our interrupt callback */
+       kvm_pvbus.ioqn.signal   = kvm_pvbus_intr_l1;
+       kvm_pvbus.ioq->notifier = &kvm_pvbus.ioqn;
+       tasklet_init(&kvm_pvbus.task, kvm_pvbus_intr_l2, 0);
+       
+       /*
+        * Finally register our queue on the host to start receiving hotplug
+        * updates
+        */
+       ret = kvm_pvbus_register();
+       if (ret < 0) {
+               printk(KERN_ERR "KVM_PVBUS: Could not register with host\n");
+               goto out_fail;
+       }
+
+       return 0;
+
+ out_fail:
+       kvmguest_ioqmgr_free(ioqmgr);
+
+       return ret;
+
+}
+
+static void __exit kvm_pvbus_exit(void)
+{
+       if (kvm_pvbus.connected)
+               kvm_pvbus_hypercall(KVM_PVBUS_OP_UNREGISTER, NULL, 0);
+
+       if (kvm_pvbus.ioq)
+               kvm_pvbus.ioq->destroy(kvm_pvbus.ioq);
+
+       kvmguest_ioqmgr_free(kvm_pvbus.ioqmgr);
+}
+
+module_init(kvm_pvbus_init);
+module_exit(kvm_pvbus_exit);
+
+
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 7e9b862..04f65c9 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -314,8 +314,10 @@ struct kvm_signal_mask {
  * No registers are clobbered by the hypercall, except that the
  * return value is in RAX.
  */
-#define KVM_NR_HYPERCALLS              1
+#define KVM_NR_HYPERCALLS              3
 
 #define __NR_hypercall_test            0
+#define __NR_hypercall_ioq              1
+#define __NR_hypercall_pvbus            2
 
 #endif


-------------------------------------------------------------------------
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