PV devices are currently discovered by pci bus. It is standard bus for x86 and good for HVM guests. Further flexibility will be achieved by a virtual bus, although some HVM guest will still require pci.
Signed-off-by: Dor Laor <[EMAIL PROTECTED]> --- drivers/kvm/Makefile | 2 +- drivers/kvm/kvm_pci_bus.c | 158 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+), 1 deletions(-) create mode 100644 drivers/kvm/kvm_pci_bus.c diff --git a/drivers/kvm/Makefile b/drivers/kvm/Makefile index 7f5607d..e51dba4 100644 --- a/drivers/kvm/Makefile +++ b/drivers/kvm/Makefile @@ -8,7 +8,7 @@ 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-pv-objs = kvm_pv.o +kvm-pv-objs = kvm_pv.o kvm_pci_bus.o obj-$(CONFIG_KVM_PV) += kvm-pv.o virtio-be-objs = virtio_backend.o obj-$(CONFIG_VIRTIO_BE) += virtio-be.o diff --git a/drivers/kvm/kvm_pci_bus.c b/drivers/kvm/kvm_pci_bus.c new file mode 100644 index 0000000..c06771e --- /dev/null +++ b/drivers/kvm/kvm_pci_bus.c @@ -0,0 +1,158 @@ +/* + * KVM virtio pci bus backend implementation + * + * Copyright (C) 2007, Qumranet, Inc., Dor Laor <[EMAIL PROTECTED]> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +//#define DEBUG +#include <linux/virtio.h> +#include <linux/spinlock.h> +#include <linux/kvm.h> +#include <linux/kvm_para.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <asm/hypercall.h> +#include <asm/io.h> +#include "kvm_pv.h" +#include "virtio_backend.h" + +static int debug = 3; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); + +#define DPRINTK(klevel, fmt, args...) \ + if (('0' + debug) >= (int)(klevel[1])) \ + printk(klevel "%s:%d: " fmt, \ + __FUNCTION__, __LINE__, ## args) + +/* + * Map between a pci device to it's dma key. + * It uses io port read to read the key value from the + * pci device. + */ +static int get_device_key(struct pci_dev *pdev, unsigned int *key) +{ + unsigned long ioaddr; + int rc; + unsigned long pio_start, pio_end, pio_flags, pio_len; + + rc = pci_enable_device(pdev); + if (rc) + goto err_out; + + pio_start = pci_resource_start (pdev, 0); + pio_end = pci_resource_end (pdev, 0); + pio_flags = pci_resource_flags (pdev, 0); + pio_len = pci_resource_len (pdev, 0); + + DPRINTK(KERN_DEBUG, "PIO region size == 0x%lx\n", pio_len); + + rc = pci_request_regions (pdev, "kvm_virtio"); + if (rc) { + DPRINTK(KERN_DEBUG, "Failed register pci region\n"); + goto err_out; + } + + ioaddr = (unsigned long)pci_iomap(pdev, 0, 0); + if (!ioaddr) { + printk(KERN_ERR "%s: cannot map PIO, aborting\n", pci_name(pdev)); + rc = -EIO; + goto err_out; + } + + DPRINTK(KERN_DEBUG, "ioaddr is %lx\n", ioaddr); + *key = ioread32((void __iomem*)ioaddr); + DPRINTK(KERN_DEBUG, "Got key = %d\n", *key); + *key = 0; + +err_out: + return rc; +} + +/* + * General pci init function + */ +int kvmbus_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent, + struct virtio_bus *vbus, + u16 dev_type) +{ + struct virtio_device *vdev; + u8 pci_rev; + int rs; + + vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); + if (vdev < 0) { + DPRINTK(KERN_ERR, "failed allocating virtio_device"); + return ENOMEM; + } + + pci_set_drvdata(pdev, vdev); + + if ((rs = kvm_guest_register_para(raw_smp_processor_id())) != 0) { + DPRINTK(KERN_ERR, "failed registering para\n"); + goto out_unreg_para; + } + + DPRINTK(KERN_DEBUG, "irq is %d\n", pdev->irq); + + pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev); + + DPRINTK(KERN_INFO, "pci dev %s (id %04x:%04x rev %02x) is a " + "guest paravirt %s device\n", + pci_name(pdev), pdev->vendor, pdev->device, pci_rev, vbus->name); + + vdev->dev.bus = pdev->dev.bus; + vdev->dev.parent = &pdev->dev; + sprintf(vdev->dev.bus_id, "%u", 0); + device_initialize(&vdev->dev); + if (device_register(&vdev->dev) != 0) { + DPRINTK(KERN_EMERG, "Cannot register device\n"); + goto out_unreg_para; + } + + if (get_device_key(pdev, &vdev->id) < 0) { + DPRINTK(KERN_ERR, "pci dev %s cannot use ioports\n", pci_name(pdev)); + goto out_unreg_para; + } + DPRINTK(KERN_DEBUG, "Got key = %x\n", vdev->id); + + vdev->desc.irq = pdev->irq; + vdev->desc.type = dev_type; + vdev->desc.status = VIRTIO_DEVICE_S_DRIVER; + + + rs = vbus->vbus_probe(vdev); + if (vdev < 0) { + DPRINTK(KERN_ERR, "failed probing for %s, err=%d\n", vbus->name, rs); + goto out_unreg_para; + } + + return 0; + +out_unreg_para: + kfree(vdev); + + return rs; +} +EXPORT_SYMBOL_GPL(kvmbus_init_one); + +void kvmbus_remove_one(struct pci_dev *pdev, struct virtio_bus *vbus) +{ + struct virtio_device *vdev = pci_get_drvdata(pdev); + + vbus->vbus_unprobe(vdev); + kfree(vdev); + pci_disable_device(pdev); +} +EXPORT_SYMBOL_GPL(kvmbus_remove_one); + +MODULE_DESCRIPTION("KVM virtual pci bus driver"); +MODULE_LICENSE("GPL"); + + ----- In simplicity there is elegance. Dor Laor ;) ------------------------------------------------------------------------- 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