get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/7343/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 7343,
    "url": "https://patches.dpdk.org/api/patches/7343/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1443652138-31782-3-git-send-email-stephen@networkplumber.org/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1443652138-31782-3-git-send-email-stephen@networkplumber.org>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1443652138-31782-3-git-send-email-stephen@networkplumber.org",
    "date": "2015-09-30T22:28:58",
    "name": "[dpdk-dev,2/2] uio: new driver to support PCI MSI-X",
    "commit_ref": null,
    "pull_url": null,
    "state": "not-applicable",
    "archived": true,
    "hash": "3b62a216156441c5a9b1a015cd994dffeaa1a12b",
    "submitter": {
        "id": 27,
        "url": "https://patches.dpdk.org/api/people/27/?format=api",
        "name": "Stephen Hemminger",
        "email": "stephen@networkplumber.org"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1443652138-31782-3-git-send-email-stephen@networkplumber.org/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/7343/comments/",
    "check": "pending",
    "checks": "https://patches.dpdk.org/api/patches/7343/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id C8AC98E61;\n\tThu,  1 Oct 2015 00:28:55 +0200 (CEST)",
            "from mail-pa0-f47.google.com (mail-pa0-f47.google.com\n\t[209.85.220.47]) by dpdk.org (Postfix) with ESMTP id EEAB68D8A\n\tfor <dev@dpdk.org>; Thu,  1 Oct 2015 00:28:52 +0200 (CEST)",
            "by pacfv12 with SMTP id fv12so53962936pac.2\n\tfor <dev@dpdk.org>; Wed, 30 Sep 2015 15:28:52 -0700 (PDT)",
            "from urahara.home.lan (static-50-53-82-155.bvtn.or.frontiernet.net.\n\t[50.53.82.155]) by smtp.gmail.com with ESMTPSA id\n\tgw3sm2603289pbc.46.2015.09.30.15.28.51\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128);\n\tWed, 30 Sep 2015 15:28:51 -0700 (PDT)"
        ],
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20130820;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references;\n\tbh=DSBsE6xHeKl+y+flUAHKxvyGhoTlDteuyDG61Gudbc4=;\n\tb=Pjn2f8FgS2LNkv9Piz1pbZBvC+OQlTIVrswdul/qYxXnGGCcMwo7BiEY/EnaMb9RcU\n\tudOySaOJ0GmSPtZTd0QITwo3OZ1bJ/YCKbzoLWB02P0UqjmwY2I9GYFggNGTYrJXQZBO\n\tTcURYK5OU1eTpLA+U2oXOUKPMKXAP/DouovGyVhaH9jt7OrV8ZeHUcIonQdtoFXudQik\n\tyIVDFR3LhPIpDV7B9K/0vgm9FIGDRbwuG8/tcoNazKj+3+RJdoXtxXhBCuu45eBi20vB\n\tAnWsLmlSXp/mnM8c4t5Sxi9rGJoTeybXnQgZo8iAVeyzf9RfJGWtYkTswaGA5omMaHkG\n\toipg==",
        "X-Gm-Message-State": "ALoCoQl/9CjCkxyxXBIQ7GaI8iOjXanoD6LPs9QsWuy4KU671CrjgRy+kgoGoaPw0h6FwOU19z8P",
        "X-Received": "by 10.69.25.1 with SMTP id im1mr7679669pbd.102.1443652132369;\n\tWed, 30 Sep 2015 15:28:52 -0700 (PDT)",
        "From": "Stephen Hemminger <stephen@networkplumber.org>",
        "To": "hjk@hansjkoch.de,\n\tgregkh@linux-foundation.org",
        "Date": "Wed, 30 Sep 2015 15:28:58 -0700",
        "Message-Id": "<1443652138-31782-3-git-send-email-stephen@networkplumber.org>",
        "X-Mailer": "git-send-email 2.1.4",
        "In-Reply-To": "<1443652138-31782-1-git-send-email-stephen@networkplumber.org>",
        "References": "<1443652138-31782-1-git-send-email-stephen@networkplumber.org>",
        "Cc": "dev@dpdk.org, linux-kernel@vger.kernel.org",
        "Subject": "[dpdk-dev] [PATCH 2/2] uio: new driver to support PCI MSI-X",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "patches and discussions about DPDK <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "This driver allows using PCI device with Message Signalled Interrupt\nfrom userspace. The API is similar to the igb_uio driver used by the DPDK.\nVia ioctl it provides a mechanism to map MSI-X interrupts into event\nfile descriptors similar to VFIO.\n\nVFIO is a better choice if IOMMU is available, but often userspace drivers\nhave to work in environments where IOMMU support (real or emulated) is\nnot available.  All UIO drivers that support DMA are not secure against\nrogue userspace applications programming DMA hardware to access\nprivate memory; this driver is no less secure than existing code.\n\nSigned-off-by: Stephen Hemminger <stephen@networkplumber.org>\n---\n drivers/uio/Kconfig          |   9 ++\n drivers/uio/Makefile         |   1 +\n drivers/uio/uio_msi.c        | 378 +++++++++++++++++++++++++++++++++++++++++++\n include/uapi/linux/Kbuild    |   1 +\n include/uapi/linux/uio_msi.h |  22 +++\n 5 files changed, 411 insertions(+)\n create mode 100644 drivers/uio/uio_msi.c\n create mode 100644 include/uapi/linux/uio_msi.h",
    "diff": "diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig\nindex 52c98ce..04adfa0 100644\n--- a/drivers/uio/Kconfig\n+++ b/drivers/uio/Kconfig\n@@ -93,6 +93,15 @@ config UIO_PCI_GENERIC\n \t  primarily, for virtualization scenarios.\n \t  If you compile this as a module, it will be called uio_pci_generic.\n \n+config UIO_PCI_MSI\n+       tristate \"Generic driver supporting MSI-x on PCI Express cards\"\n+\tdepends on PCI\n+\thelp\n+\t  Generic driver that provides Message Signalled IRQ events\n+\t  similar to VFIO. If IOMMMU is available please use VFIO\n+\t  instead since it provides more security.\n+\t  If you compile this as a module, it will be called uio_msi.\n+\n config UIO_NETX\n \ttristate \"Hilscher NetX Card driver\"\n \tdepends on PCI\ndiff --git a/drivers/uio/Makefile b/drivers/uio/Makefile\nindex 8560dad..62fc44b 100644\n--- a/drivers/uio/Makefile\n+++ b/drivers/uio/Makefile\n@@ -9,3 +9,4 @@ obj-$(CONFIG_UIO_NETX)\t+= uio_netx.o\n obj-$(CONFIG_UIO_PRUSS)         += uio_pruss.o\n obj-$(CONFIG_UIO_MF624)         += uio_mf624.o\n obj-$(CONFIG_UIO_FSL_ELBC_GPCM)\t+= uio_fsl_elbc_gpcm.o\n+obj-$(CONFIG_UIO_PCI_MSI)\t+= uio_msi.o\ndiff --git a/drivers/uio/uio_msi.c b/drivers/uio/uio_msi.c\nnew file mode 100644\nindex 0000000..802b5c4\n--- /dev/null\n+++ b/drivers/uio/uio_msi.c\n@@ -0,0 +1,378 @@\n+/*-\n+ *\n+ * Copyright (c) 2015 by Brocade Communications Systems, Inc.\n+ * Author: Stephen Hemminger <stephen@networkplumber.org>\n+ *\n+ * This work is licensed under the terms of the GNU GPL, version 2 only.\n+ */\n+\n+#define pr_fmt(fmt) KBUILD_MODNAME \": \" fmt\n+\n+#include <linux/device.h>\n+#include <linux/interrupt.h>\n+#include <linux/eventfd.h>\n+#include <linux/module.h>\n+#include <linux/pci.h>\n+#include <linux/uio_driver.h>\n+#include <linux/msi.h>\n+#include <linux/uio_msi.h>\n+\n+#define DRIVER_VERSION\t\t\"0.1.1\"\n+#define MAX_MSIX_VECTORS\t64\n+\n+/* MSI-X vector information */\n+struct uio_msi_pci_dev {\n+\tstruct uio_info info;\t\t/* UIO driver info */\n+\tstruct pci_dev *pdev;\t\t/* PCI device */\n+\tstruct mutex\tmutex;\t\t/* open/release/ioctl mutex */\n+\tint\t\tref_cnt;\t/* references to device */\n+\tunsigned int\tmax_vectors;\t/* MSI-X slots available */\n+\tstruct msix_entry *msix;\t/* MSI-X vector table */\n+\tstruct uio_msi_irq_ctx {\n+\t\tstruct eventfd_ctx *trigger; /* vector to eventfd */\n+\t\tchar *name;\t\t/* name in /proc/interrupts */\n+\t} *ctx;\n+};\n+\n+static irqreturn_t uio_intx_irqhandler(int irq, void *arg)\n+{\n+\tstruct uio_msi_pci_dev *udev = arg;\n+\n+\tif (pci_check_and_mask_intx(udev->pdev)) {\n+\t\teventfd_signal(udev->ctx->trigger, 1);\n+\t\treturn IRQ_HANDLED;\n+\t}\n+\n+\treturn IRQ_NONE;\n+}\n+\n+static irqreturn_t uio_msi_irqhandler(int irq, void *arg)\n+{\n+\tstruct eventfd_ctx *trigger = arg;\n+\n+\teventfd_signal(trigger, 1);\n+\treturn IRQ_HANDLED;\n+}\n+\n+/* set the mapping between vector # and existing eventfd. */\n+static int set_irq_eventfd(struct uio_msi_pci_dev *udev, u32 vec, int fd)\n+{\n+\tstruct eventfd_ctx *trigger;\n+\tint irq, err;\n+\n+\tif (vec >= udev->max_vectors) {\n+\t\tdev_notice(&udev->pdev->dev, \"vec %u >= num_vec %u\\n\",\n+\t\t\t   vec, udev->max_vectors);\n+\t\treturn -ERANGE;\n+\t}\n+\n+\tirq = udev->msix[vec].vector;\n+\ttrigger = udev->ctx[vec].trigger;\n+\tif (trigger) {\n+\t\t/* Clearup existing irq mapping */\n+\t\tfree_irq(irq, trigger);\n+\t\teventfd_ctx_put(trigger);\n+\t\tudev->ctx[vec].trigger = NULL;\n+\t}\n+\n+\t/* Passing -1 is used to disable interrupt */\n+\tif (fd < 0)\n+\t\treturn 0;\n+\n+\ttrigger = eventfd_ctx_fdget(fd);\n+\tif (IS_ERR(trigger)) {\n+\t\terr = PTR_ERR(trigger);\n+\t\tdev_notice(&udev->pdev->dev,\n+\t\t\t   \"eventfd ctx get failed: %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\n+\tif (udev->msix)\n+\t\terr = request_irq(irq, uio_msi_irqhandler, 0,\n+\t\t\t\t  udev->ctx[vec].name, trigger);\n+\telse\n+\t\terr = request_irq(irq, uio_intx_irqhandler, IRQF_SHARED,\n+\t\t\t\t  udev->ctx[vec].name, udev);\n+\n+\tif (err) {\n+\t\tdev_notice(&udev->pdev->dev,\n+\t\t\t   \"request irq failed: %d\\n\", err);\n+\t\teventfd_ctx_put(trigger);\n+\t\treturn err;\n+\t}\n+\n+\tudev->ctx[vec].trigger = trigger;\n+\treturn 0;\n+}\n+\n+static int\n+uio_msi_ioctl(struct uio_info *info, unsigned int cmd, unsigned long arg)\n+{\n+\tstruct uio_msi_pci_dev *udev\n+\t\t= container_of(info, struct uio_msi_pci_dev, info);\n+\tstruct uio_msi_irq_set hdr;\n+\tint err;\n+\n+\tswitch (cmd) {\n+\tcase UIO_MSI_IRQ_SET:\n+\t\tif (copy_from_user(&hdr, (void __user *)arg, sizeof(hdr)))\n+\t\t\treturn -EFAULT;\n+\n+\t\tmutex_lock(&udev->mutex);\n+\t\terr = set_irq_eventfd(udev, hdr.vec, hdr.fd);\n+\t\tmutex_unlock(&udev->mutex);\n+\t\tbreak;\n+\tdefault:\n+\t\terr = -EOPNOTSUPP;\n+\t}\n+\treturn err;\n+}\n+\n+/* Opening the UIO device for first time enables MSI-X */\n+static int\n+uio_msi_open(struct uio_info *info, struct inode *inode)\n+{\n+\tstruct uio_msi_pci_dev *udev\n+\t\t= container_of(info, struct uio_msi_pci_dev, info);\n+\tint err = 0;\n+\n+\tmutex_lock(&udev->mutex);\n+\tif (udev->ref_cnt++ == 0) {\n+\t\tif (udev->msix)\n+\t\t\terr = pci_enable_msix(udev->pdev, udev->msix,\n+\t\t\t\t\t      udev->max_vectors);\n+\t}\n+\tmutex_unlock(&udev->mutex);\n+\n+\treturn err;\n+}\n+\n+/* Last close of the UIO device releases/disables all IRQ's */\n+static int\n+uio_msi_release(struct uio_info *info, struct inode *inode)\n+{\n+\tstruct uio_msi_pci_dev *udev\n+\t\t= container_of(info, struct uio_msi_pci_dev, info);\n+\tint i;\n+\n+\tmutex_lock(&udev->mutex);\n+\tif (--udev->ref_cnt == 0) {\n+\t\tfor (i = 0; i < udev->max_vectors; i++) {\n+\t\t\tint irq = udev->msix[i].vector;\n+\t\t\tstruct eventfd_ctx *trigger = udev->ctx[i].trigger;\n+\n+\t\t\tif (!trigger)\n+\t\t\t\tcontinue;\n+\n+\t\t\tfree_irq(irq, trigger);\n+\t\t\teventfd_ctx_put(trigger);\n+\t\t\tudev->ctx[i].trigger = NULL;\n+\t\t}\n+\n+\t\tif (udev->msix)\n+\t\t\tpci_disable_msix(udev->pdev);\n+\t}\n+\tmutex_unlock(&udev->mutex);\n+\n+\treturn 0;\n+}\n+\n+/* Unmap previously ioremap'd resources */\n+static void\n+release_iomaps(struct uio_mem *mem)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < MAX_UIO_MAPS; i++, mem++) {\n+\t\tif (mem->internal_addr)\n+\t\t\tiounmap(mem->internal_addr);\n+\t}\n+}\n+\n+static int\n+setup_maps(struct pci_dev *pdev, struct uio_info *info)\n+{\n+\tint i, m = 0, p = 0, err;\n+\tstatic const char * const bar_names[] = {\n+\t\t\"BAR0\",\t\"BAR1\",\t\"BAR2\",\t\"BAR3\",\t\"BAR4\",\t\"BAR5\",\n+\t};\n+\n+\tfor (i = 0; i < ARRAY_SIZE(bar_names); i++) {\n+\t\tunsigned long start = pci_resource_start(pdev, i);\n+\t\tunsigned long flags = pci_resource_flags(pdev, i);\n+\t\tunsigned long len = pci_resource_len(pdev, i);\n+\n+\t\tif (start == 0 || len == 0)\n+\t\t\tcontinue;\n+\n+\t\tif (flags & IORESOURCE_MEM) {\n+\t\t\tvoid __iomem *addr;\n+\n+\t\t\tif (m >= MAX_UIO_MAPS)\n+\t\t\t\tcontinue;\n+\n+\t\t\taddr = ioremap(start, len);\n+\t\t\tif (addr == NULL) {\n+\t\t\t\terr = -EINVAL;\n+\t\t\t\tgoto fail;\n+\t\t\t}\n+\n+\t\t\tinfo->mem[m].name = bar_names[i];\n+\t\t\tinfo->mem[m].addr = start;\n+\t\t\tinfo->mem[m].internal_addr = addr;\n+\t\t\tinfo->mem[m].size = len;\n+\t\t\tinfo->mem[m].memtype = UIO_MEM_PHYS;\n+\t\t\t++m;\n+\t\t} else if (flags & IORESOURCE_IO) {\n+\t\t\tif (p >= MAX_UIO_PORT_REGIONS)\n+\t\t\t\tcontinue;\n+\n+\t\t\tinfo->port[p].name = bar_names[i];\n+\t\t\tinfo->port[p].start = start;\n+\t\t\tinfo->port[p].size = len;\n+\t\t\tinfo->port[p].porttype = UIO_PORT_X86;\n+\t\t\t++p;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+ fail:\n+\tfor (i = 0; i < m; i++)\n+\t\tiounmap(info->mem[i].internal_addr);\n+\treturn err;\n+}\n+\n+static int uio_msi_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n+{\n+\tstruct uio_msi_pci_dev *udev;\n+\tint i, err, vectors;\n+\n+\tudev = kzalloc(sizeof(struct uio_msi_pci_dev), GFP_KERNEL);\n+\tif (!udev)\n+\t\treturn -ENOMEM;\n+\n+\terr = pci_enable_device(pdev);\n+\tif (err != 0) {\n+\t\tdev_err(&pdev->dev, \"cannot enable PCI device\\n\");\n+\t\tgoto fail_free;\n+\t}\n+\n+\terr = pci_request_regions(pdev, \"uio_msi\");\n+\tif (err != 0) {\n+\t\tdev_err(&pdev->dev, \"Cannot request regions\\n\");\n+\t\tgoto fail_disable;\n+\t}\n+\n+\tpci_set_master(pdev);\n+\n+\t/* remap resources */\n+\terr = setup_maps(pdev, &udev->info);\n+\tif (err)\n+\t\tgoto fail_release_iomem;\n+\n+\t/* fill uio infos */\n+\tudev->info.name = \"uio_msi\";\n+\tudev->info.version = DRIVER_VERSION;\n+\tudev->info.priv = udev;\n+\tudev->pdev = pdev;\n+\tudev->info.ioctl = uio_msi_ioctl;\n+\tudev->info.open = uio_msi_open;\n+\tudev->info.release = uio_msi_release;\n+\tudev->info.irq = UIO_IRQ_CUSTOM;\n+\tmutex_init(&udev->mutex);\n+\n+\tvectors = pci_msix_vec_count(pdev);\n+\tif (vectors > 0) {\n+\t\tudev->max_vectors = min_t(u16, vectors, MAX_MSIX_VECTORS);\n+\t\tdev_info(&pdev->dev, \"using up to %u MSI-X vectors\\n\",\n+\t\t\tudev->max_vectors);\n+\n+\t\terr = -ENOMEM;\n+\t\tudev->msix = kcalloc(udev->max_vectors,\n+\t\t\t\t     sizeof(struct msix_entry), GFP_KERNEL);\n+\t\tif (!udev->msix)\n+\t\t\tgoto fail_release_iomem;\n+\t} else if (!pci_intx_mask_supported(pdev)) {\n+\t\tdev_err(&pdev->dev,\n+\t\t\t\"device does not support MSI-X or INTX\\n\");\n+\t\terr = -EINVAL;\n+\t\tgoto fail_release_iomem;\n+\t} else {\n+\t\tdev_notice(&pdev->dev, \"using INTX\\n\");\n+\t\tudev->info.irq_flags = IRQF_SHARED;\n+\t\tudev->max_vectors = 1;\n+\t}\n+\n+\tudev->ctx = kcalloc(udev->max_vectors,\n+\t\t\t    sizeof(struct uio_msi_irq_ctx), GFP_KERNEL);\n+\tif (!udev->ctx)\n+\t\tgoto fail_free_msix;\n+\n+\tfor (i = 0; i < udev->max_vectors; i++) {\n+\t\tudev->msix[i].entry = i;\n+\n+\t\tudev->ctx[i].name = kasprintf(GFP_KERNEL,\n+\t\t\t\t\t      KBUILD_MODNAME \"[%d](%s)\",\n+\t\t\t\t\t      i, pci_name(pdev));\n+\t\tif (!udev->ctx[i].name)\n+\t\t\tgoto fail_free_ctx;\n+\t}\n+\n+\t/* register uio driver */\n+\terr = uio_register_device(&pdev->dev, &udev->info);\n+\tif (err != 0)\n+\t\tgoto fail_free_ctx;\n+\n+\tpci_set_drvdata(pdev, udev);\n+\treturn 0;\n+\n+fail_free_ctx:\n+\tfor (i = 0; i < udev->max_vectors; i++)\n+\t\tkfree(udev->ctx[i].name);\n+\tkfree(udev->ctx);\n+fail_free_msix:\n+\tkfree(udev->msix);\n+fail_release_iomem:\n+\trelease_iomaps(udev->info.mem);\n+\tpci_release_regions(pdev);\n+fail_disable:\n+\tpci_disable_device(pdev);\n+fail_free:\n+\tkfree(udev);\n+\n+\tpr_notice(\"%s ret %d\\n\", __func__, err);\n+\treturn err;\n+}\n+\n+static void uio_msi_remove(struct pci_dev *pdev)\n+{\n+\tstruct uio_info *info = pci_get_drvdata(pdev);\n+\tstruct uio_msi_pci_dev *udev\n+\t\t= container_of(info, struct uio_msi_pci_dev, info);\n+\tint i;\n+\n+\tuio_unregister_device(info);\n+\trelease_iomaps(info->mem);\n+\n+\tpci_release_regions(pdev);\n+\tfor (i = 0; i < udev->max_vectors; i++)\n+\t\tkfree(udev->ctx[i].name);\n+\tkfree(udev->ctx);\n+\tkfree(udev->msix);\n+\tpci_disable_device(pdev);\n+\n+\tpci_set_drvdata(pdev, NULL);\n+\tkfree(udev);\n+}\n+\n+static struct pci_driver uio_msi_pci_driver = {\n+\t.name = \"uio_msi\",\n+\t.probe = uio_msi_probe,\n+\t.remove = uio_msi_remove,\n+};\n+\n+module_pci_driver(uio_msi_pci_driver);\n+MODULE_VERSION(DRIVER_VERSION);\n+MODULE_LICENSE(\"GPL v2\");\n+MODULE_AUTHOR(\"Stephen Hemminger <stephen@networkplumber.org>\");\n+MODULE_DESCRIPTION(\"UIO driver for MSI PCI devices\");\ndiff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild\nindex f7b2db4..d9497691 100644\n--- a/include/uapi/linux/Kbuild\n+++ b/include/uapi/linux/Kbuild\n@@ -411,6 +411,7 @@ header-y += udp.h\n header-y += uhid.h\n header-y += uinput.h\n header-y += uio.h\n+header-y += uio_msi.h\n header-y += ultrasound.h\n header-y += un.h\n header-y += unistd.h\ndiff --git a/include/uapi/linux/uio_msi.h b/include/uapi/linux/uio_msi.h\nnew file mode 100644\nindex 0000000..297de00\n--- /dev/null\n+++ b/include/uapi/linux/uio_msi.h\n@@ -0,0 +1,22 @@\n+/*\n+ * UIO_MSI API definition\n+ *\n+ * Copyright (c) 2015 by Brocade Communications Systems, Inc.\n+ * All rights reserved.\n+ *\n+ * This program is free software; you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License version 2 as\n+ * published by the Free Software Foundation.\n+ */\n+#ifndef _UIO_PCI_MSI_H\n+#define _UIO_PCI_MSI_H\n+\n+struct uio_msi_irq_set {\n+\tu32 vec;\n+\tint fd;\n+};\n+\n+#define UIO_MSI_BASE\t0x86\n+#define UIO_MSI_IRQ_SET\t_IOW('I', UIO_MSI_BASE+1, struct uio_msi_irq_set)\n+\n+#endif\n",
    "prefixes": [
        "dpdk-dev",
        "2/2"
    ]
}