Amazon ENA device doesn't implement legacy interrupt which is
required by default UIO. This driver introduces all necessary
memory mappings in order to use ENA device.

Signed-off-by: Evgeny Schemeilin <evgenys at amazon.com>
Signed-off-by: Jan Medala <jan at semihalf.com>
Signed-off-by: Jakub Palider <jpa at semihalf.com>
---
 config/common_linuxapp                           |   5 +
 lib/librte_eal/common/include/rte_pci.h          |   1 +
 lib/librte_eal/common/include/rte_pci_dev_ids.h  |  16 ++
 lib/librte_eal/linuxapp/Makefile                 |   3 +
 lib/librte_eal/linuxapp/eal/eal_pci.c            |   4 +
 lib/librte_eal/linuxapp/ena_uio/Makefile         |  55 +++++
 lib/librte_eal/linuxapp/ena_uio/ena_uio_driver.c | 276 +++++++++++++++++++++++
 7 files changed, 360 insertions(+)
 create mode 100644 lib/librte_eal/linuxapp/ena_uio/Makefile
 create mode 100644 lib/librte_eal/linuxapp/ena_uio/ena_uio_driver.c

diff --git a/config/common_linuxapp b/config/common_linuxapp
index 74bc515..1777c4e 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -249,6 +249,11 @@ CONFIG_RTE_LIBRTE_CXGBE_DEBUG_TX=n
 CONFIG_RTE_LIBRTE_CXGBE_DEBUG_RX=n

 #
+# Compile burst-oriented Amazon ENA PMD driver
+#
+CONFIG_RTE_EAL_ENA_UIO=y
+
+#
 # Compile burst-oriented Cisco ENIC PMD driver
 #
 CONFIG_RTE_LIBRTE_ENIC_PMD=y
diff --git a/lib/librte_eal/common/include/rte_pci.h 
b/lib/librte_eal/common/include/rte_pci.h
index 334c12e..201a5a7 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -149,6 +149,7 @@ enum rte_kernel_driver {
        RTE_KDRV_VFIO,
        RTE_KDRV_UIO_GENERIC,
        RTE_KDRV_NIC_UIO,
+       RTE_KDRV_ENA_UIO,
        RTE_KDRV_NONE,
 };

diff --git a/lib/librte_eal/common/include/rte_pci_dev_ids.h 
b/lib/librte_eal/common/include/rte_pci_dev_ids.h
index d088191..0600e03 100644
--- a/lib/librte_eal/common/include/rte_pci_dev_ids.h
+++ b/lib/librte_eal/common/include/rte_pci_dev_ids.h
@@ -152,6 +152,15 @@
 #define RTE_PCI_DEV_ID_DECL_BNX2XVF(vend, dev)
 #endif

+#ifndef RTE_PCI_DEV_ID_DECL_ENA
+#define RTE_PCI_DEV_ID_DECL_ENA(vend, dev)
+#endif
+
+#ifndef PCI_VENDOR_ID_AMAZON
+/** Vendor ID used by Amazon devices */
+#define PCI_VENDOR_ID_AMAZON 0x1D0F
+#endif
+
 #ifndef PCI_VENDOR_ID_INTEL
 /** Vendor ID used by Intel devices */
 #define PCI_VENDOR_ID_INTEL 0x8086
@@ -598,6 +607,12 @@ RTE_PCI_DEV_ID_DECL_VMXNET3(PCI_VENDOR_ID_VMWARE, 
VMWARE_DEV_ID_VMXNET3)

 RTE_PCI_DEV_ID_DECL_FM10KVF(PCI_VENDOR_ID_INTEL, FM10K_DEV_ID_VF)

+/****************** Amazon devices ******************/
+
+#define PCI_DEVICE_ID_ENA_VF   0xEC20
+
+RTE_PCI_DEV_ID_DECL_ENA(PCI_VENDOR_ID_AMAZON, PCI_DEVICE_ID_ENA_VF)
+
 /****************** Cisco VIC devices ******************/

 #define PCI_DEVICE_ID_CISCO_VIC_ENET         0x0043  /* ethernet vnic */
