DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH] net/nfb: new Netcope driver
@ 2019-02-26 12:57 Rastislav Cernay
  2019-02-26 12:57 ` [dpdk-dev] [PATCH] net/nfb: new netcope driver Rastislav Cernay
  0 siblings, 1 reply; 50+ messages in thread
From: Rastislav Cernay @ 2019-02-26 12:57 UTC (permalink / raw)
  To: dev; +Cc: Rastislav Cernay

From: Rastislav Cernay <cernay@netcope.com>

This patch implements new Netcope driver for NFB cards. Goal
is to gradually stop using and end support for old szedata2
driver and move to NFB. Driver has dependency on netcope-common
package, for now published on google drive and mentioned link
in doc/guides.

Rastislav Cernay (1):
  net/nfb: new netcope driver

 MAINTAINERS                      |   7 +
 config/common_base               |   4 +
 devtools/test-build.sh           |   1 +
 doc/guides/nics/features/nfb.ini |  17 ++
 doc/guides/nics/nfb.rst          | 141 ++++++++++
 drivers/net/Makefile             |   1 +
 drivers/net/meson.build          |   1 +
 drivers/net/nfb/Makefile         |  41 +++
 drivers/net/nfb/meson.build      |   9 +
 drivers/net/nfb/nfb.h            |  51 ++++
 drivers/net/nfb/nfb_ethdev.c     | 586 +++++++++++++++++++++++++++++++++++++++
 drivers/net/nfb/nfb_rx.c         | 127 +++++++++
 drivers/net/nfb/nfb_rx.h         | 226 +++++++++++++++
 drivers/net/nfb/nfb_rxmode.c     | 104 +++++++
 drivers/net/nfb/nfb_rxmode.h     |  81 ++++++
 drivers/net/nfb/nfb_stats.c      |  79 ++++++
 drivers/net/nfb/nfb_stats.h      |  52 ++++
 drivers/net/nfb/nfb_tx.c         | 112 ++++++++
 drivers/net/nfb/nfb_tx.h         | 209 ++++++++++++++
 examples/skeleton/basicfwd.c     | 198 -------------
 mk/rte.app.mk                    |   1 +
 21 files changed, 1850 insertions(+), 198 deletions(-)
 create mode 100644 doc/guides/nics/features/nfb.ini
 create mode 100644 doc/guides/nics/nfb.rst
 create mode 100644 drivers/net/nfb/Makefile
 create mode 100644 drivers/net/nfb/meson.build
 create mode 100644 drivers/net/nfb/nfb.h
 create mode 100644 drivers/net/nfb/nfb_ethdev.c
 create mode 100644 drivers/net/nfb/nfb_rx.c
 create mode 100644 drivers/net/nfb/nfb_rx.h
 create mode 100644 drivers/net/nfb/nfb_rxmode.c
 create mode 100644 drivers/net/nfb/nfb_rxmode.h
 create mode 100644 drivers/net/nfb/nfb_stats.c
 create mode 100644 drivers/net/nfb/nfb_stats.h
 create mode 100644 drivers/net/nfb/nfb_tx.c
 create mode 100644 drivers/net/nfb/nfb_tx.h
 delete mode 100644 examples/skeleton/basicfwd.c

-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [dpdk-dev] [PATCH] net/nfb: new netcope driver
  2019-02-26 12:57 [dpdk-dev] [PATCH] net/nfb: new Netcope driver Rastislav Cernay
@ 2019-02-26 12:57 ` Rastislav Cernay
  2019-02-26 14:20   ` Rami Rosen
                     ` (8 more replies)
  0 siblings, 9 replies; 50+ messages in thread
From: Rastislav Cernay @ 2019-02-26 12:57 UTC (permalink / raw)
  To: dev; +Cc: Rastislav Cernay

From: Rastislav Cernay <cernay@netcope.com>

Added new net driver for Netcope nfb cards

Signed-off-by: Rastislav Cernay <cernay@netcope.com>
---
 MAINTAINERS                      |   7 +
 config/common_base               |   4 +
 devtools/test-build.sh           |   1 +
 doc/guides/nics/features/nfb.ini |  17 ++
 doc/guides/nics/nfb.rst          | 141 ++++++++++
 drivers/net/Makefile             |   1 +
 drivers/net/meson.build          |   1 +
 drivers/net/nfb/Makefile         |  41 +++
 drivers/net/nfb/meson.build      |   9 +
 drivers/net/nfb/nfb.h            |  51 ++++
 drivers/net/nfb/nfb_ethdev.c     | 586 +++++++++++++++++++++++++++++++++++++++
 drivers/net/nfb/nfb_rx.c         | 127 +++++++++
 drivers/net/nfb/nfb_rx.h         | 226 +++++++++++++++
 drivers/net/nfb/nfb_rxmode.c     | 104 +++++++
 drivers/net/nfb/nfb_rxmode.h     |  81 ++++++
 drivers/net/nfb/nfb_stats.c      |  79 ++++++
 drivers/net/nfb/nfb_stats.h      |  52 ++++
 drivers/net/nfb/nfb_tx.c         | 112 ++++++++
 drivers/net/nfb/nfb_tx.h         | 209 ++++++++++++++
 examples/skeleton/basicfwd.c     | 198 -------------
 mk/rte.app.mk                    |   1 +
 21 files changed, 1850 insertions(+), 198 deletions(-)
 create mode 100644 doc/guides/nics/features/nfb.ini
 create mode 100644 doc/guides/nics/nfb.rst
 create mode 100644 drivers/net/nfb/Makefile
 create mode 100644 drivers/net/nfb/meson.build
 create mode 100644 drivers/net/nfb/nfb.h
 create mode 100644 drivers/net/nfb/nfb_ethdev.c
 create mode 100644 drivers/net/nfb/nfb_rx.c
 create mode 100644 drivers/net/nfb/nfb_rx.h
 create mode 100644 drivers/net/nfb/nfb_rxmode.c
 create mode 100644 drivers/net/nfb/nfb_rxmode.h
 create mode 100644 drivers/net/nfb/nfb_stats.c
 create mode 100644 drivers/net/nfb/nfb_stats.h
 create mode 100644 drivers/net/nfb/nfb_tx.c
 create mode 100644 drivers/net/nfb/nfb_tx.h
 delete mode 100644 examples/skeleton/basicfwd.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 6610440..c6bffde 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -654,6 +654,13 @@ F: drivers/net/szedata2/
 F: doc/guides/nics/szedata2.rst
 F: doc/guides/nics/features/szedata2.ini
 
+Netcope nfb
+M: Rastislav Cernay <cernay@netcope.com>
+M: Jan Remes <remes@netcope.com>
+F: drivers/net/nfb/
+F: doc/guides/nics/nfb.rst
+F: doc/guides/nics/features/nfb.ini
+
 Netronome nfp
 M: Alejandro Lucero <alejandro.lucero@netronome.com>
 F: drivers/net/nfp/
diff --git a/config/common_base b/config/common_base
index 7c6da51..1ab0a6b 100644
--- a/config/common_base
+++ b/config/common_base
@@ -360,6 +360,10 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
 # Compile software PMD backed by SZEDATA2 device
 #
 CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
+#
+# Compile software PMD backed by NFB device
+#
+CONFIG_RTE_LIBRTE_PMD_NFB=n
 
 #
 # Compile burst-oriented Cavium Thunderx NICVF PMD driver
diff --git a/devtools/test-build.sh b/devtools/test-build.sh
index 42f4ad0..ab57ab8 100755
--- a/devtools/test-build.sh
+++ b/devtools/test-build.sh
@@ -18,6 +18,7 @@ default_path=$PATH
 # - DPDK_DEP_SSL (y/[n])
 # - DPDK_DEP_IPSEC_MB (y/[n])
 # - DPDK_DEP_SZE (y/[n])
+# - DPDK_DEP_NFB (y/[n])
 # - DPDK_DEP_ZLIB (y/[n])
 # - DPDK_MAKE_JOBS (int)
 # - DPDK_NOTIFY (notify-send)
diff --git a/doc/guides/nics/features/nfb.ini b/doc/guides/nics/features/nfb.ini
new file mode 100644
index 0000000..6174d65
--- /dev/null
+++ b/doc/guides/nics/features/nfb.ini
@@ -0,0 +1,17 @@
+;
+; Supported features of the 'nfb' network poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Speed capabilities   = P
+Link status          = Y
+Queue start/stop     = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Basic stats          = Y
+Extended stats       = Y
+Stats per queue      = Y
+Other kdrv           = Y
+x86-64               = Y
+Usage doc            = Y
diff --git a/doc/guides/nics/nfb.rst b/doc/guides/nics/nfb.rst
new file mode 100644
index 0000000..9057d41
--- /dev/null
+++ b/doc/guides/nics/nfb.rst
@@ -0,0 +1,141 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright 2015 - 2016 CESNET
+
+NFB poll mode driver library
+=================================
+
+The NFB poll mode driver library implements support for the Netcope
+FPGA Boards (**NFB-***), FPGA-based programmable NICs.
+The NFB PMD uses interface provided by the libnfb library to communicate
+with the NFB cards over the nfb layer.
+
+More information about the
+`NFB cards <http://www.netcope.com/en/products/fpga-boards>`_
+and used technology
+(`Netcope Development Kit <http://www.netcope.com/en/products/fpga-development-kit>`_)
+can be found on the `Netcope Technologies website <http://www.netcope.com/>`_.
+
+.. note::
+
+   This driver has external dependencies.
+   Therefore it is disabled in default configuration files.
+   It can be enabled by setting ``CONFIG_RTE_LIBRTE_PMD_NFB=y``
+   and recompiling.
+
+.. note::
+
+   Currently the driver is supported only on x86_64 architectures.
+   Only x86_64 versions of the external libraries are provided.
+
+Prerequisites
+-------------
+
+This PMD requires kernel modules which are responsible for initialization and
+allocation of resources needed for nfb layer function.
+Communication between PMD and kernel modules is mediated by libnfb library.
+These kernel modules and library are not part of DPDK and must be installed
+separately:
+
+*  **libnfb library**
+
+   The library provides API for initialization of nfb transfers, receiving and
+   transmitting data segments.
+
+*  **Kernel modules**
+
+   * nfb
+
+   Kernel modules manage initialization of hardware, allocation and
+   sharing of resources for user space applications.
+
+Dependencies can be found here:
+`Netcope common <https://drive.google.com/file/d/13khqS312KzrRSrgGxD0CBSmd1YLJHWp8>`_.
+
+Versions of the packages
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The minimum version of the provided packages:
+
+* for DPDK from 19.02
+
+Configuration
+-------------
+
+These configuration options can be modified before compilation in the
+``.config`` file:
+
+*  ``CONFIG_RTE_LIBRTE_PMD_NFB`` default value: **n**
+
+   Value **y** enables compilation of nfb PMD.
+
+Using the NFB PMD
+----------------------
+
+Kernel modules have to be loaded before running the DPDK application.
+
+NFB card architecture
+---------------------
+
+The NFB cards are multi-port multi-queue cards, where (generally) data from any
+Ethernet port may be sent to any queue.
+They are represented in DPDK as a single port.
+
+NFB-200G2QL card employs an addon cable which allows to connect it to two
+physical PCI-E slots at the same time (see the diagram below).
+This is done to allow 200 Gbps of traffic to be transferred through the PCI-E
+bus (note that a single PCI-E 3.0 x16 slot provides only 125 Gbps theoretical
+throughput).
+
+Although each slot may be connected to a different CPU and therefore to a different
+NUMA node, the card is represented as a single port in DPDK. To work with data
+from the individual queues on the right NUMA node, connection of NUMA nodes on
+first and last queue (each NUMA node has half of the queues) need to be checked.
+
+.. figure:: img/szedata2_nfb200g_architecture.svg
+    :align: center
+
+    NFB-200G2QL high-level diagram
+
+Limitations
+-----------
+
+Since a card is always represented as a single port, but can be connected to two
+NUMA nodes, there is need for manual check where master/slave is connected.
+
+Example of usage
+----------------
+
+Read packets from 0. and 1. receive queue and write them to 0. and 1.
+transmit queue:
+
+.. code-block:: console
+
+   $RTE_TARGET/app/testpmd -l 0-3 -n 2 \
+   -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2 -i -a
+
+Example output:
+
+.. code-block:: console
+
+   [...]
+   EAL: PCI device 0000:06:00.0 on NUMA socket -1
+   EAL:   probe driver: 1b26:c1c1 net_nfb
+   PMD: Initializing NFB device (0000:06:00.0)
+   PMD: Available DMA queues RX: 8 TX: 8
+   PMD: NFB device (0000:06:00.0) successfully initialized
+   Interactive-mode selected
+   Auto-start selected
+   Configuring Port 0 (socket 0)
+   Port 0: 00:11:17:00:00:00
+   Checking link statuses...
+   Port 0 Link Up - speed 10000 Mbps - full-duplex
+   Done
+   Start automatic packet forwarding
+     io packet forwarding - CRC stripping disabled - packets/burst=32
+     nb forwarding cores=2 - nb forwarding ports=1
+     RX queues=2 - RX desc=128 - RX free threshold=0
+     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX queues=2 - TX desc=512 - TX free threshold=0
+     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX RS bit threshold=0 - TXQ flags=0x0
+   testpmd>
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 670d7f7..013c551 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -38,6 +38,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5
 DIRS-$(CONFIG_RTE_LIBRTE_MVNETA_PMD) += mvneta
 DIRS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mvpp2
 DIRS-$(CONFIG_RTE_LIBRTE_NETVSC_PMD) += netvsc
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb
 DIRS-$(CONFIG_RTE_LIBRTE_NFP_PMD) += nfp
 DIRS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += null
diff --git a/drivers/net/meson.build b/drivers/net/meson.build
index 45da3bb..6733a19 100644
--- a/drivers/net/meson.build
+++ b/drivers/net/meson.build
@@ -27,6 +27,7 @@ drivers = ['af_packet',
 	'mvneta',
 	'mvpp2',
 	'netvsc',
+	'nfb',
 	'nfp',
 	'null', 'octeontx', 'pcap', 'qede', 'ring',
 	'sfc',
diff --git a/drivers/net/nfb/Makefile b/drivers/net/nfb/Makefile
new file mode 100644
index 0000000..ee8c7df
--- /dev/null
+++ b/drivers/net/nfb/Makefile
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Cesnet
+# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_nfb.a
+
+INCLUDES :=-I$(SRCDIR)
+
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+LDLIBS += -lnfb
+LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
+LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
+LDLIBS += -lrte_bus_pci
+
+EXPORT_MAP := rte_pmd_nfb_version.map
+
+LIBABIVER := 1
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_rx.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_tx.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_stats.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_rxmode.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/nfb/meson.build b/drivers/net/nfb/meson.build
new file mode 100644
index 0000000..d7dccba
--- /dev/null
+++ b/drivers/net/nfb/meson.build
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Cesnet
+# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+dep = cc.find_library('nfb', required: true)
+build = dep.found()
+ext_deps += dep
+sources = files('nfb_rx.c', 'nfb_tx.c', 'nfb_stats.c', 'nfb_ethdev.c', 'nfb_rxmode.c')
diff --git a/drivers/net/nfb/nfb.h b/drivers/net/nfb/nfb.h
new file mode 100644
index 0000000..d032ba4
--- /dev/null
+++ b/drivers/net/nfb/nfb.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_H_
+#define _NFB_H_
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+
+/* PCI Vendor ID */
+#define PCI_VENDOR_ID_NETCOPE 0x1b26
+
+/* PCI Device IDs */
+#define PCI_DEVICE_ID_NFB_40G2  0xcb80
+#define PCI_DEVICE_ID_NFB_100G2 0xc2c1
+#define PCI_DEVICE_ID_NFB_200G2QL 0xc250
+
+/* Max index of ndp rx/tx queues */
+#define RTE_ETH_NDP_MAX_RX_QUEUES 32
+#define RTE_ETH_NDP_MAX_TX_QUEUES 32
+
+/* Max index of rx/tx dmas */
+#define RTE_MAX_NC_RXMAC 256
+#define RTE_MAX_NC_TXMAC 256
+
+#define RTE_NFB_DRIVER_NAME net_nfb
+
+struct pmd_internals {
+	uint16_t         max_rxmac;
+	uint16_t         max_txmac;
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC];
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC];
+
+	char             nfb_dev[PATH_MAX];
+	struct nfb_device *nfb;
+	/* Place to remember if filter was promiscous or filtering by table,
+	 * when disabling allmulticast
+	 */
+	enum nc_rxmac_mac_filter rx_filter_original;
+};
+
+
+#endif /* _NFB_H_ */
diff --git a/drivers/net/nfb/nfb_ethdev.c b/drivers/net/nfb/nfb_ethdev.c
new file mode 100644
index 0000000..c8d546f
--- /dev/null
+++ b/drivers/net/nfb/nfb_ethdev.c
@@ -0,0 +1,586 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_kvargs.h>
+#include <rte_dev.h>
+#include <rte_common.h>
+
+#include "nfb_stats.h"
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+/**
+ * Default MAC addr
+ */
+static struct ether_addr eth_addr = {
+	.addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
+};
+
+/**
+ * Open all RX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] rxmac
+ *   Pointer to output array of nc_rxmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of rxmac
+ */
+static void
+nfb_nc_rxmac_init(struct nfb_device *nfb,
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t *max_rxmac)
+{
+	*max_rxmac = 0;
+	while ((rxmac[*max_rxmac] = nc_rxmac_open_index(nfb, *max_rxmac)))
+		++(*max_rxmac);
+}
+
+/**
+ * Open all TX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] txmac
+ *   Pointer to output array of nc_txmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of txmac
+ */
+static void
+nfb_nc_txmac_init(struct nfb_device *nfb,
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t *max_txmac)
+{
+	*max_txmac = 0;
+	while ((txmac[*max_txmac] = nc_txmac_open_index(nfb, *max_txmac)))
+		++(*max_txmac);
+}
+
+/**
+ * Close all RX DMA queues
+ *
+ * @param rxmac
+ *   Pointer to array of nc_rxmac
+ * @param max_rxmac
+ *   Maximum index of rxmac
+ */
+static void
+nfb_nc_rxmac_deinit(struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t max_rxmac)
+{
+	for (; max_rxmac > 0; --max_rxmac) {
+		nc_rxmac_close(rxmac[max_rxmac]);
+		rxmac[max_rxmac] = NULL;
+	}
+}
+
+/**
+ * Close all TX DMA queues
+ *
+ * @param txmac
+ *   Pointer to array of nc_txmac
+ * @param max_txmac
+ *   Maximum index of txmac
+ */
+static void
+nfb_nc_txmac_deinit(struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t max_txmac)
+{
+	for (; max_txmac > 0; --max_txmac) {
+		nc_txmac_close(txmac[max_txmac]);
+		txmac[max_txmac] = NULL;
+	}
+}
+
+/**
+ * DPDK callback to start the device.
+ *
+ * Start device by starting all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+nfb_eth_dev_start(struct rte_eth_dev *dev)
+{
+	int ret;
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_rx; i++) {
+		ret = nfb_eth_rx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_rx;
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		ret = nfb_eth_tx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_tx;
+	}
+
+	return 0;
+
+err_tx:
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+err_rx:
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+	return ret;
+}
+
+/**
+ * DPDK callback to stop the device.
+ *
+ * Stop device by stopping all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+nfb_eth_dev_stop(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+}
+
+/**
+ * DPDK callback for Ethernet device configuration.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+nfb_eth_dev_configure(struct rte_eth_dev *dev)
+{
+	dev->rx_pkt_burst = nfb_eth_ndp_rx;
+	return 0;
+}
+
+/**
+ * DPDK callback to get information about the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] info
+ *   Info structure output buffer.
+ */
+static void
+nfb_eth_dev_info(struct rte_eth_dev *dev,
+	struct rte_eth_dev_info *dev_info)
+{
+	dev_info->if_index = 0;
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = dev->data->nb_rx_queues;
+	dev_info->max_tx_queues = dev->data->nb_tx_queues;
+	dev_info->min_rx_bufsize = 0;
+	dev_info->speed_capa = ETH_LINK_SPEED_100G;
+}
+
+/**
+ * DPDK callback to close the device.
+ *
+ * Destroy all queues and objects, free memory.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+nfb_eth_dev_close(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	nfb_eth_dev_stop(dev);
+
+	for (i = 0; i < nb_rx; i++) {
+		nfb_eth_rx_queue_release(dev->data->rx_queues[i]);
+		dev->data->rx_queues[i] = NULL;
+	}
+	dev->data->nb_rx_queues = 0;
+	for (i = 0; i < nb_tx; i++) {
+		nfb_eth_tx_queue_release(dev->data->tx_queues[i]);
+		dev->data->tx_queues[i] = NULL;
+	}
+	dev->data->nb_tx_queues = 0;
+}
+
+/**
+ * DPDK callback to retrieve physical link information.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] link
+ *   Storage for current link status.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+nfb_eth_link_update(struct rte_eth_dev *dev,
+	int wait_to_complete __rte_unused)
+{
+	uint16_t i;
+	struct rte_eth_link link;
+	memset(&link, 0, sizeof(link));
+
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.speed = MAC_SPEED_UNKNOWN;
+
+	link.link_speed = ETH_SPEED_NUM_NONE;
+	link.link_status = ETH_LINK_DOWN;
+	link.link_duplex = ETH_LINK_FULL_DUPLEX;
+	link.link_autoneg = ETH_LINK_SPEED_FIXED;
+
+	if (internals->rxmac[0] != NULL) {
+		nc_rxmac_read_status(internals->rxmac[0], &status);
+
+		switch (status.speed) {
+		case MAC_SPEED_10G:
+			link.link_speed = ETH_SPEED_NUM_10G;
+			break;
+		case MAC_SPEED_40G:
+			link.link_speed = ETH_SPEED_NUM_40G;
+			break;
+		case MAC_SPEED_100G:
+			link.link_speed = ETH_SPEED_NUM_100G;
+			break;
+		default:
+			link.link_speed = ETH_SPEED_NUM_NONE;
+			break;
+		}
+	}
+
+	i = 0;
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_read_status(internals->rxmac[i], &status);
+
+		if (status.enabled && status.link_up) {
+			link.link_status = ETH_LINK_UP;
+			break;
+		}
+	}
+
+	rte_eth_linkstatus_set(dev, &link);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to bring the link UP.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+nfb_eth_dev_set_link_up(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_enable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_enable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to bring the link DOWN.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+nfb_eth_dev_set_link_down(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_disable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_disable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to set primary MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+nfb_eth_mac_addr_set(struct rte_eth_dev *dev __rte_unused,
+	struct ether_addr *mac_addr __rte_unused)
+{
+	return 0;
+}
+
+static const struct eth_dev_ops ops = {
+	.dev_start = nfb_eth_dev_start,
+	.dev_stop = nfb_eth_dev_stop,
+	.dev_set_link_up = nfb_eth_dev_set_link_up,
+	.dev_set_link_down = nfb_eth_dev_set_link_down,
+	.dev_close = nfb_eth_dev_close,
+	.dev_configure = nfb_eth_dev_configure,
+	.dev_infos_get = nfb_eth_dev_info,
+	.promiscuous_enable = nfb_eth_promiscuous_enable,
+	.promiscuous_disable = nfb_eth_promiscuous_disable,
+	.allmulticast_enable = nfb_eth_allmulticast_enable,
+	.allmulticast_disable = nfb_eth_allmulticast_disable,
+	.rx_queue_start = nfb_eth_rx_queue_start,
+	.rx_queue_stop = nfb_eth_rx_queue_stop,
+	.tx_queue_start = nfb_eth_tx_queue_start,
+	.tx_queue_stop = nfb_eth_tx_queue_stop,
+	.rx_queue_setup = nfb_eth_rx_queue_setup,
+	.tx_queue_setup = nfb_eth_tx_queue_setup,
+	.rx_queue_release = nfb_eth_rx_queue_release,
+	.tx_queue_release = nfb_eth_tx_queue_release,
+	.link_update = nfb_eth_link_update,
+	.stats_get = nfb_eth_stats_get,
+	.stats_reset = nfb_eth_stats_reset,
+	.mac_addr_set = nfb_eth_mac_addr_set,
+};
+
+/**
+ * DPDK callback to initialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+nfb_eth_dev_init(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+
+	RTE_LOG(INFO, PMD, "Initializing NFB device (" PCI_PRI_FMT ")\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	snprintf(internals->nfb_dev, PATH_MAX,
+		"/dev/nfb/by-pci-slot/" PCI_PRI_FMT,
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	/*
+	 * Get number of available DMA RX and TX queues, which is maximum
+	 * number of queues that can be created and store it in private device
+	 * data structure.
+	 */
+	internals->nfb = nfb_open(internals->nfb_dev);
+	if (internals->nfb == NULL) {
+		RTE_LOG(ERR, PMD, "nfb_open(): failed to open %s",
+			internals->nfb_dev);
+		return -EINVAL;
+	}
+	data->nb_rx_queues = ndp_get_rx_queue_available_count(internals->nfb);
+	data->nb_tx_queues = ndp_get_tx_queue_available_count(internals->nfb);
+
+	RTE_LOG(INFO, PMD, "Available NDP queues RX: %u TX: %u\n",
+		data->nb_rx_queues, data->nb_tx_queues);
+
+	nfb_nc_rxmac_init(internals->nfb,
+		internals->rxmac,
+		&internals->max_rxmac);
+	nfb_nc_txmac_init(internals->nfb,
+		internals->txmac,
+		&internals->max_txmac);
+
+	/* Set rx, tx burst functions */
+	dev->rx_pkt_burst = nfb_eth_ndp_rx;
+	dev->tx_pkt_burst = nfb_eth_ndp_tx;
+
+	/* Set function callbacks for Ethernet API */
+	dev->dev_ops = &ops;
+
+	rte_eth_copy_pci_info(dev, pci_dev);
+
+	/* Get link state */
+	nfb_eth_link_update(dev, 0);
+
+	/* Allocate space for one mac address */
+	data->mac_addrs = rte_zmalloc(data->name, sizeof(struct ether_addr),
+		RTE_CACHE_LINE_SIZE);
+	if (data->mac_addrs == NULL) {
+		RTE_LOG(ERR, PMD, "Could not alloc space for MAC address!\n");
+		nfb_close(internals->nfb);
+		return -EINVAL;
+	}
+
+	ether_addr_copy(&eth_addr, data->mac_addrs);
+
+	data->promiscuous = nfb_eth_promiscuous_get(dev);
+	data->all_multicast = nfb_eth_allmulticast_get(dev);
+	internals->rx_filter_original = data->promiscuous;
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully initialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to uninitialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+nfb_eth_dev_uninit(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+
+	rte_free(dev->data->mac_addrs);
+	dev->data->mac_addrs = NULL;
+
+	nfb_nc_rxmac_deinit(internals->rxmac, internals->max_rxmac);
+	nfb_nc_txmac_deinit(internals->txmac, internals->max_txmac);
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully uninitialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+static const struct rte_pci_id nfb_pci_id_table[] = {
+	{
+		RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_40G2)
+	},
+	{
+		RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_100G2)
+	},
+	{
+		RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_200G2QL)
+	},
+	{
+		.vendor_id = 0,
+	}
+};
+
+/**
+ * DPDK callback to register a PCI device.
+ *
+ * This function spawns Ethernet devices out of a given PCI device.
+ *
+ * @param[in] pci_drv
+ *   PCI driver structure (nfb_driver).
+ * @param[in] pci_dev
+ *   PCI device information.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int nfb_eth_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+	struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_probe(pci_dev,
+		sizeof(struct pmd_internals), nfb_eth_dev_init);
+}
+
+/**
+ * DPDK callback to remove a PCI device.
+ *
+ * This function removes all Ethernet devices belong to a given PCI device.
+ *
+ * @param[in] pci_dev
+ *   Pointer to the PCI device.
+ *
+ * @return
+ *   0 on success, the function cannot fail.
+ */
+static int nfb_eth_pci_remove(struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_remove(pci_dev, nfb_eth_dev_uninit);
+}
+
+static struct rte_pci_driver nfb_eth_driver = {
+	.id_table = nfb_pci_id_table,
+	.probe = nfb_eth_pci_probe,
+	.remove = nfb_eth_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(RTE_NFB_DRIVER_NAME, nfb_eth_driver);
+RTE_PMD_REGISTER_PCI_TABLE(RTE_NFB_DRIVER_NAME, nfb_pci_id_table);
+RTE_PMD_REGISTER_KMOD_DEP(RTE_NFB_DRIVER_NAME, "* nfb");
diff --git a/drivers/net/nfb/nfb_rx.c b/drivers/net/nfb/nfb_rx.c
new file mode 100644
index 0000000..dc1cd2d
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.c
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_rx.h"
+#include "nfb.h"
+
+
+int
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	int ret = ndp_queue_start(rxq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+
+
+int
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	int ret = ndp_queue_stop(rxq->queue);
+	if (ret != 0)
+		return -EINVAL;
+
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+		uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	struct ndp_rx_queue *rxq;
+
+	rxq = rte_zmalloc_socket("ndp rx queue",
+			sizeof(struct ndp_rx_queue),
+			RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (rxq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for rx queue id "
+				"%" PRIu16 "!\n", rx_queue_id);
+		return -ENOMEM;
+	}
+
+	int ret = nfb_eth_rx_queue_init(internals->nfb,
+		rx_queue_id,
+		dev->data->port_id,
+		mb_pool,
+		rxq);
+
+	if (ret == 0)
+		dev->data->rx_queues[rx_queue_id] = rxq;
+	else
+		rte_free(rxq);
+
+	return ret;
+}
+
+int
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+		uint16_t rx_queue_id,
+		uint16_t port_id,
+		struct rte_mempool *mb_pool,
+		struct ndp_rx_queue *rxq)
+{
+	if (nfb == NULL)
+		return -EINVAL;
+
+	rxq->queue = ndp_open_rx_queue(nfb, rx_queue_id);
+	if (rxq->queue == NULL)
+		return -EINVAL;
+
+	rxq->nfb = nfb;
+	rxq->rx_queue_id = rx_queue_id;
+	rxq->in_port = port_id;
+	rxq->mb_pool = mb_pool;
+
+	const struct rte_pktmbuf_pool_private *mbp_priv =
+		rte_mempool_get_priv(mb_pool);
+	rxq->buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size -
+		RTE_PKTMBUF_HEADROOM);
+
+	rxq->rx_pkts = 0;
+	rxq->rx_bytes = 0;
+	rxq->err_pkts = 0;
+
+	return 0;
+}
+
+void
+nfb_eth_rx_queue_release(void *q)
+{
+	struct ndp_rx_queue *rxq = (struct ndp_rx_queue *)q;
+	if (rxq->queue != NULL) {
+		ndp_close_rx_queue(rxq->queue);
+		rte_free(rxq);
+		rxq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_rx.h b/drivers/net/nfb/nfb_rx.h
new file mode 100644
index 0000000..b356f5d
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.h
@@ -0,0 +1,226 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+
+
+#ifndef _NFB_RX_H_
+#define _NFB_RX_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+struct ndp_rx_queue {
+	struct nfb_device *nfb;	     /* nfb dev structure */
+	struct ndp_queue *queue;     /* rx queue */
+	uint16_t rx_queue_id;	     /* index */
+	uint8_t in_port;	     /* port */
+
+	struct rte_mempool *mb_pool; /* memory pool to allocate packets */
+	uint16_t buf_size;           /* mbuf size */
+
+	volatile uint64_t rx_pkts;   /* packets read */
+	volatile uint64_t rx_bytes;  /* bytes read */
+	volatile uint64_t err_pkts;  /* erroneous packets */
+};
+
+/**
+ * Initialize ndp_rx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param rx_queue_id
+ *   RX queue index.
+ * @param port_id
+ *   Device [external] port identifier.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ * @param[out] rxq
+ *   Pointer to ndp_rx_queue output structure
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+	uint16_t rx_queue_id,
+	uint16_t port_id,
+	struct rte_mempool *mb_pool,
+	struct ndp_rx_queue *rxq);
+
+
+/**
+ * DPDK callback to setup a RX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t rx_queue_id,
+	uint16_t nb_rx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_rxconf *rx_conf __rte_unused,
+	struct rte_mempool *mb_pool);
+
+
+/**
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void
+nfb_eth_rx_queue_release(void *q);
+
+/**
+ * Start traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * Stop traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ */
+int
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * DPDK callback for RX.
+ *
+ * @param dpdk_rxq
+ *   Generic pointer to RX queue structure.
+ * @param[out] bufs
+ *   Array to store received packets.
+ * @param nb_pkts
+ *   Maximum number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully received (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t
+nfb_eth_ndp_rx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	struct ndp_rx_queue *ndp = queue;
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "RX invalid arguments!\n");
+		return 0;
+	}
+
+	struct rte_mbuf *mbufs[nb_pkts];
+
+	unsigned int i;
+	// returns either all or nothing
+	i = rte_pktmbuf_alloc_bulk(ndp->mb_pool, mbufs, nb_pkts);
+	if (unlikely(i != 0))
+		return 0;
+
+	uint16_t packet_size;
+	uint64_t num_bytes = 0;
+	const uint16_t buf_size = ndp->buf_size;
+
+	struct rte_mbuf *mbuf;
+	struct ndp_packet packets[nb_pkts];
+
+
+	uint16_t num_rx = ndp_rx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_rx != nb_pkts)) {
+		for (i = num_rx; i < nb_pkts; i++)
+			rte_pktmbuf_free(mbufs[i]);
+	}
+
+	nb_pkts = num_rx;
+
+	num_rx = 0;
+	/*
+	 * Reads the given number of packets from NDP queue given
+	 * by queue and copies the packet data into a newly allocated mbuf
+	 * to return.
+	 */
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = mbufs[i];
+
+		/* get the space available for data in the mbuf */
+		packet_size = packets[i].data_length;
+
+		if (likely(packet_size <= buf_size)) {
+			/* NDP packet will fit in one mbuf, go ahead and copy */
+			rte_memcpy(rte_pktmbuf_mtod(mbuf, void *),
+				packets[i].data, packet_size);
+
+			mbuf->data_len = (uint16_t)packet_size;
+
+			mbuf->pkt_len = packet_size;
+			mbuf->port = ndp->in_port;
+			bufs[num_rx++] = mbuf;
+			num_bytes += packet_size;
+		} else {
+			/*
+			 * NDP packet will not fit in one mbuf,
+			 * scattered mode is not enabled, drop packet
+			 */
+			RTE_LOG(ERR, PMD,
+				"NDP segment %d bytes will not fit in one mbuf "
+				"(%d bytes), scattered mode is not enabled, "
+				"drop packet!!\n",
+				packet_size, buf_size);
+			rte_pktmbuf_free(mbuf);
+		}
+	}
+
+
+	ndp_rx_burst_put(ndp->queue);
+
+	ndp->rx_pkts += num_rx;
+	ndp->rx_bytes += num_bytes;
+	return num_rx;
+}
+
+
+
+#endif /* _NFB_RX_H_ */
diff --git a/drivers/net/nfb/nfb_rxmode.c b/drivers/net/nfb/nfb_rxmode.c
new file mode 100644
index 0000000..8a63507
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.c
@@ -0,0 +1,104 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+void
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_PROMISCUOUS);
+	}
+}
+
+void
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_TABLE;
+
+
+	// if promisc is not enabled, do nothing
+	if (!nfb_eth_promiscuous_get(dev))
+		return;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE);
+	}
+}
+
+int
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_PROMISCUOUS);
+}
+
+void
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+	}
+}
+
+void
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev)
+{
+	// if multicast is not enabled do nothing
+	if (!nfb_eth_allmulticast_get(dev))
+		return;
+
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			internals->rx_filter_original);
+	}
+}
+
+int
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+}
diff --git a/drivers/net/nfb/nfb_rxmode.h b/drivers/net/nfb/nfb_rxmode.h
new file mode 100644
index 0000000..2a72b10
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_RXMODE_H_
+#define _NFB_RXMODE_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_ethdev.h>
+#include <rte_dev.h>
+
+/**
+ * Getter for promiscuous mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to enable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to disable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev);
+
+/**
+ * Getter for allmulticast mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to enable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to disable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev);
+
+
+
+
+#endif /* _NFB_RXMODE_H_ */
diff --git a/drivers/net/nfb/nfb_stats.c b/drivers/net/nfb/nfb_stats.c
new file mode 100644
index 0000000..f2750e4
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.c
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+
+#include "nfb_stats.h"
+#include "nfb.h"
+
+int
+nfb_eth_stats_get(struct rte_eth_dev *dev,
+	struct rte_eth_stats *stats)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+	uint64_t rx_total = 0;
+	uint64_t tx_total = 0;
+	uint64_t tx_err_total = 0;
+	uint64_t rx_total_bytes = 0;
+	uint64_t tx_total_bytes = 0;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_ipackets[i] = rx_queue[i].rx_pkts;
+			stats->q_ibytes[i] = rx_queue[i].rx_bytes;
+		}
+		rx_total += stats->q_ipackets[i];
+		rx_total_bytes += stats->q_ibytes[i];
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_opackets[i] = tx_queue[i].tx_pkts;
+			stats->q_obytes[i] = tx_queue[i].tx_bytes;
+			stats->q_errors[i] = tx_queue[i].err_pkts;
+		}
+		tx_total += stats->q_opackets[i];
+		tx_total_bytes += stats->q_obytes[i];
+		tx_err_total += stats->q_errors[i];
+	}
+
+	stats->ipackets = rx_total;
+	stats->opackets = tx_total;
+	stats->ibytes = rx_total_bytes;
+	stats->obytes = tx_total_bytes;
+	stats->oerrors = tx_err_total;
+	return 0;
+}
+
+void
+nfb_eth_stats_reset(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		rx_queue[i].rx_pkts = 0;
+		rx_queue[i].rx_bytes = 0;
+		rx_queue[i].err_pkts = 0;
+	}
+	for (i = 0; i < nb_tx; i++) {
+		tx_queue[i].tx_pkts = 0;
+		tx_queue[i].tx_bytes = 0;
+		tx_queue[i].err_pkts = 0;
+	}
+}
diff --git a/drivers/net/nfb/nfb_stats.h b/drivers/net/nfb/nfb_stats.h
new file mode 100644
index 0000000..d89ca4c
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_STATS_H_
+#define _NFB_STATS_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+/**
+ * DPDK callback to get device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] stats
+ *   Stats structure output buffer.
+ *
+ * @return
+ *   0 on success and stats is filled, negative errno value otherwise and
+ *   rte_errno is set.
+ */
+int nfb_eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats);
+
+/**
+ * DPDK callback to clear device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void nfb_eth_stats_reset(struct rte_eth_dev *dev);
+
+
+
+
+#endif /* _NFB_STATS_H_ */
diff --git a/drivers/net/nfb/nfb_tx.c b/drivers/net/nfb/nfb_tx.c
new file mode 100644
index 0000000..efaaa2b
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.c
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+
+#include "nfb_tx.h"
+#include "nfb.h"
+
+int
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+
+	if (txq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	int ret = ndp_queue_start(txq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+int
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+
+	if (txq->queue != NULL) {
+		RTE_LOG(ERR, PMD, "TX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	int ret = ndp_queue_stop(txq->queue);
+	if (ret != 0)
+		return -EINVAL;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	struct ndp_tx_queue *txq;
+
+	txq = rte_zmalloc_socket("ndp tx queue",
+		sizeof(struct ndp_tx_queue),
+		RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (txq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for tx queue id "
+			"%" PRIu16 "!\n", tx_queue_id);
+		return -ENOMEM;
+	}
+
+	int ret = nfb_eth_tx_queue_init(internals->nfb,
+		tx_queue_id,
+		txq);
+
+	if (ret == 0)
+		dev->data->tx_queues[tx_queue_id] = txq;
+	else
+		rte_free(txq);
+
+	return ret;
+}
+
+int
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq)
+{
+	if (nfb == NULL)
+		return -EINVAL;
+
+	txq->queue = ndp_open_tx_queue(nfb, tx_queue_id);
+	if (txq->queue == NULL)
+		return -EINVAL;
+
+	txq->nfb = nfb;
+	txq->tx_queue_id = tx_queue_id;
+
+	txq->tx_pkts = 0;
+	txq->tx_bytes = 0;
+	txq->err_pkts = 0;
+
+	return 0;
+}
+
+void
+nfb_eth_tx_queue_release(void *q)
+{
+	struct ndp_tx_queue *txq = (struct ndp_tx_queue *)q;
+	if (txq->queue != NULL) {
+		ndp_close_tx_queue(txq->queue);
+		rte_free(txq);
+		txq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_tx.h b/drivers/net/nfb/nfb_tx.h
new file mode 100644
index 0000000..3ceb3bf
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.h
@@ -0,0 +1,209 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_TX_H_
+#define _NFB_TX_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+struct ndp_tx_queue {
+	struct nfb_device *nfb;     /* nfb dev structure */
+	struct ndp_queue *queue;    /* tx queue */
+	uint16_t          tx_queue_id;       /* index */
+	volatile uint64_t tx_pkts;  /* packets transmitted */
+	volatile uint64_t tx_bytes; /* bytes transmitted */
+	volatile uint64_t err_pkts; /* erroneous packets */
+};
+
+
+/**
+ * DPDK callback to setup a TX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mp
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused);
+
+/**
+ * Initialize ndp_tx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param tx_queue_id
+ *   TX queue index.
+ * @param[out] txq
+ *   Pointer to ndp_tx_queue output structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq);
+
+/**
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void
+nfb_eth_tx_queue_release(void *q);
+
+
+/**
+ * Start traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * Stop traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * DPDK callback for TX.
+ *
+ * @param dpdk_txq
+ *   Generic pointer to TX queue structure.
+ * @param bufs
+ *   Packets to transmit.
+ * @param nb_pkts
+ *   Number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully transmitted (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t
+nfb_eth_ndp_tx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	int i;
+	struct rte_mbuf *mbuf;
+	struct ndp_tx_queue *ndp = queue;
+	uint16_t num_tx = 0;
+	uint64_t num_bytes = 0;
+
+	void *dst;
+	uint32_t pkt_len;
+	uint8_t mbuf_segs;
+
+	struct ndp_packet packets[nb_pkts];
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "RX invalid arguments!\n");
+		return 0;
+	}
+
+	for (i = 0; i < nb_pkts; i++) {
+		packets[i].data_length = bufs[i]->pkt_len;
+		packets[i].header_length = 0;
+	}
+
+	num_tx = ndp_tx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_tx != nb_pkts))
+		return 0;
+
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = bufs[i];
+
+		pkt_len = mbuf->pkt_len;
+		mbuf_segs = mbuf->nb_segs;
+
+		num_bytes += pkt_len;
+		if (mbuf_segs == 1) {
+			/*
+			 * non-scattered packet,
+			 * transmit from one mbuf
+			 */
+			rte_memcpy(packets[i].data,
+				rte_pktmbuf_mtod(mbuf, const void *),
+				pkt_len);
+		} else {
+			/* scattered packet, transmit from more mbufs */
+			struct rte_mbuf *m = mbuf;
+			while (m) {
+				dst = packets[i].data;
+
+				rte_memcpy(dst,
+					rte_pktmbuf_mtod(m,
+					const void *),
+					m->data_len);
+				dst = ((uint8_t *)(dst)) +
+					m->data_len;
+				m = m->next;
+			}
+		}
+
+		rte_pktmbuf_free(mbuf);
+	}
+
+	ndp_tx_burst_flush(ndp->queue);
+
+	ndp->tx_pkts += num_tx;
+	ndp->err_pkts += nb_pkts - num_tx;
+	ndp->tx_bytes += num_bytes;
+	return num_tx;
+}
+
+
+
+
+#endif /* _NFB_TX_H_ */
diff --git a/examples/skeleton/basicfwd.c b/examples/skeleton/basicfwd.c
deleted file mode 100644
index 4aba1dc..0000000
--- a/examples/skeleton/basicfwd.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include <stdint.h>
-#include <inttypes.h>
-#include <rte_eal.h>
-#include <rte_ethdev.h>
-#include <rte_cycles.h>
-#include <rte_lcore.h>
-#include <rte_mbuf.h>
-
-#define RX_RING_SIZE 1024
-#define TX_RING_SIZE 1024
-
-#define NUM_MBUFS 8191
-#define MBUF_CACHE_SIZE 250
-#define BURST_SIZE 32
-
-static const struct rte_eth_conf port_conf_default = {
-	.rxmode = {
-		.max_rx_pkt_len = ETHER_MAX_LEN,
-	},
-};
-
-/* basicfwd.c: Basic DPDK skeleton forwarding example. */
-
-/*
- * Initializes a given port using global settings and with the RX buffers
- * coming from the mbuf_pool passed as a parameter.
- */
-static inline int
-port_init(uint16_t port, struct rte_mempool *mbuf_pool)
-{
-	struct rte_eth_conf port_conf = port_conf_default;
-	const uint16_t rx_rings = 1, tx_rings = 1;
-	uint16_t nb_rxd = RX_RING_SIZE;
-	uint16_t nb_txd = TX_RING_SIZE;
-	int retval;
-	uint16_t q;
-	struct rte_eth_dev_info dev_info;
-	struct rte_eth_txconf txconf;
-
-	if (!rte_eth_dev_is_valid_port(port))
-		return -1;
-
-	rte_eth_dev_info_get(port, &dev_info);
-	if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
-		port_conf.txmode.offloads |=
-			DEV_TX_OFFLOAD_MBUF_FAST_FREE;
-
-	/* Configure the Ethernet device. */
-	retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
-	if (retval != 0)
-		return retval;
-
-	retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd);
-	if (retval != 0)
-		return retval;
-
-	/* Allocate and set up 1 RX queue per Ethernet port. */
-	for (q = 0; q < rx_rings; q++) {
-		retval = rte_eth_rx_queue_setup(port, q, nb_rxd,
-				rte_eth_dev_socket_id(port), NULL, mbuf_pool);
-		if (retval < 0)
-			return retval;
-	}
-
-	txconf = dev_info.default_txconf;
-	txconf.offloads = port_conf.txmode.offloads;
-	/* Allocate and set up 1 TX queue per Ethernet port. */
-	for (q = 0; q < tx_rings; q++) {
-		retval = rte_eth_tx_queue_setup(port, q, nb_txd,
-				rte_eth_dev_socket_id(port), &txconf);
-		if (retval < 0)
-			return retval;
-	}
-
-	/* Start the Ethernet port. */
-	retval = rte_eth_dev_start(port);
-	if (retval < 0)
-		return retval;
-
-	/* Display the port MAC address. */
-	struct ether_addr addr;
-	rte_eth_macaddr_get(port, &addr);
-	printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8
-			   " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n",
-			port,
-			addr.addr_bytes[0], addr.addr_bytes[1],
-			addr.addr_bytes[2], addr.addr_bytes[3],
-			addr.addr_bytes[4], addr.addr_bytes[5]);
-
-	/* Enable RX in promiscuous mode for the Ethernet device. */
-	rte_eth_promiscuous_enable(port);
-
-	return 0;
-}
-
-/*
- * The lcore main. This is the main thread that does the work, reading from
- * an input port and writing to an output port.
- */
-static __attribute__((noreturn)) void
-lcore_main(void)
-{
-	uint16_t port;
-
-	/*
-	 * Check that the port is on the same NUMA node as the polling thread
-	 * for best performance.
-	 */
-	RTE_ETH_FOREACH_DEV(port)
-		if (rte_eth_dev_socket_id(port) > 0 &&
-				rte_eth_dev_socket_id(port) !=
-						(int)rte_socket_id())
-			printf("WARNING, port %u is on remote NUMA node to "
-					"polling thread.\n\tPerformance will "
-					"not be optimal.\n", port);
-
-	printf("\nCore %u forwarding packets. [Ctrl+C to quit]\n",
-			rte_lcore_id());
-
-	/* Run until the application is quit or killed. */
-	for (;;) {
-		/*
-		 * Receive packets on a port and forward them on the paired
-		 * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
-		 */
-		RTE_ETH_FOREACH_DEV(port) {
-
-			/* Get burst of RX packets, from first port of pair. */
-			struct rte_mbuf *bufs[BURST_SIZE];
-			const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
-					bufs, BURST_SIZE);
-
-			if (unlikely(nb_rx == 0))
-				continue;
-
-			/* Send burst of TX packets, to second port of pair. */
-			const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0,
-					bufs, nb_rx);
-
-			/* Free any unsent packets. */
-			if (unlikely(nb_tx < nb_rx)) {
-				uint16_t buf;
-				for (buf = nb_tx; buf < nb_rx; buf++)
-					rte_pktmbuf_free(bufs[buf]);
-			}
-		}
-	}
-}
-
-/*
- * The main function, which does initialization and calls the per-lcore
- * functions.
- */
-int
-main(int argc, char *argv[])
-{
-	struct rte_mempool *mbuf_pool;
-	unsigned nb_ports;
-	uint16_t portid;
-
-	/* Initialize the Environment Abstraction Layer (EAL). */
-	int ret = rte_eal_init(argc, argv);
-	if (ret < 0)
-		rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
-
-	argc -= ret;
-	argv += ret;
-
-	/* Check that there is an even number of ports to send/receive on. */
-	nb_ports = rte_eth_dev_count_avail();
-	if (nb_ports < 2 || (nb_ports & 1))
-		rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n");
-
-	/* Creates a new mempool in memory to hold the mbufs. */
-	mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
-		MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
-
-	if (mbuf_pool == NULL)
-		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
-
-	/* Initialize all ports. */
-	RTE_ETH_FOREACH_DEV(portid)
-		if (port_init(portid, mbuf_pool) != 0)
-			rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu16 "\n",
-					portid);
-
-	if (rte_lcore_count() > 1)
-		printf("\nWARNING: Too many lcores enabled. Only 1 used.\n");
-
-	/* Call lcore_main on the master core only. */
-	lcore_main();
-
-	return 0;
-}
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 8a4f0f4..32e88b5 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -196,6 +196,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC)      += -lrte_pmd_softnic
 endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD)    += -lrte_pmd_sfc_efx
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2 -lsze2
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NFB)        += -lrte_pmd_nfb -lnfb -lfdt
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_TAP)        += -lrte_pmd_tap
 _LDLIBS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += -lrte_pmd_thunderx_nicvf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD) += -lrte_pmd_vdev_netvsc
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH] net/nfb: new netcope driver
  2019-02-26 12:57 ` [dpdk-dev] [PATCH] net/nfb: new netcope driver Rastislav Cernay
@ 2019-02-26 14:20   ` Rami Rosen
  2019-02-26 16:33     ` Rastislav Černay
  2019-02-26 15:46   ` Stephen Hemminger
                     ` (7 subsequent siblings)
  8 siblings, 1 reply; 50+ messages in thread
From: Rami Rosen @ 2019-02-26 14:20 UTC (permalink / raw)
  To: Rastislav Cernay; +Cc: dev

Hi, Cernay,

> delete mode 100644 examples/skeleton/basicfwd.c

It seems that this patch deletes examples/skeleton/basicfwd.c,
(instead of patching it ?!),  maybe by mistake.

Reviewed-by: Rami Rosen <ramirose at gmail.com>

Rami Rosen

On Tue, Feb 26, 2019 at 3:04 PM Rastislav Cernay <cernay@netcope.com> wrote:

> From: Rastislav Cernay <cernay@netcope.com>
>
> Added new net driver for Netcope nfb cards
>
> Signed-off-by: Rastislav Cernay <cernay@netcope.com>
> ---
>  MAINTAINERS                      |   7 +
>  config/common_base               |   4 +
>  devtools/test-build.sh           |   1 +
>  doc/guides/nics/features/nfb.ini |  17 ++
>  doc/guides/nics/nfb.rst          | 141 ++++++++++
>  drivers/net/Makefile             |   1 +
>  drivers/net/meson.build          |   1 +
>  drivers/net/nfb/Makefile         |  41 +++
>  drivers/net/nfb/meson.build      |   9 +
>  drivers/net/nfb/nfb.h            |  51 ++++
>  drivers/net/nfb/nfb_ethdev.c     | 586
> +++++++++++++++++++++++++++++++++++++++
>  drivers/net/nfb/nfb_rx.c         | 127 +++++++++
>  drivers/net/nfb/nfb_rx.h         | 226 +++++++++++++++
>  drivers/net/nfb/nfb_rxmode.c     | 104 +++++++
>  drivers/net/nfb/nfb_rxmode.h     |  81 ++++++
>  drivers/net/nfb/nfb_stats.c      |  79 ++++++
>  drivers/net/nfb/nfb_stats.h      |  52 ++++
>  drivers/net/nfb/nfb_tx.c         | 112 ++++++++
>  drivers/net/nfb/nfb_tx.h         | 209 ++++++++++++++
>  examples/skeleton/basicfwd.c     | 198 -------------
>  mk/rte.app.mk                    |   1 +
>  21 files changed, 1850 insertions(+), 198 deletions(-)
>  create mode 100644 doc/guides/nics/features/nfb.ini
>  create mode 100644 doc/guides/nics/nfb.rst
>  create mode 100644 drivers/net/nfb/Makefile
>  create mode 100644 drivers/net/nfb/meson.build
>  create mode 100644 drivers/net/nfb/nfb.h
>  create mode 100644 drivers/net/nfb/nfb_ethdev.c
>  create mode 100644 drivers/net/nfb/nfb_rx.c
>  create mode 100644 drivers/net/nfb/nfb_rx.h
>  create mode 100644 drivers/net/nfb/nfb_rxmode.c
>  create mode 100644 drivers/net/nfb/nfb_rxmode.h
>  create mode 100644 drivers/net/nfb/nfb_stats.c
>  create mode 100644 drivers/net/nfb/nfb_stats.h
>  create mode 100644 drivers/net/nfb/nfb_tx.c
>  create mode 100644 drivers/net/nfb/nfb_tx.h
>  delete mode 100644 examples/skeleton/basicfwd.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 6610440..c6bffde 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -654,6 +654,13 @@ F: drivers/net/szedata2/
>  F: doc/guides/nics/szedata2.rst
>  F: doc/guides/nics/features/szedata2.ini
>
> +Netcope nfb
> +M: Rastislav Cernay <cernay@netcope.com>
> +M: Jan Remes <remes@netcope.com>
> +F: drivers/net/nfb/
> +F: doc/guides/nics/nfb.rst
> +F: doc/guides/nics/features/nfb.ini
> +
>  Netronome nfp
>  M: Alejandro Lucero <alejandro.lucero@netronome.com>
>  F: drivers/net/nfp/
> diff --git a/config/common_base b/config/common_base
> index 7c6da51..1ab0a6b 100644
> --- a/config/common_base
> +++ b/config/common_base
> @@ -360,6 +360,10 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
>  # Compile software PMD backed by SZEDATA2 device
>  #
>  CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
> +#
> +# Compile software PMD backed by NFB device
> +#
> +CONFIG_RTE_LIBRTE_PMD_NFB=n
>
>  #
>  # Compile burst-oriented Cavium Thunderx NICVF PMD driver
> diff --git a/devtools/test-build.sh b/devtools/test-build.sh
> index 42f4ad0..ab57ab8 100755
> --- a/devtools/test-build.sh
> +++ b/devtools/test-build.sh
> @@ -18,6 +18,7 @@ default_path=$PATH
>  # - DPDK_DEP_SSL (y/[n])
>  # - DPDK_DEP_IPSEC_MB (y/[n])
>  # - DPDK_DEP_SZE (y/[n])
> +# - DPDK_DEP_NFB (y/[n])
>  # - DPDK_DEP_ZLIB (y/[n])
>  # - DPDK_MAKE_JOBS (int)
>  # - DPDK_NOTIFY (notify-send)
> diff --git a/doc/guides/nics/features/nfb.ini
> b/doc/guides/nics/features/nfb.ini
> new file mode 100644
> index 0000000..6174d65
> --- /dev/null
> +++ b/doc/guides/nics/features/nfb.ini
> @@ -0,0 +1,17 @@
> +;
> +; Supported features of the 'nfb' network poll mode driver.
> +;
> +; Refer to default.ini for the full list of available PMD features.
> +;
> +[Features]
> +Speed capabilities   = P
> +Link status          = Y
> +Queue start/stop     = Y
> +Promiscuous mode     = Y
> +Allmulticast mode    = Y
> +Basic stats          = Y
> +Extended stats       = Y
> +Stats per queue      = Y
> +Other kdrv           = Y
> +x86-64               = Y
> +Usage doc            = Y
> diff --git a/doc/guides/nics/nfb.rst b/doc/guides/nics/nfb.rst
> new file mode 100644
> index 0000000..9057d41
> --- /dev/null
> +++ b/doc/guides/nics/nfb.rst
> @@ -0,0 +1,141 @@
> +..  SPDX-License-Identifier: BSD-3-Clause
> +    Copyright 2015 - 2016 CESNET
> +
> +NFB poll mode driver library
> +=================================
> +
> +The NFB poll mode driver library implements support for the Netcope
> +FPGA Boards (**NFB-***), FPGA-based programmable NICs.
> +The NFB PMD uses interface provided by the libnfb library to communicate
> +with the NFB cards over the nfb layer.
> +
> +More information about the
> +`NFB cards <http://www.netcope.com/en/products/fpga-boards>`_
> +and used technology
> +(`Netcope Development Kit <
> http://www.netcope.com/en/products/fpga-development-kit>`_)
> +can be found on the `Netcope Technologies website <
> http://www.netcope.com/>`_.
> +
> +.. note::
> +
> +   This driver has external dependencies.
> +   Therefore it is disabled in default configuration files.
> +   It can be enabled by setting ``CONFIG_RTE_LIBRTE_PMD_NFB=y``
> +   and recompiling.
> +
> +.. note::
> +
> +   Currently the driver is supported only on x86_64 architectures.
> +   Only x86_64 versions of the external libraries are provided.
> +
> +Prerequisites
> +-------------
> +
> +This PMD requires kernel modules which are responsible for initialization
> and
> +allocation of resources needed for nfb layer function.
> +Communication between PMD and kernel modules is mediated by libnfb
> library.
> +These kernel modules and library are not part of DPDK and must be
> installed
> +separately:
> +
> +*  **libnfb library**
> +
> +   The library provides API for initialization of nfb transfers,
> receiving and
> +   transmitting data segments.
> +
> +*  **Kernel modules**
> +
> +   * nfb
> +
> +   Kernel modules manage initialization of hardware, allocation and
> +   sharing of resources for user space applications.
> +
> +Dependencies can be found here:
> +`Netcope common <
> https://drive.google.com/file/d/13khqS312KzrRSrgGxD0CBSmd1YLJHWp8>`_.
> +
> +Versions of the packages
> +~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +The minimum version of the provided packages:
> +
> +* for DPDK from 19.02
> +
> +Configuration
> +-------------
> +
> +These configuration options can be modified before compilation in the
> +``.config`` file:
> +
> +*  ``CONFIG_RTE_LIBRTE_PMD_NFB`` default value: **n**
> +
> +   Value **y** enables compilation of nfb PMD.
> +
> +Using the NFB PMD
> +----------------------
> +
> +Kernel modules have to be loaded before running the DPDK application.
> +
> +NFB card architecture
> +---------------------
> +
> +The NFB cards are multi-port multi-queue cards, where (generally) data
> from any
> +Ethernet port may be sent to any queue.
> +They are represented in DPDK as a single port.
> +
> +NFB-200G2QL card employs an addon cable which allows to connect it to two
> +physical PCI-E slots at the same time (see the diagram below).
> +This is done to allow 200 Gbps of traffic to be transferred through the
> PCI-E
> +bus (note that a single PCI-E 3.0 x16 slot provides only 125 Gbps
> theoretical
> +throughput).
> +
> +Although each slot may be connected to a different CPU and therefore to a
> different
> +NUMA node, the card is represented as a single port in DPDK. To work with
> data
> +from the individual queues on the right NUMA node, connection of NUMA
> nodes on
> +first and last queue (each NUMA node has half of the queues) need to be
> checked.
> +
> +.. figure:: img/szedata2_nfb200g_architecture.svg
> +    :align: center
> +
> +    NFB-200G2QL high-level diagram
> +
> +Limitations
> +-----------
> +
> +Since a card is always represented as a single port, but can be connected
> to two
> +NUMA nodes, there is need for manual check where master/slave is
> connected.
> +
> +Example of usage
> +----------------
> +
> +Read packets from 0. and 1. receive queue and write them to 0. and 1.
> +transmit queue:
> +
> +.. code-block:: console
> +
> +   $RTE_TARGET/app/testpmd -l 0-3 -n 2 \
> +   -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2 -i -a
> +
> +Example output:
> +
> +.. code-block:: console
> +
> +   [...]
> +   EAL: PCI device 0000:06:00.0 on NUMA socket -1
> +   EAL:   probe driver: 1b26:c1c1 net_nfb
> +   PMD: Initializing NFB device (0000:06:00.0)
> +   PMD: Available DMA queues RX: 8 TX: 8
> +   PMD: NFB device (0000:06:00.0) successfully initialized
> +   Interactive-mode selected
> +   Auto-start selected
> +   Configuring Port 0 (socket 0)
> +   Port 0: 00:11:17:00:00:00
> +   Checking link statuses...
> +   Port 0 Link Up - speed 10000 Mbps - full-duplex
> +   Done
> +   Start automatic packet forwarding
> +     io packet forwarding - CRC stripping disabled - packets/burst=32
> +     nb forwarding cores=2 - nb forwarding ports=1
> +     RX queues=2 - RX desc=128 - RX free threshold=0
> +     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
> +     TX queues=2 - TX desc=512 - TX free threshold=0
> +     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
> +     TX RS bit threshold=0 - TXQ flags=0x0
> +   testpmd>
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index 670d7f7..013c551 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -38,6 +38,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5
>  DIRS-$(CONFIG_RTE_LIBRTE_MVNETA_PMD) += mvneta
>  DIRS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mvpp2
>  DIRS-$(CONFIG_RTE_LIBRTE_NETVSC_PMD) += netvsc
> +DIRS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb
>  DIRS-$(CONFIG_RTE_LIBRTE_NFP_PMD) += nfp
>  DIRS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt
>  DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += null
> diff --git a/drivers/net/meson.build b/drivers/net/meson.build
> index 45da3bb..6733a19 100644
> --- a/drivers/net/meson.build
> +++ b/drivers/net/meson.build
> @@ -27,6 +27,7 @@ drivers = ['af_packet',
>         'mvneta',
>         'mvpp2',
>         'netvsc',
> +       'nfb',
>         'nfp',
>         'null', 'octeontx', 'pcap', 'qede', 'ring',
>         'sfc',
> diff --git a/drivers/net/nfb/Makefile b/drivers/net/nfb/Makefile
> new file mode 100644
> index 0000000..ee8c7df
> --- /dev/null
> +++ b/drivers/net/nfb/Makefile
> @@ -0,0 +1,41 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2018 Cesnet
> +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> +# All rights reserved.
> +
> +include $(RTE_SDK)/mk/rte.vars.mk
> +
> +#
> +# library name
> +#
> +LIB = librte_pmd_nfb.a
> +
> +INCLUDES :=-I$(SRCDIR)
> +
> +
> +CFLAGS += -O3
> +CFLAGS += $(WERROR_FLAGS)
> +LDLIBS += -lnfb
> +LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
> +LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
> +LDLIBS += -lrte_bus_pci
> +
> +EXPORT_MAP := rte_pmd_nfb_version.map
> +
> +LIBABIVER := 1
> +
> +#
> +# all source are stored in SRCS-y
> +#
> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_ethdev.c
> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_rx.c
> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_tx.c
> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_stats.c
> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_rxmode.c
> +
> +#
> +# Export include files
> +#
> +SYMLINK-y-include +=
> +
> +include $(RTE_SDK)/mk/rte.lib.mk
> diff --git a/drivers/net/nfb/meson.build b/drivers/net/nfb/meson.build
> new file mode 100644
> index 0000000..d7dccba
> --- /dev/null
> +++ b/drivers/net/nfb/meson.build
> @@ -0,0 +1,9 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2018 Cesnet
> +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> +# All rights reserved.
> +
> +dep = cc.find_library('nfb', required: true)
> +build = dep.found()
> +ext_deps += dep
> +sources = files('nfb_rx.c', 'nfb_tx.c', 'nfb_stats.c', 'nfb_ethdev.c',
> 'nfb_rxmode.c')
> diff --git a/drivers/net/nfb/nfb.h b/drivers/net/nfb/nfb.h
> new file mode 100644
> index 0000000..d032ba4
> --- /dev/null
> +++ b/drivers/net/nfb/nfb.h
> @@ -0,0 +1,51 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Cesnet
> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> + * All rights reserved.
> + */
> +
> +#ifndef _NFB_H_
> +#define _NFB_H_
> +
> +#include <nfb/nfb.h>
> +#include <nfb/ndp.h>
> +#include <netcope/rxmac.h>
> +#include <netcope/txmac.h>
> +
> +#include "nfb_rx.h"
> +#include "nfb_tx.h"
> +
> +/* PCI Vendor ID */
> +#define PCI_VENDOR_ID_NETCOPE 0x1b26
> +
> +/* PCI Device IDs */
> +#define PCI_DEVICE_ID_NFB_40G2  0xcb80
> +#define PCI_DEVICE_ID_NFB_100G2 0xc2c1
> +#define PCI_DEVICE_ID_NFB_200G2QL 0xc250
> +
> +/* Max index of ndp rx/tx queues */
> +#define RTE_ETH_NDP_MAX_RX_QUEUES 32
> +#define RTE_ETH_NDP_MAX_TX_QUEUES 32
> +
> +/* Max index of rx/tx dmas */
> +#define RTE_MAX_NC_RXMAC 256
> +#define RTE_MAX_NC_TXMAC 256
> +
> +#define RTE_NFB_DRIVER_NAME net_nfb
> +
> +struct pmd_internals {
> +       uint16_t         max_rxmac;
> +       uint16_t         max_txmac;
> +       struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC];
> +       struct nc_txmac *txmac[RTE_MAX_NC_TXMAC];
> +
> +       char             nfb_dev[PATH_MAX];
> +       struct nfb_device *nfb;
> +       /* Place to remember if filter was promiscous or filtering by
> table,
> +        * when disabling allmulticast
> +        */
> +       enum nc_rxmac_mac_filter rx_filter_original;
> +};
> +
> +
> +#endif /* _NFB_H_ */
> diff --git a/drivers/net/nfb/nfb_ethdev.c b/drivers/net/nfb/nfb_ethdev.c
> new file mode 100644
> index 0000000..c8d546f
> --- /dev/null
> +++ b/drivers/net/nfb/nfb_ethdev.c
> @@ -0,0 +1,586 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Cesnet
> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> + * All rights reserved.
> + */
> +
> +#include <stdint.h>
> +#include <unistd.h>
> +#include <stdbool.h>
> +#include <err.h>
> +#include <sys/types.h>
> +#include <dirent.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <sys/mman.h>
> +
> +#include <nfb/nfb.h>
> +#include <nfb/ndp.h>
> +#include <netcope/rxmac.h>
> +#include <netcope/txmac.h>
> +
> +#include <rte_mbuf.h>
> +#include <rte_ethdev.h>
> +#include <rte_ethdev_pci.h>
> +#include <rte_malloc.h>
> +#include <rte_memcpy.h>
> +#include <rte_kvargs.h>
> +#include <rte_dev.h>
> +#include <rte_common.h>
> +
> +#include "nfb_stats.h"
> +#include "nfb_rx.h"
> +#include "nfb_tx.h"
> +#include "nfb_rxmode.h"
> +#include "nfb.h"
> +
> +/**
> + * Default MAC addr
> + */
> +static struct ether_addr eth_addr = {
> +       .addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
> +};
> +
> +/**
> + * Open all RX DMA queues
> + *
> + * @param dev
> + *   Pointer to nfb device.
> + * @param[out] rxmac
> + *   Pointer to output array of nc_rxmac
> + * @param[out] max_rxmac
> + *   Pointer to output max index of rxmac
> + */
> +static void
> +nfb_nc_rxmac_init(struct nfb_device *nfb,
> +       struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
> +       uint16_t *max_rxmac)
> +{
> +       *max_rxmac = 0;
> +       while ((rxmac[*max_rxmac] = nc_rxmac_open_index(nfb, *max_rxmac)))
> +               ++(*max_rxmac);
> +}
> +
> +/**
> + * Open all TX DMA queues
> + *
> + * @param dev
> + *   Pointer to nfb device.
> + * @param[out] txmac
> + *   Pointer to output array of nc_txmac
> + * @param[out] max_rxmac
> + *   Pointer to output max index of txmac
> + */
> +static void
> +nfb_nc_txmac_init(struct nfb_device *nfb,
> +       struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
> +       uint16_t *max_txmac)
> +{
> +       *max_txmac = 0;
> +       while ((txmac[*max_txmac] = nc_txmac_open_index(nfb, *max_txmac)))
> +               ++(*max_txmac);
> +}
> +
> +/**
> + * Close all RX DMA queues
> + *
> + * @param rxmac
> + *   Pointer to array of nc_rxmac
> + * @param max_rxmac
> + *   Maximum index of rxmac
> + */
> +static void
> +nfb_nc_rxmac_deinit(struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
> +       uint16_t max_rxmac)
> +{
> +       for (; max_rxmac > 0; --max_rxmac) {
> +               nc_rxmac_close(rxmac[max_rxmac]);
> +               rxmac[max_rxmac] = NULL;
> +       }
> +}
> +
> +/**
> + * Close all TX DMA queues
> + *
> + * @param txmac
> + *   Pointer to array of nc_txmac
> + * @param max_txmac
> + *   Maximum index of txmac
> + */
> +static void
> +nfb_nc_txmac_deinit(struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
> +       uint16_t max_txmac)
> +{
> +       for (; max_txmac > 0; --max_txmac) {
> +               nc_txmac_close(txmac[max_txmac]);
> +               txmac[max_txmac] = NULL;
> +       }
> +}
> +
> +/**
> + * DPDK callback to start the device.
> + *
> + * Start device by starting all configured queues.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +static int
> +nfb_eth_dev_start(struct rte_eth_dev *dev)
> +{
> +       int ret;
> +       uint16_t i;
> +       uint16_t nb_rx = dev->data->nb_rx_queues;
> +       uint16_t nb_tx = dev->data->nb_tx_queues;
> +
> +       for (i = 0; i < nb_rx; i++) {
> +               ret = nfb_eth_rx_queue_start(dev, i);
> +               if (ret != 0)
> +                       goto err_rx;
> +       }
> +
> +       for (i = 0; i < nb_tx; i++) {
> +               ret = nfb_eth_tx_queue_start(dev, i);
> +               if (ret != 0)
> +                       goto err_tx;
> +       }
> +
> +       return 0;
> +
> +err_tx:
> +       for (i = 0; i < nb_tx; i++)
> +               nfb_eth_tx_queue_stop(dev, i);
> +err_rx:
> +       for (i = 0; i < nb_rx; i++)
> +               nfb_eth_rx_queue_stop(dev, i);
> +       return ret;
> +}
> +
> +/**
> + * DPDK callback to stop the device.
> + *
> + * Stop device by stopping all configured queues.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + */
> +static void
> +nfb_eth_dev_stop(struct rte_eth_dev *dev)
> +{
> +       uint16_t i;
> +       uint16_t nb_rx = dev->data->nb_rx_queues;
> +       uint16_t nb_tx = dev->data->nb_tx_queues;
> +
> +       for (i = 0; i < nb_tx; i++)
> +               nfb_eth_tx_queue_stop(dev, i);
> +
> +       for (i = 0; i < nb_rx; i++)
> +               nfb_eth_rx_queue_stop(dev, i);
> +}
> +
> +/**
> + * DPDK callback for Ethernet device configuration.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +static int
> +nfb_eth_dev_configure(struct rte_eth_dev *dev)
> +{
> +       dev->rx_pkt_burst = nfb_eth_ndp_rx;
> +       return 0;
> +}
> +
> +/**
> + * DPDK callback to get information about the device.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + * @param[out] info
> + *   Info structure output buffer.
> + */
> +static void
> +nfb_eth_dev_info(struct rte_eth_dev *dev,
> +       struct rte_eth_dev_info *dev_info)
> +{
> +       dev_info->if_index = 0;
> +       dev_info->max_mac_addrs = 1;
> +       dev_info->max_rx_pktlen = (uint32_t)-1;
> +       dev_info->max_rx_queues = dev->data->nb_rx_queues;
> +       dev_info->max_tx_queues = dev->data->nb_tx_queues;
> +       dev_info->min_rx_bufsize = 0;
> +       dev_info->speed_capa = ETH_LINK_SPEED_100G;
> +}
> +
> +/**
> + * DPDK callback to close the device.
> + *
> + * Destroy all queues and objects, free memory.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + */
> +static void
> +nfb_eth_dev_close(struct rte_eth_dev *dev)
> +{
> +       uint16_t i;
> +       uint16_t nb_rx = dev->data->nb_rx_queues;
> +       uint16_t nb_tx = dev->data->nb_tx_queues;
> +
> +       nfb_eth_dev_stop(dev);
> +
> +       for (i = 0; i < nb_rx; i++) {
> +               nfb_eth_rx_queue_release(dev->data->rx_queues[i]);
> +               dev->data->rx_queues[i] = NULL;
> +       }
> +       dev->data->nb_rx_queues = 0;
> +       for (i = 0; i < nb_tx; i++) {
> +               nfb_eth_tx_queue_release(dev->data->tx_queues[i]);
> +               dev->data->tx_queues[i] = NULL;
> +       }
> +       dev->data->nb_tx_queues = 0;
> +}
> +
> +/**
> + * DPDK callback to retrieve physical link information.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + * @param[out] link
> + *   Storage for current link status.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +static int
> +nfb_eth_link_update(struct rte_eth_dev *dev,
> +       int wait_to_complete __rte_unused)
> +{
> +       uint16_t i;
> +       struct rte_eth_link link;
> +       memset(&link, 0, sizeof(link));
> +
> +       struct pmd_internals *internals = (struct pmd_internals *)
> +               dev->data->dev_private;
> +
> +       struct nc_rxmac_status status;
> +       status.speed = MAC_SPEED_UNKNOWN;
> +
> +       link.link_speed = ETH_SPEED_NUM_NONE;
> +       link.link_status = ETH_LINK_DOWN;
> +       link.link_duplex = ETH_LINK_FULL_DUPLEX;
> +       link.link_autoneg = ETH_LINK_SPEED_FIXED;
> +
> +       if (internals->rxmac[0] != NULL) {
> +               nc_rxmac_read_status(internals->rxmac[0], &status);
> +
> +               switch (status.speed) {
> +               case MAC_SPEED_10G:
> +                       link.link_speed = ETH_SPEED_NUM_10G;
> +                       break;
> +               case MAC_SPEED_40G:
> +                       link.link_speed = ETH_SPEED_NUM_40G;
> +                       break;
> +               case MAC_SPEED_100G:
> +                       link.link_speed = ETH_SPEED_NUM_100G;
> +                       break;
> +               default:
> +                       link.link_speed = ETH_SPEED_NUM_NONE;
> +                       break;
> +               }
> +       }
> +
> +       i = 0;
> +       for (i = 0; i < internals->max_rxmac; ++i) {
> +               nc_rxmac_read_status(internals->rxmac[i], &status);
> +
> +               if (status.enabled && status.link_up) {
> +                       link.link_status = ETH_LINK_UP;
> +                       break;
> +               }
> +       }
> +
> +       rte_eth_linkstatus_set(dev, &link);
> +
> +       return 0;
> +}
> +
> +/**
> + * DPDK callback to bring the link UP.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +static int
> +nfb_eth_dev_set_link_up(struct rte_eth_dev *dev)
> +{
> +       struct pmd_internals *internals = (struct pmd_internals *)
> +               dev->data->dev_private;
> +
> +       uint16_t i;
> +       for (i = 0; i < internals->max_rxmac; ++i)
> +               nc_rxmac_enable(internals->rxmac[i]);
> +
> +       for (i = 0; i < internals->max_txmac; ++i)
> +               nc_txmac_enable(internals->txmac[i]);
> +
> +       return 0;
> +}
> +
> +/**
> + * DPDK callback to bring the link DOWN.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +static int
> +nfb_eth_dev_set_link_down(struct rte_eth_dev *dev)
> +{
> +       struct pmd_internals *internals = (struct pmd_internals *)
> +               dev->data->dev_private;
> +
> +       uint16_t i;
> +       for (i = 0; i < internals->max_rxmac; ++i)
> +               nc_rxmac_disable(internals->rxmac[i]);
> +
> +       for (i = 0; i < internals->max_txmac; ++i)
> +               nc_txmac_disable(internals->txmac[i]);
> +
> +       return 0;
> +}
> +
> +/**
> + * DPDK callback to set primary MAC address.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + * @param mac_addr
> + *   MAC address to register.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +static int
> +nfb_eth_mac_addr_set(struct rte_eth_dev *dev __rte_unused,
> +       struct ether_addr *mac_addr __rte_unused)
> +{
> +       return 0;
> +}
> +
> +static const struct eth_dev_ops ops = {
> +       .dev_start = nfb_eth_dev_start,
> +       .dev_stop = nfb_eth_dev_stop,
> +       .dev_set_link_up = nfb_eth_dev_set_link_up,
> +       .dev_set_link_down = nfb_eth_dev_set_link_down,
> +       .dev_close = nfb_eth_dev_close,
> +       .dev_configure = nfb_eth_dev_configure,
> +       .dev_infos_get = nfb_eth_dev_info,
> +       .promiscuous_enable = nfb_eth_promiscuous_enable,
> +       .promiscuous_disable = nfb_eth_promiscuous_disable,
> +       .allmulticast_enable = nfb_eth_allmulticast_enable,
> +       .allmulticast_disable = nfb_eth_allmulticast_disable,
> +       .rx_queue_start = nfb_eth_rx_queue_start,
> +       .rx_queue_stop = nfb_eth_rx_queue_stop,
> +       .tx_queue_start = nfb_eth_tx_queue_start,
> +       .tx_queue_stop = nfb_eth_tx_queue_stop,
> +       .rx_queue_setup = nfb_eth_rx_queue_setup,
> +       .tx_queue_setup = nfb_eth_tx_queue_setup,
> +       .rx_queue_release = nfb_eth_rx_queue_release,
> +       .tx_queue_release = nfb_eth_tx_queue_release,
> +       .link_update = nfb_eth_link_update,
> +       .stats_get = nfb_eth_stats_get,
> +       .stats_reset = nfb_eth_stats_reset,
> +       .mac_addr_set = nfb_eth_mac_addr_set,
> +};
> +
> +/**
> + * DPDK callback to initialize an ethernet device
> + *
> + * @param dev
> + *   Pointer to ethernet device structure
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +static int
> +nfb_eth_dev_init(struct rte_eth_dev *dev)
> +{
> +       struct rte_eth_dev_data *data = dev->data;
> +       struct pmd_internals *internals = (struct pmd_internals *)
> +               data->dev_private;
> +       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
> +       struct rte_pci_addr *pci_addr = &pci_dev->addr;
> +
> +       RTE_LOG(INFO, PMD, "Initializing NFB device (" PCI_PRI_FMT ")\n",
> +               pci_addr->domain, pci_addr->bus, pci_addr->devid,
> +               pci_addr->function);
> +
> +       snprintf(internals->nfb_dev, PATH_MAX,
> +               "/dev/nfb/by-pci-slot/" PCI_PRI_FMT,
> +               pci_addr->domain, pci_addr->bus, pci_addr->devid,
> +               pci_addr->function);
> +
> +       /*
> +        * Get number of available DMA RX and TX queues, which is maximum
> +        * number of queues that can be created and store it in private
> device
> +        * data structure.
> +        */
> +       internals->nfb = nfb_open(internals->nfb_dev);
> +       if (internals->nfb == NULL) {
> +               RTE_LOG(ERR, PMD, "nfb_open(): failed to open %s",
> +                       internals->nfb_dev);
> +               return -EINVAL;
> +       }
> +       data->nb_rx_queues =
> ndp_get_rx_queue_available_count(internals->nfb);
> +       data->nb_tx_queues =
> ndp_get_tx_queue_available_count(internals->nfb);
> +
> +       RTE_LOG(INFO, PMD, "Available NDP queues RX: %u TX: %u\n",
> +               data->nb_rx_queues, data->nb_tx_queues);
> +
> +       nfb_nc_rxmac_init(internals->nfb,
> +               internals->rxmac,
> +               &internals->max_rxmac);
> +       nfb_nc_txmac_init(internals->nfb,
> +               internals->txmac,
> +               &internals->max_txmac);
> +
> +       /* Set rx, tx burst functions */
> +       dev->rx_pkt_burst = nfb_eth_ndp_rx;
> +       dev->tx_pkt_burst = nfb_eth_ndp_tx;
> +
> +       /* Set function callbacks for Ethernet API */
> +       dev->dev_ops = &ops;
> +
> +       rte_eth_copy_pci_info(dev, pci_dev);
> +
> +       /* Get link state */
> +       nfb_eth_link_update(dev, 0);
> +
> +       /* Allocate space for one mac address */
> +       data->mac_addrs = rte_zmalloc(data->name, sizeof(struct
> ether_addr),
> +               RTE_CACHE_LINE_SIZE);
> +       if (data->mac_addrs == NULL) {
> +               RTE_LOG(ERR, PMD, "Could not alloc space for MAC
> address!\n");
> +               nfb_close(internals->nfb);
> +               return -EINVAL;
> +       }
> +
> +       ether_addr_copy(&eth_addr, data->mac_addrs);
> +
> +       data->promiscuous = nfb_eth_promiscuous_get(dev);
> +       data->all_multicast = nfb_eth_allmulticast_get(dev);
> +       internals->rx_filter_original = data->promiscuous;
> +
> +       RTE_LOG(INFO, PMD, "NFB device ("
> +               PCI_PRI_FMT ") successfully initialized\n",
> +               pci_addr->domain, pci_addr->bus, pci_addr->devid,
> +               pci_addr->function);
> +
> +       return 0;
> +}
> +
> +/**
> + * DPDK callback to uninitialize an ethernet device
> + *
> + * @param dev
> + *   Pointer to ethernet device structure
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +static int
> +nfb_eth_dev_uninit(struct rte_eth_dev *dev)
> +{
> +       struct rte_eth_dev_data *data = dev->data;
> +       struct pmd_internals *internals = (struct pmd_internals *)
> +               data->dev_private;
> +
> +       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
> +       struct rte_pci_addr *pci_addr = &pci_dev->addr;
> +
> +       rte_free(dev->data->mac_addrs);
> +       dev->data->mac_addrs = NULL;
> +
> +       nfb_nc_rxmac_deinit(internals->rxmac, internals->max_rxmac);
> +       nfb_nc_txmac_deinit(internals->txmac, internals->max_txmac);
> +
> +       RTE_LOG(INFO, PMD, "NFB device ("
> +               PCI_PRI_FMT ") successfully uninitialized\n",
> +               pci_addr->domain, pci_addr->bus, pci_addr->devid,
> +               pci_addr->function);
> +
> +       return 0;
> +}
> +
> +static const struct rte_pci_id nfb_pci_id_table[] = {
> +       {
> +               RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE,
> PCI_DEVICE_ID_NFB_40G2)
> +       },
> +       {
> +               RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE,
> PCI_DEVICE_ID_NFB_100G2)
> +       },
> +       {
> +               RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE,
> PCI_DEVICE_ID_NFB_200G2QL)
> +       },
> +       {
> +               .vendor_id = 0,
> +       }
> +};
> +
> +/**
> + * DPDK callback to register a PCI device.
> + *
> + * This function spawns Ethernet devices out of a given PCI device.
> + *
> + * @param[in] pci_drv
> + *   PCI driver structure (nfb_driver).
> + * @param[in] pci_dev
> + *   PCI device information.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +static int nfb_eth_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
> +       struct rte_pci_device *pci_dev)
> +{
> +       return rte_eth_dev_pci_generic_probe(pci_dev,
> +               sizeof(struct pmd_internals), nfb_eth_dev_init);
> +}
> +
> +/**
> + * DPDK callback to remove a PCI device.
> + *
> + * This function removes all Ethernet devices belong to a given PCI
> device.
> + *
> + * @param[in] pci_dev
> + *   Pointer to the PCI device.
> + *
> + * @return
> + *   0 on success, the function cannot fail.
> + */
> +static int nfb_eth_pci_remove(struct rte_pci_device *pci_dev)
> +{
> +       return rte_eth_dev_pci_generic_remove(pci_dev, nfb_eth_dev_uninit);
> +}
> +
> +static struct rte_pci_driver nfb_eth_driver = {
> +       .id_table = nfb_pci_id_table,
> +       .probe = nfb_eth_pci_probe,
> +       .remove = nfb_eth_pci_remove,
> +};
> +
> +RTE_PMD_REGISTER_PCI(RTE_NFB_DRIVER_NAME, nfb_eth_driver);
> +RTE_PMD_REGISTER_PCI_TABLE(RTE_NFB_DRIVER_NAME, nfb_pci_id_table);
> +RTE_PMD_REGISTER_KMOD_DEP(RTE_NFB_DRIVER_NAME, "* nfb");
> diff --git a/drivers/net/nfb/nfb_rx.c b/drivers/net/nfb/nfb_rx.c
> new file mode 100644
> index 0000000..dc1cd2d
> --- /dev/null
> +++ b/drivers/net/nfb/nfb_rx.c
> @@ -0,0 +1,127 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Cesnet
> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> + * All rights reserved.
> + */
> +
> +#include "nfb_rx.h"
> +#include "nfb.h"
> +
> +
> +int
> +nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id)
> +{
> +       struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
> +
> +       if (rxq->queue == NULL) {
> +               RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
> +               return -EINVAL;
> +       }
> +
> +       int ret = ndp_queue_start(rxq->queue);
> +       if (ret != 0)
> +               goto err;
> +       dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STARTED;
> +       return 0;
> +
> +err:
> +       return -EINVAL;
> +}
> +
> +
> +
> +int
> +nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id)
> +{
> +       struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
> +
> +       if (rxq->queue == NULL) {
> +               RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
> +               return -EINVAL;
> +       }
> +
> +       int ret = ndp_queue_stop(rxq->queue);
> +       if (ret != 0)
> +               return -EINVAL;
> +
> +       dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
> +       return 0;
> +}
> +
> +int
> +nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
> +               uint16_t rx_queue_id,
> +               uint16_t nb_rx_desc __rte_unused,
> +               unsigned int socket_id,
> +               const struct rte_eth_rxconf *rx_conf __rte_unused,
> +               struct rte_mempool *mb_pool)
> +{
> +       struct pmd_internals *internals = dev->data->dev_private;
> +
> +       struct ndp_rx_queue *rxq;
> +
> +       rxq = rte_zmalloc_socket("ndp rx queue",
> +                       sizeof(struct ndp_rx_queue),
> +                       RTE_CACHE_LINE_SIZE, socket_id);
> +
> +       if (rxq == NULL) {
> +               RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for rx
> queue id "
> +                               "%" PRIu16 "!\n", rx_queue_id);
> +               return -ENOMEM;
> +       }
> +
> +       int ret = nfb_eth_rx_queue_init(internals->nfb,
> +               rx_queue_id,
> +               dev->data->port_id,
> +               mb_pool,
> +               rxq);
> +
> +       if (ret == 0)
> +               dev->data->rx_queues[rx_queue_id] = rxq;
> +       else
> +               rte_free(rxq);
> +
> +       return ret;
> +}
> +
> +int
> +nfb_eth_rx_queue_init(struct nfb_device *nfb,
> +               uint16_t rx_queue_id,
> +               uint16_t port_id,
> +               struct rte_mempool *mb_pool,
> +               struct ndp_rx_queue *rxq)
> +{
> +       if (nfb == NULL)
> +               return -EINVAL;
> +
> +       rxq->queue = ndp_open_rx_queue(nfb, rx_queue_id);
> +       if (rxq->queue == NULL)
> +               return -EINVAL;
> +
> +       rxq->nfb = nfb;
> +       rxq->rx_queue_id = rx_queue_id;
> +       rxq->in_port = port_id;
> +       rxq->mb_pool = mb_pool;
> +
> +       const struct rte_pktmbuf_pool_private *mbp_priv =
> +               rte_mempool_get_priv(mb_pool);
> +       rxq->buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size -
> +               RTE_PKTMBUF_HEADROOM);
> +
> +       rxq->rx_pkts = 0;
> +       rxq->rx_bytes = 0;
> +       rxq->err_pkts = 0;
> +
> +       return 0;
> +}
> +
> +void
> +nfb_eth_rx_queue_release(void *q)
> +{
> +       struct ndp_rx_queue *rxq = (struct ndp_rx_queue *)q;
> +       if (rxq->queue != NULL) {
> +               ndp_close_rx_queue(rxq->queue);
> +               rte_free(rxq);
> +               rxq->queue = NULL;
> +       }
> +}
> diff --git a/drivers/net/nfb/nfb_rx.h b/drivers/net/nfb/nfb_rx.h
> new file mode 100644
> index 0000000..b356f5d
> --- /dev/null
> +++ b/drivers/net/nfb/nfb_rx.h
> @@ -0,0 +1,226 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Cesnet
> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> + * All rights reserved.
> + */
> +
> +
> +
> +#ifndef _NFB_RX_H_
> +#define _NFB_RX_H_
> +
> +#include <stdint.h>
> +#include <unistd.h>
> +#include <stdbool.h>
> +#include <err.h>
> +#include <sys/types.h>
> +
> +#include <sys/mman.h>
> +
> +#include <nfb/nfb.h>
> +#include <nfb/ndp.h>
> +
> +
> +#include <rte_mbuf.h>
> +#include <rte_ethdev.h>
> +#include <rte_malloc.h>
> +#include <rte_memcpy.h>
> +#include <rte_dev.h>
> +
> +struct ndp_rx_queue {
> +       struct nfb_device *nfb;      /* nfb dev structure */
> +       struct ndp_queue *queue;     /* rx queue */
> +       uint16_t rx_queue_id;        /* index */
> +       uint8_t in_port;             /* port */
> +
> +       struct rte_mempool *mb_pool; /* memory pool to allocate packets */
> +       uint16_t buf_size;           /* mbuf size */
> +
> +       volatile uint64_t rx_pkts;   /* packets read */
> +       volatile uint64_t rx_bytes;  /* bytes read */
> +       volatile uint64_t err_pkts;  /* erroneous packets */
> +};
> +
> +/**
> + * Initialize ndp_rx_queue structure
> + *
> + * @param nfb
> + *   Pointer to nfb device structure.
> + * @param rx_queue_id
> + *   RX queue index.
> + * @param port_id
> + *   Device [external] port identifier.
> + * @param mb_pool
> + *   Memory pool for buffer allocations.
> + * @param[out] rxq
> + *   Pointer to ndp_rx_queue output structure
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +int
> +nfb_eth_rx_queue_init(struct nfb_device *nfb,
> +       uint16_t rx_queue_id,
> +       uint16_t port_id,
> +       struct rte_mempool *mb_pool,
> +       struct ndp_rx_queue *rxq);
> +
> +
> +/**
> + * DPDK callback to setup a RX queue for use.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + * @param idx
> + *   RX queue index.
> + * @param desc
> + *   Number of descriptors to configure in queue.
> + * @param socket
> + *   NUMA socket on which memory must be allocated.
> + * @param[in] conf
> + *   Thresholds parameters.
> + * @param mb_pool
> + *   Memory pool for buffer allocations.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +int
> +nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
> +       uint16_t rx_queue_id,
> +       uint16_t nb_rx_desc __rte_unused,
> +       unsigned int socket_id,
> +       const struct rte_eth_rxconf *rx_conf __rte_unused,
> +       struct rte_mempool *mb_pool);
> +
> +
> +/**
> + * DPDK callback to release a RX queue.
> + *
> + * @param dpdk_rxq
> + *   Generic RX queue pointer.
> + */
> +void
> +nfb_eth_rx_queue_release(void *q);
> +
> +/**
> + * Start traffic on Rx queue.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + * @param txq_id
> + *   RX queue index.
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +int
> +nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id);
> +
> +/**
> + * Stop traffic on Rx queue.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + * @param txq_id
> + *   RX queue index.
> + */
> +int
> +nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id);
> +
> +/**
> + * DPDK callback for RX.
> + *
> + * @param dpdk_rxq
> + *   Generic pointer to RX queue structure.
> + * @param[out] bufs
> + *   Array to store received packets.
> + * @param nb_pkts
> + *   Maximum number of packets in array.
> + *
> + * @return
> + *   Number of packets successfully received (<= nb_pkts).
> + */
> +static __rte_always_inline uint16_t
> +nfb_eth_ndp_rx(void *queue,
> +       struct rte_mbuf **bufs,
> +       uint16_t nb_pkts)
> +{
> +       struct ndp_rx_queue *ndp = queue;
> +
> +       if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
> +               RTE_LOG(ERR, PMD, "RX invalid arguments!\n");
> +               return 0;
> +       }
> +
> +       struct rte_mbuf *mbufs[nb_pkts];
> +
> +       unsigned int i;
> +       // returns either all or nothing
> +       i = rte_pktmbuf_alloc_bulk(ndp->mb_pool, mbufs, nb_pkts);
> +       if (unlikely(i != 0))
> +               return 0;
> +
> +       uint16_t packet_size;
> +       uint64_t num_bytes = 0;
> +       const uint16_t buf_size = ndp->buf_size;
> +
> +       struct rte_mbuf *mbuf;
> +       struct ndp_packet packets[nb_pkts];
> +
> +
> +       uint16_t num_rx = ndp_rx_burst_get(ndp->queue, packets, nb_pkts);
> +
> +       if (unlikely(num_rx != nb_pkts)) {
> +               for (i = num_rx; i < nb_pkts; i++)
> +                       rte_pktmbuf_free(mbufs[i]);
> +       }
> +
> +       nb_pkts = num_rx;
> +
> +       num_rx = 0;
> +       /*
> +        * Reads the given number of packets from NDP queue given
> +        * by queue and copies the packet data into a newly allocated mbuf
> +        * to return.
> +        */
> +       for (i = 0; i < nb_pkts; ++i) {
> +               mbuf = mbufs[i];
> +
> +               /* get the space available for data in the mbuf */
> +               packet_size = packets[i].data_length;
> +
> +               if (likely(packet_size <= buf_size)) {
> +                       /* NDP packet will fit in one mbuf, go ahead and
> copy */
> +                       rte_memcpy(rte_pktmbuf_mtod(mbuf, void *),
> +                               packets[i].data, packet_size);
> +
> +                       mbuf->data_len = (uint16_t)packet_size;
> +
> +                       mbuf->pkt_len = packet_size;
> +                       mbuf->port = ndp->in_port;
> +                       bufs[num_rx++] = mbuf;
> +                       num_bytes += packet_size;
> +               } else {
> +                       /*
> +                        * NDP packet will not fit in one mbuf,
> +                        * scattered mode is not enabled, drop packet
> +                        */
> +                       RTE_LOG(ERR, PMD,
> +                               "NDP segment %d bytes will not fit in one
> mbuf "
> +                               "(%d bytes), scattered mode is not
> enabled, "
> +                               "drop packet!!\n",
> +                               packet_size, buf_size);
> +                       rte_pktmbuf_free(mbuf);
> +               }
> +       }
> +
> +
> +       ndp_rx_burst_put(ndp->queue);
> +
> +       ndp->rx_pkts += num_rx;
> +       ndp->rx_bytes += num_bytes;
> +       return num_rx;
> +}
> +
> +
> +
> +#endif /* _NFB_RX_H_ */
> diff --git a/drivers/net/nfb/nfb_rxmode.c b/drivers/net/nfb/nfb_rxmode.c
> new file mode 100644
> index 0000000..8a63507
> --- /dev/null
> +++ b/drivers/net/nfb/nfb_rxmode.c
> @@ -0,0 +1,104 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Cesnet
> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> + * All rights reserved.
> + */
> +
> +
> +#include "nfb_rxmode.h"
> +#include "nfb.h"
> +
> +void
> +nfb_eth_promiscuous_enable(struct rte_eth_dev *dev)
> +{
> +       struct pmd_internals *internals = (struct pmd_internals *)
> +               dev->data->dev_private;
> +
> +       internals->rx_filter_original = RXMAC_MAC_FILTER_PROMISCUOUS;
> +
> +
> +       uint16_t i;
> +       for (i = 0; i < internals->max_rxmac; ++i) {
> +               nc_rxmac_mac_filter_enable(internals->rxmac[i],
> +                       RXMAC_MAC_FILTER_PROMISCUOUS);
> +       }
> +}
> +
> +void
> +nfb_eth_promiscuous_disable(struct rte_eth_dev *dev)
> +{
> +       struct pmd_internals *internals = (struct pmd_internals *)
> +               dev->data->dev_private;
> +
> +       internals->rx_filter_original = RXMAC_MAC_FILTER_TABLE;
> +
> +
> +       // if promisc is not enabled, do nothing
> +       if (!nfb_eth_promiscuous_get(dev))
> +               return;
> +
> +       uint16_t i;
> +       for (i = 0; i < internals->max_rxmac; ++i) {
> +               nc_rxmac_mac_filter_enable(internals->rxmac[i],
> +                       RXMAC_MAC_FILTER_TABLE);
> +       }
> +}
> +
> +int
> +nfb_eth_promiscuous_get(struct rte_eth_dev *dev)
> +{
> +       struct pmd_internals *internals = (struct pmd_internals *)
> +               dev->data->dev_private;
> +
> +       struct nc_rxmac_status status;
> +       status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
> +
> +       nc_rxmac_read_status(internals->rxmac[0], &status);
> +
> +       return (status.mac_filter == RXMAC_MAC_FILTER_PROMISCUOUS);
> +}
> +
> +void
> +nfb_eth_allmulticast_enable(struct rte_eth_dev *dev)
> +{
> +       struct pmd_internals *internals = (struct pmd_internals *)
> +               dev->data->dev_private;
> +
> +       uint16_t i;
> +       for (i = 0; i < internals->max_rxmac; ++i) {
> +               nc_rxmac_mac_filter_enable(internals->rxmac[i],
> +                       RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
> +       }
> +}
> +
> +void
> +nfb_eth_allmulticast_disable(struct rte_eth_dev *dev)
> +{
> +       // if multicast is not enabled do nothing
> +       if (!nfb_eth_allmulticast_get(dev))
> +               return;
> +
> +       struct pmd_internals *internals = (struct pmd_internals *)
> +               dev->data->dev_private;
> +
> +
> +       uint16_t i;
> +       for (i = 0; i < internals->max_rxmac; ++i) {
> +               nc_rxmac_mac_filter_enable(internals->rxmac[i],
> +                       internals->rx_filter_original);
> +       }
> +}
> +
> +int
> +nfb_eth_allmulticast_get(struct rte_eth_dev *dev)
> +{
> +       struct pmd_internals *internals = (struct pmd_internals *)
> +               dev->data->dev_private;
> +
> +       struct nc_rxmac_status status;
> +       status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
> +       nc_rxmac_read_status(internals->rxmac[0], &status);
> +
> +
> +       return (status.mac_filter == RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
> +}
> diff --git a/drivers/net/nfb/nfb_rxmode.h b/drivers/net/nfb/nfb_rxmode.h
> new file mode 100644
> index 0000000..2a72b10
> --- /dev/null
> +++ b/drivers/net/nfb/nfb_rxmode.h
> @@ -0,0 +1,81 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Cesnet
> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> + * All rights reserved.
> + */
> +
> +#ifndef _NFB_RXMODE_H_
> +#define _NFB_RXMODE_H_
> +
> +#include <stdint.h>
> +#include <unistd.h>
> +#include <stdbool.h>
> +#include <err.h>
> +#include <sys/types.h>
> +
> +#include <sys/mman.h>
> +
> +#include <nfb/nfb.h>
> +#include <nfb/ndp.h>
> +
> +#include <rte_ethdev.h>
> +#include <rte_dev.h>
> +
> +/**
> + * Getter for promiscuous mode
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + * @return 1 if enabled 0 otherwise
> + */
> +int
> +nfb_eth_promiscuous_get(struct rte_eth_dev *dev);
> +
> +/**
> + * DPDK callback to enable promiscuous mode.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + */
> +void
> +nfb_eth_promiscuous_enable(struct rte_eth_dev *dev);
> +
> +/**
> + * DPDK callback to disable promiscuous mode.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + */
> +void
> +nfb_eth_promiscuous_disable(struct rte_eth_dev *dev);
> +
> +/**
> + * Getter for allmulticast mode
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + * @return 1 if enabled 0 otherwise
> + */
> +int
> +nfb_eth_allmulticast_get(struct rte_eth_dev *dev);
> +
> +/**
> + * DPDK callback to enable allmulticast mode.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + */
> +void
> +nfb_eth_allmulticast_enable(struct rte_eth_dev *dev);
> +
> +/**
> + * DPDK callback to disable allmulticast mode.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + */
> +void
> +nfb_eth_allmulticast_disable(struct rte_eth_dev *dev);
> +
> +
> +
> +
> +#endif /* _NFB_RXMODE_H_ */
> diff --git a/drivers/net/nfb/nfb_stats.c b/drivers/net/nfb/nfb_stats.c
> new file mode 100644
> index 0000000..f2750e4
> --- /dev/null
> +++ b/drivers/net/nfb/nfb_stats.c
> @@ -0,0 +1,79 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Cesnet
> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> + * All rights reserved.
> + */
> +
> +
> +#include "nfb_stats.h"
> +#include "nfb.h"
> +
> +int
> +nfb_eth_stats_get(struct rte_eth_dev *dev,
> +       struct rte_eth_stats *stats)
> +{
> +       uint16_t i;
> +       uint16_t nb_rx = dev->data->nb_rx_queues;
> +       uint16_t nb_tx = dev->data->nb_tx_queues;
> +       uint64_t rx_total = 0;
> +       uint64_t tx_total = 0;
> +       uint64_t tx_err_total = 0;
> +       uint64_t rx_total_bytes = 0;
> +       uint64_t tx_total_bytes = 0;
> +
> +       struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
> +               dev->data->rx_queues);
> +       struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
> +               dev->data->tx_queues);
> +
> +       for (i = 0; i < nb_rx; i++) {
> +               if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> +                       stats->q_ipackets[i] = rx_queue[i].rx_pkts;
> +                       stats->q_ibytes[i] = rx_queue[i].rx_bytes;
> +               }
> +               rx_total += stats->q_ipackets[i];
> +               rx_total_bytes += stats->q_ibytes[i];
> +       }
> +
> +       for (i = 0; i < nb_tx; i++) {
> +               if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> +                       stats->q_opackets[i] = tx_queue[i].tx_pkts;
> +                       stats->q_obytes[i] = tx_queue[i].tx_bytes;
> +                       stats->q_errors[i] = tx_queue[i].err_pkts;
> +               }
> +               tx_total += stats->q_opackets[i];
> +               tx_total_bytes += stats->q_obytes[i];
> +               tx_err_total += stats->q_errors[i];
> +       }
> +
> +       stats->ipackets = rx_total;
> +       stats->opackets = tx_total;
> +       stats->ibytes = rx_total_bytes;
> +       stats->obytes = tx_total_bytes;
> +       stats->oerrors = tx_err_total;
> +       return 0;
> +}
> +
> +void
> +nfb_eth_stats_reset(struct rte_eth_dev *dev)
> +{
> +       uint16_t i;
> +       uint16_t nb_rx = dev->data->nb_rx_queues;
> +       uint16_t nb_tx = dev->data->nb_tx_queues;
> +
> +       struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
> +               dev->data->rx_queues);
> +       struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
> +               dev->data->tx_queues);
> +
> +       for (i = 0; i < nb_rx; i++) {
> +               rx_queue[i].rx_pkts = 0;
> +               rx_queue[i].rx_bytes = 0;
> +               rx_queue[i].err_pkts = 0;
> +       }
> +       for (i = 0; i < nb_tx; i++) {
> +               tx_queue[i].tx_pkts = 0;
> +               tx_queue[i].tx_bytes = 0;
> +               tx_queue[i].err_pkts = 0;
> +       }
> +}
> diff --git a/drivers/net/nfb/nfb_stats.h b/drivers/net/nfb/nfb_stats.h
> new file mode 100644
> index 0000000..d89ca4c
> --- /dev/null
> +++ b/drivers/net/nfb/nfb_stats.h
> @@ -0,0 +1,52 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Cesnet
> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> + * All rights reserved.
> + */
> +
> +#ifndef _NFB_STATS_H_
> +#define _NFB_STATS_H_
> +
> +#include <stdint.h>
> +#include <unistd.h>
> +#include <stdbool.h>
> +#include <err.h>
> +#include <sys/types.h>
> +
> +#include <sys/mman.h>
> +
> +#include <nfb/nfb.h>
> +#include <nfb/ndp.h>
> +
> +#include <rte_mbuf.h>
> +#include <rte_ethdev.h>
> +#include <rte_malloc.h>
> +#include <rte_memcpy.h>
> +#include <rte_dev.h>
> +
> +/**
> + * DPDK callback to get device statistics.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + * @param[out] stats
> + *   Stats structure output buffer.
> + *
> + * @return
> + *   0 on success and stats is filled, negative errno value otherwise and
> + *   rte_errno is set.
> + */
> +int nfb_eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats
> *stats);
> +
> +/**
> + * DPDK callback to clear device statistics.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + */
> +void nfb_eth_stats_reset(struct rte_eth_dev *dev);
> +
> +
> +
> +
> +#endif /* _NFB_STATS_H_ */
> diff --git a/drivers/net/nfb/nfb_tx.c b/drivers/net/nfb/nfb_tx.c
> new file mode 100644
> index 0000000..efaaa2b
> --- /dev/null
> +++ b/drivers/net/nfb/nfb_tx.c
> @@ -0,0 +1,112 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Cesnet
> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> + * All rights reserved.
> + */
> +
> +
> +#include "nfb_tx.h"
> +#include "nfb.h"
> +
> +int
> +nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id)
> +{
> +       struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
> +
> +       if (txq->queue == NULL) {
> +               RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
> +               return -EINVAL;
> +       }
> +
> +       int ret = ndp_queue_start(txq->queue);
> +       if (ret != 0)
> +               goto err;
> +       dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STARTED;
> +       return 0;
> +
> +err:
> +       return -EINVAL;
> +}
> +
> +int
> +nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id)
> +{
> +       struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
> +
> +       if (txq->queue != NULL) {
> +               RTE_LOG(ERR, PMD, "TX NDP queue is NULL!\n");
> +               return -EINVAL;
> +       }
> +
> +       int ret = ndp_queue_stop(txq->queue);
> +       if (ret != 0)
> +               return -EINVAL;
> +       dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
> +       return 0;
> +}
> +
> +int
> +nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
> +       uint16_t tx_queue_id,
> +       uint16_t nb_tx_desc __rte_unused,
> +       unsigned int socket_id,
> +       const struct rte_eth_txconf *tx_conf __rte_unused)
> +{
> +       struct pmd_internals *internals = dev->data->dev_private;
> +
> +       struct ndp_tx_queue *txq;
> +
> +       txq = rte_zmalloc_socket("ndp tx queue",
> +               sizeof(struct ndp_tx_queue),
> +               RTE_CACHE_LINE_SIZE, socket_id);
> +
> +       if (txq == NULL) {
> +               RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for tx
> queue id "
> +                       "%" PRIu16 "!\n", tx_queue_id);
> +               return -ENOMEM;
> +       }
> +
> +       int ret = nfb_eth_tx_queue_init(internals->nfb,
> +               tx_queue_id,
> +               txq);
> +
> +       if (ret == 0)
> +               dev->data->tx_queues[tx_queue_id] = txq;
> +       else
> +               rte_free(txq);
> +
> +       return ret;
> +}
> +
> +int
> +nfb_eth_tx_queue_init(struct nfb_device *nfb,
> +       uint16_t tx_queue_id,
> +       struct ndp_tx_queue *txq)
> +{
> +       if (nfb == NULL)
> +               return -EINVAL;
> +
> +       txq->queue = ndp_open_tx_queue(nfb, tx_queue_id);
> +       if (txq->queue == NULL)
> +               return -EINVAL;
> +
> +       txq->nfb = nfb;
> +       txq->tx_queue_id = tx_queue_id;
> +
> +       txq->tx_pkts = 0;
> +       txq->tx_bytes = 0;
> +       txq->err_pkts = 0;
> +
> +       return 0;
> +}
> +
> +void
> +nfb_eth_tx_queue_release(void *q)
> +{
> +       struct ndp_tx_queue *txq = (struct ndp_tx_queue *)q;
> +       if (txq->queue != NULL) {
> +               ndp_close_tx_queue(txq->queue);
> +               rte_free(txq);
> +               txq->queue = NULL;
> +       }
> +}
> diff --git a/drivers/net/nfb/nfb_tx.h b/drivers/net/nfb/nfb_tx.h
> new file mode 100644
> index 0000000..3ceb3bf
> --- /dev/null
> +++ b/drivers/net/nfb/nfb_tx.h
> @@ -0,0 +1,209 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Cesnet
> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> + * All rights reserved.
> + */
> +
> +#ifndef _NFB_TX_H_
> +#define _NFB_TX_H_
> +
> +#include <stdint.h>
> +#include <unistd.h>
> +#include <stdbool.h>
> +#include <err.h>
> +#include <sys/types.h>
> +
> +#include <sys/mman.h>
> +
> +#include <nfb/nfb.h>
> +#include <nfb/ndp.h>
> +
> +#include <rte_mbuf.h>
> +#include <rte_ethdev.h>
> +#include <rte_malloc.h>
> +#include <rte_memcpy.h>
> +#include <rte_dev.h>
> +
> +struct ndp_tx_queue {
> +       struct nfb_device *nfb;     /* nfb dev structure */
> +       struct ndp_queue *queue;    /* tx queue */
> +       uint16_t          tx_queue_id;       /* index */
> +       volatile uint64_t tx_pkts;  /* packets transmitted */
> +       volatile uint64_t tx_bytes; /* bytes transmitted */
> +       volatile uint64_t err_pkts; /* erroneous packets */
> +};
> +
> +
> +/**
> + * DPDK callback to setup a TX queue for use.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + * @param idx
> + *   RX queue index.
> + * @param desc
> + *   Number of descriptors to configure in queue.
> + * @param socket
> + *   NUMA socket on which memory must be allocated.
> + * @param[in] conf
> + *   Thresholds parameters.
> + * @param mp
> + *   Memory pool for buffer allocations.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +int
> +nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
> +       uint16_t tx_queue_id,
> +       uint16_t nb_tx_desc __rte_unused,
> +       unsigned int socket_id,
> +       const struct rte_eth_txconf *tx_conf __rte_unused);
> +
> +/**
> + * Initialize ndp_tx_queue structure
> + *
> + * @param nfb
> + *   Pointer to nfb device structure.
> + * @param tx_queue_id
> + *   TX queue index.
> + * @param[out] txq
> + *   Pointer to ndp_tx_queue output structure
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +int
> +nfb_eth_tx_queue_init(struct nfb_device *nfb,
> +       uint16_t tx_queue_id,
> +       struct ndp_tx_queue *txq);
> +
> +/**
> + * DPDK callback to release a RX queue.
> + *
> + * @param dpdk_rxq
> + *   Generic RX queue pointer.
> + */
> +void
> +nfb_eth_tx_queue_release(void *q);
> +
> +
> +/**
> + * Start traffic on Tx queue.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + * @param txq_id
> + *   TX queue index.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +int
> +nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id);
> +
> +/**
> + * Stop traffic on Tx queue.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + * @param txq_id
> + *   TX queue index.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +int
> +nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id);
> +
> +/**
> + * DPDK callback for TX.
> + *
> + * @param dpdk_txq
> + *   Generic pointer to TX queue structure.
> + * @param bufs
> + *   Packets to transmit.
> + * @param nb_pkts
> + *   Number of packets in array.
> + *
> + * @return
> + *   Number of packets successfully transmitted (<= nb_pkts).
> + */
> +static __rte_always_inline uint16_t
> +nfb_eth_ndp_tx(void *queue,
> +       struct rte_mbuf **bufs,
> +       uint16_t nb_pkts)
> +{
> +       int i;
> +       struct rte_mbuf *mbuf;
> +       struct ndp_tx_queue *ndp = queue;
> +       uint16_t num_tx = 0;
> +       uint64_t num_bytes = 0;
> +
> +       void *dst;
> +       uint32_t pkt_len;
> +       uint8_t mbuf_segs;
> +
> +       struct ndp_packet packets[nb_pkts];
> +
> +       if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
> +               RTE_LOG(ERR, PMD, "RX invalid arguments!\n");
> +               return 0;
> +       }
> +
> +       for (i = 0; i < nb_pkts; i++) {
> +               packets[i].data_length = bufs[i]->pkt_len;
> +               packets[i].header_length = 0;
> +       }
> +
> +       num_tx = ndp_tx_burst_get(ndp->queue, packets, nb_pkts);
> +
> +       if (unlikely(num_tx != nb_pkts))
> +               return 0;
> +
> +       for (i = 0; i < nb_pkts; ++i) {
> +               mbuf = bufs[i];
> +
> +               pkt_len = mbuf->pkt_len;
> +               mbuf_segs = mbuf->nb_segs;
> +
> +               num_bytes += pkt_len;
> +               if (mbuf_segs == 1) {
> +                       /*
> +                        * non-scattered packet,
> +                        * transmit from one mbuf
> +                        */
> +                       rte_memcpy(packets[i].data,
> +                               rte_pktmbuf_mtod(mbuf, const void *),
> +                               pkt_len);
> +               } else {
> +                       /* scattered packet, transmit from more mbufs */
> +                       struct rte_mbuf *m = mbuf;
> +                       while (m) {
> +                               dst = packets[i].data;
> +
> +                               rte_memcpy(dst,
> +                                       rte_pktmbuf_mtod(m,
> +                                       const void *),
> +                                       m->data_len);
> +                               dst = ((uint8_t *)(dst)) +
> +                                       m->data_len;
> +                               m = m->next;
> +                       }
> +               }
> +
> +               rte_pktmbuf_free(mbuf);
> +       }
> +
> +       ndp_tx_burst_flush(ndp->queue);
> +
> +       ndp->tx_pkts += num_tx;
> +       ndp->err_pkts += nb_pkts - num_tx;
> +       ndp->tx_bytes += num_bytes;
> +       return num_tx;
> +}
> +
> +
> +
> +
> +#endif /* _NFB_TX_H_ */
> diff --git a/examples/skeleton/basicfwd.c b/examples/skeleton/basicfwd.c
> deleted file mode 100644
> index 4aba1dc..0000000
> --- a/examples/skeleton/basicfwd.c
> +++ /dev/null
> @@ -1,198 +0,0 @@
> -/* SPDX-License-Identifier: BSD-3-Clause
> - * Copyright(c) 2010-2015 Intel Corporation
> - */
> -
> -#include <stdint.h>
> -#include <inttypes.h>
> -#include <rte_eal.h>
> -#include <rte_ethdev.h>
> -#include <rte_cycles.h>
> -#include <rte_lcore.h>
> -#include <rte_mbuf.h>
> -
> -#define RX_RING_SIZE 1024
> -#define TX_RING_SIZE 1024
> -
> -#define NUM_MBUFS 8191
> -#define MBUF_CACHE_SIZE 250
> -#define BURST_SIZE 32
> -
> -static const struct rte_eth_conf port_conf_default = {
> -       .rxmode = {
> -               .max_rx_pkt_len = ETHER_MAX_LEN,
> -       },
> -};
> -
> -/* basicfwd.c: Basic DPDK skeleton forwarding example. */
> -
> -/*
> - * Initializes a given port using global settings and with the RX buffers
> - * coming from the mbuf_pool passed as a parameter.
> - */
> -static inline int
> -port_init(uint16_t port, struct rte_mempool *mbuf_pool)
> -{
> -       struct rte_eth_conf port_conf = port_conf_default;
> -       const uint16_t rx_rings = 1, tx_rings = 1;
> -       uint16_t nb_rxd = RX_RING_SIZE;
> -       uint16_t nb_txd = TX_RING_SIZE;
> -       int retval;
> -       uint16_t q;
> -       struct rte_eth_dev_info dev_info;
> -       struct rte_eth_txconf txconf;
> -
> -       if (!rte_eth_dev_is_valid_port(port))
> -               return -1;
> -
> -       rte_eth_dev_info_get(port, &dev_info);
> -       if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
> -               port_conf.txmode.offloads |=
> -                       DEV_TX_OFFLOAD_MBUF_FAST_FREE;
> -
> -       /* Configure the Ethernet device. */
> -       retval = rte_eth_dev_configure(port, rx_rings, tx_rings,
> &port_conf);
> -       if (retval != 0)
> -               return retval;
> -
> -       retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd);
> -       if (retval != 0)
> -               return retval;
> -
> -       /* Allocate and set up 1 RX queue per Ethernet port. */
> -       for (q = 0; q < rx_rings; q++) {
> -               retval = rte_eth_rx_queue_setup(port, q, nb_rxd,
> -                               rte_eth_dev_socket_id(port), NULL,
> mbuf_pool);
> -               if (retval < 0)
> -                       return retval;
> -       }
> -
> -       txconf = dev_info.default_txconf;
> -       txconf.offloads = port_conf.txmode.offloads;
> -       /* Allocate and set up 1 TX queue per Ethernet port. */
> -       for (q = 0; q < tx_rings; q++) {
> -               retval = rte_eth_tx_queue_setup(port, q, nb_txd,
> -                               rte_eth_dev_socket_id(port), &txconf);
> -               if (retval < 0)
> -                       return retval;
> -       }
> -
> -       /* Start the Ethernet port. */
> -       retval = rte_eth_dev_start(port);
> -       if (retval < 0)
> -               return retval;
> -
> -       /* Display the port MAC address. */
> -       struct ether_addr addr;
> -       rte_eth_macaddr_get(port, &addr);
> -       printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8
> -                          " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n",
> -                       port,
> -                       addr.addr_bytes[0], addr.addr_bytes[1],
> -                       addr.addr_bytes[2], addr.addr_bytes[3],
> -                       addr.addr_bytes[4], addr.addr_bytes[5]);
> -
> -       /* Enable RX in promiscuous mode for the Ethernet device. */
> -       rte_eth_promiscuous_enable(port);
> -
> -       return 0;
> -}
> -
> -/*
> - * The lcore main. This is the main thread that does the work, reading
> from
> - * an input port and writing to an output port.
> - */
> -static __attribute__((noreturn)) void
> -lcore_main(void)
> -{
> -       uint16_t port;
> -
> -       /*
> -        * Check that the port is on the same NUMA node as the polling
> thread
> -        * for best performance.
> -        */
> -       RTE_ETH_FOREACH_DEV(port)
> -               if (rte_eth_dev_socket_id(port) > 0 &&
> -                               rte_eth_dev_socket_id(port) !=
> -                                               (int)rte_socket_id())
> -                       printf("WARNING, port %u is on remote NUMA node to
> "
> -                                       "polling thread.\n\tPerformance
> will "
> -                                       "not be optimal.\n", port);
> -
> -       printf("\nCore %u forwarding packets. [Ctrl+C to quit]\n",
> -                       rte_lcore_id());
> -
> -       /* Run until the application is quit or killed. */
> -       for (;;) {
> -               /*
> -                * Receive packets on a port and forward them on the paired
> -                * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2,
> etc.
> -                */
> -               RTE_ETH_FOREACH_DEV(port) {
> -
> -                       /* Get burst of RX packets, from first port of
> pair. */
> -                       struct rte_mbuf *bufs[BURST_SIZE];
> -                       const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
> -                                       bufs, BURST_SIZE);
> -
> -                       if (unlikely(nb_rx == 0))
> -                               continue;
> -
> -                       /* Send burst of TX packets, to second port of
> pair. */
> -                       const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1,
> 0,
> -                                       bufs, nb_rx);
> -
> -                       /* Free any unsent packets. */
> -                       if (unlikely(nb_tx < nb_rx)) {
> -                               uint16_t buf;
> -                               for (buf = nb_tx; buf < nb_rx; buf++)
> -                                       rte_pktmbuf_free(bufs[buf]);
> -                       }
> -               }
> -       }
> -}
> -
> -/*
> - * The main function, which does initialization and calls the per-lcore
> - * functions.
> - */
> -int
> -main(int argc, char *argv[])
> -{
> -       struct rte_mempool *mbuf_pool;
> -       unsigned nb_ports;
> -       uint16_t portid;
> -
> -       /* Initialize the Environment Abstraction Layer (EAL). */
> -       int ret = rte_eal_init(argc, argv);
> -       if (ret < 0)
> -               rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
> -
> -       argc -= ret;
> -       argv += ret;
> -
> -       /* Check that there is an even number of ports to send/receive on.
> */
> -       nb_ports = rte_eth_dev_count_avail();
> -       if (nb_ports < 2 || (nb_ports & 1))
> -               rte_exit(EXIT_FAILURE, "Error: number of ports must be
> even\n");
> -
> -       /* Creates a new mempool in memory to hold the mbufs. */
> -       mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS *
> nb_ports,
> -               MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE,
> rte_socket_id());
> -
> -       if (mbuf_pool == NULL)
> -               rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
> -
> -       /* Initialize all ports. */
> -       RTE_ETH_FOREACH_DEV(portid)
> -               if (port_init(portid, mbuf_pool) != 0)
> -                       rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu16
> "\n",
> -                                       portid);
> -
> -       if (rte_lcore_count() > 1)
> -               printf("\nWARNING: Too many lcores enabled. Only 1
> used.\n");
> -
> -       /* Call lcore_main on the master core only. */
> -       lcore_main();
> -
> -       return 0;
> -}
> diff --git a/mk/rte.app.mk b/mk/rte.app.mk
> index 8a4f0f4..32e88b5 100644
> --- a/mk/rte.app.mk
> +++ b/mk/rte.app.mk
> @@ -196,6 +196,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC)      +=
> -lrte_pmd_softnic
>  endif
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD)    += -lrte_pmd_sfc_efx
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2 -lsze2
> +_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NFB)        += -lrte_pmd_nfb -lnfb -lfdt
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_TAP)        += -lrte_pmd_tap
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) +=
> -lrte_pmd_thunderx_nicvf
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD) += -lrte_pmd_vdev_netvsc
> --
> 1.8.3.1
>
>

-- 
regards,
Rami Rosen

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH] net/nfb: new netcope driver
  2019-02-26 12:57 ` [dpdk-dev] [PATCH] net/nfb: new netcope driver Rastislav Cernay
  2019-02-26 14:20   ` Rami Rosen
@ 2019-02-26 15:46   ` Stephen Hemminger
  2019-02-27 11:43   ` [dpdk-dev] [PATCH v2] net/nfb: new Netcope driver Rastislav Cernay
                     ` (6 subsequent siblings)
  8 siblings, 0 replies; 50+ messages in thread
From: Stephen Hemminger @ 2019-02-26 15:46 UTC (permalink / raw)
  To: Rastislav Cernay; +Cc: dev

On Tue, 26 Feb 2019 13:57:04 +0100
Rastislav Cernay <cernay@netcope.com> wrote:

> +static void
> +nfb_eth_dev_info(struct rte_eth_dev *dev,
> +	struct rte_eth_dev_info *dev_info)
> +{
> +	dev_info->if_index = 0;
> +	dev_info->max_mac_addrs = 1;
> +	dev_info->max_rx_pktlen = (uint32_t)-1;
> +	dev_info->max_rx_queues = dev->data->nb_rx_queues;
> +	dev_info->max_tx_queues = dev->data->nb_tx_queues;
> +	dev_info->min_rx_bufsize = 0;
> +	dev_info->speed_capa = ETH_LINK_SPEED_100G;
> +}

Minor nit, you don't need to zero entries here, the calling
code (in rte_eth_dev_info_get) already does a memset.

+static int
+nfb_eth_link_update(struct rte_eth_dev *dev,
+	int wait_to_complete __rte_unused)
+{
+	uint16_t i;
+	struct rte_eth_link link;
+	memset(&link, 0, sizeof(link));
+
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;

Since dev_private is a void * cast is unnecessary


+	struct nc_rxmac_status status;
+	status.speed = MAC_SPEED_UNKNOWN;
+
+	link.link_speed = ETH_SPEED_NUM_NONE;
+	link.link_status = ETH_LINK_DOWN;
+	link.link_duplex = ETH_LINK_FULL_DUPLEX;
+	link.link_autoneg = ETH_LINK_SPEED;

Don't mix declarations with code.

You can use C99 structure initialization to avoid memset here.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH] net/nfb: new netcope driver
  2019-02-26 14:20   ` Rami Rosen
@ 2019-02-26 16:33     ` Rastislav Černay
  0 siblings, 0 replies; 50+ messages in thread
From: Rastislav Černay @ 2019-02-26 16:33 UTC (permalink / raw)
  To: Rami Rosen; +Cc: dev

Hi,

examples/skeleton/basicfwd.c should not be touched in any way, it is
mistake.






*Rastislav Černay I Software DeveloperNetcope Technologies, a.s.T: +420 530
510 680 <+420%20530%20510%20680>A: Sochorova 3232/34, Brno, 616 00, Czech
Republic
<https://maps.google.com/?q=Sochorova+3232/34,+Brno,+616+00,%C2%A0Czech+Republic&entry=gmail&source=g>W:
www.netcope.com
<https://www.netcope.com/>  <https://www.netcope.com/>*



On Tue, Feb 26, 2019 at 3:20 PM Rami Rosen <ramirose@gmail.com> wrote:

> Hi, Cernay,
>
> > delete mode 100644 examples/skeleton/basicfwd.c
>
> It seems that this patch deletes examples/skeleton/basicfwd.c,
> (instead of patching it ?!),  maybe by mistake.
>
> Reviewed-by: Rami Rosen <ramirose at gmail.com>
>
> Rami Rosen
>
> On Tue, Feb 26, 2019 at 3:04 PM Rastislav Cernay <cernay@netcope.com>
> wrote:
>
>> From: Rastislav Cernay <cernay@netcope.com>
>>
>> Added new net driver for Netcope nfb cards
>>
>> Signed-off-by: Rastislav Cernay <cernay@netcope.com>
>> ---
>>  MAINTAINERS                      |   7 +
>>  config/common_base               |   4 +
>>  devtools/test-build.sh           |   1 +
>>  doc/guides/nics/features/nfb.ini |  17 ++
>>  doc/guides/nics/nfb.rst          | 141 ++++++++++
>>  drivers/net/Makefile             |   1 +
>>  drivers/net/meson.build          |   1 +
>>  drivers/net/nfb/Makefile         |  41 +++
>>  drivers/net/nfb/meson.build      |   9 +
>>  drivers/net/nfb/nfb.h            |  51 ++++
>>  drivers/net/nfb/nfb_ethdev.c     | 586
>> +++++++++++++++++++++++++++++++++++++++
>>  drivers/net/nfb/nfb_rx.c         | 127 +++++++++
>>  drivers/net/nfb/nfb_rx.h         | 226 +++++++++++++++
>>  drivers/net/nfb/nfb_rxmode.c     | 104 +++++++
>>  drivers/net/nfb/nfb_rxmode.h     |  81 ++++++
>>  drivers/net/nfb/nfb_stats.c      |  79 ++++++
>>  drivers/net/nfb/nfb_stats.h      |  52 ++++
>>  drivers/net/nfb/nfb_tx.c         | 112 ++++++++
>>  drivers/net/nfb/nfb_tx.h         | 209 ++++++++++++++
>>  examples/skeleton/basicfwd.c     | 198 -------------
>>  mk/rte.app.mk                    |   1 +
>>  21 files changed, 1850 insertions(+), 198 deletions(-)
>>  create mode 100644 doc/guides/nics/features/nfb.ini
>>  create mode 100644 doc/guides/nics/nfb.rst
>>  create mode 100644 drivers/net/nfb/Makefile
>>  create mode 100644 drivers/net/nfb/meson.build
>>  create mode 100644 drivers/net/nfb/nfb.h
>>  create mode 100644 drivers/net/nfb/nfb_ethdev.c
>>  create mode 100644 drivers/net/nfb/nfb_rx.c
>>  create mode 100644 drivers/net/nfb/nfb_rx.h
>>  create mode 100644 drivers/net/nfb/nfb_rxmode.c
>>  create mode 100644 drivers/net/nfb/nfb_rxmode.h
>>  create mode 100644 drivers/net/nfb/nfb_stats.c
>>  create mode 100644 drivers/net/nfb/nfb_stats.h
>>  create mode 100644 drivers/net/nfb/nfb_tx.c
>>  create mode 100644 drivers/net/nfb/nfb_tx.h
>>  delete mode 100644 examples/skeleton/basicfwd.c
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 6610440..c6bffde 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -654,6 +654,13 @@ F: drivers/net/szedata2/
>>  F: doc/guides/nics/szedata2.rst
>>  F: doc/guides/nics/features/szedata2.ini
>>
>> +Netcope nfb
>> +M: Rastislav Cernay <cernay@netcope.com>
>> +M: Jan Remes <remes@netcope.com>
>> +F: drivers/net/nfb/
>> +F: doc/guides/nics/nfb.rst
>> +F: doc/guides/nics/features/nfb.ini
>> +
>>  Netronome nfp
>>  M: Alejandro Lucero <alejandro.lucero@netronome.com>
>>  F: drivers/net/nfp/
>> diff --git a/config/common_base b/config/common_base
>> index 7c6da51..1ab0a6b 100644
>> --- a/config/common_base
>> +++ b/config/common_base
>> @@ -360,6 +360,10 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
>>  # Compile software PMD backed by SZEDATA2 device
>>  #
>>  CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
>> +#
>> +# Compile software PMD backed by NFB device
>> +#
>> +CONFIG_RTE_LIBRTE_PMD_NFB=n
>>
>>  #
>>  # Compile burst-oriented Cavium Thunderx NICVF PMD driver
>> diff --git a/devtools/test-build.sh b/devtools/test-build.sh
>> index 42f4ad0..ab57ab8 100755
>> --- a/devtools/test-build.sh
>> +++ b/devtools/test-build.sh
>> @@ -18,6 +18,7 @@ default_path=$PATH
>>  # - DPDK_DEP_SSL (y/[n])
>>  # - DPDK_DEP_IPSEC_MB (y/[n])
>>  # - DPDK_DEP_SZE (y/[n])
>> +# - DPDK_DEP_NFB (y/[n])
>>  # - DPDK_DEP_ZLIB (y/[n])
>>  # - DPDK_MAKE_JOBS (int)
>>  # - DPDK_NOTIFY (notify-send)
>> diff --git a/doc/guides/nics/features/nfb.ini
>> b/doc/guides/nics/features/nfb.ini
>> new file mode 100644
>> index 0000000..6174d65
>> --- /dev/null
>> +++ b/doc/guides/nics/features/nfb.ini
>> @@ -0,0 +1,17 @@
>> +;
>> +; Supported features of the 'nfb' network poll mode driver.
>> +;
>> +; Refer to default.ini for the full list of available PMD features.
>> +;
>> +[Features]
>> +Speed capabilities   = P
>> +Link status          = Y
>> +Queue start/stop     = Y
>> +Promiscuous mode     = Y
>> +Allmulticast mode    = Y
>> +Basic stats          = Y
>> +Extended stats       = Y
>> +Stats per queue      = Y
>> +Other kdrv           = Y
>> +x86-64               = Y
>> +Usage doc            = Y
>> diff --git a/doc/guides/nics/nfb.rst b/doc/guides/nics/nfb.rst
>> new file mode 100644
>> index 0000000..9057d41
>> --- /dev/null
>> +++ b/doc/guides/nics/nfb.rst
>> @@ -0,0 +1,141 @@
>> +..  SPDX-License-Identifier: BSD-3-Clause
>> +    Copyright 2015 - 2016 CESNET
>> +
>> +NFB poll mode driver library
>> +=================================
>> +
>> +The NFB poll mode driver library implements support for the Netcope
>> +FPGA Boards (**NFB-***), FPGA-based programmable NICs.
>> +The NFB PMD uses interface provided by the libnfb library to communicate
>> +with the NFB cards over the nfb layer.
>> +
>> +More information about the
>> +`NFB cards <http://www.netcope.com/en/products/fpga-boards>`_
>> +and used technology
>> +(`Netcope Development Kit <
>> http://www.netcope.com/en/products/fpga-development-kit>`_)
>> +can be found on the `Netcope Technologies website <
>> http://www.netcope.com/>`_.
>> +
>> +.. note::
>> +
>> +   This driver has external dependencies.
>> +   Therefore it is disabled in default configuration files.
>> +   It can be enabled by setting ``CONFIG_RTE_LIBRTE_PMD_NFB=y``
>> +   and recompiling.
>> +
>> +.. note::
>> +
>> +   Currently the driver is supported only on x86_64 architectures.
>> +   Only x86_64 versions of the external libraries are provided.
>> +
>> +Prerequisites
>> +-------------
>> +
>> +This PMD requires kernel modules which are responsible for
>> initialization and
>> +allocation of resources needed for nfb layer function.
>> +Communication between PMD and kernel modules is mediated by libnfb
>> library.
>> +These kernel modules and library are not part of DPDK and must be
>> installed
>> +separately:
>> +
>> +*  **libnfb library**
>> +
>> +   The library provides API for initialization of nfb transfers,
>> receiving and
>> +   transmitting data segments.
>> +
>> +*  **Kernel modules**
>> +
>> +   * nfb
>> +
>> +   Kernel modules manage initialization of hardware, allocation and
>> +   sharing of resources for user space applications.
>> +
>> +Dependencies can be found here:
>> +`Netcope common <
>> https://drive.google.com/file/d/13khqS312KzrRSrgGxD0CBSmd1YLJHWp8>`_.
>> +
>> +Versions of the packages
>> +~~~~~~~~~~~~~~~~~~~~~~~~
>> +
>> +The minimum version of the provided packages:
>> +
>> +* for DPDK from 19.02
>> +
>> +Configuration
>> +-------------
>> +
>> +These configuration options can be modified before compilation in the
>> +``.config`` file:
>> +
>> +*  ``CONFIG_RTE_LIBRTE_PMD_NFB`` default value: **n**
>> +
>> +   Value **y** enables compilation of nfb PMD.
>> +
>> +Using the NFB PMD
>> +----------------------
>> +
>> +Kernel modules have to be loaded before running the DPDK application.
>> +
>> +NFB card architecture
>> +---------------------
>> +
>> +The NFB cards are multi-port multi-queue cards, where (generally) data
>> from any
>> +Ethernet port may be sent to any queue.
>> +They are represented in DPDK as a single port.
>> +
>> +NFB-200G2QL card employs an addon cable which allows to connect it to two
>> +physical PCI-E slots at the same time (see the diagram below).
>> +This is done to allow 200 Gbps of traffic to be transferred through the
>> PCI-E
>> +bus (note that a single PCI-E 3.0 x16 slot provides only 125 Gbps
>> theoretical
>> +throughput).
>> +
>> +Although each slot may be connected to a different CPU and therefore to
>> a different
>> +NUMA node, the card is represented as a single port in DPDK. To work
>> with data
>> +from the individual queues on the right NUMA node, connection of NUMA
>> nodes on
>> +first and last queue (each NUMA node has half of the queues) need to be
>> checked.
>> +
>> +.. figure:: img/szedata2_nfb200g_architecture.svg
>> +    :align: center
>> +
>> +    NFB-200G2QL high-level diagram
>> +
>> +Limitations
>> +-----------
>> +
>> +Since a card is always represented as a single port, but can be
>> connected to two
>> +NUMA nodes, there is need for manual check where master/slave is
>> connected.
>> +
>> +Example of usage
>> +----------------
>> +
>> +Read packets from 0. and 1. receive queue and write them to 0. and 1.
>> +transmit queue:
>> +
>> +.. code-block:: console
>> +
>> +   $RTE_TARGET/app/testpmd -l 0-3 -n 2 \
>> +   -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2 -i -a
>> +
>> +Example output:
>> +
>> +.. code-block:: console
>> +
>> +   [...]
>> +   EAL: PCI device 0000:06:00.0 on NUMA socket -1
>> +   EAL:   probe driver: 1b26:c1c1 net_nfb
>> +   PMD: Initializing NFB device (0000:06:00.0)
>> +   PMD: Available DMA queues RX: 8 TX: 8
>> +   PMD: NFB device (0000:06:00.0) successfully initialized
>> +   Interactive-mode selected
>> +   Auto-start selected
>> +   Configuring Port 0 (socket 0)
>> +   Port 0: 00:11:17:00:00:00
>> +   Checking link statuses...
>> +   Port 0 Link Up - speed 10000 Mbps - full-duplex
>> +   Done
>> +   Start automatic packet forwarding
>> +     io packet forwarding - CRC stripping disabled - packets/burst=32
>> +     nb forwarding cores=2 - nb forwarding ports=1
>> +     RX queues=2 - RX desc=128 - RX free threshold=0
>> +     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
>> +     TX queues=2 - TX desc=512 - TX free threshold=0
>> +     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
>> +     TX RS bit threshold=0 - TXQ flags=0x0
>> +   testpmd>
>> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
>> index 670d7f7..013c551 100644
>> --- a/drivers/net/Makefile
>> +++ b/drivers/net/Makefile
>> @@ -38,6 +38,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5
>>  DIRS-$(CONFIG_RTE_LIBRTE_MVNETA_PMD) += mvneta
>>  DIRS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mvpp2
>>  DIRS-$(CONFIG_RTE_LIBRTE_NETVSC_PMD) += netvsc
>> +DIRS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb
>>  DIRS-$(CONFIG_RTE_LIBRTE_NFP_PMD) += nfp
>>  DIRS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt
>>  DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += null
>> diff --git a/drivers/net/meson.build b/drivers/net/meson.build
>> index 45da3bb..6733a19 100644
>> --- a/drivers/net/meson.build
>> +++ b/drivers/net/meson.build
>> @@ -27,6 +27,7 @@ drivers = ['af_packet',
>>         'mvneta',
>>         'mvpp2',
>>         'netvsc',
>> +       'nfb',
>>         'nfp',
>>         'null', 'octeontx', 'pcap', 'qede', 'ring',
>>         'sfc',
>> diff --git a/drivers/net/nfb/Makefile b/drivers/net/nfb/Makefile
>> new file mode 100644
>> index 0000000..ee8c7df
>> --- /dev/null
>> +++ b/drivers/net/nfb/Makefile
>> @@ -0,0 +1,41 @@
>> +# SPDX-License-Identifier: BSD-3-Clause
>> +# Copyright(c) 2018 Cesnet
>> +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
>> +# All rights reserved.
>> +
>> +include $(RTE_SDK)/mk/rte.vars.mk
>> +
>> +#
>> +# library name
>> +#
>> +LIB = librte_pmd_nfb.a
>> +
>> +INCLUDES :=-I$(SRCDIR)
>> +
>> +
>> +CFLAGS += -O3
>> +CFLAGS += $(WERROR_FLAGS)
>> +LDLIBS += -lnfb
>> +LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
>> +LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
>> +LDLIBS += -lrte_bus_pci
>> +
>> +EXPORT_MAP := rte_pmd_nfb_version.map
>> +
>> +LIBABIVER := 1
>> +
>> +#
>> +# all source are stored in SRCS-y
>> +#
>> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_ethdev.c
>> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_rx.c
>> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_tx.c
>> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_stats.c
>> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_rxmode.c
>> +
>> +#
>> +# Export include files
>> +#
>> +SYMLINK-y-include +=
>> +
>> +include $(RTE_SDK)/mk/rte.lib.mk
>> diff --git a/drivers/net/nfb/meson.build b/drivers/net/nfb/meson.build
>> new file mode 100644
>> index 0000000..d7dccba
>> --- /dev/null
>> +++ b/drivers/net/nfb/meson.build
>> @@ -0,0 +1,9 @@
>> +# SPDX-License-Identifier: BSD-3-Clause
>> +# Copyright(c) 2018 Cesnet
>> +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
>> +# All rights reserved.
>> +
>> +dep = cc.find_library('nfb', required: true)
>> +build = dep.found()
>> +ext_deps += dep
>> +sources = files('nfb_rx.c', 'nfb_tx.c', 'nfb_stats.c', 'nfb_ethdev.c',
>> 'nfb_rxmode.c')
>> diff --git a/drivers/net/nfb/nfb.h b/drivers/net/nfb/nfb.h
>> new file mode 100644
>> index 0000000..d032ba4
>> --- /dev/null
>> +++ b/drivers/net/nfb/nfb.h
>> @@ -0,0 +1,51 @@
>> +/* SPDX-License-Identifier: BSD-3-Clause
>> + * Copyright(c) 2018 Cesnet
>> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
>> + * All rights reserved.
>> + */
>> +
>> +#ifndef _NFB_H_
>> +#define _NFB_H_
>> +
>> +#include <nfb/nfb.h>
>> +#include <nfb/ndp.h>
>> +#include <netcope/rxmac.h>
>> +#include <netcope/txmac.h>
>> +
>> +#include "nfb_rx.h"
>> +#include "nfb_tx.h"
>> +
>> +/* PCI Vendor ID */
>> +#define PCI_VENDOR_ID_NETCOPE 0x1b26
>> +
>> +/* PCI Device IDs */
>> +#define PCI_DEVICE_ID_NFB_40G2  0xcb80
>> +#define PCI_DEVICE_ID_NFB_100G2 0xc2c1
>> +#define PCI_DEVICE_ID_NFB_200G2QL 0xc250
>> +
>> +/* Max index of ndp rx/tx queues */
>> +#define RTE_ETH_NDP_MAX_RX_QUEUES 32
>> +#define RTE_ETH_NDP_MAX_TX_QUEUES 32
>> +
>> +/* Max index of rx/tx dmas */
>> +#define RTE_MAX_NC_RXMAC 256
>> +#define RTE_MAX_NC_TXMAC 256
>> +
>> +#define RTE_NFB_DRIVER_NAME net_nfb
>> +
>> +struct pmd_internals {
>> +       uint16_t         max_rxmac;
>> +       uint16_t         max_txmac;
>> +       struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC];
>> +       struct nc_txmac *txmac[RTE_MAX_NC_TXMAC];
>> +
>> +       char             nfb_dev[PATH_MAX];
>> +       struct nfb_device *nfb;
>> +       /* Place to remember if filter was promiscous or filtering by
>> table,
>> +        * when disabling allmulticast
>> +        */
>> +       enum nc_rxmac_mac_filter rx_filter_original;
>> +};
>> +
>> +
>> +#endif /* _NFB_H_ */
>> diff --git a/drivers/net/nfb/nfb_ethdev.c b/drivers/net/nfb/nfb_ethdev.c
>> new file mode 100644
>> index 0000000..c8d546f
>> --- /dev/null
>> +++ b/drivers/net/nfb/nfb_ethdev.c
>> @@ -0,0 +1,586 @@
>> +/* SPDX-License-Identifier: BSD-3-Clause
>> + * Copyright(c) 2018 Cesnet
>> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
>> + * All rights reserved.
>> + */
>> +
>> +#include <stdint.h>
>> +#include <unistd.h>
>> +#include <stdbool.h>
>> +#include <err.h>
>> +#include <sys/types.h>
>> +#include <dirent.h>
>> +#include <sys/stat.h>
>> +#include <fcntl.h>
>> +#include <sys/mman.h>
>> +
>> +#include <nfb/nfb.h>
>> +#include <nfb/ndp.h>
>> +#include <netcope/rxmac.h>
>> +#include <netcope/txmac.h>
>> +
>> +#include <rte_mbuf.h>
>> +#include <rte_ethdev.h>
>> +#include <rte_ethdev_pci.h>
>> +#include <rte_malloc.h>
>> +#include <rte_memcpy.h>
>> +#include <rte_kvargs.h>
>> +#include <rte_dev.h>
>> +#include <rte_common.h>
>> +
>> +#include "nfb_stats.h"
>> +#include "nfb_rx.h"
>> +#include "nfb_tx.h"
>> +#include "nfb_rxmode.h"
>> +#include "nfb.h"
>> +
>> +/**
>> + * Default MAC addr
>> + */
>> +static struct ether_addr eth_addr = {
>> +       .addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
>> +};
>> +
>> +/**
>> + * Open all RX DMA queues
>> + *
>> + * @param dev
>> + *   Pointer to nfb device.
>> + * @param[out] rxmac
>> + *   Pointer to output array of nc_rxmac
>> + * @param[out] max_rxmac
>> + *   Pointer to output max index of rxmac
>> + */
>> +static void
>> +nfb_nc_rxmac_init(struct nfb_device *nfb,
>> +       struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
>> +       uint16_t *max_rxmac)
>> +{
>> +       *max_rxmac = 0;
>> +       while ((rxmac[*max_rxmac] = nc_rxmac_open_index(nfb, *max_rxmac)))
>> +               ++(*max_rxmac);
>> +}
>> +
>> +/**
>> + * Open all TX DMA queues
>> + *
>> + * @param dev
>> + *   Pointer to nfb device.
>> + * @param[out] txmac
>> + *   Pointer to output array of nc_txmac
>> + * @param[out] max_rxmac
>> + *   Pointer to output max index of txmac
>> + */
>> +static void
>> +nfb_nc_txmac_init(struct nfb_device *nfb,
>> +       struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
>> +       uint16_t *max_txmac)
>> +{
>> +       *max_txmac = 0;
>> +       while ((txmac[*max_txmac] = nc_txmac_open_index(nfb, *max_txmac)))
>> +               ++(*max_txmac);
>> +}
>> +
>> +/**
>> + * Close all RX DMA queues
>> + *
>> + * @param rxmac
>> + *   Pointer to array of nc_rxmac
>> + * @param max_rxmac
>> + *   Maximum index of rxmac
>> + */
>> +static void
>> +nfb_nc_rxmac_deinit(struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
>> +       uint16_t max_rxmac)
>> +{
>> +       for (; max_rxmac > 0; --max_rxmac) {
>> +               nc_rxmac_close(rxmac[max_rxmac]);
>> +               rxmac[max_rxmac] = NULL;
>> +       }
>> +}
>> +
>> +/**
>> + * Close all TX DMA queues
>> + *
>> + * @param txmac
>> + *   Pointer to array of nc_txmac
>> + * @param max_txmac
>> + *   Maximum index of txmac
>> + */
>> +static void
>> +nfb_nc_txmac_deinit(struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
>> +       uint16_t max_txmac)
>> +{
>> +       for (; max_txmac > 0; --max_txmac) {
>> +               nc_txmac_close(txmac[max_txmac]);
>> +               txmac[max_txmac] = NULL;
>> +       }
>> +}
>> +
>> +/**
>> + * DPDK callback to start the device.
>> + *
>> + * Start device by starting all configured queues.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + *
>> + * @return
>> + *   0 on success, a negative errno value otherwise and rte_errno is set.
>> + */
>> +static int
>> +nfb_eth_dev_start(struct rte_eth_dev *dev)
>> +{
>> +       int ret;
>> +       uint16_t i;
>> +       uint16_t nb_rx = dev->data->nb_rx_queues;
>> +       uint16_t nb_tx = dev->data->nb_tx_queues;
>> +
>> +       for (i = 0; i < nb_rx; i++) {
>> +               ret = nfb_eth_rx_queue_start(dev, i);
>> +               if (ret != 0)
>> +                       goto err_rx;
>> +       }
>> +
>> +       for (i = 0; i < nb_tx; i++) {
>> +               ret = nfb_eth_tx_queue_start(dev, i);
>> +               if (ret != 0)
>> +                       goto err_tx;
>> +       }
>> +
>> +       return 0;
>> +
>> +err_tx:
>> +       for (i = 0; i < nb_tx; i++)
>> +               nfb_eth_tx_queue_stop(dev, i);
>> +err_rx:
>> +       for (i = 0; i < nb_rx; i++)
>> +               nfb_eth_rx_queue_stop(dev, i);
>> +       return ret;
>> +}
>> +
>> +/**
>> + * DPDK callback to stop the device.
>> + *
>> + * Stop device by stopping all configured queues.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + */
>> +static void
>> +nfb_eth_dev_stop(struct rte_eth_dev *dev)
>> +{
>> +       uint16_t i;
>> +       uint16_t nb_rx = dev->data->nb_rx_queues;
>> +       uint16_t nb_tx = dev->data->nb_tx_queues;
>> +
>> +       for (i = 0; i < nb_tx; i++)
>> +               nfb_eth_tx_queue_stop(dev, i);
>> +
>> +       for (i = 0; i < nb_rx; i++)
>> +               nfb_eth_rx_queue_stop(dev, i);
>> +}
>> +
>> +/**
>> + * DPDK callback for Ethernet device configuration.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + *
>> + * @return
>> + *   0 on success, a negative errno value otherwise and rte_errno is set.
>> + */
>> +static int
>> +nfb_eth_dev_configure(struct rte_eth_dev *dev)
>> +{
>> +       dev->rx_pkt_burst = nfb_eth_ndp_rx;
>> +       return 0;
>> +}
>> +
>> +/**
>> + * DPDK callback to get information about the device.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + * @param[out] info
>> + *   Info structure output buffer.
>> + */
>> +static void
>> +nfb_eth_dev_info(struct rte_eth_dev *dev,
>> +       struct rte_eth_dev_info *dev_info)
>> +{
>> +       dev_info->if_index = 0;
>> +       dev_info->max_mac_addrs = 1;
>> +       dev_info->max_rx_pktlen = (uint32_t)-1;
>> +       dev_info->max_rx_queues = dev->data->nb_rx_queues;
>> +       dev_info->max_tx_queues = dev->data->nb_tx_queues;
>> +       dev_info->min_rx_bufsize = 0;
>> +       dev_info->speed_capa = ETH_LINK_SPEED_100G;
>> +}
>> +
>> +/**
>> + * DPDK callback to close the device.
>> + *
>> + * Destroy all queues and objects, free memory.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + */
>> +static void
>> +nfb_eth_dev_close(struct rte_eth_dev *dev)
>> +{
>> +       uint16_t i;
>> +       uint16_t nb_rx = dev->data->nb_rx_queues;
>> +       uint16_t nb_tx = dev->data->nb_tx_queues;
>> +
>> +       nfb_eth_dev_stop(dev);
>> +
>> +       for (i = 0; i < nb_rx; i++) {
>> +               nfb_eth_rx_queue_release(dev->data->rx_queues[i]);
>> +               dev->data->rx_queues[i] = NULL;
>> +       }
>> +       dev->data->nb_rx_queues = 0;
>> +       for (i = 0; i < nb_tx; i++) {
>> +               nfb_eth_tx_queue_release(dev->data->tx_queues[i]);
>> +               dev->data->tx_queues[i] = NULL;
>> +       }
>> +       dev->data->nb_tx_queues = 0;
>> +}
>> +
>> +/**
>> + * DPDK callback to retrieve physical link information.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + * @param[out] link
>> + *   Storage for current link status.
>> + *
>> + * @return
>> + *   0 on success, a negative errno value otherwise and rte_errno is set.
>> + */
>> +static int
>> +nfb_eth_link_update(struct rte_eth_dev *dev,
>> +       int wait_to_complete __rte_unused)
>> +{
>> +       uint16_t i;
>> +       struct rte_eth_link link;
>> +       memset(&link, 0, sizeof(link));
>> +
>> +       struct pmd_internals *internals = (struct pmd_internals *)
>> +               dev->data->dev_private;
>> +
>> +       struct nc_rxmac_status status;
>> +       status.speed = MAC_SPEED_UNKNOWN;
>> +
>> +       link.link_speed = ETH_SPEED_NUM_NONE;
>> +       link.link_status = ETH_LINK_DOWN;
>> +       link.link_duplex = ETH_LINK_FULL_DUPLEX;
>> +       link.link_autoneg = ETH_LINK_SPEED_FIXED;
>> +
>> +       if (internals->rxmac[0] != NULL) {
>> +               nc_rxmac_read_status(internals->rxmac[0], &status);
>> +
>> +               switch (status.speed) {
>> +               case MAC_SPEED_10G:
>> +                       link.link_speed = ETH_SPEED_NUM_10G;
>> +                       break;
>> +               case MAC_SPEED_40G:
>> +                       link.link_speed = ETH_SPEED_NUM_40G;
>> +                       break;
>> +               case MAC_SPEED_100G:
>> +                       link.link_speed = ETH_SPEED_NUM_100G;
>> +                       break;
>> +               default:
>> +                       link.link_speed = ETH_SPEED_NUM_NONE;
>> +                       break;
>> +               }
>> +       }
>> +
>> +       i = 0;
>> +       for (i = 0; i < internals->max_rxmac; ++i) {
>> +               nc_rxmac_read_status(internals->rxmac[i], &status);
>> +
>> +               if (status.enabled && status.link_up) {
>> +                       link.link_status = ETH_LINK_UP;
>> +                       break;
>> +               }
>> +       }
>> +
>> +       rte_eth_linkstatus_set(dev, &link);
>> +
>> +       return 0;
>> +}
>> +
>> +/**
>> + * DPDK callback to bring the link UP.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + *
>> + * @return
>> + *   0 on success, a negative errno value otherwise and rte_errno is set.
>> + */
>> +static int
>> +nfb_eth_dev_set_link_up(struct rte_eth_dev *dev)
>> +{
>> +       struct pmd_internals *internals = (struct pmd_internals *)
>> +               dev->data->dev_private;
>> +
>> +       uint16_t i;
>> +       for (i = 0; i < internals->max_rxmac; ++i)
>> +               nc_rxmac_enable(internals->rxmac[i]);
>> +
>> +       for (i = 0; i < internals->max_txmac; ++i)
>> +               nc_txmac_enable(internals->txmac[i]);
>> +
>> +       return 0;
>> +}
>> +
>> +/**
>> + * DPDK callback to bring the link DOWN.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + *
>> + * @return
>> + *   0 on success, a negative errno value otherwise and rte_errno is set.
>> + */
>> +static int
>> +nfb_eth_dev_set_link_down(struct rte_eth_dev *dev)
>> +{
>> +       struct pmd_internals *internals = (struct pmd_internals *)
>> +               dev->data->dev_private;
>> +
>> +       uint16_t i;
>> +       for (i = 0; i < internals->max_rxmac; ++i)
>> +               nc_rxmac_disable(internals->rxmac[i]);
>> +
>> +       for (i = 0; i < internals->max_txmac; ++i)
>> +               nc_txmac_disable(internals->txmac[i]);
>> +
>> +       return 0;
>> +}
>> +
>> +/**
>> + * DPDK callback to set primary MAC address.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + * @param mac_addr
>> + *   MAC address to register.
>> + *
>> + * @return
>> + *   0 on success, a negative errno value otherwise and rte_errno is set.
>> + */
>> +static int
>> +nfb_eth_mac_addr_set(struct rte_eth_dev *dev __rte_unused,
>> +       struct ether_addr *mac_addr __rte_unused)
>> +{
>> +       return 0;
>> +}
>> +
>> +static const struct eth_dev_ops ops = {
>> +       .dev_start = nfb_eth_dev_start,
>> +       .dev_stop = nfb_eth_dev_stop,
>> +       .dev_set_link_up = nfb_eth_dev_set_link_up,
>> +       .dev_set_link_down = nfb_eth_dev_set_link_down,
>> +       .dev_close = nfb_eth_dev_close,
>> +       .dev_configure = nfb_eth_dev_configure,
>> +       .dev_infos_get = nfb_eth_dev_info,
>> +       .promiscuous_enable = nfb_eth_promiscuous_enable,
>> +       .promiscuous_disable = nfb_eth_promiscuous_disable,
>> +       .allmulticast_enable = nfb_eth_allmulticast_enable,
>> +       .allmulticast_disable = nfb_eth_allmulticast_disable,
>> +       .rx_queue_start = nfb_eth_rx_queue_start,
>> +       .rx_queue_stop = nfb_eth_rx_queue_stop,
>> +       .tx_queue_start = nfb_eth_tx_queue_start,
>> +       .tx_queue_stop = nfb_eth_tx_queue_stop,
>> +       .rx_queue_setup = nfb_eth_rx_queue_setup,
>> +       .tx_queue_setup = nfb_eth_tx_queue_setup,
>> +       .rx_queue_release = nfb_eth_rx_queue_release,
>> +       .tx_queue_release = nfb_eth_tx_queue_release,
>> +       .link_update = nfb_eth_link_update,
>> +       .stats_get = nfb_eth_stats_get,
>> +       .stats_reset = nfb_eth_stats_reset,
>> +       .mac_addr_set = nfb_eth_mac_addr_set,
>> +};
>> +
>> +/**
>> + * DPDK callback to initialize an ethernet device
>> + *
>> + * @param dev
>> + *   Pointer to ethernet device structure
>> + *
>> + * @return
>> + *   0 on success, a negative errno value otherwise and rte_errno is set.
>> + */
>> +static int
>> +nfb_eth_dev_init(struct rte_eth_dev *dev)
>> +{
>> +       struct rte_eth_dev_data *data = dev->data;
>> +       struct pmd_internals *internals = (struct pmd_internals *)
>> +               data->dev_private;
>> +       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
>> +       struct rte_pci_addr *pci_addr = &pci_dev->addr;
>> +
>> +       RTE_LOG(INFO, PMD, "Initializing NFB device (" PCI_PRI_FMT ")\n",
>> +               pci_addr->domain, pci_addr->bus, pci_addr->devid,
>> +               pci_addr->function);
>> +
>> +       snprintf(internals->nfb_dev, PATH_MAX,
>> +               "/dev/nfb/by-pci-slot/" PCI_PRI_FMT,
>> +               pci_addr->domain, pci_addr->bus, pci_addr->devid,
>> +               pci_addr->function);
>> +
>> +       /*
>> +        * Get number of available DMA RX and TX queues, which is maximum
>> +        * number of queues that can be created and store it in private
>> device
>> +        * data structure.
>> +        */
>> +       internals->nfb = nfb_open(internals->nfb_dev);
>> +       if (internals->nfb == NULL) {
>> +               RTE_LOG(ERR, PMD, "nfb_open(): failed to open %s",
>> +                       internals->nfb_dev);
>> +               return -EINVAL;
>> +       }
>> +       data->nb_rx_queues =
>> ndp_get_rx_queue_available_count(internals->nfb);
>> +       data->nb_tx_queues =
>> ndp_get_tx_queue_available_count(internals->nfb);
>> +
>> +       RTE_LOG(INFO, PMD, "Available NDP queues RX: %u TX: %u\n",
>> +               data->nb_rx_queues, data->nb_tx_queues);
>> +
>> +       nfb_nc_rxmac_init(internals->nfb,
>> +               internals->rxmac,
>> +               &internals->max_rxmac);
>> +       nfb_nc_txmac_init(internals->nfb,
>> +               internals->txmac,
>> +               &internals->max_txmac);
>> +
>> +       /* Set rx, tx burst functions */
>> +       dev->rx_pkt_burst = nfb_eth_ndp_rx;
>> +       dev->tx_pkt_burst = nfb_eth_ndp_tx;
>> +
>> +       /* Set function callbacks for Ethernet API */
>> +       dev->dev_ops = &ops;
>> +
>> +       rte_eth_copy_pci_info(dev, pci_dev);
>> +
>> +       /* Get link state */
>> +       nfb_eth_link_update(dev, 0);
>> +
>> +       /* Allocate space for one mac address */
>> +       data->mac_addrs = rte_zmalloc(data->name, sizeof(struct
>> ether_addr),
>> +               RTE_CACHE_LINE_SIZE);
>> +       if (data->mac_addrs == NULL) {
>> +               RTE_LOG(ERR, PMD, "Could not alloc space for MAC
>> address!\n");
>> +               nfb_close(internals->nfb);
>> +               return -EINVAL;
>> +       }
>> +
>> +       ether_addr_copy(&eth_addr, data->mac_addrs);
>> +
>> +       data->promiscuous = nfb_eth_promiscuous_get(dev);
>> +       data->all_multicast = nfb_eth_allmulticast_get(dev);
>> +       internals->rx_filter_original = data->promiscuous;
>> +
>> +       RTE_LOG(INFO, PMD, "NFB device ("
>> +               PCI_PRI_FMT ") successfully initialized\n",
>> +               pci_addr->domain, pci_addr->bus, pci_addr->devid,
>> +               pci_addr->function);
>> +
>> +       return 0;
>> +}
>> +
>> +/**
>> + * DPDK callback to uninitialize an ethernet device
>> + *
>> + * @param dev
>> + *   Pointer to ethernet device structure
>> + *
>> + * @return
>> + *   0 on success, a negative errno value otherwise and rte_errno is set.
>> + */
>> +static int
>> +nfb_eth_dev_uninit(struct rte_eth_dev *dev)
>> +{
>> +       struct rte_eth_dev_data *data = dev->data;
>> +       struct pmd_internals *internals = (struct pmd_internals *)
>> +               data->dev_private;
>> +
>> +       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
>> +       struct rte_pci_addr *pci_addr = &pci_dev->addr;
>> +
>> +       rte_free(dev->data->mac_addrs);
>> +       dev->data->mac_addrs = NULL;
>> +
>> +       nfb_nc_rxmac_deinit(internals->rxmac, internals->max_rxmac);
>> +       nfb_nc_txmac_deinit(internals->txmac, internals->max_txmac);
>> +
>> +       RTE_LOG(INFO, PMD, "NFB device ("
>> +               PCI_PRI_FMT ") successfully uninitialized\n",
>> +               pci_addr->domain, pci_addr->bus, pci_addr->devid,
>> +               pci_addr->function);
>> +
>> +       return 0;
>> +}
>> +
>> +static const struct rte_pci_id nfb_pci_id_table[] = {
>> +       {
>> +               RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE,
>> PCI_DEVICE_ID_NFB_40G2)
>> +       },
>> +       {
>> +               RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE,
>> PCI_DEVICE_ID_NFB_100G2)
>> +       },
>> +       {
>> +               RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE,
>> PCI_DEVICE_ID_NFB_200G2QL)
>> +       },
>> +       {
>> +               .vendor_id = 0,
>> +       }
>> +};
>> +
>> +/**
>> + * DPDK callback to register a PCI device.
>> + *
>> + * This function spawns Ethernet devices out of a given PCI device.
>> + *
>> + * @param[in] pci_drv
>> + *   PCI driver structure (nfb_driver).
>> + * @param[in] pci_dev
>> + *   PCI device information.
>> + *
>> + * @return
>> + *   0 on success, a negative errno value otherwise and rte_errno is set.
>> + */
>> +static int nfb_eth_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
>> +       struct rte_pci_device *pci_dev)
>> +{
>> +       return rte_eth_dev_pci_generic_probe(pci_dev,
>> +               sizeof(struct pmd_internals), nfb_eth_dev_init);
>> +}
>> +
>> +/**
>> + * DPDK callback to remove a PCI device.
>> + *
>> + * This function removes all Ethernet devices belong to a given PCI
>> device.
>> + *
>> + * @param[in] pci_dev
>> + *   Pointer to the PCI device.
>> + *
>> + * @return
>> + *   0 on success, the function cannot fail.
>> + */
>> +static int nfb_eth_pci_remove(struct rte_pci_device *pci_dev)
>> +{
>> +       return rte_eth_dev_pci_generic_remove(pci_dev,
>> nfb_eth_dev_uninit);
>> +}
>> +
>> +static struct rte_pci_driver nfb_eth_driver = {
>> +       .id_table = nfb_pci_id_table,
>> +       .probe = nfb_eth_pci_probe,
>> +       .remove = nfb_eth_pci_remove,
>> +};
>> +
>> +RTE_PMD_REGISTER_PCI(RTE_NFB_DRIVER_NAME, nfb_eth_driver);
>> +RTE_PMD_REGISTER_PCI_TABLE(RTE_NFB_DRIVER_NAME, nfb_pci_id_table);
>> +RTE_PMD_REGISTER_KMOD_DEP(RTE_NFB_DRIVER_NAME, "* nfb");
>> diff --git a/drivers/net/nfb/nfb_rx.c b/drivers/net/nfb/nfb_rx.c
>> new file mode 100644
>> index 0000000..dc1cd2d
>> --- /dev/null
>> +++ b/drivers/net/nfb/nfb_rx.c
>> @@ -0,0 +1,127 @@
>> +/* SPDX-License-Identifier: BSD-3-Clause
>> + * Copyright(c) 2018 Cesnet
>> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
>> + * All rights reserved.
>> + */
>> +
>> +#include "nfb_rx.h"
>> +#include "nfb.h"
>> +
>> +
>> +int
>> +nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id)
>> +{
>> +       struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
>> +
>> +       if (rxq->queue == NULL) {
>> +               RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
>> +               return -EINVAL;
>> +       }
>> +
>> +       int ret = ndp_queue_start(rxq->queue);
>> +       if (ret != 0)
>> +               goto err;
>> +       dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STARTED;
>> +       return 0;
>> +
>> +err:
>> +       return -EINVAL;
>> +}
>> +
>> +
>> +
>> +int
>> +nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id)
>> +{
>> +       struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
>> +
>> +       if (rxq->queue == NULL) {
>> +               RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
>> +               return -EINVAL;
>> +       }
>> +
>> +       int ret = ndp_queue_stop(rxq->queue);
>> +       if (ret != 0)
>> +               return -EINVAL;
>> +
>> +       dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
>> +       return 0;
>> +}
>> +
>> +int
>> +nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
>> +               uint16_t rx_queue_id,
>> +               uint16_t nb_rx_desc __rte_unused,
>> +               unsigned int socket_id,
>> +               const struct rte_eth_rxconf *rx_conf __rte_unused,
>> +               struct rte_mempool *mb_pool)
>> +{
>> +       struct pmd_internals *internals = dev->data->dev_private;
>> +
>> +       struct ndp_rx_queue *rxq;
>> +
>> +       rxq = rte_zmalloc_socket("ndp rx queue",
>> +                       sizeof(struct ndp_rx_queue),
>> +                       RTE_CACHE_LINE_SIZE, socket_id);
>> +
>> +       if (rxq == NULL) {
>> +               RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for rx
>> queue id "
>> +                               "%" PRIu16 "!\n", rx_queue_id);
>> +               return -ENOMEM;
>> +       }
>> +
>> +       int ret = nfb_eth_rx_queue_init(internals->nfb,
>> +               rx_queue_id,
>> +               dev->data->port_id,
>> +               mb_pool,
>> +               rxq);
>> +
>> +       if (ret == 0)
>> +               dev->data->rx_queues[rx_queue_id] = rxq;
>> +       else
>> +               rte_free(rxq);
>> +
>> +       return ret;
>> +}
>> +
>> +int
>> +nfb_eth_rx_queue_init(struct nfb_device *nfb,
>> +               uint16_t rx_queue_id,
>> +               uint16_t port_id,
>> +               struct rte_mempool *mb_pool,
>> +               struct ndp_rx_queue *rxq)
>> +{
>> +       if (nfb == NULL)
>> +               return -EINVAL;
>> +
>> +       rxq->queue = ndp_open_rx_queue(nfb, rx_queue_id);
>> +       if (rxq->queue == NULL)
>> +               return -EINVAL;
>> +
>> +       rxq->nfb = nfb;
>> +       rxq->rx_queue_id = rx_queue_id;
>> +       rxq->in_port = port_id;
>> +       rxq->mb_pool = mb_pool;
>> +
>> +       const struct rte_pktmbuf_pool_private *mbp_priv =
>> +               rte_mempool_get_priv(mb_pool);
>> +       rxq->buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size -
>> +               RTE_PKTMBUF_HEADROOM);
>> +
>> +       rxq->rx_pkts = 0;
>> +       rxq->rx_bytes = 0;
>> +       rxq->err_pkts = 0;
>> +
>> +       return 0;
>> +}
>> +
>> +void
>> +nfb_eth_rx_queue_release(void *q)
>> +{
>> +       struct ndp_rx_queue *rxq = (struct ndp_rx_queue *)q;
>> +       if (rxq->queue != NULL) {
>> +               ndp_close_rx_queue(rxq->queue);
>> +               rte_free(rxq);
>> +               rxq->queue = NULL;
>> +       }
>> +}
>> diff --git a/drivers/net/nfb/nfb_rx.h b/drivers/net/nfb/nfb_rx.h
>> new file mode 100644
>> index 0000000..b356f5d
>> --- /dev/null
>> +++ b/drivers/net/nfb/nfb_rx.h
>> @@ -0,0 +1,226 @@
>> +/* SPDX-License-Identifier: BSD-3-Clause
>> + * Copyright(c) 2018 Cesnet
>> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
>> + * All rights reserved.
>> + */
>> +
>> +
>> +
>> +#ifndef _NFB_RX_H_
>> +#define _NFB_RX_H_
>> +
>> +#include <stdint.h>
>> +#include <unistd.h>
>> +#include <stdbool.h>
>> +#include <err.h>
>> +#include <sys/types.h>
>> +
>> +#include <sys/mman.h>
>> +
>> +#include <nfb/nfb.h>
>> +#include <nfb/ndp.h>
>> +
>> +
>> +#include <rte_mbuf.h>
>> +#include <rte_ethdev.h>
>> +#include <rte_malloc.h>
>> +#include <rte_memcpy.h>
>> +#include <rte_dev.h>
>> +
>> +struct ndp_rx_queue {
>> +       struct nfb_device *nfb;      /* nfb dev structure */
>> +       struct ndp_queue *queue;     /* rx queue */
>> +       uint16_t rx_queue_id;        /* index */
>> +       uint8_t in_port;             /* port */
>> +
>> +       struct rte_mempool *mb_pool; /* memory pool to allocate packets */
>> +       uint16_t buf_size;           /* mbuf size */
>> +
>> +       volatile uint64_t rx_pkts;   /* packets read */
>> +       volatile uint64_t rx_bytes;  /* bytes read */
>> +       volatile uint64_t err_pkts;  /* erroneous packets */
>> +};
>> +
>> +/**
>> + * Initialize ndp_rx_queue structure
>> + *
>> + * @param nfb
>> + *   Pointer to nfb device structure.
>> + * @param rx_queue_id
>> + *   RX queue index.
>> + * @param port_id
>> + *   Device [external] port identifier.
>> + * @param mb_pool
>> + *   Memory pool for buffer allocations.
>> + * @param[out] rxq
>> + *   Pointer to ndp_rx_queue output structure
>> + * @return
>> + *   0 on success, a negative errno value otherwise and rte_errno is set.
>> + */
>> +int
>> +nfb_eth_rx_queue_init(struct nfb_device *nfb,
>> +       uint16_t rx_queue_id,
>> +       uint16_t port_id,
>> +       struct rte_mempool *mb_pool,
>> +       struct ndp_rx_queue *rxq);
>> +
>> +
>> +/**
>> + * DPDK callback to setup a RX queue for use.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + * @param idx
>> + *   RX queue index.
>> + * @param desc
>> + *   Number of descriptors to configure in queue.
>> + * @param socket
>> + *   NUMA socket on which memory must be allocated.
>> + * @param[in] conf
>> + *   Thresholds parameters.
>> + * @param mb_pool
>> + *   Memory pool for buffer allocations.
>> + *
>> + * @return
>> + *   0 on success, a negative errno value otherwise and rte_errno is set.
>> + */
>> +int
>> +nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
>> +       uint16_t rx_queue_id,
>> +       uint16_t nb_rx_desc __rte_unused,
>> +       unsigned int socket_id,
>> +       const struct rte_eth_rxconf *rx_conf __rte_unused,
>> +       struct rte_mempool *mb_pool);
>> +
>> +
>> +/**
>> + * DPDK callback to release a RX queue.
>> + *
>> + * @param dpdk_rxq
>> + *   Generic RX queue pointer.
>> + */
>> +void
>> +nfb_eth_rx_queue_release(void *q);
>> +
>> +/**
>> + * Start traffic on Rx queue.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + * @param txq_id
>> + *   RX queue index.
>> + * @return
>> + *   0 on success, a negative errno value otherwise and rte_errno is set.
>> + */
>> +int
>> +nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id);
>> +
>> +/**
>> + * Stop traffic on Rx queue.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + * @param txq_id
>> + *   RX queue index.
>> + */
>> +int
>> +nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id);
>> +
>> +/**
>> + * DPDK callback for RX.
>> + *
>> + * @param dpdk_rxq
>> + *   Generic pointer to RX queue structure.
>> + * @param[out] bufs
>> + *   Array to store received packets.
>> + * @param nb_pkts
>> + *   Maximum number of packets in array.
>> + *
>> + * @return
>> + *   Number of packets successfully received (<= nb_pkts).
>> + */
>> +static __rte_always_inline uint16_t
>> +nfb_eth_ndp_rx(void *queue,
>> +       struct rte_mbuf **bufs,
>> +       uint16_t nb_pkts)
>> +{
>> +       struct ndp_rx_queue *ndp = queue;
>> +
>> +       if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
>> +               RTE_LOG(ERR, PMD, "RX invalid arguments!\n");
>> +               return 0;
>> +       }
>> +
>> +       struct rte_mbuf *mbufs[nb_pkts];
>> +
>> +       unsigned int i;
>> +       // returns either all or nothing
>> +       i = rte_pktmbuf_alloc_bulk(ndp->mb_pool, mbufs, nb_pkts);
>> +       if (unlikely(i != 0))
>> +               return 0;
>> +
>> +       uint16_t packet_size;
>> +       uint64_t num_bytes = 0;
>> +       const uint16_t buf_size = ndp->buf_size;
>> +
>> +       struct rte_mbuf *mbuf;
>> +       struct ndp_packet packets[nb_pkts];
>> +
>> +
>> +       uint16_t num_rx = ndp_rx_burst_get(ndp->queue, packets, nb_pkts);
>> +
>> +       if (unlikely(num_rx != nb_pkts)) {
>> +               for (i = num_rx; i < nb_pkts; i++)
>> +                       rte_pktmbuf_free(mbufs[i]);
>> +       }
>> +
>> +       nb_pkts = num_rx;
>> +
>> +       num_rx = 0;
>> +       /*
>> +        * Reads the given number of packets from NDP queue given
>> +        * by queue and copies the packet data into a newly allocated mbuf
>> +        * to return.
>> +        */
>> +       for (i = 0; i < nb_pkts; ++i) {
>> +               mbuf = mbufs[i];
>> +
>> +               /* get the space available for data in the mbuf */
>> +               packet_size = packets[i].data_length;
>> +
>> +               if (likely(packet_size <= buf_size)) {
>> +                       /* NDP packet will fit in one mbuf, go ahead and
>> copy */
>> +                       rte_memcpy(rte_pktmbuf_mtod(mbuf, void *),
>> +                               packets[i].data, packet_size);
>> +
>> +                       mbuf->data_len = (uint16_t)packet_size;
>> +
>> +                       mbuf->pkt_len = packet_size;
>> +                       mbuf->port = ndp->in_port;
>> +                       bufs[num_rx++] = mbuf;
>> +                       num_bytes += packet_size;
>> +               } else {
>> +                       /*
>> +                        * NDP packet will not fit in one mbuf,
>> +                        * scattered mode is not enabled, drop packet
>> +                        */
>> +                       RTE_LOG(ERR, PMD,
>> +                               "NDP segment %d bytes will not fit in one
>> mbuf "
>> +                               "(%d bytes), scattered mode is not
>> enabled, "
>> +                               "drop packet!!\n",
>> +                               packet_size, buf_size);
>> +                       rte_pktmbuf_free(mbuf);
>> +               }
>> +       }
>> +
>> +
>> +       ndp_rx_burst_put(ndp->queue);
>> +
>> +       ndp->rx_pkts += num_rx;
>> +       ndp->rx_bytes += num_bytes;
>> +       return num_rx;
>> +}
>> +
>> +
>> +
>> +#endif /* _NFB_RX_H_ */
>> diff --git a/drivers/net/nfb/nfb_rxmode.c b/drivers/net/nfb/nfb_rxmode.c
>> new file mode 100644
>> index 0000000..8a63507
>> --- /dev/null
>> +++ b/drivers/net/nfb/nfb_rxmode.c
>> @@ -0,0 +1,104 @@
>> +/* SPDX-License-Identifier: BSD-3-Clause
>> + * Copyright(c) 2018 Cesnet
>> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
>> + * All rights reserved.
>> + */
>> +
>> +
>> +#include "nfb_rxmode.h"
>> +#include "nfb.h"
>> +
>> +void
>> +nfb_eth_promiscuous_enable(struct rte_eth_dev *dev)
>> +{
>> +       struct pmd_internals *internals = (struct pmd_internals *)
>> +               dev->data->dev_private;
>> +
>> +       internals->rx_filter_original = RXMAC_MAC_FILTER_PROMISCUOUS;
>> +
>> +
>> +       uint16_t i;
>> +       for (i = 0; i < internals->max_rxmac; ++i) {
>> +               nc_rxmac_mac_filter_enable(internals->rxmac[i],
>> +                       RXMAC_MAC_FILTER_PROMISCUOUS);
>> +       }
>> +}
>> +
>> +void
>> +nfb_eth_promiscuous_disable(struct rte_eth_dev *dev)
>> +{
>> +       struct pmd_internals *internals = (struct pmd_internals *)
>> +               dev->data->dev_private;
>> +
>> +       internals->rx_filter_original = RXMAC_MAC_FILTER_TABLE;
>> +
>> +
>> +       // if promisc is not enabled, do nothing
>> +       if (!nfb_eth_promiscuous_get(dev))
>> +               return;
>> +
>> +       uint16_t i;
>> +       for (i = 0; i < internals->max_rxmac; ++i) {
>> +               nc_rxmac_mac_filter_enable(internals->rxmac[i],
>> +                       RXMAC_MAC_FILTER_TABLE);
>> +       }
>> +}
>> +
>> +int
>> +nfb_eth_promiscuous_get(struct rte_eth_dev *dev)
>> +{
>> +       struct pmd_internals *internals = (struct pmd_internals *)
>> +               dev->data->dev_private;
>> +
>> +       struct nc_rxmac_status status;
>> +       status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
>> +
>> +       nc_rxmac_read_status(internals->rxmac[0], &status);
>> +
>> +       return (status.mac_filter == RXMAC_MAC_FILTER_PROMISCUOUS);
>> +}
>> +
>> +void
>> +nfb_eth_allmulticast_enable(struct rte_eth_dev *dev)
>> +{
>> +       struct pmd_internals *internals = (struct pmd_internals *)
>> +               dev->data->dev_private;
>> +
>> +       uint16_t i;
>> +       for (i = 0; i < internals->max_rxmac; ++i) {
>> +               nc_rxmac_mac_filter_enable(internals->rxmac[i],
>> +                       RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
>> +       }
>> +}
>> +
>> +void
>> +nfb_eth_allmulticast_disable(struct rte_eth_dev *dev)
>> +{
>> +       // if multicast is not enabled do nothing
>> +       if (!nfb_eth_allmulticast_get(dev))
>> +               return;
>> +
>> +       struct pmd_internals *internals = (struct pmd_internals *)
>> +               dev->data->dev_private;
>> +
>> +
>> +       uint16_t i;
>> +       for (i = 0; i < internals->max_rxmac; ++i) {
>> +               nc_rxmac_mac_filter_enable(internals->rxmac[i],
>> +                       internals->rx_filter_original);
>> +       }
>> +}
>> +
>> +int
>> +nfb_eth_allmulticast_get(struct rte_eth_dev *dev)
>> +{
>> +       struct pmd_internals *internals = (struct pmd_internals *)
>> +               dev->data->dev_private;
>> +
>> +       struct nc_rxmac_status status;
>> +       status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
>> +       nc_rxmac_read_status(internals->rxmac[0], &status);
>> +
>> +
>> +       return (status.mac_filter == RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
>> +}
>> diff --git a/drivers/net/nfb/nfb_rxmode.h b/drivers/net/nfb/nfb_rxmode.h
>> new file mode 100644
>> index 0000000..2a72b10
>> --- /dev/null
>> +++ b/drivers/net/nfb/nfb_rxmode.h
>> @@ -0,0 +1,81 @@
>> +/* SPDX-License-Identifier: BSD-3-Clause
>> + * Copyright(c) 2018 Cesnet
>> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
>> + * All rights reserved.
>> + */
>> +
>> +#ifndef _NFB_RXMODE_H_
>> +#define _NFB_RXMODE_H_
>> +
>> +#include <stdint.h>
>> +#include <unistd.h>
>> +#include <stdbool.h>
>> +#include <err.h>
>> +#include <sys/types.h>
>> +
>> +#include <sys/mman.h>
>> +
>> +#include <nfb/nfb.h>
>> +#include <nfb/ndp.h>
>> +
>> +#include <rte_ethdev.h>
>> +#include <rte_dev.h>
>> +
>> +/**
>> + * Getter for promiscuous mode
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + * @return 1 if enabled 0 otherwise
>> + */
>> +int
>> +nfb_eth_promiscuous_get(struct rte_eth_dev *dev);
>> +
>> +/**
>> + * DPDK callback to enable promiscuous mode.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + */
>> +void
>> +nfb_eth_promiscuous_enable(struct rte_eth_dev *dev);
>> +
>> +/**
>> + * DPDK callback to disable promiscuous mode.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + */
>> +void
>> +nfb_eth_promiscuous_disable(struct rte_eth_dev *dev);
>> +
>> +/**
>> + * Getter for allmulticast mode
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + * @return 1 if enabled 0 otherwise
>> + */
>> +int
>> +nfb_eth_allmulticast_get(struct rte_eth_dev *dev);
>> +
>> +/**
>> + * DPDK callback to enable allmulticast mode.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + */
>> +void
>> +nfb_eth_allmulticast_enable(struct rte_eth_dev *dev);
>> +
>> +/**
>> + * DPDK callback to disable allmulticast mode.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + */
>> +void
>> +nfb_eth_allmulticast_disable(struct rte_eth_dev *dev);
>> +
>> +
>> +
>> +
>> +#endif /* _NFB_RXMODE_H_ */
>> diff --git a/drivers/net/nfb/nfb_stats.c b/drivers/net/nfb/nfb_stats.c
>> new file mode 100644
>> index 0000000..f2750e4
>> --- /dev/null
>> +++ b/drivers/net/nfb/nfb_stats.c
>> @@ -0,0 +1,79 @@
>> +/* SPDX-License-Identifier: BSD-3-Clause
>> + * Copyright(c) 2018 Cesnet
>> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
>> + * All rights reserved.
>> + */
>> +
>> +
>> +#include "nfb_stats.h"
>> +#include "nfb.h"
>> +
>> +int
>> +nfb_eth_stats_get(struct rte_eth_dev *dev,
>> +       struct rte_eth_stats *stats)
>> +{
>> +       uint16_t i;
>> +       uint16_t nb_rx = dev->data->nb_rx_queues;
>> +       uint16_t nb_tx = dev->data->nb_tx_queues;
>> +       uint64_t rx_total = 0;
>> +       uint64_t tx_total = 0;
>> +       uint64_t tx_err_total = 0;
>> +       uint64_t rx_total_bytes = 0;
>> +       uint64_t tx_total_bytes = 0;
>> +
>> +       struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
>> +               dev->data->rx_queues);
>> +       struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
>> +               dev->data->tx_queues);
>> +
>> +       for (i = 0; i < nb_rx; i++) {
>> +               if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
>> +                       stats->q_ipackets[i] = rx_queue[i].rx_pkts;
>> +                       stats->q_ibytes[i] = rx_queue[i].rx_bytes;
>> +               }
>> +               rx_total += stats->q_ipackets[i];
>> +               rx_total_bytes += stats->q_ibytes[i];
>> +       }
>> +
>> +       for (i = 0; i < nb_tx; i++) {
>> +               if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
>> +                       stats->q_opackets[i] = tx_queue[i].tx_pkts;
>> +                       stats->q_obytes[i] = tx_queue[i].tx_bytes;
>> +                       stats->q_errors[i] = tx_queue[i].err_pkts;
>> +               }
>> +               tx_total += stats->q_opackets[i];
>> +               tx_total_bytes += stats->q_obytes[i];
>> +               tx_err_total += stats->q_errors[i];
>> +       }
>> +
>> +       stats->ipackets = rx_total;
>> +       stats->opackets = tx_total;
>> +       stats->ibytes = rx_total_bytes;
>> +       stats->obytes = tx_total_bytes;
>> +       stats->oerrors = tx_err_total;
>> +       return 0;
>> +}
>> +
>> +void
>> +nfb_eth_stats_reset(struct rte_eth_dev *dev)
>> +{
>> +       uint16_t i;
>> +       uint16_t nb_rx = dev->data->nb_rx_queues;
>> +       uint16_t nb_tx = dev->data->nb_tx_queues;
>> +
>> +       struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
>> +               dev->data->rx_queues);
>> +       struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
>> +               dev->data->tx_queues);
>> +
>> +       for (i = 0; i < nb_rx; i++) {
>> +               rx_queue[i].rx_pkts = 0;
>> +               rx_queue[i].rx_bytes = 0;
>> +               rx_queue[i].err_pkts = 0;
>> +       }
>> +       for (i = 0; i < nb_tx; i++) {
>> +               tx_queue[i].tx_pkts = 0;
>> +               tx_queue[i].tx_bytes = 0;
>> +               tx_queue[i].err_pkts = 0;
>> +       }
>> +}
>> diff --git a/drivers/net/nfb/nfb_stats.h b/drivers/net/nfb/nfb_stats.h
>> new file mode 100644
>> index 0000000..d89ca4c
>> --- /dev/null
>> +++ b/drivers/net/nfb/nfb_stats.h
>> @@ -0,0 +1,52 @@
>> +/* SPDX-License-Identifier: BSD-3-Clause
>> + * Copyright(c) 2018 Cesnet
>> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
>> + * All rights reserved.
>> + */
>> +
>> +#ifndef _NFB_STATS_H_
>> +#define _NFB_STATS_H_
>> +
>> +#include <stdint.h>
>> +#include <unistd.h>
>> +#include <stdbool.h>
>> +#include <err.h>
>> +#include <sys/types.h>
>> +
>> +#include <sys/mman.h>
>> +
>> +#include <nfb/nfb.h>
>> +#include <nfb/ndp.h>
>> +
>> +#include <rte_mbuf.h>
>> +#include <rte_ethdev.h>
>> +#include <rte_malloc.h>
>> +#include <rte_memcpy.h>
>> +#include <rte_dev.h>
>> +
>> +/**
>> + * DPDK callback to get device statistics.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + * @param[out] stats
>> + *   Stats structure output buffer.
>> + *
>> + * @return
>> + *   0 on success and stats is filled, negative errno value otherwise and
>> + *   rte_errno is set.
>> + */
>> +int nfb_eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats
>> *stats);
>> +
>> +/**
>> + * DPDK callback to clear device statistics.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + */
>> +void nfb_eth_stats_reset(struct rte_eth_dev *dev);
>> +
>> +
>> +
>> +
>> +#endif /* _NFB_STATS_H_ */
>> diff --git a/drivers/net/nfb/nfb_tx.c b/drivers/net/nfb/nfb_tx.c
>> new file mode 100644
>> index 0000000..efaaa2b
>> --- /dev/null
>> +++ b/drivers/net/nfb/nfb_tx.c
>> @@ -0,0 +1,112 @@
>> +/* SPDX-License-Identifier: BSD-3-Clause
>> + * Copyright(c) 2018 Cesnet
>> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
>> + * All rights reserved.
>> + */
>> +
>> +
>> +#include "nfb_tx.h"
>> +#include "nfb.h"
>> +
>> +int
>> +nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id)
>> +{
>> +       struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
>> +
>> +       if (txq->queue == NULL) {
>> +               RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
>> +               return -EINVAL;
>> +       }
>> +
>> +       int ret = ndp_queue_start(txq->queue);
>> +       if (ret != 0)
>> +               goto err;
>> +       dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STARTED;
>> +       return 0;
>> +
>> +err:
>> +       return -EINVAL;
>> +}
>> +
>> +int
>> +nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id)
>> +{
>> +       struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
>> +
>> +       if (txq->queue != NULL) {
>> +               RTE_LOG(ERR, PMD, "TX NDP queue is NULL!\n");
>> +               return -EINVAL;
>> +       }
>> +
>> +       int ret = ndp_queue_stop(txq->queue);
>> +       if (ret != 0)
>> +               return -EINVAL;
>> +       dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
>> +       return 0;
>> +}
>> +
>> +int
>> +nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
>> +       uint16_t tx_queue_id,
>> +       uint16_t nb_tx_desc __rte_unused,
>> +       unsigned int socket_id,
>> +       const struct rte_eth_txconf *tx_conf __rte_unused)
>> +{
>> +       struct pmd_internals *internals = dev->data->dev_private;
>> +
>> +       struct ndp_tx_queue *txq;
>> +
>> +       txq = rte_zmalloc_socket("ndp tx queue",
>> +               sizeof(struct ndp_tx_queue),
>> +               RTE_CACHE_LINE_SIZE, socket_id);
>> +
>> +       if (txq == NULL) {
>> +               RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for tx
>> queue id "
>> +                       "%" PRIu16 "!\n", tx_queue_id);
>> +               return -ENOMEM;
>> +       }
>> +
>> +       int ret = nfb_eth_tx_queue_init(internals->nfb,
>> +               tx_queue_id,
>> +               txq);
>> +
>> +       if (ret == 0)
>> +               dev->data->tx_queues[tx_queue_id] = txq;
>> +       else
>> +               rte_free(txq);
>> +
>> +       return ret;
>> +}
>> +
>> +int
>> +nfb_eth_tx_queue_init(struct nfb_device *nfb,
>> +       uint16_t tx_queue_id,
>> +       struct ndp_tx_queue *txq)
>> +{
>> +       if (nfb == NULL)
>> +               return -EINVAL;
>> +
>> +       txq->queue = ndp_open_tx_queue(nfb, tx_queue_id);
>> +       if (txq->queue == NULL)
>> +               return -EINVAL;
>> +
>> +       txq->nfb = nfb;
>> +       txq->tx_queue_id = tx_queue_id;
>> +
>> +       txq->tx_pkts = 0;
>> +       txq->tx_bytes = 0;
>> +       txq->err_pkts = 0;
>> +
>> +       return 0;
>> +}
>> +
>> +void
>> +nfb_eth_tx_queue_release(void *q)
>> +{
>> +       struct ndp_tx_queue *txq = (struct ndp_tx_queue *)q;
>> +       if (txq->queue != NULL) {
>> +               ndp_close_tx_queue(txq->queue);
>> +               rte_free(txq);
>> +               txq->queue = NULL;
>> +       }
>> +}
>> diff --git a/drivers/net/nfb/nfb_tx.h b/drivers/net/nfb/nfb_tx.h
>> new file mode 100644
>> index 0000000..3ceb3bf
>> --- /dev/null
>> +++ b/drivers/net/nfb/nfb_tx.h
>> @@ -0,0 +1,209 @@
>> +/* SPDX-License-Identifier: BSD-3-Clause
>> + * Copyright(c) 2018 Cesnet
>> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
>> + * All rights reserved.
>> + */
>> +
>> +#ifndef _NFB_TX_H_
>> +#define _NFB_TX_H_
>> +
>> +#include <stdint.h>
>> +#include <unistd.h>
>> +#include <stdbool.h>
>> +#include <err.h>
>> +#include <sys/types.h>
>> +
>> +#include <sys/mman.h>
>> +
>> +#include <nfb/nfb.h>
>> +#include <nfb/ndp.h>
>> +
>> +#include <rte_mbuf.h>
>> +#include <rte_ethdev.h>
>> +#include <rte_malloc.h>
>> +#include <rte_memcpy.h>
>> +#include <rte_dev.h>
>> +
>> +struct ndp_tx_queue {
>> +       struct nfb_device *nfb;     /* nfb dev structure */
>> +       struct ndp_queue *queue;    /* tx queue */
>> +       uint16_t          tx_queue_id;       /* index */
>> +       volatile uint64_t tx_pkts;  /* packets transmitted */
>> +       volatile uint64_t tx_bytes; /* bytes transmitted */
>> +       volatile uint64_t err_pkts; /* erroneous packets */
>> +};
>> +
>> +
>> +/**
>> + * DPDK callback to setup a TX queue for use.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + * @param idx
>> + *   RX queue index.
>> + * @param desc
>> + *   Number of descriptors to configure in queue.
>> + * @param socket
>> + *   NUMA socket on which memory must be allocated.
>> + * @param[in] conf
>> + *   Thresholds parameters.
>> + * @param mp
>> + *   Memory pool for buffer allocations.
>> + *
>> + * @return
>> + *   0 on success, a negative errno value otherwise and rte_errno is set.
>> + */
>> +int
>> +nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
>> +       uint16_t tx_queue_id,
>> +       uint16_t nb_tx_desc __rte_unused,
>> +       unsigned int socket_id,
>> +       const struct rte_eth_txconf *tx_conf __rte_unused);
>> +
>> +/**
>> + * Initialize ndp_tx_queue structure
>> + *
>> + * @param nfb
>> + *   Pointer to nfb device structure.
>> + * @param tx_queue_id
>> + *   TX queue index.
>> + * @param[out] txq
>> + *   Pointer to ndp_tx_queue output structure
>> + *
>> + * @return
>> + *   0 on success, a negative errno value otherwise and rte_errno is set.
>> + */
>> +int
>> +nfb_eth_tx_queue_init(struct nfb_device *nfb,
>> +       uint16_t tx_queue_id,
>> +       struct ndp_tx_queue *txq);
>> +
>> +/**
>> + * DPDK callback to release a RX queue.
>> + *
>> + * @param dpdk_rxq
>> + *   Generic RX queue pointer.
>> + */
>> +void
>> +nfb_eth_tx_queue_release(void *q);
>> +
>> +
>> +/**
>> + * Start traffic on Tx queue.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + * @param txq_id
>> + *   TX queue index.
>> + *
>> + * @return
>> + *   0 on success, a negative errno value otherwise and rte_errno is set.
>> + */
>> +int
>> +nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id);
>> +
>> +/**
>> + * Stop traffic on Tx queue.
>> + *
>> + * @param dev
>> + *   Pointer to Ethernet device structure.
>> + * @param txq_id
>> + *   TX queue index.
>> + *
>> + * @return
>> + *   0 on success, a negative errno value otherwise and rte_errno is set.
>> + */
>> +int
>> +nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id);
>> +
>> +/**
>> + * DPDK callback for TX.
>> + *
>> + * @param dpdk_txq
>> + *   Generic pointer to TX queue structure.
>> + * @param bufs
>> + *   Packets to transmit.
>> + * @param nb_pkts
>> + *   Number of packets in array.
>> + *
>> + * @return
>> + *   Number of packets successfully transmitted (<= nb_pkts).
>> + */
>> +static __rte_always_inline uint16_t
>> +nfb_eth_ndp_tx(void *queue,
>> +       struct rte_mbuf **bufs,
>> +       uint16_t nb_pkts)
>> +{
>> +       int i;
>> +       struct rte_mbuf *mbuf;
>> +       struct ndp_tx_queue *ndp = queue;
>> +       uint16_t num_tx = 0;
>> +       uint64_t num_bytes = 0;
>> +
>> +       void *dst;
>> +       uint32_t pkt_len;
>> +       uint8_t mbuf_segs;
>> +
>> +       struct ndp_packet packets[nb_pkts];
>> +
>> +       if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
>> +               RTE_LOG(ERR, PMD, "RX invalid arguments!\n");
>> +               return 0;
>> +       }
>> +
>> +       for (i = 0; i < nb_pkts; i++) {
>> +               packets[i].data_length = bufs[i]->pkt_len;
>> +               packets[i].header_length = 0;
>> +       }
>> +
>> +       num_tx = ndp_tx_burst_get(ndp->queue, packets, nb_pkts);
>> +
>> +       if (unlikely(num_tx != nb_pkts))
>> +               return 0;
>> +
>> +       for (i = 0; i < nb_pkts; ++i) {
>> +               mbuf = bufs[i];
>> +
>> +               pkt_len = mbuf->pkt_len;
>> +               mbuf_segs = mbuf->nb_segs;
>> +
>> +               num_bytes += pkt_len;
>> +               if (mbuf_segs == 1) {
>> +                       /*
>> +                        * non-scattered packet,
>> +                        * transmit from one mbuf
>> +                        */
>> +                       rte_memcpy(packets[i].data,
>> +                               rte_pktmbuf_mtod(mbuf, const void *),
>> +                               pkt_len);
>> +               } else {
>> +                       /* scattered packet, transmit from more mbufs */
>> +                       struct rte_mbuf *m = mbuf;
>> +                       while (m) {
>> +                               dst = packets[i].data;
>> +
>> +                               rte_memcpy(dst,
>> +                                       rte_pktmbuf_mtod(m,
>> +                                       const void *),
>> +                                       m->data_len);
>> +                               dst = ((uint8_t *)(dst)) +
>> +                                       m->data_len;
>> +                               m = m->next;
>> +                       }
>> +               }
>> +
>> +               rte_pktmbuf_free(mbuf);
>> +       }
>> +
>> +       ndp_tx_burst_flush(ndp->queue);
>> +
>> +       ndp->tx_pkts += num_tx;
>> +       ndp->err_pkts += nb_pkts - num_tx;
>> +       ndp->tx_bytes += num_bytes;
>> +       return num_tx;
>> +}
>> +
>> +
>> +
>> +
>> +#endif /* _NFB_TX_H_ */
>> diff --git a/examples/skeleton/basicfwd.c b/examples/skeleton/basicfwd.c
>> deleted file mode 100644
>> index 4aba1dc..0000000
>> --- a/examples/skeleton/basicfwd.c
>> +++ /dev/null
>> @@ -1,198 +0,0 @@
>> -/* SPDX-License-Identifier: BSD-3-Clause
>> - * Copyright(c) 2010-2015 Intel Corporation
>> - */
>> -
>> -#include <stdint.h>
>> -#include <inttypes.h>
>> -#include <rte_eal.h>
>> -#include <rte_ethdev.h>
>> -#include <rte_cycles.h>
>> -#include <rte_lcore.h>
>> -#include <rte_mbuf.h>
>> -
>> -#define RX_RING_SIZE 1024
>> -#define TX_RING_SIZE 1024
>> -
>> -#define NUM_MBUFS 8191
>> -#define MBUF_CACHE_SIZE 250
>> -#define BURST_SIZE 32
>> -
>> -static const struct rte_eth_conf port_conf_default = {
>> -       .rxmode = {
>> -               .max_rx_pkt_len = ETHER_MAX_LEN,
>> -       },
>> -};
>> -
>> -/* basicfwd.c: Basic DPDK skeleton forwarding example. */
>> -
>> -/*
>> - * Initializes a given port using global settings and with the RX buffers
>> - * coming from the mbuf_pool passed as a parameter.
>> - */
>> -static inline int
>> -port_init(uint16_t port, struct rte_mempool *mbuf_pool)
>> -{
>> -       struct rte_eth_conf port_conf = port_conf_default;
>> -       const uint16_t rx_rings = 1, tx_rings = 1;
>> -       uint16_t nb_rxd = RX_RING_SIZE;
>> -       uint16_t nb_txd = TX_RING_SIZE;
>> -       int retval;
>> -       uint16_t q;
>> -       struct rte_eth_dev_info dev_info;
>> -       struct rte_eth_txconf txconf;
>> -
>> -       if (!rte_eth_dev_is_valid_port(port))
>> -               return -1;
>> -
>> -       rte_eth_dev_info_get(port, &dev_info);
>> -       if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
>> -               port_conf.txmode.offloads |=
>> -                       DEV_TX_OFFLOAD_MBUF_FAST_FREE;
>> -
>> -       /* Configure the Ethernet device. */
>> -       retval = rte_eth_dev_configure(port, rx_rings, tx_rings,
>> &port_conf);
>> -       if (retval != 0)
>> -               return retval;
>> -
>> -       retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd);
>> -       if (retval != 0)
>> -               return retval;
>> -
>> -       /* Allocate and set up 1 RX queue per Ethernet port. */
>> -       for (q = 0; q < rx_rings; q++) {
>> -               retval = rte_eth_rx_queue_setup(port, q, nb_rxd,
>> -                               rte_eth_dev_socket_id(port), NULL,
>> mbuf_pool);
>> -               if (retval < 0)
>> -                       return retval;
>> -       }
>> -
>> -       txconf = dev_info.default_txconf;
>> -       txconf.offloads = port_conf.txmode.offloads;
>> -       /* Allocate and set up 1 TX queue per Ethernet port. */
>> -       for (q = 0; q < tx_rings; q++) {
>> -               retval = rte_eth_tx_queue_setup(port, q, nb_txd,
>> -                               rte_eth_dev_socket_id(port), &txconf);
>> -               if (retval < 0)
>> -                       return retval;
>> -       }
>> -
>> -       /* Start the Ethernet port. */
>> -       retval = rte_eth_dev_start(port);
>> -       if (retval < 0)
>> -               return retval;
>> -
>> -       /* Display the port MAC address. */
>> -       struct ether_addr addr;
>> -       rte_eth_macaddr_get(port, &addr);
>> -       printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8
>> -                          " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n",
>> -                       port,
>> -                       addr.addr_bytes[0], addr.addr_bytes[1],
>> -                       addr.addr_bytes[2], addr.addr_bytes[3],
>> -                       addr.addr_bytes[4], addr.addr_bytes[5]);
>> -
>> -       /* Enable RX in promiscuous mode for the Ethernet device. */
>> -       rte_eth_promiscuous_enable(port);
>> -
>> -       return 0;
>> -}
>> -
>> -/*
>> - * The lcore main. This is the main thread that does the work, reading
>> from
>> - * an input port and writing to an output port.
>> - */
>> -static __attribute__((noreturn)) void
>> -lcore_main(void)
>> -{
>> -       uint16_t port;
>> -
>> -       /*
>> -        * Check that the port is on the same NUMA node as the polling
>> thread
>> -        * for best performance.
>> -        */
>> -       RTE_ETH_FOREACH_DEV(port)
>> -               if (rte_eth_dev_socket_id(port) > 0 &&
>> -                               rte_eth_dev_socket_id(port) !=
>> -                                               (int)rte_socket_id())
>> -                       printf("WARNING, port %u is on remote NUMA node
>> to "
>> -                                       "polling thread.\n\tPerformance
>> will "
>> -                                       "not be optimal.\n", port);
>> -
>> -       printf("\nCore %u forwarding packets. [Ctrl+C to quit]\n",
>> -                       rte_lcore_id());
>> -
>> -       /* Run until the application is quit or killed. */
>> -       for (;;) {
>> -               /*
>> -                * Receive packets on a port and forward them on the
>> paired
>> -                * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2,
>> etc.
>> -                */
>> -               RTE_ETH_FOREACH_DEV(port) {
>> -
>> -                       /* Get burst of RX packets, from first port of
>> pair. */
>> -                       struct rte_mbuf *bufs[BURST_SIZE];
>> -                       const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
>> -                                       bufs, BURST_SIZE);
>> -
>> -                       if (unlikely(nb_rx == 0))
>> -                               continue;
>> -
>> -                       /* Send burst of TX packets, to second port of
>> pair. */
>> -                       const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1,
>> 0,
>> -                                       bufs, nb_rx);
>> -
>> -                       /* Free any unsent packets. */
>> -                       if (unlikely(nb_tx < nb_rx)) {
>> -                               uint16_t buf;
>> -                               for (buf = nb_tx; buf < nb_rx; buf++)
>> -                                       rte_pktmbuf_free(bufs[buf]);
>> -                       }
>> -               }
>> -       }
>> -}
>> -
>> -/*
>> - * The main function, which does initialization and calls the per-lcore
>> - * functions.
>> - */
>> -int
>> -main(int argc, char *argv[])
>> -{
>> -       struct rte_mempool *mbuf_pool;
>> -       unsigned nb_ports;
>> -       uint16_t portid;
>> -
>> -       /* Initialize the Environment Abstraction Layer (EAL). */
>> -       int ret = rte_eal_init(argc, argv);
>> -       if (ret < 0)
>> -               rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
>> -
>> -       argc -= ret;
>> -       argv += ret;
>> -
>> -       /* Check that there is an even number of ports to send/receive
>> on. */
>> -       nb_ports = rte_eth_dev_count_avail();
>> -       if (nb_ports < 2 || (nb_ports & 1))
>> -               rte_exit(EXIT_FAILURE, "Error: number of ports must be
>> even\n");
>> -
>> -       /* Creates a new mempool in memory to hold the mbufs. */
>> -       mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS *
>> nb_ports,
>> -               MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE,
>> rte_socket_id());
>> -
>> -       if (mbuf_pool == NULL)
>> -               rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
>> -
>> -       /* Initialize all ports. */
>> -       RTE_ETH_FOREACH_DEV(portid)
>> -               if (port_init(portid, mbuf_pool) != 0)
>> -                       rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu16
>> "\n",
>> -                                       portid);
>> -
>> -       if (rte_lcore_count() > 1)
>> -               printf("\nWARNING: Too many lcores enabled. Only 1
>> used.\n");
>> -
>> -       /* Call lcore_main on the master core only. */
>> -       lcore_main();
>> -
>> -       return 0;
>> -}
>> diff --git a/mk/rte.app.mk b/mk/rte.app.mk
>> index 8a4f0f4..32e88b5 100644
>> --- a/mk/rte.app.mk
>> +++ b/mk/rte.app.mk
>> @@ -196,6 +196,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC)      +=
>> -lrte_pmd_softnic
>>  endif
>>  _LDLIBS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD)    += -lrte_pmd_sfc_efx
>>  _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2 -lsze2
>> +_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NFB)        += -lrte_pmd_nfb -lnfb -lfdt
>>  _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_TAP)        += -lrte_pmd_tap
>>  _LDLIBS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) +=
>> -lrte_pmd_thunderx_nicvf
>>  _LDLIBS-$(CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD) += -lrte_pmd_vdev_netvsc
>> --
>> 1.8.3.1
>>
>>
>
> --
> regards,
> Rami Rosen
>

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [dpdk-dev] [PATCH v2] net/nfb: new Netcope driver
  2019-02-26 12:57 ` [dpdk-dev] [PATCH] net/nfb: new netcope driver Rastislav Cernay
  2019-02-26 14:20   ` Rami Rosen
  2019-02-26 15:46   ` Stephen Hemminger
@ 2019-02-27 11:43   ` Rastislav Cernay
  2019-02-27 15:28     ` Ferruh Yigit
  2019-03-01 14:37   ` [dpdk-dev] [PATCH v3] net/nfb: new netcope driver Rastislav Cernay
                     ` (5 subsequent siblings)
  8 siblings, 1 reply; 50+ messages in thread
From: Rastislav Cernay @ 2019-02-27 11:43 UTC (permalink / raw)
  To: dev; +Cc: ramirose, stephen, Rastislav Cernay

From: Rastislav Cernay <cernay@netcope.com>

Added new net driver for Netcope nfb cards

Signed-off-by: Rastislav Cernay <cernay@netcope.com>
---
v2: remove unnecessary cast
    remove unnecessary zeroing
    move declaration to not mix with code
    restore skeleton example
 MAINTAINERS                      |   7 +
 config/common_base               |   4 +
 devtools/test-build.sh           |   1 +
 doc/guides/nics/features/nfb.ini |  17 ++
 doc/guides/nics/nfb.rst          | 141 ++++++++++
 drivers/net/Makefile             |   1 +
 drivers/net/meson.build          |   1 +
 drivers/net/nfb/Makefile         |  41 +++
 drivers/net/nfb/meson.build      |   9 +
 drivers/net/nfb/nfb.h            |  51 ++++
 drivers/net/nfb/nfb_ethdev.c     | 583 +++++++++++++++++++++++++++++++++++++++
 drivers/net/nfb/nfb_rx.c         | 127 +++++++++
 drivers/net/nfb/nfb_rx.h         | 226 +++++++++++++++
 drivers/net/nfb/nfb_rxmode.c     | 104 +++++++
 drivers/net/nfb/nfb_rxmode.h     |  81 ++++++
 drivers/net/nfb/nfb_stats.c      |  79 ++++++
 drivers/net/nfb/nfb_stats.h      |  52 ++++
 drivers/net/nfb/nfb_tx.c         | 112 ++++++++
 drivers/net/nfb/nfb_tx.h         | 209 ++++++++++++++
 mk/rte.app.mk                    |   1 +
 20 files changed, 1847 insertions(+)
 create mode 100644 doc/guides/nics/features/nfb.ini
 create mode 100644 doc/guides/nics/nfb.rst
 create mode 100644 drivers/net/nfb/Makefile
 create mode 100644 drivers/net/nfb/meson.build
 create mode 100644 drivers/net/nfb/nfb.h
 create mode 100644 drivers/net/nfb/nfb_ethdev.c
 create mode 100644 drivers/net/nfb/nfb_rx.c
 create mode 100644 drivers/net/nfb/nfb_rx.h
 create mode 100644 drivers/net/nfb/nfb_rxmode.c
 create mode 100644 drivers/net/nfb/nfb_rxmode.h
 create mode 100644 drivers/net/nfb/nfb_stats.c
 create mode 100644 drivers/net/nfb/nfb_stats.h
 create mode 100644 drivers/net/nfb/nfb_tx.c
 create mode 100644 drivers/net/nfb/nfb_tx.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 6610440..c6bffde 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -654,6 +654,13 @@ F: drivers/net/szedata2/
 F: doc/guides/nics/szedata2.rst
 F: doc/guides/nics/features/szedata2.ini
 
+Netcope nfb
+M: Rastislav Cernay <cernay@netcope.com>
+M: Jan Remes <remes@netcope.com>
+F: drivers/net/nfb/
+F: doc/guides/nics/nfb.rst
+F: doc/guides/nics/features/nfb.ini
+
 Netronome nfp
 M: Alejandro Lucero <alejandro.lucero@netronome.com>
 F: drivers/net/nfp/
diff --git a/config/common_base b/config/common_base
index 7c6da51..1ab0a6b 100644
--- a/config/common_base
+++ b/config/common_base
@@ -360,6 +360,10 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
 # Compile software PMD backed by SZEDATA2 device
 #
 CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
+#
+# Compile software PMD backed by NFB device
+#
+CONFIG_RTE_LIBRTE_PMD_NFB=n
 
 #
 # Compile burst-oriented Cavium Thunderx NICVF PMD driver
diff --git a/devtools/test-build.sh b/devtools/test-build.sh
index 42f4ad0..ab57ab8 100755
--- a/devtools/test-build.sh
+++ b/devtools/test-build.sh
@@ -18,6 +18,7 @@ default_path=$PATH
 # - DPDK_DEP_SSL (y/[n])
 # - DPDK_DEP_IPSEC_MB (y/[n])
 # - DPDK_DEP_SZE (y/[n])
+# - DPDK_DEP_NFB (y/[n])
 # - DPDK_DEP_ZLIB (y/[n])
 # - DPDK_MAKE_JOBS (int)
 # - DPDK_NOTIFY (notify-send)
diff --git a/doc/guides/nics/features/nfb.ini b/doc/guides/nics/features/nfb.ini
new file mode 100644
index 0000000..6174d65
--- /dev/null
+++ b/doc/guides/nics/features/nfb.ini
@@ -0,0 +1,17 @@
+;
+; Supported features of the 'nfb' network poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Speed capabilities   = P
+Link status          = Y
+Queue start/stop     = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Basic stats          = Y
+Extended stats       = Y
+Stats per queue      = Y
+Other kdrv           = Y
+x86-64               = Y
+Usage doc            = Y
diff --git a/doc/guides/nics/nfb.rst b/doc/guides/nics/nfb.rst
new file mode 100644
index 0000000..9057d41
--- /dev/null
+++ b/doc/guides/nics/nfb.rst
@@ -0,0 +1,141 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright 2015 - 2016 CESNET
+
+NFB poll mode driver library
+=================================
+
+The NFB poll mode driver library implements support for the Netcope
+FPGA Boards (**NFB-***), FPGA-based programmable NICs.
+The NFB PMD uses interface provided by the libnfb library to communicate
+with the NFB cards over the nfb layer.
+
+More information about the
+`NFB cards <http://www.netcope.com/en/products/fpga-boards>`_
+and used technology
+(`Netcope Development Kit <http://www.netcope.com/en/products/fpga-development-kit>`_)
+can be found on the `Netcope Technologies website <http://www.netcope.com/>`_.
+
+.. note::
+
+   This driver has external dependencies.
+   Therefore it is disabled in default configuration files.
+   It can be enabled by setting ``CONFIG_RTE_LIBRTE_PMD_NFB=y``
+   and recompiling.
+
+.. note::
+
+   Currently the driver is supported only on x86_64 architectures.
+   Only x86_64 versions of the external libraries are provided.
+
+Prerequisites
+-------------
+
+This PMD requires kernel modules which are responsible for initialization and
+allocation of resources needed for nfb layer function.
+Communication between PMD and kernel modules is mediated by libnfb library.
+These kernel modules and library are not part of DPDK and must be installed
+separately:
+
+*  **libnfb library**
+
+   The library provides API for initialization of nfb transfers, receiving and
+   transmitting data segments.
+
+*  **Kernel modules**
+
+   * nfb
+
+   Kernel modules manage initialization of hardware, allocation and
+   sharing of resources for user space applications.
+
+Dependencies can be found here:
+`Netcope common <https://drive.google.com/file/d/13khqS312KzrRSrgGxD0CBSmd1YLJHWp8>`_.
+
+Versions of the packages
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The minimum version of the provided packages:
+
+* for DPDK from 19.02
+
+Configuration
+-------------
+
+These configuration options can be modified before compilation in the
+``.config`` file:
+
+*  ``CONFIG_RTE_LIBRTE_PMD_NFB`` default value: **n**
+
+   Value **y** enables compilation of nfb PMD.
+
+Using the NFB PMD
+----------------------
+
+Kernel modules have to be loaded before running the DPDK application.
+
+NFB card architecture
+---------------------
+
+The NFB cards are multi-port multi-queue cards, where (generally) data from any
+Ethernet port may be sent to any queue.
+They are represented in DPDK as a single port.
+
+NFB-200G2QL card employs an addon cable which allows to connect it to two
+physical PCI-E slots at the same time (see the diagram below).
+This is done to allow 200 Gbps of traffic to be transferred through the PCI-E
+bus (note that a single PCI-E 3.0 x16 slot provides only 125 Gbps theoretical
+throughput).
+
+Although each slot may be connected to a different CPU and therefore to a different
+NUMA node, the card is represented as a single port in DPDK. To work with data
+from the individual queues on the right NUMA node, connection of NUMA nodes on
+first and last queue (each NUMA node has half of the queues) need to be checked.
+
+.. figure:: img/szedata2_nfb200g_architecture.svg
+    :align: center
+
+    NFB-200G2QL high-level diagram
+
+Limitations
+-----------
+
+Since a card is always represented as a single port, but can be connected to two
+NUMA nodes, there is need for manual check where master/slave is connected.
+
+Example of usage
+----------------
+
+Read packets from 0. and 1. receive queue and write them to 0. and 1.
+transmit queue:
+
+.. code-block:: console
+
+   $RTE_TARGET/app/testpmd -l 0-3 -n 2 \
+   -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2 -i -a
+
+Example output:
+
+.. code-block:: console
+
+   [...]
+   EAL: PCI device 0000:06:00.0 on NUMA socket -1
+   EAL:   probe driver: 1b26:c1c1 net_nfb
+   PMD: Initializing NFB device (0000:06:00.0)
+   PMD: Available DMA queues RX: 8 TX: 8
+   PMD: NFB device (0000:06:00.0) successfully initialized
+   Interactive-mode selected
+   Auto-start selected
+   Configuring Port 0 (socket 0)
+   Port 0: 00:11:17:00:00:00
+   Checking link statuses...
+   Port 0 Link Up - speed 10000 Mbps - full-duplex
+   Done
+   Start automatic packet forwarding
+     io packet forwarding - CRC stripping disabled - packets/burst=32
+     nb forwarding cores=2 - nb forwarding ports=1
+     RX queues=2 - RX desc=128 - RX free threshold=0
+     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX queues=2 - TX desc=512 - TX free threshold=0
+     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX RS bit threshold=0 - TXQ flags=0x0
+   testpmd>
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 670d7f7..013c551 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -38,6 +38,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5
 DIRS-$(CONFIG_RTE_LIBRTE_MVNETA_PMD) += mvneta
 DIRS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mvpp2
 DIRS-$(CONFIG_RTE_LIBRTE_NETVSC_PMD) += netvsc
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb
 DIRS-$(CONFIG_RTE_LIBRTE_NFP_PMD) += nfp
 DIRS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += null
diff --git a/drivers/net/meson.build b/drivers/net/meson.build
index 45da3bb..6733a19 100644
--- a/drivers/net/meson.build
+++ b/drivers/net/meson.build
@@ -27,6 +27,7 @@ drivers = ['af_packet',
 	'mvneta',
 	'mvpp2',
 	'netvsc',
+	'nfb',
 	'nfp',
 	'null', 'octeontx', 'pcap', 'qede', 'ring',
 	'sfc',
diff --git a/drivers/net/nfb/Makefile b/drivers/net/nfb/Makefile
new file mode 100644
index 0000000..ee8c7df
--- /dev/null
+++ b/drivers/net/nfb/Makefile
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Cesnet
+# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_nfb.a
+
+INCLUDES :=-I$(SRCDIR)
+
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+LDLIBS += -lnfb
+LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
+LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
+LDLIBS += -lrte_bus_pci
+
+EXPORT_MAP := rte_pmd_nfb_version.map
+
+LIBABIVER := 1
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_rx.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_tx.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_stats.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_rxmode.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/nfb/meson.build b/drivers/net/nfb/meson.build
new file mode 100644
index 0000000..d7dccba
--- /dev/null
+++ b/drivers/net/nfb/meson.build
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Cesnet
+# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+dep = cc.find_library('nfb', required: true)
+build = dep.found()
+ext_deps += dep
+sources = files('nfb_rx.c', 'nfb_tx.c', 'nfb_stats.c', 'nfb_ethdev.c', 'nfb_rxmode.c')
diff --git a/drivers/net/nfb/nfb.h b/drivers/net/nfb/nfb.h
new file mode 100644
index 0000000..69a3826
--- /dev/null
+++ b/drivers/net/nfb/nfb.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_H_
+#define _NFB_H_
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+
+/* PCI Vendor ID */
+#define PCI_VENDOR_ID_NETCOPE 0x1b26
+
+/* PCI Device IDs */
+#define PCI_DEVICE_ID_NFB_40G2  0xcb80
+#define PCI_DEVICE_ID_NFB_100G2 0xc2c1
+#define PCI_DEVICE_ID_NFB_200G2QL 0xc250
+
+/* Max index of ndp rx/tx queues */
+#define RTE_ETH_NDP_MAX_RX_QUEUES 32
+#define RTE_ETH_NDP_MAX_TX_QUEUES 32
+
+/* Max index of rx/tx dmas */
+#define RTE_MAX_NC_RXMAC 256
+#define RTE_MAX_NC_TXMAC 256
+
+#define RTE_NFB_DRIVER_NAME net_nfb
+
+struct pmd_internals {
+	uint16_t         max_rxmac;
+	uint16_t         max_txmac;
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC];
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC];
+
+	char             nfb_dev[PATH_MAX];
+	struct nfb_device *nfb;
+	/* Place to remember if filter was promiscuous or filtering by table,
+	 * when disabling allmulticast
+	 */
+	enum nc_rxmac_mac_filter rx_filter_original;
+};
+
+
+#endif /* _NFB_H_ */
diff --git a/drivers/net/nfb/nfb_ethdev.c b/drivers/net/nfb/nfb_ethdev.c
new file mode 100644
index 0000000..24062a6
--- /dev/null
+++ b/drivers/net/nfb/nfb_ethdev.c
@@ -0,0 +1,583 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_kvargs.h>
+#include <rte_dev.h>
+#include <rte_common.h>
+
+#include "nfb_stats.h"
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+/**
+ * Default MAC addr
+ */
+static struct ether_addr eth_addr = {
+	.addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
+};
+
+/**
+ * Open all RX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] rxmac
+ *   Pointer to output array of nc_rxmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of rxmac
+ */
+static void
+nfb_nc_rxmac_init(struct nfb_device *nfb,
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t *max_rxmac)
+{
+	*max_rxmac = 0;
+	while ((rxmac[*max_rxmac] = nc_rxmac_open_index(nfb, *max_rxmac)))
+		++(*max_rxmac);
+}
+
+/**
+ * Open all TX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] txmac
+ *   Pointer to output array of nc_txmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of txmac
+ */
+static void
+nfb_nc_txmac_init(struct nfb_device *nfb,
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t *max_txmac)
+{
+	*max_txmac = 0;
+	while ((txmac[*max_txmac] = nc_txmac_open_index(nfb, *max_txmac)))
+		++(*max_txmac);
+}
+
+/**
+ * Close all RX DMA queues
+ *
+ * @param rxmac
+ *   Pointer to array of nc_rxmac
+ * @param max_rxmac
+ *   Maximum index of rxmac
+ */
+static void
+nfb_nc_rxmac_deinit(struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t max_rxmac)
+{
+	for (; max_rxmac > 0; --max_rxmac) {
+		nc_rxmac_close(rxmac[max_rxmac]);
+		rxmac[max_rxmac] = NULL;
+	}
+}
+
+/**
+ * Close all TX DMA queues
+ *
+ * @param txmac
+ *   Pointer to array of nc_txmac
+ * @param max_txmac
+ *   Maximum index of txmac
+ */
+static void
+nfb_nc_txmac_deinit(struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t max_txmac)
+{
+	for (; max_txmac > 0; --max_txmac) {
+		nc_txmac_close(txmac[max_txmac]);
+		txmac[max_txmac] = NULL;
+	}
+}
+
+/**
+ * DPDK callback to start the device.
+ *
+ * Start device by starting all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+nfb_eth_dev_start(struct rte_eth_dev *dev)
+{
+	int ret;
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_rx; i++) {
+		ret = nfb_eth_rx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_rx;
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		ret = nfb_eth_tx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_tx;
+	}
+
+	return 0;
+
+err_tx:
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+err_rx:
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+	return ret;
+}
+
+/**
+ * DPDK callback to stop the device.
+ *
+ * Stop device by stopping all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+nfb_eth_dev_stop(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+}
+
+/**
+ * DPDK callback for Ethernet device configuration.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+nfb_eth_dev_configure(struct rte_eth_dev *dev)
+{
+	dev->rx_pkt_burst = nfb_eth_ndp_rx;
+	return 0;
+}
+
+/**
+ * DPDK callback to get information about the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] info
+ *   Info structure output buffer.
+ */
+static void
+nfb_eth_dev_info(struct rte_eth_dev *dev,
+	struct rte_eth_dev_info *dev_info)
+{
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = dev->data->nb_rx_queues;
+	dev_info->max_tx_queues = dev->data->nb_tx_queues;
+	dev_info->speed_capa = ETH_LINK_SPEED_100G;
+}
+
+/**
+ * DPDK callback to close the device.
+ *
+ * Destroy all queues and objects, free memory.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+nfb_eth_dev_close(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	nfb_eth_dev_stop(dev);
+
+	for (i = 0; i < nb_rx; i++) {
+		nfb_eth_rx_queue_release(dev->data->rx_queues[i]);
+		dev->data->rx_queues[i] = NULL;
+	}
+	dev->data->nb_rx_queues = 0;
+	for (i = 0; i < nb_tx; i++) {
+		nfb_eth_tx_queue_release(dev->data->tx_queues[i]);
+		dev->data->tx_queues[i] = NULL;
+	}
+	dev->data->nb_tx_queues = 0;
+}
+
+/**
+ * DPDK callback to retrieve physical link information.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] link
+ *   Storage for current link status.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+nfb_eth_link_update(struct rte_eth_dev *dev,
+	int wait_to_complete __rte_unused)
+{
+	uint16_t i;
+	struct nc_rxmac_status status;
+	struct rte_eth_link link;
+	memset(&link, 0, sizeof(link));
+
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	status.speed = MAC_SPEED_UNKNOWN;
+
+	link.link_speed = ETH_SPEED_NUM_NONE;
+	link.link_status = ETH_LINK_DOWN;
+	link.link_duplex = ETH_LINK_FULL_DUPLEX;
+	link.link_autoneg = ETH_LINK_SPEED_FIXED;
+
+	if (internals->rxmac[0] != NULL) {
+		nc_rxmac_read_status(internals->rxmac[0], &status);
+
+		switch (status.speed) {
+		case MAC_SPEED_10G:
+			link.link_speed = ETH_SPEED_NUM_10G;
+			break;
+		case MAC_SPEED_40G:
+			link.link_speed = ETH_SPEED_NUM_40G;
+			break;
+		case MAC_SPEED_100G:
+			link.link_speed = ETH_SPEED_NUM_100G;
+			break;
+		default:
+			link.link_speed = ETH_SPEED_NUM_NONE;
+			break;
+		}
+	}
+
+	i = 0;
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_read_status(internals->rxmac[i], &status);
+
+		if (status.enabled && status.link_up) {
+			link.link_status = ETH_LINK_UP;
+			break;
+		}
+	}
+
+	rte_eth_linkstatus_set(dev, &link);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to bring the link UP.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+nfb_eth_dev_set_link_up(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_enable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_enable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to bring the link DOWN.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+nfb_eth_dev_set_link_down(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_disable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_disable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to set primary MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+nfb_eth_mac_addr_set(struct rte_eth_dev *dev __rte_unused,
+	struct ether_addr *mac_addr __rte_unused)
+{
+	return 0;
+}
+
+static const struct eth_dev_ops ops = {
+	.dev_start = nfb_eth_dev_start,
+	.dev_stop = nfb_eth_dev_stop,
+	.dev_set_link_up = nfb_eth_dev_set_link_up,
+	.dev_set_link_down = nfb_eth_dev_set_link_down,
+	.dev_close = nfb_eth_dev_close,
+	.dev_configure = nfb_eth_dev_configure,
+	.dev_infos_get = nfb_eth_dev_info,
+	.promiscuous_enable = nfb_eth_promiscuous_enable,
+	.promiscuous_disable = nfb_eth_promiscuous_disable,
+	.allmulticast_enable = nfb_eth_allmulticast_enable,
+	.allmulticast_disable = nfb_eth_allmulticast_disable,
+	.rx_queue_start = nfb_eth_rx_queue_start,
+	.rx_queue_stop = nfb_eth_rx_queue_stop,
+	.tx_queue_start = nfb_eth_tx_queue_start,
+	.tx_queue_stop = nfb_eth_tx_queue_stop,
+	.rx_queue_setup = nfb_eth_rx_queue_setup,
+	.tx_queue_setup = nfb_eth_tx_queue_setup,
+	.rx_queue_release = nfb_eth_rx_queue_release,
+	.tx_queue_release = nfb_eth_tx_queue_release,
+	.link_update = nfb_eth_link_update,
+	.stats_get = nfb_eth_stats_get,
+	.stats_reset = nfb_eth_stats_reset,
+	.mac_addr_set = nfb_eth_mac_addr_set,
+};
+
+/**
+ * DPDK callback to initialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+nfb_eth_dev_init(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+
+	RTE_LOG(INFO, PMD, "Initializing NFB device (" PCI_PRI_FMT ")\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	snprintf(internals->nfb_dev, PATH_MAX,
+		"/dev/nfb/by-pci-slot/" PCI_PRI_FMT,
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	/*
+	 * Get number of available DMA RX and TX queues, which is maximum
+	 * number of queues that can be created and store it in private device
+	 * data structure.
+	 */
+	internals->nfb = nfb_open(internals->nfb_dev);
+	if (internals->nfb == NULL) {
+		RTE_LOG(ERR, PMD, "nfb_open(): failed to open %s",
+			internals->nfb_dev);
+		return -EINVAL;
+	}
+	data->nb_rx_queues = ndp_get_rx_queue_available_count(internals->nfb);
+	data->nb_tx_queues = ndp_get_tx_queue_available_count(internals->nfb);
+
+	RTE_LOG(INFO, PMD, "Available NDP queues RX: %u TX: %u\n",
+		data->nb_rx_queues, data->nb_tx_queues);
+
+	nfb_nc_rxmac_init(internals->nfb,
+		internals->rxmac,
+		&internals->max_rxmac);
+	nfb_nc_txmac_init(internals->nfb,
+		internals->txmac,
+		&internals->max_txmac);
+
+	/* Set rx, tx burst functions */
+	dev->rx_pkt_burst = nfb_eth_ndp_rx;
+	dev->tx_pkt_burst = nfb_eth_ndp_tx;
+
+	/* Set function callbacks for Ethernet API */
+	dev->dev_ops = &ops;
+
+	rte_eth_copy_pci_info(dev, pci_dev);
+
+	/* Get link state */
+	nfb_eth_link_update(dev, 0);
+
+	/* Allocate space for one mac address */
+	data->mac_addrs = rte_zmalloc(data->name, sizeof(struct ether_addr),
+		RTE_CACHE_LINE_SIZE);
+	if (data->mac_addrs == NULL) {
+		RTE_LOG(ERR, PMD, "Could not alloc space for MAC address!\n");
+		nfb_close(internals->nfb);
+		return -EINVAL;
+	}
+
+	ether_addr_copy(&eth_addr, data->mac_addrs);
+
+	data->promiscuous = nfb_eth_promiscuous_get(dev);
+	data->all_multicast = nfb_eth_allmulticast_get(dev);
+	internals->rx_filter_original = data->promiscuous;
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully initialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to uninitialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+nfb_eth_dev_uninit(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+
+	rte_free(dev->data->mac_addrs);
+	dev->data->mac_addrs = NULL;
+
+	nfb_nc_rxmac_deinit(internals->rxmac, internals->max_rxmac);
+	nfb_nc_txmac_deinit(internals->txmac, internals->max_txmac);
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully uninitialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+static const struct rte_pci_id nfb_pci_id_table[] = {
+	{
+		RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_40G2)
+	},
+	{
+		RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_100G2)
+	},
+	{
+		RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_200G2QL)
+	},
+	{
+		.vendor_id = 0,
+	}
+};
+
+/**
+ * DPDK callback to register a PCI device.
+ *
+ * This function spawns Ethernet devices out of a given PCI device.
+ *
+ * @param[in] pci_drv
+ *   PCI driver structure (nfb_driver).
+ * @param[in] pci_dev
+ *   PCI device information.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int nfb_eth_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+	struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_probe(pci_dev,
+		sizeof(struct pmd_internals), nfb_eth_dev_init);
+}
+
+/**
+ * DPDK callback to remove a PCI device.
+ *
+ * This function removes all Ethernet devices belong to a given PCI device.
+ *
+ * @param[in] pci_dev
+ *   Pointer to the PCI device.
+ *
+ * @return
+ *   0 on success, the function cannot fail.
+ */
+static int nfb_eth_pci_remove(struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_remove(pci_dev, nfb_eth_dev_uninit);
+}
+
+static struct rte_pci_driver nfb_eth_driver = {
+	.id_table = nfb_pci_id_table,
+	.probe = nfb_eth_pci_probe,
+	.remove = nfb_eth_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(RTE_NFB_DRIVER_NAME, nfb_eth_driver);
+RTE_PMD_REGISTER_PCI_TABLE(RTE_NFB_DRIVER_NAME, nfb_pci_id_table);
+RTE_PMD_REGISTER_KMOD_DEP(RTE_NFB_DRIVER_NAME, "* nfb");
diff --git a/drivers/net/nfb/nfb_rx.c b/drivers/net/nfb/nfb_rx.c
new file mode 100644
index 0000000..dc1cd2d
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.c
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_rx.h"
+#include "nfb.h"
+
+
+int
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	int ret = ndp_queue_start(rxq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+
+
+int
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	int ret = ndp_queue_stop(rxq->queue);
+	if (ret != 0)
+		return -EINVAL;
+
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+		uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	struct ndp_rx_queue *rxq;
+
+	rxq = rte_zmalloc_socket("ndp rx queue",
+			sizeof(struct ndp_rx_queue),
+			RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (rxq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for rx queue id "
+				"%" PRIu16 "!\n", rx_queue_id);
+		return -ENOMEM;
+	}
+
+	int ret = nfb_eth_rx_queue_init(internals->nfb,
+		rx_queue_id,
+		dev->data->port_id,
+		mb_pool,
+		rxq);
+
+	if (ret == 0)
+		dev->data->rx_queues[rx_queue_id] = rxq;
+	else
+		rte_free(rxq);
+
+	return ret;
+}
+
+int
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+		uint16_t rx_queue_id,
+		uint16_t port_id,
+		struct rte_mempool *mb_pool,
+		struct ndp_rx_queue *rxq)
+{
+	if (nfb == NULL)
+		return -EINVAL;
+
+	rxq->queue = ndp_open_rx_queue(nfb, rx_queue_id);
+	if (rxq->queue == NULL)
+		return -EINVAL;
+
+	rxq->nfb = nfb;
+	rxq->rx_queue_id = rx_queue_id;
+	rxq->in_port = port_id;
+	rxq->mb_pool = mb_pool;
+
+	const struct rte_pktmbuf_pool_private *mbp_priv =
+		rte_mempool_get_priv(mb_pool);
+	rxq->buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size -
+		RTE_PKTMBUF_HEADROOM);
+
+	rxq->rx_pkts = 0;
+	rxq->rx_bytes = 0;
+	rxq->err_pkts = 0;
+
+	return 0;
+}
+
+void
+nfb_eth_rx_queue_release(void *q)
+{
+	struct ndp_rx_queue *rxq = (struct ndp_rx_queue *)q;
+	if (rxq->queue != NULL) {
+		ndp_close_rx_queue(rxq->queue);
+		rte_free(rxq);
+		rxq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_rx.h b/drivers/net/nfb/nfb_rx.h
new file mode 100644
index 0000000..b356f5d
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.h
@@ -0,0 +1,226 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+
+
+#ifndef _NFB_RX_H_
+#define _NFB_RX_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+struct ndp_rx_queue {
+	struct nfb_device *nfb;	     /* nfb dev structure */
+	struct ndp_queue *queue;     /* rx queue */
+	uint16_t rx_queue_id;	     /* index */
+	uint8_t in_port;	     /* port */
+
+	struct rte_mempool *mb_pool; /* memory pool to allocate packets */
+	uint16_t buf_size;           /* mbuf size */
+
+	volatile uint64_t rx_pkts;   /* packets read */
+	volatile uint64_t rx_bytes;  /* bytes read */
+	volatile uint64_t err_pkts;  /* erroneous packets */
+};
+
+/**
+ * Initialize ndp_rx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param rx_queue_id
+ *   RX queue index.
+ * @param port_id
+ *   Device [external] port identifier.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ * @param[out] rxq
+ *   Pointer to ndp_rx_queue output structure
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+	uint16_t rx_queue_id,
+	uint16_t port_id,
+	struct rte_mempool *mb_pool,
+	struct ndp_rx_queue *rxq);
+
+
+/**
+ * DPDK callback to setup a RX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t rx_queue_id,
+	uint16_t nb_rx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_rxconf *rx_conf __rte_unused,
+	struct rte_mempool *mb_pool);
+
+
+/**
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void
+nfb_eth_rx_queue_release(void *q);
+
+/**
+ * Start traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * Stop traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ */
+int
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * DPDK callback for RX.
+ *
+ * @param dpdk_rxq
+ *   Generic pointer to RX queue structure.
+ * @param[out] bufs
+ *   Array to store received packets.
+ * @param nb_pkts
+ *   Maximum number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully received (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t
+nfb_eth_ndp_rx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	struct ndp_rx_queue *ndp = queue;
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "RX invalid arguments!\n");
+		return 0;
+	}
+
+	struct rte_mbuf *mbufs[nb_pkts];
+
+	unsigned int i;
+	// returns either all or nothing
+	i = rte_pktmbuf_alloc_bulk(ndp->mb_pool, mbufs, nb_pkts);
+	if (unlikely(i != 0))
+		return 0;
+
+	uint16_t packet_size;
+	uint64_t num_bytes = 0;
+	const uint16_t buf_size = ndp->buf_size;
+
+	struct rte_mbuf *mbuf;
+	struct ndp_packet packets[nb_pkts];
+
+
+	uint16_t num_rx = ndp_rx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_rx != nb_pkts)) {
+		for (i = num_rx; i < nb_pkts; i++)
+			rte_pktmbuf_free(mbufs[i]);
+	}
+
+	nb_pkts = num_rx;
+
+	num_rx = 0;
+	/*
+	 * Reads the given number of packets from NDP queue given
+	 * by queue and copies the packet data into a newly allocated mbuf
+	 * to return.
+	 */
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = mbufs[i];
+
+		/* get the space available for data in the mbuf */
+		packet_size = packets[i].data_length;
+
+		if (likely(packet_size <= buf_size)) {
+			/* NDP packet will fit in one mbuf, go ahead and copy */
+			rte_memcpy(rte_pktmbuf_mtod(mbuf, void *),
+				packets[i].data, packet_size);
+
+			mbuf->data_len = (uint16_t)packet_size;
+
+			mbuf->pkt_len = packet_size;
+			mbuf->port = ndp->in_port;
+			bufs[num_rx++] = mbuf;
+			num_bytes += packet_size;
+		} else {
+			/*
+			 * NDP packet will not fit in one mbuf,
+			 * scattered mode is not enabled, drop packet
+			 */
+			RTE_LOG(ERR, PMD,
+				"NDP segment %d bytes will not fit in one mbuf "
+				"(%d bytes), scattered mode is not enabled, "
+				"drop packet!!\n",
+				packet_size, buf_size);
+			rte_pktmbuf_free(mbuf);
+		}
+	}
+
+
+	ndp_rx_burst_put(ndp->queue);
+
+	ndp->rx_pkts += num_rx;
+	ndp->rx_bytes += num_bytes;
+	return num_rx;
+}
+
+
+
+#endif /* _NFB_RX_H_ */
diff --git a/drivers/net/nfb/nfb_rxmode.c b/drivers/net/nfb/nfb_rxmode.c
new file mode 100644
index 0000000..8a63507
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.c
@@ -0,0 +1,104 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+void
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_PROMISCUOUS);
+	}
+}
+
+void
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_TABLE;
+
+
+	// if promisc is not enabled, do nothing
+	if (!nfb_eth_promiscuous_get(dev))
+		return;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE);
+	}
+}
+
+int
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_PROMISCUOUS);
+}
+
+void
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+	}
+}
+
+void
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev)
+{
+	// if multicast is not enabled do nothing
+	if (!nfb_eth_allmulticast_get(dev))
+		return;
+
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			internals->rx_filter_original);
+	}
+}
+
+int
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+}
diff --git a/drivers/net/nfb/nfb_rxmode.h b/drivers/net/nfb/nfb_rxmode.h
new file mode 100644
index 0000000..2a72b10
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_RXMODE_H_
+#define _NFB_RXMODE_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_ethdev.h>
+#include <rte_dev.h>
+
+/**
+ * Getter for promiscuous mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to enable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to disable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev);
+
+/**
+ * Getter for allmulticast mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to enable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to disable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev);
+
+
+
+
+#endif /* _NFB_RXMODE_H_ */
diff --git a/drivers/net/nfb/nfb_stats.c b/drivers/net/nfb/nfb_stats.c
new file mode 100644
index 0000000..f2750e4
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.c
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+
+#include "nfb_stats.h"
+#include "nfb.h"
+
+int
+nfb_eth_stats_get(struct rte_eth_dev *dev,
+	struct rte_eth_stats *stats)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+	uint64_t rx_total = 0;
+	uint64_t tx_total = 0;
+	uint64_t tx_err_total = 0;
+	uint64_t rx_total_bytes = 0;
+	uint64_t tx_total_bytes = 0;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_ipackets[i] = rx_queue[i].rx_pkts;
+			stats->q_ibytes[i] = rx_queue[i].rx_bytes;
+		}
+		rx_total += stats->q_ipackets[i];
+		rx_total_bytes += stats->q_ibytes[i];
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_opackets[i] = tx_queue[i].tx_pkts;
+			stats->q_obytes[i] = tx_queue[i].tx_bytes;
+			stats->q_errors[i] = tx_queue[i].err_pkts;
+		}
+		tx_total += stats->q_opackets[i];
+		tx_total_bytes += stats->q_obytes[i];
+		tx_err_total += stats->q_errors[i];
+	}
+
+	stats->ipackets = rx_total;
+	stats->opackets = tx_total;
+	stats->ibytes = rx_total_bytes;
+	stats->obytes = tx_total_bytes;
+	stats->oerrors = tx_err_total;
+	return 0;
+}
+
+void
+nfb_eth_stats_reset(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		rx_queue[i].rx_pkts = 0;
+		rx_queue[i].rx_bytes = 0;
+		rx_queue[i].err_pkts = 0;
+	}
+	for (i = 0; i < nb_tx; i++) {
+		tx_queue[i].tx_pkts = 0;
+		tx_queue[i].tx_bytes = 0;
+		tx_queue[i].err_pkts = 0;
+	}
+}
diff --git a/drivers/net/nfb/nfb_stats.h b/drivers/net/nfb/nfb_stats.h
new file mode 100644
index 0000000..d89ca4c
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_STATS_H_
+#define _NFB_STATS_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+/**
+ * DPDK callback to get device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] stats
+ *   Stats structure output buffer.
+ *
+ * @return
+ *   0 on success and stats is filled, negative errno value otherwise and
+ *   rte_errno is set.
+ */
+int nfb_eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats);
+
+/**
+ * DPDK callback to clear device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void nfb_eth_stats_reset(struct rte_eth_dev *dev);
+
+
+
+
+#endif /* _NFB_STATS_H_ */
diff --git a/drivers/net/nfb/nfb_tx.c b/drivers/net/nfb/nfb_tx.c
new file mode 100644
index 0000000..efaaa2b
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.c
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+
+#include "nfb_tx.h"
+#include "nfb.h"
+
+int
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+
+	if (txq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	int ret = ndp_queue_start(txq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+int
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+
+	if (txq->queue != NULL) {
+		RTE_LOG(ERR, PMD, "TX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	int ret = ndp_queue_stop(txq->queue);
+	if (ret != 0)
+		return -EINVAL;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	struct ndp_tx_queue *txq;
+
+	txq = rte_zmalloc_socket("ndp tx queue",
+		sizeof(struct ndp_tx_queue),
+		RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (txq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for tx queue id "
+			"%" PRIu16 "!\n", tx_queue_id);
+		return -ENOMEM;
+	}
+
+	int ret = nfb_eth_tx_queue_init(internals->nfb,
+		tx_queue_id,
+		txq);
+
+	if (ret == 0)
+		dev->data->tx_queues[tx_queue_id] = txq;
+	else
+		rte_free(txq);
+
+	return ret;
+}
+
+int
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq)
+{
+	if (nfb == NULL)
+		return -EINVAL;
+
+	txq->queue = ndp_open_tx_queue(nfb, tx_queue_id);
+	if (txq->queue == NULL)
+		return -EINVAL;
+
+	txq->nfb = nfb;
+	txq->tx_queue_id = tx_queue_id;
+
+	txq->tx_pkts = 0;
+	txq->tx_bytes = 0;
+	txq->err_pkts = 0;
+
+	return 0;
+}
+
+void
+nfb_eth_tx_queue_release(void *q)
+{
+	struct ndp_tx_queue *txq = (struct ndp_tx_queue *)q;
+	if (txq->queue != NULL) {
+		ndp_close_tx_queue(txq->queue);
+		rte_free(txq);
+		txq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_tx.h b/drivers/net/nfb/nfb_tx.h
new file mode 100644
index 0000000..3ceb3bf
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.h
@@ -0,0 +1,209 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_TX_H_
+#define _NFB_TX_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+struct ndp_tx_queue {
+	struct nfb_device *nfb;     /* nfb dev structure */
+	struct ndp_queue *queue;    /* tx queue */
+	uint16_t          tx_queue_id;       /* index */
+	volatile uint64_t tx_pkts;  /* packets transmitted */
+	volatile uint64_t tx_bytes; /* bytes transmitted */
+	volatile uint64_t err_pkts; /* erroneous packets */
+};
+
+
+/**
+ * DPDK callback to setup a TX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mp
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused);
+
+/**
+ * Initialize ndp_tx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param tx_queue_id
+ *   TX queue index.
+ * @param[out] txq
+ *   Pointer to ndp_tx_queue output structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq);
+
+/**
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void
+nfb_eth_tx_queue_release(void *q);
+
+
+/**
+ * Start traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * Stop traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * DPDK callback for TX.
+ *
+ * @param dpdk_txq
+ *   Generic pointer to TX queue structure.
+ * @param bufs
+ *   Packets to transmit.
+ * @param nb_pkts
+ *   Number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully transmitted (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t
+nfb_eth_ndp_tx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	int i;
+	struct rte_mbuf *mbuf;
+	struct ndp_tx_queue *ndp = queue;
+	uint16_t num_tx = 0;
+	uint64_t num_bytes = 0;
+
+	void *dst;
+	uint32_t pkt_len;
+	uint8_t mbuf_segs;
+
+	struct ndp_packet packets[nb_pkts];
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "RX invalid arguments!\n");
+		return 0;
+	}
+
+	for (i = 0; i < nb_pkts; i++) {
+		packets[i].data_length = bufs[i]->pkt_len;
+		packets[i].header_length = 0;
+	}
+
+	num_tx = ndp_tx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_tx != nb_pkts))
+		return 0;
+
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = bufs[i];
+
+		pkt_len = mbuf->pkt_len;
+		mbuf_segs = mbuf->nb_segs;
+
+		num_bytes += pkt_len;
+		if (mbuf_segs == 1) {
+			/*
+			 * non-scattered packet,
+			 * transmit from one mbuf
+			 */
+			rte_memcpy(packets[i].data,
+				rte_pktmbuf_mtod(mbuf, const void *),
+				pkt_len);
+		} else {
+			/* scattered packet, transmit from more mbufs */
+			struct rte_mbuf *m = mbuf;
+			while (m) {
+				dst = packets[i].data;
+
+				rte_memcpy(dst,
+					rte_pktmbuf_mtod(m,
+					const void *),
+					m->data_len);
+				dst = ((uint8_t *)(dst)) +
+					m->data_len;
+				m = m->next;
+			}
+		}
+
+		rte_pktmbuf_free(mbuf);
+	}
+
+	ndp_tx_burst_flush(ndp->queue);
+
+	ndp->tx_pkts += num_tx;
+	ndp->err_pkts += nb_pkts - num_tx;
+	ndp->tx_bytes += num_bytes;
+	return num_tx;
+}
+
+
+
+
+#endif /* _NFB_TX_H_ */
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 8a4f0f4..32e88b5 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -196,6 +196,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC)      += -lrte_pmd_softnic
 endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD)    += -lrte_pmd_sfc_efx
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2 -lsze2
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NFB)        += -lrte_pmd_nfb -lnfb -lfdt
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_TAP)        += -lrte_pmd_tap
 _LDLIBS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += -lrte_pmd_thunderx_nicvf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD) += -lrte_pmd_vdev_netvsc
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v2] net/nfb: new Netcope driver
  2019-02-27 11:43   ` [dpdk-dev] [PATCH v2] net/nfb: new Netcope driver Rastislav Cernay
@ 2019-02-27 15:28     ` Ferruh Yigit
  0 siblings, 0 replies; 50+ messages in thread
From: Ferruh Yigit @ 2019-02-27 15:28 UTC (permalink / raw)
  To: Rastislav Cernay, dev; +Cc: ramirose, stephen

On 2/27/2019 11:43 AM, Rastislav Cernay wrote:
> From: Rastislav Cernay <cernay@netcope.com>
> 
> Added new net driver for Netcope nfb cards
> 
> Signed-off-by: Rastislav Cernay <cernay@netcope.com>
> ---
> v2: remove unnecessary cast
>     remove unnecessary zeroing
>     move declaration to not mix with code
>     restore skeleton example
>  MAINTAINERS                      |   7 +
>  config/common_base               |   4 +
>  devtools/test-build.sh           |   1 +
>  doc/guides/nics/features/nfb.ini |  17 ++
>  doc/guides/nics/nfb.rst          | 141 ++++++++++

Do we need to add this file into index, doc/guides/nics/index.rst? Did you
compiled the doc and verified it is visible in the left side menu?

>  drivers/net/Makefile             |   1 +
>  drivers/net/meson.build          |   1 +
>  drivers/net/nfb/Makefile         |  41 +++
>  drivers/net/nfb/meson.build      |   9 +
>  drivers/net/nfb/nfb.h            |  51 ++++
>  drivers/net/nfb/nfb_ethdev.c     | 583 +++++++++++++++++++++++++++++++++++++++
>  drivers/net/nfb/nfb_rx.c         | 127 +++++++++
>  drivers/net/nfb/nfb_rx.h         | 226 +++++++++++++++
>  drivers/net/nfb/nfb_rxmode.c     | 104 +++++++
>  drivers/net/nfb/nfb_rxmode.h     |  81 ++++++
>  drivers/net/nfb/nfb_stats.c      |  79 ++++++
>  drivers/net/nfb/nfb_stats.h      |  52 ++++
>  drivers/net/nfb/nfb_tx.c         | 112 ++++++++
>  drivers/net/nfb/nfb_tx.h         | 209 ++++++++++++++
>  mk/rte.app.mk                    |   1 +

Can you please update the release notes (release_19_05.rst) to announce the new PMD?

Also I believe you will need a .map file, explicitly "rte_pmd_nfb_version.map"
according makefile, to be able to produce shared library.

<...>

> +Prerequisites
> +-------------
> +
> +This PMD requires kernel modules which are responsible for initialization and
> +allocation of resources needed for nfb layer function.
> +Communication between PMD and kernel modules is mediated by libnfb library.
> +These kernel modules and library are not part of DPDK and must be installed
> +separately:
> +
> +*  **libnfb library**
> +
> +   The library provides API for initialization of nfb transfers, receiving and
> +   transmitting data segments.
> +
> +*  **Kernel modules**
> +
> +   * nfb
> +
> +   Kernel modules manage initialization of hardware, allocation and
> +   sharing of resources for user space applications.
> +
> +Dependencies can be found here:
> +`Netcope common <https://drive.google.com/file/d/13khqS312KzrRSrgGxD0CBSmd1YLJHWp8>`_.

There should be a way to download prerequisites, so thanks for providing this
link, but how reliable this google drive is, is there a way to provide some link
 or information from vendor official site, as you are doing for szedata2?

Also above link gives an rpm, is there any source code option for different distros?

<...>

> +/**
> + * DPDK callback for Ethernet device configuration.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +static int
> +nfb_eth_dev_configure(struct rte_eth_dev *dev)
> +{
> +	dev->rx_pkt_burst = nfb_eth_ndp_rx;

This looks like fixed value, can be possible to move to device init instead of
having in configure()?

> +	return 0;
> +}
> +
> +/**
> + * DPDK callback to get information about the device.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + * @param[out] info
> + *   Info structure output buffer.
> + */
> +static void
> +nfb_eth_dev_info(struct rte_eth_dev *dev,
> +	struct rte_eth_dev_info *dev_info)
> +{
> +	dev_info->max_mac_addrs = 1;
> +	dev_info->max_rx_pktlen = (uint32_t)-1;
> +	dev_info->max_rx_queues = dev->data->nb_rx_queues;
> +	dev_info->max_tx_queues = dev->data->nb_tx_queues;

This prevents you increasing number of queues later, since these values are
coming from your library, most probably you already can't increase them, but a
reminder in case.

> +	dev_info->speed_capa = ETH_LINK_SPEED_10
Just to highlight that this is not setting any offload capability, any
application that requires some offload capabilities will fail to configure the
device.

<...>

> +nfb_eth_link_update(struct rte_eth_dev *dev,
> +	int wait_to_complete __rte_unused)
> +{
> +	uint16_t i;
> +	struct nc_rxmac_status status;
> +	struct rte_eth_link link;
> +	memset(&link, 0, sizeof(link));
> +
> +	struct pmd_internals *internals = dev->data->dev_private;
> +
> +	status.speed = MAC_SPEED_UNKNOWN;
> +
> +	link.link_speed = ETH_SPEED_NUM_NONE;
> +	link.link_status = ETH_LINK_DOWN;
> +	link.link_duplex = ETH_LINK_FULL_DUPLEX;
> +	link.link_autoneg = ETH_LINK_SPEED_FIXED;
> +
> +	if (internals->rxmac[0] != NULL) {
> +		nc_rxmac_read_status(internals->rxmac[0], &status);
> +
> +		switch (status.speed) {
> +		case MAC_SPEED_10G:
> +			link.link_speed = ETH_SPEED_NUM_10G;
> +			break;
> +		case MAC_SPEED_40G:
> +			link.link_speed = ETH_SPEED_NUM_40G;
> +			break;
> +		case MAC_SPEED_100G:
> +			link.link_speed = ETH_SPEED_NUM_100G;
> +			break;
> +		default:
> +			link.link_speed = ETH_SPEED_NUM_NONE;
> +			break;
> +		}
> +	}
> +
> +	i = 0;

Can drop this line.

<...>

> +/**
> + * DPDK callback to set primary MAC address.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + * @param mac_addr
> + *   MAC address to register.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +static int
> +nfb_eth_mac_addr_set(struct rte_eth_dev *dev __rte_unused,
> +	struct ether_addr *mac_addr __rte_unused)
> +{
> +	return 0;

This returns success but doesn't set the provided MAC address at all, shouldn't
send a fail insted?
Will it break any code flow if this ops is missing or returning error?

<...>

> +static int
> +nfb_eth_dev_init(struct rte_eth_dev *dev)
> +{
> +	struct rte_eth_dev_data *data = dev->data;
> +	struct pmd_internals *internals = (struct pmd_internals *)
> +		data->dev_private;
> +	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
> +	struct rte_pci_addr *pci_addr = &pci_dev->addr;
> +
> +	RTE_LOG(INFO, PMD, "Initializing NFB device (" PCI_PRI_FMT ")\n",
> +		pci_addr->domain, pci_addr->bus, pci_addr->devid,
> +		pci_addr->function);

This is using PMD log type, I agree it is simpler to use it but having own log
type gives more flexibility chaning log type dynamiccally with better
granularity, in case you are intetested in adding own logtype.

> +
> +	snprintf(internals->nfb_dev, PATH_MAX,
> +		"/dev/nfb/by-pci-slot/" PCI_PRI_FMT,
> +		pci_addr->domain, pci_addr->bus, pci_addr->devid,
> +		pci_addr->function);

Does this fixed path mean it is only supported by Linux, but not FreeBSD? If so
it can be better to document this as the supported architecture documented.

> +
> +	/*
> +	 * Get number of available DMA RX and TX queues, which is maximum
> +	 * number of queues that can be created and store it in private device
> +	 * data structure.
> +	 */
> +	internals->nfb = nfb_open(internals->nfb_dev);
> +	if (internals->nfb == NULL) {
> +		RTE_LOG(ERR, PMD, "nfb_open(): failed to open %s",
> +			internals->nfb_dev);
> +		return -EINVAL;
> +	}
> +	data->nb_rx_queues = ndp_get_rx_queue_available_count(internals->nfb);
> +	data->nb_tx_queues = ndp_get_tx_queue_available_count(internals->nfb);
> +
> +	RTE_LOG(INFO, PMD, "Available NDP queues RX: %u TX: %u\n",
> +		data->nb_rx_queues, data->nb_tx_queues);
> +
> +	nfb_nc_rxmac_init(internals->nfb,
> +		internals->rxmac,
> +		&internals->max_rxmac);
> +	nfb_nc_txmac_init(internals->nfb,
> +		internals->txmac,
> +		&internals->max_txmac);
> +
> +	/* Set rx, tx burst functions */
> +	dev->rx_pkt_burst = nfb_eth_ndp_rx;
> +	dev->tx_pkt_burst = nfb_eth_ndp_tx;
> +
> +	/* Set function callbacks for Ethernet API */
> +	dev->dev_ops = &ops;
> +
> +	rte_eth_copy_pci_info(dev, pci_dev);

This may be redundant, I guess rte_eth_dev_pci_generic_probe() does this
already, can you please check?

> +
> +	/* Get link state */
> +	nfb_eth_link_update(dev, 0);
> +
> +	/* Allocate space for one mac address */
> +	data->mac_addrs = rte_zmalloc(data->name, sizeof(struct ether_addr),
> +		RTE_CACHE_LINE_SIZE);
> +	if (data->mac_addrs == NULL) {
> +		RTE_LOG(ERR, PMD, "Could not alloc space for MAC address!\n");
> +		nfb_close(internals->nfb);
> +		return -EINVAL;
> +	}
> +
> +	ether_addr_copy(&eth_addr, data->mac_addrs);

This copies same MAC address for all instances of the device, if there are multi
ports or multi device all we have same MAC. Do you want to diffrenciate them?

<...>

> +/**
> + * DPDK callback to uninitialize an ethernet device
> + *
> + * @param dev
> + *   Pointer to ethernet device structure
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +static int
> +nfb_eth_dev_uninit(struct rte_eth_dev *dev)
> +{
> +	struct rte_eth_dev_data *data = dev->data;
> +	struct pmd_internals *internals = (struct pmd_internals *)
> +		data->dev_private;
> +
> +	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
> +	struct rte_pci_addr *pci_addr = &pci_dev->addr;
> +
> +	rte_free(dev->data->mac_addrs);
> +	dev->data->mac_addrs = NULL;

rte_eth_dev_pci_generic_remove() will cause the mac_address to be freed, you may
drop above free:

rte_eth_dev_pci_generic_remove
  rte_eth_dev_pci_release
    rte_eth_dev_release_port
      rte_free(eth_dev->data->mac_addrs);

<...>

> +static const struct rte_pci_id nfb_pci_id_table[] = {
> +	{
> +		RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_40G2)
> +	},

It is matter of taste perhaps but single line looks better to me, if you like
them as it is, I am OK with that too:
	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_40G2) },

<...>

> +static struct rte_pci_driver nfb_eth_driver = {
> +	.id_table = nfb_pci_id_table,
> +	.probe = nfb_eth_pci_probe,
> +	.remove = nfb_eth_pci_remove,

just to double check if you need any drv_flag set here, like
RTE_PCI_DRV_INTR_LSC or RTE_PCI_DRV_NEED_MAPPING?

<...>

> diff --git a/drivers/net/nfb/nfb_rx.h b/drivers/net/nfb/nfb_rx.h
> new file mode 100644
> index 0000000..b356f5d
> --- /dev/null
> +++ b/drivers/net/nfb/nfb_rx.h
> @@ -0,0 +1,226 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Cesnet
> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> + * All rights reserved.
> + */
> +
> +
> +

multiple blank lines, please clean if not intentional.

<...>

> +/**
> + * Initialize ndp_rx_queue structure
> + *
> + * @param nfb
> + *   Pointer to nfb device structure.
> + * @param rx_queue_id
> + *   RX queue index.
> + * @param port_id
> + *   Device [external] port identifier.
> + * @param mb_pool
> + *   Memory pool for buffer allocations.
> + * @param[out] rxq
> + *   Pointer to ndp_rx_queue output structure
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.

Does it really sets 'rte_errno'? I guess only copy/paste artifact, looks like
there are more in other function comments.

<...>

> +static __rte_always_inline uint16_t
> +nfb_eth_ndp_rx(void *queue,
> +	struct rte_mbuf **bufs,
> +	uint16_t nb_pkts)
> +{
> +	struct ndp_rx_queue *ndp = queue;
> +
> +	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
> +		RTE_LOG(ERR, PMD, "RX invalid arguments!\n");
> +		return 0;
> +	}
> +
> +	struct rte_mbuf *mbufs[nb_pkts];
> +
> +	unsigned int i;
> +	// returns either all or nothing

Please use c89 style comments, there are more below.

> +	i = rte_pktmbuf_alloc_bulk(ndp->mb_pool, mbufs, nb_pkts);
> +	if (unlikely(i != 0))
> +		return 0;
> +
> +	uint16_t packet_size;
> +	uint64_t num_bytes = 0;
> +	const uint16_t buf_size = ndp->buf_size;

And please have definitions at the beggining of the function.

> +
> +	struct rte_mbuf *mbuf;
> +	struct ndp_packet packets[nb_pkts];
> +
> +
> +	uint16_t num_rx = ndp_rx_burst_get(ndp->queue, packets, nb_pkts);
> +
> +	if (unlikely(num_rx != nb_pkts)) {
> +		for (i = num_rx; i < nb_pkts; i++)
> +			rte_pktmbuf_free(mbufs[i]);
> +	}
> +
> +	nb_pkts = num_rx;
> +
> +	num_rx = 0;
> +	/*
> +	 * Reads the given number of packets from NDP queue given
> +	 * by queue and copies the packet data into a newly allocated mbuf
> +	 * to return.
> +	 */
> +	for (i = 0; i < nb_pkts; ++i) {
> +		mbuf = mbufs[i];
> +
> +		/* get the space available for data in the mbuf */
> +		packet_size = packets[i].data_length;
> +
> +		if (likely(packet_size <= buf_size)) {
> +			/* NDP packet will fit in one mbuf, go ahead and copy */
> +			rte_memcpy(rte_pktmbuf_mtod(mbuf, void *),
> +				packets[i].data, packet_size);
> +
> +			mbuf->data_len = (uint16_t)packet_size;
> +
> +			mbuf->pkt_len = packet_size;
> +			mbuf->port = ndp->in_port;
> +			bufs[num_rx++] = mbuf;
> +			num_bytes += packet_size;
> +		} else {
> +			/*
> +			 * NDP packet will not fit in one mbuf,
> +			 * scattered mode is not enabled, drop packet
> +			 */
> +			RTE_LOG(ERR, PMD,
> +				"NDP segment %d bytes will not fit in one mbuf "
> +				"(%d bytes), scattered mode is not enabled, "
> +				"drop packet!!\n",
> +				packet_size, buf_size);

It may not be good idea to add log into data path, we may have tens of millions
packet per second.
And there are some logging macros that can be removed based on compile time
config options, it can be better idea to use them for data path,
CONFIG_RTE_LOG_DP_LEVEL.

<...>

> +int
> +nfb_eth_stats_get(struct rte_eth_dev *dev,
> +	struct rte_eth_stats *stats)
> +{
> +	uint16_t i;
> +	uint16_t nb_rx = dev->data->nb_rx_queues;
> +	uint16_t nb_tx = dev->data->nb_tx_queues;
> +	uint64_t rx_total = 0;
> +	uint64_t tx_total = 0;
> +	uint64_t tx_err_total = 0;
> +	uint64_t rx_total_bytes = 0;
> +	uint64_t tx_total_bytes = 0;
> +
> +	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
> +		dev->data->rx_queues);
> +	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
> +		dev->data->tx_queues);
> +
> +	for (i = 0; i < nb_rx; i++) {
> +		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> +			stats->q_ipackets[i] = rx_queue[i].rx_pkts;
> +			stats->q_ibytes[i] = rx_queue[i].rx_bytes;
> +		}
> +		rx_total += stats->q_ipackets[i];
> +		rx_total_bytes += stats->q_ibytes[i];
> +	}
> +
> +	for (i = 0; i < nb_tx; i++) {
> +		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> +			stats->q_opackets[i] = tx_queue[i].tx_pkts;
> +			stats->q_obytes[i] = tx_queue[i].tx_bytes;
> +			stats->q_errors[i] = tx_queue[i].err_pkts;

This is what David mentioned, q_errors seems like for Rx queue errors, there is
a general inconsistancey here, perhaps you can leave the code as it is but
please aware of this, it may needs to be changed soon.

<...>

> +	for (i = 0; i < nb_pkts; ++i) {
> +		mbuf = bufs[i];
> +
> +		pkt_len = mbuf->pkt_len;
> +		mbuf_segs = mbuf->nb_segs;
> +
> +		num_bytes += pkt_len;
> +		if (mbuf_segs == 1) {
> +			/*
> +			 * non-scattered packet,
> +			 * transmit from one mbuf
> +			 */
> +			rte_memcpy(packets[i].data,
> +				rte_pktmbuf_mtod(mbuf, const void *),
> +				pkt_len);
> +		} else {
> +			/* scattered packet, transmit from more mbufs */
> +			struct rte_mbuf *m = mbuf;
> +			while (m) {
> +				dst = packets[i].data;
> +
> +				rte_memcpy(dst,
> +					rte_pktmbuf_mtod(m,
> +					const void *),
> +					m->data_len);
> +				dst = ((uint8_t *)(dst)) +
> +					m->data_len;
> +				m = m->next;
> +			}
> +		}

This code looks like supports "DEV_TX_OFFLOAD_MULTI_SEGS", better to report his
capability in dev_info.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [dpdk-dev] [PATCH v3] net/nfb: new netcope driver
  2019-02-26 12:57 ` [dpdk-dev] [PATCH] net/nfb: new netcope driver Rastislav Cernay
                     ` (2 preceding siblings ...)
  2019-02-27 11:43   ` [dpdk-dev] [PATCH v2] net/nfb: new Netcope driver Rastislav Cernay
@ 2019-03-01 14:37   ` Rastislav Cernay
  2019-03-01 18:47     ` Stephen Hemminger
                       ` (4 more replies)
  2019-03-07 13:24   ` [dpdk-dev] [PATCH v4] " Rastislav Cernay
                     ` (4 subsequent siblings)
  8 siblings, 5 replies; 50+ messages in thread
From: Rastislav Cernay @ 2019-03-01 14:37 UTC (permalink / raw)
  To: dev; +Cc: ferruh.yigit, Rastislav Cernay

From: Rastislav Cernay <cernay@netcope.com>

Added new net driver for Netcope nfb cards

Signed-off-by: Rastislav Cernay <cernay@netcope.com>
---
v2: remove unnecessary cast
    remove unnecessary zeroing
    move declaration to not mix with code
    restore skeleton example
v3: add release notes
    add doc to doc index
    add architecture limits to doc
    edit features list
    add .map file
    change link to dependecies to official vendor site
    move declarations out of code
    remove false comments (rte_errno is set)
    comments to c89 style
    remove log from main rx loop
    remove redundant code
 MAINTAINERS                             |   7 +
 config/common_base                      |   4 +
 devtools/test-build.sh                  |   1 +
 doc/guides/nics/features/nfb.ini        |  18 +
 doc/guides/nics/index.rst               |   1 +
 doc/guides/nics/nfb.rst                 | 143 ++++++++
 doc/guides/rel_notes/release_19_02.rst  |   5 +
 drivers/net/Makefile                    |   1 +
 drivers/net/meson.build                 |   1 +
 drivers/net/nfb/Makefile                |  41 +++
 drivers/net/nfb/meson.build             |   9 +
 drivers/net/nfb/nfb.h                   |  50 +++
 drivers/net/nfb/nfb_ethdev.c            | 589 ++++++++++++++++++++++++++++++++
 drivers/net/nfb/nfb_rx.c                | 127 +++++++
 drivers/net/nfb/nfb_rx.h                | 213 ++++++++++++
 drivers/net/nfb/nfb_rxmode.c            | 100 ++++++
 drivers/net/nfb/nfb_rxmode.h            |  78 +++++
 drivers/net/nfb/nfb_stats.c             |  78 +++++
 drivers/net/nfb/nfb_stats.h             |  48 +++
 drivers/net/nfb/nfb_tx.c                | 113 ++++++
 drivers/net/nfb/nfb_tx.h                | 204 +++++++++++
 drivers/net/nfb/rte_nfb_pmd_version.map |   4 +
 mk/rte.app.mk                           |   1 +
 23 files changed, 1836 insertions(+)
 create mode 100644 doc/guides/nics/features/nfb.ini
 create mode 100644 doc/guides/nics/nfb.rst
 create mode 100644 drivers/net/nfb/Makefile
 create mode 100644 drivers/net/nfb/meson.build
 create mode 100644 drivers/net/nfb/nfb.h
 create mode 100644 drivers/net/nfb/nfb_ethdev.c
 create mode 100644 drivers/net/nfb/nfb_rx.c
 create mode 100644 drivers/net/nfb/nfb_rx.h
 create mode 100644 drivers/net/nfb/nfb_rxmode.c
 create mode 100644 drivers/net/nfb/nfb_rxmode.h
 create mode 100644 drivers/net/nfb/nfb_stats.c
 create mode 100644 drivers/net/nfb/nfb_stats.h
 create mode 100644 drivers/net/nfb/nfb_tx.c
 create mode 100644 drivers/net/nfb/nfb_tx.h
 create mode 100644 drivers/net/nfb/rte_nfb_pmd_version.map

diff --git a/MAINTAINERS b/MAINTAINERS
index 6610440..c6bffde 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -654,6 +654,13 @@ F: drivers/net/szedata2/
 F: doc/guides/nics/szedata2.rst
 F: doc/guides/nics/features/szedata2.ini
 
+Netcope nfb
+M: Rastislav Cernay <cernay@netcope.com>
+M: Jan Remes <remes@netcope.com>
+F: drivers/net/nfb/
+F: doc/guides/nics/nfb.rst
+F: doc/guides/nics/features/nfb.ini
+
 Netronome nfp
 M: Alejandro Lucero <alejandro.lucero@netronome.com>
 F: drivers/net/nfp/
diff --git a/config/common_base b/config/common_base
index 7c6da51..1ab0a6b 100644
--- a/config/common_base
+++ b/config/common_base
@@ -360,6 +360,10 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
 # Compile software PMD backed by SZEDATA2 device
 #
 CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
+#
+# Compile software PMD backed by NFB device
+#
+CONFIG_RTE_LIBRTE_PMD_NFB=n
 
 #
 # Compile burst-oriented Cavium Thunderx NICVF PMD driver
diff --git a/devtools/test-build.sh b/devtools/test-build.sh
index 42f4ad0..ab57ab8 100755
--- a/devtools/test-build.sh
+++ b/devtools/test-build.sh
@@ -18,6 +18,7 @@ default_path=$PATH
 # - DPDK_DEP_SSL (y/[n])
 # - DPDK_DEP_IPSEC_MB (y/[n])
 # - DPDK_DEP_SZE (y/[n])
+# - DPDK_DEP_NFB (y/[n])
 # - DPDK_DEP_ZLIB (y/[n])
 # - DPDK_MAKE_JOBS (int)
 # - DPDK_NOTIFY (notify-send)
diff --git a/doc/guides/nics/features/nfb.ini b/doc/guides/nics/features/nfb.ini
new file mode 100644
index 0000000..e1c5266
--- /dev/null
+++ b/doc/guides/nics/features/nfb.ini
@@ -0,0 +1,18 @@
+;
+; Supported features of the 'nfb' network poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Speed capabilities   = P
+Link status          = Y
+Queue start/stop     = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Basic stats          = Y
+Extended stats       = Y
+Stats per queue      = Y
+Other kdrv           = Y
+x86-64               = Y
+Usage doc            = Y
+Scattered Tx         = Y
diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index 5c80e3b..079972e 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -39,6 +39,7 @@ Network Interface Controller Drivers
     mvneta
     mvpp2
     netvsc
+    nfb
     nfp
     octeontx
     qede
diff --git a/doc/guides/nics/nfb.rst b/doc/guides/nics/nfb.rst
new file mode 100644
index 0000000..8c0be40
--- /dev/null
+++ b/doc/guides/nics/nfb.rst
@@ -0,0 +1,143 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright 2015 - 2016 CESNET
+
+NFB poll mode driver library
+=================================
+
+The NFB poll mode driver library implements support for the Netcope
+FPGA Boards (**NFB-***), FPGA-based programmable NICs.
+The NFB PMD uses interface provided by the libnfb library to communicate
+with the NFB cards over the nfb layer.
+
+More information about the
+`NFB cards <http://www.netcope.com/en/products/fpga-boards>`_
+and used technology
+(`Netcope Development Kit <http://www.netcope.com/en/products/fpga-development-kit>`_)
+can be found on the `Netcope Technologies website <http://www.netcope.com/>`_.
+
+.. note::
+
+   This driver has external dependencies.
+   Therefore it is disabled in default configuration files.
+   It can be enabled by setting ``CONFIG_RTE_LIBRTE_PMD_NFB=y``
+   and recompiling.
+
+.. note::
+
+   Currently the driver is supported only on x86_64 architectures.
+   Only x86_64 versions of the external libraries are provided.
+
+Prerequisites
+-------------
+
+This PMD requires kernel modules which are responsible for initialization and
+allocation of resources needed for nfb layer function.
+Communication between PMD and kernel modules is mediated by libnfb library.
+These kernel modules and library are not part of DPDK and must be installed
+separately:
+
+*  **libnfb library**
+
+   The library provides API for initialization of nfb transfers, receiving and
+   transmitting data segments.
+
+*  **Kernel modules**
+
+   * nfb
+
+   Kernel modules manage initialization of hardware, allocation and
+   sharing of resources for user space applications.
+
+Dependencies can be found here:
+`Netcope common <https://www.netcope.com/en/company/community-support/dpdk-libsze2#NFB>`_.
+
+Versions of the packages
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The minimum version of the provided packages:
+
+* for DPDK from 19.02
+
+Configuration
+-------------
+
+These configuration options can be modified before compilation in the
+``.config`` file:
+
+*  ``CONFIG_RTE_LIBRTE_PMD_NFB`` default value: **n**
+
+   Value **y** enables compilation of nfb PMD.
+
+Using the NFB PMD
+----------------------
+
+Kernel modules have to be loaded before running the DPDK application.
+
+NFB card architecture
+---------------------
+
+The NFB cards are multi-port multi-queue cards, where (generally) data from any
+Ethernet port may be sent to any queue.
+They are represented in DPDK as a single port.
+
+NFB-200G2QL card employs an addon cable which allows to connect it to two
+physical PCI-E slots at the same time (see the diagram below).
+This is done to allow 200 Gbps of traffic to be transferred through the PCI-E
+bus (note that a single PCI-E 3.0 x16 slot provides only 125 Gbps theoretical
+throughput).
+
+Although each slot may be connected to a different CPU and therefore to a different
+NUMA node, the card is represented as a single port in DPDK. To work with data
+from the individual queues on the right NUMA node, connection of NUMA nodes on
+first and last queue (each NUMA node has half of the queues) need to be checked.
+
+.. figure:: img/szedata2_nfb200g_architecture.svg
+    :align: center
+
+    NFB-200G2QL high-level diagram
+
+Limitations
+-----------
+
+Driver is usable only on Linux architecture.
+
+Since a card is always represented as a single port, but can be connected to two
+NUMA nodes, there is need for manual check where master/slave is connected.
+
+Example of usage
+----------------
+
+Read packets from 0. and 1. receive queue and write them to 0. and 1.
+transmit queue:
+
+.. code-block:: console
+
+   $RTE_TARGET/app/testpmd -l 0-3 -n 2 \
+   -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2 -i -a
+
+Example output:
+
+.. code-block:: console
+
+   [...]
+   EAL: PCI device 0000:06:00.0 on NUMA socket -1
+   EAL:   probe driver: 1b26:c1c1 net_nfb
+   PMD: Initializing NFB device (0000:06:00.0)
+   PMD: Available DMA queues RX: 8 TX: 8
+   PMD: NFB device (0000:06:00.0) successfully initialized
+   Interactive-mode selected
+   Auto-start selected
+   Configuring Port 0 (socket 0)
+   Port 0: 00:11:17:00:00:00
+   Checking link statuses...
+   Port 0 Link Up - speed 10000 Mbps - full-duplex
+   Done
+   Start automatic packet forwarding
+     io packet forwarding - CRC stripping disabled - packets/burst=32
+     nb forwarding cores=2 - nb forwarding ports=1
+     RX queues=2 - RX desc=128 - RX free threshold=0
+     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX queues=2 - TX desc=512 - TX free threshold=0
+     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX RS bit threshold=0 - TXQ flags=0x0
+   testpmd>
diff --git a/doc/guides/rel_notes/release_19_02.rst b/doc/guides/rel_notes/release_19_02.rst
index 3372c4d..3a59ac4 100644
--- a/doc/guides/rel_notes/release_19_02.rst
+++ b/doc/guides/rel_notes/release_19_02.rst
@@ -54,6 +54,11 @@ New Features
      Also, make sure to start the actual text at the margin.
      =========================================================
 
+* **Added NFB net PMD.**
+
+  Added the new ``nfb`` net driver for Netcope NFB cards. See
+  the :doc:`../nics/nfb` NIC guide for more details on this new driver.
+
 * **Added support to free hugepages exactly as originally allocated.**
 
   Some applications using memory event callbacks (especially for managing
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 670d7f7..013c551 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -38,6 +38,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5
 DIRS-$(CONFIG_RTE_LIBRTE_MVNETA_PMD) += mvneta
 DIRS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mvpp2
 DIRS-$(CONFIG_RTE_LIBRTE_NETVSC_PMD) += netvsc
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb
 DIRS-$(CONFIG_RTE_LIBRTE_NFP_PMD) += nfp
 DIRS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += null
diff --git a/drivers/net/meson.build b/drivers/net/meson.build
index 45da3bb..6733a19 100644
--- a/drivers/net/meson.build
+++ b/drivers/net/meson.build
@@ -27,6 +27,7 @@ drivers = ['af_packet',
 	'mvneta',
 	'mvpp2',
 	'netvsc',
+	'nfb',
 	'nfp',
 	'null', 'octeontx', 'pcap', 'qede', 'ring',
 	'sfc',
diff --git a/drivers/net/nfb/Makefile b/drivers/net/nfb/Makefile
new file mode 100644
index 0000000..ee8c7df
--- /dev/null
+++ b/drivers/net/nfb/Makefile
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Cesnet
+# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_nfb.a
+
+INCLUDES :=-I$(SRCDIR)
+
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+LDLIBS += -lnfb
+LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
+LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
+LDLIBS += -lrte_bus_pci
+
+EXPORT_MAP := rte_pmd_nfb_version.map
+
+LIBABIVER := 1
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_rx.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_tx.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_stats.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_rxmode.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/nfb/meson.build b/drivers/net/nfb/meson.build
new file mode 100644
index 0000000..d7dccba
--- /dev/null
+++ b/drivers/net/nfb/meson.build
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Cesnet
+# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+dep = cc.find_library('nfb', required: true)
+build = dep.found()
+ext_deps += dep
+sources = files('nfb_rx.c', 'nfb_tx.c', 'nfb_stats.c', 'nfb_ethdev.c', 'nfb_rxmode.c')
diff --git a/drivers/net/nfb/nfb.h b/drivers/net/nfb/nfb.h
new file mode 100644
index 0000000..42671a1
--- /dev/null
+++ b/drivers/net/nfb/nfb.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_H_
+#define _NFB_H_
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+
+/* PCI Vendor ID */
+#define PCI_VENDOR_ID_NETCOPE 0x1b26
+
+/* PCI Device IDs */
+#define PCI_DEVICE_ID_NFB_40G2  0xcb80
+#define PCI_DEVICE_ID_NFB_100G2 0xc2c1
+#define PCI_DEVICE_ID_NFB_200G2QL 0xc250
+
+/* Max index of ndp rx/tx queues */
+#define RTE_ETH_NDP_MAX_RX_QUEUES 32
+#define RTE_ETH_NDP_MAX_TX_QUEUES 32
+
+/* Max index of rx/tx dmas */
+#define RTE_MAX_NC_RXMAC 256
+#define RTE_MAX_NC_TXMAC 256
+
+#define RTE_NFB_DRIVER_NAME net_nfb
+
+struct pmd_internals {
+	uint16_t         max_rxmac;
+	uint16_t         max_txmac;
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC];
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC];
+
+	char             nfb_dev[PATH_MAX];
+	struct nfb_device *nfb;
+	/* Place to remember if filter was promiscuous or filtering by table,
+	 * when disabling allmulticast
+	 */
+	enum nc_rxmac_mac_filter rx_filter_original;
+};
+
+#endif /* _NFB_H_ */
diff --git a/drivers/net/nfb/nfb_ethdev.c b/drivers/net/nfb/nfb_ethdev.c
new file mode 100644
index 0000000..ae259ed
--- /dev/null
+++ b/drivers/net/nfb/nfb_ethdev.c
@@ -0,0 +1,589 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_kvargs.h>
+#include <rte_dev.h>
+#include <rte_common.h>
+
+#include "nfb_stats.h"
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+/**
+ * Default MAC addr
+ */
+static struct ether_addr eth_addr = {
+	.addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
+};
+
+/**
+ * Open all RX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] rxmac
+ *   Pointer to output array of nc_rxmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of rxmac
+ */
+static void
+nfb_nc_rxmac_init(struct nfb_device *nfb,
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t *max_rxmac)
+{
+	*max_rxmac = 0;
+	while ((rxmac[*max_rxmac] = nc_rxmac_open_index(nfb, *max_rxmac)))
+		++(*max_rxmac);
+}
+
+/**
+ * Open all TX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] txmac
+ *   Pointer to output array of nc_txmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of txmac
+ */
+static void
+nfb_nc_txmac_init(struct nfb_device *nfb,
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t *max_txmac)
+{
+	*max_txmac = 0;
+	while ((txmac[*max_txmac] = nc_txmac_open_index(nfb, *max_txmac)))
+		++(*max_txmac);
+}
+
+/**
+ * Close all RX DMA queues
+ *
+ * @param rxmac
+ *   Pointer to array of nc_rxmac
+ * @param max_rxmac
+ *   Maximum index of rxmac
+ */
+static void
+nfb_nc_rxmac_deinit(struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t max_rxmac)
+{
+	for (; max_rxmac > 0; --max_rxmac) {
+		nc_rxmac_close(rxmac[max_rxmac]);
+		rxmac[max_rxmac] = NULL;
+	}
+}
+
+/**
+ * Close all TX DMA queues
+ *
+ * @param txmac
+ *   Pointer to array of nc_txmac
+ * @param max_txmac
+ *   Maximum index of txmac
+ */
+static void
+nfb_nc_txmac_deinit(struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t max_txmac)
+{
+	for (; max_txmac > 0; --max_txmac) {
+		nc_txmac_close(txmac[max_txmac]);
+		txmac[max_txmac] = NULL;
+	}
+}
+
+/**
+ * DPDK callback to start the device.
+ *
+ * Start device by starting all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_start(struct rte_eth_dev *dev)
+{
+	int ret;
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_rx; i++) {
+		ret = nfb_eth_rx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_rx;
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		ret = nfb_eth_tx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_tx;
+	}
+
+	return 0;
+
+err_tx:
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+err_rx:
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+	return ret;
+}
+
+/**
+ * DPDK callback to stop the device.
+ *
+ * Stop device by stopping all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+nfb_eth_dev_stop(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+}
+
+/**
+ * DPDK callback for Ethernet device configuration.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+/**
+ * DPDK callback to get information about the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] info
+ *   Info structure output buffer.
+ */
+static void
+nfb_eth_dev_info(struct rte_eth_dev *dev,
+	struct rte_eth_dev_info *dev_info)
+{
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = dev->data->nb_rx_queues;
+	dev_info->max_tx_queues = dev->data->nb_tx_queues;
+	dev_info->speed_capa = ETH_LINK_SPEED_100G;
+}
+
+/**
+ * DPDK callback to close the device.
+ *
+ * Destroy all queues and objects, free memory.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+nfb_eth_dev_close(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	nfb_eth_dev_stop(dev);
+
+	for (i = 0; i < nb_rx; i++) {
+		nfb_eth_rx_queue_release(dev->data->rx_queues[i]);
+		dev->data->rx_queues[i] = NULL;
+	}
+	dev->data->nb_rx_queues = 0;
+	for (i = 0; i < nb_tx; i++) {
+		nfb_eth_tx_queue_release(dev->data->tx_queues[i]);
+		dev->data->tx_queues[i] = NULL;
+	}
+	dev->data->nb_tx_queues = 0;
+}
+
+/**
+ * DPDK callback to retrieve physical link information.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] link
+ *   Storage for current link status.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_link_update(struct rte_eth_dev *dev,
+	int wait_to_complete __rte_unused)
+{
+	uint16_t i;
+	struct nc_rxmac_status status;
+	struct rte_eth_link link;
+	memset(&link, 0, sizeof(link));
+
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	status.speed = MAC_SPEED_UNKNOWN;
+
+	link.link_speed = ETH_SPEED_NUM_NONE;
+	link.link_status = ETH_LINK_DOWN;
+	link.link_duplex = ETH_LINK_FULL_DUPLEX;
+	link.link_autoneg = ETH_LINK_SPEED_FIXED;
+
+	if (internals->rxmac[0] != NULL) {
+		nc_rxmac_read_status(internals->rxmac[0], &status);
+
+		switch (status.speed) {
+		case MAC_SPEED_10G:
+			link.link_speed = ETH_SPEED_NUM_10G;
+			break;
+		case MAC_SPEED_40G:
+			link.link_speed = ETH_SPEED_NUM_40G;
+			break;
+		case MAC_SPEED_100G:
+			link.link_speed = ETH_SPEED_NUM_100G;
+			break;
+		default:
+			link.link_speed = ETH_SPEED_NUM_NONE;
+			break;
+		}
+	}
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_read_status(internals->rxmac[i], &status);
+
+		if (status.enabled && status.link_up) {
+			link.link_status = ETH_LINK_UP;
+			break;
+		}
+	}
+
+	rte_eth_linkstatus_set(dev, &link);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to bring the link UP.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_set_link_up(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_enable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_enable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to bring the link DOWN.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_set_link_down(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_disable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_disable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to set primary MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_mac_addr_set(struct rte_eth_dev *dev,
+	struct ether_addr *mac_addr)
+{
+	unsigned i;
+	unsigned long long mac = 0;
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+
+	if (!is_valid_assigned_ether_addr(mac_addr)){
+		return -EINVAL;;
+	}
+
+	for (i = 0; i < 6; i++) {
+		mac <<= 8;
+		mac |= mac_addr->addr_bytes[i] & 0xFF;
+	}
+
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_set_mac(internals->rxmac[i], 0, mac, 1);
+
+	ether_addr_copy(mac_addr, data->mac_addrs);
+	return 0;
+}
+
+static const struct eth_dev_ops ops = {
+	.dev_start = nfb_eth_dev_start,
+	.dev_stop = nfb_eth_dev_stop,
+	.dev_set_link_up = nfb_eth_dev_set_link_up,
+	.dev_set_link_down = nfb_eth_dev_set_link_down,
+	.dev_close = nfb_eth_dev_close,
+	.dev_configure = nfb_eth_dev_configure,
+	.dev_infos_get = nfb_eth_dev_info,
+	.promiscuous_enable = nfb_eth_promiscuous_enable,
+	.promiscuous_disable = nfb_eth_promiscuous_disable,
+	.allmulticast_enable = nfb_eth_allmulticast_enable,
+	.allmulticast_disable = nfb_eth_allmulticast_disable,
+	.rx_queue_start = nfb_eth_rx_queue_start,
+	.rx_queue_stop = nfb_eth_rx_queue_stop,
+	.tx_queue_start = nfb_eth_tx_queue_start,
+	.tx_queue_stop = nfb_eth_tx_queue_stop,
+	.rx_queue_setup = nfb_eth_rx_queue_setup,
+	.tx_queue_setup = nfb_eth_tx_queue_setup,
+	.rx_queue_release = nfb_eth_rx_queue_release,
+	.tx_queue_release = nfb_eth_tx_queue_release,
+	.link_update = nfb_eth_link_update,
+	.stats_get = nfb_eth_stats_get,
+	.stats_reset = nfb_eth_stats_reset,
+	.mac_addr_set = nfb_eth_mac_addr_set,
+};
+
+/**
+ * DPDK callback to initialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_init(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+
+	RTE_LOG(INFO, PMD, "Initializing NFB device (" PCI_PRI_FMT ")\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	snprintf(internals->nfb_dev, PATH_MAX,
+		"/dev/nfb/by-pci-slot/" PCI_PRI_FMT,
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	/*
+	 * Get number of available DMA RX and TX queues, which is maximum
+	 * number of queues that can be created and store it in private device
+	 * data structure.
+	 */
+	internals->nfb = nfb_open(internals->nfb_dev);
+	if (internals->nfb == NULL) {
+		RTE_LOG(ERR, PMD, "nfb_open(): failed to open %s",
+			internals->nfb_dev);
+		return -EINVAL;
+	}
+	data->nb_rx_queues = ndp_get_rx_queue_available_count(internals->nfb);
+	data->nb_tx_queues = ndp_get_tx_queue_available_count(internals->nfb);
+
+	RTE_LOG(INFO, PMD, "Available NDP queues RX: %u TX: %u\n",
+		data->nb_rx_queues, data->nb_tx_queues);
+
+	nfb_nc_rxmac_init(internals->nfb,
+		internals->rxmac,
+		&internals->max_rxmac);
+	nfb_nc_txmac_init(internals->nfb,
+		internals->txmac,
+		&internals->max_txmac);
+
+	/* Set rx, tx burst functions */
+	dev->rx_pkt_burst = nfb_eth_ndp_rx;
+	dev->tx_pkt_burst = nfb_eth_ndp_tx;
+
+	/* Set function callbacks for Ethernet API */
+	dev->dev_ops = &ops;
+
+	/* Get link state */
+	nfb_eth_link_update(dev, 0);
+
+	/* Allocate space for one mac address */
+	data->mac_addrs = rte_zmalloc(data->name, sizeof(struct ether_addr),
+		RTE_CACHE_LINE_SIZE);
+	if (data->mac_addrs == NULL) {
+		RTE_LOG(ERR, PMD, "Could not alloc space for MAC address!\n");
+		nfb_close(internals->nfb);
+		return -EINVAL;
+	}
+
+	nfb_eth_mac_addr_set(dev, &eth_addr);
+
+	data->promiscuous = nfb_eth_promiscuous_get(dev);
+	data->all_multicast = nfb_eth_allmulticast_get(dev);
+	internals->rx_filter_original = data->promiscuous;
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully initialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to uninitialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_uninit(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+
+	dev->data->mac_addrs = NULL;
+
+	nfb_nc_rxmac_deinit(internals->rxmac, internals->max_rxmac);
+	nfb_nc_txmac_deinit(internals->txmac, internals->max_txmac);
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully uninitialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+static const struct rte_pci_id nfb_pci_id_table[] = {
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_40G2) },
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_100G2) },
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_200G2QL) },
+	{ .vendor_id = 0, }
+};
+
+/**
+ * DPDK callback to register a PCI device.
+ *
+ * This function spawns Ethernet devices out of a given PCI device.
+ *
+ * @param[in] pci_drv
+ *   PCI driver structure (nfb_driver).
+ * @param[in] pci_dev
+ *   PCI device information.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int nfb_eth_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+	struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_probe(pci_dev,
+		sizeof(struct pmd_internals), nfb_eth_dev_init);
+}
+
+/**
+ * DPDK callback to remove a PCI device.
+ *
+ * This function removes all Ethernet devices belong to a given PCI device.
+ *
+ * @param[in] pci_dev
+ *   Pointer to the PCI device.
+ *
+ * @return
+ *   0 on success, the function cannot fail.
+ */
+static int nfb_eth_pci_remove(struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_remove(pci_dev, nfb_eth_dev_uninit);
+}
+
+static struct rte_pci_driver nfb_eth_driver = {
+	.id_table = nfb_pci_id_table,
+	.probe = nfb_eth_pci_probe,
+	.remove = nfb_eth_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(RTE_NFB_DRIVER_NAME, nfb_eth_driver);
+RTE_PMD_REGISTER_PCI_TABLE(RTE_NFB_DRIVER_NAME, nfb_pci_id_table);
+RTE_PMD_REGISTER_KMOD_DEP(RTE_NFB_DRIVER_NAME, "* nfb");
diff --git a/drivers/net/nfb/nfb_rx.c b/drivers/net/nfb/nfb_rx.c
new file mode 100644
index 0000000..fbad6e5
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.c
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_rx.h"
+#include "nfb.h"
+
+int
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+	int ret;
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_start(rxq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+int
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+	int ret;
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_stop(rxq->queue);
+	if (ret != 0)
+		return -EINVAL;
+
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+		uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	struct ndp_rx_queue *rxq;
+	int ret;
+
+	rxq = rte_zmalloc_socket("ndp rx queue",
+			sizeof(struct ndp_rx_queue),
+			RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (rxq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for rx queue id "
+				"%" PRIu16 "!\n", rx_queue_id);
+		return -ENOMEM;
+	}
+
+	ret = nfb_eth_rx_queue_init(internals->nfb,
+		rx_queue_id,
+		dev->data->port_id,
+		mb_pool,
+		rxq);
+
+	if (ret == 0)
+		dev->data->rx_queues[rx_queue_id] = rxq;
+	else
+		rte_free(rxq);
+
+	return ret;
+}
+
+int
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+		uint16_t rx_queue_id,
+		uint16_t port_id,
+		struct rte_mempool *mb_pool,
+		struct ndp_rx_queue *rxq)
+{
+	if (nfb == NULL)
+		return -EINVAL;
+
+	rxq->queue = ndp_open_rx_queue(nfb, rx_queue_id);
+	if (rxq->queue == NULL)
+		return -EINVAL;
+
+	rxq->nfb = nfb;
+	rxq->rx_queue_id = rx_queue_id;
+	rxq->in_port = port_id;
+	rxq->mb_pool = mb_pool;
+
+	const struct rte_pktmbuf_pool_private *mbp_priv =
+		rte_mempool_get_priv(mb_pool);
+	rxq->buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size -
+		RTE_PKTMBUF_HEADROOM);
+
+	rxq->rx_pkts = 0;
+	rxq->rx_bytes = 0;
+	rxq->err_pkts = 0;
+
+	return 0;
+}
+
+void
+nfb_eth_rx_queue_release(void *q)
+{
+	struct ndp_rx_queue *rxq = (struct ndp_rx_queue *)q;
+	if (rxq->queue != NULL) {
+		ndp_close_rx_queue(rxq->queue);
+		rte_free(rxq);
+		rxq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_rx.h b/drivers/net/nfb/nfb_rx.h
new file mode 100644
index 0000000..7d2dbd4
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.h
@@ -0,0 +1,213 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_RX_H_
+#define _NFB_RX_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+struct ndp_rx_queue {
+	struct nfb_device *nfb;	     /* nfb dev structure */
+	struct ndp_queue *queue;     /* rx queue */
+	uint16_t rx_queue_id;	     /* index */
+	uint8_t in_port;	     /* port */
+
+	struct rte_mempool *mb_pool; /* memory pool to allocate packets */
+	uint16_t buf_size;           /* mbuf size */
+
+	volatile uint64_t rx_pkts;   /* packets read */
+	volatile uint64_t rx_bytes;  /* bytes read */
+	volatile uint64_t err_pkts;  /* erroneous packets */
+};
+
+/**
+ * Initialize ndp_rx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param rx_queue_id
+ *   RX queue index.
+ * @param port_id
+ *   Device [external] port identifier.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ * @param[out] rxq
+ *   Pointer to ndp_rx_queue output structure
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+	uint16_t rx_queue_id,
+	uint16_t port_id,
+	struct rte_mempool *mb_pool,
+	struct ndp_rx_queue *rxq);
+
+/**
+ * DPDK callback to setup a RX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t rx_queue_id,
+	uint16_t nb_rx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_rxconf *rx_conf __rte_unused,
+	struct rte_mempool *mb_pool);
+
+/**
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void
+nfb_eth_rx_queue_release(void *q);
+
+/**
+ * Start traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * Stop traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ */
+int
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * DPDK callback for RX.
+ *
+ * @param dpdk_rxq
+ *   Generic pointer to RX queue structure.
+ * @param[out] bufs
+ *   Array to store received packets.
+ * @param nb_pkts
+ *   Maximum number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully received (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t
+nfb_eth_ndp_rx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	struct ndp_rx_queue *ndp = queue;
+	uint16_t packet_size;
+	uint64_t num_bytes = 0;
+	uint16_t num_rx;
+	unsigned int i;
+
+	const uint16_t buf_size = ndp->buf_size;
+
+	struct rte_mbuf *mbuf;
+	struct ndp_packet packets[nb_pkts];
+
+	struct rte_mbuf *mbufs[nb_pkts];
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "RX invalid arguments!\n");
+		return 0;
+	}
+
+	/* returns either all or nothing */
+	i = rte_pktmbuf_alloc_bulk(ndp->mb_pool, mbufs, nb_pkts);
+	if (unlikely(i != 0))
+		return 0;
+
+	num_rx = ndp_rx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_rx != nb_pkts)) {
+		for (i = num_rx; i < nb_pkts; i++)
+			rte_pktmbuf_free(mbufs[i]);
+	}
+
+	nb_pkts = num_rx;
+
+	num_rx = 0;
+	/*
+	 * Reads the given number of packets from NDP queue given
+	 * by queue and copies the packet data into a newly allocated mbuf
+	 * to return.
+	 */
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = mbufs[i];
+
+		/* get the space available for data in the mbuf */
+		packet_size = packets[i].data_length;
+
+		if (likely(packet_size <= buf_size)) {
+			/* NDP packet will fit in one mbuf, go ahead and copy */
+			rte_memcpy(rte_pktmbuf_mtod(mbuf, void *),
+				packets[i].data, packet_size);
+
+			mbuf->data_len = (uint16_t)packet_size;
+
+			mbuf->pkt_len = packet_size;
+			mbuf->port = ndp->in_port;
+			bufs[num_rx++] = mbuf;
+			num_bytes += packet_size;
+		} else {
+			/*
+			 * NDP packet will not fit in one mbuf,
+			 * scattered mode is not enabled, drop packet
+			 */
+			rte_pktmbuf_free(mbuf);
+		}
+	}
+
+	ndp_rx_burst_put(ndp->queue);
+
+	ndp->rx_pkts += num_rx;
+	ndp->rx_bytes += num_bytes;
+	return num_rx;
+}
+
+#endif /* _NFB_RX_H_ */
diff --git a/drivers/net/nfb/nfb_rxmode.c b/drivers/net/nfb/nfb_rxmode.c
new file mode 100644
index 0000000..e98ed07
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.c
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+void
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+	uint16_t i;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_PROMISCUOUS);
+	}
+}
+
+void
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+	uint16_t i;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_TABLE;
+
+	/* if promisc is not enabled, do nothing */
+	if (!nfb_eth_promiscuous_get(dev))
+		return;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE);
+	}
+}
+
+int
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_PROMISCUOUS);
+}
+
+void
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+	}
+}
+
+void
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+
+	/* if multicast is not enabled do nothing */
+	if (!nfb_eth_allmulticast_get(dev))
+		return;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			internals->rx_filter_original);
+	}
+}
+
+int
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+}
diff --git a/drivers/net/nfb/nfb_rxmode.h b/drivers/net/nfb/nfb_rxmode.h
new file mode 100644
index 0000000..e381b73
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_RXMODE_H_
+#define _NFB_RXMODE_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_ethdev.h>
+#include <rte_dev.h>
+
+/**
+ * Getter for promiscuous mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to enable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to disable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev);
+
+/**
+ * Getter for allmulticast mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to enable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to disable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev);
+
+#endif /* _NFB_RXMODE_H_ */
diff --git a/drivers/net/nfb/nfb_stats.c b/drivers/net/nfb/nfb_stats.c
new file mode 100644
index 0000000..ffc27a5
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.c
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_stats.h"
+#include "nfb.h"
+
+int
+nfb_eth_stats_get(struct rte_eth_dev *dev,
+	struct rte_eth_stats *stats)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+	uint64_t rx_total = 0;
+	uint64_t tx_total = 0;
+	uint64_t tx_err_total = 0;
+	uint64_t rx_total_bytes = 0;
+	uint64_t tx_total_bytes = 0;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_ipackets[i] = rx_queue[i].rx_pkts;
+			stats->q_ibytes[i] = rx_queue[i].rx_bytes;
+		}
+		rx_total += stats->q_ipackets[i];
+		rx_total_bytes += stats->q_ibytes[i];
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_opackets[i] = tx_queue[i].tx_pkts;
+			stats->q_obytes[i] = tx_queue[i].tx_bytes;
+			stats->q_errors[i] = tx_queue[i].err_pkts;
+		}
+		tx_total += stats->q_opackets[i];
+		tx_total_bytes += stats->q_obytes[i];
+		tx_err_total += stats->q_errors[i];
+	}
+
+	stats->ipackets = rx_total;
+	stats->opackets = tx_total;
+	stats->ibytes = rx_total_bytes;
+	stats->obytes = tx_total_bytes;
+	stats->oerrors = tx_err_total;
+	return 0;
+}
+
+void
+nfb_eth_stats_reset(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		rx_queue[i].rx_pkts = 0;
+		rx_queue[i].rx_bytes = 0;
+		rx_queue[i].err_pkts = 0;
+	}
+	for (i = 0; i < nb_tx; i++) {
+		tx_queue[i].tx_pkts = 0;
+		tx_queue[i].tx_bytes = 0;
+		tx_queue[i].err_pkts = 0;
+	}
+}
diff --git a/drivers/net/nfb/nfb_stats.h b/drivers/net/nfb/nfb_stats.h
new file mode 100644
index 0000000..ce0591a
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_STATS_H_
+#define _NFB_STATS_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+/**
+ * DPDK callback to get device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] stats
+ *   Stats structure output buffer.
+ *
+ * @return
+ *   0 on success and stats is filled, negative errno value otherwise.
+ */
+int nfb_eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats);
+
+/**
+ * DPDK callback to clear device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void nfb_eth_stats_reset(struct rte_eth_dev *dev);
+
+#endif /* _NFB_STATS_H_ */
diff --git a/drivers/net/nfb/nfb_tx.c b/drivers/net/nfb/nfb_tx.c
new file mode 100644
index 0000000..1a4542f
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.c
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_tx.h"
+#include "nfb.h"
+
+int
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+	int ret;
+
+	if (txq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_start(txq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+int
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+	int ret;
+
+	if (txq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "TX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_stop(txq->queue);
+	if (ret != 0)
+		return -EINVAL;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	int ret;
+	struct ndp_tx_queue *txq;
+
+	txq = rte_zmalloc_socket("ndp tx queue",
+		sizeof(struct ndp_tx_queue),
+		RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (txq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for tx queue id "
+			"%" PRIu16 "!\n", tx_queue_id);
+		return -ENOMEM;
+	}
+
+	ret = nfb_eth_tx_queue_init(internals->nfb,
+		tx_queue_id,
+		txq);
+
+	if (ret == 0)
+		dev->data->tx_queues[tx_queue_id] = txq;
+	else
+		rte_free(txq);
+
+	return ret;
+}
+
+int
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq)
+{
+	if (nfb == NULL)
+		return -EINVAL;
+
+	txq->queue = ndp_open_tx_queue(nfb, tx_queue_id);
+	if (txq->queue == NULL)
+		return -EINVAL;
+
+	txq->nfb = nfb;
+	txq->tx_queue_id = tx_queue_id;
+
+	txq->tx_pkts = 0;
+	txq->tx_bytes = 0;
+	txq->err_pkts = 0;
+
+	return 0;
+}
+
+void
+nfb_eth_tx_queue_release(void *q)
+{
+	struct ndp_tx_queue *txq = (struct ndp_tx_queue *)q;
+	if (txq->queue != NULL) {
+		ndp_close_tx_queue(txq->queue);
+		rte_free(txq);
+		txq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_tx.h b/drivers/net/nfb/nfb_tx.h
new file mode 100644
index 0000000..b17f776
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.h
@@ -0,0 +1,204 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_TX_H_
+#define _NFB_TX_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+struct ndp_tx_queue {
+	struct nfb_device *nfb;     /* nfb dev structure */
+	struct ndp_queue *queue;    /* tx queue */
+	uint16_t          tx_queue_id;       /* index */
+	volatile uint64_t tx_pkts;  /* packets transmitted */
+	volatile uint64_t tx_bytes; /* bytes transmitted */
+	volatile uint64_t err_pkts; /* erroneous packets */
+};
+
+/**
+ * DPDK callback to setup a TX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mp
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused);
+
+/**
+ * Initialize ndp_tx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param tx_queue_id
+ *   TX queue index.
+ * @param[out] txq
+ *   Pointer to ndp_tx_queue output structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq);
+
+/**
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void
+nfb_eth_tx_queue_release(void *q);
+
+/**
+ * Start traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * Stop traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * DPDK callback for TX.
+ *
+ * @param dpdk_txq
+ *   Generic pointer to TX queue structure.
+ * @param bufs
+ *   Packets to transmit.
+ * @param nb_pkts
+ *   Number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully transmitted (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t
+nfb_eth_ndp_tx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	int i;
+	struct rte_mbuf *mbuf;
+	struct ndp_tx_queue *ndp = queue;
+	uint16_t num_tx = 0;
+	uint64_t num_bytes = 0;
+
+	void *dst;
+	uint32_t pkt_len;
+	uint8_t mbuf_segs;
+
+	struct ndp_packet packets[nb_pkts];
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "RX invalid arguments!\n");
+		return 0;
+	}
+
+	for (i = 0; i < nb_pkts; i++) {
+		packets[i].data_length = bufs[i]->pkt_len;
+		packets[i].header_length = 0;
+	}
+
+	num_tx = ndp_tx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_tx != nb_pkts))
+		return 0;
+
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = bufs[i];
+
+		pkt_len = mbuf->pkt_len;
+		mbuf_segs = mbuf->nb_segs;
+
+		num_bytes += pkt_len;
+		if (mbuf_segs == 1) {
+			/*
+			 * non-scattered packet,
+			 * transmit from one mbuf
+			 */
+			rte_memcpy(packets[i].data,
+				rte_pktmbuf_mtod(mbuf, const void *),
+				pkt_len);
+		} else {
+			/* scattered packet, transmit from more mbufs */
+			struct rte_mbuf *m = mbuf;
+			while (m) {
+				dst = packets[i].data;
+
+				rte_memcpy(dst,
+					rte_pktmbuf_mtod(m,
+					const void *),
+					m->data_len);
+				dst = ((uint8_t *)(dst)) +
+					m->data_len;
+				m = m->next;
+			}
+		}
+
+		rte_pktmbuf_free(mbuf);
+	}
+
+	ndp_tx_burst_flush(ndp->queue);
+
+	ndp->tx_pkts += num_tx;
+	ndp->err_pkts += nb_pkts - num_tx;
+	ndp->tx_bytes += num_bytes;
+	return num_tx;
+}
+
+#endif /* _NFB_TX_H_ */
diff --git a/drivers/net/nfb/rte_nfb_pmd_version.map b/drivers/net/nfb/rte_nfb_pmd_version.map
new file mode 100644
index 0000000..97fd251
--- /dev/null
+++ b/drivers/net/nfb/rte_nfb_pmd_version.map
@@ -0,0 +1,4 @@
+DPDK_19.02 {
+
+        local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 8a4f0f4..32e88b5 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -196,6 +196,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC)      += -lrte_pmd_softnic
 endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD)    += -lrte_pmd_sfc_efx
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2 -lsze2
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NFB)        += -lrte_pmd_nfb -lnfb -lfdt
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_TAP)        += -lrte_pmd_tap
 _LDLIBS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += -lrte_pmd_thunderx_nicvf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD) += -lrte_pmd_vdev_netvsc
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v3] net/nfb: new netcope driver
  2019-03-01 14:37   ` [dpdk-dev] [PATCH v3] net/nfb: new netcope driver Rastislav Cernay
@ 2019-03-01 18:47     ` Stephen Hemminger
  2019-03-04 14:07       ` Rastislav Černay
  2019-03-01 18:50     ` Stephen Hemminger
                       ` (3 subsequent siblings)
  4 siblings, 1 reply; 50+ messages in thread
From: Stephen Hemminger @ 2019-03-01 18:47 UTC (permalink / raw)
  To: Rastislav Cernay; +Cc: dev, ferruh.yigit

On Fri,  1 Mar 2019 15:37:34 +0100
Rastislav Cernay <cernay@netcope.com> wrote:

> +/**
> + * Default MAC addr
> + */
> +static struct ether_addr eth_addr = {
> +	.addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }

You might want to consider using a random ethernet address.
What does the device do on Linux?

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v3] net/nfb: new netcope driver
  2019-03-01 14:37   ` [dpdk-dev] [PATCH v3] net/nfb: new netcope driver Rastislav Cernay
  2019-03-01 18:47     ` Stephen Hemminger
@ 2019-03-01 18:50     ` Stephen Hemminger
  2019-03-04  9:53       ` David Marchand
  2019-03-04 11:34     ` David Marchand
                       ` (2 subsequent siblings)
  4 siblings, 1 reply; 50+ messages in thread
From: Stephen Hemminger @ 2019-03-01 18:50 UTC (permalink / raw)
  To: Rastislav Cernay; +Cc: dev, ferruh.yigit

On Fri,  1 Mar 2019 15:37:34 +0100
Rastislav Cernay <cernay@netcope.com> wrote:

> From: Rastislav Cernay <cernay@netcope.com>
> 
> Added new net driver for Netcope nfb cards
> 
> Signed-off-by: Rastislav Cernay <cernay@netcope.com>
> ---

Please fix these obvious style issues from checkpatches

ERROR:SPACING: space required before the open brace '{'
#934: FILE: drivers/net/nfb/nfb_ethdev.c:380:
+	if (!is_valid_assigned_ether_addr(mac_addr)){

WARNING:ONE_SEMICOLON: Statements terminations use 1 semicolon
#935: FILE: drivers/net/nfb/nfb_ethdev.c:381:
+		return -EINVAL;;

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v3] net/nfb: new netcope driver
  2019-03-01 18:50     ` Stephen Hemminger
@ 2019-03-04  9:53       ` David Marchand
  0 siblings, 0 replies; 50+ messages in thread
From: David Marchand @ 2019-03-04  9:53 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: Rastislav Cernay, dev, Yigit, Ferruh

On Fri, Mar 1, 2019 at 7:50 PM Stephen Hemminger <stephen@networkplumber.org>
wrote:

> On Fri,  1 Mar 2019 15:37:34 +0100
> Rastislav Cernay <cernay@netcope.com> wrote:
>
> > From: Rastislav Cernay <cernay@netcope.com>
> >
> > Added new net driver for Netcope nfb cards
> >
> > Signed-off-by: Rastislav Cernay <cernay@netcope.com>
> > ---
>
> Please fix these obvious style issues from checkpatches
>
> ERROR:SPACING: space required before the open brace '{'
> #934: FILE: drivers/net/nfb/nfb_ethdev.c:380:
> +       if (!is_valid_assigned_ether_addr(mac_addr)){
>
> WARNING:ONE_SEMICOLON: Statements terminations use 1 semicolon
> #935: FILE: drivers/net/nfb/nfb_ethdev.c:381:
> +               return -EINVAL;;
>


And if you look carefully at checkpatches.sh output, you can see:
[dmarchan@dmarchan dpdk]$ ./devtools/checkpatches.sh

### net/nfb: new netcope driver

[snip]

total: 1 errors, 2 warnings, 1884 lines checked
./devtools/checkpatches.sh: line 65: res: command not found

I will post a fix on checkpatches.sh for this, then a new warning appears:

Warning in /doc/guides/nics/nfb.rst:
Using explicit .svg extension instead of .*


-- 
David Marchand

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v3] net/nfb: new netcope driver
  2019-03-01 14:37   ` [dpdk-dev] [PATCH v3] net/nfb: new netcope driver Rastislav Cernay
  2019-03-01 18:47     ` Stephen Hemminger
  2019-03-01 18:50     ` Stephen Hemminger
@ 2019-03-04 11:34     ` David Marchand
  2019-03-04 14:33       ` Rastislav Černay
  2019-03-05 20:31     ` Rami Rosen
  2019-03-05 22:41     ` Luca Boccassi
  4 siblings, 1 reply; 50+ messages in thread
From: David Marchand @ 2019-03-04 11:34 UTC (permalink / raw)
  To: Rastislav Cernay; +Cc: dev, Yigit, Ferruh

On Fri, Mar 1, 2019 at 3:38 PM Rastislav Cernay <cernay@netcope.com> wrote:

> diff --git a/drivers/net/nfb/nfb_stats.c b/drivers/net/nfb/nfb_stats.c
> new file mode 100644
> index 0000000..ffc27a5
> --- /dev/null
> +++ b/drivers/net/nfb/nfb_stats.c
> @@ -0,0 +1,78 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Cesnet
> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> + * All rights reserved.
> + */
> +
> +#include "nfb_stats.h"
> +#include "nfb.h"
> +
> +int
> +nfb_eth_stats_get(struct rte_eth_dev *dev,
> +       struct rte_eth_stats *stats)
> +{
> +       uint16_t i;
> +       uint16_t nb_rx = dev->data->nb_rx_queues;
> +       uint16_t nb_tx = dev->data->nb_tx_queues;
> +       uint64_t rx_total = 0;
> +       uint64_t tx_total = 0;
> +       uint64_t tx_err_total = 0;
> +       uint64_t rx_total_bytes = 0;
> +       uint64_t tx_total_bytes = 0;
> +
> +       struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
> +               dev->data->rx_queues);
> +       struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
> +               dev->data->tx_queues);
> +
> +       for (i = 0; i < nb_rx; i++) {
> +               if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> +                       stats->q_ipackets[i] = rx_queue[i].rx_pkts;
> +                       stats->q_ibytes[i] = rx_queue[i].rx_bytes;
> +               }
> +               rx_total += stats->q_ipackets[i];
> +               rx_total_bytes += stats->q_ibytes[i];
> +       }
>

What is the point of adding when i >= RTE_ETHDEV_QUEUE_STAT_CNTRS ?
Hopefully, ethdev passes a zero'd structure, but still I find it confusing.



> +
> +       for (i = 0; i < nb_tx; i++) {
> +               if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> +                       stats->q_opackets[i] = tx_queue[i].tx_pkts;
> +                       stats->q_obytes[i] = tx_queue[i].tx_bytes;
> +                       stats->q_errors[i] = tx_queue[i].err_pkts;
> +               }
> +               tx_total += stats->q_opackets[i];
> +               tx_total_bytes += stats->q_obytes[i];
> +               tx_err_total += stats->q_errors[i];
> +       }
>

Idem.
Besides, q_errors[] is for reception errors.

+
> +       stats->ipackets = rx_total;
> +       stats->opackets = tx_total;
> +       stats->ibytes = rx_total_bytes;
> +       stats->obytes = tx_total_bytes;
> +       stats->oerrors = tx_err_total;
> +       return 0;
> +}
>
>
-- 
David Marchand

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v3] net/nfb: new netcope driver
  2019-03-04 14:33       ` Rastislav Černay
@ 2019-03-04 12:35         ` David Marchand
  2019-03-04 12:48           ` David Marchand
  0 siblings, 1 reply; 50+ messages in thread
From: David Marchand @ 2019-03-04 12:35 UTC (permalink / raw)
  To: Rastislav Černay; +Cc: dev, Yigit, Ferruh

On Mon, Mar 4, 2019 at 1:30 PM Rastislav Černay <cernay@netcope.com> wrote:

> >>> What is the point of adding when i >= RTE_ETHDEV_QUEUE_STAT_CNTRS ?
>
> struct rte_eth_stats {
> ...
> uint64_t q_opackets[RTE_ETHDEV_QUEUE_STAT_CNTRS]
> ...
> }
>
> As there can be more queues (nb_tx) then RTE_ETHDEV_QUEUE_STAT_CNTRS (16)
> and struct rte_eth_stats eth_stats is allocated statically,
> there is need to check so it does not write garbage somewhere.
>

How about looping on min(nb_tx, RTE_ETHDEV_QUEUE_STAT_CNTRS) ?



> >>> Besides, q_errors[] is for reception errors.
> I will fix that, meanwhile could q_errors[] be renamed to q_ierrors[]?
> Also could there be a way to publish output errors per queue, for example
> q_oerrors[]?
>

At the moment, no, this would be a api breakage, and adding oerrors would
be a abi breakage.
This can be discussed yes, I just sent a series about q_errors[].

You can still export this via xstats.


-- 
David Marchand

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v3] net/nfb: new netcope driver
  2019-03-04 12:35         ` David Marchand
@ 2019-03-04 12:48           ` David Marchand
  2019-03-04 15:15             ` Rastislav Černay
  0 siblings, 1 reply; 50+ messages in thread
From: David Marchand @ 2019-03-04 12:48 UTC (permalink / raw)
  To: Rastislav Černay; +Cc: dev, Yigit, Ferruh

On Mon, Mar 4, 2019 at 1:35 PM David Marchand <david.marchand@redhat.com>
wrote:

>
>
> On Mon, Mar 4, 2019 at 1:30 PM Rastislav Černay <cernay@netcope.com>
> wrote:
>
>> >>> What is the point of adding when i >= RTE_ETHDEV_QUEUE_STAT_CNTRS ?
>>
>> struct rte_eth_stats {
>> ...
>> uint64_t q_opackets[RTE_ETHDEV_QUEUE_STAT_CNTRS]
>> ...
>> }
>>
>> As there can be more queues (nb_tx) then RTE_ETHDEV_QUEUE_STAT_CNTRS
>> (16) and struct rte_eth_stats eth_stats is allocated statically,
>> there is need to check so it does not write garbage somewhere.
>>
>
> How about looping on min(nb_tx, RTE_ETHDEV_QUEUE_STAT_CNTRS) ?
>

Or add the tx_queue[i].tx_xxx; to the associated global stats and only
fills q_xxx depending on the check.


-- 
David Marchand

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v3] net/nfb: new netcope driver
  2019-03-01 18:47     ` Stephen Hemminger
@ 2019-03-04 14:07       ` Rastislav Černay
  0 siblings, 0 replies; 50+ messages in thread
From: Rastislav Černay @ 2019-03-04 14:07 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev, ferruh.yigit

Typically device works in promiscuous mode and filtering/processing is done
after
packets are received, use of MACS is a marginal case so we are not exactly
focused
on it. I will add random ethernet address so card can work in initial state
with multiple
devices.




On Fri, Mar 1, 2019 at 7:47 PM Stephen Hemminger <stephen@networkplumber.org>
wrote:

> On Fri,  1 Mar 2019 15:37:34 +0100
> Rastislav Cernay <cernay@netcope.com> wrote:
>
> > +/**
> > + * Default MAC addr
> > + */
> > +static struct ether_addr eth_addr = {
> > +     .addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
>
> You might want to consider using a random ethernet address.
> What does the device do on Linux?
>

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v3] net/nfb: new netcope driver
  2019-03-04 11:34     ` David Marchand
@ 2019-03-04 14:33       ` Rastislav Černay
  2019-03-04 12:35         ` David Marchand
  0 siblings, 1 reply; 50+ messages in thread
From: Rastislav Černay @ 2019-03-04 14:33 UTC (permalink / raw)
  To: David Marchand; +Cc: dev, Yigit, Ferruh

>>> What is the point of adding when i >= RTE_ETHDEV_QUEUE_STAT_CNTRS ?

struct rte_eth_stats {
...
uint64_t q_opackets[RTE_ETHDEV_QUEUE_STAT_CNTRS]
...
}

As there can be more queues (nb_tx) then RTE_ETHDEV_QUEUE_STAT_CNTRS (16)
and struct rte_eth_stats eth_stats is allocated statically,
there is need to check so it does not write garbage somewhere.

>>> Besides, q_errors[] is for reception errors.
I will fix that, meanwhile could q_errors[] be renamed to q_ierrors[]? Also
could there be a way to publish output errors per queue, for example
q_oerrors[]?



On Mon, Mar 4, 2019 at 12:35 PM David Marchand <david.marchand@redhat.com>
wrote:

>
> On Fri, Mar 1, 2019 at 3:38 PM Rastislav Cernay <cernay@netcope.com>
> wrote:
>
>> diff --git a/drivers/net/nfb/nfb_stats.c b/drivers/net/nfb/nfb_stats.c
>> new file mode 100644
>> index 0000000..ffc27a5
>> --- /dev/null
>> +++ b/drivers/net/nfb/nfb_stats.c
>> @@ -0,0 +1,78 @@
>> +/* SPDX-License-Identifier: BSD-3-Clause
>> + * Copyright(c) 2018 Cesnet
>> + * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
>> + * All rights reserved.
>> + */
>> +
>> +#include "nfb_stats.h"
>> +#include "nfb.h"
>> +
>> +int
>> +nfb_eth_stats_get(struct rte_eth_dev *dev,
>> +       struct rte_eth_stats *stats)
>> +{
>> +       uint16_t i;
>> +       uint16_t nb_rx = dev->data->nb_rx_queues;
>> +       uint16_t nb_tx = dev->data->nb_tx_queues;
>> +       uint64_t rx_total = 0;
>> +       uint64_t tx_total = 0;
>> +       uint64_t tx_err_total = 0;
>> +       uint64_t rx_total_bytes = 0;
>> +       uint64_t tx_total_bytes = 0;
>> +
>> +       struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
>> +               dev->data->rx_queues);
>> +       struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
>> +               dev->data->tx_queues);
>> +
>> +       for (i = 0; i < nb_rx; i++) {
>> +               if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
>> +                       stats->q_ipackets[i] = rx_queue[i].rx_pkts;
>> +                       stats->q_ibytes[i] = rx_queue[i].rx_bytes;
>> +               }
>> +               rx_total += stats->q_ipackets[i];
>> +               rx_total_bytes += stats->q_ibytes[i];
>> +       }
>>
>
> What is the point of adding when i >= RTE_ETHDEV_QUEUE_STAT_CNTRS ?
> Hopefully, ethdev passes a zero'd structure, but still I find it confusing.
>
>
>
>> +
>> +       for (i = 0; i < nb_tx; i++) {
>> +               if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
>> +                       stats->q_opackets[i] = tx_queue[i].tx_pkts;
>> +                       stats->q_obytes[i] = tx_queue[i].tx_bytes;
>> +                       stats->q_errors[i] = tx_queue[i].err_pkts;
>> +               }
>> +               tx_total += stats->q_opackets[i];
>> +               tx_total_bytes += stats->q_obytes[i];
>> +               tx_err_total += stats->q_errors[i];
>> +       }
>>
>
> Idem.
> Besides, q_errors[] is for reception errors.
>
> +
>> +       stats->ipackets = rx_total;
>> +       stats->opackets = tx_total;
>> +       stats->ibytes = rx_total_bytes;
>> +       stats->obytes = tx_total_bytes;
>> +       stats->oerrors = tx_err_total;
>> +       return 0;
>> +}
>>
>>
> --
> David Marchand
>

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v3] net/nfb: new netcope driver
  2019-03-04 12:48           ` David Marchand
@ 2019-03-04 15:15             ` Rastislav Černay
  0 siblings, 0 replies; 50+ messages in thread
From: Rastislav Černay @ 2019-03-04 15:15 UTC (permalink / raw)
  To: David Marchand; +Cc: dev, Yigit, Ferruh

>>>How about looping on min(nb_tx, RTE_ETHDEV_QUEUE_STAT_CNTRS) ?
This would lead to incomplete tx_total (and other total) stats. Maybe I
could just
add commentary, why it is written like this and leave it be?


On Mon, Mar 4, 2019 at 1:48 PM David Marchand <david.marchand@redhat.com>
wrote:

> On Mon, Mar 4, 2019 at 1:35 PM David Marchand <david.marchand@redhat.com>
> wrote:
>
>>
>>
>> On Mon, Mar 4, 2019 at 1:30 PM Rastislav Černay <cernay@netcope.com>
>> wrote:
>>
>>> >>> What is the point of adding when i >= RTE_ETHDEV_QUEUE_STAT_CNTRS ?
>>>
>>> struct rte_eth_stats {
>>> ...
>>> uint64_t q_opackets[RTE_ETHDEV_QUEUE_STAT_CNTRS]
>>> ...
>>> }
>>>
>>> As there can be more queues (nb_tx) then RTE_ETHDEV_QUEUE_STAT_CNTRS
>>> (16) and struct rte_eth_stats eth_stats is allocated statically,
>>> there is need to check so it does not write garbage somewhere.
>>>
>>
>> How about looping on min(nb_tx, RTE_ETHDEV_QUEUE_STAT_CNTRS) ?
>>
>
> Or add the tx_queue[i].tx_xxx; to the associated global stats and only
> fills q_xxx depending on the check.
>
>
> --
> David Marchand
>

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v3] net/nfb: new netcope driver
  2019-03-01 14:37   ` [dpdk-dev] [PATCH v3] net/nfb: new netcope driver Rastislav Cernay
                       ` (2 preceding siblings ...)
  2019-03-04 11:34     ` David Marchand
@ 2019-03-05 20:31     ` Rami Rosen
  2019-03-05 22:41     ` Luca Boccassi
  4 siblings, 0 replies; 50+ messages in thread
From: Rami Rosen @ 2019-03-05 20:31 UTC (permalink / raw)
  To: Rastislav Cernay; +Cc: dev, Ferruh Yigit

Hi,

Added new net driver for Netcope nfb cards

Signed-off-by: Rastislav Cernay <cernay at netcope.com>
Reviewed-by: Rami Rosen <ramirose@gmail.com>
---
v2: remove unnecessary cast
    remove unnecessary zeroing
    move declaration to not mix with code
    restore skeleton example
v3: add release notes
    add doc to doc index
    add architecture limits to doc
    edit features list
    add .map file
    change link to dependecies to official vendor site
    move declarations out of code
    remove false comments (rte_errno is set)
    comments to c89 style
    remove log from main rx loop
    remove redundant code
 MAINTAINERS                             |   7 +
 config/common_base                      |   4 +
 devtools/test-build.sh                  |   1 +
 doc/guides/nics/features/nfb.ini        |  18 +
 doc/guides/nics/index.rst               |   1 +
 doc/guides/nics/nfb.rst                 | 143 ++++++++
 doc/guides/rel_notes/release_19_02.rst  |   5 +
 drivers/net/Makefile                    |   1 +
 drivers/net/meson.build                 |   1 +
 drivers/net/nfb/Makefile                |  41 +++
 drivers/net/nfb/meson.build             |   9 +
 drivers/net/nfb/nfb.h                   |  50 +++
 drivers/net/nfb/nfb_ethdev.c            | 589
++++++++++++++++++++++++++++++++
 drivers/net/nfb/nfb_rx.c                | 127 +++++++
 drivers/net/nfb/nfb_rx.h                | 213 ++++++++++++
 drivers/net/nfb/nfb_rxmode.c            | 100 ++++++
 drivers/net/nfb/nfb_rxmode.h            |  78 +++++
 drivers/net/nfb/nfb_stats.c             |  78 +++++
 drivers/net/nfb/nfb_stats.h             |  48 +++
 drivers/net/nfb/nfb_tx.c                | 113 ++++++
 drivers/net/nfb/nfb_tx.h                | 204 +++++++++++
 drivers/net/nfb/rte_nfb_pmd_version.map |   4 +
 mk/rte.app.mk                           |   1 +
 23 files changed, 1836 insertions(+)
 create mode 100644 doc/guides/nics/features/nfb.ini
 create mode 100644 doc/guides/nics/nfb.rst
 create mode 100644 drivers/net/nfb/Makefile
 create mode 100644 drivers/net/nfb/meson.build
 create mode 100644 drivers/net/nfb/nfb.h
 create mode 100644 drivers/net/nfb/nfb_ethdev.c
 create mode 100644 drivers/net/nfb/nfb_rx.c
 create mode 100644 drivers/net/nfb/nfb_rx.h
 create mode 100644 drivers/net/nfb/nfb_rxmode.c
 create mode 100644 drivers/net/nfb/nfb_rxmode.h
 create mode 100644 drivers/net/nfb/nfb_stats.c
 create mode 100644 drivers/net/nfb/nfb_stats.h
 create mode 100644 drivers/net/nfb/nfb_tx.c
 create mode 100644 drivers/net/nfb/nfb_tx.h
 create mode 100644 drivers/net/nfb/rte_nfb_pmd_version.map

Minors:

+int
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+ uint16_t rx_queue_id,
+ uint16_t port_id,
+ struct rte_mempool *mb_pool,
+ struct ndp_rx_queue *rxq)
+{
+ if (nfb == NULL)
+ return -EINVAL;
+
+ rxq->queue = ndp_open_rx_queue(nfb, rx_queue_id);
+ if (rxq->queue == NULL)
+ return -EINVAL;
+
+ rxq->nfb = nfb;
+ rxq->rx_queue_id = rx_queue_id;
+ rxq->in_port = port_id;
+ rxq->mb_pool = mb_pool;

maybe better to have the following declaration at the beginning
of the method (though not sure it will cause a compilation error
under most compilers)

+
+ const struct rte_pktmbuf_pool_private *mbp_priv =
+ rte_mempool_get_priv(mb_pool);


static __rte_always_inline uint16_t
+nfb_eth_ndp_tx(void *queue,
+ struct rte_mbuf **bufs,
+ uint16_t nb_pkts)
+{
...
...
Should be "TX invalid arguments!\n"):

+ if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+ RTE_LOG(ERR, PMD, "RX invalid arguments!\n");
+ return 0;
+ }
+

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v3] net/nfb: new netcope driver
  2019-03-01 14:37   ` [dpdk-dev] [PATCH v3] net/nfb: new netcope driver Rastislav Cernay
                       ` (3 preceding siblings ...)
  2019-03-05 20:31     ` Rami Rosen
@ 2019-03-05 22:41     ` Luca Boccassi
  2019-03-06 14:51       ` Rastislav Černay
  4 siblings, 1 reply; 50+ messages in thread
From: Luca Boccassi @ 2019-03-05 22:41 UTC (permalink / raw)
  To: Rastislav Cernay, dev

On Fri, 2019-03-01 at 15:37 +0100, Rastislav Cernay wrote:
> From: Rastislav Cernay <cernay@netcope.com>
> 
> Added new net driver for Netcope nfb cards
> 
> Signed-off-by: Rastislav Cernay <cernay@netcope.com>
> ---
> v2: remove unnecessary cast
>     remove unnecessary zeroing
>     move declaration to not mix with code
>     restore skeleton example
> v3: add release notes
>     add doc to doc index
>     add architecture limits to doc
>     edit features list
>     add .map file
>     change link to dependecies to official vendor site
>     move declarations out of code
>     remove false comments (rte_errno is set)
>     comments to c89 style
>     remove log from main rx loop
>     remove redundant code
>  MAINTAINERS                             |   7 +
>  config/common_base                      |   4 +
>  devtools/test-build.sh                  |   1 +
>  doc/guides/nics/features/nfb.ini        |  18 +
>  doc/guides/nics/index.rst               |   1 +
>  doc/guides/nics/nfb.rst                 | 143 ++++++++
>  doc/guides/rel_notes/release_19_02.rst  |   5 +
>  drivers/net/Makefile                    |   1 +
>  drivers/net/meson.build                 |   1 +
>  drivers/net/nfb/Makefile                |  41 +++
>  drivers/net/nfb/meson.build             |   9 +
>  drivers/net/nfb/nfb.h                   |  50 +++
>  drivers/net/nfb/nfb_ethdev.c            | 589
> ++++++++++++++++++++++++++++++++
>  drivers/net/nfb/nfb_rx.c                | 127 +++++++
>  drivers/net/nfb/nfb_rx.h                | 213 ++++++++++++
>  drivers/net/nfb/nfb_rxmode.c            | 100 ++++++
>  drivers/net/nfb/nfb_rxmode.h            |  78 +++++
>  drivers/net/nfb/nfb_stats.c             |  78 +++++
>  drivers/net/nfb/nfb_stats.h             |  48 +++
>  drivers/net/nfb/nfb_tx.c                | 113 ++++++
>  drivers/net/nfb/nfb_tx.h                | 204 +++++++++++
>  drivers/net/nfb/rte_nfb_pmd_version.map |   4 +
>  mk/rte.app.mk                           |   1 +
>  23 files changed, 1836 insertions(+)
>  create mode 100644 doc/guides/nics/features/nfb.ini
>  create mode 100644 doc/guides/nics/nfb.rst
>  create mode 100644 drivers/net/nfb/Makefile
>  create mode 100644 drivers/net/nfb/meson.build
>  create mode 100644 drivers/net/nfb/nfb.h
>  create mode 100644 drivers/net/nfb/nfb_ethdev.c
>  create mode 100644 drivers/net/nfb/nfb_rx.c
>  create mode 100644 drivers/net/nfb/nfb_rx.h
>  create mode 100644 drivers/net/nfb/nfb_rxmode.c
>  create mode 100644 drivers/net/nfb/nfb_rxmode.h
>  create mode 100644 drivers/net/nfb/nfb_stats.c
>  create mode 100644 drivers/net/nfb/nfb_stats.h
>  create mode 100644 drivers/net/nfb/nfb_tx.c
>  create mode 100644 drivers/net/nfb/nfb_tx.h
>  create mode 100644 drivers/net/nfb/rte_nfb_pmd_version.map
> 

<...>

> diff --git a/drivers/net/nfb/meson.build
> b/drivers/net/nfb/meson.build
> new file mode 100644
> index 0000000..d7dccba
> --- /dev/null
> +++ b/drivers/net/nfb/meson.build
> @@ -0,0 +1,9 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2018 Cesnet
> +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> +# All rights reserved.
> +
> +dep = cc.find_library('nfb', required: true)

This unconditionally breaks the build, please look at how
drivers/net/pcap/meson.build checks for dependencies for an example (I
assume libnfd does not provide a pkg-config file?)

> +build = dep.found()
> +ext_deps += dep
> +sources = files('nfb_rx.c', 'nfb_tx.c', 'nfb_stats.c',
> 'nfb_ethdev.c', 'nfb_rxmode.c')

<...>

> diff --git a/drivers/net/nfb/rte_nfb_pmd_version.map
> b/drivers/net/nfb/rte_nfb_pmd_version.map
> new file mode 100644
> index 0000000..97fd251
> --- /dev/null
> +++ b/drivers/net/nfb/rte_nfb_pmd_version.map
> @@ -0,0 +1,4 @@
> +DPDK_19.02 {
> +
> +        local: *;
> +};

These are all new symbols so they should be marked as experimental,
please see doc/guides/contributing/versioning.rst

> diff --git a/mk/rte.app.mk b/mk/rte.app.mk
> index 8a4f0f4..32e88b5 100644
> --- a/mk/rte.app.mk
> +++ b/mk/rte.app.mk
> @@ -196,6 +196,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC)      +=
> -lrte_pmd_softnic
>  endif
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD)    += -lrte_pmd_sfc_efx
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2
> -lsze2
> +_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NFB)        += -lrte_pmd_nfb -lnfb
> -lfdt

Why is -lfdt added? I don't see any symbols from libfdt used in the
rest of the patch?

>  _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_TAP)        += -lrte_pmd_tap
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) +=
> -lrte_pmd_thunderx_nicvf
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD) +=
> -lrte_pmd_vdev_netvsc

-- 
Kind regards,
Luca Boccassi

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v3] net/nfb: new netcope driver
  2019-03-06 14:51       ` Rastislav Černay
@ 2019-03-06 13:25         ` Luca Boccassi
  0 siblings, 0 replies; 50+ messages in thread
From: Luca Boccassi @ 2019-03-06 13:25 UTC (permalink / raw)
  To: Rastislav Černay; +Cc: dev

On Wed, 2019-03-06 at 15:51 +0100, Rastislav Černay wrote:
> > 
> > --Why is -lfdt added? I don't see any symbols from libfdt used in
> > the
> > --rest of the patch?
> > 
> 
> Hi,
> libnfb is dependent on fdt and there is a special case, where some
> functions are defined in header (netcope/rxmac.h, netcope/txmac.h).
> So if one wants to use functions, from these headers fdt needs to be
> linked
> manually, not just through nfb. I also added fdt to meson.build
> so it is little clearer, however if libnfb is installed libfdt is
> always
> installed too.

This is a perfect use case for pkg-config. Please consider shipping a
libnfb.pc file in libnfb, so that you can define a Libs.private: -fdt
and users don't have to worry about these things themselves.

-- 
Kind regards,
Luca Boccassi

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v3] net/nfb: new netcope driver
  2019-03-05 22:41     ` Luca Boccassi
@ 2019-03-06 14:51       ` Rastislav Černay
  2019-03-06 13:25         ` Luca Boccassi
  0 siblings, 1 reply; 50+ messages in thread
From: Rastislav Černay @ 2019-03-06 14:51 UTC (permalink / raw)
  To: Luca Boccassi; +Cc: dev

>
>
> --Why is -lfdt added? I don't see any symbols from libfdt used in the
> --rest of the patch?
>

Hi,
libnfb is dependent on fdt and there is a special case, where some
functions are defined in header (netcope/rxmac.h, netcope/txmac.h).
So if one wants to use functions, from these headers fdt needs to be linked
manually, not just through nfb. I also added fdt to meson.build
so it is little clearer, however if libnfb is installed libfdt is always
installed too.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [dpdk-dev] [PATCH v4] net/nfb: new netcope driver
  2019-02-26 12:57 ` [dpdk-dev] [PATCH] net/nfb: new netcope driver Rastislav Cernay
                     ` (3 preceding siblings ...)
  2019-03-01 14:37   ` [dpdk-dev] [PATCH v3] net/nfb: new netcope driver Rastislav Cernay
@ 2019-03-07 13:24   ` Rastislav Cernay
  2019-03-07 13:46     ` Luca Boccassi
  2019-03-22 12:12   ` [dpdk-dev] [PATCH v5] " Rastislav Cernay
                     ` (3 subsequent siblings)
  8 siblings, 1 reply; 50+ messages in thread
From: Rastislav Cernay @ 2019-03-07 13:24 UTC (permalink / raw)
  To: dev; +Cc: bluca, ferruh.yigit, Rastislav Cernay

From: Rastislav Cernay <cernay@netcope.com>

Note: New netcope-commong pcg on which is support for pkg-config,
will be released soon and uploaded on official site.

Added new net driver for Netcope nfb cards

Signed-off-by: Rastislav Cernay <cernay@netcope.com>
---
v2: remove unnecessary cast
    remove unnecessary zeroing
    move declaration to not mix with code
    restore skeleton example
v3: add release notes
    add doc to doc index
    add architecture limits to doc
    edit features list
    add .map file
    change link to dependecies to official vendor site
    move declarations out of code
    remove false comments (rte_errno is set)
    comments to c89 style
    remove log from main rx loop
    remove redundant code
v4: add random initial MAC
    fix format
    move declarations out of code
    fix error log in TX
    q_errors is for reception errors
    pmd is experimental
    dependency check fixed
    support for pkg-config
 MAINTAINERS                             |   7 +
 config/common_base                      |   4 +
 devtools/test-build.sh                  |   1 +
 doc/guides/nics/features/nfb.ini        |  18 +
 doc/guides/nics/index.rst               |   1 +
 doc/guides/nics/nfb.rst                 | 143 +++++++
 doc/guides/rel_notes/release_19_02.rst  |   5 +
 drivers/net/Makefile                    |   1 +
 drivers/net/meson.build                 |   1 +
 drivers/net/nfb/Makefile                |  44 +++
 drivers/net/nfb/meson.build             |  15 +
 drivers/net/nfb/nfb.h                   |  50 +++
 drivers/net/nfb/nfb_ethdev.c            | 647 ++++++++++++++++++++++++++++++++
 drivers/net/nfb/nfb_rx.c                | 127 +++++++
 drivers/net/nfb/nfb_rx.h                | 231 ++++++++++++
 drivers/net/nfb/nfb_rxmode.c            | 100 +++++
 drivers/net/nfb/nfb_rxmode.h            |  96 +++++
 drivers/net/nfb/nfb_stats.c             |  77 ++++
 drivers/net/nfb/nfb_stats.h             |  56 +++
 drivers/net/nfb/nfb_tx.c                | 113 ++++++
 drivers/net/nfb/nfb_tx.h                | 222 +++++++++++
 drivers/net/nfb/rte_nfb_pmd_version.map |   4 +
 mk/rte.app.mk                           |   2 +
 23 files changed, 1965 insertions(+)
 create mode 100644 doc/guides/nics/features/nfb.ini
 create mode 100644 doc/guides/nics/nfb.rst
 create mode 100644 drivers/net/nfb/Makefile
 create mode 100644 drivers/net/nfb/meson.build
 create mode 100644 drivers/net/nfb/nfb.h
 create mode 100644 drivers/net/nfb/nfb_ethdev.c
 create mode 100644 drivers/net/nfb/nfb_rx.c
 create mode 100644 drivers/net/nfb/nfb_rx.h
 create mode 100644 drivers/net/nfb/nfb_rxmode.c
 create mode 100644 drivers/net/nfb/nfb_rxmode.h
 create mode 100644 drivers/net/nfb/nfb_stats.c
 create mode 100644 drivers/net/nfb/nfb_stats.h
 create mode 100644 drivers/net/nfb/nfb_tx.c
 create mode 100644 drivers/net/nfb/nfb_tx.h
 create mode 100644 drivers/net/nfb/rte_nfb_pmd_version.map

diff --git a/MAINTAINERS b/MAINTAINERS
index 6610440..436f3d2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -654,6 +654,13 @@ F: drivers/net/szedata2/
 F: doc/guides/nics/szedata2.rst
 F: doc/guides/nics/features/szedata2.ini
 
+Netcope nfb - EXPERIMENTAL
+M: Rastislav Cernay <cernay@netcope.com>
+M: Jan Remes <remes@netcope.com>
+F: drivers/net/nfb/
+F: doc/guides/nics/nfb.rst
+F: doc/guides/nics/features/nfb.ini
+
 Netronome nfp
 M: Alejandro Lucero <alejandro.lucero@netronome.com>
 F: drivers/net/nfp/
diff --git a/config/common_base b/config/common_base
index 7c6da51..1ab0a6b 100644
--- a/config/common_base
+++ b/config/common_base
@@ -360,6 +360,10 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
 # Compile software PMD backed by SZEDATA2 device
 #
 CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
+#
+# Compile software PMD backed by NFB device
+#
+CONFIG_RTE_LIBRTE_PMD_NFB=n
 
 #
 # Compile burst-oriented Cavium Thunderx NICVF PMD driver
diff --git a/devtools/test-build.sh b/devtools/test-build.sh
index 42f4ad0..ab57ab8 100755
--- a/devtools/test-build.sh
+++ b/devtools/test-build.sh
@@ -18,6 +18,7 @@ default_path=$PATH
 # - DPDK_DEP_SSL (y/[n])
 # - DPDK_DEP_IPSEC_MB (y/[n])
 # - DPDK_DEP_SZE (y/[n])
+# - DPDK_DEP_NFB (y/[n])
 # - DPDK_DEP_ZLIB (y/[n])
 # - DPDK_MAKE_JOBS (int)
 # - DPDK_NOTIFY (notify-send)
diff --git a/doc/guides/nics/features/nfb.ini b/doc/guides/nics/features/nfb.ini
new file mode 100644
index 0000000..e1c5266
--- /dev/null
+++ b/doc/guides/nics/features/nfb.ini
@@ -0,0 +1,18 @@
+;
+; Supported features of the 'nfb' network poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Speed capabilities   = P
+Link status          = Y
+Queue start/stop     = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Basic stats          = Y
+Extended stats       = Y
+Stats per queue      = Y
+Other kdrv           = Y
+x86-64               = Y
+Usage doc            = Y
+Scattered Tx         = Y
diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index 5c80e3b..079972e 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -39,6 +39,7 @@ Network Interface Controller Drivers
     mvneta
     mvpp2
     netvsc
+    nfb
     nfp
     octeontx
     qede
diff --git a/doc/guides/nics/nfb.rst b/doc/guides/nics/nfb.rst
new file mode 100644
index 0000000..8c0be40
--- /dev/null
+++ b/doc/guides/nics/nfb.rst
@@ -0,0 +1,143 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright 2015 - 2016 CESNET
+
+NFB poll mode driver library
+=================================
+
+The NFB poll mode driver library implements support for the Netcope
+FPGA Boards (**NFB-***), FPGA-based programmable NICs.
+The NFB PMD uses interface provided by the libnfb library to communicate
+with the NFB cards over the nfb layer.
+
+More information about the
+`NFB cards <http://www.netcope.com/en/products/fpga-boards>`_
+and used technology
+(`Netcope Development Kit <http://www.netcope.com/en/products/fpga-development-kit>`_)
+can be found on the `Netcope Technologies website <http://www.netcope.com/>`_.
+
+.. note::
+
+   This driver has external dependencies.
+   Therefore it is disabled in default configuration files.
+   It can be enabled by setting ``CONFIG_RTE_LIBRTE_PMD_NFB=y``
+   and recompiling.
+
+.. note::
+
+   Currently the driver is supported only on x86_64 architectures.
+   Only x86_64 versions of the external libraries are provided.
+
+Prerequisites
+-------------
+
+This PMD requires kernel modules which are responsible for initialization and
+allocation of resources needed for nfb layer function.
+Communication between PMD and kernel modules is mediated by libnfb library.
+These kernel modules and library are not part of DPDK and must be installed
+separately:
+
+*  **libnfb library**
+
+   The library provides API for initialization of nfb transfers, receiving and
+   transmitting data segments.
+
+*  **Kernel modules**
+
+   * nfb
+
+   Kernel modules manage initialization of hardware, allocation and
+   sharing of resources for user space applications.
+
+Dependencies can be found here:
+`Netcope common <https://www.netcope.com/en/company/community-support/dpdk-libsze2#NFB>`_.
+
+Versions of the packages
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The minimum version of the provided packages:
+
+* for DPDK from 19.02
+
+Configuration
+-------------
+
+These configuration options can be modified before compilation in the
+``.config`` file:
+
+*  ``CONFIG_RTE_LIBRTE_PMD_NFB`` default value: **n**
+
+   Value **y** enables compilation of nfb PMD.
+
+Using the NFB PMD
+----------------------
+
+Kernel modules have to be loaded before running the DPDK application.
+
+NFB card architecture
+---------------------
+
+The NFB cards are multi-port multi-queue cards, where (generally) data from any
+Ethernet port may be sent to any queue.
+They are represented in DPDK as a single port.
+
+NFB-200G2QL card employs an addon cable which allows to connect it to two
+physical PCI-E slots at the same time (see the diagram below).
+This is done to allow 200 Gbps of traffic to be transferred through the PCI-E
+bus (note that a single PCI-E 3.0 x16 slot provides only 125 Gbps theoretical
+throughput).
+
+Although each slot may be connected to a different CPU and therefore to a different
+NUMA node, the card is represented as a single port in DPDK. To work with data
+from the individual queues on the right NUMA node, connection of NUMA nodes on
+first and last queue (each NUMA node has half of the queues) need to be checked.
+
+.. figure:: img/szedata2_nfb200g_architecture.svg
+    :align: center
+
+    NFB-200G2QL high-level diagram
+
+Limitations
+-----------
+
+Driver is usable only on Linux architecture.
+
+Since a card is always represented as a single port, but can be connected to two
+NUMA nodes, there is need for manual check where master/slave is connected.
+
+Example of usage
+----------------
+
+Read packets from 0. and 1. receive queue and write them to 0. and 1.
+transmit queue:
+
+.. code-block:: console
+
+   $RTE_TARGET/app/testpmd -l 0-3 -n 2 \
+   -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2 -i -a
+
+Example output:
+
+.. code-block:: console
+
+   [...]
+   EAL: PCI device 0000:06:00.0 on NUMA socket -1
+   EAL:   probe driver: 1b26:c1c1 net_nfb
+   PMD: Initializing NFB device (0000:06:00.0)
+   PMD: Available DMA queues RX: 8 TX: 8
+   PMD: NFB device (0000:06:00.0) successfully initialized
+   Interactive-mode selected
+   Auto-start selected
+   Configuring Port 0 (socket 0)
+   Port 0: 00:11:17:00:00:00
+   Checking link statuses...
+   Port 0 Link Up - speed 10000 Mbps - full-duplex
+   Done
+   Start automatic packet forwarding
+     io packet forwarding - CRC stripping disabled - packets/burst=32
+     nb forwarding cores=2 - nb forwarding ports=1
+     RX queues=2 - RX desc=128 - RX free threshold=0
+     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX queues=2 - TX desc=512 - TX free threshold=0
+     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX RS bit threshold=0 - TXQ flags=0x0
+   testpmd>
diff --git a/doc/guides/rel_notes/release_19_02.rst b/doc/guides/rel_notes/release_19_02.rst
index 3372c4d..9955b6b 100644
--- a/doc/guides/rel_notes/release_19_02.rst
+++ b/doc/guides/rel_notes/release_19_02.rst
@@ -54,6 +54,11 @@ New Features
      Also, make sure to start the actual text at the margin.
      =========================================================
 
+* **Added an experimental net PMD NFB.**
+
+  Added the new ``nfb`` net driver for Netcope NFB cards. See
+  the :doc:`../nics/nfb` NIC guide for more details on this new driver.
+
 * **Added support to free hugepages exactly as originally allocated.**
 
   Some applications using memory event callbacks (especially for managing
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 670d7f7..013c551 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -38,6 +38,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5
 DIRS-$(CONFIG_RTE_LIBRTE_MVNETA_PMD) += mvneta
 DIRS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mvpp2
 DIRS-$(CONFIG_RTE_LIBRTE_NETVSC_PMD) += netvsc
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb
 DIRS-$(CONFIG_RTE_LIBRTE_NFP_PMD) += nfp
 DIRS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += null
diff --git a/drivers/net/meson.build b/drivers/net/meson.build
index 45da3bb..6733a19 100644
--- a/drivers/net/meson.build
+++ b/drivers/net/meson.build
@@ -27,6 +27,7 @@ drivers = ['af_packet',
 	'mvneta',
 	'mvpp2',
 	'netvsc',
+	'nfb',
 	'nfp',
 	'null', 'octeontx', 'pcap', 'qede', 'ring',
 	'sfc',
diff --git a/drivers/net/nfb/Makefile b/drivers/net/nfb/Makefile
new file mode 100644
index 0000000..968184e
--- /dev/null
+++ b/drivers/net/nfb/Makefile
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Cesnet
+# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_nfb.a
+
+INCLUDES :=-I$(SRCDIR)
+
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --cflags libnfb)
+LDLIBS += -lnfb
+LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
+LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
+LDLIBS += -lrte_bus_pci
+LDLIBS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --libs libnfb)
+
+EXPORT_MAP := rte_pmd_nfb_version.map
+
+LIBABIVER := 1
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_rx.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_tx.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_stats.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_rxmode.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/nfb/meson.build b/drivers/net/nfb/meson.build
new file mode 100644
index 0000000..16df146
--- /dev/null
+++ b/drivers/net/nfb/meson.build
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Cesnet
+# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+dep = cc.find_library('nfb', required: false)
+
+build = dep.found() and cc.has_header('nfb/nfb.h', dependencies: dep)
+
+allow_experimental_apis = true
+
+ext_deps += dep
+
+sources = files('nfb_rx.c', 'nfb_tx.c', 'nfb_stats.c', 'nfb_ethdev.c', 'nfb_rxmode.c')
+pkgconfig_extra_libs += '-lnfb'
diff --git a/drivers/net/nfb/nfb.h b/drivers/net/nfb/nfb.h
new file mode 100644
index 0000000..42671a1
--- /dev/null
+++ b/drivers/net/nfb/nfb.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_H_
+#define _NFB_H_
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+
+/* PCI Vendor ID */
+#define PCI_VENDOR_ID_NETCOPE 0x1b26
+
+/* PCI Device IDs */
+#define PCI_DEVICE_ID_NFB_40G2  0xcb80
+#define PCI_DEVICE_ID_NFB_100G2 0xc2c1
+#define PCI_DEVICE_ID_NFB_200G2QL 0xc250
+
+/* Max index of ndp rx/tx queues */
+#define RTE_ETH_NDP_MAX_RX_QUEUES 32
+#define RTE_ETH_NDP_MAX_TX_QUEUES 32
+
+/* Max index of rx/tx dmas */
+#define RTE_MAX_NC_RXMAC 256
+#define RTE_MAX_NC_TXMAC 256
+
+#define RTE_NFB_DRIVER_NAME net_nfb
+
+struct pmd_internals {
+	uint16_t         max_rxmac;
+	uint16_t         max_txmac;
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC];
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC];
+
+	char             nfb_dev[PATH_MAX];
+	struct nfb_device *nfb;
+	/* Place to remember if filter was promiscuous or filtering by table,
+	 * when disabling allmulticast
+	 */
+	enum nc_rxmac_mac_filter rx_filter_original;
+};
+
+#endif /* _NFB_H_ */
diff --git a/drivers/net/nfb/nfb_ethdev.c b/drivers/net/nfb/nfb_ethdev.c
new file mode 100644
index 0000000..a5a6bdc
--- /dev/null
+++ b/drivers/net/nfb/nfb_ethdev.c
@@ -0,0 +1,647 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_kvargs.h>
+#include <rte_dev.h>
+#include <rte_common.h>
+
+#include "nfb_stats.h"
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+/**
+ * Default MAC addr
+ */
+static struct ether_addr eth_addr = {
+	.addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Open all RX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] rxmac
+ *   Pointer to output array of nc_rxmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of rxmac
+ */
+static void __rte_experimental
+nfb_nc_rxmac_init(struct nfb_device *nfb,
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t *max_rxmac)
+{
+	*max_rxmac = 0;
+	while ((rxmac[*max_rxmac] = nc_rxmac_open_index(nfb, *max_rxmac)))
+		++(*max_rxmac);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Open all TX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] txmac
+ *   Pointer to output array of nc_txmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of txmac
+ */
+static void __rte_experimental
+nfb_nc_txmac_init(struct nfb_device *nfb,
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t *max_txmac)
+{
+	*max_txmac = 0;
+	while ((txmac[*max_txmac] = nc_txmac_open_index(nfb, *max_txmac)))
+		++(*max_txmac);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Close all RX DMA queues
+ *
+ * @param rxmac
+ *   Pointer to array of nc_rxmac
+ * @param max_rxmac
+ *   Maximum index of rxmac
+ */
+static void __rte_experimental
+nfb_nc_rxmac_deinit(struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t max_rxmac)
+{
+	for (; max_rxmac > 0; --max_rxmac) {
+		nc_rxmac_close(rxmac[max_rxmac]);
+		rxmac[max_rxmac] = NULL;
+	}
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Close all TX DMA queues
+ *
+ * @param txmac
+ *   Pointer to array of nc_txmac
+ * @param max_txmac
+ *   Maximum index of txmac
+ */
+static void __rte_experimental
+nfb_nc_txmac_deinit(struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t max_txmac)
+{
+	for (; max_txmac > 0; --max_txmac) {
+		nc_txmac_close(txmac[max_txmac]);
+		txmac[max_txmac] = NULL;
+	}
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to start the device.
+ *
+ * Start device by starting all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_dev_start(struct rte_eth_dev *dev)
+{
+	int ret;
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_rx; i++) {
+		ret = nfb_eth_rx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_rx;
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		ret = nfb_eth_tx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_tx;
+	}
+
+	return 0;
+
+err_tx:
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+err_rx:
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+	return ret;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to stop the device.
+ *
+ * Stop device by stopping all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void __rte_experimental
+nfb_eth_dev_stop(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback for Ethernet device configuration.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to get information about the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] info
+ *   Info structure output buffer.
+ */
+static void __rte_experimental
+nfb_eth_dev_info(struct rte_eth_dev *dev,
+	struct rte_eth_dev_info *dev_info)
+{
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = dev->data->nb_rx_queues;
+	dev_info->max_tx_queues = dev->data->nb_tx_queues;
+	dev_info->speed_capa = ETH_LINK_SPEED_100G;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to close the device.
+ *
+ * Destroy all queues and objects, free memory.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void __rte_experimental
+nfb_eth_dev_close(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	nfb_eth_dev_stop(dev);
+
+	for (i = 0; i < nb_rx; i++) {
+		nfb_eth_rx_queue_release(dev->data->rx_queues[i]);
+		dev->data->rx_queues[i] = NULL;
+	}
+	dev->data->nb_rx_queues = 0;
+	for (i = 0; i < nb_tx; i++) {
+		nfb_eth_tx_queue_release(dev->data->tx_queues[i]);
+		dev->data->tx_queues[i] = NULL;
+	}
+	dev->data->nb_tx_queues = 0;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to retrieve physical link information.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] link
+ *   Storage for current link status.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_link_update(struct rte_eth_dev *dev,
+	int wait_to_complete __rte_unused)
+{
+	uint16_t i;
+	struct nc_rxmac_status status;
+	struct rte_eth_link link;
+	memset(&link, 0, sizeof(link));
+
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	status.speed = MAC_SPEED_UNKNOWN;
+
+	link.link_speed = ETH_SPEED_NUM_NONE;
+	link.link_status = ETH_LINK_DOWN;
+	link.link_duplex = ETH_LINK_FULL_DUPLEX;
+	link.link_autoneg = ETH_LINK_SPEED_FIXED;
+
+	if (internals->rxmac[0] != NULL) {
+		nc_rxmac_read_status(internals->rxmac[0], &status);
+
+		switch (status.speed) {
+		case MAC_SPEED_10G:
+			link.link_speed = ETH_SPEED_NUM_10G;
+			break;
+		case MAC_SPEED_40G:
+			link.link_speed = ETH_SPEED_NUM_40G;
+			break;
+		case MAC_SPEED_100G:
+			link.link_speed = ETH_SPEED_NUM_100G;
+			break;
+		default:
+			link.link_speed = ETH_SPEED_NUM_NONE;
+			break;
+		}
+	}
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_read_status(internals->rxmac[i], &status);
+
+		if (status.enabled && status.link_up) {
+			link.link_status = ETH_LINK_UP;
+			break;
+		}
+	}
+
+	rte_eth_linkstatus_set(dev, &link);
+
+	return 0;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to bring the link UP.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_dev_set_link_up(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_enable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_enable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to bring the link DOWN.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_dev_set_link_down(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_disable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_disable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to set primary MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_mac_addr_set(struct rte_eth_dev *dev,
+	struct ether_addr *mac_addr)
+{
+	unsigned int i;
+	unsigned long long mac = 0;
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+
+	if (!is_valid_assigned_ether_addr(mac_addr))
+		return -EINVAL;
+
+	for (i = 0; i < 6; i++) {
+		mac <<= 8;
+		mac |= mac_addr->addr_bytes[i] & 0xFF;
+	}
+
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_set_mac(internals->rxmac[i], 0, mac, 1);
+
+	ether_addr_copy(mac_addr, data->mac_addrs);
+	return 0;
+}
+
+static const struct eth_dev_ops ops = {
+	.dev_start = nfb_eth_dev_start,
+	.dev_stop = nfb_eth_dev_stop,
+	.dev_set_link_up = nfb_eth_dev_set_link_up,
+	.dev_set_link_down = nfb_eth_dev_set_link_down,
+	.dev_close = nfb_eth_dev_close,
+	.dev_configure = nfb_eth_dev_configure,
+	.dev_infos_get = nfb_eth_dev_info,
+	.promiscuous_enable = nfb_eth_promiscuous_enable,
+	.promiscuous_disable = nfb_eth_promiscuous_disable,
+	.allmulticast_enable = nfb_eth_allmulticast_enable,
+	.allmulticast_disable = nfb_eth_allmulticast_disable,
+	.rx_queue_start = nfb_eth_rx_queue_start,
+	.rx_queue_stop = nfb_eth_rx_queue_stop,
+	.tx_queue_start = nfb_eth_tx_queue_start,
+	.tx_queue_stop = nfb_eth_tx_queue_stop,
+	.rx_queue_setup = nfb_eth_rx_queue_setup,
+	.tx_queue_setup = nfb_eth_tx_queue_setup,
+	.rx_queue_release = nfb_eth_rx_queue_release,
+	.tx_queue_release = nfb_eth_tx_queue_release,
+	.link_update = nfb_eth_link_update,
+	.stats_get = nfb_eth_stats_get,
+	.stats_reset = nfb_eth_stats_reset,
+	.mac_addr_set = nfb_eth_mac_addr_set,
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to initialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_dev_init(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+	struct ether_addr eth_addr_init;
+
+	RTE_LOG(INFO, PMD, "Initializing NFB device (" PCI_PRI_FMT ")\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	snprintf(internals->nfb_dev, PATH_MAX,
+		"/dev/nfb/by-pci-slot/" PCI_PRI_FMT,
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	/*
+	 * Get number of available DMA RX and TX queues, which is maximum
+	 * number of queues that can be created and store it in private device
+	 * data structure.
+	 */
+	internals->nfb = nfb_open(internals->nfb_dev);
+	if (internals->nfb == NULL) {
+		RTE_LOG(ERR, PMD, "nfb_open(): failed to open %s",
+			internals->nfb_dev);
+		return -EINVAL;
+	}
+	data->nb_rx_queues = ndp_get_rx_queue_available_count(internals->nfb);
+	data->nb_tx_queues = ndp_get_tx_queue_available_count(internals->nfb);
+
+	RTE_LOG(INFO, PMD, "Available NDP queues RX: %u TX: %u\n",
+		data->nb_rx_queues, data->nb_tx_queues);
+
+	nfb_nc_rxmac_init(internals->nfb,
+		internals->rxmac,
+		&internals->max_rxmac);
+	nfb_nc_txmac_init(internals->nfb,
+		internals->txmac,
+		&internals->max_txmac);
+
+	/* Set rx, tx burst functions */
+	dev->rx_pkt_burst = nfb_eth_ndp_rx;
+	dev->tx_pkt_burst = nfb_eth_ndp_tx;
+
+	/* Set function callbacks for Ethernet API */
+	dev->dev_ops = &ops;
+
+	/* Get link state */
+	nfb_eth_link_update(dev, 0);
+
+	/* Allocate space for one mac address */
+	data->mac_addrs = rte_zmalloc(data->name, sizeof(struct ether_addr),
+		RTE_CACHE_LINE_SIZE);
+	if (data->mac_addrs == NULL) {
+		RTE_LOG(ERR, PMD, "Could not alloc space for MAC address!\n");
+		nfb_close(internals->nfb);
+		return -EINVAL;
+	}
+
+	eth_random_addr(eth_addr_init.addr_bytes);
+	eth_addr_init.addr_bytes[0] = eth_addr.addr_bytes[0];
+	eth_addr_init.addr_bytes[1] = eth_addr.addr_bytes[1];
+	eth_addr_init.addr_bytes[2] = eth_addr.addr_bytes[2];
+
+	nfb_eth_mac_addr_set(dev, &eth_addr_init);
+
+	data->promiscuous = nfb_eth_promiscuous_get(dev);
+	data->all_multicast = nfb_eth_allmulticast_get(dev);
+	internals->rx_filter_original = data->promiscuous;
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully initialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to uninitialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_dev_uninit(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+
+	dev->data->mac_addrs = NULL;
+
+	nfb_nc_rxmac_deinit(internals->rxmac, internals->max_rxmac);
+	nfb_nc_txmac_deinit(internals->txmac, internals->max_txmac);
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully uninitialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+static const struct rte_pci_id nfb_pci_id_table[] = {
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_40G2) },
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_100G2) },
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_200G2QL) },
+	{ .vendor_id = 0, }
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to register a PCI device.
+ *
+ * This function spawns Ethernet devices out of a given PCI device.
+ *
+ * @param[in] pci_drv
+ *   PCI driver structure (nfb_driver).
+ * @param[in] pci_dev
+ *   PCI device information.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+		struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_probe(pci_dev,
+		sizeof(struct pmd_internals), nfb_eth_dev_init);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to remove a PCI device.
+ *
+ * This function removes all Ethernet devices belong to a given PCI device.
+ *
+ * @param[in] pci_dev
+ *   Pointer to the PCI device.
+ *
+ * @return
+ *   0 on success, the function cannot fail.
+ */
+static int __rte_experimental
+nfb_eth_pci_remove(struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_remove(pci_dev, nfb_eth_dev_uninit);
+}
+
+static struct rte_pci_driver nfb_eth_driver = {
+	.id_table = nfb_pci_id_table,
+	.probe = nfb_eth_pci_probe,
+	.remove = nfb_eth_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(RTE_NFB_DRIVER_NAME, nfb_eth_driver);
+RTE_PMD_REGISTER_PCI_TABLE(RTE_NFB_DRIVER_NAME, nfb_pci_id_table);
+RTE_PMD_REGISTER_KMOD_DEP(RTE_NFB_DRIVER_NAME, "* nfb");
diff --git a/drivers/net/nfb/nfb_rx.c b/drivers/net/nfb/nfb_rx.c
new file mode 100644
index 0000000..7026c1b
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.c
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_rx.h"
+#include "nfb.h"
+
+int __rte_experimental
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+	int ret;
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_start(rxq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+int __rte_experimental
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+	int ret;
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_stop(rxq->queue);
+	if (ret != 0)
+		return -EINVAL;
+
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int __rte_experimental
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+		uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	struct ndp_rx_queue *rxq;
+	int ret;
+
+	rxq = rte_zmalloc_socket("ndp rx queue",
+			sizeof(struct ndp_rx_queue),
+			RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (rxq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for rx queue id "
+				"%" PRIu16 "!\n", rx_queue_id);
+		return -ENOMEM;
+	}
+
+	ret = nfb_eth_rx_queue_init(internals->nfb,
+		rx_queue_id,
+		dev->data->port_id,
+		mb_pool,
+		rxq);
+
+	if (ret == 0)
+		dev->data->rx_queues[rx_queue_id] = rxq;
+	else
+		rte_free(rxq);
+
+	return ret;
+}
+
+int __rte_experimental
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+		uint16_t rx_queue_id,
+		uint16_t port_id,
+		struct rte_mempool *mb_pool,
+		struct ndp_rx_queue *rxq)
+{
+	const struct rte_pktmbuf_pool_private *mbp_priv =
+		rte_mempool_get_priv(mb_pool);
+
+	if (nfb == NULL)
+		return -EINVAL;
+
+	rxq->queue = ndp_open_rx_queue(nfb, rx_queue_id);
+	if (rxq->queue == NULL)
+		return -EINVAL;
+
+	rxq->nfb = nfb;
+	rxq->rx_queue_id = rx_queue_id;
+	rxq->in_port = port_id;
+	rxq->mb_pool = mb_pool;
+	rxq->buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size -
+		RTE_PKTMBUF_HEADROOM);
+
+	rxq->rx_pkts = 0;
+	rxq->rx_bytes = 0;
+	rxq->err_pkts = 0;
+
+	return 0;
+}
+
+void __rte_experimental
+nfb_eth_rx_queue_release(void *q)
+{
+	struct ndp_rx_queue *rxq = (struct ndp_rx_queue *)q;
+	if (rxq->queue != NULL) {
+		ndp_close_rx_queue(rxq->queue);
+		rte_free(rxq);
+		rxq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_rx.h b/drivers/net/nfb/nfb_rx.h
new file mode 100644
index 0000000..772ccfc
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.h
@@ -0,0 +1,231 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_RX_H_
+#define _NFB_RX_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+struct ndp_rx_queue {
+	struct nfb_device *nfb;	     /* nfb dev structure */
+	struct ndp_queue *queue;     /* rx queue */
+	uint16_t rx_queue_id;	     /* index */
+	uint8_t in_port;	     /* port */
+
+	struct rte_mempool *mb_pool; /* memory pool to allocate packets */
+	uint16_t buf_size;           /* mbuf size */
+
+	volatile uint64_t rx_pkts;   /* packets read */
+	volatile uint64_t rx_bytes;  /* bytes read */
+	volatile uint64_t err_pkts;  /* erroneous packets */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Initialize ndp_rx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param rx_queue_id
+ *   RX queue index.
+ * @param port_id
+ *   Device [external] port identifier.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ * @param[out] rxq
+ *   Pointer to ndp_rx_queue output structure
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+	uint16_t rx_queue_id,
+	uint16_t port_id,
+	struct rte_mempool *mb_pool,
+	struct ndp_rx_queue *rxq);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to setup a RX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t rx_queue_id,
+	uint16_t nb_rx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_rxconf *rx_conf __rte_unused,
+	struct rte_mempool *mb_pool);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void __rte_experimental
+nfb_eth_rx_queue_release(void *q);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Start traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Stop traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ */
+int __rte_experimental
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback for RX.
+ *
+ * @param dpdk_rxq
+ *   Generic pointer to RX queue structure.
+ * @param[out] bufs
+ *   Array to store received packets.
+ * @param nb_pkts
+ *   Maximum number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully received (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t __rte_experimental
+nfb_eth_ndp_rx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	struct ndp_rx_queue *ndp = queue;
+	uint16_t packet_size;
+	uint64_t num_bytes = 0;
+	uint16_t num_rx;
+	unsigned int i;
+
+	const uint16_t buf_size = ndp->buf_size;
+
+	struct rte_mbuf *mbuf;
+	struct ndp_packet packets[nb_pkts];
+
+	struct rte_mbuf *mbufs[nb_pkts];
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "RX invalid arguments!\n");
+		return 0;
+	}
+
+	/* returns either all or nothing */
+	i = rte_pktmbuf_alloc_bulk(ndp->mb_pool, mbufs, nb_pkts);
+	if (unlikely(i != 0))
+		return 0;
+
+	num_rx = ndp_rx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_rx != nb_pkts)) {
+		for (i = num_rx; i < nb_pkts; i++)
+			rte_pktmbuf_free(mbufs[i]);
+	}
+
+	nb_pkts = num_rx;
+
+	num_rx = 0;
+	/*
+	 * Reads the given number of packets from NDP queue given
+	 * by queue and copies the packet data into a newly allocated mbuf
+	 * to return.
+	 */
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = mbufs[i];
+
+		/* get the space available for data in the mbuf */
+		packet_size = packets[i].data_length;
+
+		if (likely(packet_size <= buf_size)) {
+			/* NDP packet will fit in one mbuf, go ahead and copy */
+			rte_memcpy(rte_pktmbuf_mtod(mbuf, void *),
+				packets[i].data, packet_size);
+
+			mbuf->data_len = (uint16_t)packet_size;
+
+			mbuf->pkt_len = packet_size;
+			mbuf->port = ndp->in_port;
+			bufs[num_rx++] = mbuf;
+			num_bytes += packet_size;
+		} else {
+			/*
+			 * NDP packet will not fit in one mbuf,
+			 * scattered mode is not enabled, drop packet
+			 */
+			rte_pktmbuf_free(mbuf);
+		}
+	}
+
+	ndp_rx_burst_put(ndp->queue);
+
+	ndp->rx_pkts += num_rx;
+	ndp->rx_bytes += num_bytes;
+	return num_rx;
+}
+
+#endif /* _NFB_RX_H_ */
diff --git a/drivers/net/nfb/nfb_rxmode.c b/drivers/net/nfb/nfb_rxmode.c
new file mode 100644
index 0000000..a6c9cb4
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.c
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+void __rte_experimental
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+	uint16_t i;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_PROMISCUOUS);
+	}
+}
+
+void __rte_experimental
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+	uint16_t i;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_TABLE;
+
+	/* if promisc is not enabled, do nothing */
+	if (!nfb_eth_promiscuous_get(dev))
+		return;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE);
+	}
+}
+
+int __rte_experimental
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_PROMISCUOUS);
+}
+
+void __rte_experimental
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+	}
+}
+
+void __rte_experimental
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+
+	/* if multicast is not enabled do nothing */
+	if (!nfb_eth_allmulticast_get(dev))
+		return;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			internals->rx_filter_original);
+	}
+}
+
+int __rte_experimental
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+}
diff --git a/drivers/net/nfb/nfb_rxmode.h b/drivers/net/nfb/nfb_rxmode.h
new file mode 100644
index 0000000..051130f
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.h
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_RXMODE_H_
+#define _NFB_RXMODE_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_ethdev.h>
+#include <rte_dev.h>
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Getter for promiscuous mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int __rte_experimental
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to enable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void __rte_experimental
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to disable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void __rte_experimental
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Getter for allmulticast mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int __rte_experimental
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to enable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void __rte_experimental
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to disable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void __rte_experimental
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev);
+
+#endif /* _NFB_RXMODE_H_ */
diff --git a/drivers/net/nfb/nfb_stats.c b/drivers/net/nfb/nfb_stats.c
new file mode 100644
index 0000000..a4f22c8
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.c
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_stats.h"
+#include "nfb.h"
+
+int __rte_experimental
+nfb_eth_stats_get(struct rte_eth_dev *dev,
+	struct rte_eth_stats *stats)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+	uint64_t rx_total = 0;
+	uint64_t tx_total = 0;
+	uint64_t tx_err_total = 0;
+	uint64_t rx_total_bytes = 0;
+	uint64_t tx_total_bytes = 0;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_ipackets[i] = rx_queue[i].rx_pkts;
+			stats->q_ibytes[i] = rx_queue[i].rx_bytes;
+		}
+		rx_total += stats->q_ipackets[i];
+		rx_total_bytes += stats->q_ibytes[i];
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_opackets[i] = tx_queue[i].tx_pkts;
+			stats->q_obytes[i] = tx_queue[i].tx_bytes;
+		}
+		tx_total += stats->q_opackets[i];
+		tx_total_bytes += stats->q_obytes[i];
+		tx_err_total += tx_queue[i].err_pkts;
+	}
+
+	stats->ipackets = rx_total;
+	stats->opackets = tx_total;
+	stats->ibytes = rx_total_bytes;
+	stats->obytes = tx_total_bytes;
+	stats->oerrors = tx_err_total;
+	return 0;
+}
+
+void __rte_experimental
+nfb_eth_stats_reset(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		rx_queue[i].rx_pkts = 0;
+		rx_queue[i].rx_bytes = 0;
+		rx_queue[i].err_pkts = 0;
+	}
+	for (i = 0; i < nb_tx; i++) {
+		tx_queue[i].tx_pkts = 0;
+		tx_queue[i].tx_bytes = 0;
+		tx_queue[i].err_pkts = 0;
+	}
+}
diff --git a/drivers/net/nfb/nfb_stats.h b/drivers/net/nfb/nfb_stats.h
new file mode 100644
index 0000000..85439c6
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_STATS_H_
+#define _NFB_STATS_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to get device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] stats
+ *   Stats structure output buffer.
+ *
+ * @return
+ *   0 on success and stats is filled, negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to clear device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void __rte_experimental
+nfb_eth_stats_reset(struct rte_eth_dev *dev);
+
+#endif /* _NFB_STATS_H_ */
diff --git a/drivers/net/nfb/nfb_tx.c b/drivers/net/nfb/nfb_tx.c
new file mode 100644
index 0000000..8ef756b
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.c
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_tx.h"
+#include "nfb.h"
+
+int __rte_experimental
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+	int ret;
+
+	if (txq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_start(txq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+int __rte_experimental
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+	int ret;
+
+	if (txq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "TX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_stop(txq->queue);
+	if (ret != 0)
+		return -EINVAL;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int __rte_experimental
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	int ret;
+	struct ndp_tx_queue *txq;
+
+	txq = rte_zmalloc_socket("ndp tx queue",
+		sizeof(struct ndp_tx_queue),
+		RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (txq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for tx queue id "
+			"%" PRIu16 "!\n", tx_queue_id);
+		return -ENOMEM;
+	}
+
+	ret = nfb_eth_tx_queue_init(internals->nfb,
+		tx_queue_id,
+		txq);
+
+	if (ret == 0)
+		dev->data->tx_queues[tx_queue_id] = txq;
+	else
+		rte_free(txq);
+
+	return ret;
+}
+
+int __rte_experimental
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq)
+{
+	if (nfb == NULL)
+		return -EINVAL;
+
+	txq->queue = ndp_open_tx_queue(nfb, tx_queue_id);
+	if (txq->queue == NULL)
+		return -EINVAL;
+
+	txq->nfb = nfb;
+	txq->tx_queue_id = tx_queue_id;
+
+	txq->tx_pkts = 0;
+	txq->tx_bytes = 0;
+	txq->err_pkts = 0;
+
+	return 0;
+}
+
+void __rte_experimental
+nfb_eth_tx_queue_release(void *q)
+{
+	struct ndp_tx_queue *txq = (struct ndp_tx_queue *)q;
+	if (txq->queue != NULL) {
+		ndp_close_tx_queue(txq->queue);
+		rte_free(txq);
+		txq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_tx.h b/drivers/net/nfb/nfb_tx.h
new file mode 100644
index 0000000..32a1bdb
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.h
@@ -0,0 +1,222 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_TX_H_
+#define _NFB_TX_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+struct ndp_tx_queue {
+	struct nfb_device *nfb;     /* nfb dev structure */
+	struct ndp_queue *queue;    /* tx queue */
+	uint16_t          tx_queue_id;       /* index */
+	volatile uint64_t tx_pkts;  /* packets transmitted */
+	volatile uint64_t tx_bytes; /* bytes transmitted */
+	volatile uint64_t err_pkts; /* erroneous packets */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to setup a TX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mp
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Initialize ndp_tx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param tx_queue_id
+ *   TX queue index.
+ * @param[out] txq
+ *   Pointer to ndp_tx_queue output structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void __rte_experimental
+nfb_eth_tx_queue_release(void *q);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Start traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Stop traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback for TX.
+ *
+ * @param dpdk_txq
+ *   Generic pointer to TX queue structure.
+ * @param bufs
+ *   Packets to transmit.
+ * @param nb_pkts
+ *   Number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully transmitted (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t __rte_experimental
+nfb_eth_ndp_tx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	int i;
+	struct rte_mbuf *mbuf;
+	struct ndp_tx_queue *ndp = queue;
+	uint16_t num_tx = 0;
+	uint64_t num_bytes = 0;
+
+	void *dst;
+	uint32_t pkt_len;
+	uint8_t mbuf_segs;
+
+	struct ndp_packet packets[nb_pkts];
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "TX invalid arguments!\n");
+		return 0;
+	}
+
+	for (i = 0; i < nb_pkts; i++) {
+		packets[i].data_length = bufs[i]->pkt_len;
+		packets[i].header_length = 0;
+	}
+
+	num_tx = ndp_tx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_tx != nb_pkts))
+		return 0;
+
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = bufs[i];
+
+		pkt_len = mbuf->pkt_len;
+		mbuf_segs = mbuf->nb_segs;
+
+		num_bytes += pkt_len;
+		if (mbuf_segs == 1) {
+			/*
+			 * non-scattered packet,
+			 * transmit from one mbuf
+			 */
+			rte_memcpy(packets[i].data,
+				rte_pktmbuf_mtod(mbuf, const void *),
+				pkt_len);
+		} else {
+			/* scattered packet, transmit from more mbufs */
+			struct rte_mbuf *m = mbuf;
+			while (m) {
+				dst = packets[i].data;
+
+				rte_memcpy(dst,
+					rte_pktmbuf_mtod(m,
+					const void *),
+					m->data_len);
+				dst = ((uint8_t *)(dst)) +
+					m->data_len;
+				m = m->next;
+			}
+		}
+
+		rte_pktmbuf_free(mbuf);
+	}
+
+	ndp_tx_burst_flush(ndp->queue);
+
+	ndp->tx_pkts += num_tx;
+	ndp->err_pkts += nb_pkts - num_tx;
+	ndp->tx_bytes += num_bytes;
+	return num_tx;
+}
+
+#endif /* _NFB_TX_H_ */
diff --git a/drivers/net/nfb/rte_nfb_pmd_version.map b/drivers/net/nfb/rte_nfb_pmd_version.map
new file mode 100644
index 0000000..66748c0
--- /dev/null
+++ b/drivers/net/nfb/rte_nfb_pmd_version.map
@@ -0,0 +1,4 @@
+EXPERIMENTAL {
+
+        local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 8a4f0f4..836973c 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -196,6 +196,8 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC)      += -lrte_pmd_softnic
 endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD)    += -lrte_pmd_sfc_efx
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2 -lsze2
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NFB)        += -lrte_pmd_nfb
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NFB)        +=  $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --libs --static libnfb)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_TAP)        += -lrte_pmd_tap
 _LDLIBS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += -lrte_pmd_thunderx_nicvf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD) += -lrte_pmd_vdev_netvsc
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v4] net/nfb: new netcope driver
  2019-03-07 13:24   ` [dpdk-dev] [PATCH v4] " Rastislav Cernay
@ 2019-03-07 13:46     ` Luca Boccassi
  2019-03-07 14:14       ` Jan Remeš
  0 siblings, 1 reply; 50+ messages in thread
From: Luca Boccassi @ 2019-03-07 13:46 UTC (permalink / raw)
  To: Rastislav Cernay, dev

On Thu, 2019-03-07 at 14:24 +0100, Rastislav Cernay wrote:
> From: Rastislav Cernay <cernay@netcope.com>
> 
> Note: New netcope-commong pcg on which is support for pkg-config,
> will be released soon and uploaded on official site.
> 
> Added new net driver for Netcope nfb cards
> 
> Signed-off-by: Rastislav Cernay <cernay@netcope.com>
> ---
> v2: remove unnecessary cast
>     remove unnecessary zeroing
>     move declaration to not mix with code
>     restore skeleton example
> v3: add release notes
>     add doc to doc index
>     add architecture limits to doc
>     edit features list
>     add .map file
>     change link to dependecies to official vendor site
>     move declarations out of code
>     remove false comments (rte_errno is set)
>     comments to c89 style
>     remove log from main rx loop
>     remove redundant code
> v4: add random initial MAC
>     fix format
>     move declarations out of code
>     fix error log in TX
>     q_errors is for reception errors
>     pmd is experimental
>     dependency check fixed
>     support for pkg-config
>  MAINTAINERS                             |   7 +
>  config/common_base                      |   4 +
>  devtools/test-build.sh                  |   1 +
>  doc/guides/nics/features/nfb.ini        |  18 +
>  doc/guides/nics/index.rst               |   1 +
>  doc/guides/nics/nfb.rst                 | 143 +++++++
>  doc/guides/rel_notes/release_19_02.rst  |   5 +
>  drivers/net/Makefile                    |   1 +
>  drivers/net/meson.build                 |   1 +
>  drivers/net/nfb/Makefile                |  44 +++
>  drivers/net/nfb/meson.build             |  15 +
>  drivers/net/nfb/nfb.h                   |  50 +++
>  drivers/net/nfb/nfb_ethdev.c            | 647
> ++++++++++++++++++++++++++++++++
>  drivers/net/nfb/nfb_rx.c                | 127 +++++++
>  drivers/net/nfb/nfb_rx.h                | 231 ++++++++++++
>  drivers/net/nfb/nfb_rxmode.c            | 100 +++++
>  drivers/net/nfb/nfb_rxmode.h            |  96 +++++
>  drivers/net/nfb/nfb_stats.c             |  77 ++++
>  drivers/net/nfb/nfb_stats.h             |  56 +++
>  drivers/net/nfb/nfb_tx.c                | 113 ++++++
>  drivers/net/nfb/nfb_tx.h                | 222 +++++++++++
>  drivers/net/nfb/rte_nfb_pmd_version.map |   4 +
>  mk/rte.app.mk                           |   2 +
>  23 files changed, 1965 insertions(+)
>  create mode 100644 doc/guides/nics/features/nfb.ini
>  create mode 100644 doc/guides/nics/nfb.rst
>  create mode 100644 drivers/net/nfb/Makefile
>  create mode 100644 drivers/net/nfb/meson.build
>  create mode 100644 drivers/net/nfb/nfb.h
>  create mode 100644 drivers/net/nfb/nfb_ethdev.c
>  create mode 100644 drivers/net/nfb/nfb_rx.c
>  create mode 100644 drivers/net/nfb/nfb_rx.h
>  create mode 100644 drivers/net/nfb/nfb_rxmode.c
>  create mode 100644 drivers/net/nfb/nfb_rxmode.h
>  create mode 100644 drivers/net/nfb/nfb_stats.c
>  create mode 100644 drivers/net/nfb/nfb_stats.h
>  create mode 100644 drivers/net/nfb/nfb_tx.c
>  create mode 100644 drivers/net/nfb/nfb_tx.h
>  create mode 100644 drivers/net/nfb/rte_nfb_pmd_version.map

<...>

> +
> +.. note::
> +
> +   This driver has external dependencies.
> +   Therefore it is disabled in default configuration files.
> +   It can be enabled by setting ``CONFIG_RTE_LIBRTE_PMD_NFB=y``
> +   and recompiling.
> +
> +.. note::
> +
> +   Currently the driver is supported only on x86_64 architectures.
> +   Only x86_64 versions of the external libraries are provided.
> +
> +Prerequisites
> +-------------
> +
> +This PMD requires kernel modules which are responsible for
> initialization and
> +allocation of resources needed for nfb layer function.
> +Communication between PMD and kernel modules is mediated by libnfb
> library.
> +These kernel modules and library are not part of DPDK and must be
> installed
> +separately:
> +
> +*  **libnfb library**
> +
> +   The library provides API for initialization of nfb transfers,
> receiving and
> +   transmitting data segments.
> +
> +*  **Kernel modules**
> +
> +   * nfb
> +
> +   Kernel modules manage initialization of hardware, allocation and
> +   sharing of resources for user space applications.
> +
> +Dependencies can be found here:
> +`Netcope common <
> https://www.netcope.com/en/company/community-support/dpdk-libsze2#NFB>`_
> .

I see netcope-common provides a pkg-config file, that's great.
However it's a bit broken at the moment:

Name: netcope-common
Version: 6.3.0
Description: Common software package for NetCOPE platform
Libs: -L${libdir}
Cflags: -I${includedir}

There is no linker flag, and Libs.private is missing. It should have:

Libs: -L${libdir} -lnfb
Libs.private: -lfdt

Could you please get it fixed?

> +Versions of the packages
> +~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +The minimum version of the provided packages:
> +
> +* for DPDK from 19.02
> +
> +Configuration
> +-------------
> +
> +These configuration options can be modified before compilation in
> the
> +``.config`` file:
> +
> +*  ``CONFIG_RTE_LIBRTE_PMD_NFB`` default value: **n**
> +
> +   Value **y** enables compilation of nfb PMD.
> +
> +Using the NFB PMD
> +----------------------
> +
> +Kernel modules have to be loaded before running the DPDK
> application.
> +
> +NFB card architecture
> +---------------------
> +
> +The NFB cards are multi-port multi-queue cards, where (generally)
> data from any
> +Ethernet port may be sent to any queue.
> +They are represented in DPDK as a single port.
> +
> +NFB-200G2QL card employs an addon cable which allows to connect it
> to two
> +physical PCI-E slots at the same time (see the diagram below).
> +This is done to allow 200 Gbps of traffic to be transferred through
> the PCI-E
> +bus (note that a single PCI-E 3.0 x16 slot provides only 125 Gbps
> theoretical
> +throughput).
> +
> +Although each slot may be connected to a different CPU and therefore
> to a different
> +NUMA node, the card is represented as a single port in DPDK. To work
> with data
> +from the individual queues on the right NUMA node, connection of
> NUMA nodes on
> +first and last queue (each NUMA node has half of the queues) need to
> be checked.
> +
> +.. figure:: img/szedata2_nfb200g_architecture.svg
> +    :align: center
> +
> +    NFB-200G2QL high-level diagram
> +
> +Limitations
> +-----------
> +
> +Driver is usable only on Linux architecture.
> +
> +Since a card is always represented as a single port, but can be
> connected to two
> +NUMA nodes, there is need for manual check where master/slave is
> connected.
> +
> +Example of usage
> +----------------
> +
> +Read packets from 0. and 1. receive queue and write them to 0. and
> 1.
> +transmit queue:
> +
> +.. code-block:: console
> +
> +   $RTE_TARGET/app/testpmd -l 0-3 -n 2 \
> +   -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2 -i -a
> +
> +Example output:
> +
> +.. code-block:: console
> +
> +   [...]
> +   EAL: PCI device 0000:06:00.0 on NUMA socket -1
> +   EAL:   probe driver: 1b26:c1c1 net_nfb
> +   PMD: Initializing NFB device (0000:06:00.0)
> +   PMD: Available DMA queues RX: 8 TX: 8
> +   PMD: NFB device (0000:06:00.0) successfully initialized
> +   Interactive-mode selected
> +   Auto-start selected
> +   Configuring Port 0 (socket 0)
> +   Port 0: 00:11:17:00:00:00
> +   Checking link statuses...
> +   Port 0 Link Up - speed 10000 Mbps - full-duplex
> +   Done
> +   Start automatic packet forwarding
> +     io packet forwarding - CRC stripping disabled -
> packets/burst=32
> +     nb forwarding cores=2 - nb forwarding ports=1
> +     RX queues=2 - RX desc=128 - RX free threshold=0
> +     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
> +     TX queues=2 - TX desc=512 - TX free threshold=0
> +     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
> +     TX RS bit threshold=0 - TXQ flags=0x0
> +   testpmd>
> diff --git a/doc/guides/rel_notes/release_19_02.rst
> b/doc/guides/rel_notes/release_19_02.rst
> index 3372c4d..9955b6b 100644
> --- a/doc/guides/rel_notes/release_19_02.rst
> +++ b/doc/guides/rel_notes/release_19_02.rst
> @@ -54,6 +54,11 @@ New Features
>       Also, make sure to start the actual text at the margin.
>       =========================================================
>  
> +* **Added an experimental net PMD NFB.**
> +
> +  Added the new ``nfb`` net driver for Netcope NFB cards. See
> +  the :doc:`../nics/nfb` NIC guide for more details on this new
> driver.
> +
>  * **Added support to free hugepages exactly as originally
> allocated.**
>  
>    Some applications using memory event callbacks (especially for
> managing
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index 670d7f7..013c551 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -38,6 +38,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5
>  DIRS-$(CONFIG_RTE_LIBRTE_MVNETA_PMD) += mvneta
>  DIRS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mvpp2
>  DIRS-$(CONFIG_RTE_LIBRTE_NETVSC_PMD) += netvsc
> +DIRS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb
>  DIRS-$(CONFIG_RTE_LIBRTE_NFP_PMD) += nfp
>  DIRS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt
>  DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += null
> diff --git a/drivers/net/meson.build b/drivers/net/meson.build
> index 45da3bb..6733a19 100644
> --- a/drivers/net/meson.build
> +++ b/drivers/net/meson.build
> @@ -27,6 +27,7 @@ drivers = ['af_packet',
>  	'mvneta',
>  	'mvpp2',
>  	'netvsc',
> +	'nfb',
>  	'nfp',
>  	'null', 'octeontx', 'pcap', 'qede', 'ring',
>  	'sfc',
> diff --git a/drivers/net/nfb/Makefile b/drivers/net/nfb/Makefile
> new file mode 100644
> index 0000000..968184e
> --- /dev/null
> +++ b/drivers/net/nfb/Makefile
> @@ -0,0 +1,44 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2018 Cesnet
> +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> +# All rights reserved.
> +
> +include $(RTE_SDK)/mk/rte.vars.mk
> +
> +#
> +# library name
> +#
> +LIB = librte_pmd_nfb.a
> +
> +INCLUDES :=-I$(SRCDIR)
> +
> +
> +CFLAGS += -O3
> +CFLAGS += $(WERROR_FLAGS)
> +CFLAGS += -DALLOW_EXPERIMENTAL_API
> +CFLAGS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-
> config --cflags libnfb)

This will not work - the pkg-config filename is netcope-common.pc, not
libnfb.pc. The convention would be to rename the pkg-config file to
libnfb.pc, but if you want to keep the current name then all pkg-config 
calls in this patch need to be updated.

> +LDLIBS += -lnfb

Do not hard-code this, pkg-config is used below.

> +LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
> +LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
> +LDLIBS += -lrte_bus_pci
> +LDLIBS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-
> config --libs libnfb)

Use:

LDLIBS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --libs libnfb || echo "-lnfb")

This way you have a fallback if pkg-config is not installed.

> +EXPORT_MAP := rte_pmd_nfb_version.map
> +
> +LIBABIVER := 1
> +
> +#
> +# all source are stored in SRCS-y
> +#
> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_ethdev.c
> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_rx.c
> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_tx.c
> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_stats.c
> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_rxmode.c
> +
> +#
> +# Export include files
> +#
> +SYMLINK-y-include +=
> +
> +include $(RTE_SDK)/mk/rte.lib.mk
> diff --git a/drivers/net/nfb/meson.build
> b/drivers/net/nfb/meson.build
> new file mode 100644
> index 0000000..16df146
> --- /dev/null
> +++ b/drivers/net/nfb/meson.build
> @@ -0,0 +1,15 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2018 Cesnet
> +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> +# All rights reserved.
> +
> +dep = cc.find_library('nfb', required: false)
> +
> +build = dep.found() and cc.has_header('nfb/nfb.h', dependencies:
> dep)
> +
> +allow_experimental_apis = true
> +
> +ext_deps += dep
> +
> +sources = files('nfb_rx.c', 'nfb_tx.c', 'nfb_stats.c',
> 'nfb_ethdev.c', 'nfb_rxmode.c')
> +pkgconfig_extra_libs += '-lnfb'

libnfb ships a pkg-config file, so please do this instead so that
static compilation can work correctly:

dep = dependency('netcope-common', required: false)
build = dep.found()

allow_experimental_apis = true

ext_deps += dep

sources = files('nfb_rx.c', 'nfb_tx.c', 'nfb_stats.c', 'nfb_ethdev.c', 'nfb_rxmode.c')

-- 
Kind regards,
Luca Boccassi

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v4] net/nfb: new netcope driver
  2019-03-07 13:46     ` Luca Boccassi
@ 2019-03-07 14:14       ` Jan Remeš
  0 siblings, 0 replies; 50+ messages in thread
From: Jan Remeš @ 2019-03-07 14:14 UTC (permalink / raw)
  To: Luca Boccassi; +Cc: Rastislav Cernay, dev

Hi,

> I see netcope-common provides a pkg-config file, that's great.
> However it's a bit broken at the moment:
>
> Name: netcope-common
> Version: 6.3.0
> Description: Common software package for NetCOPE platform
> Libs: -L${libdir}
> Cflags: -I${includedir}
>
> There is no linker flag, and Libs.private is missing. It should have:
>
> Libs: -L${libdir} -lnfb
> Libs.private: -lfdt
>
> Could you please get it fixed?

We are preparing a release of netcope-common, which will include fixed
pkg-config file.

>
> This will not work - the pkg-config filename is netcope-common.pc, not
> libnfb.pc. The convention would be to rename the pkg-config file to
> libnfb.pc, but if you want to keep the current name then all pkg-config
> calls in this patch need to be updated.

The first proposal on this issue, which this patch version is based
upon, was to add a new "libnfb.pc" pkg-config file to netcope-common.
This might be finalized either as a fix in netcope-common.pc or a
separate libnfb.pc being shipped. Once this decision is made, we will
address it appropriately in the patch.

Best regards,
  Jan Remes

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [dpdk-dev] [PATCH v5] net/nfb: new netcope driver
  2019-02-26 12:57 ` [dpdk-dev] [PATCH] net/nfb: new netcope driver Rastislav Cernay
                     ` (4 preceding siblings ...)
  2019-03-07 13:24   ` [dpdk-dev] [PATCH v4] " Rastislav Cernay
@ 2019-03-22 12:12   ` Rastislav Cernay
  2019-03-22 12:12     ` Rastislav Cernay
  2019-03-28 16:01     ` Ferruh Yigit
  2019-04-04  9:05   ` [dpdk-dev] [PATCH v6] " Rastislav Cernay
                     ` (2 subsequent siblings)
  8 siblings, 2 replies; 50+ messages in thread
From: Rastislav Cernay @ 2019-03-22 12:12 UTC (permalink / raw)
  To: dev; +Cc: Rastislav Cernay

From: Rastislav Cernay <cernay@netcope.com>

Added new net driver for Netcope nfb cards

Signed-off-by: Rastislav Cernay <cernay@netcope.com>
---
v2: remove unnecessary cast
    remove unnecessary zeroing
    move declaration to not mix with code
    restore skeleton example
v3: add release notes
    add doc to doc index
    add architecture limits to doc
    edit features list
    add .map file
    change link to dependecies to official vendor site
    move declarations out of code
    remove false comments (rte_errno is set)
    comments to c89 style
    remove log from main rx loop
    remove redundant code
v4: API is experimental
    fixed meson build dependency
    random initial MAC
    stats->q_errors is for intput err only
    move more declarations to a beginning
    fixed err log in TX
    use of pkg-config
v5: fixed pkg-config for new version of netcope-common
 MAINTAINERS                             |   7 +
 config/common_base                      |   4 +
 devtools/test-build.sh                  |   1 +
 doc/guides/nics/features/nfb.ini        |  18 +
 doc/guides/nics/index.rst               |   1 +
 doc/guides/nics/nfb.rst                 | 143 +++++++
 doc/guides/rel_notes/release_19_02.rst  |   5 +
 drivers/net/Makefile                    |   1 +
 drivers/net/meson.build                 |   1 +
 drivers/net/nfb/Makefile                |  44 +++
 drivers/net/nfb/meson.build             |  15 +
 drivers/net/nfb/nfb.h                   |  50 +++
 drivers/net/nfb/nfb_ethdev.c            | 647 ++++++++++++++++++++++++++++++++
 drivers/net/nfb/nfb_rx.c                | 127 +++++++
 drivers/net/nfb/nfb_rx.h                | 231 ++++++++++++
 drivers/net/nfb/nfb_rxmode.c            | 100 +++++
 drivers/net/nfb/nfb_rxmode.h            |  96 +++++
 drivers/net/nfb/nfb_stats.c             |  77 ++++
 drivers/net/nfb/nfb_stats.h             |  56 +++
 drivers/net/nfb/nfb_tx.c                | 113 ++++++
 drivers/net/nfb/nfb_tx.h                | 222 +++++++++++
 drivers/net/nfb/rte_nfb_pmd_version.map |   4 +
 mk/rte.app.mk                           |   2 +
 23 files changed, 1965 insertions(+)
 create mode 100644 doc/guides/nics/features/nfb.ini
 create mode 100644 doc/guides/nics/nfb.rst
 create mode 100644 drivers/net/nfb/Makefile
 create mode 100644 drivers/net/nfb/meson.build
 create mode 100644 drivers/net/nfb/nfb.h
 create mode 100644 drivers/net/nfb/nfb_ethdev.c
 create mode 100644 drivers/net/nfb/nfb_rx.c
 create mode 100644 drivers/net/nfb/nfb_rx.h
 create mode 100644 drivers/net/nfb/nfb_rxmode.c
 create mode 100644 drivers/net/nfb/nfb_rxmode.h
 create mode 100644 drivers/net/nfb/nfb_stats.c
 create mode 100644 drivers/net/nfb/nfb_stats.h
 create mode 100644 drivers/net/nfb/nfb_tx.c
 create mode 100644 drivers/net/nfb/nfb_tx.h
 create mode 100644 drivers/net/nfb/rte_nfb_pmd_version.map

diff --git a/MAINTAINERS b/MAINTAINERS
index 6610440..436f3d2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -654,6 +654,13 @@ F: drivers/net/szedata2/
 F: doc/guides/nics/szedata2.rst
 F: doc/guides/nics/features/szedata2.ini
 
+Netcope nfb - EXPERIMENTAL
+M: Rastislav Cernay <cernay@netcope.com>
+M: Jan Remes <remes@netcope.com>
+F: drivers/net/nfb/
+F: doc/guides/nics/nfb.rst
+F: doc/guides/nics/features/nfb.ini
+
 Netronome nfp
 M: Alejandro Lucero <alejandro.lucero@netronome.com>
 F: drivers/net/nfp/
diff --git a/config/common_base b/config/common_base
index 7c6da51..1ab0a6b 100644
--- a/config/common_base
+++ b/config/common_base
@@ -360,6 +360,10 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
 # Compile software PMD backed by SZEDATA2 device
 #
 CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
+#
+# Compile software PMD backed by NFB device
+#
+CONFIG_RTE_LIBRTE_PMD_NFB=n
 
 #
 # Compile burst-oriented Cavium Thunderx NICVF PMD driver
diff --git a/devtools/test-build.sh b/devtools/test-build.sh
index 42f4ad0..ab57ab8 100755
--- a/devtools/test-build.sh
+++ b/devtools/test-build.sh
@@ -18,6 +18,7 @@ default_path=$PATH
 # - DPDK_DEP_SSL (y/[n])
 # - DPDK_DEP_IPSEC_MB (y/[n])
 # - DPDK_DEP_SZE (y/[n])
+# - DPDK_DEP_NFB (y/[n])
 # - DPDK_DEP_ZLIB (y/[n])
 # - DPDK_MAKE_JOBS (int)
 # - DPDK_NOTIFY (notify-send)
diff --git a/doc/guides/nics/features/nfb.ini b/doc/guides/nics/features/nfb.ini
new file mode 100644
index 0000000..e1c5266
--- /dev/null
+++ b/doc/guides/nics/features/nfb.ini
@@ -0,0 +1,18 @@
+;
+; Supported features of the 'nfb' network poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Speed capabilities   = P
+Link status          = Y
+Queue start/stop     = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Basic stats          = Y
+Extended stats       = Y
+Stats per queue      = Y
+Other kdrv           = Y
+x86-64               = Y
+Usage doc            = Y
+Scattered Tx         = Y
diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index 5c80e3b..079972e 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -39,6 +39,7 @@ Network Interface Controller Drivers
     mvneta
     mvpp2
     netvsc
+    nfb
     nfp
     octeontx
     qede
diff --git a/doc/guides/nics/nfb.rst b/doc/guides/nics/nfb.rst
new file mode 100644
index 0000000..8c0be40
--- /dev/null
+++ b/doc/guides/nics/nfb.rst
@@ -0,0 +1,143 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright 2015 - 2016 CESNET
+
+NFB poll mode driver library
+=================================
+
+The NFB poll mode driver library implements support for the Netcope
+FPGA Boards (**NFB-***), FPGA-based programmable NICs.
+The NFB PMD uses interface provided by the libnfb library to communicate
+with the NFB cards over the nfb layer.
+
+More information about the
+`NFB cards <http://www.netcope.com/en/products/fpga-boards>`_
+and used technology
+(`Netcope Development Kit <http://www.netcope.com/en/products/fpga-development-kit>`_)
+can be found on the `Netcope Technologies website <http://www.netcope.com/>`_.
+
+.. note::
+
+   This driver has external dependencies.
+   Therefore it is disabled in default configuration files.
+   It can be enabled by setting ``CONFIG_RTE_LIBRTE_PMD_NFB=y``
+   and recompiling.
+
+.. note::
+
+   Currently the driver is supported only on x86_64 architectures.
+   Only x86_64 versions of the external libraries are provided.
+
+Prerequisites
+-------------
+
+This PMD requires kernel modules which are responsible for initialization and
+allocation of resources needed for nfb layer function.
+Communication between PMD and kernel modules is mediated by libnfb library.
+These kernel modules and library are not part of DPDK and must be installed
+separately:
+
+*  **libnfb library**
+
+   The library provides API for initialization of nfb transfers, receiving and
+   transmitting data segments.
+
+*  **Kernel modules**
+
+   * nfb
+
+   Kernel modules manage initialization of hardware, allocation and
+   sharing of resources for user space applications.
+
+Dependencies can be found here:
+`Netcope common <https://www.netcope.com/en/company/community-support/dpdk-libsze2#NFB>`_.
+
+Versions of the packages
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The minimum version of the provided packages:
+
+* for DPDK from 19.02
+
+Configuration
+-------------
+
+These configuration options can be modified before compilation in the
+``.config`` file:
+
+*  ``CONFIG_RTE_LIBRTE_PMD_NFB`` default value: **n**
+
+   Value **y** enables compilation of nfb PMD.
+
+Using the NFB PMD
+----------------------
+
+Kernel modules have to be loaded before running the DPDK application.
+
+NFB card architecture
+---------------------
+
+The NFB cards are multi-port multi-queue cards, where (generally) data from any
+Ethernet port may be sent to any queue.
+They are represented in DPDK as a single port.
+
+NFB-200G2QL card employs an addon cable which allows to connect it to two
+physical PCI-E slots at the same time (see the diagram below).
+This is done to allow 200 Gbps of traffic to be transferred through the PCI-E
+bus (note that a single PCI-E 3.0 x16 slot provides only 125 Gbps theoretical
+throughput).
+
+Although each slot may be connected to a different CPU and therefore to a different
+NUMA node, the card is represented as a single port in DPDK. To work with data
+from the individual queues on the right NUMA node, connection of NUMA nodes on
+first and last queue (each NUMA node has half of the queues) need to be checked.
+
+.. figure:: img/szedata2_nfb200g_architecture.svg
+    :align: center
+
+    NFB-200G2QL high-level diagram
+
+Limitations
+-----------
+
+Driver is usable only on Linux architecture.
+
+Since a card is always represented as a single port, but can be connected to two
+NUMA nodes, there is need for manual check where master/slave is connected.
+
+Example of usage
+----------------
+
+Read packets from 0. and 1. receive queue and write them to 0. and 1.
+transmit queue:
+
+.. code-block:: console
+
+   $RTE_TARGET/app/testpmd -l 0-3 -n 2 \
+   -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2 -i -a
+
+Example output:
+
+.. code-block:: console
+
+   [...]
+   EAL: PCI device 0000:06:00.0 on NUMA socket -1
+   EAL:   probe driver: 1b26:c1c1 net_nfb
+   PMD: Initializing NFB device (0000:06:00.0)
+   PMD: Available DMA queues RX: 8 TX: 8
+   PMD: NFB device (0000:06:00.0) successfully initialized
+   Interactive-mode selected
+   Auto-start selected
+   Configuring Port 0 (socket 0)
+   Port 0: 00:11:17:00:00:00
+   Checking link statuses...
+   Port 0 Link Up - speed 10000 Mbps - full-duplex
+   Done
+   Start automatic packet forwarding
+     io packet forwarding - CRC stripping disabled - packets/burst=32
+     nb forwarding cores=2 - nb forwarding ports=1
+     RX queues=2 - RX desc=128 - RX free threshold=0
+     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX queues=2 - TX desc=512 - TX free threshold=0
+     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX RS bit threshold=0 - TXQ flags=0x0
+   testpmd>
diff --git a/doc/guides/rel_notes/release_19_02.rst b/doc/guides/rel_notes/release_19_02.rst
index 3372c4d..9955b6b 100644
--- a/doc/guides/rel_notes/release_19_02.rst
+++ b/doc/guides/rel_notes/release_19_02.rst
@@ -54,6 +54,11 @@ New Features
      Also, make sure to start the actual text at the margin.
      =========================================================
 
+* **Added an experimental net PMD NFB.**
+
+  Added the new ``nfb`` net driver for Netcope NFB cards. See
+  the :doc:`../nics/nfb` NIC guide for more details on this new driver.
+
 * **Added support to free hugepages exactly as originally allocated.**
 
   Some applications using memory event callbacks (especially for managing
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 670d7f7..013c551 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -38,6 +38,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5
 DIRS-$(CONFIG_RTE_LIBRTE_MVNETA_PMD) += mvneta
 DIRS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mvpp2
 DIRS-$(CONFIG_RTE_LIBRTE_NETVSC_PMD) += netvsc
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb
 DIRS-$(CONFIG_RTE_LIBRTE_NFP_PMD) += nfp
 DIRS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += null
diff --git a/drivers/net/meson.build b/drivers/net/meson.build
index 45da3bb..6733a19 100644
--- a/drivers/net/meson.build
+++ b/drivers/net/meson.build
@@ -27,6 +27,7 @@ drivers = ['af_packet',
 	'mvneta',
 	'mvpp2',
 	'netvsc',
+	'nfb',
 	'nfp',
 	'null', 'octeontx', 'pcap', 'qede', 'ring',
 	'sfc',
diff --git a/drivers/net/nfb/Makefile b/drivers/net/nfb/Makefile
new file mode 100644
index 0000000..e7189dc
--- /dev/null
+++ b/drivers/net/nfb/Makefile
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Cesnet
+# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_nfb.a
+
+INCLUDES :=-I$(SRCDIR)
+
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --cflags netcope-common)
+LDLIBS += -lnfb
+LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
+LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
+LDLIBS += -lrte_bus_pci
+LDLIBS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --libs netcope-common)
+
+EXPORT_MAP := rte_pmd_nfb_version.map
+
+LIBABIVER := 1
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_rx.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_tx.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_stats.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_rxmode.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/nfb/meson.build b/drivers/net/nfb/meson.build
new file mode 100644
index 0000000..16df146
--- /dev/null
+++ b/drivers/net/nfb/meson.build
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Cesnet
+# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+dep = cc.find_library('nfb', required: false)
+
+build = dep.found() and cc.has_header('nfb/nfb.h', dependencies: dep)
+
+allow_experimental_apis = true
+
+ext_deps += dep
+
+sources = files('nfb_rx.c', 'nfb_tx.c', 'nfb_stats.c', 'nfb_ethdev.c', 'nfb_rxmode.c')
+pkgconfig_extra_libs += '-lnfb'
diff --git a/drivers/net/nfb/nfb.h b/drivers/net/nfb/nfb.h
new file mode 100644
index 0000000..42671a1
--- /dev/null
+++ b/drivers/net/nfb/nfb.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_H_
+#define _NFB_H_
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+
+/* PCI Vendor ID */
+#define PCI_VENDOR_ID_NETCOPE 0x1b26
+
+/* PCI Device IDs */
+#define PCI_DEVICE_ID_NFB_40G2  0xcb80
+#define PCI_DEVICE_ID_NFB_100G2 0xc2c1
+#define PCI_DEVICE_ID_NFB_200G2QL 0xc250
+
+/* Max index of ndp rx/tx queues */
+#define RTE_ETH_NDP_MAX_RX_QUEUES 32
+#define RTE_ETH_NDP_MAX_TX_QUEUES 32
+
+/* Max index of rx/tx dmas */
+#define RTE_MAX_NC_RXMAC 256
+#define RTE_MAX_NC_TXMAC 256
+
+#define RTE_NFB_DRIVER_NAME net_nfb
+
+struct pmd_internals {
+	uint16_t         max_rxmac;
+	uint16_t         max_txmac;
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC];
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC];
+
+	char             nfb_dev[PATH_MAX];
+	struct nfb_device *nfb;
+	/* Place to remember if filter was promiscuous or filtering by table,
+	 * when disabling allmulticast
+	 */
+	enum nc_rxmac_mac_filter rx_filter_original;
+};
+
+#endif /* _NFB_H_ */
diff --git a/drivers/net/nfb/nfb_ethdev.c b/drivers/net/nfb/nfb_ethdev.c
new file mode 100644
index 0000000..a5a6bdc
--- /dev/null
+++ b/drivers/net/nfb/nfb_ethdev.c
@@ -0,0 +1,647 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_kvargs.h>
+#include <rte_dev.h>
+#include <rte_common.h>
+
+#include "nfb_stats.h"
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+/**
+ * Default MAC addr
+ */
+static struct ether_addr eth_addr = {
+	.addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Open all RX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] rxmac
+ *   Pointer to output array of nc_rxmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of rxmac
+ */
+static void __rte_experimental
+nfb_nc_rxmac_init(struct nfb_device *nfb,
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t *max_rxmac)
+{
+	*max_rxmac = 0;
+	while ((rxmac[*max_rxmac] = nc_rxmac_open_index(nfb, *max_rxmac)))
+		++(*max_rxmac);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Open all TX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] txmac
+ *   Pointer to output array of nc_txmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of txmac
+ */
+static void __rte_experimental
+nfb_nc_txmac_init(struct nfb_device *nfb,
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t *max_txmac)
+{
+	*max_txmac = 0;
+	while ((txmac[*max_txmac] = nc_txmac_open_index(nfb, *max_txmac)))
+		++(*max_txmac);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Close all RX DMA queues
+ *
+ * @param rxmac
+ *   Pointer to array of nc_rxmac
+ * @param max_rxmac
+ *   Maximum index of rxmac
+ */
+static void __rte_experimental
+nfb_nc_rxmac_deinit(struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t max_rxmac)
+{
+	for (; max_rxmac > 0; --max_rxmac) {
+		nc_rxmac_close(rxmac[max_rxmac]);
+		rxmac[max_rxmac] = NULL;
+	}
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Close all TX DMA queues
+ *
+ * @param txmac
+ *   Pointer to array of nc_txmac
+ * @param max_txmac
+ *   Maximum index of txmac
+ */
+static void __rte_experimental
+nfb_nc_txmac_deinit(struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t max_txmac)
+{
+	for (; max_txmac > 0; --max_txmac) {
+		nc_txmac_close(txmac[max_txmac]);
+		txmac[max_txmac] = NULL;
+	}
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to start the device.
+ *
+ * Start device by starting all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_dev_start(struct rte_eth_dev *dev)
+{
+	int ret;
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_rx; i++) {
+		ret = nfb_eth_rx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_rx;
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		ret = nfb_eth_tx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_tx;
+	}
+
+	return 0;
+
+err_tx:
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+err_rx:
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+	return ret;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to stop the device.
+ *
+ * Stop device by stopping all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void __rte_experimental
+nfb_eth_dev_stop(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback for Ethernet device configuration.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to get information about the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] info
+ *   Info structure output buffer.
+ */
+static void __rte_experimental
+nfb_eth_dev_info(struct rte_eth_dev *dev,
+	struct rte_eth_dev_info *dev_info)
+{
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = dev->data->nb_rx_queues;
+	dev_info->max_tx_queues = dev->data->nb_tx_queues;
+	dev_info->speed_capa = ETH_LINK_SPEED_100G;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to close the device.
+ *
+ * Destroy all queues and objects, free memory.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void __rte_experimental
+nfb_eth_dev_close(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	nfb_eth_dev_stop(dev);
+
+	for (i = 0; i < nb_rx; i++) {
+		nfb_eth_rx_queue_release(dev->data->rx_queues[i]);
+		dev->data->rx_queues[i] = NULL;
+	}
+	dev->data->nb_rx_queues = 0;
+	for (i = 0; i < nb_tx; i++) {
+		nfb_eth_tx_queue_release(dev->data->tx_queues[i]);
+		dev->data->tx_queues[i] = NULL;
+	}
+	dev->data->nb_tx_queues = 0;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to retrieve physical link information.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] link
+ *   Storage for current link status.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_link_update(struct rte_eth_dev *dev,
+	int wait_to_complete __rte_unused)
+{
+	uint16_t i;
+	struct nc_rxmac_status status;
+	struct rte_eth_link link;
+	memset(&link, 0, sizeof(link));
+
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	status.speed = MAC_SPEED_UNKNOWN;
+
+	link.link_speed = ETH_SPEED_NUM_NONE;
+	link.link_status = ETH_LINK_DOWN;
+	link.link_duplex = ETH_LINK_FULL_DUPLEX;
+	link.link_autoneg = ETH_LINK_SPEED_FIXED;
+
+	if (internals->rxmac[0] != NULL) {
+		nc_rxmac_read_status(internals->rxmac[0], &status);
+
+		switch (status.speed) {
+		case MAC_SPEED_10G:
+			link.link_speed = ETH_SPEED_NUM_10G;
+			break;
+		case MAC_SPEED_40G:
+			link.link_speed = ETH_SPEED_NUM_40G;
+			break;
+		case MAC_SPEED_100G:
+			link.link_speed = ETH_SPEED_NUM_100G;
+			break;
+		default:
+			link.link_speed = ETH_SPEED_NUM_NONE;
+			break;
+		}
+	}
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_read_status(internals->rxmac[i], &status);
+
+		if (status.enabled && status.link_up) {
+			link.link_status = ETH_LINK_UP;
+			break;
+		}
+	}
+
+	rte_eth_linkstatus_set(dev, &link);
+
+	return 0;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to bring the link UP.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_dev_set_link_up(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_enable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_enable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to bring the link DOWN.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_dev_set_link_down(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_disable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_disable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to set primary MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_mac_addr_set(struct rte_eth_dev *dev,
+	struct ether_addr *mac_addr)
+{
+	unsigned int i;
+	unsigned long long mac = 0;
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+
+	if (!is_valid_assigned_ether_addr(mac_addr))
+		return -EINVAL;
+
+	for (i = 0; i < 6; i++) {
+		mac <<= 8;
+		mac |= mac_addr->addr_bytes[i] & 0xFF;
+	}
+
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_set_mac(internals->rxmac[i], 0, mac, 1);
+
+	ether_addr_copy(mac_addr, data->mac_addrs);
+	return 0;
+}
+
+static const struct eth_dev_ops ops = {
+	.dev_start = nfb_eth_dev_start,
+	.dev_stop = nfb_eth_dev_stop,
+	.dev_set_link_up = nfb_eth_dev_set_link_up,
+	.dev_set_link_down = nfb_eth_dev_set_link_down,
+	.dev_close = nfb_eth_dev_close,
+	.dev_configure = nfb_eth_dev_configure,
+	.dev_infos_get = nfb_eth_dev_info,
+	.promiscuous_enable = nfb_eth_promiscuous_enable,
+	.promiscuous_disable = nfb_eth_promiscuous_disable,
+	.allmulticast_enable = nfb_eth_allmulticast_enable,
+	.allmulticast_disable = nfb_eth_allmulticast_disable,
+	.rx_queue_start = nfb_eth_rx_queue_start,
+	.rx_queue_stop = nfb_eth_rx_queue_stop,
+	.tx_queue_start = nfb_eth_tx_queue_start,
+	.tx_queue_stop = nfb_eth_tx_queue_stop,
+	.rx_queue_setup = nfb_eth_rx_queue_setup,
+	.tx_queue_setup = nfb_eth_tx_queue_setup,
+	.rx_queue_release = nfb_eth_rx_queue_release,
+	.tx_queue_release = nfb_eth_tx_queue_release,
+	.link_update = nfb_eth_link_update,
+	.stats_get = nfb_eth_stats_get,
+	.stats_reset = nfb_eth_stats_reset,
+	.mac_addr_set = nfb_eth_mac_addr_set,
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to initialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_dev_init(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+	struct ether_addr eth_addr_init;
+
+	RTE_LOG(INFO, PMD, "Initializing NFB device (" PCI_PRI_FMT ")\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	snprintf(internals->nfb_dev, PATH_MAX,
+		"/dev/nfb/by-pci-slot/" PCI_PRI_FMT,
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	/*
+	 * Get number of available DMA RX and TX queues, which is maximum
+	 * number of queues that can be created and store it in private device
+	 * data structure.
+	 */
+	internals->nfb = nfb_open(internals->nfb_dev);
+	if (internals->nfb == NULL) {
+		RTE_LOG(ERR, PMD, "nfb_open(): failed to open %s",
+			internals->nfb_dev);
+		return -EINVAL;
+	}
+	data->nb_rx_queues = ndp_get_rx_queue_available_count(internals->nfb);
+	data->nb_tx_queues = ndp_get_tx_queue_available_count(internals->nfb);
+
+	RTE_LOG(INFO, PMD, "Available NDP queues RX: %u TX: %u\n",
+		data->nb_rx_queues, data->nb_tx_queues);
+
+	nfb_nc_rxmac_init(internals->nfb,
+		internals->rxmac,
+		&internals->max_rxmac);
+	nfb_nc_txmac_init(internals->nfb,
+		internals->txmac,
+		&internals->max_txmac);
+
+	/* Set rx, tx burst functions */
+	dev->rx_pkt_burst = nfb_eth_ndp_rx;
+	dev->tx_pkt_burst = nfb_eth_ndp_tx;
+
+	/* Set function callbacks for Ethernet API */
+	dev->dev_ops = &ops;
+
+	/* Get link state */
+	nfb_eth_link_update(dev, 0);
+
+	/* Allocate space for one mac address */
+	data->mac_addrs = rte_zmalloc(data->name, sizeof(struct ether_addr),
+		RTE_CACHE_LINE_SIZE);
+	if (data->mac_addrs == NULL) {
+		RTE_LOG(ERR, PMD, "Could not alloc space for MAC address!\n");
+		nfb_close(internals->nfb);
+		return -EINVAL;
+	}
+
+	eth_random_addr(eth_addr_init.addr_bytes);
+	eth_addr_init.addr_bytes[0] = eth_addr.addr_bytes[0];
+	eth_addr_init.addr_bytes[1] = eth_addr.addr_bytes[1];
+	eth_addr_init.addr_bytes[2] = eth_addr.addr_bytes[2];
+
+	nfb_eth_mac_addr_set(dev, &eth_addr_init);
+
+	data->promiscuous = nfb_eth_promiscuous_get(dev);
+	data->all_multicast = nfb_eth_allmulticast_get(dev);
+	internals->rx_filter_original = data->promiscuous;
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully initialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to uninitialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_dev_uninit(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+
+	dev->data->mac_addrs = NULL;
+
+	nfb_nc_rxmac_deinit(internals->rxmac, internals->max_rxmac);
+	nfb_nc_txmac_deinit(internals->txmac, internals->max_txmac);
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully uninitialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+static const struct rte_pci_id nfb_pci_id_table[] = {
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_40G2) },
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_100G2) },
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_200G2QL) },
+	{ .vendor_id = 0, }
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to register a PCI device.
+ *
+ * This function spawns Ethernet devices out of a given PCI device.
+ *
+ * @param[in] pci_drv
+ *   PCI driver structure (nfb_driver).
+ * @param[in] pci_dev
+ *   PCI device information.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+		struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_probe(pci_dev,
+		sizeof(struct pmd_internals), nfb_eth_dev_init);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to remove a PCI device.
+ *
+ * This function removes all Ethernet devices belong to a given PCI device.
+ *
+ * @param[in] pci_dev
+ *   Pointer to the PCI device.
+ *
+ * @return
+ *   0 on success, the function cannot fail.
+ */
+static int __rte_experimental
+nfb_eth_pci_remove(struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_remove(pci_dev, nfb_eth_dev_uninit);
+}
+
+static struct rte_pci_driver nfb_eth_driver = {
+	.id_table = nfb_pci_id_table,
+	.probe = nfb_eth_pci_probe,
+	.remove = nfb_eth_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(RTE_NFB_DRIVER_NAME, nfb_eth_driver);
+RTE_PMD_REGISTER_PCI_TABLE(RTE_NFB_DRIVER_NAME, nfb_pci_id_table);
+RTE_PMD_REGISTER_KMOD_DEP(RTE_NFB_DRIVER_NAME, "* nfb");
diff --git a/drivers/net/nfb/nfb_rx.c b/drivers/net/nfb/nfb_rx.c
new file mode 100644
index 0000000..7026c1b
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.c
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_rx.h"
+#include "nfb.h"
+
+int __rte_experimental
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+	int ret;
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_start(rxq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+int __rte_experimental
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+	int ret;
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_stop(rxq->queue);
+	if (ret != 0)
+		return -EINVAL;
+
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int __rte_experimental
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+		uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	struct ndp_rx_queue *rxq;
+	int ret;
+
+	rxq = rte_zmalloc_socket("ndp rx queue",
+			sizeof(struct ndp_rx_queue),
+			RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (rxq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for rx queue id "
+				"%" PRIu16 "!\n", rx_queue_id);
+		return -ENOMEM;
+	}
+
+	ret = nfb_eth_rx_queue_init(internals->nfb,
+		rx_queue_id,
+		dev->data->port_id,
+		mb_pool,
+		rxq);
+
+	if (ret == 0)
+		dev->data->rx_queues[rx_queue_id] = rxq;
+	else
+		rte_free(rxq);
+
+	return ret;
+}
+
+int __rte_experimental
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+		uint16_t rx_queue_id,
+		uint16_t port_id,
+		struct rte_mempool *mb_pool,
+		struct ndp_rx_queue *rxq)
+{
+	const struct rte_pktmbuf_pool_private *mbp_priv =
+		rte_mempool_get_priv(mb_pool);
+
+	if (nfb == NULL)
+		return -EINVAL;
+
+	rxq->queue = ndp_open_rx_queue(nfb, rx_queue_id);
+	if (rxq->queue == NULL)
+		return -EINVAL;
+
+	rxq->nfb = nfb;
+	rxq->rx_queue_id = rx_queue_id;
+	rxq->in_port = port_id;
+	rxq->mb_pool = mb_pool;
+	rxq->buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size -
+		RTE_PKTMBUF_HEADROOM);
+
+	rxq->rx_pkts = 0;
+	rxq->rx_bytes = 0;
+	rxq->err_pkts = 0;
+
+	return 0;
+}
+
+void __rte_experimental
+nfb_eth_rx_queue_release(void *q)
+{
+	struct ndp_rx_queue *rxq = (struct ndp_rx_queue *)q;
+	if (rxq->queue != NULL) {
+		ndp_close_rx_queue(rxq->queue);
+		rte_free(rxq);
+		rxq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_rx.h b/drivers/net/nfb/nfb_rx.h
new file mode 100644
index 0000000..772ccfc
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.h
@@ -0,0 +1,231 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_RX_H_
+#define _NFB_RX_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+struct ndp_rx_queue {
+	struct nfb_device *nfb;	     /* nfb dev structure */
+	struct ndp_queue *queue;     /* rx queue */
+	uint16_t rx_queue_id;	     /* index */
+	uint8_t in_port;	     /* port */
+
+	struct rte_mempool *mb_pool; /* memory pool to allocate packets */
+	uint16_t buf_size;           /* mbuf size */
+
+	volatile uint64_t rx_pkts;   /* packets read */
+	volatile uint64_t rx_bytes;  /* bytes read */
+	volatile uint64_t err_pkts;  /* erroneous packets */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Initialize ndp_rx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param rx_queue_id
+ *   RX queue index.
+ * @param port_id
+ *   Device [external] port identifier.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ * @param[out] rxq
+ *   Pointer to ndp_rx_queue output structure
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+	uint16_t rx_queue_id,
+	uint16_t port_id,
+	struct rte_mempool *mb_pool,
+	struct ndp_rx_queue *rxq);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to setup a RX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t rx_queue_id,
+	uint16_t nb_rx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_rxconf *rx_conf __rte_unused,
+	struct rte_mempool *mb_pool);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void __rte_experimental
+nfb_eth_rx_queue_release(void *q);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Start traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Stop traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ */
+int __rte_experimental
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback for RX.
+ *
+ * @param dpdk_rxq
+ *   Generic pointer to RX queue structure.
+ * @param[out] bufs
+ *   Array to store received packets.
+ * @param nb_pkts
+ *   Maximum number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully received (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t __rte_experimental
+nfb_eth_ndp_rx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	struct ndp_rx_queue *ndp = queue;
+	uint16_t packet_size;
+	uint64_t num_bytes = 0;
+	uint16_t num_rx;
+	unsigned int i;
+
+	const uint16_t buf_size = ndp->buf_size;
+
+	struct rte_mbuf *mbuf;
+	struct ndp_packet packets[nb_pkts];
+
+	struct rte_mbuf *mbufs[nb_pkts];
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "RX invalid arguments!\n");
+		return 0;
+	}
+
+	/* returns either all or nothing */
+	i = rte_pktmbuf_alloc_bulk(ndp->mb_pool, mbufs, nb_pkts);
+	if (unlikely(i != 0))
+		return 0;
+
+	num_rx = ndp_rx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_rx != nb_pkts)) {
+		for (i = num_rx; i < nb_pkts; i++)
+			rte_pktmbuf_free(mbufs[i]);
+	}
+
+	nb_pkts = num_rx;
+
+	num_rx = 0;
+	/*
+	 * Reads the given number of packets from NDP queue given
+	 * by queue and copies the packet data into a newly allocated mbuf
+	 * to return.
+	 */
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = mbufs[i];
+
+		/* get the space available for data in the mbuf */
+		packet_size = packets[i].data_length;
+
+		if (likely(packet_size <= buf_size)) {
+			/* NDP packet will fit in one mbuf, go ahead and copy */
+			rte_memcpy(rte_pktmbuf_mtod(mbuf, void *),
+				packets[i].data, packet_size);
+
+			mbuf->data_len = (uint16_t)packet_size;
+
+			mbuf->pkt_len = packet_size;
+			mbuf->port = ndp->in_port;
+			bufs[num_rx++] = mbuf;
+			num_bytes += packet_size;
+		} else {
+			/*
+			 * NDP packet will not fit in one mbuf,
+			 * scattered mode is not enabled, drop packet
+			 */
+			rte_pktmbuf_free(mbuf);
+		}
+	}
+
+	ndp_rx_burst_put(ndp->queue);
+
+	ndp->rx_pkts += num_rx;
+	ndp->rx_bytes += num_bytes;
+	return num_rx;
+}
+
+#endif /* _NFB_RX_H_ */
diff --git a/drivers/net/nfb/nfb_rxmode.c b/drivers/net/nfb/nfb_rxmode.c
new file mode 100644
index 0000000..a6c9cb4
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.c
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+void __rte_experimental
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+	uint16_t i;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_PROMISCUOUS);
+	}
+}
+
+void __rte_experimental
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+	uint16_t i;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_TABLE;
+
+	/* if promisc is not enabled, do nothing */
+	if (!nfb_eth_promiscuous_get(dev))
+		return;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE);
+	}
+}
+
+int __rte_experimental
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_PROMISCUOUS);
+}
+
+void __rte_experimental
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+	}
+}
+
+void __rte_experimental
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+
+	/* if multicast is not enabled do nothing */
+	if (!nfb_eth_allmulticast_get(dev))
+		return;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			internals->rx_filter_original);
+	}
+}
+
+int __rte_experimental
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+}
diff --git a/drivers/net/nfb/nfb_rxmode.h b/drivers/net/nfb/nfb_rxmode.h
new file mode 100644
index 0000000..051130f
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.h
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_RXMODE_H_
+#define _NFB_RXMODE_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_ethdev.h>
+#include <rte_dev.h>
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Getter for promiscuous mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int __rte_experimental
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to enable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void __rte_experimental
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to disable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void __rte_experimental
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Getter for allmulticast mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int __rte_experimental
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to enable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void __rte_experimental
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to disable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void __rte_experimental
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev);
+
+#endif /* _NFB_RXMODE_H_ */
diff --git a/drivers/net/nfb/nfb_stats.c b/drivers/net/nfb/nfb_stats.c
new file mode 100644
index 0000000..a4f22c8
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.c
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_stats.h"
+#include "nfb.h"
+
+int __rte_experimental
+nfb_eth_stats_get(struct rte_eth_dev *dev,
+	struct rte_eth_stats *stats)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+	uint64_t rx_total = 0;
+	uint64_t tx_total = 0;
+	uint64_t tx_err_total = 0;
+	uint64_t rx_total_bytes = 0;
+	uint64_t tx_total_bytes = 0;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_ipackets[i] = rx_queue[i].rx_pkts;
+			stats->q_ibytes[i] = rx_queue[i].rx_bytes;
+		}
+		rx_total += stats->q_ipackets[i];
+		rx_total_bytes += stats->q_ibytes[i];
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_opackets[i] = tx_queue[i].tx_pkts;
+			stats->q_obytes[i] = tx_queue[i].tx_bytes;
+		}
+		tx_total += stats->q_opackets[i];
+		tx_total_bytes += stats->q_obytes[i];
+		tx_err_total += tx_queue[i].err_pkts;
+	}
+
+	stats->ipackets = rx_total;
+	stats->opackets = tx_total;
+	stats->ibytes = rx_total_bytes;
+	stats->obytes = tx_total_bytes;
+	stats->oerrors = tx_err_total;
+	return 0;
+}
+
+void __rte_experimental
+nfb_eth_stats_reset(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		rx_queue[i].rx_pkts = 0;
+		rx_queue[i].rx_bytes = 0;
+		rx_queue[i].err_pkts = 0;
+	}
+	for (i = 0; i < nb_tx; i++) {
+		tx_queue[i].tx_pkts = 0;
+		tx_queue[i].tx_bytes = 0;
+		tx_queue[i].err_pkts = 0;
+	}
+}
diff --git a/drivers/net/nfb/nfb_stats.h b/drivers/net/nfb/nfb_stats.h
new file mode 100644
index 0000000..85439c6
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_STATS_H_
+#define _NFB_STATS_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to get device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] stats
+ *   Stats structure output buffer.
+ *
+ * @return
+ *   0 on success and stats is filled, negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to clear device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void __rte_experimental
+nfb_eth_stats_reset(struct rte_eth_dev *dev);
+
+#endif /* _NFB_STATS_H_ */
diff --git a/drivers/net/nfb/nfb_tx.c b/drivers/net/nfb/nfb_tx.c
new file mode 100644
index 0000000..8ef756b
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.c
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_tx.h"
+#include "nfb.h"
+
+int __rte_experimental
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+	int ret;
+
+	if (txq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_start(txq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+int __rte_experimental
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+	int ret;
+
+	if (txq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "TX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_stop(txq->queue);
+	if (ret != 0)
+		return -EINVAL;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int __rte_experimental
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	int ret;
+	struct ndp_tx_queue *txq;
+
+	txq = rte_zmalloc_socket("ndp tx queue",
+		sizeof(struct ndp_tx_queue),
+		RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (txq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for tx queue id "
+			"%" PRIu16 "!\n", tx_queue_id);
+		return -ENOMEM;
+	}
+
+	ret = nfb_eth_tx_queue_init(internals->nfb,
+		tx_queue_id,
+		txq);
+
+	if (ret == 0)
+		dev->data->tx_queues[tx_queue_id] = txq;
+	else
+		rte_free(txq);
+
+	return ret;
+}
+
+int __rte_experimental
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq)
+{
+	if (nfb == NULL)
+		return -EINVAL;
+
+	txq->queue = ndp_open_tx_queue(nfb, tx_queue_id);
+	if (txq->queue == NULL)
+		return -EINVAL;
+
+	txq->nfb = nfb;
+	txq->tx_queue_id = tx_queue_id;
+
+	txq->tx_pkts = 0;
+	txq->tx_bytes = 0;
+	txq->err_pkts = 0;
+
+	return 0;
+}
+
+void __rte_experimental
+nfb_eth_tx_queue_release(void *q)
+{
+	struct ndp_tx_queue *txq = (struct ndp_tx_queue *)q;
+	if (txq->queue != NULL) {
+		ndp_close_tx_queue(txq->queue);
+		rte_free(txq);
+		txq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_tx.h b/drivers/net/nfb/nfb_tx.h
new file mode 100644
index 0000000..32a1bdb
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.h
@@ -0,0 +1,222 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_TX_H_
+#define _NFB_TX_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+struct ndp_tx_queue {
+	struct nfb_device *nfb;     /* nfb dev structure */
+	struct ndp_queue *queue;    /* tx queue */
+	uint16_t          tx_queue_id;       /* index */
+	volatile uint64_t tx_pkts;  /* packets transmitted */
+	volatile uint64_t tx_bytes; /* bytes transmitted */
+	volatile uint64_t err_pkts; /* erroneous packets */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to setup a TX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mp
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Initialize ndp_tx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param tx_queue_id
+ *   TX queue index.
+ * @param[out] txq
+ *   Pointer to ndp_tx_queue output structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void __rte_experimental
+nfb_eth_tx_queue_release(void *q);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Start traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Stop traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback for TX.
+ *
+ * @param dpdk_txq
+ *   Generic pointer to TX queue structure.
+ * @param bufs
+ *   Packets to transmit.
+ * @param nb_pkts
+ *   Number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully transmitted (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t __rte_experimental
+nfb_eth_ndp_tx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	int i;
+	struct rte_mbuf *mbuf;
+	struct ndp_tx_queue *ndp = queue;
+	uint16_t num_tx = 0;
+	uint64_t num_bytes = 0;
+
+	void *dst;
+	uint32_t pkt_len;
+	uint8_t mbuf_segs;
+
+	struct ndp_packet packets[nb_pkts];
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "TX invalid arguments!\n");
+		return 0;
+	}
+
+	for (i = 0; i < nb_pkts; i++) {
+		packets[i].data_length = bufs[i]->pkt_len;
+		packets[i].header_length = 0;
+	}
+
+	num_tx = ndp_tx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_tx != nb_pkts))
+		return 0;
+
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = bufs[i];
+
+		pkt_len = mbuf->pkt_len;
+		mbuf_segs = mbuf->nb_segs;
+
+		num_bytes += pkt_len;
+		if (mbuf_segs == 1) {
+			/*
+			 * non-scattered packet,
+			 * transmit from one mbuf
+			 */
+			rte_memcpy(packets[i].data,
+				rte_pktmbuf_mtod(mbuf, const void *),
+				pkt_len);
+		} else {
+			/* scattered packet, transmit from more mbufs */
+			struct rte_mbuf *m = mbuf;
+			while (m) {
+				dst = packets[i].data;
+
+				rte_memcpy(dst,
+					rte_pktmbuf_mtod(m,
+					const void *),
+					m->data_len);
+				dst = ((uint8_t *)(dst)) +
+					m->data_len;
+				m = m->next;
+			}
+		}
+
+		rte_pktmbuf_free(mbuf);
+	}
+
+	ndp_tx_burst_flush(ndp->queue);
+
+	ndp->tx_pkts += num_tx;
+	ndp->err_pkts += nb_pkts - num_tx;
+	ndp->tx_bytes += num_bytes;
+	return num_tx;
+}
+
+#endif /* _NFB_TX_H_ */
diff --git a/drivers/net/nfb/rte_nfb_pmd_version.map b/drivers/net/nfb/rte_nfb_pmd_version.map
new file mode 100644
index 0000000..66748c0
--- /dev/null
+++ b/drivers/net/nfb/rte_nfb_pmd_version.map
@@ -0,0 +1,4 @@
+EXPERIMENTAL {
+
+        local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 8a4f0f4..1511fe3 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -196,6 +196,8 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC)      += -lrte_pmd_softnic
 endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD)    += -lrte_pmd_sfc_efx
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2 -lsze2
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NFB)        += -lrte_pmd_nfb
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NFB)        +=  $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --libs netcope-common)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_TAP)        += -lrte_pmd_tap
 _LDLIBS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += -lrte_pmd_thunderx_nicvf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD) += -lrte_pmd_vdev_netvsc
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [dpdk-dev] [PATCH v5] net/nfb: new netcope driver
  2019-03-22 12:12   ` [dpdk-dev] [PATCH v5] " Rastislav Cernay
@ 2019-03-22 12:12     ` Rastislav Cernay
  2019-03-28 16:01     ` Ferruh Yigit
  1 sibling, 0 replies; 50+ messages in thread
From: Rastislav Cernay @ 2019-03-22 12:12 UTC (permalink / raw)
  To: dev; +Cc: Rastislav Cernay

From: Rastislav Cernay <cernay@netcope.com>

Added new net driver for Netcope nfb cards

Signed-off-by: Rastislav Cernay <cernay@netcope.com>
---
v2: remove unnecessary cast
    remove unnecessary zeroing
    move declaration to not mix with code
    restore skeleton example
v3: add release notes
    add doc to doc index
    add architecture limits to doc
    edit features list
    add .map file
    change link to dependecies to official vendor site
    move declarations out of code
    remove false comments (rte_errno is set)
    comments to c89 style
    remove log from main rx loop
    remove redundant code
v4: API is experimental
    fixed meson build dependency
    random initial MAC
    stats->q_errors is for intput err only
    move more declarations to a beginning
    fixed err log in TX
    use of pkg-config
v5: fixed pkg-config for new version of netcope-common
 MAINTAINERS                             |   7 +
 config/common_base                      |   4 +
 devtools/test-build.sh                  |   1 +
 doc/guides/nics/features/nfb.ini        |  18 +
 doc/guides/nics/index.rst               |   1 +
 doc/guides/nics/nfb.rst                 | 143 +++++++
 doc/guides/rel_notes/release_19_02.rst  |   5 +
 drivers/net/Makefile                    |   1 +
 drivers/net/meson.build                 |   1 +
 drivers/net/nfb/Makefile                |  44 +++
 drivers/net/nfb/meson.build             |  15 +
 drivers/net/nfb/nfb.h                   |  50 +++
 drivers/net/nfb/nfb_ethdev.c            | 647 ++++++++++++++++++++++++++++++++
 drivers/net/nfb/nfb_rx.c                | 127 +++++++
 drivers/net/nfb/nfb_rx.h                | 231 ++++++++++++
 drivers/net/nfb/nfb_rxmode.c            | 100 +++++
 drivers/net/nfb/nfb_rxmode.h            |  96 +++++
 drivers/net/nfb/nfb_stats.c             |  77 ++++
 drivers/net/nfb/nfb_stats.h             |  56 +++
 drivers/net/nfb/nfb_tx.c                | 113 ++++++
 drivers/net/nfb/nfb_tx.h                | 222 +++++++++++
 drivers/net/nfb/rte_nfb_pmd_version.map |   4 +
 mk/rte.app.mk                           |   2 +
 23 files changed, 1965 insertions(+)
 create mode 100644 doc/guides/nics/features/nfb.ini
 create mode 100644 doc/guides/nics/nfb.rst
 create mode 100644 drivers/net/nfb/Makefile
 create mode 100644 drivers/net/nfb/meson.build
 create mode 100644 drivers/net/nfb/nfb.h
 create mode 100644 drivers/net/nfb/nfb_ethdev.c
 create mode 100644 drivers/net/nfb/nfb_rx.c
 create mode 100644 drivers/net/nfb/nfb_rx.h
 create mode 100644 drivers/net/nfb/nfb_rxmode.c
 create mode 100644 drivers/net/nfb/nfb_rxmode.h
 create mode 100644 drivers/net/nfb/nfb_stats.c
 create mode 100644 drivers/net/nfb/nfb_stats.h
 create mode 100644 drivers/net/nfb/nfb_tx.c
 create mode 100644 drivers/net/nfb/nfb_tx.h
 create mode 100644 drivers/net/nfb/rte_nfb_pmd_version.map

diff --git a/MAINTAINERS b/MAINTAINERS
index 6610440..436f3d2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -654,6 +654,13 @@ F: drivers/net/szedata2/
 F: doc/guides/nics/szedata2.rst
 F: doc/guides/nics/features/szedata2.ini
 
+Netcope nfb - EXPERIMENTAL
+M: Rastislav Cernay <cernay@netcope.com>
+M: Jan Remes <remes@netcope.com>
+F: drivers/net/nfb/
+F: doc/guides/nics/nfb.rst
+F: doc/guides/nics/features/nfb.ini
+
 Netronome nfp
 M: Alejandro Lucero <alejandro.lucero@netronome.com>
 F: drivers/net/nfp/
diff --git a/config/common_base b/config/common_base
index 7c6da51..1ab0a6b 100644
--- a/config/common_base
+++ b/config/common_base
@@ -360,6 +360,10 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
 # Compile software PMD backed by SZEDATA2 device
 #
 CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
+#
+# Compile software PMD backed by NFB device
+#
+CONFIG_RTE_LIBRTE_PMD_NFB=n
 
 #
 # Compile burst-oriented Cavium Thunderx NICVF PMD driver
diff --git a/devtools/test-build.sh b/devtools/test-build.sh
index 42f4ad0..ab57ab8 100755
--- a/devtools/test-build.sh
+++ b/devtools/test-build.sh
@@ -18,6 +18,7 @@ default_path=$PATH
 # - DPDK_DEP_SSL (y/[n])
 # - DPDK_DEP_IPSEC_MB (y/[n])
 # - DPDK_DEP_SZE (y/[n])
+# - DPDK_DEP_NFB (y/[n])
 # - DPDK_DEP_ZLIB (y/[n])
 # - DPDK_MAKE_JOBS (int)
 # - DPDK_NOTIFY (notify-send)
diff --git a/doc/guides/nics/features/nfb.ini b/doc/guides/nics/features/nfb.ini
new file mode 100644
index 0000000..e1c5266
--- /dev/null
+++ b/doc/guides/nics/features/nfb.ini
@@ -0,0 +1,18 @@
+;
+; Supported features of the 'nfb' network poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Speed capabilities   = P
+Link status          = Y
+Queue start/stop     = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Basic stats          = Y
+Extended stats       = Y
+Stats per queue      = Y
+Other kdrv           = Y
+x86-64               = Y
+Usage doc            = Y
+Scattered Tx         = Y
diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index 5c80e3b..079972e 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -39,6 +39,7 @@ Network Interface Controller Drivers
     mvneta
     mvpp2
     netvsc
+    nfb
     nfp
     octeontx
     qede
diff --git a/doc/guides/nics/nfb.rst b/doc/guides/nics/nfb.rst
new file mode 100644
index 0000000..8c0be40
--- /dev/null
+++ b/doc/guides/nics/nfb.rst
@@ -0,0 +1,143 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright 2015 - 2016 CESNET
+
+NFB poll mode driver library
+=================================
+
+The NFB poll mode driver library implements support for the Netcope
+FPGA Boards (**NFB-***), FPGA-based programmable NICs.
+The NFB PMD uses interface provided by the libnfb library to communicate
+with the NFB cards over the nfb layer.
+
+More information about the
+`NFB cards <http://www.netcope.com/en/products/fpga-boards>`_
+and used technology
+(`Netcope Development Kit <http://www.netcope.com/en/products/fpga-development-kit>`_)
+can be found on the `Netcope Technologies website <http://www.netcope.com/>`_.
+
+.. note::
+
+   This driver has external dependencies.
+   Therefore it is disabled in default configuration files.
+   It can be enabled by setting ``CONFIG_RTE_LIBRTE_PMD_NFB=y``
+   and recompiling.
+
+.. note::
+
+   Currently the driver is supported only on x86_64 architectures.
+   Only x86_64 versions of the external libraries are provided.
+
+Prerequisites
+-------------
+
+This PMD requires kernel modules which are responsible for initialization and
+allocation of resources needed for nfb layer function.
+Communication between PMD and kernel modules is mediated by libnfb library.
+These kernel modules and library are not part of DPDK and must be installed
+separately:
+
+*  **libnfb library**
+
+   The library provides API for initialization of nfb transfers, receiving and
+   transmitting data segments.
+
+*  **Kernel modules**
+
+   * nfb
+
+   Kernel modules manage initialization of hardware, allocation and
+   sharing of resources for user space applications.
+
+Dependencies can be found here:
+`Netcope common <https://www.netcope.com/en/company/community-support/dpdk-libsze2#NFB>`_.
+
+Versions of the packages
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The minimum version of the provided packages:
+
+* for DPDK from 19.02
+
+Configuration
+-------------
+
+These configuration options can be modified before compilation in the
+``.config`` file:
+
+*  ``CONFIG_RTE_LIBRTE_PMD_NFB`` default value: **n**
+
+   Value **y** enables compilation of nfb PMD.
+
+Using the NFB PMD
+----------------------
+
+Kernel modules have to be loaded before running the DPDK application.
+
+NFB card architecture
+---------------------
+
+The NFB cards are multi-port multi-queue cards, where (generally) data from any
+Ethernet port may be sent to any queue.
+They are represented in DPDK as a single port.
+
+NFB-200G2QL card employs an addon cable which allows to connect it to two
+physical PCI-E slots at the same time (see the diagram below).
+This is done to allow 200 Gbps of traffic to be transferred through the PCI-E
+bus (note that a single PCI-E 3.0 x16 slot provides only 125 Gbps theoretical
+throughput).
+
+Although each slot may be connected to a different CPU and therefore to a different
+NUMA node, the card is represented as a single port in DPDK. To work with data
+from the individual queues on the right NUMA node, connection of NUMA nodes on
+first and last queue (each NUMA node has half of the queues) need to be checked.
+
+.. figure:: img/szedata2_nfb200g_architecture.svg
+    :align: center
+
+    NFB-200G2QL high-level diagram
+
+Limitations
+-----------
+
+Driver is usable only on Linux architecture.
+
+Since a card is always represented as a single port, but can be connected to two
+NUMA nodes, there is need for manual check where master/slave is connected.
+
+Example of usage
+----------------
+
+Read packets from 0. and 1. receive queue and write them to 0. and 1.
+transmit queue:
+
+.. code-block:: console
+
+   $RTE_TARGET/app/testpmd -l 0-3 -n 2 \
+   -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2 -i -a
+
+Example output:
+
+.. code-block:: console
+
+   [...]
+   EAL: PCI device 0000:06:00.0 on NUMA socket -1
+   EAL:   probe driver: 1b26:c1c1 net_nfb
+   PMD: Initializing NFB device (0000:06:00.0)
+   PMD: Available DMA queues RX: 8 TX: 8
+   PMD: NFB device (0000:06:00.0) successfully initialized
+   Interactive-mode selected
+   Auto-start selected
+   Configuring Port 0 (socket 0)
+   Port 0: 00:11:17:00:00:00
+   Checking link statuses...
+   Port 0 Link Up - speed 10000 Mbps - full-duplex
+   Done
+   Start automatic packet forwarding
+     io packet forwarding - CRC stripping disabled - packets/burst=32
+     nb forwarding cores=2 - nb forwarding ports=1
+     RX queues=2 - RX desc=128 - RX free threshold=0
+     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX queues=2 - TX desc=512 - TX free threshold=0
+     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX RS bit threshold=0 - TXQ flags=0x0
+   testpmd>
diff --git a/doc/guides/rel_notes/release_19_02.rst b/doc/guides/rel_notes/release_19_02.rst
index 3372c4d..9955b6b 100644
--- a/doc/guides/rel_notes/release_19_02.rst
+++ b/doc/guides/rel_notes/release_19_02.rst
@@ -54,6 +54,11 @@ New Features
      Also, make sure to start the actual text at the margin.
      =========================================================
 
+* **Added an experimental net PMD NFB.**
+
+  Added the new ``nfb`` net driver for Netcope NFB cards. See
+  the :doc:`../nics/nfb` NIC guide for more details on this new driver.
+
 * **Added support to free hugepages exactly as originally allocated.**
 
   Some applications using memory event callbacks (especially for managing
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 670d7f7..013c551 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -38,6 +38,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5
 DIRS-$(CONFIG_RTE_LIBRTE_MVNETA_PMD) += mvneta
 DIRS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mvpp2
 DIRS-$(CONFIG_RTE_LIBRTE_NETVSC_PMD) += netvsc
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb
 DIRS-$(CONFIG_RTE_LIBRTE_NFP_PMD) += nfp
 DIRS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += null
diff --git a/drivers/net/meson.build b/drivers/net/meson.build
index 45da3bb..6733a19 100644
--- a/drivers/net/meson.build
+++ b/drivers/net/meson.build
@@ -27,6 +27,7 @@ drivers = ['af_packet',
 	'mvneta',
 	'mvpp2',
 	'netvsc',
+	'nfb',
 	'nfp',
 	'null', 'octeontx', 'pcap', 'qede', 'ring',
 	'sfc',
diff --git a/drivers/net/nfb/Makefile b/drivers/net/nfb/Makefile
new file mode 100644
index 0000000..e7189dc
--- /dev/null
+++ b/drivers/net/nfb/Makefile
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Cesnet
+# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_nfb.a
+
+INCLUDES :=-I$(SRCDIR)
+
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --cflags netcope-common)
+LDLIBS += -lnfb
+LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
+LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
+LDLIBS += -lrte_bus_pci
+LDLIBS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --libs netcope-common)
+
+EXPORT_MAP := rte_pmd_nfb_version.map
+
+LIBABIVER := 1
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_rx.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_tx.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_stats.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_NFB) += nfb_rxmode.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/nfb/meson.build b/drivers/net/nfb/meson.build
new file mode 100644
index 0000000..16df146
--- /dev/null
+++ b/drivers/net/nfb/meson.build
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Cesnet
+# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+dep = cc.find_library('nfb', required: false)
+
+build = dep.found() and cc.has_header('nfb/nfb.h', dependencies: dep)
+
+allow_experimental_apis = true
+
+ext_deps += dep
+
+sources = files('nfb_rx.c', 'nfb_tx.c', 'nfb_stats.c', 'nfb_ethdev.c', 'nfb_rxmode.c')
+pkgconfig_extra_libs += '-lnfb'
diff --git a/drivers/net/nfb/nfb.h b/drivers/net/nfb/nfb.h
new file mode 100644
index 0000000..42671a1
--- /dev/null
+++ b/drivers/net/nfb/nfb.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_H_
+#define _NFB_H_
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+
+/* PCI Vendor ID */
+#define PCI_VENDOR_ID_NETCOPE 0x1b26
+
+/* PCI Device IDs */
+#define PCI_DEVICE_ID_NFB_40G2  0xcb80
+#define PCI_DEVICE_ID_NFB_100G2 0xc2c1
+#define PCI_DEVICE_ID_NFB_200G2QL 0xc250
+
+/* Max index of ndp rx/tx queues */
+#define RTE_ETH_NDP_MAX_RX_QUEUES 32
+#define RTE_ETH_NDP_MAX_TX_QUEUES 32
+
+/* Max index of rx/tx dmas */
+#define RTE_MAX_NC_RXMAC 256
+#define RTE_MAX_NC_TXMAC 256
+
+#define RTE_NFB_DRIVER_NAME net_nfb
+
+struct pmd_internals {
+	uint16_t         max_rxmac;
+	uint16_t         max_txmac;
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC];
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC];
+
+	char             nfb_dev[PATH_MAX];
+	struct nfb_device *nfb;
+	/* Place to remember if filter was promiscuous or filtering by table,
+	 * when disabling allmulticast
+	 */
+	enum nc_rxmac_mac_filter rx_filter_original;
+};
+
+#endif /* _NFB_H_ */
diff --git a/drivers/net/nfb/nfb_ethdev.c b/drivers/net/nfb/nfb_ethdev.c
new file mode 100644
index 0000000..a5a6bdc
--- /dev/null
+++ b/drivers/net/nfb/nfb_ethdev.c
@@ -0,0 +1,647 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_kvargs.h>
+#include <rte_dev.h>
+#include <rte_common.h>
+
+#include "nfb_stats.h"
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+/**
+ * Default MAC addr
+ */
+static struct ether_addr eth_addr = {
+	.addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Open all RX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] rxmac
+ *   Pointer to output array of nc_rxmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of rxmac
+ */
+static void __rte_experimental
+nfb_nc_rxmac_init(struct nfb_device *nfb,
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t *max_rxmac)
+{
+	*max_rxmac = 0;
+	while ((rxmac[*max_rxmac] = nc_rxmac_open_index(nfb, *max_rxmac)))
+		++(*max_rxmac);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Open all TX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] txmac
+ *   Pointer to output array of nc_txmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of txmac
+ */
+static void __rte_experimental
+nfb_nc_txmac_init(struct nfb_device *nfb,
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t *max_txmac)
+{
+	*max_txmac = 0;
+	while ((txmac[*max_txmac] = nc_txmac_open_index(nfb, *max_txmac)))
+		++(*max_txmac);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Close all RX DMA queues
+ *
+ * @param rxmac
+ *   Pointer to array of nc_rxmac
+ * @param max_rxmac
+ *   Maximum index of rxmac
+ */
+static void __rte_experimental
+nfb_nc_rxmac_deinit(struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t max_rxmac)
+{
+	for (; max_rxmac > 0; --max_rxmac) {
+		nc_rxmac_close(rxmac[max_rxmac]);
+		rxmac[max_rxmac] = NULL;
+	}
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Close all TX DMA queues
+ *
+ * @param txmac
+ *   Pointer to array of nc_txmac
+ * @param max_txmac
+ *   Maximum index of txmac
+ */
+static void __rte_experimental
+nfb_nc_txmac_deinit(struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t max_txmac)
+{
+	for (; max_txmac > 0; --max_txmac) {
+		nc_txmac_close(txmac[max_txmac]);
+		txmac[max_txmac] = NULL;
+	}
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to start the device.
+ *
+ * Start device by starting all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_dev_start(struct rte_eth_dev *dev)
+{
+	int ret;
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_rx; i++) {
+		ret = nfb_eth_rx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_rx;
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		ret = nfb_eth_tx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_tx;
+	}
+
+	return 0;
+
+err_tx:
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+err_rx:
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+	return ret;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to stop the device.
+ *
+ * Stop device by stopping all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void __rte_experimental
+nfb_eth_dev_stop(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback for Ethernet device configuration.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to get information about the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] info
+ *   Info structure output buffer.
+ */
+static void __rte_experimental
+nfb_eth_dev_info(struct rte_eth_dev *dev,
+	struct rte_eth_dev_info *dev_info)
+{
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = dev->data->nb_rx_queues;
+	dev_info->max_tx_queues = dev->data->nb_tx_queues;
+	dev_info->speed_capa = ETH_LINK_SPEED_100G;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to close the device.
+ *
+ * Destroy all queues and objects, free memory.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void __rte_experimental
+nfb_eth_dev_close(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	nfb_eth_dev_stop(dev);
+
+	for (i = 0; i < nb_rx; i++) {
+		nfb_eth_rx_queue_release(dev->data->rx_queues[i]);
+		dev->data->rx_queues[i] = NULL;
+	}
+	dev->data->nb_rx_queues = 0;
+	for (i = 0; i < nb_tx; i++) {
+		nfb_eth_tx_queue_release(dev->data->tx_queues[i]);
+		dev->data->tx_queues[i] = NULL;
+	}
+	dev->data->nb_tx_queues = 0;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to retrieve physical link information.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] link
+ *   Storage for current link status.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_link_update(struct rte_eth_dev *dev,
+	int wait_to_complete __rte_unused)
+{
+	uint16_t i;
+	struct nc_rxmac_status status;
+	struct rte_eth_link link;
+	memset(&link, 0, sizeof(link));
+
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	status.speed = MAC_SPEED_UNKNOWN;
+
+	link.link_speed = ETH_SPEED_NUM_NONE;
+	link.link_status = ETH_LINK_DOWN;
+	link.link_duplex = ETH_LINK_FULL_DUPLEX;
+	link.link_autoneg = ETH_LINK_SPEED_FIXED;
+
+	if (internals->rxmac[0] != NULL) {
+		nc_rxmac_read_status(internals->rxmac[0], &status);
+
+		switch (status.speed) {
+		case MAC_SPEED_10G:
+			link.link_speed = ETH_SPEED_NUM_10G;
+			break;
+		case MAC_SPEED_40G:
+			link.link_speed = ETH_SPEED_NUM_40G;
+			break;
+		case MAC_SPEED_100G:
+			link.link_speed = ETH_SPEED_NUM_100G;
+			break;
+		default:
+			link.link_speed = ETH_SPEED_NUM_NONE;
+			break;
+		}
+	}
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_read_status(internals->rxmac[i], &status);
+
+		if (status.enabled && status.link_up) {
+			link.link_status = ETH_LINK_UP;
+			break;
+		}
+	}
+
+	rte_eth_linkstatus_set(dev, &link);
+
+	return 0;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to bring the link UP.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_dev_set_link_up(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_enable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_enable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to bring the link DOWN.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_dev_set_link_down(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_disable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_disable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to set primary MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_mac_addr_set(struct rte_eth_dev *dev,
+	struct ether_addr *mac_addr)
+{
+	unsigned int i;
+	unsigned long long mac = 0;
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+
+	if (!is_valid_assigned_ether_addr(mac_addr))
+		return -EINVAL;
+
+	for (i = 0; i < 6; i++) {
+		mac <<= 8;
+		mac |= mac_addr->addr_bytes[i] & 0xFF;
+	}
+
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_set_mac(internals->rxmac[i], 0, mac, 1);
+
+	ether_addr_copy(mac_addr, data->mac_addrs);
+	return 0;
+}
+
+static const struct eth_dev_ops ops = {
+	.dev_start = nfb_eth_dev_start,
+	.dev_stop = nfb_eth_dev_stop,
+	.dev_set_link_up = nfb_eth_dev_set_link_up,
+	.dev_set_link_down = nfb_eth_dev_set_link_down,
+	.dev_close = nfb_eth_dev_close,
+	.dev_configure = nfb_eth_dev_configure,
+	.dev_infos_get = nfb_eth_dev_info,
+	.promiscuous_enable = nfb_eth_promiscuous_enable,
+	.promiscuous_disable = nfb_eth_promiscuous_disable,
+	.allmulticast_enable = nfb_eth_allmulticast_enable,
+	.allmulticast_disable = nfb_eth_allmulticast_disable,
+	.rx_queue_start = nfb_eth_rx_queue_start,
+	.rx_queue_stop = nfb_eth_rx_queue_stop,
+	.tx_queue_start = nfb_eth_tx_queue_start,
+	.tx_queue_stop = nfb_eth_tx_queue_stop,
+	.rx_queue_setup = nfb_eth_rx_queue_setup,
+	.tx_queue_setup = nfb_eth_tx_queue_setup,
+	.rx_queue_release = nfb_eth_rx_queue_release,
+	.tx_queue_release = nfb_eth_tx_queue_release,
+	.link_update = nfb_eth_link_update,
+	.stats_get = nfb_eth_stats_get,
+	.stats_reset = nfb_eth_stats_reset,
+	.mac_addr_set = nfb_eth_mac_addr_set,
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to initialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_dev_init(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+	struct ether_addr eth_addr_init;
+
+	RTE_LOG(INFO, PMD, "Initializing NFB device (" PCI_PRI_FMT ")\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	snprintf(internals->nfb_dev, PATH_MAX,
+		"/dev/nfb/by-pci-slot/" PCI_PRI_FMT,
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	/*
+	 * Get number of available DMA RX and TX queues, which is maximum
+	 * number of queues that can be created and store it in private device
+	 * data structure.
+	 */
+	internals->nfb = nfb_open(internals->nfb_dev);
+	if (internals->nfb == NULL) {
+		RTE_LOG(ERR, PMD, "nfb_open(): failed to open %s",
+			internals->nfb_dev);
+		return -EINVAL;
+	}
+	data->nb_rx_queues = ndp_get_rx_queue_available_count(internals->nfb);
+	data->nb_tx_queues = ndp_get_tx_queue_available_count(internals->nfb);
+
+	RTE_LOG(INFO, PMD, "Available NDP queues RX: %u TX: %u\n",
+		data->nb_rx_queues, data->nb_tx_queues);
+
+	nfb_nc_rxmac_init(internals->nfb,
+		internals->rxmac,
+		&internals->max_rxmac);
+	nfb_nc_txmac_init(internals->nfb,
+		internals->txmac,
+		&internals->max_txmac);
+
+	/* Set rx, tx burst functions */
+	dev->rx_pkt_burst = nfb_eth_ndp_rx;
+	dev->tx_pkt_burst = nfb_eth_ndp_tx;
+
+	/* Set function callbacks for Ethernet API */
+	dev->dev_ops = &ops;
+
+	/* Get link state */
+	nfb_eth_link_update(dev, 0);
+
+	/* Allocate space for one mac address */
+	data->mac_addrs = rte_zmalloc(data->name, sizeof(struct ether_addr),
+		RTE_CACHE_LINE_SIZE);
+	if (data->mac_addrs == NULL) {
+		RTE_LOG(ERR, PMD, "Could not alloc space for MAC address!\n");
+		nfb_close(internals->nfb);
+		return -EINVAL;
+	}
+
+	eth_random_addr(eth_addr_init.addr_bytes);
+	eth_addr_init.addr_bytes[0] = eth_addr.addr_bytes[0];
+	eth_addr_init.addr_bytes[1] = eth_addr.addr_bytes[1];
+	eth_addr_init.addr_bytes[2] = eth_addr.addr_bytes[2];
+
+	nfb_eth_mac_addr_set(dev, &eth_addr_init);
+
+	data->promiscuous = nfb_eth_promiscuous_get(dev);
+	data->all_multicast = nfb_eth_allmulticast_get(dev);
+	internals->rx_filter_original = data->promiscuous;
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully initialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to uninitialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_dev_uninit(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+
+	dev->data->mac_addrs = NULL;
+
+	nfb_nc_rxmac_deinit(internals->rxmac, internals->max_rxmac);
+	nfb_nc_txmac_deinit(internals->txmac, internals->max_txmac);
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully uninitialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+static const struct rte_pci_id nfb_pci_id_table[] = {
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_40G2) },
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_100G2) },
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_200G2QL) },
+	{ .vendor_id = 0, }
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to register a PCI device.
+ *
+ * This function spawns Ethernet devices out of a given PCI device.
+ *
+ * @param[in] pci_drv
+ *   PCI driver structure (nfb_driver).
+ * @param[in] pci_dev
+ *   PCI device information.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int __rte_experimental
+nfb_eth_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+		struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_probe(pci_dev,
+		sizeof(struct pmd_internals), nfb_eth_dev_init);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to remove a PCI device.
+ *
+ * This function removes all Ethernet devices belong to a given PCI device.
+ *
+ * @param[in] pci_dev
+ *   Pointer to the PCI device.
+ *
+ * @return
+ *   0 on success, the function cannot fail.
+ */
+static int __rte_experimental
+nfb_eth_pci_remove(struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_remove(pci_dev, nfb_eth_dev_uninit);
+}
+
+static struct rte_pci_driver nfb_eth_driver = {
+	.id_table = nfb_pci_id_table,
+	.probe = nfb_eth_pci_probe,
+	.remove = nfb_eth_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(RTE_NFB_DRIVER_NAME, nfb_eth_driver);
+RTE_PMD_REGISTER_PCI_TABLE(RTE_NFB_DRIVER_NAME, nfb_pci_id_table);
+RTE_PMD_REGISTER_KMOD_DEP(RTE_NFB_DRIVER_NAME, "* nfb");
diff --git a/drivers/net/nfb/nfb_rx.c b/drivers/net/nfb/nfb_rx.c
new file mode 100644
index 0000000..7026c1b
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.c
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_rx.h"
+#include "nfb.h"
+
+int __rte_experimental
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+	int ret;
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_start(rxq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+int __rte_experimental
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+	int ret;
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_stop(rxq->queue);
+	if (ret != 0)
+		return -EINVAL;
+
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int __rte_experimental
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+		uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	struct ndp_rx_queue *rxq;
+	int ret;
+
+	rxq = rte_zmalloc_socket("ndp rx queue",
+			sizeof(struct ndp_rx_queue),
+			RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (rxq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for rx queue id "
+				"%" PRIu16 "!\n", rx_queue_id);
+		return -ENOMEM;
+	}
+
+	ret = nfb_eth_rx_queue_init(internals->nfb,
+		rx_queue_id,
+		dev->data->port_id,
+		mb_pool,
+		rxq);
+
+	if (ret == 0)
+		dev->data->rx_queues[rx_queue_id] = rxq;
+	else
+		rte_free(rxq);
+
+	return ret;
+}
+
+int __rte_experimental
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+		uint16_t rx_queue_id,
+		uint16_t port_id,
+		struct rte_mempool *mb_pool,
+		struct ndp_rx_queue *rxq)
+{
+	const struct rte_pktmbuf_pool_private *mbp_priv =
+		rte_mempool_get_priv(mb_pool);
+
+	if (nfb == NULL)
+		return -EINVAL;
+
+	rxq->queue = ndp_open_rx_queue(nfb, rx_queue_id);
+	if (rxq->queue == NULL)
+		return -EINVAL;
+
+	rxq->nfb = nfb;
+	rxq->rx_queue_id = rx_queue_id;
+	rxq->in_port = port_id;
+	rxq->mb_pool = mb_pool;
+	rxq->buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size -
+		RTE_PKTMBUF_HEADROOM);
+
+	rxq->rx_pkts = 0;
+	rxq->rx_bytes = 0;
+	rxq->err_pkts = 0;
+
+	return 0;
+}
+
+void __rte_experimental
+nfb_eth_rx_queue_release(void *q)
+{
+	struct ndp_rx_queue *rxq = (struct ndp_rx_queue *)q;
+	if (rxq->queue != NULL) {
+		ndp_close_rx_queue(rxq->queue);
+		rte_free(rxq);
+		rxq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_rx.h b/drivers/net/nfb/nfb_rx.h
new file mode 100644
index 0000000..772ccfc
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.h
@@ -0,0 +1,231 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_RX_H_
+#define _NFB_RX_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+struct ndp_rx_queue {
+	struct nfb_device *nfb;	     /* nfb dev structure */
+	struct ndp_queue *queue;     /* rx queue */
+	uint16_t rx_queue_id;	     /* index */
+	uint8_t in_port;	     /* port */
+
+	struct rte_mempool *mb_pool; /* memory pool to allocate packets */
+	uint16_t buf_size;           /* mbuf size */
+
+	volatile uint64_t rx_pkts;   /* packets read */
+	volatile uint64_t rx_bytes;  /* bytes read */
+	volatile uint64_t err_pkts;  /* erroneous packets */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Initialize ndp_rx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param rx_queue_id
+ *   RX queue index.
+ * @param port_id
+ *   Device [external] port identifier.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ * @param[out] rxq
+ *   Pointer to ndp_rx_queue output structure
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+	uint16_t rx_queue_id,
+	uint16_t port_id,
+	struct rte_mempool *mb_pool,
+	struct ndp_rx_queue *rxq);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to setup a RX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t rx_queue_id,
+	uint16_t nb_rx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_rxconf *rx_conf __rte_unused,
+	struct rte_mempool *mb_pool);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void __rte_experimental
+nfb_eth_rx_queue_release(void *q);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Start traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Stop traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ */
+int __rte_experimental
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback for RX.
+ *
+ * @param dpdk_rxq
+ *   Generic pointer to RX queue structure.
+ * @param[out] bufs
+ *   Array to store received packets.
+ * @param nb_pkts
+ *   Maximum number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully received (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t __rte_experimental
+nfb_eth_ndp_rx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	struct ndp_rx_queue *ndp = queue;
+	uint16_t packet_size;
+	uint64_t num_bytes = 0;
+	uint16_t num_rx;
+	unsigned int i;
+
+	const uint16_t buf_size = ndp->buf_size;
+
+	struct rte_mbuf *mbuf;
+	struct ndp_packet packets[nb_pkts];
+
+	struct rte_mbuf *mbufs[nb_pkts];
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "RX invalid arguments!\n");
+		return 0;
+	}
+
+	/* returns either all or nothing */
+	i = rte_pktmbuf_alloc_bulk(ndp->mb_pool, mbufs, nb_pkts);
+	if (unlikely(i != 0))
+		return 0;
+
+	num_rx = ndp_rx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_rx != nb_pkts)) {
+		for (i = num_rx; i < nb_pkts; i++)
+			rte_pktmbuf_free(mbufs[i]);
+	}
+
+	nb_pkts = num_rx;
+
+	num_rx = 0;
+	/*
+	 * Reads the given number of packets from NDP queue given
+	 * by queue and copies the packet data into a newly allocated mbuf
+	 * to return.
+	 */
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = mbufs[i];
+
+		/* get the space available for data in the mbuf */
+		packet_size = packets[i].data_length;
+
+		if (likely(packet_size <= buf_size)) {
+			/* NDP packet will fit in one mbuf, go ahead and copy */
+			rte_memcpy(rte_pktmbuf_mtod(mbuf, void *),
+				packets[i].data, packet_size);
+
+			mbuf->data_len = (uint16_t)packet_size;
+
+			mbuf->pkt_len = packet_size;
+			mbuf->port = ndp->in_port;
+			bufs[num_rx++] = mbuf;
+			num_bytes += packet_size;
+		} else {
+			/*
+			 * NDP packet will not fit in one mbuf,
+			 * scattered mode is not enabled, drop packet
+			 */
+			rte_pktmbuf_free(mbuf);
+		}
+	}
+
+	ndp_rx_burst_put(ndp->queue);
+
+	ndp->rx_pkts += num_rx;
+	ndp->rx_bytes += num_bytes;
+	return num_rx;
+}
+
+#endif /* _NFB_RX_H_ */
diff --git a/drivers/net/nfb/nfb_rxmode.c b/drivers/net/nfb/nfb_rxmode.c
new file mode 100644
index 0000000..a6c9cb4
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.c
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+void __rte_experimental
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+	uint16_t i;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_PROMISCUOUS);
+	}
+}
+
+void __rte_experimental
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+	uint16_t i;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_TABLE;
+
+	/* if promisc is not enabled, do nothing */
+	if (!nfb_eth_promiscuous_get(dev))
+		return;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE);
+	}
+}
+
+int __rte_experimental
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_PROMISCUOUS);
+}
+
+void __rte_experimental
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+	}
+}
+
+void __rte_experimental
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+
+	/* if multicast is not enabled do nothing */
+	if (!nfb_eth_allmulticast_get(dev))
+		return;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			internals->rx_filter_original);
+	}
+}
+
+int __rte_experimental
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+}
diff --git a/drivers/net/nfb/nfb_rxmode.h b/drivers/net/nfb/nfb_rxmode.h
new file mode 100644
index 0000000..051130f
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.h
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_RXMODE_H_
+#define _NFB_RXMODE_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_ethdev.h>
+#include <rte_dev.h>
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Getter for promiscuous mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int __rte_experimental
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to enable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void __rte_experimental
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to disable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void __rte_experimental
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Getter for allmulticast mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int __rte_experimental
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to enable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void __rte_experimental
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to disable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void __rte_experimental
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev);
+
+#endif /* _NFB_RXMODE_H_ */
diff --git a/drivers/net/nfb/nfb_stats.c b/drivers/net/nfb/nfb_stats.c
new file mode 100644
index 0000000..a4f22c8
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.c
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_stats.h"
+#include "nfb.h"
+
+int __rte_experimental
+nfb_eth_stats_get(struct rte_eth_dev *dev,
+	struct rte_eth_stats *stats)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+	uint64_t rx_total = 0;
+	uint64_t tx_total = 0;
+	uint64_t tx_err_total = 0;
+	uint64_t rx_total_bytes = 0;
+	uint64_t tx_total_bytes = 0;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_ipackets[i] = rx_queue[i].rx_pkts;
+			stats->q_ibytes[i] = rx_queue[i].rx_bytes;
+		}
+		rx_total += stats->q_ipackets[i];
+		rx_total_bytes += stats->q_ibytes[i];
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_opackets[i] = tx_queue[i].tx_pkts;
+			stats->q_obytes[i] = tx_queue[i].tx_bytes;
+		}
+		tx_total += stats->q_opackets[i];
+		tx_total_bytes += stats->q_obytes[i];
+		tx_err_total += tx_queue[i].err_pkts;
+	}
+
+	stats->ipackets = rx_total;
+	stats->opackets = tx_total;
+	stats->ibytes = rx_total_bytes;
+	stats->obytes = tx_total_bytes;
+	stats->oerrors = tx_err_total;
+	return 0;
+}
+
+void __rte_experimental
+nfb_eth_stats_reset(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		rx_queue[i].rx_pkts = 0;
+		rx_queue[i].rx_bytes = 0;
+		rx_queue[i].err_pkts = 0;
+	}
+	for (i = 0; i < nb_tx; i++) {
+		tx_queue[i].tx_pkts = 0;
+		tx_queue[i].tx_bytes = 0;
+		tx_queue[i].err_pkts = 0;
+	}
+}
diff --git a/drivers/net/nfb/nfb_stats.h b/drivers/net/nfb/nfb_stats.h
new file mode 100644
index 0000000..85439c6
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_STATS_H_
+#define _NFB_STATS_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to get device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] stats
+ *   Stats structure output buffer.
+ *
+ * @return
+ *   0 on success and stats is filled, negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to clear device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void __rte_experimental
+nfb_eth_stats_reset(struct rte_eth_dev *dev);
+
+#endif /* _NFB_STATS_H_ */
diff --git a/drivers/net/nfb/nfb_tx.c b/drivers/net/nfb/nfb_tx.c
new file mode 100644
index 0000000..8ef756b
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.c
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_tx.h"
+#include "nfb.h"
+
+int __rte_experimental
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+	int ret;
+
+	if (txq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_start(txq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+int __rte_experimental
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+	int ret;
+
+	if (txq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "TX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_stop(txq->queue);
+	if (ret != 0)
+		return -EINVAL;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int __rte_experimental
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	int ret;
+	struct ndp_tx_queue *txq;
+
+	txq = rte_zmalloc_socket("ndp tx queue",
+		sizeof(struct ndp_tx_queue),
+		RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (txq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for tx queue id "
+			"%" PRIu16 "!\n", tx_queue_id);
+		return -ENOMEM;
+	}
+
+	ret = nfb_eth_tx_queue_init(internals->nfb,
+		tx_queue_id,
+		txq);
+
+	if (ret == 0)
+		dev->data->tx_queues[tx_queue_id] = txq;
+	else
+		rte_free(txq);
+
+	return ret;
+}
+
+int __rte_experimental
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq)
+{
+	if (nfb == NULL)
+		return -EINVAL;
+
+	txq->queue = ndp_open_tx_queue(nfb, tx_queue_id);
+	if (txq->queue == NULL)
+		return -EINVAL;
+
+	txq->nfb = nfb;
+	txq->tx_queue_id = tx_queue_id;
+
+	txq->tx_pkts = 0;
+	txq->tx_bytes = 0;
+	txq->err_pkts = 0;
+
+	return 0;
+}
+
+void __rte_experimental
+nfb_eth_tx_queue_release(void *q)
+{
+	struct ndp_tx_queue *txq = (struct ndp_tx_queue *)q;
+	if (txq->queue != NULL) {
+		ndp_close_tx_queue(txq->queue);
+		rte_free(txq);
+		txq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_tx.h b/drivers/net/nfb/nfb_tx.h
new file mode 100644
index 0000000..32a1bdb
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.h
@@ -0,0 +1,222 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Cesnet
+ * Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_TX_H_
+#define _NFB_TX_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+struct ndp_tx_queue {
+	struct nfb_device *nfb;     /* nfb dev structure */
+	struct ndp_queue *queue;    /* tx queue */
+	uint16_t          tx_queue_id;       /* index */
+	volatile uint64_t tx_pkts;  /* packets transmitted */
+	volatile uint64_t tx_bytes; /* bytes transmitted */
+	volatile uint64_t err_pkts; /* erroneous packets */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to setup a TX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mp
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Initialize ndp_tx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param tx_queue_id
+ *   TX queue index.
+ * @param[out] txq
+ *   Pointer to ndp_tx_queue output structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void __rte_experimental
+nfb_eth_tx_queue_release(void *q);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Start traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Stop traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int __rte_experimental
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * DPDK callback for TX.
+ *
+ * @param dpdk_txq
+ *   Generic pointer to TX queue structure.
+ * @param bufs
+ *   Packets to transmit.
+ * @param nb_pkts
+ *   Number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully transmitted (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t __rte_experimental
+nfb_eth_ndp_tx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	int i;
+	struct rte_mbuf *mbuf;
+	struct ndp_tx_queue *ndp = queue;
+	uint16_t num_tx = 0;
+	uint64_t num_bytes = 0;
+
+	void *dst;
+	uint32_t pkt_len;
+	uint8_t mbuf_segs;
+
+	struct ndp_packet packets[nb_pkts];
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "TX invalid arguments!\n");
+		return 0;
+	}
+
+	for (i = 0; i < nb_pkts; i++) {
+		packets[i].data_length = bufs[i]->pkt_len;
+		packets[i].header_length = 0;
+	}
+
+	num_tx = ndp_tx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_tx != nb_pkts))
+		return 0;
+
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = bufs[i];
+
+		pkt_len = mbuf->pkt_len;
+		mbuf_segs = mbuf->nb_segs;
+
+		num_bytes += pkt_len;
+		if (mbuf_segs == 1) {
+			/*
+			 * non-scattered packet,
+			 * transmit from one mbuf
+			 */
+			rte_memcpy(packets[i].data,
+				rte_pktmbuf_mtod(mbuf, const void *),
+				pkt_len);
+		} else {
+			/* scattered packet, transmit from more mbufs */
+			struct rte_mbuf *m = mbuf;
+			while (m) {
+				dst = packets[i].data;
+
+				rte_memcpy(dst,
+					rte_pktmbuf_mtod(m,
+					const void *),
+					m->data_len);
+				dst = ((uint8_t *)(dst)) +
+					m->data_len;
+				m = m->next;
+			}
+		}
+
+		rte_pktmbuf_free(mbuf);
+	}
+
+	ndp_tx_burst_flush(ndp->queue);
+
+	ndp->tx_pkts += num_tx;
+	ndp->err_pkts += nb_pkts - num_tx;
+	ndp->tx_bytes += num_bytes;
+	return num_tx;
+}
+
+#endif /* _NFB_TX_H_ */
diff --git a/drivers/net/nfb/rte_nfb_pmd_version.map b/drivers/net/nfb/rte_nfb_pmd_version.map
new file mode 100644
index 0000000..66748c0
--- /dev/null
+++ b/drivers/net/nfb/rte_nfb_pmd_version.map
@@ -0,0 +1,4 @@
+EXPERIMENTAL {
+
+        local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 8a4f0f4..1511fe3 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -196,6 +196,8 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC)      += -lrte_pmd_softnic
 endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD)    += -lrte_pmd_sfc_efx
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2 -lsze2
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NFB)        += -lrte_pmd_nfb
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NFB)        +=  $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --libs netcope-common)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_TAP)        += -lrte_pmd_tap
 _LDLIBS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += -lrte_pmd_thunderx_nicvf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD) += -lrte_pmd_vdev_netvsc
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v5] net/nfb: new netcope driver
  2019-03-22 12:12   ` [dpdk-dev] [PATCH v5] " Rastislav Cernay
  2019-03-22 12:12     ` Rastislav Cernay
@ 2019-03-28 16:01     ` Ferruh Yigit
  2019-03-28 16:01       ` Ferruh Yigit
  2019-04-01 14:55       ` Rastislav Černay
  1 sibling, 2 replies; 50+ messages in thread
From: Ferruh Yigit @ 2019-03-28 16:01 UTC (permalink / raw)
  To: Rastislav Cernay, dev

On 3/22/2019 12:12 PM, Rastislav Cernay wrote:
> From: Rastislav Cernay <cernay@netcope.com>
> 
> Added new net driver for Netcope nfb cards
> 
> Signed-off-by: Rastislav Cernay <cernay@netcope.com>
> ---
> v2: remove unnecessary cast
>     remove unnecessary zeroing
>     move declaration to not mix with code
>     restore skeleton example
> v3: add release notes
>     add doc to doc index
>     add architecture limits to doc
>     edit features list
>     add .map file
>     change link to dependecies to official vendor site
>     move declarations out of code
>     remove false comments (rte_errno is set)
>     comments to c89 style
>     remove log from main rx loop
>     remove redundant code
> v4: API is experimental
>     fixed meson build dependency
>     random initial MAC
>     stats->q_errors is for intput err only
>     move more declarations to a beginning
>     fixed err log in TX
>     use of pkg-config
> v5: fixed pkg-config for new version of netcope-common
>  MAINTAINERS                             |   7 +
>  config/common_base                      |   4 +
>  devtools/test-build.sh                  |   1 +
>  doc/guides/nics/features/nfb.ini        |  18 +
>  doc/guides/nics/index.rst               |   1 +
>  doc/guides/nics/nfb.rst                 | 143 +++++++
>  doc/guides/rel_notes/release_19_02.rst  |   5 +

Can you update the 19.05 release notes please?

>  drivers/net/Makefile                    |   1 +
>  drivers/net/meson.build                 |   1 +
>  drivers/net/nfb/Makefile                |  44 +++
>  drivers/net/nfb/meson.build             |  15 +
>  drivers/net/nfb/nfb.h                   |  50 +++
>  drivers/net/nfb/nfb_ethdev.c            | 647 ++++++++++++++++++++++++++++++++
>  drivers/net/nfb/nfb_rx.c                | 127 +++++++
>  drivers/net/nfb/nfb_rx.h                | 231 ++++++++++++
>  drivers/net/nfb/nfb_rxmode.c            | 100 +++++
>  drivers/net/nfb/nfb_rxmode.h            |  96 +++++
>  drivers/net/nfb/nfb_stats.c             |  77 ++++
>  drivers/net/nfb/nfb_stats.h             |  56 +++
>  drivers/net/nfb/nfb_tx.c                | 113 ++++++
>  drivers/net/nfb/nfb_tx.h                | 222 +++++++++++
>  drivers/net/nfb/rte_nfb_pmd_version.map |   4 +

The filename should be "rte_pmd_nfb_version.map" as stated in Makefile.
This brings the question, did you ever build dpdk as shared library or with
meson build system with this PMD enabled :)
Because it fails because of this wrong naming..


Even after renaming the .map file, meson build fails, I haven't dig the problem,
can you please check it?

<...>

> @@ -360,6 +360,10 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
>  # Compile software PMD backed by SZEDATA2 device
>  #
>  CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
> +#
> +# Compile software PMD backed by NFB device
> +#
> +CONFIG_RTE_LIBRTE_PMD_NFB=n

Can you please rename the config option to "CONFIG_RTE_LIBRTE_NFB_PMD"?
I guess unintentionally, there is an convension,
Physical PMDs have the config name: CONFIG_RTE_LIBRTE_.*_PMD
Virtual PMDs have the config name:  CONFIG_RTE_LIBRTE_PMD_.*=y
I perfer same syntax for all, but it is what it is now, and I believe it doesn't
worth the hassle of changing them.

I think only 'SZEDATA2' breaks current login, and I guess you copied from it,
but let's start NFB according convention: CONFIG_RTE_LIBRTE_NFB_PMD


Also please leave a blank line between previous config block.

<...>

> +Prerequisites
> +-------------
> +
> +This PMD requires kernel modules which are responsible for initialization and
> +allocation of resources needed for nfb layer function.
> +Communication between PMD and kernel modules is mediated by libnfb library.
> +These kernel modules and library are not part of DPDK and must be installed
> +separately:
> +
> +*  **libnfb library**
> +
> +   The library provides API for initialization of nfb transfers, receiving and
> +   transmitting data segments.
> +
> +*  **Kernel modules**
> +
> +   * nfb
> +
> +   Kernel modules manage initialization of hardware, allocation and
> +   sharing of resources for user space applications.
> +
> +Dependencies can be found here:
> +`Netcope common <https://www.netcope.com/en/company/community-support/dpdk-libsze2#NFB>`_.

I have a problem here, this requires 'netcope-common-6.4.0-1.x86_64.rpm' rpm to
be installed [1], meanwhile szedata requires
'netcope-common-light-3.0.5-1.x86_64.rpm' to be installed, and these two
packages conflicts with eachother.

What is the way of having an environment that dependencies of two netcope HW can
be provided at same time? This is really time consuming each time update system
for it.

[1]
Is rpm only option, how people using Ubuntu for example will use your devices?

> +
> +Versions of the packages
> +~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +The minimum version of the provided packages:
> +
> +* for DPDK from 19.02

Is it 19.05 now?

<...>

> +Example output:
> +
> +.. code-block:: console
> +
> +   [...]
> +   EAL: PCI device 0000:06:00.0 on NUMA socket -1
> +   EAL:   probe driver: 1b26:c1c1 net_nfb
> +   PMD: Initializing NFB device (0000:06:00.0)
> +   PMD: Available DMA queues RX: 8 TX: 8
> +   PMD: NFB device (0000:06:00.0) successfully initialized
> +   Interactive-mode selected
> +   Auto-start selected
> +   Configuring Port 0 (socket 0)
> +   Port 0: 00:11:17:00:00:00
> +   Checking link statuses...
> +   Port 0 Link Up - speed 10000 Mbps - full-duplex
> +   Done
> +   Start automatic packet forwarding
> +     io packet forwarding - CRC stripping disabled - packets/burst=32
> +     nb forwarding cores=2 - nb forwarding ports=1
> +     RX queues=2 - RX desc=128 - RX free threshold=0
> +     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
> +     TX queues=2 - TX desc=512 - TX free threshold=0
> +     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
> +     TX RS bit threshold=0 - TXQ flags=0x0
> +   testpmd>

I think testpmd logging is not like this any more, can you please update the app
log with latest code.

<...>

> @@ -0,0 +1,44 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2018 Cesnet
> +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>

Should year be 2019, or 2018-2019?


<...>

> @@ -0,0 +1,15 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2018 Cesnet
> +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> +# All rights reserved.
> +
> +dep = cc.find_library('nfb', required: false)
> +
> +build = dep.found() and cc.has_header('nfb/nfb.h', dependencies: dep)
> +
> +allow_experimental_apis = true

Why allow_experimental only in meson, but not Makefile?
Can you please add list of experimental APIs called just below this as comment?

<...>

> +/**
> + * Default MAC addr
> + */
> +static struct ether_addr eth_addr = {
> +	.addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
> +};

it looks like this can be static const.

> +
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
> + *

Why these tags are added, to say PMD is experimental?
These only makes sense for public APIs which PMD doesn't have at all, these are
doxygen comments for API documentation. Please remove them.

Also I recognized '__rte_experimental' tags, again which are for internal
checking and warning the applications if they are using experimental public API,
it doesn't apply here. Please remove them.
Last thing, the "EXPERIMENTAL" tag in .map file, that also doesn't apply here,
please make it release version, 'DPDK_19.05"

I think your note about being experimental in MAINTAINERS file and the note in
release notes is good,
Can you please also update the driver documentation too, nfb.rst, to say driver
is experimental? I think those notes are good enough overall.


btw, why do you prefer to have driver as experimental?
What does it mean it being experimental from your point of view exactly?


<...>

> +static int __rte_experimental
> +nfb_eth_mac_addr_set(struct rte_eth_dev *dev,
> +	struct ether_addr *mac_addr)
> +{
> +	unsigned int i;
> +	unsigned long long mac = 0;

Would you prefer to use a fixed length deceleration, uint64_t?

> +	struct rte_eth_dev_data *data = dev->data;
> +	struct pmd_internals *internals = (struct pmd_internals *)
> +		data->dev_private;
> +
> +	if (!is_valid_assigned_ether_addr(mac_addr))
> +		return -EINVAL;
> +
> +	for (i = 0; i < 6; i++) {

Can you please use "ETHER_ADDR_LEN" instead of 6?

<...>

> +	for (i = 0; i < nb_rx; i++) {
> +		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> +			stats->q_ipackets[i] = rx_queue[i].rx_pkts;
> +			stats->q_ibytes[i] = rx_queue[i].rx_bytes;
> +		}
> +		rx_total += stats->q_ipackets[i];
> +		rx_total_bytes += stats->q_ibytes[i];

Why these are not protected with "RTE_ETHDEV_QUEUE_STAT_CNTRS" check,
if "i >= RTE_ETHDEV_QUEUE_STAT_CNTRS" you shouldn't access to 'stats->q_.*[i]'

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v5] net/nfb: new netcope driver
  2019-03-28 16:01     ` Ferruh Yigit
@ 2019-03-28 16:01       ` Ferruh Yigit
  2019-04-01 14:55       ` Rastislav Černay
  1 sibling, 0 replies; 50+ messages in thread
From: Ferruh Yigit @ 2019-03-28 16:01 UTC (permalink / raw)
  To: Rastislav Cernay, dev

On 3/22/2019 12:12 PM, Rastislav Cernay wrote:
> From: Rastislav Cernay <cernay@netcope.com>
> 
> Added new net driver for Netcope nfb cards
> 
> Signed-off-by: Rastislav Cernay <cernay@netcope.com>
> ---
> v2: remove unnecessary cast
>     remove unnecessary zeroing
>     move declaration to not mix with code
>     restore skeleton example
> v3: add release notes
>     add doc to doc index
>     add architecture limits to doc
>     edit features list
>     add .map file
>     change link to dependecies to official vendor site
>     move declarations out of code
>     remove false comments (rte_errno is set)
>     comments to c89 style
>     remove log from main rx loop
>     remove redundant code
> v4: API is experimental
>     fixed meson build dependency
>     random initial MAC
>     stats->q_errors is for intput err only
>     move more declarations to a beginning
>     fixed err log in TX
>     use of pkg-config
> v5: fixed pkg-config for new version of netcope-common
>  MAINTAINERS                             |   7 +
>  config/common_base                      |   4 +
>  devtools/test-build.sh                  |   1 +
>  doc/guides/nics/features/nfb.ini        |  18 +
>  doc/guides/nics/index.rst               |   1 +
>  doc/guides/nics/nfb.rst                 | 143 +++++++
>  doc/guides/rel_notes/release_19_02.rst  |   5 +

Can you update the 19.05 release notes please?

>  drivers/net/Makefile                    |   1 +
>  drivers/net/meson.build                 |   1 +
>  drivers/net/nfb/Makefile                |  44 +++
>  drivers/net/nfb/meson.build             |  15 +
>  drivers/net/nfb/nfb.h                   |  50 +++
>  drivers/net/nfb/nfb_ethdev.c            | 647 ++++++++++++++++++++++++++++++++
>  drivers/net/nfb/nfb_rx.c                | 127 +++++++
>  drivers/net/nfb/nfb_rx.h                | 231 ++++++++++++
>  drivers/net/nfb/nfb_rxmode.c            | 100 +++++
>  drivers/net/nfb/nfb_rxmode.h            |  96 +++++
>  drivers/net/nfb/nfb_stats.c             |  77 ++++
>  drivers/net/nfb/nfb_stats.h             |  56 +++
>  drivers/net/nfb/nfb_tx.c                | 113 ++++++
>  drivers/net/nfb/nfb_tx.h                | 222 +++++++++++
>  drivers/net/nfb/rte_nfb_pmd_version.map |   4 +

The filename should be "rte_pmd_nfb_version.map" as stated in Makefile.
This brings the question, did you ever build dpdk as shared library or with
meson build system with this PMD enabled :)
Because it fails because of this wrong naming..


Even after renaming the .map file, meson build fails, I haven't dig the problem,
can you please check it?

<...>

> @@ -360,6 +360,10 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
>  # Compile software PMD backed by SZEDATA2 device
>  #
>  CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
> +#
> +# Compile software PMD backed by NFB device
> +#
> +CONFIG_RTE_LIBRTE_PMD_NFB=n

Can you please rename the config option to "CONFIG_RTE_LIBRTE_NFB_PMD"?
I guess unintentionally, there is an convension,
Physical PMDs have the config name: CONFIG_RTE_LIBRTE_.*_PMD
Virtual PMDs have the config name:  CONFIG_RTE_LIBRTE_PMD_.*=y
I perfer same syntax for all, but it is what it is now, and I believe it doesn't
worth the hassle of changing them.

I think only 'SZEDATA2' breaks current login, and I guess you copied from it,
but let's start NFB according convention: CONFIG_RTE_LIBRTE_NFB_PMD


Also please leave a blank line between previous config block.

<...>

> +Prerequisites
> +-------------
> +
> +This PMD requires kernel modules which are responsible for initialization and
> +allocation of resources needed for nfb layer function.
> +Communication between PMD and kernel modules is mediated by libnfb library.
> +These kernel modules and library are not part of DPDK and must be installed
> +separately:
> +
> +*  **libnfb library**
> +
> +   The library provides API for initialization of nfb transfers, receiving and
> +   transmitting data segments.
> +
> +*  **Kernel modules**
> +
> +   * nfb
> +
> +   Kernel modules manage initialization of hardware, allocation and
> +   sharing of resources for user space applications.
> +
> +Dependencies can be found here:
> +`Netcope common <https://www.netcope.com/en/company/community-support/dpdk-libsze2#NFB>`_.

I have a problem here, this requires 'netcope-common-6.4.0-1.x86_64.rpm' rpm to
be installed [1], meanwhile szedata requires
'netcope-common-light-3.0.5-1.x86_64.rpm' to be installed, and these two
packages conflicts with eachother.

What is the way of having an environment that dependencies of two netcope HW can
be provided at same time? This is really time consuming each time update system
for it.

[1]
Is rpm only option, how people using Ubuntu for example will use your devices?

> +
> +Versions of the packages
> +~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +The minimum version of the provided packages:
> +
> +* for DPDK from 19.02

Is it 19.05 now?

<...>

> +Example output:
> +
> +.. code-block:: console
> +
> +   [...]
> +   EAL: PCI device 0000:06:00.0 on NUMA socket -1
> +   EAL:   probe driver: 1b26:c1c1 net_nfb
> +   PMD: Initializing NFB device (0000:06:00.0)
> +   PMD: Available DMA queues RX: 8 TX: 8
> +   PMD: NFB device (0000:06:00.0) successfully initialized
> +   Interactive-mode selected
> +   Auto-start selected
> +   Configuring Port 0 (socket 0)
> +   Port 0: 00:11:17:00:00:00
> +   Checking link statuses...
> +   Port 0 Link Up - speed 10000 Mbps - full-duplex
> +   Done
> +   Start automatic packet forwarding
> +     io packet forwarding - CRC stripping disabled - packets/burst=32
> +     nb forwarding cores=2 - nb forwarding ports=1
> +     RX queues=2 - RX desc=128 - RX free threshold=0
> +     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
> +     TX queues=2 - TX desc=512 - TX free threshold=0
> +     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
> +     TX RS bit threshold=0 - TXQ flags=0x0
> +   testpmd>

I think testpmd logging is not like this any more, can you please update the app
log with latest code.

<...>

> @@ -0,0 +1,44 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2018 Cesnet
> +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>

Should year be 2019, or 2018-2019?


<...>

> @@ -0,0 +1,15 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2018 Cesnet
> +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> +# All rights reserved.
> +
> +dep = cc.find_library('nfb', required: false)
> +
> +build = dep.found() and cc.has_header('nfb/nfb.h', dependencies: dep)
> +
> +allow_experimental_apis = true

Why allow_experimental only in meson, but not Makefile?
Can you please add list of experimental APIs called just below this as comment?

<...>

> +/**
> + * Default MAC addr
> + */
> +static struct ether_addr eth_addr = {
> +	.addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
> +};

it looks like this can be static const.

> +
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
> + *

Why these tags are added, to say PMD is experimental?
These only makes sense for public APIs which PMD doesn't have at all, these are
doxygen comments for API documentation. Please remove them.

Also I recognized '__rte_experimental' tags, again which are for internal
checking and warning the applications if they are using experimental public API,
it doesn't apply here. Please remove them.
Last thing, the "EXPERIMENTAL" tag in .map file, that also doesn't apply here,
please make it release version, 'DPDK_19.05"

I think your note about being experimental in MAINTAINERS file and the note in
release notes is good,
Can you please also update the driver documentation too, nfb.rst, to say driver
is experimental? I think those notes are good enough overall.


btw, why do you prefer to have driver as experimental?
What does it mean it being experimental from your point of view exactly?


<...>

> +static int __rte_experimental
> +nfb_eth_mac_addr_set(struct rte_eth_dev *dev,
> +	struct ether_addr *mac_addr)
> +{
> +	unsigned int i;
> +	unsigned long long mac = 0;

Would you prefer to use a fixed length deceleration, uint64_t?

> +	struct rte_eth_dev_data *data = dev->data;
> +	struct pmd_internals *internals = (struct pmd_internals *)
> +		data->dev_private;
> +
> +	if (!is_valid_assigned_ether_addr(mac_addr))
> +		return -EINVAL;
> +
> +	for (i = 0; i < 6; i++) {

Can you please use "ETHER_ADDR_LEN" instead of 6?

<...>

> +	for (i = 0; i < nb_rx; i++) {
> +		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> +			stats->q_ipackets[i] = rx_queue[i].rx_pkts;
> +			stats->q_ibytes[i] = rx_queue[i].rx_bytes;
> +		}
> +		rx_total += stats->q_ipackets[i];
> +		rx_total_bytes += stats->q_ibytes[i];

Why these are not protected with "RTE_ETHDEV_QUEUE_STAT_CNTRS" check,
if "i >= RTE_ETHDEV_QUEUE_STAT_CNTRS" you shouldn't access to 'stats->q_.*[i]'

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v5] net/nfb: new netcope driver
  2019-04-01 14:55       ` Rastislav Černay
@ 2019-04-01 14:22         ` Ferruh Yigit
  2019-04-01 14:22           ` Ferruh Yigit
  2019-04-02 16:05           ` Rastislav Černay
  2019-04-01 14:23         ` Luca Boccassi
  2019-04-01 14:55         ` Rastislav Černay
  2 siblings, 2 replies; 50+ messages in thread
From: Ferruh Yigit @ 2019-04-01 14:22 UTC (permalink / raw)
  To: Rastislav Černay; +Cc: dev, Luca Boccassi

On 4/1/2019 3:55 PM, Rastislav Černay wrote:
> Hi Ferruh,
> 
> I fixed most of issues you wrote, but before I send v6, I would like to make
> sure everything is in order, mainly the experimental issue.
> 
> I have a problem here, this requires 'netcope-common-6.4.0-1.x86_64.rpm' rpm to
> be installed [1], meanwhile szedata requires
> 'netcope-common-light-3.0.5-1.x86_64.rpm' to be installed, and these two
> packages conflicts with eachother.
> 
> What is the way of having an environment that dependencies of two netcope HW can
> be provided at same time? This is really time consuming each time update system
> for it.
> 
> <...>
> Sadly, szedata2 and nfb dirvers can not coexist in same enviroment. There is no
> way to provide dependecies at same time.

Isn't this also problem for you too? What is your solution when testing both?

> 
> Is rpm only option, how people using Ubuntu for example will use your devices?
> <...>
> For now, yes, only option is rpm and support for Ubuntu will be added later.

Is this limitation in driver document? If not can you please update it.

> 
> 
> Why allow_experimental only in meson, but not Makefile?
> <...>
> It is in Makefile too.
> CFLAGS += -DALLOW_EXPERIMENTAL_API
> 
> Can you please add list of experimental APIs called just below this as comment?
> <...>
> No experimental API is called in driver.

OK, so please clean the meson file.

> 
> btw, why do you prefer to have driver as experimental?
> What does it mean it being experimental from your point of view exactly?
> <...>
> I do not prefer to have driver experimental, only reason it is there is
> this mail:
> 
> Luca Boccassi bluca@debian.org <mailto:bluca@debian.org>
> Tue, Mar 5, 11:41 PM
> to me, dev
> <...>
>> diff --git a/drivers/net/nfb/rte_nfb_pmd_version.map
>> b/drivers/net/nfb/rte_nfb_pmd_version.map
>> new file mode 100644
>> index 0000000..97fd251
>> --- /dev/null
>> +++ b/drivers/net/nfb/rte_nfb_pmd_version.map
>> @@ -0,0 +1,4 @@
>> +DPDK_19.02 {
>> +
>> +        local: *;
>> +};
> 
> These are all new symbols so they should be marked as experimental,
> please see doc/guides/contributing/versioning.rst
> 
> So after reading doc/guides/contributing/versioning.rst I thought that
> all new drivers should be experimental as they are new before they stabilize,
> and during this time changes can be done to public functions without much hassle.
> Should I keep driver experimental?

No please don't keep it experimental. Luca is right new symbols should be marked
as experimental, here news symbols are APIs and this PMD doesn't have any, all
it has is 'local' symbols.
cc'ed Luca if I am missing anything.

And if this is the only reason you documented the PMD as experimental, you can
clean MAINTAINERS file, release notes etc...

> 
> *
> 
> *Rastislav Černay I /Software Developer/*
> Netcope Technologies, a.s.
> 
> *T:* +420 530 510 680 <tel:+420%20530%20510%20680>
> *A:* Sochorova 3232/34, Brno, 616 00, Czech Republic
> <https://maps.google.com/?q=Sochorova+3232/34,+Brno,+616+00,%C2%A0Czech+Republic&entry=gmail&source=g>
> *W: www.netcope.com <https://www.netcope.com/>
> 
>  <https://www.netcope.com/>*
> 
> *
> **
> 
> 
> 
> On Thu, Mar 28, 2019 at 5:01 PM Ferruh Yigit <ferruh.yigit@intel.com
> <mailto:ferruh.yigit@intel.com>> wrote:
> 
>     On 3/22/2019 12:12 PM, Rastislav Cernay wrote:
>     > From: Rastislav Cernay <cernay@netcope.com <mailto:cernay@netcope.com>>
>     >
>     > Added new net driver for Netcope nfb cards
>     >
>     > Signed-off-by: Rastislav Cernay <cernay@netcope.com
>     <mailto:cernay@netcope.com>>
>     > ---
>     > v2: remove unnecessary cast
>     >     remove unnecessary zeroing
>     >     move declaration to not mix with code
>     >     restore skeleton example
>     > v3: add release notes
>     >     add doc to doc index
>     >     add architecture limits to doc
>     >     edit features list
>     >     add .map file
>     >     change link to dependecies to official vendor site
>     >     move declarations out of code
>     >     remove false comments (rte_errno is set)
>     >     comments to c89 style
>     >     remove log from main rx loop
>     >     remove redundant code
>     > v4: API is experimental
>     >     fixed meson build dependency
>     >     random initial MAC
>     >     stats->q_errors is for intput err only
>     >     move more declarations to a beginning
>     >     fixed err log in TX
>     >     use of pkg-config
>     > v5: fixed pkg-config for new version of netcope-common
>     >  MAINTAINERS                             |   7 +
>     >  config/common_base                      |   4 +
>     >  devtools/test-build.sh                  |   1 +
>     >  doc/guides/nics/features/nfb.ini        |  18 +
>     >  doc/guides/nics/index.rst               |   1 +
>     >  doc/guides/nics/nfb.rst                 | 143 +++++++
>     >  doc/guides/rel_notes/release_19_02.rst  |   5 +
> 
>     Can you update the 19.05 release notes please?
> 
>     >  drivers/net/Makefile                    |   1 +
>     >  drivers/net/meson.build                 |   1 +
>     >  drivers/net/nfb/Makefile                |  44 +++
>     >  drivers/net/nfb/meson.build             |  15 +
>     >  drivers/net/nfb/nfb.h                   |  50 +++
>     >  drivers/net/nfb/nfb_ethdev.c            | 647
>     ++++++++++++++++++++++++++++++++
>     >  drivers/net/nfb/nfb_rx.c                | 127 +++++++
>     >  drivers/net/nfb/nfb_rx.h                | 231 ++++++++++++
>     >  drivers/net/nfb/nfb_rxmode.c            | 100 +++++
>     >  drivers/net/nfb/nfb_rxmode.h            |  96 +++++
>     >  drivers/net/nfb/nfb_stats.c             |  77 ++++
>     >  drivers/net/nfb/nfb_stats.h             |  56 +++
>     >  drivers/net/nfb/nfb_tx.c                | 113 ++++++
>     >  drivers/net/nfb/nfb_tx.h                | 222 +++++++++++
>     >  drivers/net/nfb/rte_nfb_pmd_version.map |   4 +
> 
>     The filename should be "rte_pmd_nfb_version.map" as stated in Makefile.
>     This brings the question, did you ever build dpdk as shared library or with
>     meson build system with this PMD enabled :)
>     Because it fails because of this wrong naming..
> 
> 
>     Even after renaming the .map file, meson build fails, I haven't dig the problem,
>     can you please check it?
> 
>     <...>
> 
>     > @@ -360,6 +360,10 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
>     >  # Compile software PMD backed by SZEDATA2 device
>     >  #
>     >  CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
>     > +#
>     > +# Compile software PMD backed by NFB device
>     > +#
>     > +CONFIG_RTE_LIBRTE_PMD_NFB=n
> 
>     Can you please rename the config option to "CONFIG_RTE_LIBRTE_NFB_PMD"?
>     I guess unintentionally, there is an convension,
>     Physical PMDs have the config name: CONFIG_RTE_LIBRTE_.*_PMD
>     Virtual PMDs have the config name:  CONFIG_RTE_LIBRTE_PMD_.*=y
>     I perfer same syntax for all, but it is what it is now, and I believe it doesn't
>     worth the hassle of changing them.
> 
>     I think only 'SZEDATA2' breaks current login, and I guess you copied from it,
>     but let's start NFB according convention: CONFIG_RTE_LIBRTE_NFB_PMD
> 
> 
>     Also please leave a blank line between previous config block.
> 
>     <...>
> 
>     > +Prerequisites
>     > +-------------
>     > +
>     > +This PMD requires kernel modules which are responsible for initialization and
>     > +allocation of resources needed for nfb layer function.
>     > +Communication between PMD and kernel modules is mediated by libnfb library.
>     > +These kernel modules and library are not part of DPDK and must be installed
>     > +separately:
>     > +
>     > +*  **libnfb library**
>     > +
>     > +   The library provides API for initialization of nfb transfers,
>     receiving and
>     > +   transmitting data segments.
>     > +
>     > +*  **Kernel modules**
>     > +
>     > +   * nfb
>     > +
>     > +   Kernel modules manage initialization of hardware, allocation and
>     > +   sharing of resources for user space applications.
>     > +
>     > +Dependencies can be found here:
>     > +`Netcope common
>     <https://www.netcope.com/en/company/community-support/dpdk-libsze2#NFB>`_.
> 
>     I have a problem here, this requires 'netcope-common-6.4.0-1.x86_64.rpm' rpm to
>     be installed [1], meanwhile szedata requires
>     'netcope-common-light-3.0.5-1.x86_64.rpm' to be installed, and these two
>     packages conflicts with eachother.
> 
>     What is the way of having an environment that dependencies of two netcope HW can
>     be provided at same time? This is really time consuming each time update system
>     for it.
> 
>     [1]
>     Is rpm only option, how people using Ubuntu for example will use your devices?
> 
>     > +
>     > +Versions of the packages
>     > +~~~~~~~~~~~~~~~~~~~~~~~~
>     > +
>     > +The minimum version of the provided packages:
>     > +
>     > +* for DPDK from 19.02
> 
>     Is it 19.05 now?
> 
>     <...>
> 
>     > +Example output:
>     > +
>     > +.. code-block:: console
>     > +
>     > +   [...]
>     > +   EAL: PCI device 0000:06:00.0 on NUMA socket -1
>     > +   EAL:   probe driver: 1b26:c1c1 net_nfb
>     > +   PMD: Initializing NFB device (0000:06:00.0)
>     > +   PMD: Available DMA queues RX: 8 TX: 8
>     > +   PMD: NFB device (0000:06:00.0) successfully initialized
>     > +   Interactive-mode selected
>     > +   Auto-start selected
>     > +   Configuring Port 0 (socket 0)
>     > +   Port 0: 00:11:17:00:00:00
>     > +   Checking link statuses...
>     > +   Port 0 Link Up - speed 10000 Mbps - full-duplex
>     > +   Done
>     > +   Start automatic packet forwarding
>     > +     io packet forwarding - CRC stripping disabled - packets/burst=32
>     > +     nb forwarding cores=2 - nb forwarding ports=1
>     > +     RX queues=2 - RX desc=128 - RX free threshold=0
>     > +     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
>     > +     TX queues=2 - TX desc=512 - TX free threshold=0
>     > +     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
>     > +     TX RS bit threshold=0 - TXQ flags=0x0
>     > +   testpmd>
> 
>     I think testpmd logging is not like this any more, can you please update the app
>     log with latest code.
> 
>     <...>
> 
>     > @@ -0,0 +1,44 @@
>     > +# SPDX-License-Identifier: BSD-3-Clause
>     > +# Copyright(c) 2018 Cesnet
>     > +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com
>     <mailto:info@netcope.com>>
> 
>     Should year be 2019, or 2018-2019?
> 
> 
>     <...>
> 
>     > @@ -0,0 +1,15 @@
>     > +# SPDX-License-Identifier: BSD-3-Clause
>     > +# Copyright(c) 2018 Cesnet
>     > +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com
>     <mailto:info@netcope.com>>
>     > +# All rights reserved.
>     > +
>     > +dep = cc.find_library('nfb', required: false)
>     > +
>     > +build = dep.found() and cc.has_header('nfb/nfb.h', dependencies: dep)
>     > +
>     > +allow_experimental_apis = true
> 
>     Why allow_experimental only in meson, but not Makefile?
>     Can you please add list of experimental APIs called just below this as comment?
> 
>     <...>
> 
>     > +/**
>     > + * Default MAC addr
>     > + */
>     > +static struct ether_addr eth_addr = {
>     > +     .addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
>     > +};
> 
>     it looks like this can be static const.
> 
>     > +
>     > +/**
>     > + * @warning
>     > + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
>     > + *
> 
>     Why these tags are added, to say PMD is experimental?
>     These only makes sense for public APIs which PMD doesn't have at all, these are
>     doxygen comments for API documentation. Please remove them.
> 
>     Also I recognized '__rte_experimental' tags, again which are for internal
>     checking and warning the applications if they are using experimental public API,
>     it doesn't apply here. Please remove them.
>     Last thing, the "EXPERIMENTAL" tag in .map file, that also doesn't apply here,
>     please make it release version, 'DPDK_19.05"
> 
>     I think your note about being experimental in MAINTAINERS file and the note in
>     release notes is good,
>     Can you please also update the driver documentation too, nfb.rst, to say driver
>     is experimental? I think those notes are good enough overall.
> 
> 
>     btw, why do you prefer to have driver as experimental?
>     What does it mean it being experimental from your point of view exactly?
> 
> 
>     <...>
> 
>     > +static int __rte_experimental
>     > +nfb_eth_mac_addr_set(struct rte_eth_dev *dev,
>     > +     struct ether_addr *mac_addr)
>     > +{
>     > +     unsigned int i;
>     > +     unsigned long long mac = 0;
> 
>     Would you prefer to use a fixed length deceleration, uint64_t?
> 
>     > +     struct rte_eth_dev_data *data = dev->data;
>     > +     struct pmd_internals *internals = (struct pmd_internals *)
>     > +             data->dev_private;
>     > +
>     > +     if (!is_valid_assigned_ether_addr(mac_addr))
>     > +             return -EINVAL;
>     > +
>     > +     for (i = 0; i < 6; i++) {
> 
>     Can you please use "ETHER_ADDR_LEN" instead of 6?
> 
>     <...>
> 
>     > +     for (i = 0; i < nb_rx; i++) {
>     > +             if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
>     > +                     stats->q_ipackets[i] = rx_queue[i].rx_pkts;
>     > +                     stats->q_ibytes[i] = rx_queue[i].rx_bytes;
>     > +             }
>     > +             rx_total += stats->q_ipackets[i];
>     > +             rx_total_bytes += stats->q_ibytes[i];
> 
>     Why these are not protected with "RTE_ETHDEV_QUEUE_STAT_CNTRS" check,
>     if "i >= RTE_ETHDEV_QUEUE_STAT_CNTRS" you shouldn't access to 'stats->q_.*[i]'
> 

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v5] net/nfb: new netcope driver
  2019-04-01 14:22         ` Ferruh Yigit
@ 2019-04-01 14:22           ` Ferruh Yigit
  2019-04-02 16:05           ` Rastislav Černay
  1 sibling, 0 replies; 50+ messages in thread
From: Ferruh Yigit @ 2019-04-01 14:22 UTC (permalink / raw)
  To: Rastislav Černay; +Cc: dev, Luca Boccassi

On 4/1/2019 3:55 PM, Rastislav Černay wrote:
> Hi Ferruh,
> 
> I fixed most of issues you wrote, but before I send v6, I would like to make
> sure everything is in order, mainly the experimental issue.
> 
> I have a problem here, this requires 'netcope-common-6.4.0-1.x86_64.rpm' rpm to
> be installed [1], meanwhile szedata requires
> 'netcope-common-light-3.0.5-1.x86_64.rpm' to be installed, and these two
> packages conflicts with eachother.
> 
> What is the way of having an environment that dependencies of two netcope HW can
> be provided at same time? This is really time consuming each time update system
> for it.
> 
> <...>
> Sadly, szedata2 and nfb dirvers can not coexist in same enviroment. There is no
> way to provide dependecies at same time.

Isn't this also problem for you too? What is your solution when testing both?

> 
> Is rpm only option, how people using Ubuntu for example will use your devices?
> <...>
> For now, yes, only option is rpm and support for Ubuntu will be added later.

Is this limitation in driver document? If not can you please update it.

> 
> 
> Why allow_experimental only in meson, but not Makefile?
> <...>
> It is in Makefile too.
> CFLAGS += -DALLOW_EXPERIMENTAL_API
> 
> Can you please add list of experimental APIs called just below this as comment?
> <...>
> No experimental API is called in driver.

OK, so please clean the meson file.

> 
> btw, why do you prefer to have driver as experimental?
> What does it mean it being experimental from your point of view exactly?
> <...>
> I do not prefer to have driver experimental, only reason it is there is
> this mail:
> 
> Luca Boccassi bluca@debian.org <mailto:bluca@debian.org>
> Tue, Mar 5, 11:41 PM
> to me, dev
> <...>
>> diff --git a/drivers/net/nfb/rte_nfb_pmd_version.map
>> b/drivers/net/nfb/rte_nfb_pmd_version.map
>> new file mode 100644
>> index 0000000..97fd251
>> --- /dev/null
>> +++ b/drivers/net/nfb/rte_nfb_pmd_version.map
>> @@ -0,0 +1,4 @@
>> +DPDK_19.02 {
>> +
>> +        local: *;
>> +};
> 
> These are all new symbols so they should be marked as experimental,
> please see doc/guides/contributing/versioning.rst
> 
> So after reading doc/guides/contributing/versioning.rst I thought that
> all new drivers should be experimental as they are new before they stabilize,
> and during this time changes can be done to public functions without much hassle.
> Should I keep driver experimental?

No please don't keep it experimental. Luca is right new symbols should be marked
as experimental, here news symbols are APIs and this PMD doesn't have any, all
it has is 'local' symbols.
cc'ed Luca if I am missing anything.

And if this is the only reason you documented the PMD as experimental, you can
clean MAINTAINERS file, release notes etc...

> 
> *
> 
> *Rastislav Černay I /Software Developer/*
> Netcope Technologies, a.s.
> 
> *T:* +420 530 510 680 <tel:+420%20530%20510%20680>
> *A:* Sochorova 3232/34, Brno, 616 00, Czech Republic
> <https://maps.google.com/?q=Sochorova+3232/34,+Brno,+616+00,%C2%A0Czech+Republic&entry=gmail&source=g>
> *W: www.netcope.com <https://www.netcope.com/>
> 
>  <https://www.netcope.com/>*
> 
> *
> **
> 
> 
> 
> On Thu, Mar 28, 2019 at 5:01 PM Ferruh Yigit <ferruh.yigit@intel.com
> <mailto:ferruh.yigit@intel.com>> wrote:
> 
>     On 3/22/2019 12:12 PM, Rastislav Cernay wrote:
>     > From: Rastislav Cernay <cernay@netcope.com <mailto:cernay@netcope.com>>
>     >
>     > Added new net driver for Netcope nfb cards
>     >
>     > Signed-off-by: Rastislav Cernay <cernay@netcope.com
>     <mailto:cernay@netcope.com>>
>     > ---
>     > v2: remove unnecessary cast
>     >     remove unnecessary zeroing
>     >     move declaration to not mix with code
>     >     restore skeleton example
>     > v3: add release notes
>     >     add doc to doc index
>     >     add architecture limits to doc
>     >     edit features list
>     >     add .map file
>     >     change link to dependecies to official vendor site
>     >     move declarations out of code
>     >     remove false comments (rte_errno is set)
>     >     comments to c89 style
>     >     remove log from main rx loop
>     >     remove redundant code
>     > v4: API is experimental
>     >     fixed meson build dependency
>     >     random initial MAC
>     >     stats->q_errors is for intput err only
>     >     move more declarations to a beginning
>     >     fixed err log in TX
>     >     use of pkg-config
>     > v5: fixed pkg-config for new version of netcope-common
>     >  MAINTAINERS                             |   7 +
>     >  config/common_base                      |   4 +
>     >  devtools/test-build.sh                  |   1 +
>     >  doc/guides/nics/features/nfb.ini        |  18 +
>     >  doc/guides/nics/index.rst               |   1 +
>     >  doc/guides/nics/nfb.rst                 | 143 +++++++
>     >  doc/guides/rel_notes/release_19_02.rst  |   5 +
> 
>     Can you update the 19.05 release notes please?
> 
>     >  drivers/net/Makefile                    |   1 +
>     >  drivers/net/meson.build                 |   1 +
>     >  drivers/net/nfb/Makefile                |  44 +++
>     >  drivers/net/nfb/meson.build             |  15 +
>     >  drivers/net/nfb/nfb.h                   |  50 +++
>     >  drivers/net/nfb/nfb_ethdev.c            | 647
>     ++++++++++++++++++++++++++++++++
>     >  drivers/net/nfb/nfb_rx.c                | 127 +++++++
>     >  drivers/net/nfb/nfb_rx.h                | 231 ++++++++++++
>     >  drivers/net/nfb/nfb_rxmode.c            | 100 +++++
>     >  drivers/net/nfb/nfb_rxmode.h            |  96 +++++
>     >  drivers/net/nfb/nfb_stats.c             |  77 ++++
>     >  drivers/net/nfb/nfb_stats.h             |  56 +++
>     >  drivers/net/nfb/nfb_tx.c                | 113 ++++++
>     >  drivers/net/nfb/nfb_tx.h                | 222 +++++++++++
>     >  drivers/net/nfb/rte_nfb_pmd_version.map |   4 +
> 
>     The filename should be "rte_pmd_nfb_version.map" as stated in Makefile.
>     This brings the question, did you ever build dpdk as shared library or with
>     meson build system with this PMD enabled :)
>     Because it fails because of this wrong naming..
> 
> 
>     Even after renaming the .map file, meson build fails, I haven't dig the problem,
>     can you please check it?
> 
>     <...>
> 
>     > @@ -360,6 +360,10 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
>     >  # Compile software PMD backed by SZEDATA2 device
>     >  #
>     >  CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
>     > +#
>     > +# Compile software PMD backed by NFB device
>     > +#
>     > +CONFIG_RTE_LIBRTE_PMD_NFB=n
> 
>     Can you please rename the config option to "CONFIG_RTE_LIBRTE_NFB_PMD"?
>     I guess unintentionally, there is an convension,
>     Physical PMDs have the config name: CONFIG_RTE_LIBRTE_.*_PMD
>     Virtual PMDs have the config name:  CONFIG_RTE_LIBRTE_PMD_.*=y
>     I perfer same syntax for all, but it is what it is now, and I believe it doesn't
>     worth the hassle of changing them.
> 
>     I think only 'SZEDATA2' breaks current login, and I guess you copied from it,
>     but let's start NFB according convention: CONFIG_RTE_LIBRTE_NFB_PMD
> 
> 
>     Also please leave a blank line between previous config block.
> 
>     <...>
> 
>     > +Prerequisites
>     > +-------------
>     > +
>     > +This PMD requires kernel modules which are responsible for initialization and
>     > +allocation of resources needed for nfb layer function.
>     > +Communication between PMD and kernel modules is mediated by libnfb library.
>     > +These kernel modules and library are not part of DPDK and must be installed
>     > +separately:
>     > +
>     > +*  **libnfb library**
>     > +
>     > +   The library provides API for initialization of nfb transfers,
>     receiving and
>     > +   transmitting data segments.
>     > +
>     > +*  **Kernel modules**
>     > +
>     > +   * nfb
>     > +
>     > +   Kernel modules manage initialization of hardware, allocation and
>     > +   sharing of resources for user space applications.
>     > +
>     > +Dependencies can be found here:
>     > +`Netcope common
>     <https://www.netcope.com/en/company/community-support/dpdk-libsze2#NFB>`_.
> 
>     I have a problem here, this requires 'netcope-common-6.4.0-1.x86_64.rpm' rpm to
>     be installed [1], meanwhile szedata requires
>     'netcope-common-light-3.0.5-1.x86_64.rpm' to be installed, and these two
>     packages conflicts with eachother.
> 
>     What is the way of having an environment that dependencies of two netcope HW can
>     be provided at same time? This is really time consuming each time update system
>     for it.
> 
>     [1]
>     Is rpm only option, how people using Ubuntu for example will use your devices?
> 
>     > +
>     > +Versions of the packages
>     > +~~~~~~~~~~~~~~~~~~~~~~~~
>     > +
>     > +The minimum version of the provided packages:
>     > +
>     > +* for DPDK from 19.02
> 
>     Is it 19.05 now?
> 
>     <...>
> 
>     > +Example output:
>     > +
>     > +.. code-block:: console
>     > +
>     > +   [...]
>     > +   EAL: PCI device 0000:06:00.0 on NUMA socket -1
>     > +   EAL:   probe driver: 1b26:c1c1 net_nfb
>     > +   PMD: Initializing NFB device (0000:06:00.0)
>     > +   PMD: Available DMA queues RX: 8 TX: 8
>     > +   PMD: NFB device (0000:06:00.0) successfully initialized
>     > +   Interactive-mode selected
>     > +   Auto-start selected
>     > +   Configuring Port 0 (socket 0)
>     > +   Port 0: 00:11:17:00:00:00
>     > +   Checking link statuses...
>     > +   Port 0 Link Up - speed 10000 Mbps - full-duplex
>     > +   Done
>     > +   Start automatic packet forwarding
>     > +     io packet forwarding - CRC stripping disabled - packets/burst=32
>     > +     nb forwarding cores=2 - nb forwarding ports=1
>     > +     RX queues=2 - RX desc=128 - RX free threshold=0
>     > +     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
>     > +     TX queues=2 - TX desc=512 - TX free threshold=0
>     > +     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
>     > +     TX RS bit threshold=0 - TXQ flags=0x0
>     > +   testpmd>
> 
>     I think testpmd logging is not like this any more, can you please update the app
>     log with latest code.
> 
>     <...>
> 
>     > @@ -0,0 +1,44 @@
>     > +# SPDX-License-Identifier: BSD-3-Clause
>     > +# Copyright(c) 2018 Cesnet
>     > +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com
>     <mailto:info@netcope.com>>
> 
>     Should year be 2019, or 2018-2019?
> 
> 
>     <...>
> 
>     > @@ -0,0 +1,15 @@
>     > +# SPDX-License-Identifier: BSD-3-Clause
>     > +# Copyright(c) 2018 Cesnet
>     > +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com
>     <mailto:info@netcope.com>>
>     > +# All rights reserved.
>     > +
>     > +dep = cc.find_library('nfb', required: false)
>     > +
>     > +build = dep.found() and cc.has_header('nfb/nfb.h', dependencies: dep)
>     > +
>     > +allow_experimental_apis = true
> 
>     Why allow_experimental only in meson, but not Makefile?
>     Can you please add list of experimental APIs called just below this as comment?
> 
>     <...>
> 
>     > +/**
>     > + * Default MAC addr
>     > + */
>     > +static struct ether_addr eth_addr = {
>     > +     .addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
>     > +};
> 
>     it looks like this can be static const.
> 
>     > +
>     > +/**
>     > + * @warning
>     > + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
>     > + *
> 
>     Why these tags are added, to say PMD is experimental?
>     These only makes sense for public APIs which PMD doesn't have at all, these are
>     doxygen comments for API documentation. Please remove them.
> 
>     Also I recognized '__rte_experimental' tags, again which are for internal
>     checking and warning the applications if they are using experimental public API,
>     it doesn't apply here. Please remove them.
>     Last thing, the "EXPERIMENTAL" tag in .map file, that also doesn't apply here,
>     please make it release version, 'DPDK_19.05"
> 
>     I think your note about being experimental in MAINTAINERS file and the note in
>     release notes is good,
>     Can you please also update the driver documentation too, nfb.rst, to say driver
>     is experimental? I think those notes are good enough overall.
> 
> 
>     btw, why do you prefer to have driver as experimental?
>     What does it mean it being experimental from your point of view exactly?
> 
> 
>     <...>
> 
>     > +static int __rte_experimental
>     > +nfb_eth_mac_addr_set(struct rte_eth_dev *dev,
>     > +     struct ether_addr *mac_addr)
>     > +{
>     > +     unsigned int i;
>     > +     unsigned long long mac = 0;
> 
>     Would you prefer to use a fixed length deceleration, uint64_t?
> 
>     > +     struct rte_eth_dev_data *data = dev->data;
>     > +     struct pmd_internals *internals = (struct pmd_internals *)
>     > +             data->dev_private;
>     > +
>     > +     if (!is_valid_assigned_ether_addr(mac_addr))
>     > +             return -EINVAL;
>     > +
>     > +     for (i = 0; i < 6; i++) {
> 
>     Can you please use "ETHER_ADDR_LEN" instead of 6?
> 
>     <...>
> 
>     > +     for (i = 0; i < nb_rx; i++) {
>     > +             if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
>     > +                     stats->q_ipackets[i] = rx_queue[i].rx_pkts;
>     > +                     stats->q_ibytes[i] = rx_queue[i].rx_bytes;
>     > +             }
>     > +             rx_total += stats->q_ipackets[i];
>     > +             rx_total_bytes += stats->q_ibytes[i];
> 
>     Why these are not protected with "RTE_ETHDEV_QUEUE_STAT_CNTRS" check,
>     if "i >= RTE_ETHDEV_QUEUE_STAT_CNTRS" you shouldn't access to 'stats->q_.*[i]'
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v5] net/nfb: new netcope driver
  2019-04-01 14:55       ` Rastislav Černay
  2019-04-01 14:22         ` Ferruh Yigit
@ 2019-04-01 14:23         ` Luca Boccassi
  2019-04-01 14:23           ` Luca Boccassi
  2019-04-01 14:55         ` Rastislav Černay
  2 siblings, 1 reply; 50+ messages in thread
From: Luca Boccassi @ 2019-04-01 14:23 UTC (permalink / raw)
  To: Rastislav Černay, Ferruh Yigit; +Cc: dev

On Mon, 2019-04-01 at 16:55 +0200, Rastislav Černay wrote:
> Hi Ferruh,

<...>

> btw, why do you prefer to have driver as experimental?
> What does it mean it being experimental from your point of view
> exactly?
> <...>
> I do not prefer to have driver experimental, only reason it is there
> is
> this mail:
> 
> Luca Boccassi 
> bluca@debian.org
> 
> Tue, Mar 5, 11:41 PM
> to me, dev
> <...>
> > diff --git a/drivers/net/nfb/rte_nfb_pmd_version.map
> > b/drivers/net/nfb/rte_nfb_pmd_version.map
> > new file mode 100644
> > index 0000000..97fd251
> > --- /dev/null
> > +++ b/drivers/net/nfb/rte_nfb_pmd_version.map
> > @@ -0,0 +1,4 @@
> > +DPDK_19.02 {
> > +
> > +        local: *;
> > +};
> 
> These are all new symbols so they should be marked as experimental,
> please see doc/guides/contributing/versioning.rst
> 
> So after reading doc/guides/contributing/versioning.rst I thought
> that
> all new drivers should be experimental as they are new before they
> stabilize,
> and during this time changes can be done to public functions without
> much
> hassle.
> Should I keep driver experimental?

Sorry that was just a misunderstanding on my part, I was thinking of
libraries. Please disregard that comment.

-- 
Kind regards,
Luca Boccassi

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v5] net/nfb: new netcope driver
  2019-04-01 14:23         ` Luca Boccassi
@ 2019-04-01 14:23           ` Luca Boccassi
  0 siblings, 0 replies; 50+ messages in thread
From: Luca Boccassi @ 2019-04-01 14:23 UTC (permalink / raw)
  To: Rastislav Černay, Ferruh Yigit; +Cc: dev

On Mon, 2019-04-01 at 16:55 +0200, Rastislav Černay wrote:
> Hi Ferruh,

<...>

> btw, why do you prefer to have driver as experimental?
> What does it mean it being experimental from your point of view
> exactly?
> <...>
> I do not prefer to have driver experimental, only reason it is there
> is
> this mail:
> 
> Luca Boccassi 
> bluca@debian.org
> 
> Tue, Mar 5, 11:41 PM
> to me, dev
> <...>
> > diff --git a/drivers/net/nfb/rte_nfb_pmd_version.map
> > b/drivers/net/nfb/rte_nfb_pmd_version.map
> > new file mode 100644
> > index 0000000..97fd251
> > --- /dev/null
> > +++ b/drivers/net/nfb/rte_nfb_pmd_version.map
> > @@ -0,0 +1,4 @@
> > +DPDK_19.02 {
> > +
> > +        local: *;
> > +};
> 
> These are all new symbols so they should be marked as experimental,
> please see doc/guides/contributing/versioning.rst
> 
> So after reading doc/guides/contributing/versioning.rst I thought
> that
> all new drivers should be experimental as they are new before they
> stabilize,
> and during this time changes can be done to public functions without
> much
> hassle.
> Should I keep driver experimental?

Sorry that was just a misunderstanding on my part, I was thinking of
libraries. Please disregard that comment.

-- 
Kind regards,
Luca Boccassi

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v5] net/nfb: new netcope driver
  2019-03-28 16:01     ` Ferruh Yigit
  2019-03-28 16:01       ` Ferruh Yigit
@ 2019-04-01 14:55       ` Rastislav Černay
  2019-04-01 14:22         ` Ferruh Yigit
                           ` (2 more replies)
  1 sibling, 3 replies; 50+ messages in thread
From: Rastislav Černay @ 2019-04-01 14:55 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev

Hi Ferruh,

I fixed most of issues you wrote, but before I send v6, I would like to make
sure everything is in order, mainly the experimental issue.

I have a problem here, this requires 'netcope-common-6.4.0-1.x86_64.rpm'
rpm to
be installed [1], meanwhile szedata requires
'netcope-common-light-3.0.5-1.x86_64.rpm' to be installed, and these two
packages conflicts with eachother.

What is the way of having an environment that dependencies of two netcope
HW can
be provided at same time? This is really time consuming each time update
system
for it.

<...>
Sadly, szedata2 and nfb dirvers can not coexist in same enviroment. There
is no
way to provide dependecies at same time.

Is rpm only option, how people using Ubuntu for example will use your
devices?
<...>
For now, yes, only option is rpm and support for Ubuntu will be added later.


Why allow_experimental only in meson, but not Makefile?
<...>
It is in Makefile too.
CFLAGS += -DALLOW_EXPERIMENTAL_API

Can you please add list of experimental APIs called just below this as
comment?
<...>
No experimental API is called in driver.

btw, why do you prefer to have driver as experimental?
What does it mean it being experimental from your point of view exactly?
<...>
I do not prefer to have driver experimental, only reason it is there is
this mail:

Luca Boccassi bluca@debian.org
Tue, Mar 5, 11:41 PM
to me, dev
<...>
> diff --git a/drivers/net/nfb/rte_nfb_pmd_version.map
> b/drivers/net/nfb/rte_nfb_pmd_version.map
> new file mode 100644
> index 0000000..97fd251
> --- /dev/null
> +++ b/drivers/net/nfb/rte_nfb_pmd_version.map
> @@ -0,0 +1,4 @@
> +DPDK_19.02 {
> +
> +        local: *;
> +};

These are all new symbols so they should be marked as experimental,
please see doc/guides/contributing/versioning.rst

So after reading doc/guides/contributing/versioning.rst I thought that
all new drivers should be experimental as they are new before they
stabilize,
and during this time changes can be done to public functions without much
hassle.
Should I keep driver experimental?






*Rastislav Černay I Software DeveloperNetcope Technologies, a.s.T: +420 530
510 680 <+420%20530%20510%20680>A: Sochorova 3232/34, Brno, 616 00, Czech
Republic
<https://maps.google.com/?q=Sochorova+3232/34,+Brno,+616+00,%C2%A0Czech+Republic&entry=gmail&source=g>W:
www.netcope.com
<https://www.netcope.com/>  <https://www.netcope.com/>*



On Thu, Mar 28, 2019 at 5:01 PM Ferruh Yigit <ferruh.yigit@intel.com> wrote:

> On 3/22/2019 12:12 PM, Rastislav Cernay wrote:
> > From: Rastislav Cernay <cernay@netcope.com>
> >
> > Added new net driver for Netcope nfb cards
> >
> > Signed-off-by: Rastislav Cernay <cernay@netcope.com>
> > ---
> > v2: remove unnecessary cast
> >     remove unnecessary zeroing
> >     move declaration to not mix with code
> >     restore skeleton example
> > v3: add release notes
> >     add doc to doc index
> >     add architecture limits to doc
> >     edit features list
> >     add .map file
> >     change link to dependecies to official vendor site
> >     move declarations out of code
> >     remove false comments (rte_errno is set)
> >     comments to c89 style
> >     remove log from main rx loop
> >     remove redundant code
> > v4: API is experimental
> >     fixed meson build dependency
> >     random initial MAC
> >     stats->q_errors is for intput err only
> >     move more declarations to a beginning
> >     fixed err log in TX
> >     use of pkg-config
> > v5: fixed pkg-config for new version of netcope-common
> >  MAINTAINERS                             |   7 +
> >  config/common_base                      |   4 +
> >  devtools/test-build.sh                  |   1 +
> >  doc/guides/nics/features/nfb.ini        |  18 +
> >  doc/guides/nics/index.rst               |   1 +
> >  doc/guides/nics/nfb.rst                 | 143 +++++++
> >  doc/guides/rel_notes/release_19_02.rst  |   5 +
>
> Can you update the 19.05 release notes please?
>
> >  drivers/net/Makefile                    |   1 +
> >  drivers/net/meson.build                 |   1 +
> >  drivers/net/nfb/Makefile                |  44 +++
> >  drivers/net/nfb/meson.build             |  15 +
> >  drivers/net/nfb/nfb.h                   |  50 +++
> >  drivers/net/nfb/nfb_ethdev.c            | 647
> ++++++++++++++++++++++++++++++++
> >  drivers/net/nfb/nfb_rx.c                | 127 +++++++
> >  drivers/net/nfb/nfb_rx.h                | 231 ++++++++++++
> >  drivers/net/nfb/nfb_rxmode.c            | 100 +++++
> >  drivers/net/nfb/nfb_rxmode.h            |  96 +++++
> >  drivers/net/nfb/nfb_stats.c             |  77 ++++
> >  drivers/net/nfb/nfb_stats.h             |  56 +++
> >  drivers/net/nfb/nfb_tx.c                | 113 ++++++
> >  drivers/net/nfb/nfb_tx.h                | 222 +++++++++++
> >  drivers/net/nfb/rte_nfb_pmd_version.map |   4 +
>
> The filename should be "rte_pmd_nfb_version.map" as stated in Makefile.
> This brings the question, did you ever build dpdk as shared library or with
> meson build system with this PMD enabled :)
> Because it fails because of this wrong naming..
>
>
> Even after renaming the .map file, meson build fails, I haven't dig the
> problem,
> can you please check it?
>
> <...>
>
> > @@ -360,6 +360,10 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
> >  # Compile software PMD backed by SZEDATA2 device
> >  #
> >  CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
> > +#
> > +# Compile software PMD backed by NFB device
> > +#
> > +CONFIG_RTE_LIBRTE_PMD_NFB=n
>
> Can you please rename the config option to "CONFIG_RTE_LIBRTE_NFB_PMD"?
> I guess unintentionally, there is an convension,
> Physical PMDs have the config name: CONFIG_RTE_LIBRTE_.*_PMD
> Virtual PMDs have the config name:  CONFIG_RTE_LIBRTE_PMD_.*=y
> I perfer same syntax for all, but it is what it is now, and I believe it
> doesn't
> worth the hassle of changing them.
>
> I think only 'SZEDATA2' breaks current login, and I guess you copied from
> it,
> but let's start NFB according convention: CONFIG_RTE_LIBRTE_NFB_PMD
>
>
> Also please leave a blank line between previous config block.
>
> <...>
>
> > +Prerequisites
> > +-------------
> > +
> > +This PMD requires kernel modules which are responsible for
> initialization and
> > +allocation of resources needed for nfb layer function.
> > +Communication between PMD and kernel modules is mediated by libnfb
> library.
> > +These kernel modules and library are not part of DPDK and must be
> installed
> > +separately:
> > +
> > +*  **libnfb library**
> > +
> > +   The library provides API for initialization of nfb transfers,
> receiving and
> > +   transmitting data segments.
> > +
> > +*  **Kernel modules**
> > +
> > +   * nfb
> > +
> > +   Kernel modules manage initialization of hardware, allocation and
> > +   sharing of resources for user space applications.
> > +
> > +Dependencies can be found here:
> > +`Netcope common <
> https://www.netcope.com/en/company/community-support/dpdk-libsze2#NFB>`_.
>
> I have a problem here, this requires 'netcope-common-6.4.0-1.x86_64.rpm'
> rpm to
> be installed [1], meanwhile szedata requires
> 'netcope-common-light-3.0.5-1.x86_64.rpm' to be installed, and these two
> packages conflicts with eachother.
>
> What is the way of having an environment that dependencies of two netcope
> HW can
> be provided at same time? This is really time consuming each time update
> system
> for it.
>
> [1]
> Is rpm only option, how people using Ubuntu for example will use your
> devices?
>
> > +
> > +Versions of the packages
> > +~~~~~~~~~~~~~~~~~~~~~~~~
> > +
> > +The minimum version of the provided packages:
> > +
> > +* for DPDK from 19.02
>
> Is it 19.05 now?
>
> <...>
>
> > +Example output:
> > +
> > +.. code-block:: console
> > +
> > +   [...]
> > +   EAL: PCI device 0000:06:00.0 on NUMA socket -1
> > +   EAL:   probe driver: 1b26:c1c1 net_nfb
> > +   PMD: Initializing NFB device (0000:06:00.0)
> > +   PMD: Available DMA queues RX: 8 TX: 8
> > +   PMD: NFB device (0000:06:00.0) successfully initialized
> > +   Interactive-mode selected
> > +   Auto-start selected
> > +   Configuring Port 0 (socket 0)
> > +   Port 0: 00:11:17:00:00:00
> > +   Checking link statuses...
> > +   Port 0 Link Up - speed 10000 Mbps - full-duplex
> > +   Done
> > +   Start automatic packet forwarding
> > +     io packet forwarding - CRC stripping disabled - packets/burst=32
> > +     nb forwarding cores=2 - nb forwarding ports=1
> > +     RX queues=2 - RX desc=128 - RX free threshold=0
> > +     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
> > +     TX queues=2 - TX desc=512 - TX free threshold=0
> > +     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
> > +     TX RS bit threshold=0 - TXQ flags=0x0
> > +   testpmd>
>
> I think testpmd logging is not like this any more, can you please update
> the app
> log with latest code.
>
> <...>
>
> > @@ -0,0 +1,44 @@
> > +# SPDX-License-Identifier: BSD-3-Clause
> > +# Copyright(c) 2018 Cesnet
> > +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
>
> Should year be 2019, or 2018-2019?
>
>
> <...>
>
> > @@ -0,0 +1,15 @@
> > +# SPDX-License-Identifier: BSD-3-Clause
> > +# Copyright(c) 2018 Cesnet
> > +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> > +# All rights reserved.
> > +
> > +dep = cc.find_library('nfb', required: false)
> > +
> > +build = dep.found() and cc.has_header('nfb/nfb.h', dependencies: dep)
> > +
> > +allow_experimental_apis = true
>
> Why allow_experimental only in meson, but not Makefile?
> Can you please add list of experimental APIs called just below this as
> comment?
>
> <...>
>
> > +/**
> > + * Default MAC addr
> > + */
> > +static struct ether_addr eth_addr = {
> > +     .addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
> > +};
>
> it looks like this can be static const.
>
> > +
> > +/**
> > + * @warning
> > + * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> > + *
>
> Why these tags are added, to say PMD is experimental?
> These only makes sense for public APIs which PMD doesn't have at all,
> these are
> doxygen comments for API documentation. Please remove them.
>
> Also I recognized '__rte_experimental' tags, again which are for internal
> checking and warning the applications if they are using experimental
> public API,
> it doesn't apply here. Please remove them.
> Last thing, the "EXPERIMENTAL" tag in .map file, that also doesn't apply
> here,
> please make it release version, 'DPDK_19.05"
>
> I think your note about being experimental in MAINTAINERS file and the
> note in
> release notes is good,
> Can you please also update the driver documentation too, nfb.rst, to say
> driver
> is experimental? I think those notes are good enough overall.
>
>
> btw, why do you prefer to have driver as experimental?
> What does it mean it being experimental from your point of view exactly?
>
>
> <...>
>
> > +static int __rte_experimental
> > +nfb_eth_mac_addr_set(struct rte_eth_dev *dev,
> > +     struct ether_addr *mac_addr)
> > +{
> > +     unsigned int i;
> > +     unsigned long long mac = 0;
>
> Would you prefer to use a fixed length deceleration, uint64_t?
>
> > +     struct rte_eth_dev_data *data = dev->data;
> > +     struct pmd_internals *internals = (struct pmd_internals *)
> > +             data->dev_private;
> > +
> > +     if (!is_valid_assigned_ether_addr(mac_addr))
> > +             return -EINVAL;
> > +
> > +     for (i = 0; i < 6; i++) {
>
> Can you please use "ETHER_ADDR_LEN" instead of 6?
>
> <...>
>
> > +     for (i = 0; i < nb_rx; i++) {
> > +             if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> > +                     stats->q_ipackets[i] = rx_queue[i].rx_pkts;
> > +                     stats->q_ibytes[i] = rx_queue[i].rx_bytes;
> > +             }
> > +             rx_total += stats->q_ipackets[i];
> > +             rx_total_bytes += stats->q_ibytes[i];
>
> Why these are not protected with "RTE_ETHDEV_QUEUE_STAT_CNTRS" check,
> if "i >= RTE_ETHDEV_QUEUE_STAT_CNTRS" you shouldn't access to
> 'stats->q_.*[i]'
>

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v5] net/nfb: new netcope driver
  2019-04-01 14:55       ` Rastislav Černay
  2019-04-01 14:22         ` Ferruh Yigit
  2019-04-01 14:23         ` Luca Boccassi
@ 2019-04-01 14:55         ` Rastislav Černay
  2 siblings, 0 replies; 50+ messages in thread
From: Rastislav Černay @ 2019-04-01 14:55 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev

Hi Ferruh,

I fixed most of issues you wrote, but before I send v6, I would like to make
sure everything is in order, mainly the experimental issue.

I have a problem here, this requires 'netcope-common-6.4.0-1.x86_64.rpm'
rpm to
be installed [1], meanwhile szedata requires
'netcope-common-light-3.0.5-1.x86_64.rpm' to be installed, and these two
packages conflicts with eachother.

What is the way of having an environment that dependencies of two netcope
HW can
be provided at same time? This is really time consuming each time update
system
for it.

<...>
Sadly, szedata2 and nfb dirvers can not coexist in same enviroment. There
is no
way to provide dependecies at same time.

Is rpm only option, how people using Ubuntu for example will use your
devices?
<...>
For now, yes, only option is rpm and support for Ubuntu will be added later.


Why allow_experimental only in meson, but not Makefile?
<...>
It is in Makefile too.
CFLAGS += -DALLOW_EXPERIMENTAL_API

Can you please add list of experimental APIs called just below this as
comment?
<...>
No experimental API is called in driver.

btw, why do you prefer to have driver as experimental?
What does it mean it being experimental from your point of view exactly?
<...>
I do not prefer to have driver experimental, only reason it is there is
this mail:

Luca Boccassi bluca@debian.org
Tue, Mar 5, 11:41 PM
to me, dev
<...>
> diff --git a/drivers/net/nfb/rte_nfb_pmd_version.map
> b/drivers/net/nfb/rte_nfb_pmd_version.map
> new file mode 100644
> index 0000000..97fd251
> --- /dev/null
> +++ b/drivers/net/nfb/rte_nfb_pmd_version.map
> @@ -0,0 +1,4 @@
> +DPDK_19.02 {
> +
> +        local: *;
> +};

These are all new symbols so they should be marked as experimental,
please see doc/guides/contributing/versioning.rst

So after reading doc/guides/contributing/versioning.rst I thought that
all new drivers should be experimental as they are new before they
stabilize,
and during this time changes can be done to public functions without much
hassle.
Should I keep driver experimental?






*Rastislav Černay I Software DeveloperNetcope Technologies, a.s.T: +420 530
510 680 <+420%20530%20510%20680>A: Sochorova 3232/34, Brno, 616 00, Czech
Republic
<https://maps.google.com/?q=Sochorova+3232/34,+Brno,+616+00,%C2%A0Czech+Republic&entry=gmail&source=g>W:
www.netcope.com
<https://www.netcope.com/>  <https://www.netcope.com/>*



On Thu, Mar 28, 2019 at 5:01 PM Ferruh Yigit <ferruh.yigit@intel.com> wrote:

> On 3/22/2019 12:12 PM, Rastislav Cernay wrote:
> > From: Rastislav Cernay <cernay@netcope.com>
> >
> > Added new net driver for Netcope nfb cards
> >
> > Signed-off-by: Rastislav Cernay <cernay@netcope.com>
> > ---
> > v2: remove unnecessary cast
> >     remove unnecessary zeroing
> >     move declaration to not mix with code
> >     restore skeleton example
> > v3: add release notes
> >     add doc to doc index
> >     add architecture limits to doc
> >     edit features list
> >     add .map file
> >     change link to dependecies to official vendor site
> >     move declarations out of code
> >     remove false comments (rte_errno is set)
> >     comments to c89 style
> >     remove log from main rx loop
> >     remove redundant code
> > v4: API is experimental
> >     fixed meson build dependency
> >     random initial MAC
> >     stats->q_errors is for intput err only
> >     move more declarations to a beginning
> >     fixed err log in TX
> >     use of pkg-config
> > v5: fixed pkg-config for new version of netcope-common
> >  MAINTAINERS                             |   7 +
> >  config/common_base                      |   4 +
> >  devtools/test-build.sh                  |   1 +
> >  doc/guides/nics/features/nfb.ini        |  18 +
> >  doc/guides/nics/index.rst               |   1 +
> >  doc/guides/nics/nfb.rst                 | 143 +++++++
> >  doc/guides/rel_notes/release_19_02.rst  |   5 +
>
> Can you update the 19.05 release notes please?
>
> >  drivers/net/Makefile                    |   1 +
> >  drivers/net/meson.build                 |   1 +
> >  drivers/net/nfb/Makefile                |  44 +++
> >  drivers/net/nfb/meson.build             |  15 +
> >  drivers/net/nfb/nfb.h                   |  50 +++
> >  drivers/net/nfb/nfb_ethdev.c            | 647
> ++++++++++++++++++++++++++++++++
> >  drivers/net/nfb/nfb_rx.c                | 127 +++++++
> >  drivers/net/nfb/nfb_rx.h                | 231 ++++++++++++
> >  drivers/net/nfb/nfb_rxmode.c            | 100 +++++
> >  drivers/net/nfb/nfb_rxmode.h            |  96 +++++
> >  drivers/net/nfb/nfb_stats.c             |  77 ++++
> >  drivers/net/nfb/nfb_stats.h             |  56 +++
> >  drivers/net/nfb/nfb_tx.c                | 113 ++++++
> >  drivers/net/nfb/nfb_tx.h                | 222 +++++++++++
> >  drivers/net/nfb/rte_nfb_pmd_version.map |   4 +
>
> The filename should be "rte_pmd_nfb_version.map" as stated in Makefile.
> This brings the question, did you ever build dpdk as shared library or with
> meson build system with this PMD enabled :)
> Because it fails because of this wrong naming..
>
>
> Even after renaming the .map file, meson build fails, I haven't dig the
> problem,
> can you please check it?
>
> <...>
>
> > @@ -360,6 +360,10 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
> >  # Compile software PMD backed by SZEDATA2 device
> >  #
> >  CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
> > +#
> > +# Compile software PMD backed by NFB device
> > +#
> > +CONFIG_RTE_LIBRTE_PMD_NFB=n
>
> Can you please rename the config option to "CONFIG_RTE_LIBRTE_NFB_PMD"?
> I guess unintentionally, there is an convension,
> Physical PMDs have the config name: CONFIG_RTE_LIBRTE_.*_PMD
> Virtual PMDs have the config name:  CONFIG_RTE_LIBRTE_PMD_.*=y
> I perfer same syntax for all, but it is what it is now, and I believe it
> doesn't
> worth the hassle of changing them.
>
> I think only 'SZEDATA2' breaks current login, and I guess you copied from
> it,
> but let's start NFB according convention: CONFIG_RTE_LIBRTE_NFB_PMD
>
>
> Also please leave a blank line between previous config block.
>
> <...>
>
> > +Prerequisites
> > +-------------
> > +
> > +This PMD requires kernel modules which are responsible for
> initialization and
> > +allocation of resources needed for nfb layer function.
> > +Communication between PMD and kernel modules is mediated by libnfb
> library.
> > +These kernel modules and library are not part of DPDK and must be
> installed
> > +separately:
> > +
> > +*  **libnfb library**
> > +
> > +   The library provides API for initialization of nfb transfers,
> receiving and
> > +   transmitting data segments.
> > +
> > +*  **Kernel modules**
> > +
> > +   * nfb
> > +
> > +   Kernel modules manage initialization of hardware, allocation and
> > +   sharing of resources for user space applications.
> > +
> > +Dependencies can be found here:
> > +`Netcope common <
> https://www.netcope.com/en/company/community-support/dpdk-libsze2#NFB>`_.
>
> I have a problem here, this requires 'netcope-common-6.4.0-1.x86_64.rpm'
> rpm to
> be installed [1], meanwhile szedata requires
> 'netcope-common-light-3.0.5-1.x86_64.rpm' to be installed, and these two
> packages conflicts with eachother.
>
> What is the way of having an environment that dependencies of two netcope
> HW can
> be provided at same time? This is really time consuming each time update
> system
> for it.
>
> [1]
> Is rpm only option, how people using Ubuntu for example will use your
> devices?
>
> > +
> > +Versions of the packages
> > +~~~~~~~~~~~~~~~~~~~~~~~~
> > +
> > +The minimum version of the provided packages:
> > +
> > +* for DPDK from 19.02
>
> Is it 19.05 now?
>
> <...>
>
> > +Example output:
> > +
> > +.. code-block:: console
> > +
> > +   [...]
> > +   EAL: PCI device 0000:06:00.0 on NUMA socket -1
> > +   EAL:   probe driver: 1b26:c1c1 net_nfb
> > +   PMD: Initializing NFB device (0000:06:00.0)
> > +   PMD: Available DMA queues RX: 8 TX: 8
> > +   PMD: NFB device (0000:06:00.0) successfully initialized
> > +   Interactive-mode selected
> > +   Auto-start selected
> > +   Configuring Port 0 (socket 0)
> > +   Port 0: 00:11:17:00:00:00
> > +   Checking link statuses...
> > +   Port 0 Link Up - speed 10000 Mbps - full-duplex
> > +   Done
> > +   Start automatic packet forwarding
> > +     io packet forwarding - CRC stripping disabled - packets/burst=32
> > +     nb forwarding cores=2 - nb forwarding ports=1
> > +     RX queues=2 - RX desc=128 - RX free threshold=0
> > +     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
> > +     TX queues=2 - TX desc=512 - TX free threshold=0
> > +     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
> > +     TX RS bit threshold=0 - TXQ flags=0x0
> > +   testpmd>
>
> I think testpmd logging is not like this any more, can you please update
> the app
> log with latest code.
>
> <...>
>
> > @@ -0,0 +1,44 @@
> > +# SPDX-License-Identifier: BSD-3-Clause
> > +# Copyright(c) 2018 Cesnet
> > +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
>
> Should year be 2019, or 2018-2019?
>
>
> <...>
>
> > @@ -0,0 +1,15 @@
> > +# SPDX-License-Identifier: BSD-3-Clause
> > +# Copyright(c) 2018 Cesnet
> > +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com>
> > +# All rights reserved.
> > +
> > +dep = cc.find_library('nfb', required: false)
> > +
> > +build = dep.found() and cc.has_header('nfb/nfb.h', dependencies: dep)
> > +
> > +allow_experimental_apis = true
>
> Why allow_experimental only in meson, but not Makefile?
> Can you please add list of experimental APIs called just below this as
> comment?
>
> <...>
>
> > +/**
> > + * Default MAC addr
> > + */
> > +static struct ether_addr eth_addr = {
> > +     .addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
> > +};
>
> it looks like this can be static const.
>
> > +
> > +/**
> > + * @warning
> > + * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> > + *
>
> Why these tags are added, to say PMD is experimental?
> These only makes sense for public APIs which PMD doesn't have at all,
> these are
> doxygen comments for API documentation. Please remove them.
>
> Also I recognized '__rte_experimental' tags, again which are for internal
> checking and warning the applications if they are using experimental
> public API,
> it doesn't apply here. Please remove them.
> Last thing, the "EXPERIMENTAL" tag in .map file, that also doesn't apply
> here,
> please make it release version, 'DPDK_19.05"
>
> I think your note about being experimental in MAINTAINERS file and the
> note in
> release notes is good,
> Can you please also update the driver documentation too, nfb.rst, to say
> driver
> is experimental? I think those notes are good enough overall.
>
>
> btw, why do you prefer to have driver as experimental?
> What does it mean it being experimental from your point of view exactly?
>
>
> <...>
>
> > +static int __rte_experimental
> > +nfb_eth_mac_addr_set(struct rte_eth_dev *dev,
> > +     struct ether_addr *mac_addr)
> > +{
> > +     unsigned int i;
> > +     unsigned long long mac = 0;
>
> Would you prefer to use a fixed length deceleration, uint64_t?
>
> > +     struct rte_eth_dev_data *data = dev->data;
> > +     struct pmd_internals *internals = (struct pmd_internals *)
> > +             data->dev_private;
> > +
> > +     if (!is_valid_assigned_ether_addr(mac_addr))
> > +             return -EINVAL;
> > +
> > +     for (i = 0; i < 6; i++) {
>
> Can you please use "ETHER_ADDR_LEN" instead of 6?
>
> <...>
>
> > +     for (i = 0; i < nb_rx; i++) {
> > +             if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> > +                     stats->q_ipackets[i] = rx_queue[i].rx_pkts;
> > +                     stats->q_ibytes[i] = rx_queue[i].rx_bytes;
> > +             }
> > +             rx_total += stats->q_ipackets[i];
> > +             rx_total_bytes += stats->q_ibytes[i];
>
> Why these are not protected with "RTE_ETHDEV_QUEUE_STAT_CNTRS" check,
> if "i >= RTE_ETHDEV_QUEUE_STAT_CNTRS" you shouldn't access to
> 'stats->q_.*[i]'
>

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v5] net/nfb: new netcope driver
  2019-04-01 14:22         ` Ferruh Yigit
  2019-04-01 14:22           ` Ferruh Yigit
@ 2019-04-02 16:05           ` Rastislav Černay
  2019-04-02 16:05             ` Rastislav Černay
  1 sibling, 1 reply; 50+ messages in thread
From: Rastislav Černay @ 2019-04-02 16:05 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev

> I have a problem here, this requires 'netcope-common-6.4.0-1.x86_64.rpm'
rpm to
> be installed [1], meanwhile szedata requires
> 'netcope-common-light-3.0.5-1.x86_64.rpm' to be installed, and these two
> packages conflicts with eachother.
>
> What is the way of having an environment that dependencies of two netcope
HW can
> be provided at same time? This is really time consuming each time update
system
> for it.
>
> <...>
> Sadly, szedata2 and nfb dirvers can not coexist in same enviroment. There
is no
> way to provide dependecies at same time.

>Isn't this also problem for you too? What is your solution when testing
both?

For us this is not a problem. The nfb driver is direct incompatible
continuation of
szedata2 driver. They are both working on same HW and thus it does not make
sense to have both on same system. So our solution is not to test them both
at
same time.






*Rastislav Černay I Software DeveloperNetcope Technologies, a.s.T: +420 530
510 680 <+420%20530%20510%20680>A: Sochorova 3232/34, Brno, 616 00, Czech
Republic
<https://maps.google.com/?q=Sochorova+3232/34,+Brno,+616+00,%C2%A0Czech+Republic&entry=gmail&source=g>W:
www.netcope.com
<https://www.netcope.com/>  <https://www.netcope.com/>*



On Mon, Apr 1, 2019 at 4:22 PM Ferruh Yigit <ferruh.yigit@intel.com> wrote:

> On 4/1/2019 3:55 PM, Rastislav Černay wrote:
> > Hi Ferruh,
> >
> > I fixed most of issues you wrote, but before I send v6, I would like to
> make
> > sure everything is in order, mainly the experimental issue.
> >
> > I have a problem here, this requires 'netcope-common-6.4.0-1.x86_64.rpm'
> rpm to
> > be installed [1], meanwhile szedata requires
> > 'netcope-common-light-3.0.5-1.x86_64.rpm' to be installed, and these two
> > packages conflicts with eachother.
> >
> > What is the way of having an environment that dependencies of two
> netcope HW can
> > be provided at same time? This is really time consuming each time update
> system
> > for it.
> >
> > <...>
> > Sadly, szedata2 and nfb dirvers can not coexist in same enviroment.
> There is no
> > way to provide dependecies at same time.
>
> Isn't this also problem for you too? What is your solution when testing
> both?
>
> >
> > Is rpm only option, how people using Ubuntu for example will use your
> devices?
> > <...>
> > For now, yes, only option is rpm and support for Ubuntu will be added
> later.
>
> Is this limitation in driver document? If not can you please update it.
>
> >
> >
> > Why allow_experimental only in meson, but not Makefile?
> > <...>
> > It is in Makefile too.
> > CFLAGS += -DALLOW_EXPERIMENTAL_API
> >
> > Can you please add list of experimental APIs called just below this as
> comment?
> > <...>
> > No experimental API is called in driver.
>
> OK, so please clean the meson file.
>
> >
> > btw, why do you prefer to have driver as experimental?
> > What does it mean it being experimental from your point of view exactly?
> > <...>
> > I do not prefer to have driver experimental, only reason it is there is
> > this mail:
> >
> > Luca Boccassi bluca@debian.org <mailto:bluca@debian.org>
> > Tue, Mar 5, 11:41 PM
> > to me, dev
> > <...>
> >> diff --git a/drivers/net/nfb/rte_nfb_pmd_version.map
> >> b/drivers/net/nfb/rte_nfb_pmd_version.map
> >> new file mode 100644
> >> index 0000000..97fd251
> >> --- /dev/null
> >> +++ b/drivers/net/nfb/rte_nfb_pmd_version.map
> >> @@ -0,0 +1,4 @@
> >> +DPDK_19.02 {
> >> +
> >> +        local: *;
> >> +};
> >
> > These are all new symbols so they should be marked as experimental,
> > please see doc/guides/contributing/versioning.rst
> >
> > So after reading doc/guides/contributing/versioning.rst I thought that
> > all new drivers should be experimental as they are new before they
> stabilize,
> > and during this time changes can be done to public functions without
> much hassle.
> > Should I keep driver experimental?
>
> No please don't keep it experimental. Luca is right new symbols should be
> marked
> as experimental, here news symbols are APIs and this PMD doesn't have any,
> all
> it has is 'local' symbols.
> cc'ed Luca if I am missing anything.
>
> And if this is the only reason you documented the PMD as experimental, you
> can
> clean MAINTAINERS file, release notes etc...
>
> >
> > *
> >
> > *Rastislav Černay I /Software Developer/*
> > Netcope Technologies, a.s.
> >
> > *T:* +420 530 510 680 <tel:+420%20530%20510%20680>
> > *A:* Sochorova 3232/34, Brno, 616 00, Czech Republic
> > <
> https://maps.google.com/?q=Sochorova+3232/34,+Brno,+616+00,%C2%A0Czech+Republic&entry=gmail&source=g
> >
> > *W: www.netcope.com <https://www.netcope.com/>
> >
> >  <https://www.netcope.com/>*
> >
> > *
> > **
> >
> >
> >
> > On Thu, Mar 28, 2019 at 5:01 PM Ferruh Yigit <ferruh.yigit@intel.com
> > <mailto:ferruh.yigit@intel.com>> wrote:
> >
> >     On 3/22/2019 12:12 PM, Rastislav Cernay wrote:
> >     > From: Rastislav Cernay <cernay@netcope.com <mailto:
> cernay@netcope.com>>
> >     >
> >     > Added new net driver for Netcope nfb cards
> >     >
> >     > Signed-off-by: Rastislav Cernay <cernay@netcope.com
> >     <mailto:cernay@netcope.com>>
> >     > ---
> >     > v2: remove unnecessary cast
> >     >     remove unnecessary zeroing
> >     >     move declaration to not mix with code
> >     >     restore skeleton example
> >     > v3: add release notes
> >     >     add doc to doc index
> >     >     add architecture limits to doc
> >     >     edit features list
> >     >     add .map file
> >     >     change link to dependecies to official vendor site
> >     >     move declarations out of code
> >     >     remove false comments (rte_errno is set)
> >     >     comments to c89 style
> >     >     remove log from main rx loop
> >     >     remove redundant code
> >     > v4: API is experimental
> >     >     fixed meson build dependency
> >     >     random initial MAC
> >     >     stats->q_errors is for intput err only
> >     >     move more declarations to a beginning
> >     >     fixed err log in TX
> >     >     use of pkg-config
> >     > v5: fixed pkg-config for new version of netcope-common
> >     >  MAINTAINERS                             |   7 +
> >     >  config/common_base                      |   4 +
> >     >  devtools/test-build.sh                  |   1 +
> >     >  doc/guides/nics/features/nfb.ini        |  18 +
> >     >  doc/guides/nics/index.rst               |   1 +
> >     >  doc/guides/nics/nfb.rst                 | 143 +++++++
> >     >  doc/guides/rel_notes/release_19_02.rst  |   5 +
> >
> >     Can you update the 19.05 release notes please?
> >
> >     >  drivers/net/Makefile                    |   1 +
> >     >  drivers/net/meson.build                 |   1 +
> >     >  drivers/net/nfb/Makefile                |  44 +++
> >     >  drivers/net/nfb/meson.build             |  15 +
> >     >  drivers/net/nfb/nfb.h                   |  50 +++
> >     >  drivers/net/nfb/nfb_ethdev.c            | 647
> >     ++++++++++++++++++++++++++++++++
> >     >  drivers/net/nfb/nfb_rx.c                | 127 +++++++
> >     >  drivers/net/nfb/nfb_rx.h                | 231 ++++++++++++
> >     >  drivers/net/nfb/nfb_rxmode.c            | 100 +++++
> >     >  drivers/net/nfb/nfb_rxmode.h            |  96 +++++
> >     >  drivers/net/nfb/nfb_stats.c             |  77 ++++
> >     >  drivers/net/nfb/nfb_stats.h             |  56 +++
> >     >  drivers/net/nfb/nfb_tx.c                | 113 ++++++
> >     >  drivers/net/nfb/nfb_tx.h                | 222 +++++++++++
> >     >  drivers/net/nfb/rte_nfb_pmd_version.map |   4 +
> >
> >     The filename should be "rte_pmd_nfb_version.map" as stated in
> Makefile.
> >     This brings the question, did you ever build dpdk as shared library
> or with
> >     meson build system with this PMD enabled :)
> >     Because it fails because of this wrong naming..
> >
> >
> >     Even after renaming the .map file, meson build fails, I haven't dig
> the problem,
> >     can you please check it?
> >
> >     <...>
> >
> >     > @@ -360,6 +360,10 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
> >     >  # Compile software PMD backed by SZEDATA2 device
> >     >  #
> >     >  CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
> >     > +#
> >     > +# Compile software PMD backed by NFB device
> >     > +#
> >     > +CONFIG_RTE_LIBRTE_PMD_NFB=n
> >
> >     Can you please rename the config option to
> "CONFIG_RTE_LIBRTE_NFB_PMD"?
> >     I guess unintentionally, there is an convension,
> >     Physical PMDs have the config name: CONFIG_RTE_LIBRTE_.*_PMD
> >     Virtual PMDs have the config name:  CONFIG_RTE_LIBRTE_PMD_.*=y
> >     I perfer same syntax for all, but it is what it is now, and I
> believe it doesn't
> >     worth the hassle of changing them.
> >
> >     I think only 'SZEDATA2' breaks current login, and I guess you copied
> from it,
> >     but let's start NFB according convention: CONFIG_RTE_LIBRTE_NFB_PMD
> >
> >
> >     Also please leave a blank line between previous config block.
> >
> >     <...>
> >
> >     > +Prerequisites
> >     > +-------------
> >     > +
> >     > +This PMD requires kernel modules which are responsible for
> initialization and
> >     > +allocation of resources needed for nfb layer function.
> >     > +Communication between PMD and kernel modules is mediated by
> libnfb library.
> >     > +These kernel modules and library are not part of DPDK and must be
> installed
> >     > +separately:
> >     > +
> >     > +*  **libnfb library**
> >     > +
> >     > +   The library provides API for initialization of nfb transfers,
> >     receiving and
> >     > +   transmitting data segments.
> >     > +
> >     > +*  **Kernel modules**
> >     > +
> >     > +   * nfb
> >     > +
> >     > +   Kernel modules manage initialization of hardware, allocation
> and
> >     > +   sharing of resources for user space applications.
> >     > +
> >     > +Dependencies can be found here:
> >     > +`Netcope common
> >     <
> https://www.netcope.com/en/company/community-support/dpdk-libsze2#NFB>`_.
> >
> >     I have a problem here, this requires
> 'netcope-common-6.4.0-1.x86_64.rpm' rpm to
> >     be installed [1], meanwhile szedata requires
> >     'netcope-common-light-3.0.5-1.x86_64.rpm' to be installed, and these
> two
> >     packages conflicts with eachother.
> >
> >     What is the way of having an environment that dependencies of two
> netcope HW can
> >     be provided at same time? This is really time consuming each time
> update system
> >     for it.
> >
> >     [1]
> >     Is rpm only option, how people using Ubuntu for example will use
> your devices?
> >
> >     > +
> >     > +Versions of the packages
> >     > +~~~~~~~~~~~~~~~~~~~~~~~~
> >     > +
> >     > +The minimum version of the provided packages:
> >     > +
> >     > +* for DPDK from 19.02
> >
> >     Is it 19.05 now?
> >
> >     <...>
> >
> >     > +Example output:
> >     > +
> >     > +.. code-block:: console
> >     > +
> >     > +   [...]
> >     > +   EAL: PCI device 0000:06:00.0 on NUMA socket -1
> >     > +   EAL:   probe driver: 1b26:c1c1 net_nfb
> >     > +   PMD: Initializing NFB device (0000:06:00.0)
> >     > +   PMD: Available DMA queues RX: 8 TX: 8
> >     > +   PMD: NFB device (0000:06:00.0) successfully initialized
> >     > +   Interactive-mode selected
> >     > +   Auto-start selected
> >     > +   Configuring Port 0 (socket 0)
> >     > +   Port 0: 00:11:17:00:00:00
> >     > +   Checking link statuses...
> >     > +   Port 0 Link Up - speed 10000 Mbps - full-duplex
> >     > +   Done
> >     > +   Start automatic packet forwarding
> >     > +     io packet forwarding - CRC stripping disabled -
> packets/burst=32
> >     > +     nb forwarding cores=2 - nb forwarding ports=1
> >     > +     RX queues=2 - RX desc=128 - RX free threshold=0
> >     > +     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
> >     > +     TX queues=2 - TX desc=512 - TX free threshold=0
> >     > +     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
> >     > +     TX RS bit threshold=0 - TXQ flags=0x0
> >     > +   testpmd>
> >
> >     I think testpmd logging is not like this any more, can you please
> update the app
> >     log with latest code.
> >
> >     <...>
> >
> >     > @@ -0,0 +1,44 @@
> >     > +# SPDX-License-Identifier: BSD-3-Clause
> >     > +# Copyright(c) 2018 Cesnet
> >     > +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com
> >     <mailto:info@netcope.com>>
> >
> >     Should year be 2019, or 2018-2019?
> >
> >
> >     <...>
> >
> >     > @@ -0,0 +1,15 @@
> >     > +# SPDX-License-Identifier: BSD-3-Clause
> >     > +# Copyright(c) 2018 Cesnet
> >     > +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com
> >     <mailto:info@netcope.com>>
> >     > +# All rights reserved.
> >     > +
> >     > +dep = cc.find_library('nfb', required: false)
> >     > +
> >     > +build = dep.found() and cc.has_header('nfb/nfb.h', dependencies:
> dep)
> >     > +
> >     > +allow_experimental_apis = true
> >
> >     Why allow_experimental only in meson, but not Makefile?
> >     Can you please add list of experimental APIs called just below this
> as comment?
> >
> >     <...>
> >
> >     > +/**
> >     > + * Default MAC addr
> >     > + */
> >     > +static struct ether_addr eth_addr = {
> >     > +     .addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
> >     > +};
> >
> >     it looks like this can be static const.
> >
> >     > +
> >     > +/**
> >     > + * @warning
> >     > + * @b EXPERIMENTAL: this API may change, or be removed, without
> prior notice
> >     > + *
> >
> >     Why these tags are added, to say PMD is experimental?
> >     These only makes sense for public APIs which PMD doesn't have at
> all, these are
> >     doxygen comments for API documentation. Please remove them.
> >
> >     Also I recognized '__rte_experimental' tags, again which are for
> internal
> >     checking and warning the applications if they are using experimental
> public API,
> >     it doesn't apply here. Please remove them.
> >     Last thing, the "EXPERIMENTAL" tag in .map file, that also doesn't
> apply here,
> >     please make it release version, 'DPDK_19.05"
> >
> >     I think your note about being experimental in MAINTAINERS file and
> the note in
> >     release notes is good,
> >     Can you please also update the driver documentation too, nfb.rst, to
> say driver
> >     is experimental? I think those notes are good enough overall.
> >
> >
> >     btw, why do you prefer to have driver as experimental?
> >     What does it mean it being experimental from your point of view
> exactly?
> >
> >
> >     <...>
> >
> >     > +static int __rte_experimental
> >     > +nfb_eth_mac_addr_set(struct rte_eth_dev *dev,
> >     > +     struct ether_addr *mac_addr)
> >     > +{
> >     > +     unsigned int i;
> >     > +     unsigned long long mac = 0;
> >
> >     Would you prefer to use a fixed length deceleration, uint64_t?
> >
> >     > +     struct rte_eth_dev_data *data = dev->data;
> >     > +     struct pmd_internals *internals = (struct pmd_internals *)
> >     > +             data->dev_private;
> >     > +
> >     > +     if (!is_valid_assigned_ether_addr(mac_addr))
> >     > +             return -EINVAL;
> >     > +
> >     > +     for (i = 0; i < 6; i++) {
> >
> >     Can you please use "ETHER_ADDR_LEN" instead of 6?
> >
> >     <...>
> >
> >     > +     for (i = 0; i < nb_rx; i++) {
> >     > +             if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> >     > +                     stats->q_ipackets[i] = rx_queue[i].rx_pkts;
> >     > +                     stats->q_ibytes[i] = rx_queue[i].rx_bytes;
> >     > +             }
> >     > +             rx_total += stats->q_ipackets[i];
> >     > +             rx_total_bytes += stats->q_ibytes[i];
> >
> >     Why these are not protected with "RTE_ETHDEV_QUEUE_STAT_CNTRS" check,
> >     if "i >= RTE_ETHDEV_QUEUE_STAT_CNTRS" you shouldn't access to
> 'stats->q_.*[i]'
> >
>
>

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v5] net/nfb: new netcope driver
  2019-04-02 16:05           ` Rastislav Černay
@ 2019-04-02 16:05             ` Rastislav Černay
  0 siblings, 0 replies; 50+ messages in thread
From: Rastislav Černay @ 2019-04-02 16:05 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev

> I have a problem here, this requires 'netcope-common-6.4.0-1.x86_64.rpm'
rpm to
> be installed [1], meanwhile szedata requires
> 'netcope-common-light-3.0.5-1.x86_64.rpm' to be installed, and these two
> packages conflicts with eachother.
>
> What is the way of having an environment that dependencies of two netcope
HW can
> be provided at same time? This is really time consuming each time update
system
> for it.
>
> <...>
> Sadly, szedata2 and nfb dirvers can not coexist in same enviroment. There
is no
> way to provide dependecies at same time.

>Isn't this also problem for you too? What is your solution when testing
both?

For us this is not a problem. The nfb driver is direct incompatible
continuation of
szedata2 driver. They are both working on same HW and thus it does not make
sense to have both on same system. So our solution is not to test them both
at
same time.






*Rastislav Černay I Software DeveloperNetcope Technologies, a.s.T: +420 530
510 680 <+420%20530%20510%20680>A: Sochorova 3232/34, Brno, 616 00, Czech
Republic
<https://maps.google.com/?q=Sochorova+3232/34,+Brno,+616+00,%C2%A0Czech+Republic&entry=gmail&source=g>W:
www.netcope.com
<https://www.netcope.com/>  <https://www.netcope.com/>*



On Mon, Apr 1, 2019 at 4:22 PM Ferruh Yigit <ferruh.yigit@intel.com> wrote:

> On 4/1/2019 3:55 PM, Rastislav Černay wrote:
> > Hi Ferruh,
> >
> > I fixed most of issues you wrote, but before I send v6, I would like to
> make
> > sure everything is in order, mainly the experimental issue.
> >
> > I have a problem here, this requires 'netcope-common-6.4.0-1.x86_64.rpm'
> rpm to
> > be installed [1], meanwhile szedata requires
> > 'netcope-common-light-3.0.5-1.x86_64.rpm' to be installed, and these two
> > packages conflicts with eachother.
> >
> > What is the way of having an environment that dependencies of two
> netcope HW can
> > be provided at same time? This is really time consuming each time update
> system
> > for it.
> >
> > <...>
> > Sadly, szedata2 and nfb dirvers can not coexist in same enviroment.
> There is no
> > way to provide dependecies at same time.
>
> Isn't this also problem for you too? What is your solution when testing
> both?
>
> >
> > Is rpm only option, how people using Ubuntu for example will use your
> devices?
> > <...>
> > For now, yes, only option is rpm and support for Ubuntu will be added
> later.
>
> Is this limitation in driver document? If not can you please update it.
>
> >
> >
> > Why allow_experimental only in meson, but not Makefile?
> > <...>
> > It is in Makefile too.
> > CFLAGS += -DALLOW_EXPERIMENTAL_API
> >
> > Can you please add list of experimental APIs called just below this as
> comment?
> > <...>
> > No experimental API is called in driver.
>
> OK, so please clean the meson file.
>
> >
> > btw, why do you prefer to have driver as experimental?
> > What does it mean it being experimental from your point of view exactly?
> > <...>
> > I do not prefer to have driver experimental, only reason it is there is
> > this mail:
> >
> > Luca Boccassi bluca@debian.org <mailto:bluca@debian.org>
> > Tue, Mar 5, 11:41 PM
> > to me, dev
> > <...>
> >> diff --git a/drivers/net/nfb/rte_nfb_pmd_version.map
> >> b/drivers/net/nfb/rte_nfb_pmd_version.map
> >> new file mode 100644
> >> index 0000000..97fd251
> >> --- /dev/null
> >> +++ b/drivers/net/nfb/rte_nfb_pmd_version.map
> >> @@ -0,0 +1,4 @@
> >> +DPDK_19.02 {
> >> +
> >> +        local: *;
> >> +};
> >
> > These are all new symbols so they should be marked as experimental,
> > please see doc/guides/contributing/versioning.rst
> >
> > So after reading doc/guides/contributing/versioning.rst I thought that
> > all new drivers should be experimental as they are new before they
> stabilize,
> > and during this time changes can be done to public functions without
> much hassle.
> > Should I keep driver experimental?
>
> No please don't keep it experimental. Luca is right new symbols should be
> marked
> as experimental, here news symbols are APIs and this PMD doesn't have any,
> all
> it has is 'local' symbols.
> cc'ed Luca if I am missing anything.
>
> And if this is the only reason you documented the PMD as experimental, you
> can
> clean MAINTAINERS file, release notes etc...
>
> >
> > *
> >
> > *Rastislav Černay I /Software Developer/*
> > Netcope Technologies, a.s.
> >
> > *T:* +420 530 510 680 <tel:+420%20530%20510%20680>
> > *A:* Sochorova 3232/34, Brno, 616 00, Czech Republic
> > <
> https://maps.google.com/?q=Sochorova+3232/34,+Brno,+616+00,%C2%A0Czech+Republic&entry=gmail&source=g
> >
> > *W: www.netcope.com <https://www.netcope.com/>
> >
> >  <https://www.netcope.com/>*
> >
> > *
> > **
> >
> >
> >
> > On Thu, Mar 28, 2019 at 5:01 PM Ferruh Yigit <ferruh.yigit@intel.com
> > <mailto:ferruh.yigit@intel.com>> wrote:
> >
> >     On 3/22/2019 12:12 PM, Rastislav Cernay wrote:
> >     > From: Rastislav Cernay <cernay@netcope.com <mailto:
> cernay@netcope.com>>
> >     >
> >     > Added new net driver for Netcope nfb cards
> >     >
> >     > Signed-off-by: Rastislav Cernay <cernay@netcope.com
> >     <mailto:cernay@netcope.com>>
> >     > ---
> >     > v2: remove unnecessary cast
> >     >     remove unnecessary zeroing
> >     >     move declaration to not mix with code
> >     >     restore skeleton example
> >     > v3: add release notes
> >     >     add doc to doc index
> >     >     add architecture limits to doc
> >     >     edit features list
> >     >     add .map file
> >     >     change link to dependecies to official vendor site
> >     >     move declarations out of code
> >     >     remove false comments (rte_errno is set)
> >     >     comments to c89 style
> >     >     remove log from main rx loop
> >     >     remove redundant code
> >     > v4: API is experimental
> >     >     fixed meson build dependency
> >     >     random initial MAC
> >     >     stats->q_errors is for intput err only
> >     >     move more declarations to a beginning
> >     >     fixed err log in TX
> >     >     use of pkg-config
> >     > v5: fixed pkg-config for new version of netcope-common
> >     >  MAINTAINERS                             |   7 +
> >     >  config/common_base                      |   4 +
> >     >  devtools/test-build.sh                  |   1 +
> >     >  doc/guides/nics/features/nfb.ini        |  18 +
> >     >  doc/guides/nics/index.rst               |   1 +
> >     >  doc/guides/nics/nfb.rst                 | 143 +++++++
> >     >  doc/guides/rel_notes/release_19_02.rst  |   5 +
> >
> >     Can you update the 19.05 release notes please?
> >
> >     >  drivers/net/Makefile                    |   1 +
> >     >  drivers/net/meson.build                 |   1 +
> >     >  drivers/net/nfb/Makefile                |  44 +++
> >     >  drivers/net/nfb/meson.build             |  15 +
> >     >  drivers/net/nfb/nfb.h                   |  50 +++
> >     >  drivers/net/nfb/nfb_ethdev.c            | 647
> >     ++++++++++++++++++++++++++++++++
> >     >  drivers/net/nfb/nfb_rx.c                | 127 +++++++
> >     >  drivers/net/nfb/nfb_rx.h                | 231 ++++++++++++
> >     >  drivers/net/nfb/nfb_rxmode.c            | 100 +++++
> >     >  drivers/net/nfb/nfb_rxmode.h            |  96 +++++
> >     >  drivers/net/nfb/nfb_stats.c             |  77 ++++
> >     >  drivers/net/nfb/nfb_stats.h             |  56 +++
> >     >  drivers/net/nfb/nfb_tx.c                | 113 ++++++
> >     >  drivers/net/nfb/nfb_tx.h                | 222 +++++++++++
> >     >  drivers/net/nfb/rte_nfb_pmd_version.map |   4 +
> >
> >     The filename should be "rte_pmd_nfb_version.map" as stated in
> Makefile.
> >     This brings the question, did you ever build dpdk as shared library
> or with
> >     meson build system with this PMD enabled :)
> >     Because it fails because of this wrong naming..
> >
> >
> >     Even after renaming the .map file, meson build fails, I haven't dig
> the problem,
> >     can you please check it?
> >
> >     <...>
> >
> >     > @@ -360,6 +360,10 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
> >     >  # Compile software PMD backed by SZEDATA2 device
> >     >  #
> >     >  CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
> >     > +#
> >     > +# Compile software PMD backed by NFB device
> >     > +#
> >     > +CONFIG_RTE_LIBRTE_PMD_NFB=n
> >
> >     Can you please rename the config option to
> "CONFIG_RTE_LIBRTE_NFB_PMD"?
> >     I guess unintentionally, there is an convension,
> >     Physical PMDs have the config name: CONFIG_RTE_LIBRTE_.*_PMD
> >     Virtual PMDs have the config name:  CONFIG_RTE_LIBRTE_PMD_.*=y
> >     I perfer same syntax for all, but it is what it is now, and I
> believe it doesn't
> >     worth the hassle of changing them.
> >
> >     I think only 'SZEDATA2' breaks current login, and I guess you copied
> from it,
> >     but let's start NFB according convention: CONFIG_RTE_LIBRTE_NFB_PMD
> >
> >
> >     Also please leave a blank line between previous config block.
> >
> >     <...>
> >
> >     > +Prerequisites
> >     > +-------------
> >     > +
> >     > +This PMD requires kernel modules which are responsible for
> initialization and
> >     > +allocation of resources needed for nfb layer function.
> >     > +Communication between PMD and kernel modules is mediated by
> libnfb library.
> >     > +These kernel modules and library are not part of DPDK and must be
> installed
> >     > +separately:
> >     > +
> >     > +*  **libnfb library**
> >     > +
> >     > +   The library provides API for initialization of nfb transfers,
> >     receiving and
> >     > +   transmitting data segments.
> >     > +
> >     > +*  **Kernel modules**
> >     > +
> >     > +   * nfb
> >     > +
> >     > +   Kernel modules manage initialization of hardware, allocation
> and
> >     > +   sharing of resources for user space applications.
> >     > +
> >     > +Dependencies can be found here:
> >     > +`Netcope common
> >     <
> https://www.netcope.com/en/company/community-support/dpdk-libsze2#NFB>`_.
> >
> >     I have a problem here, this requires
> 'netcope-common-6.4.0-1.x86_64.rpm' rpm to
> >     be installed [1], meanwhile szedata requires
> >     'netcope-common-light-3.0.5-1.x86_64.rpm' to be installed, and these
> two
> >     packages conflicts with eachother.
> >
> >     What is the way of having an environment that dependencies of two
> netcope HW can
> >     be provided at same time? This is really time consuming each time
> update system
> >     for it.
> >
> >     [1]
> >     Is rpm only option, how people using Ubuntu for example will use
> your devices?
> >
> >     > +
> >     > +Versions of the packages
> >     > +~~~~~~~~~~~~~~~~~~~~~~~~
> >     > +
> >     > +The minimum version of the provided packages:
> >     > +
> >     > +* for DPDK from 19.02
> >
> >     Is it 19.05 now?
> >
> >     <...>
> >
> >     > +Example output:
> >     > +
> >     > +.. code-block:: console
> >     > +
> >     > +   [...]
> >     > +   EAL: PCI device 0000:06:00.0 on NUMA socket -1
> >     > +   EAL:   probe driver: 1b26:c1c1 net_nfb
> >     > +   PMD: Initializing NFB device (0000:06:00.0)
> >     > +   PMD: Available DMA queues RX: 8 TX: 8
> >     > +   PMD: NFB device (0000:06:00.0) successfully initialized
> >     > +   Interactive-mode selected
> >     > +   Auto-start selected
> >     > +   Configuring Port 0 (socket 0)
> >     > +   Port 0: 00:11:17:00:00:00
> >     > +   Checking link statuses...
> >     > +   Port 0 Link Up - speed 10000 Mbps - full-duplex
> >     > +   Done
> >     > +   Start automatic packet forwarding
> >     > +     io packet forwarding - CRC stripping disabled -
> packets/burst=32
> >     > +     nb forwarding cores=2 - nb forwarding ports=1
> >     > +     RX queues=2 - RX desc=128 - RX free threshold=0
> >     > +     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
> >     > +     TX queues=2 - TX desc=512 - TX free threshold=0
> >     > +     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
> >     > +     TX RS bit threshold=0 - TXQ flags=0x0
> >     > +   testpmd>
> >
> >     I think testpmd logging is not like this any more, can you please
> update the app
> >     log with latest code.
> >
> >     <...>
> >
> >     > @@ -0,0 +1,44 @@
> >     > +# SPDX-License-Identifier: BSD-3-Clause
> >     > +# Copyright(c) 2018 Cesnet
> >     > +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com
> >     <mailto:info@netcope.com>>
> >
> >     Should year be 2019, or 2018-2019?
> >
> >
> >     <...>
> >
> >     > @@ -0,0 +1,15 @@
> >     > +# SPDX-License-Identifier: BSD-3-Clause
> >     > +# Copyright(c) 2018 Cesnet
> >     > +# Copyright(c) 2018 Netcope Technologies, a.s. <info@netcope.com
> >     <mailto:info@netcope.com>>
> >     > +# All rights reserved.
> >     > +
> >     > +dep = cc.find_library('nfb', required: false)
> >     > +
> >     > +build = dep.found() and cc.has_header('nfb/nfb.h', dependencies:
> dep)
> >     > +
> >     > +allow_experimental_apis = true
> >
> >     Why allow_experimental only in meson, but not Makefile?
> >     Can you please add list of experimental APIs called just below this
> as comment?
> >
> >     <...>
> >
> >     > +/**
> >     > + * Default MAC addr
> >     > + */
> >     > +static struct ether_addr eth_addr = {
> >     > +     .addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
> >     > +};
> >
> >     it looks like this can be static const.
> >
> >     > +
> >     > +/**
> >     > + * @warning
> >     > + * @b EXPERIMENTAL: this API may change, or be removed, without
> prior notice
> >     > + *
> >
> >     Why these tags are added, to say PMD is experimental?
> >     These only makes sense for public APIs which PMD doesn't have at
> all, these are
> >     doxygen comments for API documentation. Please remove them.
> >
> >     Also I recognized '__rte_experimental' tags, again which are for
> internal
> >     checking and warning the applications if they are using experimental
> public API,
> >     it doesn't apply here. Please remove them.
> >     Last thing, the "EXPERIMENTAL" tag in .map file, that also doesn't
> apply here,
> >     please make it release version, 'DPDK_19.05"
> >
> >     I think your note about being experimental in MAINTAINERS file and
> the note in
> >     release notes is good,
> >     Can you please also update the driver documentation too, nfb.rst, to
> say driver
> >     is experimental? I think those notes are good enough overall.
> >
> >
> >     btw, why do you prefer to have driver as experimental?
> >     What does it mean it being experimental from your point of view
> exactly?
> >
> >
> >     <...>
> >
> >     > +static int __rte_experimental
> >     > +nfb_eth_mac_addr_set(struct rte_eth_dev *dev,
> >     > +     struct ether_addr *mac_addr)
> >     > +{
> >     > +     unsigned int i;
> >     > +     unsigned long long mac = 0;
> >
> >     Would you prefer to use a fixed length deceleration, uint64_t?
> >
> >     > +     struct rte_eth_dev_data *data = dev->data;
> >     > +     struct pmd_internals *internals = (struct pmd_internals *)
> >     > +             data->dev_private;
> >     > +
> >     > +     if (!is_valid_assigned_ether_addr(mac_addr))
> >     > +             return -EINVAL;
> >     > +
> >     > +     for (i = 0; i < 6; i++) {
> >
> >     Can you please use "ETHER_ADDR_LEN" instead of 6?
> >
> >     <...>
> >
> >     > +     for (i = 0; i < nb_rx; i++) {
> >     > +             if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
> >     > +                     stats->q_ipackets[i] = rx_queue[i].rx_pkts;
> >     > +                     stats->q_ibytes[i] = rx_queue[i].rx_bytes;
> >     > +             }
> >     > +             rx_total += stats->q_ipackets[i];
> >     > +             rx_total_bytes += stats->q_ibytes[i];
> >
> >     Why these are not protected with "RTE_ETHDEV_QUEUE_STAT_CNTRS" check,
> >     if "i >= RTE_ETHDEV_QUEUE_STAT_CNTRS" you shouldn't access to
> 'stats->q_.*[i]'
> >
>
>

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [dpdk-dev] [PATCH v6] net/nfb: new netcope driver
  2019-02-26 12:57 ` [dpdk-dev] [PATCH] net/nfb: new netcope driver Rastislav Cernay
                     ` (5 preceding siblings ...)
  2019-03-22 12:12   ` [dpdk-dev] [PATCH v5] " Rastislav Cernay
@ 2019-04-04  9:05   ` Rastislav Cernay
  2019-04-04  9:05     ` Rastislav Cernay
  2019-04-05  0:08     ` Ferruh Yigit
  2019-04-07 15:03   ` [dpdk-dev] [PATCH v7] " Rastislav Cernay
  2019-04-12 14:37   ` [dpdk-dev] [PATCH] net/nfb: remove redundant linking Rastislav Cernay
  8 siblings, 2 replies; 50+ messages in thread
From: Rastislav Cernay @ 2019-04-04  9:05 UTC (permalink / raw)
  To: dev; +Cc: Rastislav Cernay

From: Rastislav Cernay <cernay@netcope.com>

Added new net driver for Netcope nfb cards

Signed-off-by: Rastislav Cernay <cernay@netcope.com>
---
v2: remove unnecessary cast
    remove unnecessary zeroing
    move declaration to not mix with code
    restore skeleton example
v3: add release notes
    add doc to doc index
    add architecture limits to doc
    edit features list
    add .map file
    change link to dependecies to official vendor site
    move declarations out of code
    remove false comments (rte_errno is set)
    comments to c89 style
    remove log from main rx loop
    remove redundant code
v4: API is experimental
    fixed meson build dependency
    random initial MAC
    stats->q_errors is for intput err only
    move more declarations to a beginning
    fixed err log in TX
    use of pkg-config
v5: fixed pkg-config for new version of netcope-common
v6: driver is not experimental
    fix stats
    fix some code issues
    add release notes
    update code to 19.05
    fix copyright
    fix meson build
 MAINTAINERS                             |   7 +
 config/common_base                      |   5 +
 devtools/test-build.sh                  |   1 +
 doc/guides/nics/features/nfb.ini        |  18 +
 doc/guides/nics/index.rst               |   1 +
 doc/guides/nics/nfb.rst                 | 143 ++++++
 doc/guides/rel_notes/release_19_05.rst  |   5 +
 drivers/net/Makefile                    |   1 +
 drivers/net/meson.build                 |   1 +
 drivers/net/nfb/Makefile                |  43 ++
 drivers/net/nfb/meson.build             |  15 +
 drivers/net/nfb/nfb.h                   |  50 ++
 drivers/net/nfb/nfb_ethdev.c            | 596 ++++++++++++++++++++++++
 drivers/net/nfb/nfb_rx.c                | 127 +++++
 drivers/net/nfb/nfb_rx.h                | 213 +++++++++
 drivers/net/nfb/nfb_rxmode.c            | 100 ++++
 drivers/net/nfb/nfb_rxmode.h            |  78 ++++
 drivers/net/nfb/nfb_stats.c             |  77 +++
 drivers/net/nfb/nfb_stats.h             |  50 ++
 drivers/net/nfb/nfb_tx.c                | 113 +++++
 drivers/net/nfb/nfb_tx.h                | 204 ++++++++
 drivers/net/nfb/rte_pmd_nfb_version.map |   4 +
 mk/rte.app.mk                           |   2 +
 23 files changed, 1854 insertions(+)
 create mode 100644 doc/guides/nics/features/nfb.ini
 create mode 100644 doc/guides/nics/nfb.rst
 create mode 100644 drivers/net/nfb/Makefile
 create mode 100644 drivers/net/nfb/meson.build
 create mode 100644 drivers/net/nfb/nfb.h
 create mode 100644 drivers/net/nfb/nfb_ethdev.c
 create mode 100644 drivers/net/nfb/nfb_rx.c
 create mode 100644 drivers/net/nfb/nfb_rx.h
 create mode 100644 drivers/net/nfb/nfb_rxmode.c
 create mode 100644 drivers/net/nfb/nfb_rxmode.h
 create mode 100644 drivers/net/nfb/nfb_stats.c
 create mode 100644 drivers/net/nfb/nfb_stats.h
 create mode 100644 drivers/net/nfb/nfb_tx.c
 create mode 100644 drivers/net/nfb/nfb_tx.h
 create mode 100644 drivers/net/nfb/rte_pmd_nfb_version.map

diff --git a/MAINTAINERS b/MAINTAINERS
index e9ff2b4c2..304190591 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -662,6 +662,13 @@ F: drivers/net/szedata2/
 F: doc/guides/nics/szedata2.rst
 F: doc/guides/nics/features/szedata2.ini
 
+Netcope nfb
+M: Rastislav Cernay <cernay@netcope.com>
+M: Jan Remes <remes@netcope.com>
+F: drivers/net/nfb/
+F: doc/guides/nics/nfb.rst
+F: doc/guides/nics/features/nfb.ini
+
 Netronome nfp
 M: Alejandro Lucero <alejandro.lucero@netronome.com>
 F: drivers/net/nfp/
diff --git a/config/common_base b/config/common_base
index 6292bc4af..8208d5ddb 100644
--- a/config/common_base
+++ b/config/common_base
@@ -375,6 +375,11 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
 #
 CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
 
+#
+# Compile software PMD backed by NFB device
+#
+CONFIG_RTE_LIBRTE_NFB_PMD=n
+
 #
 # Compile burst-oriented Cavium Thunderx NICVF PMD driver
 #
diff --git a/devtools/test-build.sh b/devtools/test-build.sh
index 70e91da52..9b50bf73d 100755
--- a/devtools/test-build.sh
+++ b/devtools/test-build.sh
@@ -19,6 +19,7 @@ default_path=$PATH
 # - DPDK_DEP_SSL (y/[n])
 # - DPDK_DEP_IPSEC_MB (y/[n])
 # - DPDK_DEP_SZE (y/[n])
+# - DPDK_DEP_NFB (y/[n])
 # - DPDK_DEP_ZLIB (y/[n])
 # - DPDK_MAKE_JOBS (int)
 # - DPDK_NOTIFY (notify-send)
diff --git a/doc/guides/nics/features/nfb.ini b/doc/guides/nics/features/nfb.ini
new file mode 100644
index 000000000..e1c5266d5
--- /dev/null
+++ b/doc/guides/nics/features/nfb.ini
@@ -0,0 +1,18 @@
+;
+; Supported features of the 'nfb' network poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Speed capabilities   = P
+Link status          = Y
+Queue start/stop     = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Basic stats          = Y
+Extended stats       = Y
+Stats per queue      = Y
+Other kdrv           = Y
+x86-64               = Y
+Usage doc            = Y
+Scattered Tx         = Y
diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index 5c80e3baa..079972e90 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -39,6 +39,7 @@ Network Interface Controller Drivers
     mvneta
     mvpp2
     netvsc
+    nfb
     nfp
     octeontx
     qede
diff --git a/doc/guides/nics/nfb.rst b/doc/guides/nics/nfb.rst
new file mode 100644
index 000000000..155c18ccc
--- /dev/null
+++ b/doc/guides/nics/nfb.rst
@@ -0,0 +1,143 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright 2015 - 2016 CESNET
+
+NFB poll mode driver library
+=================================
+
+The NFB poll mode driver library implements support for the Netcope
+FPGA Boards (**NFB-***), FPGA-based programmable NICs.
+The NFB PMD uses interface provided by the libnfb library to communicate
+with the NFB cards over the nfb layer.
+
+More information about the
+`NFB cards <http://www.netcope.com/en/products/fpga-boards>`_
+and used technology
+(`Netcope Development Kit <http://www.netcope.com/en/products/fpga-development-kit>`_)
+can be found on the `Netcope Technologies website <http://www.netcope.com/>`_.
+
+.. note::
+
+   This driver has external dependencies.
+   Therefore it is disabled in default configuration files.
+   It can be enabled by setting ``CONFIG_RTE_LIBRTE_NFB_PMD=y``
+   and recompiling.
+
+.. note::
+
+   Currently the driver is supported only on x86_64 architectures.
+   Only x86_64 versions of the external libraries are provided.
+
+Prerequisites
+-------------
+
+This PMD requires kernel modules which are responsible for initialization and
+allocation of resources needed for nfb layer function.
+Communication between PMD and kernel modules is mediated by libnfb library.
+These kernel modules and library are not part of DPDK and must be installed
+separately:
+
+*  **libnfb library**
+
+   The library provides API for initialization of nfb transfers, receiving and
+   transmitting data segments.
+
+*  **Kernel modules**
+
+   * nfb
+
+   Kernel modules manage initialization of hardware, allocation and
+   sharing of resources for user space applications.
+
+Dependencies can be found here:
+`Netcope common <https://www.netcope.com/en/company/community-support/dpdk-libsze2#NFB>`_.
+
+Versions of the packages
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The minimum version of the provided packages:
+
+* for DPDK from 19.05
+
+Configuration
+-------------
+
+These configuration options can be modified before compilation in the
+``.config`` file:
+
+*  ``CONFIG_RTE_LIBRTE_NFB_PMD`` default value: **n**
+
+   Value **y** enables compilation of nfb PMD.
+
+Using the NFB PMD
+----------------------
+
+Kernel modules have to be loaded before running the DPDK application.
+
+NFB card architecture
+---------------------
+
+The NFB cards are multi-port multi-queue cards, where (generally) data from any
+Ethernet port may be sent to any queue.
+They are represented in DPDK as a single port.
+
+NFB-200G2QL card employs an addon cable which allows to connect it to two
+physical PCI-E slots at the same time (see the diagram below).
+This is done to allow 200 Gbps of traffic to be transferred through the PCI-E
+bus (note that a single PCI-E 3.0 x16 slot provides only 125 Gbps theoretical
+throughput).
+
+Although each slot may be connected to a different CPU and therefore to a different
+NUMA node, the card is represented as a single port in DPDK. To work with data
+from the individual queues on the right NUMA node, connection of NUMA nodes on
+first and last queue (each NUMA node has half of the queues) need to be checked.
+
+.. figure:: img/szedata2_nfb200g_architecture.svg
+    :align: center
+
+    NFB-200G2QL high-level diagram
+
+Limitations
+-----------
+
+Driver is usable only on Linux architecture, namely on CentOS.
+
+Since a card is always represented as a single port, but can be connected to two
+NUMA nodes, there is need for manual check where master/slave is connected.
+
+Example of usage
+----------------
+
+Read packets from 0. and 1. receive queue and write them to 0. and 1.
+transmit queue:
+
+.. code-block:: console
+
+   $RTE_TARGET/app/testpmd -l 0-3 -n 2 \
+   -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2 -i -a
+
+Example output:
+
+.. code-block:: console
+
+   [...]
+   EAL: PCI device 0000:06:00.0 on NUMA socket -1
+   EAL:   probe driver: 1b26:c1c1 net_nfb
+   PMD: Initializing NFB device (0000:06:00.0)
+   PMD: Available DMA queues RX: 8 TX: 8
+   PMD: NFB device (0000:06:00.0) successfully initialized
+   Interactive-mode selected
+   Auto-start selected
+   Configuring Port 0 (socket 0)
+   Port 0: 00:11:17:00:00:00
+   Checking link statuses...
+   Port 0 Link Up - speed 10000 Mbps - full-duplex
+   Done
+   Start automatic packet forwarding
+     io packet forwarding - CRC stripping disabled - packets/burst=32
+     nb forwarding cores=2 - nb forwarding ports=1
+     RX queues=2 - RX desc=128 - RX free threshold=0
+     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX queues=2 - TX desc=512 - TX free threshold=0
+     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX RS bit threshold=0 - TXQ flags=0x0
+   testpmd>
diff --git a/doc/guides/rel_notes/release_19_05.rst b/doc/guides/rel_notes/release_19_05.rst
index 86132821b..f7001a0d8 100644
--- a/doc/guides/rel_notes/release_19_05.rst
+++ b/doc/guides/rel_notes/release_19_05.rst
@@ -54,6 +54,11 @@ New Features
      Also, make sure to start the actual text at the margin.
      =========================================================
 
+* **Added a net PMD NFB.**
+
+  Added the new ``nfb`` net driver for Netcope NFB cards. See
+  the :doc:`../nics/nfb` NIC guide for more details on this new driver.
+
 * **Updated KNI module and PMD.**
 
   Updated the KNI kernel module to set the max_mtu according to the given
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 502869a87..5eb811bfd 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -38,6 +38,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5
 DIRS-$(CONFIG_RTE_LIBRTE_MVNETA_PMD) += mvneta
 DIRS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mvpp2
 DIRS-$(CONFIG_RTE_LIBRTE_NETVSC_PMD) += netvsc
+DIRS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb
 DIRS-$(CONFIG_RTE_LIBRTE_NFP_PMD) += nfp
 DIRS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += null
diff --git a/drivers/net/meson.build b/drivers/net/meson.build
index 3ecc78cee..3e259f47c 100644
--- a/drivers/net/meson.build
+++ b/drivers/net/meson.build
@@ -27,6 +27,7 @@ drivers = ['af_packet',
 	'mvneta',
 	'mvpp2',
 	'netvsc',
+	'nfb',
 	'nfp',
 	'null', 'octeontx', 'pcap', 'qede', 'ring',
 	'sfc',
diff --git a/drivers/net/nfb/Makefile b/drivers/net/nfb/Makefile
new file mode 100644
index 000000000..943eae33f
--- /dev/null
+++ b/drivers/net/nfb/Makefile
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2019 Cesnet
+# Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_nfb.a
+
+INCLUDES :=-I$(SRCDIR)
+
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --cflags netcope-common)
+LDLIBS += -lnfb
+LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
+LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
+LDLIBS += -lrte_bus_pci
+LDLIBS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --libs netcope-common)
+
+EXPORT_MAP := rte_nfb_pmd_version.map
+
+LIBABIVER := 1
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_rx.c
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_tx.c
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_stats.c
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_rxmode.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/nfb/meson.build b/drivers/net/nfb/meson.build
new file mode 100644
index 000000000..457955d72
--- /dev/null
+++ b/drivers/net/nfb/meson.build
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2019 Cesnet
+# Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+dep = cc.find_library('nfb', required: false)
+
+build = dep.found() and cc.has_header('nfb/nfb.h', dependencies: dep)
+
+nc = dependency('netcope-common', required: false)
+
+ext_deps += dep
+ext_deps += nc
+
+sources = files('nfb_rx.c', 'nfb_tx.c', 'nfb_stats.c', 'nfb_ethdev.c', 'nfb_rxmode.c')
diff --git a/drivers/net/nfb/nfb.h b/drivers/net/nfb/nfb.h
new file mode 100644
index 000000000..fe9fb96da
--- /dev/null
+++ b/drivers/net/nfb/nfb.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_H_
+#define _NFB_H_
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+
+/* PCI Vendor ID */
+#define PCI_VENDOR_ID_NETCOPE 0x1b26
+
+/* PCI Device IDs */
+#define PCI_DEVICE_ID_NFB_40G2  0xcb80
+#define PCI_DEVICE_ID_NFB_100G2 0xc2c1
+#define PCI_DEVICE_ID_NFB_200G2QL 0xc250
+
+/* Max index of ndp rx/tx queues */
+#define RTE_ETH_NDP_MAX_RX_QUEUES 32
+#define RTE_ETH_NDP_MAX_TX_QUEUES 32
+
+/* Max index of rx/tx dmas */
+#define RTE_MAX_NC_RXMAC 256
+#define RTE_MAX_NC_TXMAC 256
+
+#define RTE_NFB_DRIVER_NAME net_nfb
+
+struct pmd_internals {
+	uint16_t         max_rxmac;
+	uint16_t         max_txmac;
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC];
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC];
+
+	char             nfb_dev[PATH_MAX];
+	struct nfb_device *nfb;
+	/* Place to remember if filter was promiscuous or filtering by table,
+	 * when disabling allmulticast
+	 */
+	enum nc_rxmac_mac_filter rx_filter_original;
+};
+
+#endif /* _NFB_H_ */
diff --git a/drivers/net/nfb/nfb_ethdev.c b/drivers/net/nfb/nfb_ethdev.c
new file mode 100644
index 000000000..630170b55
--- /dev/null
+++ b/drivers/net/nfb/nfb_ethdev.c
@@ -0,0 +1,596 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_kvargs.h>
+#include <rte_dev.h>
+#include <rte_common.h>
+
+#include "nfb_stats.h"
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+/**
+ * Default MAC addr
+ */
+static const struct ether_addr eth_addr = {
+	.addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
+};
+
+/**
+ * Open all RX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] rxmac
+ *   Pointer to output array of nc_rxmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of rxmac
+ */
+static void
+nfb_nc_rxmac_init(struct nfb_device *nfb,
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t *max_rxmac)
+{
+	*max_rxmac = 0;
+	while ((rxmac[*max_rxmac] = nc_rxmac_open_index(nfb, *max_rxmac)))
+		++(*max_rxmac);
+}
+
+/**
+ * Open all TX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] txmac
+ *   Pointer to output array of nc_txmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of txmac
+ */
+static void
+nfb_nc_txmac_init(struct nfb_device *nfb,
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t *max_txmac)
+{
+	*max_txmac = 0;
+	while ((txmac[*max_txmac] = nc_txmac_open_index(nfb, *max_txmac)))
+		++(*max_txmac);
+}
+
+/**
+ * Close all RX DMA queues
+ *
+ * @param rxmac
+ *   Pointer to array of nc_rxmac
+ * @param max_rxmac
+ *   Maximum index of rxmac
+ */
+static void
+nfb_nc_rxmac_deinit(struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t max_rxmac)
+{
+	for (; max_rxmac > 0; --max_rxmac) {
+		nc_rxmac_close(rxmac[max_rxmac]);
+		rxmac[max_rxmac] = NULL;
+	}
+}
+
+/**
+ * Close all TX DMA queues
+ *
+ * @param txmac
+ *   Pointer to array of nc_txmac
+ * @param max_txmac
+ *   Maximum index of txmac
+ */
+static void
+nfb_nc_txmac_deinit(struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t max_txmac)
+{
+	for (; max_txmac > 0; --max_txmac) {
+		nc_txmac_close(txmac[max_txmac]);
+		txmac[max_txmac] = NULL;
+	}
+}
+
+/**
+ * DPDK callback to start the device.
+ *
+ * Start device by starting all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_start(struct rte_eth_dev *dev)
+{
+	int ret;
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_rx; i++) {
+		ret = nfb_eth_rx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_rx;
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		ret = nfb_eth_tx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_tx;
+	}
+
+	return 0;
+
+err_tx:
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+err_rx:
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+	return ret;
+}
+
+/**
+ * DPDK callback to stop the device.
+ *
+ * Stop device by stopping all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+nfb_eth_dev_stop(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+}
+
+/**
+ * DPDK callback for Ethernet device configuration.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+/**
+ * DPDK callback to get information about the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] info
+ *   Info structure output buffer.
+ */
+static void
+nfb_eth_dev_info(struct rte_eth_dev *dev,
+	struct rte_eth_dev_info *dev_info)
+{
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = dev->data->nb_rx_queues;
+	dev_info->max_tx_queues = dev->data->nb_tx_queues;
+	dev_info->speed_capa = ETH_LINK_SPEED_100G;
+}
+
+/**
+ * DPDK callback to close the device.
+ *
+ * Destroy all queues and objects, free memory.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+nfb_eth_dev_close(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	nfb_eth_dev_stop(dev);
+
+	for (i = 0; i < nb_rx; i++) {
+		nfb_eth_rx_queue_release(dev->data->rx_queues[i]);
+		dev->data->rx_queues[i] = NULL;
+	}
+	dev->data->nb_rx_queues = 0;
+	for (i = 0; i < nb_tx; i++) {
+		nfb_eth_tx_queue_release(dev->data->tx_queues[i]);
+		dev->data->tx_queues[i] = NULL;
+	}
+	dev->data->nb_tx_queues = 0;
+}
+
+/**
+ * DPDK callback to retrieve physical link information.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] link
+ *   Storage for current link status.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_link_update(struct rte_eth_dev *dev,
+	int wait_to_complete __rte_unused)
+{
+	uint16_t i;
+	struct nc_rxmac_status status;
+	struct rte_eth_link link;
+	memset(&link, 0, sizeof(link));
+
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	status.speed = MAC_SPEED_UNKNOWN;
+
+	link.link_speed = ETH_SPEED_NUM_NONE;
+	link.link_status = ETH_LINK_DOWN;
+	link.link_duplex = ETH_LINK_FULL_DUPLEX;
+	link.link_autoneg = ETH_LINK_SPEED_FIXED;
+
+	if (internals->rxmac[0] != NULL) {
+		nc_rxmac_read_status(internals->rxmac[0], &status);
+
+		switch (status.speed) {
+		case MAC_SPEED_10G:
+			link.link_speed = ETH_SPEED_NUM_10G;
+			break;
+		case MAC_SPEED_40G:
+			link.link_speed = ETH_SPEED_NUM_40G;
+			break;
+		case MAC_SPEED_100G:
+			link.link_speed = ETH_SPEED_NUM_100G;
+			break;
+		default:
+			link.link_speed = ETH_SPEED_NUM_NONE;
+			break;
+		}
+	}
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_read_status(internals->rxmac[i], &status);
+
+		if (status.enabled && status.link_up) {
+			link.link_status = ETH_LINK_UP;
+			break;
+		}
+	}
+
+	rte_eth_linkstatus_set(dev, &link);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to bring the link UP.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_set_link_up(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_enable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_enable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to bring the link DOWN.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_set_link_down(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_disable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_disable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to set primary MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_mac_addr_set(struct rte_eth_dev *dev,
+	struct ether_addr *mac_addr)
+{
+	unsigned int i;
+	uint64_t mac = 0;
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+
+	if (!is_valid_assigned_ether_addr(mac_addr))
+		return -EINVAL;
+
+	for (i = 0; i < ETHER_ADDR_LEN; i++) {
+		mac <<= 8;
+		mac |= mac_addr->addr_bytes[i] & 0xFF;
+	}
+
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_set_mac(internals->rxmac[i], 0, mac, 1);
+
+	ether_addr_copy(mac_addr, data->mac_addrs);
+	return 0;
+}
+
+static const struct eth_dev_ops ops = {
+	.dev_start = nfb_eth_dev_start,
+	.dev_stop = nfb_eth_dev_stop,
+	.dev_set_link_up = nfb_eth_dev_set_link_up,
+	.dev_set_link_down = nfb_eth_dev_set_link_down,
+	.dev_close = nfb_eth_dev_close,
+	.dev_configure = nfb_eth_dev_configure,
+	.dev_infos_get = nfb_eth_dev_info,
+	.promiscuous_enable = nfb_eth_promiscuous_enable,
+	.promiscuous_disable = nfb_eth_promiscuous_disable,
+	.allmulticast_enable = nfb_eth_allmulticast_enable,
+	.allmulticast_disable = nfb_eth_allmulticast_disable,
+	.rx_queue_start = nfb_eth_rx_queue_start,
+	.rx_queue_stop = nfb_eth_rx_queue_stop,
+	.tx_queue_start = nfb_eth_tx_queue_start,
+	.tx_queue_stop = nfb_eth_tx_queue_stop,
+	.rx_queue_setup = nfb_eth_rx_queue_setup,
+	.tx_queue_setup = nfb_eth_tx_queue_setup,
+	.rx_queue_release = nfb_eth_rx_queue_release,
+	.tx_queue_release = nfb_eth_tx_queue_release,
+	.link_update = nfb_eth_link_update,
+	.stats_get = nfb_eth_stats_get,
+	.stats_reset = nfb_eth_stats_reset,
+	.mac_addr_set = nfb_eth_mac_addr_set,
+};
+
+/**
+ * DPDK callback to initialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_init(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+	struct ether_addr eth_addr_init;
+
+	RTE_LOG(INFO, PMD, "Initializing NFB device (" PCI_PRI_FMT ")\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	snprintf(internals->nfb_dev, PATH_MAX,
+		"/dev/nfb/by-pci-slot/" PCI_PRI_FMT,
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	/*
+	 * Get number of available DMA RX and TX queues, which is maximum
+	 * number of queues that can be created and store it in private device
+	 * data structure.
+	 */
+	internals->nfb = nfb_open(internals->nfb_dev);
+	if (internals->nfb == NULL) {
+		RTE_LOG(ERR, PMD, "nfb_open(): failed to open %s",
+			internals->nfb_dev);
+		return -EINVAL;
+	}
+	data->nb_rx_queues = ndp_get_rx_queue_available_count(internals->nfb);
+	data->nb_tx_queues = ndp_get_tx_queue_available_count(internals->nfb);
+
+	RTE_LOG(INFO, PMD, "Available NDP queues RX: %u TX: %u\n",
+		data->nb_rx_queues, data->nb_tx_queues);
+
+	nfb_nc_rxmac_init(internals->nfb,
+		internals->rxmac,
+		&internals->max_rxmac);
+	nfb_nc_txmac_init(internals->nfb,
+		internals->txmac,
+		&internals->max_txmac);
+
+	/* Set rx, tx burst functions */
+	dev->rx_pkt_burst = nfb_eth_ndp_rx;
+	dev->tx_pkt_burst = nfb_eth_ndp_tx;
+
+	/* Set function callbacks for Ethernet API */
+	dev->dev_ops = &ops;
+
+	/* Get link state */
+	nfb_eth_link_update(dev, 0);
+
+	/* Allocate space for one mac address */
+	data->mac_addrs = rte_zmalloc(data->name, sizeof(struct ether_addr),
+		RTE_CACHE_LINE_SIZE);
+	if (data->mac_addrs == NULL) {
+		RTE_LOG(ERR, PMD, "Could not alloc space for MAC address!\n");
+		nfb_close(internals->nfb);
+		return -EINVAL;
+	}
+
+	eth_random_addr(eth_addr_init.addr_bytes);
+	eth_addr_init.addr_bytes[0] = eth_addr.addr_bytes[0];
+	eth_addr_init.addr_bytes[1] = eth_addr.addr_bytes[1];
+	eth_addr_init.addr_bytes[2] = eth_addr.addr_bytes[2];
+
+	nfb_eth_mac_addr_set(dev, &eth_addr_init);
+
+	data->promiscuous = nfb_eth_promiscuous_get(dev);
+	data->all_multicast = nfb_eth_allmulticast_get(dev);
+	internals->rx_filter_original = data->promiscuous;
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully initialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to uninitialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_uninit(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+
+	dev->data->mac_addrs = NULL;
+
+	nfb_nc_rxmac_deinit(internals->rxmac, internals->max_rxmac);
+	nfb_nc_txmac_deinit(internals->txmac, internals->max_txmac);
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully uninitialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+static const struct rte_pci_id nfb_pci_id_table[] = {
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_40G2) },
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_100G2) },
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_200G2QL) },
+	{ .vendor_id = 0, }
+};
+
+/**
+ * DPDK callback to register a PCI device.
+ *
+ * This function spawns Ethernet devices out of a given PCI device.
+ *
+ * @param[in] pci_drv
+ *   PCI driver structure (nfb_driver).
+ * @param[in] pci_dev
+ *   PCI device information.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+		struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_probe(pci_dev,
+		sizeof(struct pmd_internals), nfb_eth_dev_init);
+}
+
+/**
+ * DPDK callback to remove a PCI device.
+ *
+ * This function removes all Ethernet devices belong to a given PCI device.
+ *
+ * @param[in] pci_dev
+ *   Pointer to the PCI device.
+ *
+ * @return
+ *   0 on success, the function cannot fail.
+ */
+static int
+nfb_eth_pci_remove(struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_remove(pci_dev, nfb_eth_dev_uninit);
+}
+
+static struct rte_pci_driver nfb_eth_driver = {
+	.id_table = nfb_pci_id_table,
+	.probe = nfb_eth_pci_probe,
+	.remove = nfb_eth_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(RTE_NFB_DRIVER_NAME, nfb_eth_driver);
+RTE_PMD_REGISTER_PCI_TABLE(RTE_NFB_DRIVER_NAME, nfb_pci_id_table);
+RTE_PMD_REGISTER_KMOD_DEP(RTE_NFB_DRIVER_NAME, "* nfb");
diff --git a/drivers/net/nfb/nfb_rx.c b/drivers/net/nfb/nfb_rx.c
new file mode 100644
index 000000000..9147b00b0
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.c
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_rx.h"
+#include "nfb.h"
+
+int
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+	int ret;
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_start(rxq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+int
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+	int ret;
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_stop(rxq->queue);
+	if (ret != 0)
+		return -EINVAL;
+
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+		uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	struct ndp_rx_queue *rxq;
+	int ret;
+
+	rxq = rte_zmalloc_socket("ndp rx queue",
+			sizeof(struct ndp_rx_queue),
+			RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (rxq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for rx queue id "
+				"%" PRIu16 "!\n", rx_queue_id);
+		return -ENOMEM;
+	}
+
+	ret = nfb_eth_rx_queue_init(internals->nfb,
+		rx_queue_id,
+		dev->data->port_id,
+		mb_pool,
+		rxq);
+
+	if (ret == 0)
+		dev->data->rx_queues[rx_queue_id] = rxq;
+	else
+		rte_free(rxq);
+
+	return ret;
+}
+
+int
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+		uint16_t rx_queue_id,
+		uint16_t port_id,
+		struct rte_mempool *mb_pool,
+		struct ndp_rx_queue *rxq)
+{
+	const struct rte_pktmbuf_pool_private *mbp_priv =
+		rte_mempool_get_priv(mb_pool);
+
+	if (nfb == NULL)
+		return -EINVAL;
+
+	rxq->queue = ndp_open_rx_queue(nfb, rx_queue_id);
+	if (rxq->queue == NULL)
+		return -EINVAL;
+
+	rxq->nfb = nfb;
+	rxq->rx_queue_id = rx_queue_id;
+	rxq->in_port = port_id;
+	rxq->mb_pool = mb_pool;
+	rxq->buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size -
+		RTE_PKTMBUF_HEADROOM);
+
+	rxq->rx_pkts = 0;
+	rxq->rx_bytes = 0;
+	rxq->err_pkts = 0;
+
+	return 0;
+}
+
+void
+nfb_eth_rx_queue_release(void *q)
+{
+	struct ndp_rx_queue *rxq = (struct ndp_rx_queue *)q;
+	if (rxq->queue != NULL) {
+		ndp_close_rx_queue(rxq->queue);
+		rte_free(rxq);
+		rxq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_rx.h b/drivers/net/nfb/nfb_rx.h
new file mode 100644
index 000000000..a4da59526
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.h
@@ -0,0 +1,213 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_RX_H_
+#define _NFB_RX_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+struct ndp_rx_queue {
+	struct nfb_device *nfb;	     /* nfb dev structure */
+	struct ndp_queue *queue;     /* rx queue */
+	uint16_t rx_queue_id;	     /* index */
+	uint8_t in_port;	     /* port */
+
+	struct rte_mempool *mb_pool; /* memory pool to allocate packets */
+	uint16_t buf_size;           /* mbuf size */
+
+	volatile uint64_t rx_pkts;   /* packets read */
+	volatile uint64_t rx_bytes;  /* bytes read */
+	volatile uint64_t err_pkts;  /* erroneous packets */
+};
+
+/**
+ * Initialize ndp_rx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param rx_queue_id
+ *   RX queue index.
+ * @param port_id
+ *   Device [external] port identifier.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ * @param[out] rxq
+ *   Pointer to ndp_rx_queue output structure
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+	uint16_t rx_queue_id,
+	uint16_t port_id,
+	struct rte_mempool *mb_pool,
+	struct ndp_rx_queue *rxq);
+
+/**
+ * DPDK callback to setup a RX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t rx_queue_id,
+	uint16_t nb_rx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_rxconf *rx_conf __rte_unused,
+	struct rte_mempool *mb_pool);
+
+/**
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void
+nfb_eth_rx_queue_release(void *q);
+
+/**
+ * Start traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * Stop traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ */
+int
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * DPDK callback for RX.
+ *
+ * @param dpdk_rxq
+ *   Generic pointer to RX queue structure.
+ * @param[out] bufs
+ *   Array to store received packets.
+ * @param nb_pkts
+ *   Maximum number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully received (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t
+nfb_eth_ndp_rx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	struct ndp_rx_queue *ndp = queue;
+	uint16_t packet_size;
+	uint64_t num_bytes = 0;
+	uint16_t num_rx;
+	unsigned int i;
+
+	const uint16_t buf_size = ndp->buf_size;
+
+	struct rte_mbuf *mbuf;
+	struct ndp_packet packets[nb_pkts];
+
+	struct rte_mbuf *mbufs[nb_pkts];
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "RX invalid arguments!\n");
+		return 0;
+	}
+
+	/* returns either all or nothing */
+	i = rte_pktmbuf_alloc_bulk(ndp->mb_pool, mbufs, nb_pkts);
+	if (unlikely(i != 0))
+		return 0;
+
+	num_rx = ndp_rx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_rx != nb_pkts)) {
+		for (i = num_rx; i < nb_pkts; i++)
+			rte_pktmbuf_free(mbufs[i]);
+	}
+
+	nb_pkts = num_rx;
+
+	num_rx = 0;
+	/*
+	 * Reads the given number of packets from NDP queue given
+	 * by queue and copies the packet data into a newly allocated mbuf
+	 * to return.
+	 */
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = mbufs[i];
+
+		/* get the space available for data in the mbuf */
+		packet_size = packets[i].data_length;
+
+		if (likely(packet_size <= buf_size)) {
+			/* NDP packet will fit in one mbuf, go ahead and copy */
+			rte_memcpy(rte_pktmbuf_mtod(mbuf, void *),
+				packets[i].data, packet_size);
+
+			mbuf->data_len = (uint16_t)packet_size;
+
+			mbuf->pkt_len = packet_size;
+			mbuf->port = ndp->in_port;
+			bufs[num_rx++] = mbuf;
+			num_bytes += packet_size;
+		} else {
+			/*
+			 * NDP packet will not fit in one mbuf,
+			 * scattered mode is not enabled, drop packet
+			 */
+			rte_pktmbuf_free(mbuf);
+		}
+	}
+
+	ndp_rx_burst_put(ndp->queue);
+
+	ndp->rx_pkts += num_rx;
+	ndp->rx_bytes += num_bytes;
+	return num_rx;
+}
+
+#endif /* _NFB_RX_H_ */
diff --git a/drivers/net/nfb/nfb_rxmode.c b/drivers/net/nfb/nfb_rxmode.c
new file mode 100644
index 000000000..97bfcb238
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.c
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+void
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+	uint16_t i;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_PROMISCUOUS);
+	}
+}
+
+void
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+	uint16_t i;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_TABLE;
+
+	/* if promisc is not enabled, do nothing */
+	if (!nfb_eth_promiscuous_get(dev))
+		return;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE);
+	}
+}
+
+int
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_PROMISCUOUS);
+}
+
+void
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+	}
+}
+
+void
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+
+	/* if multicast is not enabled do nothing */
+	if (!nfb_eth_allmulticast_get(dev))
+		return;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			internals->rx_filter_original);
+	}
+}
+
+int
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+}
diff --git a/drivers/net/nfb/nfb_rxmode.h b/drivers/net/nfb/nfb_rxmode.h
new file mode 100644
index 000000000..60d5eaeab
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_RXMODE_H_
+#define _NFB_RXMODE_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_ethdev.h>
+#include <rte_dev.h>
+
+/**
+ * Getter for promiscuous mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to enable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to disable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev);
+
+/**
+ * Getter for allmulticast mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to enable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to disable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev);
+
+#endif /* _NFB_RXMODE_H_ */
diff --git a/drivers/net/nfb/nfb_stats.c b/drivers/net/nfb/nfb_stats.c
new file mode 100644
index 000000000..5aa4d0089
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.c
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_stats.h"
+#include "nfb.h"
+
+int
+nfb_eth_stats_get(struct rte_eth_dev *dev,
+	struct rte_eth_stats *stats)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+	uint64_t rx_total = 0;
+	uint64_t tx_total = 0;
+	uint64_t tx_err_total = 0;
+	uint64_t rx_total_bytes = 0;
+	uint64_t tx_total_bytes = 0;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_ipackets[i] = rx_queue[i].rx_pkts;
+			stats->q_ibytes[i] = rx_queue[i].rx_bytes;
+		}
+		rx_total += rx_queue[i].rx_pkts;
+		rx_total_bytes += rx_queue[i].rx_bytes;
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_opackets[i] = tx_queue[i].tx_pkts;
+			stats->q_obytes[i] = tx_queue[i].tx_bytes;
+		}
+		tx_total += tx_queue[i].tx_pkts;
+		tx_total_bytes += tx_queue[i].tx_bytes;
+		tx_err_total += tx_queue[i].err_pkts;
+	}
+
+	stats->ipackets = rx_total;
+	stats->opackets = tx_total;
+	stats->ibytes = rx_total_bytes;
+	stats->obytes = tx_total_bytes;
+	stats->oerrors = tx_err_total;
+	return 0;
+}
+
+void
+nfb_eth_stats_reset(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		rx_queue[i].rx_pkts = 0;
+		rx_queue[i].rx_bytes = 0;
+		rx_queue[i].err_pkts = 0;
+	}
+	for (i = 0; i < nb_tx; i++) {
+		tx_queue[i].tx_pkts = 0;
+		tx_queue[i].tx_bytes = 0;
+		tx_queue[i].err_pkts = 0;
+	}
+}
diff --git a/drivers/net/nfb/nfb_stats.h b/drivers/net/nfb/nfb_stats.h
new file mode 100644
index 000000000..c54dfd4c6
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_STATS_H_
+#define _NFB_STATS_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+/**
+ * DPDK callback to get device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] stats
+ *   Stats structure output buffer.
+ *
+ * @return
+ *   0 on success and stats is filled, negative errno value otherwise.
+ */
+int
+nfb_eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats);
+
+/**
+ * DPDK callback to clear device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_stats_reset(struct rte_eth_dev *dev);
+
+#endif /* _NFB_STATS_H_ */
diff --git a/drivers/net/nfb/nfb_tx.c b/drivers/net/nfb/nfb_tx.c
new file mode 100644
index 000000000..9b912feb1
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.c
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_tx.h"
+#include "nfb.h"
+
+int
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+	int ret;
+
+	if (txq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_start(txq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+int
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+	int ret;
+
+	if (txq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "TX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_stop(txq->queue);
+	if (ret != 0)
+		return -EINVAL;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	int ret;
+	struct ndp_tx_queue *txq;
+
+	txq = rte_zmalloc_socket("ndp tx queue",
+		sizeof(struct ndp_tx_queue),
+		RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (txq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for tx queue id "
+			"%" PRIu16 "!\n", tx_queue_id);
+		return -ENOMEM;
+	}
+
+	ret = nfb_eth_tx_queue_init(internals->nfb,
+		tx_queue_id,
+		txq);
+
+	if (ret == 0)
+		dev->data->tx_queues[tx_queue_id] = txq;
+	else
+		rte_free(txq);
+
+	return ret;
+}
+
+int
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq)
+{
+	if (nfb == NULL)
+		return -EINVAL;
+
+	txq->queue = ndp_open_tx_queue(nfb, tx_queue_id);
+	if (txq->queue == NULL)
+		return -EINVAL;
+
+	txq->nfb = nfb;
+	txq->tx_queue_id = tx_queue_id;
+
+	txq->tx_pkts = 0;
+	txq->tx_bytes = 0;
+	txq->err_pkts = 0;
+
+	return 0;
+}
+
+void
+nfb_eth_tx_queue_release(void *q)
+{
+	struct ndp_tx_queue *txq = (struct ndp_tx_queue *)q;
+	if (txq->queue != NULL) {
+		ndp_close_tx_queue(txq->queue);
+		rte_free(txq);
+		txq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_tx.h b/drivers/net/nfb/nfb_tx.h
new file mode 100644
index 000000000..59f27d03e
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.h
@@ -0,0 +1,204 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_TX_H_
+#define _NFB_TX_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+struct ndp_tx_queue {
+	struct nfb_device *nfb;     /* nfb dev structure */
+	struct ndp_queue *queue;    /* tx queue */
+	uint16_t          tx_queue_id;       /* index */
+	volatile uint64_t tx_pkts;  /* packets transmitted */
+	volatile uint64_t tx_bytes; /* bytes transmitted */
+	volatile uint64_t err_pkts; /* erroneous packets */
+};
+
+/**
+ * DPDK callback to setup a TX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mp
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused);
+
+/**
+ * Initialize ndp_tx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param tx_queue_id
+ *   TX queue index.
+ * @param[out] txq
+ *   Pointer to ndp_tx_queue output structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq);
+
+/**
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void
+nfb_eth_tx_queue_release(void *q);
+
+/**
+ * Start traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * Stop traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * DPDK callback for TX.
+ *
+ * @param dpdk_txq
+ *   Generic pointer to TX queue structure.
+ * @param bufs
+ *   Packets to transmit.
+ * @param nb_pkts
+ *   Number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully transmitted (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t
+nfb_eth_ndp_tx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	int i;
+	struct rte_mbuf *mbuf;
+	struct ndp_tx_queue *ndp = queue;
+	uint16_t num_tx = 0;
+	uint64_t num_bytes = 0;
+
+	void *dst;
+	uint32_t pkt_len;
+	uint8_t mbuf_segs;
+
+	struct ndp_packet packets[nb_pkts];
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "TX invalid arguments!\n");
+		return 0;
+	}
+
+	for (i = 0; i < nb_pkts; i++) {
+		packets[i].data_length = bufs[i]->pkt_len;
+		packets[i].header_length = 0;
+	}
+
+	num_tx = ndp_tx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_tx != nb_pkts))
+		return 0;
+
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = bufs[i];
+
+		pkt_len = mbuf->pkt_len;
+		mbuf_segs = mbuf->nb_segs;
+
+		num_bytes += pkt_len;
+		if (mbuf_segs == 1) {
+			/*
+			 * non-scattered packet,
+			 * transmit from one mbuf
+			 */
+			rte_memcpy(packets[i].data,
+				rte_pktmbuf_mtod(mbuf, const void *),
+				pkt_len);
+		} else {
+			/* scattered packet, transmit from more mbufs */
+			struct rte_mbuf *m = mbuf;
+			while (m) {
+				dst = packets[i].data;
+
+				rte_memcpy(dst,
+					rte_pktmbuf_mtod(m,
+					const void *),
+					m->data_len);
+				dst = ((uint8_t *)(dst)) +
+					m->data_len;
+				m = m->next;
+			}
+		}
+
+		rte_pktmbuf_free(mbuf);
+	}
+
+	ndp_tx_burst_flush(ndp->queue);
+
+	ndp->tx_pkts += num_tx;
+	ndp->err_pkts += nb_pkts - num_tx;
+	ndp->tx_bytes += num_bytes;
+	return num_tx;
+}
+
+#endif /* _NFB_TX_H_ */
diff --git a/drivers/net/nfb/rte_pmd_nfb_version.map b/drivers/net/nfb/rte_pmd_nfb_version.map
new file mode 100644
index 000000000..fc8c95e91
--- /dev/null
+++ b/drivers/net/nfb/rte_pmd_nfb_version.map
@@ -0,0 +1,4 @@
+DPDK_19.05 {
+
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 262132fc6..381dc7fca 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -196,6 +196,8 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC)      += -lrte_pmd_softnic
 endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD)    += -lrte_pmd_sfc_efx
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2 -lsze2
+_LDLIBS-$(CONFIG_RTE_LIBRTE_NFB_PMD)        += -lrte_pmd_nfb
+_LDLIBS-$(CONFIG_RTE_LIBRTE_NFB_PMD)        +=  $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --libs netcope-common)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_TAP)        += -lrte_pmd_tap
 _LDLIBS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += -lrte_pmd_thunderx_nicvf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD) += -lrte_pmd_vdev_netvsc
-- 
2.17.1

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [dpdk-dev] [PATCH v6] net/nfb: new netcope driver
  2019-04-04  9:05   ` [dpdk-dev] [PATCH v6] " Rastislav Cernay
@ 2019-04-04  9:05     ` Rastislav Cernay
  2019-04-05  0:08     ` Ferruh Yigit
  1 sibling, 0 replies; 50+ messages in thread
From: Rastislav Cernay @ 2019-04-04  9:05 UTC (permalink / raw)
  To: dev; +Cc: Rastislav Cernay

From: Rastislav Cernay <cernay@netcope.com>

Added new net driver for Netcope nfb cards

Signed-off-by: Rastislav Cernay <cernay@netcope.com>
---
v2: remove unnecessary cast
    remove unnecessary zeroing
    move declaration to not mix with code
    restore skeleton example
v3: add release notes
    add doc to doc index
    add architecture limits to doc
    edit features list
    add .map file
    change link to dependecies to official vendor site
    move declarations out of code
    remove false comments (rte_errno is set)
    comments to c89 style
    remove log from main rx loop
    remove redundant code
v4: API is experimental
    fixed meson build dependency
    random initial MAC
    stats->q_errors is for intput err only
    move more declarations to a beginning
    fixed err log in TX
    use of pkg-config
v5: fixed pkg-config for new version of netcope-common
v6: driver is not experimental
    fix stats
    fix some code issues
    add release notes
    update code to 19.05
    fix copyright
    fix meson build
 MAINTAINERS                             |   7 +
 config/common_base                      |   5 +
 devtools/test-build.sh                  |   1 +
 doc/guides/nics/features/nfb.ini        |  18 +
 doc/guides/nics/index.rst               |   1 +
 doc/guides/nics/nfb.rst                 | 143 ++++++
 doc/guides/rel_notes/release_19_05.rst  |   5 +
 drivers/net/Makefile                    |   1 +
 drivers/net/meson.build                 |   1 +
 drivers/net/nfb/Makefile                |  43 ++
 drivers/net/nfb/meson.build             |  15 +
 drivers/net/nfb/nfb.h                   |  50 ++
 drivers/net/nfb/nfb_ethdev.c            | 596 ++++++++++++++++++++++++
 drivers/net/nfb/nfb_rx.c                | 127 +++++
 drivers/net/nfb/nfb_rx.h                | 213 +++++++++
 drivers/net/nfb/nfb_rxmode.c            | 100 ++++
 drivers/net/nfb/nfb_rxmode.h            |  78 ++++
 drivers/net/nfb/nfb_stats.c             |  77 +++
 drivers/net/nfb/nfb_stats.h             |  50 ++
 drivers/net/nfb/nfb_tx.c                | 113 +++++
 drivers/net/nfb/nfb_tx.h                | 204 ++++++++
 drivers/net/nfb/rte_pmd_nfb_version.map |   4 +
 mk/rte.app.mk                           |   2 +
 23 files changed, 1854 insertions(+)
 create mode 100644 doc/guides/nics/features/nfb.ini
 create mode 100644 doc/guides/nics/nfb.rst
 create mode 100644 drivers/net/nfb/Makefile
 create mode 100644 drivers/net/nfb/meson.build
 create mode 100644 drivers/net/nfb/nfb.h
 create mode 100644 drivers/net/nfb/nfb_ethdev.c
 create mode 100644 drivers/net/nfb/nfb_rx.c
 create mode 100644 drivers/net/nfb/nfb_rx.h
 create mode 100644 drivers/net/nfb/nfb_rxmode.c
 create mode 100644 drivers/net/nfb/nfb_rxmode.h
 create mode 100644 drivers/net/nfb/nfb_stats.c
 create mode 100644 drivers/net/nfb/nfb_stats.h
 create mode 100644 drivers/net/nfb/nfb_tx.c
 create mode 100644 drivers/net/nfb/nfb_tx.h
 create mode 100644 drivers/net/nfb/rte_pmd_nfb_version.map

diff --git a/MAINTAINERS b/MAINTAINERS
index e9ff2b4c2..304190591 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -662,6 +662,13 @@ F: drivers/net/szedata2/
 F: doc/guides/nics/szedata2.rst
 F: doc/guides/nics/features/szedata2.ini
 
+Netcope nfb
+M: Rastislav Cernay <cernay@netcope.com>
+M: Jan Remes <remes@netcope.com>
+F: drivers/net/nfb/
+F: doc/guides/nics/nfb.rst
+F: doc/guides/nics/features/nfb.ini
+
 Netronome nfp
 M: Alejandro Lucero <alejandro.lucero@netronome.com>
 F: drivers/net/nfp/
diff --git a/config/common_base b/config/common_base
index 6292bc4af..8208d5ddb 100644
--- a/config/common_base
+++ b/config/common_base
@@ -375,6 +375,11 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
 #
 CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
 
+#
+# Compile software PMD backed by NFB device
+#
+CONFIG_RTE_LIBRTE_NFB_PMD=n
+
 #
 # Compile burst-oriented Cavium Thunderx NICVF PMD driver
 #
diff --git a/devtools/test-build.sh b/devtools/test-build.sh
index 70e91da52..9b50bf73d 100755
--- a/devtools/test-build.sh
+++ b/devtools/test-build.sh
@@ -19,6 +19,7 @@ default_path=$PATH
 # - DPDK_DEP_SSL (y/[n])
 # - DPDK_DEP_IPSEC_MB (y/[n])
 # - DPDK_DEP_SZE (y/[n])
+# - DPDK_DEP_NFB (y/[n])
 # - DPDK_DEP_ZLIB (y/[n])
 # - DPDK_MAKE_JOBS (int)
 # - DPDK_NOTIFY (notify-send)
diff --git a/doc/guides/nics/features/nfb.ini b/doc/guides/nics/features/nfb.ini
new file mode 100644
index 000000000..e1c5266d5
--- /dev/null
+++ b/doc/guides/nics/features/nfb.ini
@@ -0,0 +1,18 @@
+;
+; Supported features of the 'nfb' network poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Speed capabilities   = P
+Link status          = Y
+Queue start/stop     = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Basic stats          = Y
+Extended stats       = Y
+Stats per queue      = Y
+Other kdrv           = Y
+x86-64               = Y
+Usage doc            = Y
+Scattered Tx         = Y
diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index 5c80e3baa..079972e90 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -39,6 +39,7 @@ Network Interface Controller Drivers
     mvneta
     mvpp2
     netvsc
+    nfb
     nfp
     octeontx
     qede
diff --git a/doc/guides/nics/nfb.rst b/doc/guides/nics/nfb.rst
new file mode 100644
index 000000000..155c18ccc
--- /dev/null
+++ b/doc/guides/nics/nfb.rst
@@ -0,0 +1,143 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright 2015 - 2016 CESNET
+
+NFB poll mode driver library
+=================================
+
+The NFB poll mode driver library implements support for the Netcope
+FPGA Boards (**NFB-***), FPGA-based programmable NICs.
+The NFB PMD uses interface provided by the libnfb library to communicate
+with the NFB cards over the nfb layer.
+
+More information about the
+`NFB cards <http://www.netcope.com/en/products/fpga-boards>`_
+and used technology
+(`Netcope Development Kit <http://www.netcope.com/en/products/fpga-development-kit>`_)
+can be found on the `Netcope Technologies website <http://www.netcope.com/>`_.
+
+.. note::
+
+   This driver has external dependencies.
+   Therefore it is disabled in default configuration files.
+   It can be enabled by setting ``CONFIG_RTE_LIBRTE_NFB_PMD=y``
+   and recompiling.
+
+.. note::
+
+   Currently the driver is supported only on x86_64 architectures.
+   Only x86_64 versions of the external libraries are provided.
+
+Prerequisites
+-------------
+
+This PMD requires kernel modules which are responsible for initialization and
+allocation of resources needed for nfb layer function.
+Communication between PMD and kernel modules is mediated by libnfb library.
+These kernel modules and library are not part of DPDK and must be installed
+separately:
+
+*  **libnfb library**
+
+   The library provides API for initialization of nfb transfers, receiving and
+   transmitting data segments.
+
+*  **Kernel modules**
+
+   * nfb
+
+   Kernel modules manage initialization of hardware, allocation and
+   sharing of resources for user space applications.
+
+Dependencies can be found here:
+`Netcope common <https://www.netcope.com/en/company/community-support/dpdk-libsze2#NFB>`_.
+
+Versions of the packages
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The minimum version of the provided packages:
+
+* for DPDK from 19.05
+
+Configuration
+-------------
+
+These configuration options can be modified before compilation in the
+``.config`` file:
+
+*  ``CONFIG_RTE_LIBRTE_NFB_PMD`` default value: **n**
+
+   Value **y** enables compilation of nfb PMD.
+
+Using the NFB PMD
+----------------------
+
+Kernel modules have to be loaded before running the DPDK application.
+
+NFB card architecture
+---------------------
+
+The NFB cards are multi-port multi-queue cards, where (generally) data from any
+Ethernet port may be sent to any queue.
+They are represented in DPDK as a single port.
+
+NFB-200G2QL card employs an addon cable which allows to connect it to two
+physical PCI-E slots at the same time (see the diagram below).
+This is done to allow 200 Gbps of traffic to be transferred through the PCI-E
+bus (note that a single PCI-E 3.0 x16 slot provides only 125 Gbps theoretical
+throughput).
+
+Although each slot may be connected to a different CPU and therefore to a different
+NUMA node, the card is represented as a single port in DPDK. To work with data
+from the individual queues on the right NUMA node, connection of NUMA nodes on
+first and last queue (each NUMA node has half of the queues) need to be checked.
+
+.. figure:: img/szedata2_nfb200g_architecture.svg
+    :align: center
+
+    NFB-200G2QL high-level diagram
+
+Limitations
+-----------
+
+Driver is usable only on Linux architecture, namely on CentOS.
+
+Since a card is always represented as a single port, but can be connected to two
+NUMA nodes, there is need for manual check where master/slave is connected.
+
+Example of usage
+----------------
+
+Read packets from 0. and 1. receive queue and write them to 0. and 1.
+transmit queue:
+
+.. code-block:: console
+
+   $RTE_TARGET/app/testpmd -l 0-3 -n 2 \
+   -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2 -i -a
+
+Example output:
+
+.. code-block:: console
+
+   [...]
+   EAL: PCI device 0000:06:00.0 on NUMA socket -1
+   EAL:   probe driver: 1b26:c1c1 net_nfb
+   PMD: Initializing NFB device (0000:06:00.0)
+   PMD: Available DMA queues RX: 8 TX: 8
+   PMD: NFB device (0000:06:00.0) successfully initialized
+   Interactive-mode selected
+   Auto-start selected
+   Configuring Port 0 (socket 0)
+   Port 0: 00:11:17:00:00:00
+   Checking link statuses...
+   Port 0 Link Up - speed 10000 Mbps - full-duplex
+   Done
+   Start automatic packet forwarding
+     io packet forwarding - CRC stripping disabled - packets/burst=32
+     nb forwarding cores=2 - nb forwarding ports=1
+     RX queues=2 - RX desc=128 - RX free threshold=0
+     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX queues=2 - TX desc=512 - TX free threshold=0
+     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX RS bit threshold=0 - TXQ flags=0x0
+   testpmd>
diff --git a/doc/guides/rel_notes/release_19_05.rst b/doc/guides/rel_notes/release_19_05.rst
index 86132821b..f7001a0d8 100644
--- a/doc/guides/rel_notes/release_19_05.rst
+++ b/doc/guides/rel_notes/release_19_05.rst
@@ -54,6 +54,11 @@ New Features
      Also, make sure to start the actual text at the margin.
      =========================================================
 
+* **Added a net PMD NFB.**
+
+  Added the new ``nfb`` net driver for Netcope NFB cards. See
+  the :doc:`../nics/nfb` NIC guide for more details on this new driver.
+
 * **Updated KNI module and PMD.**
 
   Updated the KNI kernel module to set the max_mtu according to the given
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 502869a87..5eb811bfd 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -38,6 +38,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5
 DIRS-$(CONFIG_RTE_LIBRTE_MVNETA_PMD) += mvneta
 DIRS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mvpp2
 DIRS-$(CONFIG_RTE_LIBRTE_NETVSC_PMD) += netvsc
+DIRS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb
 DIRS-$(CONFIG_RTE_LIBRTE_NFP_PMD) += nfp
 DIRS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += null
diff --git a/drivers/net/meson.build b/drivers/net/meson.build
index 3ecc78cee..3e259f47c 100644
--- a/drivers/net/meson.build
+++ b/drivers/net/meson.build
@@ -27,6 +27,7 @@ drivers = ['af_packet',
 	'mvneta',
 	'mvpp2',
 	'netvsc',
+	'nfb',
 	'nfp',
 	'null', 'octeontx', 'pcap', 'qede', 'ring',
 	'sfc',
diff --git a/drivers/net/nfb/Makefile b/drivers/net/nfb/Makefile
new file mode 100644
index 000000000..943eae33f
--- /dev/null
+++ b/drivers/net/nfb/Makefile
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2019 Cesnet
+# Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_nfb.a
+
+INCLUDES :=-I$(SRCDIR)
+
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --cflags netcope-common)
+LDLIBS += -lnfb
+LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
+LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
+LDLIBS += -lrte_bus_pci
+LDLIBS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --libs netcope-common)
+
+EXPORT_MAP := rte_nfb_pmd_version.map
+
+LIBABIVER := 1
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_rx.c
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_tx.c
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_stats.c
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_rxmode.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/nfb/meson.build b/drivers/net/nfb/meson.build
new file mode 100644
index 000000000..457955d72
--- /dev/null
+++ b/drivers/net/nfb/meson.build
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2019 Cesnet
+# Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+dep = cc.find_library('nfb', required: false)
+
+build = dep.found() and cc.has_header('nfb/nfb.h', dependencies: dep)
+
+nc = dependency('netcope-common', required: false)
+
+ext_deps += dep
+ext_deps += nc
+
+sources = files('nfb_rx.c', 'nfb_tx.c', 'nfb_stats.c', 'nfb_ethdev.c', 'nfb_rxmode.c')
diff --git a/drivers/net/nfb/nfb.h b/drivers/net/nfb/nfb.h
new file mode 100644
index 000000000..fe9fb96da
--- /dev/null
+++ b/drivers/net/nfb/nfb.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_H_
+#define _NFB_H_
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+
+/* PCI Vendor ID */
+#define PCI_VENDOR_ID_NETCOPE 0x1b26
+
+/* PCI Device IDs */
+#define PCI_DEVICE_ID_NFB_40G2  0xcb80
+#define PCI_DEVICE_ID_NFB_100G2 0xc2c1
+#define PCI_DEVICE_ID_NFB_200G2QL 0xc250
+
+/* Max index of ndp rx/tx queues */
+#define RTE_ETH_NDP_MAX_RX_QUEUES 32
+#define RTE_ETH_NDP_MAX_TX_QUEUES 32
+
+/* Max index of rx/tx dmas */
+#define RTE_MAX_NC_RXMAC 256
+#define RTE_MAX_NC_TXMAC 256
+
+#define RTE_NFB_DRIVER_NAME net_nfb
+
+struct pmd_internals {
+	uint16_t         max_rxmac;
+	uint16_t         max_txmac;
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC];
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC];
+
+	char             nfb_dev[PATH_MAX];
+	struct nfb_device *nfb;
+	/* Place to remember if filter was promiscuous or filtering by table,
+	 * when disabling allmulticast
+	 */
+	enum nc_rxmac_mac_filter rx_filter_original;
+};
+
+#endif /* _NFB_H_ */
diff --git a/drivers/net/nfb/nfb_ethdev.c b/drivers/net/nfb/nfb_ethdev.c
new file mode 100644
index 000000000..630170b55
--- /dev/null
+++ b/drivers/net/nfb/nfb_ethdev.c
@@ -0,0 +1,596 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_kvargs.h>
+#include <rte_dev.h>
+#include <rte_common.h>
+
+#include "nfb_stats.h"
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+/**
+ * Default MAC addr
+ */
+static const struct ether_addr eth_addr = {
+	.addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
+};
+
+/**
+ * Open all RX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] rxmac
+ *   Pointer to output array of nc_rxmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of rxmac
+ */
+static void
+nfb_nc_rxmac_init(struct nfb_device *nfb,
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t *max_rxmac)
+{
+	*max_rxmac = 0;
+	while ((rxmac[*max_rxmac] = nc_rxmac_open_index(nfb, *max_rxmac)))
+		++(*max_rxmac);
+}
+
+/**
+ * Open all TX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] txmac
+ *   Pointer to output array of nc_txmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of txmac
+ */
+static void
+nfb_nc_txmac_init(struct nfb_device *nfb,
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t *max_txmac)
+{
+	*max_txmac = 0;
+	while ((txmac[*max_txmac] = nc_txmac_open_index(nfb, *max_txmac)))
+		++(*max_txmac);
+}
+
+/**
+ * Close all RX DMA queues
+ *
+ * @param rxmac
+ *   Pointer to array of nc_rxmac
+ * @param max_rxmac
+ *   Maximum index of rxmac
+ */
+static void
+nfb_nc_rxmac_deinit(struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t max_rxmac)
+{
+	for (; max_rxmac > 0; --max_rxmac) {
+		nc_rxmac_close(rxmac[max_rxmac]);
+		rxmac[max_rxmac] = NULL;
+	}
+}
+
+/**
+ * Close all TX DMA queues
+ *
+ * @param txmac
+ *   Pointer to array of nc_txmac
+ * @param max_txmac
+ *   Maximum index of txmac
+ */
+static void
+nfb_nc_txmac_deinit(struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t max_txmac)
+{
+	for (; max_txmac > 0; --max_txmac) {
+		nc_txmac_close(txmac[max_txmac]);
+		txmac[max_txmac] = NULL;
+	}
+}
+
+/**
+ * DPDK callback to start the device.
+ *
+ * Start device by starting all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_start(struct rte_eth_dev *dev)
+{
+	int ret;
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_rx; i++) {
+		ret = nfb_eth_rx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_rx;
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		ret = nfb_eth_tx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_tx;
+	}
+
+	return 0;
+
+err_tx:
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+err_rx:
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+	return ret;
+}
+
+/**
+ * DPDK callback to stop the device.
+ *
+ * Stop device by stopping all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+nfb_eth_dev_stop(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+}
+
+/**
+ * DPDK callback for Ethernet device configuration.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+/**
+ * DPDK callback to get information about the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] info
+ *   Info structure output buffer.
+ */
+static void
+nfb_eth_dev_info(struct rte_eth_dev *dev,
+	struct rte_eth_dev_info *dev_info)
+{
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = dev->data->nb_rx_queues;
+	dev_info->max_tx_queues = dev->data->nb_tx_queues;
+	dev_info->speed_capa = ETH_LINK_SPEED_100G;
+}
+
+/**
+ * DPDK callback to close the device.
+ *
+ * Destroy all queues and objects, free memory.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+nfb_eth_dev_close(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	nfb_eth_dev_stop(dev);
+
+	for (i = 0; i < nb_rx; i++) {
+		nfb_eth_rx_queue_release(dev->data->rx_queues[i]);
+		dev->data->rx_queues[i] = NULL;
+	}
+	dev->data->nb_rx_queues = 0;
+	for (i = 0; i < nb_tx; i++) {
+		nfb_eth_tx_queue_release(dev->data->tx_queues[i]);
+		dev->data->tx_queues[i] = NULL;
+	}
+	dev->data->nb_tx_queues = 0;
+}
+
+/**
+ * DPDK callback to retrieve physical link information.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] link
+ *   Storage for current link status.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_link_update(struct rte_eth_dev *dev,
+	int wait_to_complete __rte_unused)
+{
+	uint16_t i;
+	struct nc_rxmac_status status;
+	struct rte_eth_link link;
+	memset(&link, 0, sizeof(link));
+
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	status.speed = MAC_SPEED_UNKNOWN;
+
+	link.link_speed = ETH_SPEED_NUM_NONE;
+	link.link_status = ETH_LINK_DOWN;
+	link.link_duplex = ETH_LINK_FULL_DUPLEX;
+	link.link_autoneg = ETH_LINK_SPEED_FIXED;
+
+	if (internals->rxmac[0] != NULL) {
+		nc_rxmac_read_status(internals->rxmac[0], &status);
+
+		switch (status.speed) {
+		case MAC_SPEED_10G:
+			link.link_speed = ETH_SPEED_NUM_10G;
+			break;
+		case MAC_SPEED_40G:
+			link.link_speed = ETH_SPEED_NUM_40G;
+			break;
+		case MAC_SPEED_100G:
+			link.link_speed = ETH_SPEED_NUM_100G;
+			break;
+		default:
+			link.link_speed = ETH_SPEED_NUM_NONE;
+			break;
+		}
+	}
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_read_status(internals->rxmac[i], &status);
+
+		if (status.enabled && status.link_up) {
+			link.link_status = ETH_LINK_UP;
+			break;
+		}
+	}
+
+	rte_eth_linkstatus_set(dev, &link);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to bring the link UP.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_set_link_up(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_enable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_enable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to bring the link DOWN.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_set_link_down(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_disable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_disable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to set primary MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_mac_addr_set(struct rte_eth_dev *dev,
+	struct ether_addr *mac_addr)
+{
+	unsigned int i;
+	uint64_t mac = 0;
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+
+	if (!is_valid_assigned_ether_addr(mac_addr))
+		return -EINVAL;
+
+	for (i = 0; i < ETHER_ADDR_LEN; i++) {
+		mac <<= 8;
+		mac |= mac_addr->addr_bytes[i] & 0xFF;
+	}
+
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_set_mac(internals->rxmac[i], 0, mac, 1);
+
+	ether_addr_copy(mac_addr, data->mac_addrs);
+	return 0;
+}
+
+static const struct eth_dev_ops ops = {
+	.dev_start = nfb_eth_dev_start,
+	.dev_stop = nfb_eth_dev_stop,
+	.dev_set_link_up = nfb_eth_dev_set_link_up,
+	.dev_set_link_down = nfb_eth_dev_set_link_down,
+	.dev_close = nfb_eth_dev_close,
+	.dev_configure = nfb_eth_dev_configure,
+	.dev_infos_get = nfb_eth_dev_info,
+	.promiscuous_enable = nfb_eth_promiscuous_enable,
+	.promiscuous_disable = nfb_eth_promiscuous_disable,
+	.allmulticast_enable = nfb_eth_allmulticast_enable,
+	.allmulticast_disable = nfb_eth_allmulticast_disable,
+	.rx_queue_start = nfb_eth_rx_queue_start,
+	.rx_queue_stop = nfb_eth_rx_queue_stop,
+	.tx_queue_start = nfb_eth_tx_queue_start,
+	.tx_queue_stop = nfb_eth_tx_queue_stop,
+	.rx_queue_setup = nfb_eth_rx_queue_setup,
+	.tx_queue_setup = nfb_eth_tx_queue_setup,
+	.rx_queue_release = nfb_eth_rx_queue_release,
+	.tx_queue_release = nfb_eth_tx_queue_release,
+	.link_update = nfb_eth_link_update,
+	.stats_get = nfb_eth_stats_get,
+	.stats_reset = nfb_eth_stats_reset,
+	.mac_addr_set = nfb_eth_mac_addr_set,
+};
+
+/**
+ * DPDK callback to initialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_init(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+	struct ether_addr eth_addr_init;
+
+	RTE_LOG(INFO, PMD, "Initializing NFB device (" PCI_PRI_FMT ")\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	snprintf(internals->nfb_dev, PATH_MAX,
+		"/dev/nfb/by-pci-slot/" PCI_PRI_FMT,
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	/*
+	 * Get number of available DMA RX and TX queues, which is maximum
+	 * number of queues that can be created and store it in private device
+	 * data structure.
+	 */
+	internals->nfb = nfb_open(internals->nfb_dev);
+	if (internals->nfb == NULL) {
+		RTE_LOG(ERR, PMD, "nfb_open(): failed to open %s",
+			internals->nfb_dev);
+		return -EINVAL;
+	}
+	data->nb_rx_queues = ndp_get_rx_queue_available_count(internals->nfb);
+	data->nb_tx_queues = ndp_get_tx_queue_available_count(internals->nfb);
+
+	RTE_LOG(INFO, PMD, "Available NDP queues RX: %u TX: %u\n",
+		data->nb_rx_queues, data->nb_tx_queues);
+
+	nfb_nc_rxmac_init(internals->nfb,
+		internals->rxmac,
+		&internals->max_rxmac);
+	nfb_nc_txmac_init(internals->nfb,
+		internals->txmac,
+		&internals->max_txmac);
+
+	/* Set rx, tx burst functions */
+	dev->rx_pkt_burst = nfb_eth_ndp_rx;
+	dev->tx_pkt_burst = nfb_eth_ndp_tx;
+
+	/* Set function callbacks for Ethernet API */
+	dev->dev_ops = &ops;
+
+	/* Get link state */
+	nfb_eth_link_update(dev, 0);
+
+	/* Allocate space for one mac address */
+	data->mac_addrs = rte_zmalloc(data->name, sizeof(struct ether_addr),
+		RTE_CACHE_LINE_SIZE);
+	if (data->mac_addrs == NULL) {
+		RTE_LOG(ERR, PMD, "Could not alloc space for MAC address!\n");
+		nfb_close(internals->nfb);
+		return -EINVAL;
+	}
+
+	eth_random_addr(eth_addr_init.addr_bytes);
+	eth_addr_init.addr_bytes[0] = eth_addr.addr_bytes[0];
+	eth_addr_init.addr_bytes[1] = eth_addr.addr_bytes[1];
+	eth_addr_init.addr_bytes[2] = eth_addr.addr_bytes[2];
+
+	nfb_eth_mac_addr_set(dev, &eth_addr_init);
+
+	data->promiscuous = nfb_eth_promiscuous_get(dev);
+	data->all_multicast = nfb_eth_allmulticast_get(dev);
+	internals->rx_filter_original = data->promiscuous;
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully initialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to uninitialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_uninit(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+
+	dev->data->mac_addrs = NULL;
+
+	nfb_nc_rxmac_deinit(internals->rxmac, internals->max_rxmac);
+	nfb_nc_txmac_deinit(internals->txmac, internals->max_txmac);
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully uninitialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+static const struct rte_pci_id nfb_pci_id_table[] = {
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_40G2) },
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_100G2) },
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_200G2QL) },
+	{ .vendor_id = 0, }
+};
+
+/**
+ * DPDK callback to register a PCI device.
+ *
+ * This function spawns Ethernet devices out of a given PCI device.
+ *
+ * @param[in] pci_drv
+ *   PCI driver structure (nfb_driver).
+ * @param[in] pci_dev
+ *   PCI device information.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+		struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_probe(pci_dev,
+		sizeof(struct pmd_internals), nfb_eth_dev_init);
+}
+
+/**
+ * DPDK callback to remove a PCI device.
+ *
+ * This function removes all Ethernet devices belong to a given PCI device.
+ *
+ * @param[in] pci_dev
+ *   Pointer to the PCI device.
+ *
+ * @return
+ *   0 on success, the function cannot fail.
+ */
+static int
+nfb_eth_pci_remove(struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_remove(pci_dev, nfb_eth_dev_uninit);
+}
+
+static struct rte_pci_driver nfb_eth_driver = {
+	.id_table = nfb_pci_id_table,
+	.probe = nfb_eth_pci_probe,
+	.remove = nfb_eth_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(RTE_NFB_DRIVER_NAME, nfb_eth_driver);
+RTE_PMD_REGISTER_PCI_TABLE(RTE_NFB_DRIVER_NAME, nfb_pci_id_table);
+RTE_PMD_REGISTER_KMOD_DEP(RTE_NFB_DRIVER_NAME, "* nfb");
diff --git a/drivers/net/nfb/nfb_rx.c b/drivers/net/nfb/nfb_rx.c
new file mode 100644
index 000000000..9147b00b0
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.c
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_rx.h"
+#include "nfb.h"
+
+int
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+	int ret;
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_start(rxq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+int
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+	int ret;
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_stop(rxq->queue);
+	if (ret != 0)
+		return -EINVAL;
+
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+		uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	struct ndp_rx_queue *rxq;
+	int ret;
+
+	rxq = rte_zmalloc_socket("ndp rx queue",
+			sizeof(struct ndp_rx_queue),
+			RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (rxq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for rx queue id "
+				"%" PRIu16 "!\n", rx_queue_id);
+		return -ENOMEM;
+	}
+
+	ret = nfb_eth_rx_queue_init(internals->nfb,
+		rx_queue_id,
+		dev->data->port_id,
+		mb_pool,
+		rxq);
+
+	if (ret == 0)
+		dev->data->rx_queues[rx_queue_id] = rxq;
+	else
+		rte_free(rxq);
+
+	return ret;
+}
+
+int
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+		uint16_t rx_queue_id,
+		uint16_t port_id,
+		struct rte_mempool *mb_pool,
+		struct ndp_rx_queue *rxq)
+{
+	const struct rte_pktmbuf_pool_private *mbp_priv =
+		rte_mempool_get_priv(mb_pool);
+
+	if (nfb == NULL)
+		return -EINVAL;
+
+	rxq->queue = ndp_open_rx_queue(nfb, rx_queue_id);
+	if (rxq->queue == NULL)
+		return -EINVAL;
+
+	rxq->nfb = nfb;
+	rxq->rx_queue_id = rx_queue_id;
+	rxq->in_port = port_id;
+	rxq->mb_pool = mb_pool;
+	rxq->buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size -
+		RTE_PKTMBUF_HEADROOM);
+
+	rxq->rx_pkts = 0;
+	rxq->rx_bytes = 0;
+	rxq->err_pkts = 0;
+
+	return 0;
+}
+
+void
+nfb_eth_rx_queue_release(void *q)
+{
+	struct ndp_rx_queue *rxq = (struct ndp_rx_queue *)q;
+	if (rxq->queue != NULL) {
+		ndp_close_rx_queue(rxq->queue);
+		rte_free(rxq);
+		rxq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_rx.h b/drivers/net/nfb/nfb_rx.h
new file mode 100644
index 000000000..a4da59526
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.h
@@ -0,0 +1,213 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_RX_H_
+#define _NFB_RX_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+struct ndp_rx_queue {
+	struct nfb_device *nfb;	     /* nfb dev structure */
+	struct ndp_queue *queue;     /* rx queue */
+	uint16_t rx_queue_id;	     /* index */
+	uint8_t in_port;	     /* port */
+
+	struct rte_mempool *mb_pool; /* memory pool to allocate packets */
+	uint16_t buf_size;           /* mbuf size */
+
+	volatile uint64_t rx_pkts;   /* packets read */
+	volatile uint64_t rx_bytes;  /* bytes read */
+	volatile uint64_t err_pkts;  /* erroneous packets */
+};
+
+/**
+ * Initialize ndp_rx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param rx_queue_id
+ *   RX queue index.
+ * @param port_id
+ *   Device [external] port identifier.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ * @param[out] rxq
+ *   Pointer to ndp_rx_queue output structure
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+	uint16_t rx_queue_id,
+	uint16_t port_id,
+	struct rte_mempool *mb_pool,
+	struct ndp_rx_queue *rxq);
+
+/**
+ * DPDK callback to setup a RX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t rx_queue_id,
+	uint16_t nb_rx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_rxconf *rx_conf __rte_unused,
+	struct rte_mempool *mb_pool);
+
+/**
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void
+nfb_eth_rx_queue_release(void *q);
+
+/**
+ * Start traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * Stop traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ */
+int
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * DPDK callback for RX.
+ *
+ * @param dpdk_rxq
+ *   Generic pointer to RX queue structure.
+ * @param[out] bufs
+ *   Array to store received packets.
+ * @param nb_pkts
+ *   Maximum number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully received (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t
+nfb_eth_ndp_rx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	struct ndp_rx_queue *ndp = queue;
+	uint16_t packet_size;
+	uint64_t num_bytes = 0;
+	uint16_t num_rx;
+	unsigned int i;
+
+	const uint16_t buf_size = ndp->buf_size;
+
+	struct rte_mbuf *mbuf;
+	struct ndp_packet packets[nb_pkts];
+
+	struct rte_mbuf *mbufs[nb_pkts];
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "RX invalid arguments!\n");
+		return 0;
+	}
+
+	/* returns either all or nothing */
+	i = rte_pktmbuf_alloc_bulk(ndp->mb_pool, mbufs, nb_pkts);
+	if (unlikely(i != 0))
+		return 0;
+
+	num_rx = ndp_rx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_rx != nb_pkts)) {
+		for (i = num_rx; i < nb_pkts; i++)
+			rte_pktmbuf_free(mbufs[i]);
+	}
+
+	nb_pkts = num_rx;
+
+	num_rx = 0;
+	/*
+	 * Reads the given number of packets from NDP queue given
+	 * by queue and copies the packet data into a newly allocated mbuf
+	 * to return.
+	 */
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = mbufs[i];
+
+		/* get the space available for data in the mbuf */
+		packet_size = packets[i].data_length;
+
+		if (likely(packet_size <= buf_size)) {
+			/* NDP packet will fit in one mbuf, go ahead and copy */
+			rte_memcpy(rte_pktmbuf_mtod(mbuf, void *),
+				packets[i].data, packet_size);
+
+			mbuf->data_len = (uint16_t)packet_size;
+
+			mbuf->pkt_len = packet_size;
+			mbuf->port = ndp->in_port;
+			bufs[num_rx++] = mbuf;
+			num_bytes += packet_size;
+		} else {
+			/*
+			 * NDP packet will not fit in one mbuf,
+			 * scattered mode is not enabled, drop packet
+			 */
+			rte_pktmbuf_free(mbuf);
+		}
+	}
+
+	ndp_rx_burst_put(ndp->queue);
+
+	ndp->rx_pkts += num_rx;
+	ndp->rx_bytes += num_bytes;
+	return num_rx;
+}
+
+#endif /* _NFB_RX_H_ */
diff --git a/drivers/net/nfb/nfb_rxmode.c b/drivers/net/nfb/nfb_rxmode.c
new file mode 100644
index 000000000..97bfcb238
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.c
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+void
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+	uint16_t i;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_PROMISCUOUS);
+	}
+}
+
+void
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+	uint16_t i;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_TABLE;
+
+	/* if promisc is not enabled, do nothing */
+	if (!nfb_eth_promiscuous_get(dev))
+		return;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE);
+	}
+}
+
+int
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_PROMISCUOUS);
+}
+
+void
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+	}
+}
+
+void
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+
+	/* if multicast is not enabled do nothing */
+	if (!nfb_eth_allmulticast_get(dev))
+		return;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			internals->rx_filter_original);
+	}
+}
+
+int
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+}
diff --git a/drivers/net/nfb/nfb_rxmode.h b/drivers/net/nfb/nfb_rxmode.h
new file mode 100644
index 000000000..60d5eaeab
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_RXMODE_H_
+#define _NFB_RXMODE_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_ethdev.h>
+#include <rte_dev.h>
+
+/**
+ * Getter for promiscuous mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to enable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to disable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev);
+
+/**
+ * Getter for allmulticast mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to enable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to disable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev);
+
+#endif /* _NFB_RXMODE_H_ */
diff --git a/drivers/net/nfb/nfb_stats.c b/drivers/net/nfb/nfb_stats.c
new file mode 100644
index 000000000..5aa4d0089
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.c
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_stats.h"
+#include "nfb.h"
+
+int
+nfb_eth_stats_get(struct rte_eth_dev *dev,
+	struct rte_eth_stats *stats)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+	uint64_t rx_total = 0;
+	uint64_t tx_total = 0;
+	uint64_t tx_err_total = 0;
+	uint64_t rx_total_bytes = 0;
+	uint64_t tx_total_bytes = 0;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_ipackets[i] = rx_queue[i].rx_pkts;
+			stats->q_ibytes[i] = rx_queue[i].rx_bytes;
+		}
+		rx_total += rx_queue[i].rx_pkts;
+		rx_total_bytes += rx_queue[i].rx_bytes;
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_opackets[i] = tx_queue[i].tx_pkts;
+			stats->q_obytes[i] = tx_queue[i].tx_bytes;
+		}
+		tx_total += tx_queue[i].tx_pkts;
+		tx_total_bytes += tx_queue[i].tx_bytes;
+		tx_err_total += tx_queue[i].err_pkts;
+	}
+
+	stats->ipackets = rx_total;
+	stats->opackets = tx_total;
+	stats->ibytes = rx_total_bytes;
+	stats->obytes = tx_total_bytes;
+	stats->oerrors = tx_err_total;
+	return 0;
+}
+
+void
+nfb_eth_stats_reset(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		rx_queue[i].rx_pkts = 0;
+		rx_queue[i].rx_bytes = 0;
+		rx_queue[i].err_pkts = 0;
+	}
+	for (i = 0; i < nb_tx; i++) {
+		tx_queue[i].tx_pkts = 0;
+		tx_queue[i].tx_bytes = 0;
+		tx_queue[i].err_pkts = 0;
+	}
+}
diff --git a/drivers/net/nfb/nfb_stats.h b/drivers/net/nfb/nfb_stats.h
new file mode 100644
index 000000000..c54dfd4c6
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_STATS_H_
+#define _NFB_STATS_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+/**
+ * DPDK callback to get device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] stats
+ *   Stats structure output buffer.
+ *
+ * @return
+ *   0 on success and stats is filled, negative errno value otherwise.
+ */
+int
+nfb_eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats);
+
+/**
+ * DPDK callback to clear device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_stats_reset(struct rte_eth_dev *dev);
+
+#endif /* _NFB_STATS_H_ */
diff --git a/drivers/net/nfb/nfb_tx.c b/drivers/net/nfb/nfb_tx.c
new file mode 100644
index 000000000..9b912feb1
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.c
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_tx.h"
+#include "nfb.h"
+
+int
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+	int ret;
+
+	if (txq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_start(txq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+int
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+	int ret;
+
+	if (txq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "TX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_stop(txq->queue);
+	if (ret != 0)
+		return -EINVAL;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	int ret;
+	struct ndp_tx_queue *txq;
+
+	txq = rte_zmalloc_socket("ndp tx queue",
+		sizeof(struct ndp_tx_queue),
+		RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (txq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for tx queue id "
+			"%" PRIu16 "!\n", tx_queue_id);
+		return -ENOMEM;
+	}
+
+	ret = nfb_eth_tx_queue_init(internals->nfb,
+		tx_queue_id,
+		txq);
+
+	if (ret == 0)
+		dev->data->tx_queues[tx_queue_id] = txq;
+	else
+		rte_free(txq);
+
+	return ret;
+}
+
+int
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq)
+{
+	if (nfb == NULL)
+		return -EINVAL;
+
+	txq->queue = ndp_open_tx_queue(nfb, tx_queue_id);
+	if (txq->queue == NULL)
+		return -EINVAL;
+
+	txq->nfb = nfb;
+	txq->tx_queue_id = tx_queue_id;
+
+	txq->tx_pkts = 0;
+	txq->tx_bytes = 0;
+	txq->err_pkts = 0;
+
+	return 0;
+}
+
+void
+nfb_eth_tx_queue_release(void *q)
+{
+	struct ndp_tx_queue *txq = (struct ndp_tx_queue *)q;
+	if (txq->queue != NULL) {
+		ndp_close_tx_queue(txq->queue);
+		rte_free(txq);
+		txq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_tx.h b/drivers/net/nfb/nfb_tx.h
new file mode 100644
index 000000000..59f27d03e
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.h
@@ -0,0 +1,204 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_TX_H_
+#define _NFB_TX_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sys/types.h>
+
+#include <sys/mman.h>
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+struct ndp_tx_queue {
+	struct nfb_device *nfb;     /* nfb dev structure */
+	struct ndp_queue *queue;    /* tx queue */
+	uint16_t          tx_queue_id;       /* index */
+	volatile uint64_t tx_pkts;  /* packets transmitted */
+	volatile uint64_t tx_bytes; /* bytes transmitted */
+	volatile uint64_t err_pkts; /* erroneous packets */
+};
+
+/**
+ * DPDK callback to setup a TX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mp
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused);
+
+/**
+ * Initialize ndp_tx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param tx_queue_id
+ *   TX queue index.
+ * @param[out] txq
+ *   Pointer to ndp_tx_queue output structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq);
+
+/**
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void
+nfb_eth_tx_queue_release(void *q);
+
+/**
+ * Start traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * Stop traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * DPDK callback for TX.
+ *
+ * @param dpdk_txq
+ *   Generic pointer to TX queue structure.
+ * @param bufs
+ *   Packets to transmit.
+ * @param nb_pkts
+ *   Number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully transmitted (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t
+nfb_eth_ndp_tx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	int i;
+	struct rte_mbuf *mbuf;
+	struct ndp_tx_queue *ndp = queue;
+	uint16_t num_tx = 0;
+	uint64_t num_bytes = 0;
+
+	void *dst;
+	uint32_t pkt_len;
+	uint8_t mbuf_segs;
+
+	struct ndp_packet packets[nb_pkts];
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "TX invalid arguments!\n");
+		return 0;
+	}
+
+	for (i = 0; i < nb_pkts; i++) {
+		packets[i].data_length = bufs[i]->pkt_len;
+		packets[i].header_length = 0;
+	}
+
+	num_tx = ndp_tx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_tx != nb_pkts))
+		return 0;
+
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = bufs[i];
+
+		pkt_len = mbuf->pkt_len;
+		mbuf_segs = mbuf->nb_segs;
+
+		num_bytes += pkt_len;
+		if (mbuf_segs == 1) {
+			/*
+			 * non-scattered packet,
+			 * transmit from one mbuf
+			 */
+			rte_memcpy(packets[i].data,
+				rte_pktmbuf_mtod(mbuf, const void *),
+				pkt_len);
+		} else {
+			/* scattered packet, transmit from more mbufs */
+			struct rte_mbuf *m = mbuf;
+			while (m) {
+				dst = packets[i].data;
+
+				rte_memcpy(dst,
+					rte_pktmbuf_mtod(m,
+					const void *),
+					m->data_len);
+				dst = ((uint8_t *)(dst)) +
+					m->data_len;
+				m = m->next;
+			}
+		}
+
+		rte_pktmbuf_free(mbuf);
+	}
+
+	ndp_tx_burst_flush(ndp->queue);
+
+	ndp->tx_pkts += num_tx;
+	ndp->err_pkts += nb_pkts - num_tx;
+	ndp->tx_bytes += num_bytes;
+	return num_tx;
+}
+
+#endif /* _NFB_TX_H_ */
diff --git a/drivers/net/nfb/rte_pmd_nfb_version.map b/drivers/net/nfb/rte_pmd_nfb_version.map
new file mode 100644
index 000000000..fc8c95e91
--- /dev/null
+++ b/drivers/net/nfb/rte_pmd_nfb_version.map
@@ -0,0 +1,4 @@
+DPDK_19.05 {
+
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 262132fc6..381dc7fca 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -196,6 +196,8 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC)      += -lrte_pmd_softnic
 endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD)    += -lrte_pmd_sfc_efx
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2 -lsze2
+_LDLIBS-$(CONFIG_RTE_LIBRTE_NFB_PMD)        += -lrte_pmd_nfb
+_LDLIBS-$(CONFIG_RTE_LIBRTE_NFB_PMD)        +=  $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --libs netcope-common)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_TAP)        += -lrte_pmd_tap
 _LDLIBS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += -lrte_pmd_thunderx_nicvf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD) += -lrte_pmd_vdev_netvsc
-- 
2.17.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v6] net/nfb: new netcope driver
  2019-04-04  9:05   ` [dpdk-dev] [PATCH v6] " Rastislav Cernay
  2019-04-04  9:05     ` Rastislav Cernay
@ 2019-04-05  0:08     ` Ferruh Yigit
  2019-04-05  0:08       ` Ferruh Yigit
  1 sibling, 1 reply; 50+ messages in thread
From: Ferruh Yigit @ 2019-04-05  0:08 UTC (permalink / raw)
  To: Rastislav Cernay, dev

On 4/4/2019 10:05 AM, Rastislav Cernay wrote:
> From: Rastislav Cernay <cernay@netcope.com>
> 
> Added new net driver for Netcope nfb cards
> 
> Signed-off-by: Rastislav Cernay <cernay@netcope.com>

<...>

> @@ -0,0 +1,18 @@
> +;
> +; Supported features of the 'nfb' network poll mode driver.
> +;
> +; Refer to default.ini for the full list of available PMD features.
> +;
> +[Features]
> +Speed capabilities   = P
> +Link status          = Y
> +Queue start/stop     = Y
> +Promiscuous mode     = Y
> +Allmulticast mode    = Y
> +Basic stats          = Y
> +Extended stats       = Y
> +Stats per queue      = Y
> +Other kdrv           = Y
> +x86-64               = Y
> +Usage doc            = Y
> +Scattered Tx         = Y

We don't have 'Scattered Tx' feature defined, please remove.

<...>

> @@ -0,0 +1,143 @@
> +..  SPDX-License-Identifier: BSD-3-Clause
> +    Copyright 2015 - 2016 CESNET

You may want update the copyright year to 2019.

<...>

> +Although each slot may be connected to a different CPU and therefore to a different
> +NUMA node, the card is represented as a single port in DPDK. To work with data
> +from the individual queues on the right NUMA node, connection of NUMA nodes on
> +first and last queue (each NUMA node has half of the queues) need to be checked.
> +
> +.. figure:: img/szedata2_nfb200g_architecture.svg

Getting following warning from ./devtools/checkpatches.sh:
Warning in /doc/guides/nics/nfb.rst:
Using explicit .svg extension instead of .*

the comment on the script says:
        # svg figures must be included with wildcard extension
        # because of png conversion for pdf docs
so it seems this breaks the pdf creation.

updating as following should solve it:
.. figure:: img/szedata2_nfb200g_architecture.*

<...>

> +CFLAGS += -O3
> +CFLAGS += $(WERROR_FLAGS)
> +CFLAGS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --cflags netcope-common)
> +LDLIBS += -lnfb
> +LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
> +LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs

Are kvargs & ring libraries really needed? Can you please clean all unnecessary
libraries.

> +LDLIBS += -lrte_bus_pci
> +LDLIBS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --libs netcope-common)
> +
> +EXPORT_MAP := rte_nfb_pmd_version.map

The .map file name seems corrected, but this time EXPORT_MAP value is wrong J
It was correct and changed in this version and it is wrong now, shared library
build is still failing because of this.

<...>

> @@ -0,0 +1,596 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2019 Cesnet
> + * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
> + * All rights reserved.
> + */
> +
> +#include <stdint.h>
> +#include <unistd.h>
> +#include <stdbool.h>
> +#include <err.h>
> +#include <sys/types.h>
> +#include <dirent.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <sys/mman.h>
> +
> +#include <nfb/nfb.h>
> +#include <nfb/ndp.h>
> +#include <netcope/rxmac.h>
> +#include <netcope/txmac.h>
> +
> +#include <rte_mbuf.h>
> +#include <rte_ethdev.h>
> +#include <rte_ethdev_pci.h>
> +#include <rte_malloc.h>
> +#include <rte_memcpy.h>
> +#include <rte_kvargs.h>

Is kvargs header nedded, I don't see kvargs used.
Can you please clean all unnecessary headers, if you don't push initial version
clean, it is less likely they will be cleaned in the future.

This comment is valid for all .c files.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v6] net/nfb: new netcope driver
  2019-04-05  0:08     ` Ferruh Yigit
@ 2019-04-05  0:08       ` Ferruh Yigit
  0 siblings, 0 replies; 50+ messages in thread
From: Ferruh Yigit @ 2019-04-05  0:08 UTC (permalink / raw)
  To: Rastislav Cernay, dev

On 4/4/2019 10:05 AM, Rastislav Cernay wrote:
> From: Rastislav Cernay <cernay@netcope.com>
> 
> Added new net driver for Netcope nfb cards
> 
> Signed-off-by: Rastislav Cernay <cernay@netcope.com>

<...>

> @@ -0,0 +1,18 @@
> +;
> +; Supported features of the 'nfb' network poll mode driver.
> +;
> +; Refer to default.ini for the full list of available PMD features.
> +;
> +[Features]
> +Speed capabilities   = P
> +Link status          = Y
> +Queue start/stop     = Y
> +Promiscuous mode     = Y
> +Allmulticast mode    = Y
> +Basic stats          = Y
> +Extended stats       = Y
> +Stats per queue      = Y
> +Other kdrv           = Y
> +x86-64               = Y
> +Usage doc            = Y
> +Scattered Tx         = Y

We don't have 'Scattered Tx' feature defined, please remove.

<...>

> @@ -0,0 +1,143 @@
> +..  SPDX-License-Identifier: BSD-3-Clause
> +    Copyright 2015 - 2016 CESNET

You may want update the copyright year to 2019.

<...>

> +Although each slot may be connected to a different CPU and therefore to a different
> +NUMA node, the card is represented as a single port in DPDK. To work with data
> +from the individual queues on the right NUMA node, connection of NUMA nodes on
> +first and last queue (each NUMA node has half of the queues) need to be checked.
> +
> +.. figure:: img/szedata2_nfb200g_architecture.svg

Getting following warning from ./devtools/checkpatches.sh:
Warning in /doc/guides/nics/nfb.rst:
Using explicit .svg extension instead of .*

the comment on the script says:
        # svg figures must be included with wildcard extension
        # because of png conversion for pdf docs
so it seems this breaks the pdf creation.

updating as following should solve it:
.. figure:: img/szedata2_nfb200g_architecture.*

<...>

> +CFLAGS += -O3
> +CFLAGS += $(WERROR_FLAGS)
> +CFLAGS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --cflags netcope-common)
> +LDLIBS += -lnfb
> +LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
> +LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs

Are kvargs & ring libraries really needed? Can you please clean all unnecessary
libraries.

> +LDLIBS += -lrte_bus_pci
> +LDLIBS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --libs netcope-common)
> +
> +EXPORT_MAP := rte_nfb_pmd_version.map

The .map file name seems corrected, but this time EXPORT_MAP value is wrong J
It was correct and changed in this version and it is wrong now, shared library
build is still failing because of this.

<...>

> @@ -0,0 +1,596 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2019 Cesnet
> + * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
> + * All rights reserved.
> + */
> +
> +#include <stdint.h>
> +#include <unistd.h>
> +#include <stdbool.h>
> +#include <err.h>
> +#include <sys/types.h>
> +#include <dirent.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <sys/mman.h>
> +
> +#include <nfb/nfb.h>
> +#include <nfb/ndp.h>
> +#include <netcope/rxmac.h>
> +#include <netcope/txmac.h>
> +
> +#include <rte_mbuf.h>
> +#include <rte_ethdev.h>
> +#include <rte_ethdev_pci.h>
> +#include <rte_malloc.h>
> +#include <rte_memcpy.h>
> +#include <rte_kvargs.h>

Is kvargs header nedded, I don't see kvargs used.
Can you please clean all unnecessary headers, if you don't push initial version
clean, it is less likely they will be cleaned in the future.

This comment is valid for all .c files.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [dpdk-dev] [PATCH v7] net/nfb: new netcope driver
  2019-02-26 12:57 ` [dpdk-dev] [PATCH] net/nfb: new netcope driver Rastislav Cernay
                     ` (6 preceding siblings ...)
  2019-04-04  9:05   ` [dpdk-dev] [PATCH v6] " Rastislav Cernay
@ 2019-04-07 15:03   ` Rastislav Cernay
  2019-04-07 15:03     ` Rastislav Cernay
                       ` (2 more replies)
  2019-04-12 14:37   ` [dpdk-dev] [PATCH] net/nfb: remove redundant linking Rastislav Cernay
  8 siblings, 3 replies; 50+ messages in thread
From: Rastislav Cernay @ 2019-04-07 15:03 UTC (permalink / raw)
  To: dev; +Cc: ferruh.yigit, Rastislav Cernay

From: Rastislav Cernay <cernay@netcope.com>

Added new net driver for Netcope nfb cards

Signed-off-by: Rastislav Cernay <cernay@netcope.com>
---
v2: remove unnecessary cast
    remove unnecessary zeroing
    move declaration to not mix with code
    restore skeleton example
v3: add release notes
    add doc to doc index
    add architecture limits to doc
    edit features list
    add .map file
    change link to dependecies to official vendor site
    move declarations out of code
    remove false comments (rte_errno is set)
    comments to c89 style
    remove log from main rx loop
    remove redundant code
v4: API is experimental
    fixed meson build dependency
    random initial MAC
    stats->q_errors is for intput err only
    move more declarations to a beginning
    fixed err log in TX
    use of pkg-config
v5: fixed pkg-config for new version of netcope-common
v6: driver is not experimental
    fix stats
    fix some code issues
    add release notes
    update code to 19.05
    fix copyright
    fix meson build
v7: fix doc
    fix shared build
    remove unused includes and libs
 MAINTAINERS                             |   7 +
 config/common_base                      |   5 +
 devtools/test-build.sh                  |   1 +
 doc/guides/nics/features/nfb.ini        |  17 +
 doc/guides/nics/index.rst               |   1 +
 doc/guides/nics/nfb.rst                 | 144 ++++++++
 doc/guides/rel_notes/release_19_05.rst  |   5 +
 drivers/net/Makefile                    |   1 +
 drivers/net/meson.build                 |   1 +
 drivers/net/nfb/Makefile                |  43 +++
 drivers/net/nfb/meson.build             |  15 +
 drivers/net/nfb/nfb.h                   |  50 +++
 drivers/net/nfb/nfb_ethdev.c            | 579 ++++++++++++++++++++++++++++++++
 drivers/net/nfb/nfb_rx.c                | 127 +++++++
 drivers/net/nfb/nfb_rx.h                | 202 +++++++++++
 drivers/net/nfb/nfb_rxmode.c            | 100 ++++++
 drivers/net/nfb/nfb_rxmode.h            |  69 ++++
 drivers/net/nfb/nfb_stats.c             |  77 +++++
 drivers/net/nfb/nfb_stats.h             |  38 +++
 drivers/net/nfb/nfb_tx.c                | 113 +++++++
 drivers/net/nfb/nfb_tx.h                | 193 +++++++++++
 drivers/net/nfb/rte_pmd_nfb_version.map |   4 +
 mk/rte.app.mk                           |   2 +
 23 files changed, 1794 insertions(+)
 create mode 100644 doc/guides/nics/features/nfb.ini
 create mode 100644 doc/guides/nics/nfb.rst
 create mode 100644 drivers/net/nfb/Makefile
 create mode 100644 drivers/net/nfb/meson.build
 create mode 100644 drivers/net/nfb/nfb.h
 create mode 100644 drivers/net/nfb/nfb_ethdev.c
 create mode 100644 drivers/net/nfb/nfb_rx.c
 create mode 100644 drivers/net/nfb/nfb_rx.h
 create mode 100644 drivers/net/nfb/nfb_rxmode.c
 create mode 100644 drivers/net/nfb/nfb_rxmode.h
 create mode 100644 drivers/net/nfb/nfb_stats.c
 create mode 100644 drivers/net/nfb/nfb_stats.h
 create mode 100644 drivers/net/nfb/nfb_tx.c
 create mode 100644 drivers/net/nfb/nfb_tx.h
 create mode 100644 drivers/net/nfb/rte_pmd_nfb_version.map

diff --git a/MAINTAINERS b/MAINTAINERS
index e9ff2b4..3041905 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -662,6 +662,13 @@ F: drivers/net/szedata2/
 F: doc/guides/nics/szedata2.rst
 F: doc/guides/nics/features/szedata2.ini
 
+Netcope nfb
+M: Rastislav Cernay <cernay@netcope.com>
+M: Jan Remes <remes@netcope.com>
+F: drivers/net/nfb/
+F: doc/guides/nics/nfb.rst
+F: doc/guides/nics/features/nfb.ini
+
 Netronome nfp
 M: Alejandro Lucero <alejandro.lucero@netronome.com>
 F: drivers/net/nfp/
diff --git a/config/common_base b/config/common_base
index 6292bc4..8208d5d 100644
--- a/config/common_base
+++ b/config/common_base
@@ -376,6 +376,11 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
 CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
 
 #
+# Compile software PMD backed by NFB device
+#
+CONFIG_RTE_LIBRTE_NFB_PMD=n
+
+#
 # Compile burst-oriented Cavium Thunderx NICVF PMD driver
 #
 CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD=y
diff --git a/devtools/test-build.sh b/devtools/test-build.sh
index 70e91da..9b50bf7 100755
--- a/devtools/test-build.sh
+++ b/devtools/test-build.sh
@@ -19,6 +19,7 @@ default_path=$PATH
 # - DPDK_DEP_SSL (y/[n])
 # - DPDK_DEP_IPSEC_MB (y/[n])
 # - DPDK_DEP_SZE (y/[n])
+# - DPDK_DEP_NFB (y/[n])
 # - DPDK_DEP_ZLIB (y/[n])
 # - DPDK_MAKE_JOBS (int)
 # - DPDK_NOTIFY (notify-send)
diff --git a/doc/guides/nics/features/nfb.ini b/doc/guides/nics/features/nfb.ini
new file mode 100644
index 0000000..6174d65
--- /dev/null
+++ b/doc/guides/nics/features/nfb.ini
@@ -0,0 +1,17 @@
+;
+; Supported features of the 'nfb' network poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Speed capabilities   = P
+Link status          = Y
+Queue start/stop     = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Basic stats          = Y
+Extended stats       = Y
+Stats per queue      = Y
+Other kdrv           = Y
+x86-64               = Y
+Usage doc            = Y
diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index 5c80e3b..079972e 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -39,6 +39,7 @@ Network Interface Controller Drivers
     mvneta
     mvpp2
     netvsc
+    nfb
     nfp
     octeontx
     qede
diff --git a/doc/guides/nics/nfb.rst b/doc/guides/nics/nfb.rst
new file mode 100644
index 0000000..a7fb963
--- /dev/null
+++ b/doc/guides/nics/nfb.rst
@@ -0,0 +1,144 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright 2019 Cesnet
+    Copyright 2019 Netcope Technologies
+
+NFB poll mode driver library
+=================================
+
+The NFB poll mode driver library implements support for the Netcope
+FPGA Boards (**NFB-***), FPGA-based programmable NICs.
+The NFB PMD uses interface provided by the libnfb library to communicate
+with the NFB cards over the nfb layer.
+
+More information about the
+`NFB cards <http://www.netcope.com/en/products/fpga-boards>`_
+and used technology
+(`Netcope Development Kit <http://www.netcope.com/en/products/fpga-development-kit>`_)
+can be found on the `Netcope Technologies website <http://www.netcope.com/>`_.
+
+.. note::
+
+   This driver has external dependencies.
+   Therefore it is disabled in default configuration files.
+   It can be enabled by setting ``CONFIG_RTE_LIBRTE_NFB_PMD=y``
+   and recompiling.
+
+.. note::
+
+   Currently the driver is supported only on x86_64 architectures.
+   Only x86_64 versions of the external libraries are provided.
+
+Prerequisites
+-------------
+
+This PMD requires kernel modules which are responsible for initialization and
+allocation of resources needed for nfb layer function.
+Communication between PMD and kernel modules is mediated by libnfb library.
+These kernel modules and library are not part of DPDK and must be installed
+separately:
+
+*  **libnfb library**
+
+   The library provides API for initialization of nfb transfers, receiving and
+   transmitting data segments.
+
+*  **Kernel modules**
+
+   * nfb
+
+   Kernel modules manage initialization of hardware, allocation and
+   sharing of resources for user space applications.
+
+Dependencies can be found here:
+`Netcope common <https://www.netcope.com/en/company/community-support/dpdk-libsze2#NFB>`_.
+
+Versions of the packages
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The minimum version of the provided packages:
+
+* for DPDK from 19.05
+
+Configuration
+-------------
+
+These configuration options can be modified before compilation in the
+``.config`` file:
+
+*  ``CONFIG_RTE_LIBRTE_NFB_PMD`` default value: **n**
+
+   Value **y** enables compilation of nfb PMD.
+
+Using the NFB PMD
+----------------------
+
+Kernel modules have to be loaded before running the DPDK application.
+
+NFB card architecture
+---------------------
+
+The NFB cards are multi-port multi-queue cards, where (generally) data from any
+Ethernet port may be sent to any queue.
+They are represented in DPDK as a single port.
+
+NFB-200G2QL card employs an addon cable which allows to connect it to two
+physical PCI-E slots at the same time (see the diagram below).
+This is done to allow 200 Gbps of traffic to be transferred through the PCI-E
+bus (note that a single PCI-E 3.0 x16 slot provides only 125 Gbps theoretical
+throughput).
+
+Although each slot may be connected to a different CPU and therefore to a different
+NUMA node, the card is represented as a single port in DPDK. To work with data
+from the individual queues on the right NUMA node, connection of NUMA nodes on
+first and last queue (each NUMA node has half of the queues) need to be checked.
+
+.. figure:: img/szedata2_nfb200g_architecture.*
+    :align: center
+
+    NFB-200G2QL high-level diagram
+
+Limitations
+-----------
+
+Driver is usable only on Linux architecture, namely on CentOS.
+
+Since a card is always represented as a single port, but can be connected to two
+NUMA nodes, there is need for manual check where master/slave is connected.
+
+Example of usage
+----------------
+
+Read packets from 0. and 1. receive queue and write them to 0. and 1.
+transmit queue:
+
+.. code-block:: console
+
+   $RTE_TARGET/app/testpmd -l 0-3 -n 2 \
+   -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2 -i -a
+
+Example output:
+
+.. code-block:: console
+
+   [...]
+   EAL: PCI device 0000:06:00.0 on NUMA socket -1
+   EAL:   probe driver: 1b26:c1c1 net_nfb
+   PMD: Initializing NFB device (0000:06:00.0)
+   PMD: Available DMA queues RX: 8 TX: 8
+   PMD: NFB device (0000:06:00.0) successfully initialized
+   Interactive-mode selected
+   Auto-start selected
+   Configuring Port 0 (socket 0)
+   Port 0: 00:11:17:00:00:00
+   Checking link statuses...
+   Port 0 Link Up - speed 10000 Mbps - full-duplex
+   Done
+   Start automatic packet forwarding
+     io packet forwarding - CRC stripping disabled - packets/burst=32
+     nb forwarding cores=2 - nb forwarding ports=1
+     RX queues=2 - RX desc=128 - RX free threshold=0
+     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX queues=2 - TX desc=512 - TX free threshold=0
+     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX RS bit threshold=0 - TXQ flags=0x0
+   testpmd>
diff --git a/doc/guides/rel_notes/release_19_05.rst b/doc/guides/rel_notes/release_19_05.rst
index 8613282..f7001a0 100644
--- a/doc/guides/rel_notes/release_19_05.rst
+++ b/doc/guides/rel_notes/release_19_05.rst
@@ -54,6 +54,11 @@ New Features
      Also, make sure to start the actual text at the margin.
      =========================================================
 
+* **Added a net PMD NFB.**
+
+  Added the new ``nfb`` net driver for Netcope NFB cards. See
+  the :doc:`../nics/nfb` NIC guide for more details on this new driver.
+
 * **Updated KNI module and PMD.**
 
   Updated the KNI kernel module to set the max_mtu according to the given
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 502869a..5eb811b 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -38,6 +38,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5
 DIRS-$(CONFIG_RTE_LIBRTE_MVNETA_PMD) += mvneta
 DIRS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mvpp2
 DIRS-$(CONFIG_RTE_LIBRTE_NETVSC_PMD) += netvsc
+DIRS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb
 DIRS-$(CONFIG_RTE_LIBRTE_NFP_PMD) += nfp
 DIRS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += null
diff --git a/drivers/net/meson.build b/drivers/net/meson.build
index 3ecc78c..3e259f4 100644
--- a/drivers/net/meson.build
+++ b/drivers/net/meson.build
@@ -27,6 +27,7 @@ drivers = ['af_packet',
 	'mvneta',
 	'mvpp2',
 	'netvsc',
+	'nfb',
 	'nfp',
 	'null', 'octeontx', 'pcap', 'qede', 'ring',
 	'sfc',
diff --git a/drivers/net/nfb/Makefile b/drivers/net/nfb/Makefile
new file mode 100644
index 0000000..21b09b3
--- /dev/null
+++ b/drivers/net/nfb/Makefile
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2019 Cesnet
+# Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_nfb.a
+
+INCLUDES :=-I$(SRCDIR)
+
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --cflags netcope-common)
+LDLIBS += -lnfb
+LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool
+LDLIBS += -lrte_ethdev -lrte_net
+LDLIBS += -lrte_bus_pci
+LDLIBS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --libs netcope-common)
+
+EXPORT_MAP := rte_pmd_nfb_version.map
+
+LIBABIVER := 1
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_rx.c
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_tx.c
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_stats.c
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_rxmode.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/nfb/meson.build b/drivers/net/nfb/meson.build
new file mode 100644
index 0000000..457955d
--- /dev/null
+++ b/drivers/net/nfb/meson.build
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2019 Cesnet
+# Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+dep = cc.find_library('nfb', required: false)
+
+build = dep.found() and cc.has_header('nfb/nfb.h', dependencies: dep)
+
+nc = dependency('netcope-common', required: false)
+
+ext_deps += dep
+ext_deps += nc
+
+sources = files('nfb_rx.c', 'nfb_tx.c', 'nfb_stats.c', 'nfb_ethdev.c', 'nfb_rxmode.c')
diff --git a/drivers/net/nfb/nfb.h b/drivers/net/nfb/nfb.h
new file mode 100644
index 0000000..fe9fb96
--- /dev/null
+++ b/drivers/net/nfb/nfb.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_H_
+#define _NFB_H_
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+
+/* PCI Vendor ID */
+#define PCI_VENDOR_ID_NETCOPE 0x1b26
+
+/* PCI Device IDs */
+#define PCI_DEVICE_ID_NFB_40G2  0xcb80
+#define PCI_DEVICE_ID_NFB_100G2 0xc2c1
+#define PCI_DEVICE_ID_NFB_200G2QL 0xc250
+
+/* Max index of ndp rx/tx queues */
+#define RTE_ETH_NDP_MAX_RX_QUEUES 32
+#define RTE_ETH_NDP_MAX_TX_QUEUES 32
+
+/* Max index of rx/tx dmas */
+#define RTE_MAX_NC_RXMAC 256
+#define RTE_MAX_NC_TXMAC 256
+
+#define RTE_NFB_DRIVER_NAME net_nfb
+
+struct pmd_internals {
+	uint16_t         max_rxmac;
+	uint16_t         max_txmac;
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC];
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC];
+
+	char             nfb_dev[PATH_MAX];
+	struct nfb_device *nfb;
+	/* Place to remember if filter was promiscuous or filtering by table,
+	 * when disabling allmulticast
+	 */
+	enum nc_rxmac_mac_filter rx_filter_original;
+};
+
+#endif /* _NFB_H_ */
diff --git a/drivers/net/nfb/nfb_ethdev.c b/drivers/net/nfb/nfb_ethdev.c
new file mode 100644
index 0000000..be7cced
--- /dev/null
+++ b/drivers/net/nfb/nfb_ethdev.c
@@ -0,0 +1,579 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include <rte_ethdev_pci.h>
+
+#include "nfb_stats.h"
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+/**
+ * Default MAC addr
+ */
+static const struct ether_addr eth_addr = {
+	.addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
+};
+
+/**
+ * Open all RX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] rxmac
+ *   Pointer to output array of nc_rxmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of rxmac
+ */
+static void
+nfb_nc_rxmac_init(struct nfb_device *nfb,
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t *max_rxmac)
+{
+	*max_rxmac = 0;
+	while ((rxmac[*max_rxmac] = nc_rxmac_open_index(nfb, *max_rxmac)))
+		++(*max_rxmac);
+}
+
+/**
+ * Open all TX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] txmac
+ *   Pointer to output array of nc_txmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of txmac
+ */
+static void
+nfb_nc_txmac_init(struct nfb_device *nfb,
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t *max_txmac)
+{
+	*max_txmac = 0;
+	while ((txmac[*max_txmac] = nc_txmac_open_index(nfb, *max_txmac)))
+		++(*max_txmac);
+}
+
+/**
+ * Close all RX DMA queues
+ *
+ * @param rxmac
+ *   Pointer to array of nc_rxmac
+ * @param max_rxmac
+ *   Maximum index of rxmac
+ */
+static void
+nfb_nc_rxmac_deinit(struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t max_rxmac)
+{
+	for (; max_rxmac > 0; --max_rxmac) {
+		nc_rxmac_close(rxmac[max_rxmac]);
+		rxmac[max_rxmac] = NULL;
+	}
+}
+
+/**
+ * Close all TX DMA queues
+ *
+ * @param txmac
+ *   Pointer to array of nc_txmac
+ * @param max_txmac
+ *   Maximum index of txmac
+ */
+static void
+nfb_nc_txmac_deinit(struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t max_txmac)
+{
+	for (; max_txmac > 0; --max_txmac) {
+		nc_txmac_close(txmac[max_txmac]);
+		txmac[max_txmac] = NULL;
+	}
+}
+
+/**
+ * DPDK callback to start the device.
+ *
+ * Start device by starting all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_start(struct rte_eth_dev *dev)
+{
+	int ret;
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_rx; i++) {
+		ret = nfb_eth_rx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_rx;
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		ret = nfb_eth_tx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_tx;
+	}
+
+	return 0;
+
+err_tx:
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+err_rx:
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+	return ret;
+}
+
+/**
+ * DPDK callback to stop the device.
+ *
+ * Stop device by stopping all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+nfb_eth_dev_stop(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+}
+
+/**
+ * DPDK callback for Ethernet device configuration.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+/**
+ * DPDK callback to get information about the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] info
+ *   Info structure output buffer.
+ */
+static void
+nfb_eth_dev_info(struct rte_eth_dev *dev,
+	struct rte_eth_dev_info *dev_info)
+{
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = dev->data->nb_rx_queues;
+	dev_info->max_tx_queues = dev->data->nb_tx_queues;
+	dev_info->speed_capa = ETH_LINK_SPEED_100G;
+}
+
+/**
+ * DPDK callback to close the device.
+ *
+ * Destroy all queues and objects, free memory.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+nfb_eth_dev_close(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	nfb_eth_dev_stop(dev);
+
+	for (i = 0; i < nb_rx; i++) {
+		nfb_eth_rx_queue_release(dev->data->rx_queues[i]);
+		dev->data->rx_queues[i] = NULL;
+	}
+	dev->data->nb_rx_queues = 0;
+	for (i = 0; i < nb_tx; i++) {
+		nfb_eth_tx_queue_release(dev->data->tx_queues[i]);
+		dev->data->tx_queues[i] = NULL;
+	}
+	dev->data->nb_tx_queues = 0;
+}
+
+/**
+ * DPDK callback to retrieve physical link information.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] link
+ *   Storage for current link status.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_link_update(struct rte_eth_dev *dev,
+	int wait_to_complete __rte_unused)
+{
+	uint16_t i;
+	struct nc_rxmac_status status;
+	struct rte_eth_link link;
+	memset(&link, 0, sizeof(link));
+
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	status.speed = MAC_SPEED_UNKNOWN;
+
+	link.link_speed = ETH_SPEED_NUM_NONE;
+	link.link_status = ETH_LINK_DOWN;
+	link.link_duplex = ETH_LINK_FULL_DUPLEX;
+	link.link_autoneg = ETH_LINK_SPEED_FIXED;
+
+	if (internals->rxmac[0] != NULL) {
+		nc_rxmac_read_status(internals->rxmac[0], &status);
+
+		switch (status.speed) {
+		case MAC_SPEED_10G:
+			link.link_speed = ETH_SPEED_NUM_10G;
+			break;
+		case MAC_SPEED_40G:
+			link.link_speed = ETH_SPEED_NUM_40G;
+			break;
+		case MAC_SPEED_100G:
+			link.link_speed = ETH_SPEED_NUM_100G;
+			break;
+		default:
+			link.link_speed = ETH_SPEED_NUM_NONE;
+			break;
+		}
+	}
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_read_status(internals->rxmac[i], &status);
+
+		if (status.enabled && status.link_up) {
+			link.link_status = ETH_LINK_UP;
+			break;
+		}
+	}
+
+	rte_eth_linkstatus_set(dev, &link);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to bring the link UP.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_set_link_up(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_enable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_enable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to bring the link DOWN.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_set_link_down(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_disable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_disable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to set primary MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_mac_addr_set(struct rte_eth_dev *dev,
+	struct ether_addr *mac_addr)
+{
+	unsigned int i;
+	uint64_t mac = 0;
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+
+	if (!is_valid_assigned_ether_addr(mac_addr))
+		return -EINVAL;
+
+	for (i = 0; i < ETHER_ADDR_LEN; i++) {
+		mac <<= 8;
+		mac |= mac_addr->addr_bytes[i] & 0xFF;
+	}
+
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_set_mac(internals->rxmac[i], 0, mac, 1);
+
+	ether_addr_copy(mac_addr, data->mac_addrs);
+	return 0;
+}
+
+static const struct eth_dev_ops ops = {
+	.dev_start = nfb_eth_dev_start,
+	.dev_stop = nfb_eth_dev_stop,
+	.dev_set_link_up = nfb_eth_dev_set_link_up,
+	.dev_set_link_down = nfb_eth_dev_set_link_down,
+	.dev_close = nfb_eth_dev_close,
+	.dev_configure = nfb_eth_dev_configure,
+	.dev_infos_get = nfb_eth_dev_info,
+	.promiscuous_enable = nfb_eth_promiscuous_enable,
+	.promiscuous_disable = nfb_eth_promiscuous_disable,
+	.allmulticast_enable = nfb_eth_allmulticast_enable,
+	.allmulticast_disable = nfb_eth_allmulticast_disable,
+	.rx_queue_start = nfb_eth_rx_queue_start,
+	.rx_queue_stop = nfb_eth_rx_queue_stop,
+	.tx_queue_start = nfb_eth_tx_queue_start,
+	.tx_queue_stop = nfb_eth_tx_queue_stop,
+	.rx_queue_setup = nfb_eth_rx_queue_setup,
+	.tx_queue_setup = nfb_eth_tx_queue_setup,
+	.rx_queue_release = nfb_eth_rx_queue_release,
+	.tx_queue_release = nfb_eth_tx_queue_release,
+	.link_update = nfb_eth_link_update,
+	.stats_get = nfb_eth_stats_get,
+	.stats_reset = nfb_eth_stats_reset,
+	.mac_addr_set = nfb_eth_mac_addr_set,
+};
+
+/**
+ * DPDK callback to initialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_init(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+	struct ether_addr eth_addr_init;
+
+	RTE_LOG(INFO, PMD, "Initializing NFB device (" PCI_PRI_FMT ")\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	snprintf(internals->nfb_dev, PATH_MAX,
+		"/dev/nfb/by-pci-slot/" PCI_PRI_FMT,
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	/*
+	 * Get number of available DMA RX and TX queues, which is maximum
+	 * number of queues that can be created and store it in private device
+	 * data structure.
+	 */
+	internals->nfb = nfb_open(internals->nfb_dev);
+	if (internals->nfb == NULL) {
+		RTE_LOG(ERR, PMD, "nfb_open(): failed to open %s",
+			internals->nfb_dev);
+		return -EINVAL;
+	}
+	data->nb_rx_queues = ndp_get_rx_queue_available_count(internals->nfb);
+	data->nb_tx_queues = ndp_get_tx_queue_available_count(internals->nfb);
+
+	RTE_LOG(INFO, PMD, "Available NDP queues RX: %u TX: %u\n",
+		data->nb_rx_queues, data->nb_tx_queues);
+
+	nfb_nc_rxmac_init(internals->nfb,
+		internals->rxmac,
+		&internals->max_rxmac);
+	nfb_nc_txmac_init(internals->nfb,
+		internals->txmac,
+		&internals->max_txmac);
+
+	/* Set rx, tx burst functions */
+	dev->rx_pkt_burst = nfb_eth_ndp_rx;
+	dev->tx_pkt_burst = nfb_eth_ndp_tx;
+
+	/* Set function callbacks for Ethernet API */
+	dev->dev_ops = &ops;
+
+	/* Get link state */
+	nfb_eth_link_update(dev, 0);
+
+	/* Allocate space for one mac address */
+	data->mac_addrs = rte_zmalloc(data->name, sizeof(struct ether_addr),
+		RTE_CACHE_LINE_SIZE);
+	if (data->mac_addrs == NULL) {
+		RTE_LOG(ERR, PMD, "Could not alloc space for MAC address!\n");
+		nfb_close(internals->nfb);
+		return -EINVAL;
+	}
+
+	eth_random_addr(eth_addr_init.addr_bytes);
+	eth_addr_init.addr_bytes[0] = eth_addr.addr_bytes[0];
+	eth_addr_init.addr_bytes[1] = eth_addr.addr_bytes[1];
+	eth_addr_init.addr_bytes[2] = eth_addr.addr_bytes[2];
+
+	nfb_eth_mac_addr_set(dev, &eth_addr_init);
+
+	data->promiscuous = nfb_eth_promiscuous_get(dev);
+	data->all_multicast = nfb_eth_allmulticast_get(dev);
+	internals->rx_filter_original = data->promiscuous;
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully initialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to uninitialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_uninit(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+
+	dev->data->mac_addrs = NULL;
+
+	nfb_nc_rxmac_deinit(internals->rxmac, internals->max_rxmac);
+	nfb_nc_txmac_deinit(internals->txmac, internals->max_txmac);
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully uninitialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+static const struct rte_pci_id nfb_pci_id_table[] = {
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_40G2) },
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_100G2) },
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_200G2QL) },
+	{ .vendor_id = 0, }
+};
+
+/**
+ * DPDK callback to register a PCI device.
+ *
+ * This function spawns Ethernet devices out of a given PCI device.
+ *
+ * @param[in] pci_drv
+ *   PCI driver structure (nfb_driver).
+ * @param[in] pci_dev
+ *   PCI device information.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+		struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_probe(pci_dev,
+		sizeof(struct pmd_internals), nfb_eth_dev_init);
+}
+
+/**
+ * DPDK callback to remove a PCI device.
+ *
+ * This function removes all Ethernet devices belong to a given PCI device.
+ *
+ * @param[in] pci_dev
+ *   Pointer to the PCI device.
+ *
+ * @return
+ *   0 on success, the function cannot fail.
+ */
+static int
+nfb_eth_pci_remove(struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_remove(pci_dev, nfb_eth_dev_uninit);
+}
+
+static struct rte_pci_driver nfb_eth_driver = {
+	.id_table = nfb_pci_id_table,
+	.probe = nfb_eth_pci_probe,
+	.remove = nfb_eth_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(RTE_NFB_DRIVER_NAME, nfb_eth_driver);
+RTE_PMD_REGISTER_PCI_TABLE(RTE_NFB_DRIVER_NAME, nfb_pci_id_table);
+RTE_PMD_REGISTER_KMOD_DEP(RTE_NFB_DRIVER_NAME, "* nfb");
diff --git a/drivers/net/nfb/nfb_rx.c b/drivers/net/nfb/nfb_rx.c
new file mode 100644
index 0000000..9147b00
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.c
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_rx.h"
+#include "nfb.h"
+
+int
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+	int ret;
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_start(rxq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+int
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+	int ret;
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_stop(rxq->queue);
+	if (ret != 0)
+		return -EINVAL;
+
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+		uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	struct ndp_rx_queue *rxq;
+	int ret;
+
+	rxq = rte_zmalloc_socket("ndp rx queue",
+			sizeof(struct ndp_rx_queue),
+			RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (rxq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for rx queue id "
+				"%" PRIu16 "!\n", rx_queue_id);
+		return -ENOMEM;
+	}
+
+	ret = nfb_eth_rx_queue_init(internals->nfb,
+		rx_queue_id,
+		dev->data->port_id,
+		mb_pool,
+		rxq);
+
+	if (ret == 0)
+		dev->data->rx_queues[rx_queue_id] = rxq;
+	else
+		rte_free(rxq);
+
+	return ret;
+}
+
+int
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+		uint16_t rx_queue_id,
+		uint16_t port_id,
+		struct rte_mempool *mb_pool,
+		struct ndp_rx_queue *rxq)
+{
+	const struct rte_pktmbuf_pool_private *mbp_priv =
+		rte_mempool_get_priv(mb_pool);
+
+	if (nfb == NULL)
+		return -EINVAL;
+
+	rxq->queue = ndp_open_rx_queue(nfb, rx_queue_id);
+	if (rxq->queue == NULL)
+		return -EINVAL;
+
+	rxq->nfb = nfb;
+	rxq->rx_queue_id = rx_queue_id;
+	rxq->in_port = port_id;
+	rxq->mb_pool = mb_pool;
+	rxq->buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size -
+		RTE_PKTMBUF_HEADROOM);
+
+	rxq->rx_pkts = 0;
+	rxq->rx_bytes = 0;
+	rxq->err_pkts = 0;
+
+	return 0;
+}
+
+void
+nfb_eth_rx_queue_release(void *q)
+{
+	struct ndp_rx_queue *rxq = (struct ndp_rx_queue *)q;
+	if (rxq->queue != NULL) {
+		ndp_close_rx_queue(rxq->queue);
+		rte_free(rxq);
+		rxq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_rx.h b/drivers/net/nfb/nfb_rx.h
new file mode 100644
index 0000000..88a0307
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.h
@@ -0,0 +1,202 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_RX_H_
+#define _NFB_RX_H_
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+
+struct ndp_rx_queue {
+	struct nfb_device *nfb;	     /* nfb dev structure */
+	struct ndp_queue *queue;     /* rx queue */
+	uint16_t rx_queue_id;	     /* index */
+	uint8_t in_port;	     /* port */
+
+	struct rte_mempool *mb_pool; /* memory pool to allocate packets */
+	uint16_t buf_size;           /* mbuf size */
+
+	volatile uint64_t rx_pkts;   /* packets read */
+	volatile uint64_t rx_bytes;  /* bytes read */
+	volatile uint64_t err_pkts;  /* erroneous packets */
+};
+
+/**
+ * Initialize ndp_rx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param rx_queue_id
+ *   RX queue index.
+ * @param port_id
+ *   Device [external] port identifier.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ * @param[out] rxq
+ *   Pointer to ndp_rx_queue output structure
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+	uint16_t rx_queue_id,
+	uint16_t port_id,
+	struct rte_mempool *mb_pool,
+	struct ndp_rx_queue *rxq);
+
+/**
+ * DPDK callback to setup a RX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t rx_queue_id,
+	uint16_t nb_rx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_rxconf *rx_conf __rte_unused,
+	struct rte_mempool *mb_pool);
+
+/**
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void
+nfb_eth_rx_queue_release(void *q);
+
+/**
+ * Start traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * Stop traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ */
+int
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * DPDK callback for RX.
+ *
+ * @param dpdk_rxq
+ *   Generic pointer to RX queue structure.
+ * @param[out] bufs
+ *   Array to store received packets.
+ * @param nb_pkts
+ *   Maximum number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully received (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t
+nfb_eth_ndp_rx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	struct ndp_rx_queue *ndp = queue;
+	uint16_t packet_size;
+	uint64_t num_bytes = 0;
+	uint16_t num_rx;
+	unsigned int i;
+
+	const uint16_t buf_size = ndp->buf_size;
+
+	struct rte_mbuf *mbuf;
+	struct ndp_packet packets[nb_pkts];
+
+	struct rte_mbuf *mbufs[nb_pkts];
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "RX invalid arguments!\n");
+		return 0;
+	}
+
+	/* returns either all or nothing */
+	i = rte_pktmbuf_alloc_bulk(ndp->mb_pool, mbufs, nb_pkts);
+	if (unlikely(i != 0))
+		return 0;
+
+	num_rx = ndp_rx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_rx != nb_pkts)) {
+		for (i = num_rx; i < nb_pkts; i++)
+			rte_pktmbuf_free(mbufs[i]);
+	}
+
+	nb_pkts = num_rx;
+
+	num_rx = 0;
+	/*
+	 * Reads the given number of packets from NDP queue given
+	 * by queue and copies the packet data into a newly allocated mbuf
+	 * to return.
+	 */
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = mbufs[i];
+
+		/* get the space available for data in the mbuf */
+		packet_size = packets[i].data_length;
+
+		if (likely(packet_size <= buf_size)) {
+			/* NDP packet will fit in one mbuf, go ahead and copy */
+			rte_memcpy(rte_pktmbuf_mtod(mbuf, void *),
+				packets[i].data, packet_size);
+
+			mbuf->data_len = (uint16_t)packet_size;
+
+			mbuf->pkt_len = packet_size;
+			mbuf->port = ndp->in_port;
+			bufs[num_rx++] = mbuf;
+			num_bytes += packet_size;
+		} else {
+			/*
+			 * NDP packet will not fit in one mbuf,
+			 * scattered mode is not enabled, drop packet
+			 */
+			rte_pktmbuf_free(mbuf);
+		}
+	}
+
+	ndp_rx_burst_put(ndp->queue);
+
+	ndp->rx_pkts += num_rx;
+	ndp->rx_bytes += num_bytes;
+	return num_rx;
+}
+
+#endif /* _NFB_RX_H_ */
diff --git a/drivers/net/nfb/nfb_rxmode.c b/drivers/net/nfb/nfb_rxmode.c
new file mode 100644
index 0000000..97bfcb2
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.c
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+void
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+	uint16_t i;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_PROMISCUOUS);
+	}
+}
+
+void
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+	uint16_t i;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_TABLE;
+
+	/* if promisc is not enabled, do nothing */
+	if (!nfb_eth_promiscuous_get(dev))
+		return;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE);
+	}
+}
+
+int
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_PROMISCUOUS);
+}
+
+void
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+	}
+}
+
+void
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+
+	/* if multicast is not enabled do nothing */
+	if (!nfb_eth_allmulticast_get(dev))
+		return;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			internals->rx_filter_original);
+	}
+}
+
+int
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+}
diff --git a/drivers/net/nfb/nfb_rxmode.h b/drivers/net/nfb/nfb_rxmode.h
new file mode 100644
index 0000000..4c59651
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_RXMODE_H_
+#define _NFB_RXMODE_H_
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_ethdev.h>
+
+/**
+ * Getter for promiscuous mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to enable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to disable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev);
+
+/**
+ * Getter for allmulticast mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to enable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to disable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev);
+
+#endif /* _NFB_RXMODE_H_ */
diff --git a/drivers/net/nfb/nfb_stats.c b/drivers/net/nfb/nfb_stats.c
new file mode 100644
index 0000000..5aa4d00
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.c
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_stats.h"
+#include "nfb.h"
+
+int
+nfb_eth_stats_get(struct rte_eth_dev *dev,
+	struct rte_eth_stats *stats)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+	uint64_t rx_total = 0;
+	uint64_t tx_total = 0;
+	uint64_t tx_err_total = 0;
+	uint64_t rx_total_bytes = 0;
+	uint64_t tx_total_bytes = 0;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_ipackets[i] = rx_queue[i].rx_pkts;
+			stats->q_ibytes[i] = rx_queue[i].rx_bytes;
+		}
+		rx_total += rx_queue[i].rx_pkts;
+		rx_total_bytes += rx_queue[i].rx_bytes;
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_opackets[i] = tx_queue[i].tx_pkts;
+			stats->q_obytes[i] = tx_queue[i].tx_bytes;
+		}
+		tx_total += tx_queue[i].tx_pkts;
+		tx_total_bytes += tx_queue[i].tx_bytes;
+		tx_err_total += tx_queue[i].err_pkts;
+	}
+
+	stats->ipackets = rx_total;
+	stats->opackets = tx_total;
+	stats->ibytes = rx_total_bytes;
+	stats->obytes = tx_total_bytes;
+	stats->oerrors = tx_err_total;
+	return 0;
+}
+
+void
+nfb_eth_stats_reset(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		rx_queue[i].rx_pkts = 0;
+		rx_queue[i].rx_bytes = 0;
+		rx_queue[i].err_pkts = 0;
+	}
+	for (i = 0; i < nb_tx; i++) {
+		tx_queue[i].tx_pkts = 0;
+		tx_queue[i].tx_bytes = 0;
+		tx_queue[i].err_pkts = 0;
+	}
+}
diff --git a/drivers/net/nfb/nfb_stats.h b/drivers/net/nfb/nfb_stats.h
new file mode 100644
index 0000000..c7d8c8c
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_STATS_H_
+#define _NFB_STATS_H_
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_ethdev.h>
+
+/**
+ * DPDK callback to get device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] stats
+ *   Stats structure output buffer.
+ *
+ * @return
+ *   0 on success and stats is filled, negative errno value otherwise.
+ */
+int
+nfb_eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats);
+
+/**
+ * DPDK callback to clear device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_stats_reset(struct rte_eth_dev *dev);
+
+#endif /* _NFB_STATS_H_ */
diff --git a/drivers/net/nfb/nfb_tx.c b/drivers/net/nfb/nfb_tx.c
new file mode 100644
index 0000000..9b912fe
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.c
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_tx.h"
+#include "nfb.h"
+
+int
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+	int ret;
+
+	if (txq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_start(txq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+int
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+	int ret;
+
+	if (txq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "TX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_stop(txq->queue);
+	if (ret != 0)
+		return -EINVAL;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	int ret;
+	struct ndp_tx_queue *txq;
+
+	txq = rte_zmalloc_socket("ndp tx queue",
+		sizeof(struct ndp_tx_queue),
+		RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (txq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for tx queue id "
+			"%" PRIu16 "!\n", tx_queue_id);
+		return -ENOMEM;
+	}
+
+	ret = nfb_eth_tx_queue_init(internals->nfb,
+		tx_queue_id,
+		txq);
+
+	if (ret == 0)
+		dev->data->tx_queues[tx_queue_id] = txq;
+	else
+		rte_free(txq);
+
+	return ret;
+}
+
+int
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq)
+{
+	if (nfb == NULL)
+		return -EINVAL;
+
+	txq->queue = ndp_open_tx_queue(nfb, tx_queue_id);
+	if (txq->queue == NULL)
+		return -EINVAL;
+
+	txq->nfb = nfb;
+	txq->tx_queue_id = tx_queue_id;
+
+	txq->tx_pkts = 0;
+	txq->tx_bytes = 0;
+	txq->err_pkts = 0;
+
+	return 0;
+}
+
+void
+nfb_eth_tx_queue_release(void *q)
+{
+	struct ndp_tx_queue *txq = (struct ndp_tx_queue *)q;
+	if (txq->queue != NULL) {
+		ndp_close_tx_queue(txq->queue);
+		rte_free(txq);
+		txq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_tx.h b/drivers/net/nfb/nfb_tx.h
new file mode 100644
index 0000000..edf5ede
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.h
@@ -0,0 +1,193 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_TX_H_
+#define _NFB_TX_H_
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+
+struct ndp_tx_queue {
+	struct nfb_device *nfb;     /* nfb dev structure */
+	struct ndp_queue *queue;    /* tx queue */
+	uint16_t          tx_queue_id;       /* index */
+	volatile uint64_t tx_pkts;  /* packets transmitted */
+	volatile uint64_t tx_bytes; /* bytes transmitted */
+	volatile uint64_t err_pkts; /* erroneous packets */
+};
+
+/**
+ * DPDK callback to setup a TX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mp
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused);
+
+/**
+ * Initialize ndp_tx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param tx_queue_id
+ *   TX queue index.
+ * @param[out] txq
+ *   Pointer to ndp_tx_queue output structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq);
+
+/**
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void
+nfb_eth_tx_queue_release(void *q);
+
+/**
+ * Start traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * Stop traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * DPDK callback for TX.
+ *
+ * @param dpdk_txq
+ *   Generic pointer to TX queue structure.
+ * @param bufs
+ *   Packets to transmit.
+ * @param nb_pkts
+ *   Number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully transmitted (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t
+nfb_eth_ndp_tx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	int i;
+	struct rte_mbuf *mbuf;
+	struct ndp_tx_queue *ndp = queue;
+	uint16_t num_tx = 0;
+	uint64_t num_bytes = 0;
+
+	void *dst;
+	uint32_t pkt_len;
+	uint8_t mbuf_segs;
+
+	struct ndp_packet packets[nb_pkts];
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "TX invalid arguments!\n");
+		return 0;
+	}
+
+	for (i = 0; i < nb_pkts; i++) {
+		packets[i].data_length = bufs[i]->pkt_len;
+		packets[i].header_length = 0;
+	}
+
+	num_tx = ndp_tx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_tx != nb_pkts))
+		return 0;
+
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = bufs[i];
+
+		pkt_len = mbuf->pkt_len;
+		mbuf_segs = mbuf->nb_segs;
+
+		num_bytes += pkt_len;
+		if (mbuf_segs == 1) {
+			/*
+			 * non-scattered packet,
+			 * transmit from one mbuf
+			 */
+			rte_memcpy(packets[i].data,
+				rte_pktmbuf_mtod(mbuf, const void *),
+				pkt_len);
+		} else {
+			/* scattered packet, transmit from more mbufs */
+			struct rte_mbuf *m = mbuf;
+			while (m) {
+				dst = packets[i].data;
+
+				rte_memcpy(dst,
+					rte_pktmbuf_mtod(m,
+					const void *),
+					m->data_len);
+				dst = ((uint8_t *)(dst)) +
+					m->data_len;
+				m = m->next;
+			}
+		}
+
+		rte_pktmbuf_free(mbuf);
+	}
+
+	ndp_tx_burst_flush(ndp->queue);
+
+	ndp->tx_pkts += num_tx;
+	ndp->err_pkts += nb_pkts - num_tx;
+	ndp->tx_bytes += num_bytes;
+	return num_tx;
+}
+
+#endif /* _NFB_TX_H_ */
diff --git a/drivers/net/nfb/rte_pmd_nfb_version.map b/drivers/net/nfb/rte_pmd_nfb_version.map
new file mode 100644
index 0000000..fc8c95e
--- /dev/null
+++ b/drivers/net/nfb/rte_pmd_nfb_version.map
@@ -0,0 +1,4 @@
+DPDK_19.05 {
+
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 262132f..381dc7f 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -196,6 +196,8 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC)      += -lrte_pmd_softnic
 endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD)    += -lrte_pmd_sfc_efx
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2 -lsze2
+_LDLIBS-$(CONFIG_RTE_LIBRTE_NFB_PMD)        += -lrte_pmd_nfb
+_LDLIBS-$(CONFIG_RTE_LIBRTE_NFB_PMD)        +=  $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --libs netcope-common)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_TAP)        += -lrte_pmd_tap
 _LDLIBS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += -lrte_pmd_thunderx_nicvf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD) += -lrte_pmd_vdev_netvsc
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [dpdk-dev] [PATCH v7] net/nfb: new netcope driver
  2019-04-07 15:03   ` [dpdk-dev] [PATCH v7] " Rastislav Cernay
@ 2019-04-07 15:03     ` Rastislav Cernay
  2019-04-12 12:15     ` Ferruh Yigit
  2019-04-12 12:16     ` Ferruh Yigit
  2 siblings, 0 replies; 50+ messages in thread
From: Rastislav Cernay @ 2019-04-07 15:03 UTC (permalink / raw)
  To: dev; +Cc: ferruh.yigit, Rastislav Cernay

From: Rastislav Cernay <cernay@netcope.com>

Added new net driver for Netcope nfb cards

Signed-off-by: Rastislav Cernay <cernay@netcope.com>
---
v2: remove unnecessary cast
    remove unnecessary zeroing
    move declaration to not mix with code
    restore skeleton example
v3: add release notes
    add doc to doc index
    add architecture limits to doc
    edit features list
    add .map file
    change link to dependecies to official vendor site
    move declarations out of code
    remove false comments (rte_errno is set)
    comments to c89 style
    remove log from main rx loop
    remove redundant code
v4: API is experimental
    fixed meson build dependency
    random initial MAC
    stats->q_errors is for intput err only
    move more declarations to a beginning
    fixed err log in TX
    use of pkg-config
v5: fixed pkg-config for new version of netcope-common
v6: driver is not experimental
    fix stats
    fix some code issues
    add release notes
    update code to 19.05
    fix copyright
    fix meson build
v7: fix doc
    fix shared build
    remove unused includes and libs
 MAINTAINERS                             |   7 +
 config/common_base                      |   5 +
 devtools/test-build.sh                  |   1 +
 doc/guides/nics/features/nfb.ini        |  17 +
 doc/guides/nics/index.rst               |   1 +
 doc/guides/nics/nfb.rst                 | 144 ++++++++
 doc/guides/rel_notes/release_19_05.rst  |   5 +
 drivers/net/Makefile                    |   1 +
 drivers/net/meson.build                 |   1 +
 drivers/net/nfb/Makefile                |  43 +++
 drivers/net/nfb/meson.build             |  15 +
 drivers/net/nfb/nfb.h                   |  50 +++
 drivers/net/nfb/nfb_ethdev.c            | 579 ++++++++++++++++++++++++++++++++
 drivers/net/nfb/nfb_rx.c                | 127 +++++++
 drivers/net/nfb/nfb_rx.h                | 202 +++++++++++
 drivers/net/nfb/nfb_rxmode.c            | 100 ++++++
 drivers/net/nfb/nfb_rxmode.h            |  69 ++++
 drivers/net/nfb/nfb_stats.c             |  77 +++++
 drivers/net/nfb/nfb_stats.h             |  38 +++
 drivers/net/nfb/nfb_tx.c                | 113 +++++++
 drivers/net/nfb/nfb_tx.h                | 193 +++++++++++
 drivers/net/nfb/rte_pmd_nfb_version.map |   4 +
 mk/rte.app.mk                           |   2 +
 23 files changed, 1794 insertions(+)
 create mode 100644 doc/guides/nics/features/nfb.ini
 create mode 100644 doc/guides/nics/nfb.rst
 create mode 100644 drivers/net/nfb/Makefile
 create mode 100644 drivers/net/nfb/meson.build
 create mode 100644 drivers/net/nfb/nfb.h
 create mode 100644 drivers/net/nfb/nfb_ethdev.c
 create mode 100644 drivers/net/nfb/nfb_rx.c
 create mode 100644 drivers/net/nfb/nfb_rx.h
 create mode 100644 drivers/net/nfb/nfb_rxmode.c
 create mode 100644 drivers/net/nfb/nfb_rxmode.h
 create mode 100644 drivers/net/nfb/nfb_stats.c
 create mode 100644 drivers/net/nfb/nfb_stats.h
 create mode 100644 drivers/net/nfb/nfb_tx.c
 create mode 100644 drivers/net/nfb/nfb_tx.h
 create mode 100644 drivers/net/nfb/rte_pmd_nfb_version.map

diff --git a/MAINTAINERS b/MAINTAINERS
index e9ff2b4..3041905 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -662,6 +662,13 @@ F: drivers/net/szedata2/
 F: doc/guides/nics/szedata2.rst
 F: doc/guides/nics/features/szedata2.ini
 
+Netcope nfb
+M: Rastislav Cernay <cernay@netcope.com>
+M: Jan Remes <remes@netcope.com>
+F: drivers/net/nfb/
+F: doc/guides/nics/nfb.rst
+F: doc/guides/nics/features/nfb.ini
+
 Netronome nfp
 M: Alejandro Lucero <alejandro.lucero@netronome.com>
 F: drivers/net/nfp/
diff --git a/config/common_base b/config/common_base
index 6292bc4..8208d5d 100644
--- a/config/common_base
+++ b/config/common_base
@@ -376,6 +376,11 @@ CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n
 CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
 
 #
+# Compile software PMD backed by NFB device
+#
+CONFIG_RTE_LIBRTE_NFB_PMD=n
+
+#
 # Compile burst-oriented Cavium Thunderx NICVF PMD driver
 #
 CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD=y
diff --git a/devtools/test-build.sh b/devtools/test-build.sh
index 70e91da..9b50bf7 100755
--- a/devtools/test-build.sh
+++ b/devtools/test-build.sh
@@ -19,6 +19,7 @@ default_path=$PATH
 # - DPDK_DEP_SSL (y/[n])
 # - DPDK_DEP_IPSEC_MB (y/[n])
 # - DPDK_DEP_SZE (y/[n])
+# - DPDK_DEP_NFB (y/[n])
 # - DPDK_DEP_ZLIB (y/[n])
 # - DPDK_MAKE_JOBS (int)
 # - DPDK_NOTIFY (notify-send)
diff --git a/doc/guides/nics/features/nfb.ini b/doc/guides/nics/features/nfb.ini
new file mode 100644
index 0000000..6174d65
--- /dev/null
+++ b/doc/guides/nics/features/nfb.ini
@@ -0,0 +1,17 @@
+;
+; Supported features of the 'nfb' network poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Speed capabilities   = P
+Link status          = Y
+Queue start/stop     = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Basic stats          = Y
+Extended stats       = Y
+Stats per queue      = Y
+Other kdrv           = Y
+x86-64               = Y
+Usage doc            = Y
diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index 5c80e3b..079972e 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -39,6 +39,7 @@ Network Interface Controller Drivers
     mvneta
     mvpp2
     netvsc
+    nfb
     nfp
     octeontx
     qede
diff --git a/doc/guides/nics/nfb.rst b/doc/guides/nics/nfb.rst
new file mode 100644
index 0000000..a7fb963
--- /dev/null
+++ b/doc/guides/nics/nfb.rst
@@ -0,0 +1,144 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright 2019 Cesnet
+    Copyright 2019 Netcope Technologies
+
+NFB poll mode driver library
+=================================
+
+The NFB poll mode driver library implements support for the Netcope
+FPGA Boards (**NFB-***), FPGA-based programmable NICs.
+The NFB PMD uses interface provided by the libnfb library to communicate
+with the NFB cards over the nfb layer.
+
+More information about the
+`NFB cards <http://www.netcope.com/en/products/fpga-boards>`_
+and used technology
+(`Netcope Development Kit <http://www.netcope.com/en/products/fpga-development-kit>`_)
+can be found on the `Netcope Technologies website <http://www.netcope.com/>`_.
+
+.. note::
+
+   This driver has external dependencies.
+   Therefore it is disabled in default configuration files.
+   It can be enabled by setting ``CONFIG_RTE_LIBRTE_NFB_PMD=y``
+   and recompiling.
+
+.. note::
+
+   Currently the driver is supported only on x86_64 architectures.
+   Only x86_64 versions of the external libraries are provided.
+
+Prerequisites
+-------------
+
+This PMD requires kernel modules which are responsible for initialization and
+allocation of resources needed for nfb layer function.
+Communication between PMD and kernel modules is mediated by libnfb library.
+These kernel modules and library are not part of DPDK and must be installed
+separately:
+
+*  **libnfb library**
+
+   The library provides API for initialization of nfb transfers, receiving and
+   transmitting data segments.
+
+*  **Kernel modules**
+
+   * nfb
+
+   Kernel modules manage initialization of hardware, allocation and
+   sharing of resources for user space applications.
+
+Dependencies can be found here:
+`Netcope common <https://www.netcope.com/en/company/community-support/dpdk-libsze2#NFB>`_.
+
+Versions of the packages
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The minimum version of the provided packages:
+
+* for DPDK from 19.05
+
+Configuration
+-------------
+
+These configuration options can be modified before compilation in the
+``.config`` file:
+
+*  ``CONFIG_RTE_LIBRTE_NFB_PMD`` default value: **n**
+
+   Value **y** enables compilation of nfb PMD.
+
+Using the NFB PMD
+----------------------
+
+Kernel modules have to be loaded before running the DPDK application.
+
+NFB card architecture
+---------------------
+
+The NFB cards are multi-port multi-queue cards, where (generally) data from any
+Ethernet port may be sent to any queue.
+They are represented in DPDK as a single port.
+
+NFB-200G2QL card employs an addon cable which allows to connect it to two
+physical PCI-E slots at the same time (see the diagram below).
+This is done to allow 200 Gbps of traffic to be transferred through the PCI-E
+bus (note that a single PCI-E 3.0 x16 slot provides only 125 Gbps theoretical
+throughput).
+
+Although each slot may be connected to a different CPU and therefore to a different
+NUMA node, the card is represented as a single port in DPDK. To work with data
+from the individual queues on the right NUMA node, connection of NUMA nodes on
+first and last queue (each NUMA node has half of the queues) need to be checked.
+
+.. figure:: img/szedata2_nfb200g_architecture.*
+    :align: center
+
+    NFB-200G2QL high-level diagram
+
+Limitations
+-----------
+
+Driver is usable only on Linux architecture, namely on CentOS.
+
+Since a card is always represented as a single port, but can be connected to two
+NUMA nodes, there is need for manual check where master/slave is connected.
+
+Example of usage
+----------------
+
+Read packets from 0. and 1. receive queue and write them to 0. and 1.
+transmit queue:
+
+.. code-block:: console
+
+   $RTE_TARGET/app/testpmd -l 0-3 -n 2 \
+   -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2 -i -a
+
+Example output:
+
+.. code-block:: console
+
+   [...]
+   EAL: PCI device 0000:06:00.0 on NUMA socket -1
+   EAL:   probe driver: 1b26:c1c1 net_nfb
+   PMD: Initializing NFB device (0000:06:00.0)
+   PMD: Available DMA queues RX: 8 TX: 8
+   PMD: NFB device (0000:06:00.0) successfully initialized
+   Interactive-mode selected
+   Auto-start selected
+   Configuring Port 0 (socket 0)
+   Port 0: 00:11:17:00:00:00
+   Checking link statuses...
+   Port 0 Link Up - speed 10000 Mbps - full-duplex
+   Done
+   Start automatic packet forwarding
+     io packet forwarding - CRC stripping disabled - packets/burst=32
+     nb forwarding cores=2 - nb forwarding ports=1
+     RX queues=2 - RX desc=128 - RX free threshold=0
+     RX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX queues=2 - TX desc=512 - TX free threshold=0
+     TX threshold registers: pthresh=0 hthresh=0 wthresh=0
+     TX RS bit threshold=0 - TXQ flags=0x0
+   testpmd>
diff --git a/doc/guides/rel_notes/release_19_05.rst b/doc/guides/rel_notes/release_19_05.rst
index 8613282..f7001a0 100644
--- a/doc/guides/rel_notes/release_19_05.rst
+++ b/doc/guides/rel_notes/release_19_05.rst
@@ -54,6 +54,11 @@ New Features
      Also, make sure to start the actual text at the margin.
      =========================================================
 
+* **Added a net PMD NFB.**
+
+  Added the new ``nfb`` net driver for Netcope NFB cards. See
+  the :doc:`../nics/nfb` NIC guide for more details on this new driver.
+
 * **Updated KNI module and PMD.**
 
   Updated the KNI kernel module to set the max_mtu according to the given
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 502869a..5eb811b 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -38,6 +38,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5
 DIRS-$(CONFIG_RTE_LIBRTE_MVNETA_PMD) += mvneta
 DIRS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mvpp2
 DIRS-$(CONFIG_RTE_LIBRTE_NETVSC_PMD) += netvsc
+DIRS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb
 DIRS-$(CONFIG_RTE_LIBRTE_NFP_PMD) += nfp
 DIRS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += null
diff --git a/drivers/net/meson.build b/drivers/net/meson.build
index 3ecc78c..3e259f4 100644
--- a/drivers/net/meson.build
+++ b/drivers/net/meson.build
@@ -27,6 +27,7 @@ drivers = ['af_packet',
 	'mvneta',
 	'mvpp2',
 	'netvsc',
+	'nfb',
 	'nfp',
 	'null', 'octeontx', 'pcap', 'qede', 'ring',
 	'sfc',
diff --git a/drivers/net/nfb/Makefile b/drivers/net/nfb/Makefile
new file mode 100644
index 0000000..21b09b3
--- /dev/null
+++ b/drivers/net/nfb/Makefile
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2019 Cesnet
+# Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_nfb.a
+
+INCLUDES :=-I$(SRCDIR)
+
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --cflags netcope-common)
+LDLIBS += -lnfb
+LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool
+LDLIBS += -lrte_ethdev -lrte_net
+LDLIBS += -lrte_bus_pci
+LDLIBS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --libs netcope-common)
+
+EXPORT_MAP := rte_pmd_nfb_version.map
+
+LIBABIVER := 1
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_rx.c
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_tx.c
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_stats.c
+SRCS-$(CONFIG_RTE_LIBRTE_NFB_PMD) += nfb_rxmode.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/nfb/meson.build b/drivers/net/nfb/meson.build
new file mode 100644
index 0000000..457955d
--- /dev/null
+++ b/drivers/net/nfb/meson.build
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2019 Cesnet
+# Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+# All rights reserved.
+
+dep = cc.find_library('nfb', required: false)
+
+build = dep.found() and cc.has_header('nfb/nfb.h', dependencies: dep)
+
+nc = dependency('netcope-common', required: false)
+
+ext_deps += dep
+ext_deps += nc
+
+sources = files('nfb_rx.c', 'nfb_tx.c', 'nfb_stats.c', 'nfb_ethdev.c', 'nfb_rxmode.c')
diff --git a/drivers/net/nfb/nfb.h b/drivers/net/nfb/nfb.h
new file mode 100644
index 0000000..fe9fb96
--- /dev/null
+++ b/drivers/net/nfb/nfb.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_H_
+#define _NFB_H_
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+
+/* PCI Vendor ID */
+#define PCI_VENDOR_ID_NETCOPE 0x1b26
+
+/* PCI Device IDs */
+#define PCI_DEVICE_ID_NFB_40G2  0xcb80
+#define PCI_DEVICE_ID_NFB_100G2 0xc2c1
+#define PCI_DEVICE_ID_NFB_200G2QL 0xc250
+
+/* Max index of ndp rx/tx queues */
+#define RTE_ETH_NDP_MAX_RX_QUEUES 32
+#define RTE_ETH_NDP_MAX_TX_QUEUES 32
+
+/* Max index of rx/tx dmas */
+#define RTE_MAX_NC_RXMAC 256
+#define RTE_MAX_NC_TXMAC 256
+
+#define RTE_NFB_DRIVER_NAME net_nfb
+
+struct pmd_internals {
+	uint16_t         max_rxmac;
+	uint16_t         max_txmac;
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC];
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC];
+
+	char             nfb_dev[PATH_MAX];
+	struct nfb_device *nfb;
+	/* Place to remember if filter was promiscuous or filtering by table,
+	 * when disabling allmulticast
+	 */
+	enum nc_rxmac_mac_filter rx_filter_original;
+};
+
+#endif /* _NFB_H_ */
diff --git a/drivers/net/nfb/nfb_ethdev.c b/drivers/net/nfb/nfb_ethdev.c
new file mode 100644
index 0000000..be7cced
--- /dev/null
+++ b/drivers/net/nfb/nfb_ethdev.c
@@ -0,0 +1,579 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+#include <netcope/rxmac.h>
+#include <netcope/txmac.h>
+
+#include <rte_ethdev_pci.h>
+
+#include "nfb_stats.h"
+#include "nfb_rx.h"
+#include "nfb_tx.h"
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+/**
+ * Default MAC addr
+ */
+static const struct ether_addr eth_addr = {
+	.addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
+};
+
+/**
+ * Open all RX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] rxmac
+ *   Pointer to output array of nc_rxmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of rxmac
+ */
+static void
+nfb_nc_rxmac_init(struct nfb_device *nfb,
+	struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t *max_rxmac)
+{
+	*max_rxmac = 0;
+	while ((rxmac[*max_rxmac] = nc_rxmac_open_index(nfb, *max_rxmac)))
+		++(*max_rxmac);
+}
+
+/**
+ * Open all TX DMA queues
+ *
+ * @param dev
+ *   Pointer to nfb device.
+ * @param[out] txmac
+ *   Pointer to output array of nc_txmac
+ * @param[out] max_rxmac
+ *   Pointer to output max index of txmac
+ */
+static void
+nfb_nc_txmac_init(struct nfb_device *nfb,
+	struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t *max_txmac)
+{
+	*max_txmac = 0;
+	while ((txmac[*max_txmac] = nc_txmac_open_index(nfb, *max_txmac)))
+		++(*max_txmac);
+}
+
+/**
+ * Close all RX DMA queues
+ *
+ * @param rxmac
+ *   Pointer to array of nc_rxmac
+ * @param max_rxmac
+ *   Maximum index of rxmac
+ */
+static void
+nfb_nc_rxmac_deinit(struct nc_rxmac *rxmac[RTE_MAX_NC_RXMAC],
+	uint16_t max_rxmac)
+{
+	for (; max_rxmac > 0; --max_rxmac) {
+		nc_rxmac_close(rxmac[max_rxmac]);
+		rxmac[max_rxmac] = NULL;
+	}
+}
+
+/**
+ * Close all TX DMA queues
+ *
+ * @param txmac
+ *   Pointer to array of nc_txmac
+ * @param max_txmac
+ *   Maximum index of txmac
+ */
+static void
+nfb_nc_txmac_deinit(struct nc_txmac *txmac[RTE_MAX_NC_TXMAC],
+	uint16_t max_txmac)
+{
+	for (; max_txmac > 0; --max_txmac) {
+		nc_txmac_close(txmac[max_txmac]);
+		txmac[max_txmac] = NULL;
+	}
+}
+
+/**
+ * DPDK callback to start the device.
+ *
+ * Start device by starting all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_start(struct rte_eth_dev *dev)
+{
+	int ret;
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_rx; i++) {
+		ret = nfb_eth_rx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_rx;
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		ret = nfb_eth_tx_queue_start(dev, i);
+		if (ret != 0)
+			goto err_tx;
+	}
+
+	return 0;
+
+err_tx:
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+err_rx:
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+	return ret;
+}
+
+/**
+ * DPDK callback to stop the device.
+ *
+ * Stop device by stopping all configured queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+nfb_eth_dev_stop(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	for (i = 0; i < nb_tx; i++)
+		nfb_eth_tx_queue_stop(dev, i);
+
+	for (i = 0; i < nb_rx; i++)
+		nfb_eth_rx_queue_stop(dev, i);
+}
+
+/**
+ * DPDK callback for Ethernet device configuration.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+/**
+ * DPDK callback to get information about the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] info
+ *   Info structure output buffer.
+ */
+static void
+nfb_eth_dev_info(struct rte_eth_dev *dev,
+	struct rte_eth_dev_info *dev_info)
+{
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = dev->data->nb_rx_queues;
+	dev_info->max_tx_queues = dev->data->nb_tx_queues;
+	dev_info->speed_capa = ETH_LINK_SPEED_100G;
+}
+
+/**
+ * DPDK callback to close the device.
+ *
+ * Destroy all queues and objects, free memory.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+nfb_eth_dev_close(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	nfb_eth_dev_stop(dev);
+
+	for (i = 0; i < nb_rx; i++) {
+		nfb_eth_rx_queue_release(dev->data->rx_queues[i]);
+		dev->data->rx_queues[i] = NULL;
+	}
+	dev->data->nb_rx_queues = 0;
+	for (i = 0; i < nb_tx; i++) {
+		nfb_eth_tx_queue_release(dev->data->tx_queues[i]);
+		dev->data->tx_queues[i] = NULL;
+	}
+	dev->data->nb_tx_queues = 0;
+}
+
+/**
+ * DPDK callback to retrieve physical link information.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] link
+ *   Storage for current link status.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_link_update(struct rte_eth_dev *dev,
+	int wait_to_complete __rte_unused)
+{
+	uint16_t i;
+	struct nc_rxmac_status status;
+	struct rte_eth_link link;
+	memset(&link, 0, sizeof(link));
+
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	status.speed = MAC_SPEED_UNKNOWN;
+
+	link.link_speed = ETH_SPEED_NUM_NONE;
+	link.link_status = ETH_LINK_DOWN;
+	link.link_duplex = ETH_LINK_FULL_DUPLEX;
+	link.link_autoneg = ETH_LINK_SPEED_FIXED;
+
+	if (internals->rxmac[0] != NULL) {
+		nc_rxmac_read_status(internals->rxmac[0], &status);
+
+		switch (status.speed) {
+		case MAC_SPEED_10G:
+			link.link_speed = ETH_SPEED_NUM_10G;
+			break;
+		case MAC_SPEED_40G:
+			link.link_speed = ETH_SPEED_NUM_40G;
+			break;
+		case MAC_SPEED_100G:
+			link.link_speed = ETH_SPEED_NUM_100G;
+			break;
+		default:
+			link.link_speed = ETH_SPEED_NUM_NONE;
+			break;
+		}
+	}
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_read_status(internals->rxmac[i], &status);
+
+		if (status.enabled && status.link_up) {
+			link.link_status = ETH_LINK_UP;
+			break;
+		}
+	}
+
+	rte_eth_linkstatus_set(dev, &link);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to bring the link UP.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_set_link_up(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_enable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_enable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to bring the link DOWN.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_set_link_down(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_disable(internals->rxmac[i]);
+
+	for (i = 0; i < internals->max_txmac; ++i)
+		nc_txmac_disable(internals->txmac[i]);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to set primary MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_mac_addr_set(struct rte_eth_dev *dev,
+	struct ether_addr *mac_addr)
+{
+	unsigned int i;
+	uint64_t mac = 0;
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+
+	if (!is_valid_assigned_ether_addr(mac_addr))
+		return -EINVAL;
+
+	for (i = 0; i < ETHER_ADDR_LEN; i++) {
+		mac <<= 8;
+		mac |= mac_addr->addr_bytes[i] & 0xFF;
+	}
+
+	for (i = 0; i < internals->max_rxmac; ++i)
+		nc_rxmac_set_mac(internals->rxmac[i], 0, mac, 1);
+
+	ether_addr_copy(mac_addr, data->mac_addrs);
+	return 0;
+}
+
+static const struct eth_dev_ops ops = {
+	.dev_start = nfb_eth_dev_start,
+	.dev_stop = nfb_eth_dev_stop,
+	.dev_set_link_up = nfb_eth_dev_set_link_up,
+	.dev_set_link_down = nfb_eth_dev_set_link_down,
+	.dev_close = nfb_eth_dev_close,
+	.dev_configure = nfb_eth_dev_configure,
+	.dev_infos_get = nfb_eth_dev_info,
+	.promiscuous_enable = nfb_eth_promiscuous_enable,
+	.promiscuous_disable = nfb_eth_promiscuous_disable,
+	.allmulticast_enable = nfb_eth_allmulticast_enable,
+	.allmulticast_disable = nfb_eth_allmulticast_disable,
+	.rx_queue_start = nfb_eth_rx_queue_start,
+	.rx_queue_stop = nfb_eth_rx_queue_stop,
+	.tx_queue_start = nfb_eth_tx_queue_start,
+	.tx_queue_stop = nfb_eth_tx_queue_stop,
+	.rx_queue_setup = nfb_eth_rx_queue_setup,
+	.tx_queue_setup = nfb_eth_tx_queue_setup,
+	.rx_queue_release = nfb_eth_rx_queue_release,
+	.tx_queue_release = nfb_eth_tx_queue_release,
+	.link_update = nfb_eth_link_update,
+	.stats_get = nfb_eth_stats_get,
+	.stats_reset = nfb_eth_stats_reset,
+	.mac_addr_set = nfb_eth_mac_addr_set,
+};
+
+/**
+ * DPDK callback to initialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_init(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+	struct ether_addr eth_addr_init;
+
+	RTE_LOG(INFO, PMD, "Initializing NFB device (" PCI_PRI_FMT ")\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	snprintf(internals->nfb_dev, PATH_MAX,
+		"/dev/nfb/by-pci-slot/" PCI_PRI_FMT,
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	/*
+	 * Get number of available DMA RX and TX queues, which is maximum
+	 * number of queues that can be created and store it in private device
+	 * data structure.
+	 */
+	internals->nfb = nfb_open(internals->nfb_dev);
+	if (internals->nfb == NULL) {
+		RTE_LOG(ERR, PMD, "nfb_open(): failed to open %s",
+			internals->nfb_dev);
+		return -EINVAL;
+	}
+	data->nb_rx_queues = ndp_get_rx_queue_available_count(internals->nfb);
+	data->nb_tx_queues = ndp_get_tx_queue_available_count(internals->nfb);
+
+	RTE_LOG(INFO, PMD, "Available NDP queues RX: %u TX: %u\n",
+		data->nb_rx_queues, data->nb_tx_queues);
+
+	nfb_nc_rxmac_init(internals->nfb,
+		internals->rxmac,
+		&internals->max_rxmac);
+	nfb_nc_txmac_init(internals->nfb,
+		internals->txmac,
+		&internals->max_txmac);
+
+	/* Set rx, tx burst functions */
+	dev->rx_pkt_burst = nfb_eth_ndp_rx;
+	dev->tx_pkt_burst = nfb_eth_ndp_tx;
+
+	/* Set function callbacks for Ethernet API */
+	dev->dev_ops = &ops;
+
+	/* Get link state */
+	nfb_eth_link_update(dev, 0);
+
+	/* Allocate space for one mac address */
+	data->mac_addrs = rte_zmalloc(data->name, sizeof(struct ether_addr),
+		RTE_CACHE_LINE_SIZE);
+	if (data->mac_addrs == NULL) {
+		RTE_LOG(ERR, PMD, "Could not alloc space for MAC address!\n");
+		nfb_close(internals->nfb);
+		return -EINVAL;
+	}
+
+	eth_random_addr(eth_addr_init.addr_bytes);
+	eth_addr_init.addr_bytes[0] = eth_addr.addr_bytes[0];
+	eth_addr_init.addr_bytes[1] = eth_addr.addr_bytes[1];
+	eth_addr_init.addr_bytes[2] = eth_addr.addr_bytes[2];
+
+	nfb_eth_mac_addr_set(dev, &eth_addr_init);
+
+	data->promiscuous = nfb_eth_promiscuous_get(dev);
+	data->all_multicast = nfb_eth_allmulticast_get(dev);
+	internals->rx_filter_original = data->promiscuous;
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully initialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+/**
+ * DPDK callback to uninitialize an ethernet device
+ *
+ * @param dev
+ *   Pointer to ethernet device structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_dev_uninit(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_internals *internals = (struct pmd_internals *)
+		data->dev_private;
+
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_pci_addr *pci_addr = &pci_dev->addr;
+
+	dev->data->mac_addrs = NULL;
+
+	nfb_nc_rxmac_deinit(internals->rxmac, internals->max_rxmac);
+	nfb_nc_txmac_deinit(internals->txmac, internals->max_txmac);
+
+	RTE_LOG(INFO, PMD, "NFB device ("
+		PCI_PRI_FMT ") successfully uninitialized\n",
+		pci_addr->domain, pci_addr->bus, pci_addr->devid,
+		pci_addr->function);
+
+	return 0;
+}
+
+static const struct rte_pci_id nfb_pci_id_table[] = {
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_40G2) },
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_100G2) },
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_NETCOPE, PCI_DEVICE_ID_NFB_200G2QL) },
+	{ .vendor_id = 0, }
+};
+
+/**
+ * DPDK callback to register a PCI device.
+ *
+ * This function spawns Ethernet devices out of a given PCI device.
+ *
+ * @param[in] pci_drv
+ *   PCI driver structure (nfb_driver).
+ * @param[in] pci_dev
+ *   PCI device information.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+static int
+nfb_eth_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+		struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_probe(pci_dev,
+		sizeof(struct pmd_internals), nfb_eth_dev_init);
+}
+
+/**
+ * DPDK callback to remove a PCI device.
+ *
+ * This function removes all Ethernet devices belong to a given PCI device.
+ *
+ * @param[in] pci_dev
+ *   Pointer to the PCI device.
+ *
+ * @return
+ *   0 on success, the function cannot fail.
+ */
+static int
+nfb_eth_pci_remove(struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_remove(pci_dev, nfb_eth_dev_uninit);
+}
+
+static struct rte_pci_driver nfb_eth_driver = {
+	.id_table = nfb_pci_id_table,
+	.probe = nfb_eth_pci_probe,
+	.remove = nfb_eth_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(RTE_NFB_DRIVER_NAME, nfb_eth_driver);
+RTE_PMD_REGISTER_PCI_TABLE(RTE_NFB_DRIVER_NAME, nfb_pci_id_table);
+RTE_PMD_REGISTER_KMOD_DEP(RTE_NFB_DRIVER_NAME, "* nfb");
diff --git a/drivers/net/nfb/nfb_rx.c b/drivers/net/nfb/nfb_rx.c
new file mode 100644
index 0000000..9147b00
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.c
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_rx.h"
+#include "nfb.h"
+
+int
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+	int ret;
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_start(rxq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+int
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id)
+{
+	struct ndp_rx_queue *rxq = dev->data->rx_queues[rxq_id];
+	int ret;
+
+	if (rxq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_stop(rxq->queue);
+	if (ret != 0)
+		return -EINVAL;
+
+	dev->data->rx_queue_state[rxq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+		uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	struct ndp_rx_queue *rxq;
+	int ret;
+
+	rxq = rte_zmalloc_socket("ndp rx queue",
+			sizeof(struct ndp_rx_queue),
+			RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (rxq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for rx queue id "
+				"%" PRIu16 "!\n", rx_queue_id);
+		return -ENOMEM;
+	}
+
+	ret = nfb_eth_rx_queue_init(internals->nfb,
+		rx_queue_id,
+		dev->data->port_id,
+		mb_pool,
+		rxq);
+
+	if (ret == 0)
+		dev->data->rx_queues[rx_queue_id] = rxq;
+	else
+		rte_free(rxq);
+
+	return ret;
+}
+
+int
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+		uint16_t rx_queue_id,
+		uint16_t port_id,
+		struct rte_mempool *mb_pool,
+		struct ndp_rx_queue *rxq)
+{
+	const struct rte_pktmbuf_pool_private *mbp_priv =
+		rte_mempool_get_priv(mb_pool);
+
+	if (nfb == NULL)
+		return -EINVAL;
+
+	rxq->queue = ndp_open_rx_queue(nfb, rx_queue_id);
+	if (rxq->queue == NULL)
+		return -EINVAL;
+
+	rxq->nfb = nfb;
+	rxq->rx_queue_id = rx_queue_id;
+	rxq->in_port = port_id;
+	rxq->mb_pool = mb_pool;
+	rxq->buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size -
+		RTE_PKTMBUF_HEADROOM);
+
+	rxq->rx_pkts = 0;
+	rxq->rx_bytes = 0;
+	rxq->err_pkts = 0;
+
+	return 0;
+}
+
+void
+nfb_eth_rx_queue_release(void *q)
+{
+	struct ndp_rx_queue *rxq = (struct ndp_rx_queue *)q;
+	if (rxq->queue != NULL) {
+		ndp_close_rx_queue(rxq->queue);
+		rte_free(rxq);
+		rxq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_rx.h b/drivers/net/nfb/nfb_rx.h
new file mode 100644
index 0000000..88a0307
--- /dev/null
+++ b/drivers/net/nfb/nfb_rx.h
@@ -0,0 +1,202 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_RX_H_
+#define _NFB_RX_H_
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+
+struct ndp_rx_queue {
+	struct nfb_device *nfb;	     /* nfb dev structure */
+	struct ndp_queue *queue;     /* rx queue */
+	uint16_t rx_queue_id;	     /* index */
+	uint8_t in_port;	     /* port */
+
+	struct rte_mempool *mb_pool; /* memory pool to allocate packets */
+	uint16_t buf_size;           /* mbuf size */
+
+	volatile uint64_t rx_pkts;   /* packets read */
+	volatile uint64_t rx_bytes;  /* bytes read */
+	volatile uint64_t err_pkts;  /* erroneous packets */
+};
+
+/**
+ * Initialize ndp_rx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param rx_queue_id
+ *   RX queue index.
+ * @param port_id
+ *   Device [external] port identifier.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ * @param[out] rxq
+ *   Pointer to ndp_rx_queue output structure
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_rx_queue_init(struct nfb_device *nfb,
+	uint16_t rx_queue_id,
+	uint16_t port_id,
+	struct rte_mempool *mb_pool,
+	struct ndp_rx_queue *rxq);
+
+/**
+ * DPDK callback to setup a RX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mb_pool
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_rx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t rx_queue_id,
+	uint16_t nb_rx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_rxconf *rx_conf __rte_unused,
+	struct rte_mempool *mb_pool);
+
+/**
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void
+nfb_eth_rx_queue_release(void *q);
+
+/**
+ * Start traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * Stop traffic on Rx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   RX queue index.
+ */
+int
+nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id);
+
+/**
+ * DPDK callback for RX.
+ *
+ * @param dpdk_rxq
+ *   Generic pointer to RX queue structure.
+ * @param[out] bufs
+ *   Array to store received packets.
+ * @param nb_pkts
+ *   Maximum number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully received (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t
+nfb_eth_ndp_rx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	struct ndp_rx_queue *ndp = queue;
+	uint16_t packet_size;
+	uint64_t num_bytes = 0;
+	uint16_t num_rx;
+	unsigned int i;
+
+	const uint16_t buf_size = ndp->buf_size;
+
+	struct rte_mbuf *mbuf;
+	struct ndp_packet packets[nb_pkts];
+
+	struct rte_mbuf *mbufs[nb_pkts];
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "RX invalid arguments!\n");
+		return 0;
+	}
+
+	/* returns either all or nothing */
+	i = rte_pktmbuf_alloc_bulk(ndp->mb_pool, mbufs, nb_pkts);
+	if (unlikely(i != 0))
+		return 0;
+
+	num_rx = ndp_rx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_rx != nb_pkts)) {
+		for (i = num_rx; i < nb_pkts; i++)
+			rte_pktmbuf_free(mbufs[i]);
+	}
+
+	nb_pkts = num_rx;
+
+	num_rx = 0;
+	/*
+	 * Reads the given number of packets from NDP queue given
+	 * by queue and copies the packet data into a newly allocated mbuf
+	 * to return.
+	 */
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = mbufs[i];
+
+		/* get the space available for data in the mbuf */
+		packet_size = packets[i].data_length;
+
+		if (likely(packet_size <= buf_size)) {
+			/* NDP packet will fit in one mbuf, go ahead and copy */
+			rte_memcpy(rte_pktmbuf_mtod(mbuf, void *),
+				packets[i].data, packet_size);
+
+			mbuf->data_len = (uint16_t)packet_size;
+
+			mbuf->pkt_len = packet_size;
+			mbuf->port = ndp->in_port;
+			bufs[num_rx++] = mbuf;
+			num_bytes += packet_size;
+		} else {
+			/*
+			 * NDP packet will not fit in one mbuf,
+			 * scattered mode is not enabled, drop packet
+			 */
+			rte_pktmbuf_free(mbuf);
+		}
+	}
+
+	ndp_rx_burst_put(ndp->queue);
+
+	ndp->rx_pkts += num_rx;
+	ndp->rx_bytes += num_bytes;
+	return num_rx;
+}
+
+#endif /* _NFB_RX_H_ */
diff --git a/drivers/net/nfb/nfb_rxmode.c b/drivers/net/nfb/nfb_rxmode.c
new file mode 100644
index 0000000..97bfcb2
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.c
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_rxmode.h"
+#include "nfb.h"
+
+void
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+	uint16_t i;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_PROMISCUOUS);
+	}
+}
+
+void
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+	uint16_t i;
+
+	internals->rx_filter_original = RXMAC_MAC_FILTER_TABLE;
+
+	/* if promisc is not enabled, do nothing */
+	if (!nfb_eth_promiscuous_get(dev))
+		return;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE);
+	}
+}
+
+int
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_PROMISCUOUS);
+}
+
+void
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+	}
+}
+
+void
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	uint16_t i;
+
+	/* if multicast is not enabled do nothing */
+	if (!nfb_eth_allmulticast_get(dev))
+		return;
+
+	for (i = 0; i < internals->max_rxmac; ++i) {
+		nc_rxmac_mac_filter_enable(internals->rxmac[i],
+			internals->rx_filter_original);
+	}
+}
+
+int
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = (struct pmd_internals *)
+		dev->data->dev_private;
+
+	struct nc_rxmac_status status;
+	status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS;
+	nc_rxmac_read_status(internals->rxmac[0], &status);
+
+	return (status.mac_filter == RXMAC_MAC_FILTER_TABLE_BCAST_MCAST);
+}
diff --git a/drivers/net/nfb/nfb_rxmode.h b/drivers/net/nfb/nfb_rxmode.h
new file mode 100644
index 0000000..4c59651
--- /dev/null
+++ b/drivers/net/nfb/nfb_rxmode.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_RXMODE_H_
+#define _NFB_RXMODE_H_
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_ethdev.h>
+
+/**
+ * Getter for promiscuous mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int
+nfb_eth_promiscuous_get(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to enable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_promiscuous_enable(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to disable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_promiscuous_disable(struct rte_eth_dev *dev);
+
+/**
+ * Getter for allmulticast mode
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @return 1 if enabled 0 otherwise
+ */
+int
+nfb_eth_allmulticast_get(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to enable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_allmulticast_enable(struct rte_eth_dev *dev);
+
+/**
+ * DPDK callback to disable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_allmulticast_disable(struct rte_eth_dev *dev);
+
+#endif /* _NFB_RXMODE_H_ */
diff --git a/drivers/net/nfb/nfb_stats.c b/drivers/net/nfb/nfb_stats.c
new file mode 100644
index 0000000..5aa4d00
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.c
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_stats.h"
+#include "nfb.h"
+
+int
+nfb_eth_stats_get(struct rte_eth_dev *dev,
+	struct rte_eth_stats *stats)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+	uint64_t rx_total = 0;
+	uint64_t tx_total = 0;
+	uint64_t tx_err_total = 0;
+	uint64_t rx_total_bytes = 0;
+	uint64_t tx_total_bytes = 0;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_ipackets[i] = rx_queue[i].rx_pkts;
+			stats->q_ibytes[i] = rx_queue[i].rx_bytes;
+		}
+		rx_total += rx_queue[i].rx_pkts;
+		rx_total_bytes += rx_queue[i].rx_bytes;
+	}
+
+	for (i = 0; i < nb_tx; i++) {
+		if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+			stats->q_opackets[i] = tx_queue[i].tx_pkts;
+			stats->q_obytes[i] = tx_queue[i].tx_bytes;
+		}
+		tx_total += tx_queue[i].tx_pkts;
+		tx_total_bytes += tx_queue[i].tx_bytes;
+		tx_err_total += tx_queue[i].err_pkts;
+	}
+
+	stats->ipackets = rx_total;
+	stats->opackets = tx_total;
+	stats->ibytes = rx_total_bytes;
+	stats->obytes = tx_total_bytes;
+	stats->oerrors = tx_err_total;
+	return 0;
+}
+
+void
+nfb_eth_stats_reset(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	uint16_t nb_rx = dev->data->nb_rx_queues;
+	uint16_t nb_tx = dev->data->nb_tx_queues;
+
+	struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **)
+		dev->data->rx_queues);
+	struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **)
+		dev->data->tx_queues);
+
+	for (i = 0; i < nb_rx; i++) {
+		rx_queue[i].rx_pkts = 0;
+		rx_queue[i].rx_bytes = 0;
+		rx_queue[i].err_pkts = 0;
+	}
+	for (i = 0; i < nb_tx; i++) {
+		tx_queue[i].tx_pkts = 0;
+		tx_queue[i].tx_bytes = 0;
+		tx_queue[i].err_pkts = 0;
+	}
+}
diff --git a/drivers/net/nfb/nfb_stats.h b/drivers/net/nfb/nfb_stats.h
new file mode 100644
index 0000000..c7d8c8c
--- /dev/null
+++ b/drivers/net/nfb/nfb_stats.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_STATS_H_
+#define _NFB_STATS_H_
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_ethdev.h>
+
+/**
+ * DPDK callback to get device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param[out] stats
+ *   Stats structure output buffer.
+ *
+ * @return
+ *   0 on success and stats is filled, negative errno value otherwise.
+ */
+int
+nfb_eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats);
+
+/**
+ * DPDK callback to clear device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+void
+nfb_eth_stats_reset(struct rte_eth_dev *dev);
+
+#endif /* _NFB_STATS_H_ */
diff --git a/drivers/net/nfb/nfb_tx.c b/drivers/net/nfb/nfb_tx.c
new file mode 100644
index 0000000..9b912fe
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.c
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#include "nfb_tx.h"
+#include "nfb.h"
+
+int
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+	int ret;
+
+	if (txq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "RX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_start(txq->queue);
+	if (ret != 0)
+		goto err;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
+int
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id)
+{
+	struct ndp_tx_queue *txq = dev->data->tx_queues[txq_id];
+	int ret;
+
+	if (txq->queue == NULL) {
+		RTE_LOG(ERR, PMD, "TX NDP queue is NULL!\n");
+		return -EINVAL;
+	}
+
+	ret = ndp_queue_stop(txq->queue);
+	if (ret != 0)
+		return -EINVAL;
+	dev->data->tx_queue_state[txq_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+int
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	int ret;
+	struct ndp_tx_queue *txq;
+
+	txq = rte_zmalloc_socket("ndp tx queue",
+		sizeof(struct ndp_tx_queue),
+		RTE_CACHE_LINE_SIZE, socket_id);
+
+	if (txq == NULL) {
+		RTE_LOG(ERR, PMD, "rte_zmalloc_socket() failed for tx queue id "
+			"%" PRIu16 "!\n", tx_queue_id);
+		return -ENOMEM;
+	}
+
+	ret = nfb_eth_tx_queue_init(internals->nfb,
+		tx_queue_id,
+		txq);
+
+	if (ret == 0)
+		dev->data->tx_queues[tx_queue_id] = txq;
+	else
+		rte_free(txq);
+
+	return ret;
+}
+
+int
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq)
+{
+	if (nfb == NULL)
+		return -EINVAL;
+
+	txq->queue = ndp_open_tx_queue(nfb, tx_queue_id);
+	if (txq->queue == NULL)
+		return -EINVAL;
+
+	txq->nfb = nfb;
+	txq->tx_queue_id = tx_queue_id;
+
+	txq->tx_pkts = 0;
+	txq->tx_bytes = 0;
+	txq->err_pkts = 0;
+
+	return 0;
+}
+
+void
+nfb_eth_tx_queue_release(void *q)
+{
+	struct ndp_tx_queue *txq = (struct ndp_tx_queue *)q;
+	if (txq->queue != NULL) {
+		ndp_close_tx_queue(txq->queue);
+		rte_free(txq);
+		txq->queue = NULL;
+	}
+}
diff --git a/drivers/net/nfb/nfb_tx.h b/drivers/net/nfb/nfb_tx.h
new file mode 100644
index 0000000..edf5ede
--- /dev/null
+++ b/drivers/net/nfb/nfb_tx.h
@@ -0,0 +1,193 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Cesnet
+ * Copyright(c) 2019 Netcope Technologies, a.s. <info@netcope.com>
+ * All rights reserved.
+ */
+
+#ifndef _NFB_TX_H_
+#define _NFB_TX_H_
+
+#include <nfb/nfb.h>
+#include <nfb/ndp.h>
+
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+
+struct ndp_tx_queue {
+	struct nfb_device *nfb;     /* nfb dev structure */
+	struct ndp_queue *queue;    /* tx queue */
+	uint16_t          tx_queue_id;       /* index */
+	volatile uint64_t tx_pkts;  /* packets transmitted */
+	volatile uint64_t tx_bytes; /* bytes transmitted */
+	volatile uint64_t err_pkts; /* erroneous packets */
+};
+
+/**
+ * DPDK callback to setup a TX queue for use.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param[in] conf
+ *   Thresholds parameters.
+ * @param mp
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_setup(struct rte_eth_dev *dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id,
+	const struct rte_eth_txconf *tx_conf __rte_unused);
+
+/**
+ * Initialize ndp_tx_queue structure
+ *
+ * @param nfb
+ *   Pointer to nfb device structure.
+ * @param tx_queue_id
+ *   TX queue index.
+ * @param[out] txq
+ *   Pointer to ndp_tx_queue output structure
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_init(struct nfb_device *nfb,
+	uint16_t tx_queue_id,
+	struct ndp_tx_queue *txq);
+
+/**
+ * DPDK callback to release a RX queue.
+ *
+ * @param dpdk_rxq
+ *   Generic RX queue pointer.
+ */
+void
+nfb_eth_tx_queue_release(void *q);
+
+/**
+ * Start traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * Stop traffic on Tx queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param txq_id
+ *   TX queue index.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+nfb_eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t txq_id);
+
+/**
+ * DPDK callback for TX.
+ *
+ * @param dpdk_txq
+ *   Generic pointer to TX queue structure.
+ * @param bufs
+ *   Packets to transmit.
+ * @param nb_pkts
+ *   Number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully transmitted (<= nb_pkts).
+ */
+static __rte_always_inline uint16_t
+nfb_eth_ndp_tx(void *queue,
+	struct rte_mbuf **bufs,
+	uint16_t nb_pkts)
+{
+	int i;
+	struct rte_mbuf *mbuf;
+	struct ndp_tx_queue *ndp = queue;
+	uint16_t num_tx = 0;
+	uint64_t num_bytes = 0;
+
+	void *dst;
+	uint32_t pkt_len;
+	uint8_t mbuf_segs;
+
+	struct ndp_packet packets[nb_pkts];
+
+	if (unlikely(ndp->queue == NULL || nb_pkts == 0)) {
+		RTE_LOG(ERR, PMD, "TX invalid arguments!\n");
+		return 0;
+	}
+
+	for (i = 0; i < nb_pkts; i++) {
+		packets[i].data_length = bufs[i]->pkt_len;
+		packets[i].header_length = 0;
+	}
+
+	num_tx = ndp_tx_burst_get(ndp->queue, packets, nb_pkts);
+
+	if (unlikely(num_tx != nb_pkts))
+		return 0;
+
+	for (i = 0; i < nb_pkts; ++i) {
+		mbuf = bufs[i];
+
+		pkt_len = mbuf->pkt_len;
+		mbuf_segs = mbuf->nb_segs;
+
+		num_bytes += pkt_len;
+		if (mbuf_segs == 1) {
+			/*
+			 * non-scattered packet,
+			 * transmit from one mbuf
+			 */
+			rte_memcpy(packets[i].data,
+				rte_pktmbuf_mtod(mbuf, const void *),
+				pkt_len);
+		} else {
+			/* scattered packet, transmit from more mbufs */
+			struct rte_mbuf *m = mbuf;
+			while (m) {
+				dst = packets[i].data;
+
+				rte_memcpy(dst,
+					rte_pktmbuf_mtod(m,
+					const void *),
+					m->data_len);
+				dst = ((uint8_t *)(dst)) +
+					m->data_len;
+				m = m->next;
+			}
+		}
+
+		rte_pktmbuf_free(mbuf);
+	}
+
+	ndp_tx_burst_flush(ndp->queue);
+
+	ndp->tx_pkts += num_tx;
+	ndp->err_pkts += nb_pkts - num_tx;
+	ndp->tx_bytes += num_bytes;
+	return num_tx;
+}
+
+#endif /* _NFB_TX_H_ */
diff --git a/drivers/net/nfb/rte_pmd_nfb_version.map b/drivers/net/nfb/rte_pmd_nfb_version.map
new file mode 100644
index 0000000..fc8c95e
--- /dev/null
+++ b/drivers/net/nfb/rte_pmd_nfb_version.map
@@ -0,0 +1,4 @@
+DPDK_19.05 {
+
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 262132f..381dc7f 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -196,6 +196,8 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC)      += -lrte_pmd_softnic
 endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_SFC_EFX_PMD)    += -lrte_pmd_sfc_efx
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2 -lsze2
+_LDLIBS-$(CONFIG_RTE_LIBRTE_NFB_PMD)        += -lrte_pmd_nfb
+_LDLIBS-$(CONFIG_RTE_LIBRTE_NFB_PMD)        +=  $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --libs netcope-common)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_TAP)        += -lrte_pmd_tap
 _LDLIBS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += -lrte_pmd_thunderx_nicvf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD) += -lrte_pmd_vdev_netvsc
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v7] net/nfb: new netcope driver
  2019-04-07 15:03   ` [dpdk-dev] [PATCH v7] " Rastislav Cernay
  2019-04-07 15:03     ` Rastislav Cernay
@ 2019-04-12 12:15     ` Ferruh Yigit
  2019-04-12 12:15       ` Ferruh Yigit
  2019-04-12 12:16     ` Ferruh Yigit
  2 siblings, 1 reply; 50+ messages in thread
From: Ferruh Yigit @ 2019-04-12 12:15 UTC (permalink / raw)
  To: Rastislav Cernay, dev

On 4/7/2019 4:03 PM, Rastislav Cernay wrote:
> From: Rastislav Cernay <cernay@netcope.com>
> 
> Added new net driver for Netcope nfb cards
> 
> Signed-off-by: Rastislav Cernay <cernay@netcope.com>

<...>

> +CFLAGS += -O3
> +CFLAGS += $(WERROR_FLAGS)
> +CFLAGS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --cflags netcope-common)
> +LDLIBS += -lnfb
> +LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool
> +LDLIBS += -lrte_ethdev -lrte_net
> +LDLIBS += -lrte_bus_pci
> +LDLIBS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --libs netcope-common)

With this pkg-config line, isn't it above "LDLIBS += -lnfb" become redundant,
can we remove that line?
If so please send a seperate patch to remove it, I can squash into original one.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v7] net/nfb: new netcope driver
  2019-04-12 12:15     ` Ferruh Yigit
@ 2019-04-12 12:15       ` Ferruh Yigit
  0 siblings, 0 replies; 50+ messages in thread
From: Ferruh Yigit @ 2019-04-12 12:15 UTC (permalink / raw)
  To: Rastislav Cernay, dev

On 4/7/2019 4:03 PM, Rastislav Cernay wrote:
> From: Rastislav Cernay <cernay@netcope.com>
> 
> Added new net driver for Netcope nfb cards
> 
> Signed-off-by: Rastislav Cernay <cernay@netcope.com>

<...>

> +CFLAGS += -O3
> +CFLAGS += $(WERROR_FLAGS)
> +CFLAGS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --cflags netcope-common)
> +LDLIBS += -lnfb
> +LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool
> +LDLIBS += -lrte_ethdev -lrte_net
> +LDLIBS += -lrte_bus_pci
> +LDLIBS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --libs netcope-common)

With this pkg-config line, isn't it above "LDLIBS += -lnfb" become redundant,
can we remove that line?
If so please send a seperate patch to remove it, I can squash into original one.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v7] net/nfb: new netcope driver
  2019-04-07 15:03   ` [dpdk-dev] [PATCH v7] " Rastislav Cernay
  2019-04-07 15:03     ` Rastislav Cernay
  2019-04-12 12:15     ` Ferruh Yigit
@ 2019-04-12 12:16     ` Ferruh Yigit
  2019-04-12 12:16       ` Ferruh Yigit
  2 siblings, 1 reply; 50+ messages in thread
From: Ferruh Yigit @ 2019-04-12 12:16 UTC (permalink / raw)
  To: Rastislav Cernay, dev

On 4/7/2019 4:03 PM, Rastislav Cernay wrote:
> From: Rastislav Cernay <cernay@netcope.com>
> 
> Added new net driver for Netcope nfb cards
> 
> Signed-off-by: Rastislav Cernay <cernay@netcope.com>

Hi Rastislav,

Welcome to DPDK!


Applied to dpdk-next-net/master, thanks.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH v7] net/nfb: new netcope driver
  2019-04-12 12:16     ` Ferruh Yigit
@ 2019-04-12 12:16       ` Ferruh Yigit
  0 siblings, 0 replies; 50+ messages in thread
From: Ferruh Yigit @ 2019-04-12 12:16 UTC (permalink / raw)
  To: Rastislav Cernay, dev

On 4/7/2019 4:03 PM, Rastislav Cernay wrote:
> From: Rastislav Cernay <cernay@netcope.com>
> 
> Added new net driver for Netcope nfb cards
> 
> Signed-off-by: Rastislav Cernay <cernay@netcope.com>

Hi Rastislav,

Welcome to DPDK!


Applied to dpdk-next-net/master, thanks.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [dpdk-dev] [PATCH] net/nfb: remove redundant linking
  2019-02-26 12:57 ` [dpdk-dev] [PATCH] net/nfb: new netcope driver Rastislav Cernay
                     ` (7 preceding siblings ...)
  2019-04-07 15:03   ` [dpdk-dev] [PATCH v7] " Rastislav Cernay
@ 2019-04-12 14:37   ` Rastislav Cernay
  2019-04-12 14:37     ` Rastislav Cernay
  2019-04-12 15:02     ` Ferruh Yigit
  8 siblings, 2 replies; 50+ messages in thread
From: Rastislav Cernay @ 2019-04-12 14:37 UTC (permalink / raw)
  To: dev; +Cc: ferruh.yigit, Rastislav Cernay

From: Rastislav Cernay <cernay@netcope.com>

Signed-off-by: Rastislav Cernay <cernay@netcope.com>
---
 drivers/net/nfb/Makefile | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/net/nfb/Makefile b/drivers/net/nfb/Makefile
index 21b09b3..a84b423 100644
--- a/drivers/net/nfb/Makefile
+++ b/drivers/net/nfb/Makefile
@@ -16,7 +16,6 @@ INCLUDES :=-I$(SRCDIR)
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 CFLAGS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --cflags netcope-common)
-LDLIBS += -lnfb
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool
 LDLIBS += -lrte_ethdev -lrte_net
 LDLIBS += -lrte_bus_pci
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [dpdk-dev] [PATCH] net/nfb: remove redundant linking
  2019-04-12 14:37   ` [dpdk-dev] [PATCH] net/nfb: remove redundant linking Rastislav Cernay
@ 2019-04-12 14:37     ` Rastislav Cernay
  2019-04-12 15:02     ` Ferruh Yigit
  1 sibling, 0 replies; 50+ messages in thread
From: Rastislav Cernay @ 2019-04-12 14:37 UTC (permalink / raw)
  To: dev; +Cc: ferruh.yigit, Rastislav Cernay

From: Rastislav Cernay <cernay@netcope.com>

Signed-off-by: Rastislav Cernay <cernay@netcope.com>
---
 drivers/net/nfb/Makefile | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/net/nfb/Makefile b/drivers/net/nfb/Makefile
index 21b09b3..a84b423 100644
--- a/drivers/net/nfb/Makefile
+++ b/drivers/net/nfb/Makefile
@@ -16,7 +16,6 @@ INCLUDES :=-I$(SRCDIR)
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 CFLAGS += $(shell command -v pkg-config > /dev/null 2>&1 && pkg-config --cflags netcope-common)
-LDLIBS += -lnfb
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool
 LDLIBS += -lrte_ethdev -lrte_net
 LDLIBS += -lrte_bus_pci
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH] net/nfb: remove redundant linking
  2019-04-12 14:37   ` [dpdk-dev] [PATCH] net/nfb: remove redundant linking Rastislav Cernay
  2019-04-12 14:37     ` Rastislav Cernay
@ 2019-04-12 15:02     ` Ferruh Yigit
  2019-04-12 15:02       ` Ferruh Yigit
  1 sibling, 1 reply; 50+ messages in thread
From: Ferruh Yigit @ 2019-04-12 15:02 UTC (permalink / raw)
  To: Rastislav Cernay, dev

On 4/12/2019 3:37 PM, Rastislav Cernay wrote:
> From: Rastislav Cernay <cernay@netcope.com>
> 
> Signed-off-by: Rastislav Cernay <cernay@netcope.com>

Squashed into relevant commit in next-net, thanks.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [dpdk-dev] [PATCH] net/nfb: remove redundant linking
  2019-04-12 15:02     ` Ferruh Yigit
@ 2019-04-12 15:02       ` Ferruh Yigit
  0 siblings, 0 replies; 50+ messages in thread
From: Ferruh Yigit @ 2019-04-12 15:02 UTC (permalink / raw)
  To: Rastislav Cernay, dev

On 4/12/2019 3:37 PM, Rastislav Cernay wrote:
> From: Rastislav Cernay <cernay@netcope.com>
> 
> Signed-off-by: Rastislav Cernay <cernay@netcope.com>

Squashed into relevant commit in next-net, thanks.

^ permalink raw reply	[flat|nested] 50+ messages in thread

end of thread, other threads:[~2019-04-12 15:02 UTC | newest]

Thread overview: 50+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-26 12:57 [dpdk-dev] [PATCH] net/nfb: new Netcope driver Rastislav Cernay
2019-02-26 12:57 ` [dpdk-dev] [PATCH] net/nfb: new netcope driver Rastislav Cernay
2019-02-26 14:20   ` Rami Rosen
2019-02-26 16:33     ` Rastislav Černay
2019-02-26 15:46   ` Stephen Hemminger
2019-02-27 11:43   ` [dpdk-dev] [PATCH v2] net/nfb: new Netcope driver Rastislav Cernay
2019-02-27 15:28     ` Ferruh Yigit
2019-03-01 14:37   ` [dpdk-dev] [PATCH v3] net/nfb: new netcope driver Rastislav Cernay
2019-03-01 18:47     ` Stephen Hemminger
2019-03-04 14:07       ` Rastislav Černay
2019-03-01 18:50     ` Stephen Hemminger
2019-03-04  9:53       ` David Marchand
2019-03-04 11:34     ` David Marchand
2019-03-04 14:33       ` Rastislav Černay
2019-03-04 12:35         ` David Marchand
2019-03-04 12:48           ` David Marchand
2019-03-04 15:15             ` Rastislav Černay
2019-03-05 20:31     ` Rami Rosen
2019-03-05 22:41     ` Luca Boccassi
2019-03-06 14:51       ` Rastislav Černay
2019-03-06 13:25         ` Luca Boccassi
2019-03-07 13:24   ` [dpdk-dev] [PATCH v4] " Rastislav Cernay
2019-03-07 13:46     ` Luca Boccassi
2019-03-07 14:14       ` Jan Remeš
2019-03-22 12:12   ` [dpdk-dev] [PATCH v5] " Rastislav Cernay
2019-03-22 12:12     ` Rastislav Cernay
2019-03-28 16:01     ` Ferruh Yigit
2019-03-28 16:01       ` Ferruh Yigit
2019-04-01 14:55       ` Rastislav Černay
2019-04-01 14:22         ` Ferruh Yigit
2019-04-01 14:22           ` Ferruh Yigit
2019-04-02 16:05           ` Rastislav Černay
2019-04-02 16:05             ` Rastislav Černay
2019-04-01 14:23         ` Luca Boccassi
2019-04-01 14:23           ` Luca Boccassi
2019-04-01 14:55         ` Rastislav Černay
2019-04-04  9:05   ` [dpdk-dev] [PATCH v6] " Rastislav Cernay
2019-04-04  9:05     ` Rastislav Cernay
2019-04-05  0:08     ` Ferruh Yigit
2019-04-05  0:08       ` Ferruh Yigit
2019-04-07 15:03   ` [dpdk-dev] [PATCH v7] " Rastislav Cernay
2019-04-07 15:03     ` Rastislav Cernay
2019-04-12 12:15     ` Ferruh Yigit
2019-04-12 12:15       ` Ferruh Yigit
2019-04-12 12:16     ` Ferruh Yigit
2019-04-12 12:16       ` Ferruh Yigit
2019-04-12 14:37   ` [dpdk-dev] [PATCH] net/nfb: remove redundant linking Rastislav Cernay
2019-04-12 14:37     ` Rastislav Cernay
2019-04-12 15:02     ` Ferruh Yigit
2019-04-12 15:02       ` Ferruh Yigit

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).