[dpdk-dev,v3,2/4] nfp-uio: new uio driver for netronome nfp6000 card

Message ID 1444992324-5504-3-git-send-email-alejandro.lucero@netronome.com (mailing list archive)
State Superseded, archived
Headers

Commit Message

Alejandro Lucero Oct. 16, 2015, 10:45 a.m. UTC
  From: "Alejandro.Lucero" <alejandro.lucero@netronome.com>

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 <alejandro.lucero@netronome.com>
Signed-off-by: Rolf.Neugebauer <rolf.neugebauer@netronome.com>
---
 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
  

Comments

David Marchand Oct. 21, 2015, 5:24 a.m. UTC | #1
Hello Alejandro,

On Fri, Oct 16, 2015 at 12:45 PM, Alejandro.Lucero <
alejandro.lucero@netronome.com> wrote:

> From: "Alejandro.Lucero" <alejandro.lucero@netronome.com>
>
> 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 <alejandro.lucero@netronome.com>
> Signed-off-by: Rolf.Neugebauer <rolf.neugebauer@netronome.com>
>

Please, can you elaborate on the need for (yet another) uio driver, rather
than make igb_uio work with your hardware ?

Thanks.
  
Alejandro Lucero Oct. 21, 2015, 2:39 p.m. UTC | #2
Hi David,

On Wed, Oct 21, 2015 at 6:24 AM, David Marchand <david.marchand@6wind.com>
wrote:

> Hello Alejandro,
>
> On Fri, Oct 16, 2015 at 12:45 PM, Alejandro.Lucero <
> alejandro.lucero@netronome.com> wrote:
>
>> From: "Alejandro.Lucero" <alejandro.lucero@netronome.com>
>>
>> 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 <alejandro.lucero@netronome.com>
>> Signed-off-by: Rolf.Neugebauer <rolf.neugebauer@netronome.com>
>>
>
> Please, can you elaborate on the need for (yet another) uio driver, rather
> than make igb_uio work with your hardware ?
>
>
We have two different needs not covered by igb_uio:

  - pci mask needs to be 40 bits instead of 64
  - some old kernel have buggy IOMMU with devices with pci masks as those
40 bits. This can be fixed just using kernel DMA API for a harmless dma
memory allocation. We have such a allocation along with the release in our
nfp_uio driver.

I thought to modify igb_uio adding a kernel param for setting another pci
mask than igb default one, but this is to leave to the user the right
initialisation.

But there is another more important reason for having a different driver:
future PF support. Our device is programmable with processing units and
functional units being configured by firmware code. Every part of the chip
is addressable from the host which is possible through a BSP kernel driver.
Device PCI BARs are not the same than network device (PF or VF) PCI BARs:
the latter is a subregion of the former. VFs subregions are easy to get
thanks to SRIOV. But in order to get the right subregions sizes and
addresses for the PF, special firmware symbols are needed. User space
programs can use the BSP through specific libraries but that requires
support from the BSP, or from another driver doing the same. So nfp_uio
will likely add that support.

I have been looking at the possibility of getting rid of nfp_uio. The fact
is our PMD can work without it, both for the PF and VF (not the PMD version
already submitted but one under development).  The PF support requires not
using UIO at all, because the device is attached to the BSP driver. The
only problem with this approach is we do not have support for interrupts,
what is not critical (I can see other PMDs not having support for Link
Status Changes) but we do not like it as programs can register callbacks
for these interrupts which would not work at all.

Interrupt support could be implemented in the BSP, doing the same UIO or
VFIO do, but this will require (minor) changes to DPDK for having another
intr_handle (not UIO, not VFIO). I do not know if other PMDs could also
make use of such a change but I guess that would help to accept those
changes.

Therefore, the easiest thing to do is to implement the PF support in the
nfp_uio by now.

I hope this explanation can help to justify nfp_uio.

Thanks


> Thanks.
>
> --
> David Marchand
>
  
Thomas Monjalon Oct. 21, 2015, 3:25 p.m. UTC | #3
2015-10-21 15:39, Alejandro Lucero:
> On Wed, Oct 21, 2015 at 6:24 AM, David Marchand <david.marchand@6wind.com>
> wrote:
> > Please, can you elaborate on the need for (yet another) uio driver, rather
> > than make igb_uio work with your hardware ?
[...]
> I have been looking at the possibility of getting rid of nfp_uio. The fact
> is our PMD can work without it, both for the PF and VF (not the PMD version
> already submitted but one under development).  The PF support requires not
> using UIO at all, because the device is attached to the BSP driver. The
> only problem with this approach is we do not have support for interrupts,
> what is not critical (I can see other PMDs not having support for Link
> Status Changes) but we do not like it as programs can register callbacks
> for these interrupts which would not work at all.
> 
> Interrupt support could be implemented in the BSP, doing the same UIO or
> VFIO do, but this will require (minor) changes to DPDK for having another
> intr_handle (not UIO, not VFIO). I do not know if other PMDs could also
> make use of such a change but I guess that would help to accept those
> changes.

We are going to have an external handler (used for mlx5):
	http://dpdk.org/ml/archives/dev/2015-October/024678.html
Problem solved :)

Is it possible to rework your PMD without nfp-uio?

Thanks
  