@@ -656,6 +671,7 @@ RTE_PCI_DEV_ID_DECL_BNX2X(PCI_VENDOR_ID_BROADCOM, 
BNX2X_DEV_ID_57840_MF)
  */
 #undef RTE_PCI_DEV_ID_DECL_BNX2X
 #undef RTE_PCI_DEV_ID_DECL_BNX2XVF
+#undef RTE_PCI_DEV_ID_DECL_ENA
 #undef RTE_PCI_DEV_ID_DECL_EM
 #undef RTE_PCI_DEV_ID_DECL_IGB
 #undef RTE_PCI_DEV_ID_DECL_IGBVF
diff --git a/lib/librte_eal/linuxapp/Makefile b/lib/librte_eal/linuxapp/Makefile
index d9c5233..b293b1c 100644
--- a/lib/librte_eal/linuxapp/Makefile
+++ b/lib/librte_eal/linuxapp/Makefile
@@ -31,6 +31,9 @@

 include $(RTE_SDK)/mk/rte.vars.mk

+ifeq ($(CONFIG_RTE_EAL_ENA_UIO),y)
+DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += ena_uio
+endif
 ifeq ($(CONFIG_RTE_EAL_IGB_UIO),y)
 DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += igb_uio
 endif
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c 
b/lib/librte_eal/linuxapp/eal/eal_pci.c
index bc5b5be..b05a564 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -137,6 +137,7 @@ pci_map_device(struct rte_pci_device *dev)
 #endif
                break;
        case RTE_KDRV_IGB_UIO:
+       case RTE_KDRV_ENA_UIO:
        case RTE_KDRV_UIO_GENERIC:
                /* map resources for devices that use uio */
                ret = pci_uio_map_resource(dev);
@@ -161,6 +162,7 @@ pci_unmap_device(struct rte_pci_device *dev)
                RTE_LOG(ERR, EAL, "Hotplug doesn't support vfio yet\n");
                break;
        case RTE_KDRV_IGB_UIO:
+       case RTE_KDRV_ENA_UIO:
        case RTE_KDRV_UIO_GENERIC:
                /* unmap resources for devices that use uio */
                pci_uio_unmap_resource(dev);
