This patch adds a driver for my shared memory PCI device using the uio_pci interface. The driver exports two memory regions. The first memory region are device registers for sending interrupts and the second memory region maps the shared memory. Cam --- drivers/uio/Kconfig | 8 +++ drivers/uio/Makefile | 1 + drivers/uio/uio_ivshmem.c | 143 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+), 0 deletions(-) create mode 100644 drivers/uio/uio_ivshmem.c diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig index 8aa1955..6e15207 100644 --- a/drivers/uio/Kconfig +++ b/drivers/uio/Kconfig @@ -84,6 +84,14 @@ config UIO_SERCOS3 If you compile this as a module, it will be called uio_sercos3. +config UIO_IVSHMEM + tristate "KVM shared memory PCI driver" + default n + help + Userspace I/O interface for the KVM shared memory device. This + driver will make available two memory regions, the first is + registers and the second is a region for sharing between VMs. + config UIO_PCI_GENERIC tristate "Generic driver for PCI 2.3 and PCI Express cards" depends on PCI diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile index 73b2e75..3aa0104 100644 --- a/drivers/uio/Makefile +++ b/drivers/uio/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_UIO_SMX) += uio_smx.o obj-$(CONFIG_UIO_AEC) += uio_aec.o obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o +obj-$(CONFIG_UIO_IVSHMEM) += uio_ivshmem.o diff --git a/drivers/uio/uio_ivshmem.c b/drivers/uio/uio_ivshmem.c new file mode 100644 index 0000000..7a1cf65 --- /dev/null +++ b/drivers/uio/uio_ivshmem.c @@ -0,0 +1,143 @@ +/* + * UIO IVShmem Driver + * + * (C) 2009 Cam Macdonell + * based on Hilscher CIF card driver (C) 2007 Hans J. Koch <hjk@xxxxxxxxxxxxx> + * + * Licensed under GPL version 2 only. + * + */ + +#include <linux/device.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/uio_driver.h> + +#include <asm/io.h> + +#define IntrStatus 0x02 +#define IntrMask 0x00 + +static irqreturn_t ivshmem_handler(int irq, struct uio_info *dev_info) +{ + + void __iomem *plx_intscr = dev_info->mem[0].internal_addr + + IntrStatus; + u16 val; + + val = readw(plx_intscr); + if (val == 0) + return IRQ_NONE; + + return IRQ_HANDLED; +} + +static int __devinit ivshmem_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct uio_info *info; + + info = kzalloc(sizeof(struct uio_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + if (pci_enable_device(dev)) + goto out_free; + + if (pci_request_regions(dev, "ivshmem")) + goto out_disable; + + info->mem[0].addr = pci_resource_start(dev, 0); + if (!info->mem[0].addr) + goto out_release; + info->mem[0].internal_addr = pci_ioremap_bar(dev, 0); + if (!info->mem[0].internal_addr) + goto out_release; + + info->mem[0].size = pci_resource_len(dev, 0); + info->mem[0].memtype = UIO_MEM_PHYS; + + info->mem[1].addr = pci_resource_start(dev, 1); + if (!info->mem[0].addr) + goto out_unmap; + info->mem[1].internal_addr = pci_ioremap_bar(dev, 1); + if (!info->mem[1].internal_addr) + goto out_unmap; + + info->mem[1].size = pci_resource_len(dev, 1); + info->mem[1].memtype = UIO_MEM_PHYS; + + + info->name = "ivshmem"; + info->version = "0.0.1"; + info->irq = dev->irq; + info->irq_flags = IRQF_DISABLED | IRQF_SHARED; + info->handler = ivshmem_handler; + + if (uio_register_device(&dev->dev, info)) + goto out_unmap2; + + pci_set_drvdata(dev, info); + + writew(0xffff, info->mem[0].internal_addr + IntrMask); + + return 0; +out_unmap2: + iounmap(info->mem[1].internal_addr); +out_unmap: + iounmap(info->mem[0].internal_addr); +out_release: + pci_release_regions(dev); +out_disable: + pci_disable_device(dev); +out_free: + kfree (info); + return -ENODEV; +} + +static void ivshmem_pci_remove(struct pci_dev *dev) +{ + struct uio_info *info = pci_get_drvdata(dev); + + uio_unregister_device(info); + pci_release_regions(dev); + pci_disable_device(dev); + pci_set_drvdata(dev, NULL); + iounmap(info->mem[0].internal_addr); + + kfree (info); +} + +static struct pci_device_id ivshmem_pci_ids[] __devinitdata = { + { + .vendor = 0x1af4, + .device = 0x1110, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { 0, } +}; + +static struct pci_driver ivshmem_pci_driver = { + .name = "uio_ivshmem", + .id_table = ivshmem_pci_ids, + .probe = ivshmem_pci_probe, + .remove = ivshmem_pci_remove, +}; + +static int __init ivshmem_init_module(void) +{ + return pci_register_driver(&ivshmem_pci_driver); +} + +static void __exit ivshmem_exit_module(void) +{ + pci_unregister_driver(&ivshmem_pci_driver); +} + +module_init(ivshmem_init_module); +module_exit(ivshmem_exit_module); + +MODULE_DEVICE_TABLE(pci, ivshmem_pci_ids); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Cam Macdonell"); -- 1.6.0.6 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html