Alejandro Lucero Oct. 21, 2015, 3:57 p.m. UTC | #4
Wow!

This is just what we (likely) need.

We could have that support in our BSP but this is something yet to be
approved. Setting  per VF pci bus master and pci mask should also be added
to BSP.

Current PMD submitted would need nfp_uio by now for LSC interrupt support.
As I said, this is not critical so NFP devices could be used with that
limitation. My concern is tests without using nfp_uio have not been done,
just some minor work for proof of concept.

I understand interest for not having another UIO driver does exist. We
could maintain an external nfp_uio by now till either we get rid of it or
we definitely find out it is really needed. any chance to accept nfp_uio by
now?

Thanks

On Wed, Oct 21, 2015 at 4:25 PM, Thomas Monjalon <thomas.monjalon@6wind.com>
wrote:

> 2015-10-21 15:39, Alejandro Lucero:
> > On Wed, Oct 21, 2015 at 6:24 AM, David Marchand <
> david.marchand@6wind.com>
> > wrote:
> > > Please, can you elaborate on the need for (yet another) uio driver,
> rather
> > > than make igb_uio work with your hardware ?
> [...]
> > I have been looking at the possibility of getting rid of nfp_uio. The
> fact
> > is our PMD can work without it, both for the PF and VF (not the PMD
> version
> > already submitted but one under development).  The PF support requires
> not
> > using UIO at all, because the device is attached to the BSP driver. The
> > only problem with this approach is we do not have support for interrupts,
> > what is not critical (I can see other PMDs not having support for Link
> > Status Changes) but we do not like it as programs can register callbacks
> > for these interrupts which would not work at all.
> >
> > Interrupt support could be implemented in the BSP, doing the same UIO or
> > VFIO do, but this will require (minor) changes to DPDK for having another
> > intr_handle (not UIO, not VFIO). I do not know if other PMDs could also
> > make use of such a change but I guess that would help to accept those
> > changes.
>
> We are going to have an external handler (used for mlx5):
>         http://dpdk.org/ml/archives/dev/2015-October/024678.html
> Problem solved :)
>
> Is it possible to rework your PMD without nfp-uio?
>
> Thanks
>
  
Thomas Monjalon Oct. 21, 2015, 4:03 p.m. UTC | #5
2015-10-21 16:57, Alejandro Lucero:
> I understand interest for not having another UIO driver does exist. We
> could maintain an external nfp_uio by now till either we get rid of it or
> we definitely find out it is really needed. any chance to accept nfp_uio by
> now?

No, there are some work currently to get rid of igb_uio.
So there are little chances to accept nfp_uio one day.
Please take the first step of integrating your PMD without link interrupt.
Later we'll be able to discuss how to mitigate the interrupt issue.
  
Alejandro Lucero Oct. 21, 2015, 7:40 p.m. UTC | #6
On Wed, Oct 21, 2015 at 5:03 PM, Thomas Monjalon <thomas.monjalon@6wind.com>
wrote:

> 2015-10-21 16:57, Alejandro Lucero:
> > I understand interest for not having another UIO driver does exist. We
> > could maintain an external nfp_uio by now till either we get rid of it or
> > we definitely find out it is really needed. any chance to accept nfp_uio
> by
> > now?
>
> No, there are some work currently to get rid of igb_uio.
> So there are little chances to accept nfp_uio one day.
> Please take the first step of integrating your PMD without link interrupt.
> Later we'll be able to discuss how to mitigate the interrupt issue.
>

Ok. I will create a new patchset version without nfp_uio.

By the way, that work with igb_uio is about the patches to pci_uio_generic?
I thought there was some reticence from the maintainer for adding pci bus
master there.
  
Alejandro Lucero Oct. 22, 2015, 11:46 a.m. UTC | #7
Submitting just the PMD for integration makes sense. I will remove all the
references to nfp_uio.

My doubt is with documentation. Working with the NFP PMD will not be
possible without nfp_uio. We could modify the documentation saying it is
possible to use igb_uio, but this is not the right thing to do (pci mask
will be wrong). So, would it be acceptable to submit a new PMD without any
documentation by now? I prefer this for the sake of integration than giving
wrong or incomplete documentation.

Thanks

On Wed, Oct 21, 2015 at 8:40 PM, Alejandro Lucero <
alejandro.lucero@netronome.com> wrote:

>
>
> On Wed, Oct 21, 2015 at 5:03 PM, Thomas Monjalon <
> thomas.monjalon@6wind.com> wrote:
>
>> 2015-10-21 16:57, Alejandro Lucero:
>> > I understand interest for not having another UIO driver does exist. We
>> > could maintain an external nfp_uio by now till either we get rid of it
>> or
>> > we definitely find out it is really needed. any chance to accept
>> nfp_uio by
>> > now?
>>
>> No, there are some work currently to get rid of igb_uio.
>> So there are little chances to accept nfp_uio one day.
>> Please take the first step of integrating your PMD without link interrupt.
>> Later we'll be able to discuss how to mitigate the interrupt issue.
>>
>
> Ok. I will create a new patchset version without nfp_uio.
>
> By the way, that work with igb_uio is about the patches to
> pci_uio_generic? I thought there was some reticence from the maintainer for
> adding pci bus master there.
>
>
>
  

Patch

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 <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>
+
+#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 <support@netronome.com>");
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;