@@ -355,6 +357,8 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t 
bus,
        if (!ret) {
                if (!strcmp(driver, "vfio-pci"))
                        dev->kdrv = RTE_KDRV_VFIO;
+               else if (!strcmp(driver, "ena_uio"))
+                       dev->kdrv = RTE_KDRV_ENA_UIO;
                else if (!strcmp(driver, "igb_uio"))
                        dev->kdrv = RTE_KDRV_IGB_UIO;
                else if (!strcmp(driver, "uio_pci_generic"))
diff --git a/lib/librte_eal/linuxapp/ena_uio/Makefile 
b/lib/librte_eal/linuxapp/ena_uio/Makefile
new file mode 100644
index 0000000..10c4dc6
--- /dev/null
+++ b/lib/librte_eal/linuxapp/ena_uio/Makefile
@@ -0,0 +1,55 @@
+#
+# BSD LICENSE
+#
+# Copyright (c) 2015-2016 Amazon.com, Inc. or its affiliates.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# module name and path
+#
+MODULE = ena_uio
+MODULE_PATH = drivers/net/ena_uio
+
+#
+# CFLAGS
+#
+MODULE_CFLAGS += -I$(SRCDIR) --param max-inline-insns-single=100
+MODULE_CFLAGS += -I$(RTE_OUTPUT)/include
+MODULE_CFLAGS += -Winline -Wall -Werror
+MODULE_CFLAGS += -include $(RTE_OUTPUT)/include/rte_config.h
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-y += ena_uio_driver.c
+
+include $(RTE_SDK)/mk/rte.module.mk
diff --git a/lib/librte_eal/linuxapp/ena_uio/ena_uio_driver.c 
b/lib/librte_eal/linuxapp/ena_uio/ena_uio_driver.c
new file mode 100644
index 0000000..8bf8a9e
--- /dev/null
+++ b/lib/librte_eal/linuxapp/ena_uio/ena_uio_driver.c
@@ -0,0 +1,276 @@
+/*-
+* BSD LICENSE
+*
+* Copyright (c) 2015-2016 Amazon.com, Inc. or its affiliates.
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in
+* the documentation and/or other materials provided with the
+* distribution.
+* * Neither the name of copyright holder nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/uio_driver.h>
+#include <linux/io.h>
+#include <linux/msi.h>
+#include <linux/version.h>
+#include <linux/slab.h>
+
+#include "rte_pci_dev_ids.h"
+
+#define DRV_MODULE_NAME         "ena_uio"
+#define DRV_MODULE_VERSION      "1.0"
+#define DRV_MODULE_RELDATE      "January 14, 2016"
+
+/**
+       Defines from uio_driver.h
+*/
+
+/* defines for uio_info->irq */
+#define UIO_IRQ_CUSTOM  -1
+#define UIO_IRQ_NONE     0
+
+
+/* defines for uio_port->porttype */
+#define UIO_PORT_NONE   0
+#define UIO_PORT_X86    1
+#define UIO_PORT_GPIO   2
+#define UIO_PORT_OTHER  3
+
+/* defines for muio_mem->memtype */
+#define UIO_MEM_NONE           0
+#define UIO_MEM_PHYS           1
+#define UIO_MEM_LOGICAL        2
+#define UIO_MEM_VIRTUAL        3
+#define UIO_MEM_PHYS_CACHEABLE 4
+#define UIO_MEM_PHYS_WC        5
+
+#define UIO_MMAP_PHYSICAL_CACHE 0x1
+#define UIO_MMAP_PHYSICAL_WC    0x2
+
+
+MODULE_AUTHOR("Alex Matushevsky <alex at annapurnaLabs.com>");
+MODULE_DESCRIPTION("UIO driver for Amazon ENA PCI cards");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+
+/* PCI BARs */
+#define ENA_REG_BAR            0
+
+
+typedef enum {
+       ENA = 0
+} board_t;
+
+static DEFINE_PCI_DEVICE_TABLE(ena_uio_pci_tbl) = {
+       { PCI_VENDOR_ID_AMAZON, PCI_DEVICE_ID_ENA_VF,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, ENA},
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, ena_uio_pci_tbl);
+
+
+/**
+ * A structure describing the private information for a uio device.
+ */
+struct rte_uio_pci_dev {
+       struct uio_info info;
+       struct pci_dev *pdev;
+       spinlock_t lock; /* spinlock for accessing PCI config space or msix 
data in multi tasks/isr */
+};
+
+
+static int
+ena_uio_pci_irqcontrol(struct uio_info *info, s32 irq_state)
+{
+       return -1;
+}
+
+static irqreturn_t
+ena_uio_pci_irqhandler(int irq, struct uio_info *info)
+{
+       return IRQ_NONE;
+}
+
+static int
+ena_uio_pci_setup_iomem(struct pci_dev *dev, struct uio_info *info,
+                      int n, int pci_bar, const char *name)
+{
+       unsigned long addr, len;
+       void *internal_addr;
+
+       addr = pci_resource_start(dev, pci_bar);
+       len = pci_resource_len(dev, pci_bar);
+
+       printk(KERN_INFO "addr len %lu f %lu\n", addr, len);
+       if (addr == 0 || len == 0)
+               return -1;
+
+       internal_addr = ioremap(addr, len);
+
+       printk(KERN_INFO "internal addr %p for %d len %lu \n", internal_addr, 
n, len);
+       if (internal_addr == NULL) {
+
+               return -1;
+       }
+       info->mem[n].name = name;
+       info->mem[n].addr = addr;
+       info->mem[n].internal_addr = internal_addr;
+       info->mem[n].size = len;
+       info->mem[n].memtype = UIO_MEM_PHYS;
+
+       return 0;
+}
+
+/* Unmap previously ioremap'd resources */
+static void
+ena_uio_pci_release_iomem(struct uio_info *info)
+{
+       int i;
+       for (i = 0; i < MAX_UIO_MAPS; i++) {
+               if (info->mem[i].internal_addr)
+                       iounmap(info->mem[i].internal_addr);
+       }
+}
+
+static int
+ena_uio_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       struct rte_uio_pci_dev *udev;
+
+       udev = kzalloc(sizeof(struct rte_uio_pci_dev), GFP_KERNEL);
+       if (!udev)
+               return -ENOMEM;
+
+       /*
+        * enable device: ask low-level code to enable I/O and
+        * memory
+        */
+       if (pci_enable_device(dev)) {
+               printk(KERN_ERR "Cannot enable PCI device\n");
+               goto fail_free;
+       }
+
+       if (pci_set_dma_mask(dev, DMA_BIT_MASK(40))) {
+               printk(KERN_ERR "Cannot set DMA mask\n");
+               goto fail_disable;
+       }
+
+       if (pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(40))) {
+               printk(KERN_ERR "Cannot set DMA mask\n");
+               goto fail_disable;
+       }
+
+       /*
+        * reserve device's PCI memory regions for use by this
+        * module
+        */
+       if (pci_request_regions(dev, "ena_uio")) {
+               printk(KERN_ERR "Cannot request regions\n");
+               goto fail_disable;
+       }
+
+       /* enable bus mastering on the device */
+       pci_set_master(dev);
+
+       /* remap IO memory */
+       if (ena_uio_pci_setup_iomem(dev, &udev->info, 0, ENA_REG_BAR, "bar0"))
+               goto fail_release_iomem;
+
+       /* fill uio infos */
+       udev->info.name = "ENA UIO";
+       udev->info.version = "1.0";
+       udev->info.handler = ena_uio_pci_irqhandler;
+       udev->info.irqcontrol = ena_uio_pci_irqcontrol;
+       udev->info.priv = udev;
+       udev->pdev = dev;
+       spin_lock_init(&udev->lock);
+
+       /* irq is not supported */
+       udev->info.irq_flags = 0;
+       udev->info.irq = -1;
+
+       pci_set_drvdata(dev, udev);
+
+       /* register uio driver */
+       if (uio_register_device(&dev->dev, &udev->info))
+               goto fail_release_iomem;
+
+       return 0;
+
+fail_release_iomem:
+       ena_uio_pci_release_iomem(&udev->info);
+
+       pci_release_regions(dev);
+fail_disable:
+       pci_disable_device(dev);
+fail_free:
+       kfree(udev);
+
+       return -ENODEV;
+}
+
+
+static void
+ena_uio_pci_remove(struct pci_dev *dev)
+{
+       struct uio_info *info = pci_get_drvdata(dev);
+
+       if (info->priv == NULL) {
+               return;
+       }
+
+       uio_unregister_device(info);
+       ena_uio_pci_release_iomem(info);
+
+       pci_release_regions(dev);
+       pci_disable_device(dev);
+       pci_set_drvdata(dev, NULL);
+       kfree(info);
+}
+
+static struct pci_driver ena_uio_pci_driver = {
+        .name           = DRV_MODULE_NAME,
+        .id_table       = ena_uio_pci_tbl,
+        .probe          = ena_uio_pci_probe,
+        .remove         = ena_uio_pci_remove,
+};
+
+static int __init ena_uio_init(void)
+{
+       return pci_register_driver(&ena_uio_pci_driver);
+}
+
+static void __exit ena_uio_cleanup(void)
+{
+       pci_unregister_driver(&ena_uio_pci_driver);
+}
+
+module_init(ena_uio_init);
+module_exit(ena_uio_cleanup);
-- 
1.9.1

Reply via email to