Patchwork Shared memory uio_pci driver

login
register
mail settings
Submitter Cam Macdonell
Date March 5, 2010, 11:53 p.m.
Message ID <1267833190-25292-1-git-send-email-cam@cs.ualberta.ca>
Download mbox | patch
Permalink /patch/47035/
State New
Headers show

Comments

Cam Macdonell - March 5, 2010, 11:53 p.m.
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

Patch

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@linutronix.de>
+ *
+ * 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");