From patchwork Fri Oct 16 10:45:22 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alejandro Lucero X-Patchwork-Id: 7701 Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id 5A8368E59; Fri, 16 Oct 2015 12:45:18 +0200 (CEST) Received: from ubuntu (host217-39-174-19.in-addr.btopenworld.com [217.39.174.19]) by dpdk.org (Postfix) with SMTP id 06D04592B for ; Fri, 16 Oct 2015 12:45:11 +0200 (CEST) Received: by ubuntu (Postfix, from userid 5466) id 9D622EA76C; Fri, 16 Oct 2015 11:45:24 +0100 (BST) From: "Alejandro.Lucero" To: dev@dpdk.org Date: Fri, 16 Oct 2015 11:45:22 +0100 Message-Id: <1444992324-5504-3-git-send-email-alejandro.lucero@netronome.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1444992324-5504-1-git-send-email-alejandro.lucero@netronome.com> References: <1444992324-5504-1-git-send-email-alejandro.lucero@netronome.com> Subject: [dpdk-dev] [PATCH v3 2/4] nfp-uio: new uio driver for netronome nfp6000 card X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: "Alejandro.Lucero" This patch adds a new UIO kernel driver for supporting PCI VFs with Netronome nfp6000 card. Future PCI PF support will be based on changes to this module. Signed-off-by: Alejandro.Lucero Signed-off-by: Rolf.Neugebauer --- lib/librte_eal/common/include/rte_pci.h | 1 + lib/librte_eal/linuxapp/Makefile | 3 + lib/librte_eal/linuxapp/eal/eal_pci.c | 4 + lib/librte_eal/linuxapp/eal/eal_pci_uio.c | 2 +- lib/librte_eal/linuxapp/nfp_uio/Makefile | 53 +++ lib/librte_eal/linuxapp/nfp_uio/nfp_uio.c | 497 +++++++++++++++++++++++++++++ lib/librte_ether/rte_ethdev.c | 1 + 7 files changed, 560 insertions(+), 1 deletion(-) create mode 100644 lib/librte_eal/linuxapp/nfp_uio/Makefile create mode 100644 lib/librte_eal/linuxapp/nfp_uio/nfp_uio.c diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h index 83e3c28..89baaf6 100644 --- a/lib/librte_eal/common/include/rte_pci.h +++ b/lib/librte_eal/common/include/rte_pci.h @@ -146,6 +146,7 @@ struct rte_devargs; enum rte_kernel_driver { RTE_KDRV_UNKNOWN = 0, RTE_KDRV_IGB_UIO, + RTE_KDRV_NFP_UIO, RTE_KDRV_VFIO, RTE_KDRV_UIO_GENERIC, RTE_KDRV_NIC_UIO, diff --git a/lib/librte_eal/linuxapp/Makefile b/lib/librte_eal/linuxapp/Makefile index d9c5233..f36dc4b 100644 --- a/lib/librte_eal/linuxapp/Makefile +++ b/lib/librte_eal/linuxapp/Makefile @@ -34,6 +34,9 @@ include $(RTE_SDK)/mk/rte.vars.mk ifeq ($(CONFIG_RTE_EAL_IGB_UIO),y) DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += igb_uio endif +ifeq ($(CONFIG_RTE_EAL_NFP_UIO),y) +DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += nfp_uio +endif DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal ifeq ($(CONFIG_RTE_KNI_KMOD),y) DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += kni diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c index bc5b5be..19a93fe 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_NFP_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_NFP_UIO: case RTE_KDRV_UIO_GENERIC: /* unmap resources for devices that use uio */ pci_uio_unmap_resource(dev); @@ -357,6 +359,8 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus, dev->kdrv = RTE_KDRV_VFIO; else if (!strcmp(driver, "igb_uio")) dev->kdrv = RTE_KDRV_IGB_UIO; + else if (!strcmp(driver, "nfp_uio")) + dev->kdrv = RTE_KDRV_NFP_UIO; else if (!strcmp(driver, "uio_pci_generic")) dev->kdrv = RTE_KDRV_UIO_GENERIC; else diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c index ac50e13..29ec9cb 100644 --- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c +++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c @@ -270,7 +270,7 @@ pci_uio_alloc_resource(struct rte_pci_device *dev, goto error; } - if (dev->kdrv == RTE_KDRV_IGB_UIO) + if (dev->kdrv == RTE_KDRV_IGB_UIO || dev->kdrv == RTE_KDRV_NFP_UIO) dev->intr_handle.type = RTE_INTR_HANDLE_UIO; else { dev->intr_handle.type = RTE_INTR_HANDLE_UIO_INTX; diff --git a/lib/librte_eal/linuxapp/nfp_uio/Makefile b/lib/librte_eal/linuxapp/nfp_uio/Makefile new file mode 100644 index 0000000..b9e2f0a --- /dev/null +++ b/lib/librte_eal/linuxapp/nfp_uio/Makefile @@ -0,0 +1,53 @@ +# BSD LICENSE +# +# Copyright(c) 2014-2015 Netronome. All rights reserved. +# 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 Intel Corporation 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 = nfp_uio +MODULE_PATH = drivers/net/nfp_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 := nfp_uio.c + +include $(RTE_SDK)/mk/rte.module.mk diff --git a/lib/librte_eal/linuxapp/nfp_uio/nfp_uio.c b/lib/librte_eal/linuxapp/nfp_uio/nfp_uio.c new file mode 100644 index 0000000..98192a5 --- /dev/null +++ b/lib/librte_eal/linuxapp/nfp_uio/nfp_uio.c @@ -0,0 +1,497 @@ +/* + * Copyright (c) 2014, 2015 Netronome Systems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. 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 + * + * 3. Neither the name of the 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 HOLDER 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. + */ + +/* + * Netronome DPDK uio kernel module + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef PCI_MSIX_ENTRY_SIZE +#define PCI_MSIX_ENTRY_SIZE 16 +#define PCI_MSIX_ENTRY_LOWER_ADDR 0 +#define PCI_MSIX_ENTRY_UPPER_ADDR 4 +#define PCI_MSIX_ENTRY_DATA 8 +#define PCI_MSIX_ENTRY_VECTOR_CTRL 12 +#define PCI_MSIX_ENTRY_CTRL_MASKBIT 1 +#endif + +/* Ideally we should support two types of interrupts: + * + * - Link Status Change Interrupt + * - Exception Interrupt + * + * But the uio Linux kernel interface just admits one interrupt per uio device. + */ +#define NFP_NUM_MSI_VECTORS 1 + +/* + * A structure describing the private information for a uio device. + */ +struct nfp_uio_pci_dev { + struct uio_info info; + struct pci_dev *pdev; + /* spinlock for accessing PCI config space or msix + * data in multi tasks/isr + */ + spinlock_t lock; + + /* pointer to the msix vectors to be allocated later */ + struct msix_entry msix_entries[NFP_NUM_MSI_VECTORS]; +}; + +#define PCI_VENDOR_ID_NETRONOME 0x19ee +#define PCI_DEVICE_NFP6000_VF_NIC 0x6003 + +#define RTE_PCI_DEV_ID_DECL_NETRO(vend, dev) {PCI_DEVICE(vend, dev)}, + +/* PCI device id table */ +static struct pci_device_id nfp_uio_pci_ids[] = { +RTE_PCI_DEV_ID_DECL_NETRO(PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_NFP6000_VF_NIC) +{ 0, }, +}; + +MODULE_DEVICE_TABLE(pci, nfp_uio_pci_ids); + +static inline struct nfp_uio_pci_dev * +nfp_uio_get_uio_pci_dev(struct uio_info *info) +{ + return container_of(info, struct nfp_uio_pci_dev, info); +} + +static inline int +pci_lock(struct pci_dev *pdev) +{ + /* Some function names changes between 3.2.0 and 3.3.0... */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) + pci_block_user_cfg_access(pdev); + return 1; +#else + return pci_cfg_access_trylock(pdev); +#endif +} + +static inline void +pci_unlock(struct pci_dev *pdev) +{ + /* Some function names changes between 3.2.0 and 3.3.0... */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) + pci_unblock_user_cfg_access(pdev); +#else + pci_cfg_access_unlock(pdev); +#endif +} + +/* + * It masks the msix on/off of generating MSI-X messages. + */ +static int +nfp_uio_msix_mask_irq(struct msi_desc *desc, int32_t state) +{ + u32 mask_bits = desc->masked; + unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_VECTOR_CTRL; + + if (state != 0) + mask_bits &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT; + else + mask_bits |= PCI_MSIX_ENTRY_CTRL_MASKBIT; + + if (mask_bits != desc->masked) { + writel(mask_bits, desc->mask_base + offset); + readl(desc->mask_base); + desc->masked = mask_bits; + } + + return 0; +} + +/** + * This function sets/clears the masks for generating LSC interrupts. + * + * @param info + * The pointer to struct uio_info. + * @param on + * The on/off flag of masking LSC. + * @return + * -On success, zero value. + * -On failure, a negative value. + */ +static int +nfp_uio_set_interrupt_mask(struct nfp_uio_pci_dev *udev, int32_t state) +{ + struct pci_dev *pdev = udev->pdev; + struct msi_desc *desc; + + /* TODO: Should we change this based on if the firmware advertises + NFP_NET_CFG_CTRL_MSIXAUTO? */ + + list_for_each_entry(desc, &pdev->msi_list, list) { + nfp_uio_msix_mask_irq(desc, state); + } + return 0; +} + +/** + * This is the irqcontrol callback to be registered to uio_info. + * It can be used to disable/enable interrupt from user space processes. + * + * @param info + * pointer to uio_info. + * @param irq_state + * state value. 1 to enable interrupt, 0 to disable interrupt. + * + * @return + * - On success, 0. + * - On failure, a negative value. + */ +static int +nfp_uio_pci_irqcontrol(struct uio_info *info, s32 irq_state) +{ + unsigned long flags; + struct nfp_uio_pci_dev *udev = nfp_uio_get_uio_pci_dev(info); + struct pci_dev *pdev = udev->pdev; + + spin_lock_irqsave(&udev->lock, flags); + if (!pci_lock(pdev)) { + spin_unlock_irqrestore(&udev->lock, flags); + return -1; + } + + nfp_uio_set_interrupt_mask(udev, irq_state); + + pci_unlock(pdev); + spin_unlock_irqrestore(&udev->lock, flags); + + return 0; +} + +/** + * This is interrupt handler which will check if the interrupt is for the right + device. If yes, disable it here and will be enable later. + */ +static irqreturn_t +nfp_uio_pci_irqhandler(int irq, struct uio_info *info) +{ + irqreturn_t ret = IRQ_NONE; + unsigned long flags; + struct nfp_uio_pci_dev *udev = nfp_uio_get_uio_pci_dev(info); + struct pci_dev *pdev = udev->pdev; + + spin_lock_irqsave(&udev->lock, flags); + /* block userspace PCI config reads/writes */ + if (!pci_lock(pdev)) + goto spin_unlock; + + ret = IRQ_HANDLED; + + /* unblock userspace PCI config reads/writes */ + pci_unlock(pdev); +spin_unlock: + spin_unlock_irqrestore(&udev->lock, flags); + dev_info(&pdev->dev, "irq 0x%x %s\n", irq, + (ret == IRQ_HANDLED) ? "handled" : "not handled"); + + return ret; +} + +/* Remap pci resources described by bar #pci_bar in uio resource n. */ +static int +nfp_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; + + if (ARRAY_SIZE(info->mem) <= n) + return -EINVAL; + + addr = pci_resource_start(dev, pci_bar); + len = pci_resource_len(dev, pci_bar); + if (addr == 0 || len == 0) + return -1; + internal_addr = ioremap(addr, len); + if (!internal_addr) + 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; +} + +/* Get pci port io resources described by bar #pci_bar in uio resource n. */ +static int +nfp_uio_pci_setup_ioport(struct pci_dev *dev, struct uio_info *info, + int n, int pci_bar, const char *name) +{ + unsigned long addr, len; + + if (ARRAY_SIZE(info->port) <= n) + return -EINVAL; + + addr = pci_resource_start(dev, pci_bar); + len = pci_resource_len(dev, pci_bar); + if (addr == 0 || len == 0) + return -1; + + info->port[n].name = name; + info->port[n].start = addr; + info->port[n].size = len; + info->port[n].porttype = UIO_PORT_X86; + + return 0; +} + +/* Unmap previously ioremap'd resources */ +static void +nfp_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 +nfp_uio_setup_bars(struct pci_dev *dev, struct uio_info *info) +{ + int i, iom, iop, ret; + unsigned long flags; + static const char *bar_names[PCI_STD_RESOURCE_END + 1] = { + "BAR0", + "BAR1", + "BAR2", + "BAR3", + "BAR4", + "BAR5", + }; + + iom = 0; + iop = 0; + + for (i = 0; i != ARRAY_SIZE(bar_names); i++) { + if (pci_resource_len(dev, i) == 0 || + pci_resource_start(dev, i) == 0) + continue; + + flags = pci_resource_flags(dev, i); + if (flags & IORESOURCE_MEM) { + ret = nfp_uio_pci_setup_iomem(dev, info, iom, i, + bar_names[i]); + if (ret != 0) + return ret; + iom++; + } else if (flags & IORESOURCE_IO) { + ret = nfp_uio_pci_setup_ioport(dev, info, iop, i, + bar_names[i]); + if (ret != 0) + return ret; + iop++; + } + } + + return (iom != 0) ? ret : -ENOENT; +} + +/* Configuring interrupt. First try MSI-X, then MSI. */ +static void +init_interrupt(struct nfp_uio_pci_dev *udev) +{ + int vector; + + for (vector = 0; vector < NFP_NUM_MSI_VECTORS; vector++) + udev->msix_entries[vector].entry = vector; + + if (pci_enable_msix(udev->pdev, udev->msix_entries, + NFP_NUM_MSI_VECTORS) == 0) { + udev->info.irq_flags = 0; + udev->info.irq = udev->msix_entries[0].vector; + dev_info(&udev->pdev->dev, "%s configured with MSI-X\n", + udev->info.name); + } else + dev_info(&udev->pdev->dev, "%s MSI-X initialization error\n", + udev->info.name); +} + +static int +nfp_uio_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct nfp_uio_pci_dev *udev; + void *map_addr; + dma_addr_t map_dma_addr; + + udev = kzalloc(sizeof(*udev), GFP_KERNEL); + if (!udev) + return -ENOMEM; + + /* + * enable device: ask low-level code to enable I/O and + * memory + */ + if (pci_enable_device(dev)) { + dev_err(&dev->dev, "Cannot enable PCI device\n"); + goto fail_free; + } + + /* + * reserve device's PCI memory regions for use by this + * module + */ + if (pci_request_regions(dev, "nfp_uio")) { + dev_err(&dev->dev, "Cannot request regions\n"); + goto fail_disable; + } + + /* enable bus mastering on the device */ + pci_set_master(dev); + + /* remap IO memory */ + if (nfp_uio_setup_bars(dev, &udev->info)) + goto fail_release_iomem; + + /* set 40-bit DMA mask */ + if (pci_set_dma_mask(dev, DMA_BIT_MASK(40))) { + dev_err(&dev->dev, "Cannot set DMA mask\n"); + goto fail_release_iomem; + } else if (pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(40))) { + dev_err(&dev->dev, "Cannot set consistent DMA mask\n"); + goto fail_release_iomem; + } + + /* fill uio infos */ + udev->info.name = "Netronome NFP UIO"; + udev->info.version = "0.1"; + udev->info.handler = nfp_uio_pci_irqhandler; + udev->info.irqcontrol = nfp_uio_pci_irqcontrol; + udev->info.priv = udev; + udev->pdev = dev; + spin_lock_init(&udev->lock); + + init_interrupt(udev); + + pci_set_drvdata(dev, &udev->info); + nfp_uio_pci_irqcontrol(&udev->info, 0); + + /* register uio driver */ + if (uio_register_device(&dev->dev, &udev->info)) + goto fail_release_iomem; + + dev_info(&dev->dev, "uio device registered with irq %lx\n", + udev->info.irq); + + /* When binding drivers to devices, some old kernels do not + * link devices to iommu identity mapping if iommu=pt is used. + * + * This is not a problem if the driver does later some call to + * the DMA API because the mapping can be done then. But DPDK + * apps do not use that DMA API at all. + * + * Doing a harmless dma mapping for attaching the device to + * the iommu identity mapping + */ + + map_addr = dma_zalloc_coherent(&dev->dev, 1024, + &map_dma_addr, GFP_KERNEL); + + pr_info("nfp_uio: mapping 1K dma=%#llx host=%p\n", + (unsigned long long)map_dma_addr, map_addr); + + dma_free_coherent(&dev->dev, 1024, map_addr, map_dma_addr); + + pr_info("nfp_uio: unmapping 1K dma=%#llx host=%p\n", + (unsigned long long)map_dma_addr, map_addr); + + return 0; + +fail_release_iomem: + nfp_uio_pci_release_iomem(&udev->info); + pci_disable_msix(udev->pdev); + pci_release_regions(dev); +fail_disable: + pci_disable_device(dev); +fail_free: + kfree(udev); + + return -ENODEV; +} + +static void +nfp_uio_pci_remove(struct pci_dev *dev) +{ + struct uio_info *info = pci_get_drvdata(dev); + + BUG_ON(!info); + BUG_ON(!info->priv); + + uio_unregister_device(info); + nfp_uio_pci_release_iomem(info); + pci_disable_msix(dev); + pci_release_regions(dev); + pci_disable_device(dev); + pci_set_drvdata(dev, NULL); + kfree(info); +} + +static struct pci_driver nfp_uio_pci_driver = { + .name = "nfp_uio", + .id_table = nfp_uio_pci_ids, + .probe = nfp_uio_pci_probe, + .remove = nfp_uio_pci_remove, +}; + +static int __init +nfp_uio_pci_init_module(void) +{ + return pci_register_driver(&nfp_uio_pci_driver); +} + +static void __exit +nfp_uio_pci_exit_module(void) +{ + pci_unregister_driver(&nfp_uio_pci_driver); +} + +module_init(nfp_uio_pci_init_module); +module_exit(nfp_uio_pci_exit_module); + +MODULE_DESCRIPTION("UIO driver for Netronome NFP PCI cards"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Netronome Systems "); diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c index f593f6e..a84bc63 100644 --- a/lib/librte_ether/rte_ethdev.c +++ b/lib/librte_ether/rte_ethdev.c @@ -513,6 +513,7 @@ rte_eth_dev_is_detachable(uint8_t port_id) if (rte_eth_devices[port_id].dev_type == RTE_ETH_DEV_PCI) { switch (rte_eth_devices[port_id].pci_dev->kdrv) { case RTE_KDRV_IGB_UIO: + case RTE_KDRV_NFP_UIO: case RTE_KDRV_UIO_GENERIC: case RTE_KDRV_NIC_UIO: break;