All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] Virtual PMD using sze2 layer for COMBO cards
@ 2015-06-19  8:24 Matej Vido
  2015-06-19  8:25 ` [PATCH 1/2] szedata2: new poll mode driver Matej Vido
                   ` (2 more replies)
  0 siblings, 3 replies; 36+ messages in thread
From: Matej Vido @ 2015-06-19  8:24 UTC (permalink / raw)
  To: dev

This is virtual PMD which communicates with COMBO-80G and COMBO-100G
cards through sze2 layer. Communication with COMBO card is managed
through interface provided by libsze2 library and kernel modules
(combov3, szedata2_cv3).

To compile and use PMD, it is necessary to have libsze2 library installed and 
kernel modules (combov3, szedata2_cv3) loaded.
Therefore in default configuration PMD compilation is disabled. To compile
szedata2 PMD, it is necessary to enable CONFIG_RTE_LIBRTE_PMD_SZEDATA2=y.

We have done performance measurement. Results are available in pdf file:
https://www.liberouter.org/wp-content/uploads/2015/06/pmd_szedata2_dpdk_measurement.pdf

Measurement was not done with final version of firmware. Performance will
be increased soon with new firmware version.

Matej Vido (2):
  szedata2: new poll mode driver
  doc: added documentation for szedata2 PMD

 config/common_bsdapp                              |    5 +
 config/common_linuxapp                            |    5 +
 doc/guides/nics/index.rst                         |    1 +
 doc/guides/nics/szedata2.rst                      |  105 ++
 doc/guides/prog_guide/source_org.rst              |    1 +
 drivers/net/Makefile                              |    1 +
 drivers/net/szedata2/Makefile                     |   62 ++
 drivers/net/szedata2/rte_eth_szedata2.c           | 1120 +++++++++++++++++++++
 drivers/net/szedata2/rte_eth_szedata2.h           |   96 ++
 drivers/net/szedata2/rte_pmd_szedata2_version.map |    4 +
 mk/rte.app.mk                                     |    3 +
 11 files changed, 1403 insertions(+)
 create mode 100644 doc/guides/nics/szedata2.rst
 create mode 100644 drivers/net/szedata2/Makefile
 create mode 100644 drivers/net/szedata2/rte_eth_szedata2.c
 create mode 100644 drivers/net/szedata2/rte_eth_szedata2.h
 create mode 100644 drivers/net/szedata2/rte_pmd_szedata2_version.map

-- 
Matej Vido
Software Developer
CESNET, a. l. e.

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

* [PATCH 1/2] szedata2: new poll mode driver
  2015-06-19  8:24 [PATCH 0/2] Virtual PMD using sze2 layer for COMBO cards Matej Vido
@ 2015-06-19  8:25 ` Matej Vido
  2016-03-21 17:45   ` Stephen Hemminger
  2015-06-19  8:25 ` [PATCH 2/2] doc: added documentation for szedata2 PMD Matej Vido
  2015-09-18  8:32 ` [PATCH v2 0/5] Virtual PMD using sze2 layer for COMBO cards Matej Vido
  2 siblings, 1 reply; 36+ messages in thread
From: Matej Vido @ 2015-06-19  8:25 UTC (permalink / raw)
  To: dev

Added virtual PMD which communicates with COMBO cards through sze2
layer using libsze2 library.

Signed-off-by: Matej Vido <vido@cesnet.cz>
---
 config/common_bsdapp                              |    5 +
 config/common_linuxapp                            |    5 +
 drivers/net/Makefile                              |    1 +
 drivers/net/szedata2/Makefile                     |   62 ++
 drivers/net/szedata2/rte_eth_szedata2.c           | 1120 +++++++++++++++++++++
 drivers/net/szedata2/rte_eth_szedata2.h           |   96 ++
 drivers/net/szedata2/rte_pmd_szedata2_version.map |    4 +
 mk/rte.app.mk                                     |    3 +
 8 files changed, 1296 insertions(+)
 create mode 100644 drivers/net/szedata2/Makefile
 create mode 100644 drivers/net/szedata2/rte_eth_szedata2.c
 create mode 100644 drivers/net/szedata2/rte_eth_szedata2.h
 create mode 100644 drivers/net/szedata2/rte_pmd_szedata2_version.map

diff --git a/config/common_bsdapp b/config/common_bsdapp
index 0b169c8..d5f5970 100644
--- a/config/common_bsdapp
+++ b/config/common_bsdapp
@@ -249,6 +249,11 @@ CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
 CONFIG_RTE_LIBRTE_PMD_PCAP=y
 
 #
+# Compile software PMD backed by SZEDATA2 device
+#
+CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
+
+#
 # Compile link bonding PMD library
 #
 CONFIG_RTE_LIBRTE_PMD_BOND=y
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 5deb55a..3bec728 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -246,6 +246,11 @@ CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
 CONFIG_RTE_LIBRTE_PMD_PCAP=n
 
 #
+# Compile software PMD backed by SZEDATA2 device
+#
+CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
+
+#
 # Compile link bonding PMD library
 #
 CONFIG_RTE_LIBRTE_PMD_BOND=y
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 1e6648a..3312b13 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -45,6 +45,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_RING) += ring
 DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio
 DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += vmxnet3
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += xenvirt
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += szedata2
 
 include $(RTE_SDK)/mk/rte.sharelib.mk
 include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/drivers/net/szedata2/Makefile b/drivers/net/szedata2/Makefile
new file mode 100644
index 0000000..c3c42e5
--- /dev/null
+++ b/drivers/net/szedata2/Makefile
@@ -0,0 +1,62 @@
+#   BSD LICENSE
+#
+#   Copyright (c) 2015 CESNET
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of CESNET nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_szedata2.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+EXPORT_MAP := rte_pmd_szedata2_version.map
+
+LIBABIVER := 1
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += rte_eth_szedata2.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += lib/librte_malloc
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += lib/librte_kvargs
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/szedata2/rte_eth_szedata2.c b/drivers/net/szedata2/rte_eth_szedata2.c
new file mode 100644
index 0000000..cb3b2a2
--- /dev/null
+++ b/drivers/net/szedata2/rte_eth_szedata2.c
@@ -0,0 +1,1120 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (c) 2015 CESNET
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of CESNET nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+
+#include <libsze2.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_kvargs.h>
+#include <rte_dev.h>
+
+#include "rte_eth_szedata2.h"
+
+#define RTE_ETH_SZEDATA2_DEV_PATH_ARG "dev_path"
+#define RTE_ETH_SZEDATA2_RX_IFACES_ARG "rx_ifaces"
+#define RTE_ETH_SZEDATA2_TX_IFACES_ARG "tx_ifaces"
+
+#define RTE_ETH_SZEDATA2_MAX_RX_QUEUES 32
+#define RTE_ETH_SZEDATA2_MAX_TX_QUEUES 32
+#define RTE_ETH_SZEDATA2_TX_LOCK_SIZE 33554432 /**< 32*1024*1024 */
+
+/**
+ * size of szedata2_packet header with alignment
+ */
+#define RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED 8
+
+struct szedata2_rx_queue {
+	struct szedata * sze;
+	uint8_t rx_channel;
+	uint8_t in_port;
+	struct rte_mempool *mb_pool;
+	volatile uint64_t rx_pkts;
+	volatile uint64_t rx_bytes;
+	volatile uint64_t err_pkts;
+};
+
+struct szedata2_tx_queue {
+	struct szedata * sze;
+	uint8_t tx_channel;
+	volatile uint64_t tx_pkts;
+	volatile uint64_t err_pkts;
+	volatile uint64_t tx_bytes;
+};
+
+struct rxtx_szedata2 {
+	uint32_t num_of_rx;
+	uint32_t num_of_tx;
+	uint32_t sze_rx_mask_req;
+	uint32_t sze_tx_mask_req;
+	char * sze_dev;
+};
+
+struct pmd_internals {
+	struct szedata2_rx_queue rx_queue[RTE_ETH_SZEDATA2_MAX_RX_QUEUES];
+	struct szedata2_tx_queue tx_queue[RTE_ETH_SZEDATA2_MAX_TX_QUEUES];
+	unsigned nb_rx_queues;
+	unsigned nb_tx_queues;
+	uint32_t num_of_rx;
+	uint32_t num_of_tx;
+	uint32_t sze_rx_req;
+	uint32_t sze_tx_req;
+	int if_index;
+	char * sze_dev;
+};
+
+static const char *valid_arguments[] = {
+	RTE_ETH_SZEDATA2_DEV_PATH_ARG,
+	RTE_ETH_SZEDATA2_RX_IFACES_ARG,
+	RTE_ETH_SZEDATA2_TX_IFACES_ARG,
+	NULL
+};
+
+static struct ether_addr eth_addr = {
+	.addr_bytes = { 0, 0, 0, 0x1, 0x2, 0x3 }
+};
+static const char *drivername = "SZEdata2 PMD";
+static struct rte_eth_link pmd_link = {
+		.link_speed = ETH_LINK_SPEED_10G,
+		.link_duplex = ETH_LINK_FULL_DUPLEX,
+		.link_status = 0
+};
+
+
+static uint32_t
+count_set_bits(uint32_t num)
+{
+	num = num - ((num >> 1) & 0x55555555); /* reuse input as temporary */
+	num = (num & 0x33333333) + ((num >> 2) & 0x33333333);        /* temp */
+	return (((num + (num >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; /* count */
+}
+
+static uint16_t
+eth_szedata2_rx(void *queue,
+		struct rte_mbuf **bufs,
+		uint16_t nb_pkts)
+{
+	unsigned int i;
+	struct rte_mbuf *mbuf;
+	struct szedata2_rx_queue *sze_q = queue;
+	struct rte_pktmbuf_pool_private *mbp_priv;
+	uint16_t num_rx = 0;
+	uint16_t buf_size;
+	uint16_t sg_size;
+	uint16_t hw_size;
+	uint16_t packet_size;
+	uint64_t num_bytes = 0;
+	struct szedata * sze = sze_q->sze;
+	uint8_t * header_ptr = NULL; /* header of packet */
+	uint8_t * packet_ptr1 = NULL;
+	uint8_t * packet_ptr2 = NULL;
+	uint16_t packet_len1 = 0;
+	uint16_t packet_len2 = 0;
+	uint16_t hw_data_align;
+
+	if (unlikely(sze_q->sze == NULL || nb_pkts == 0)) {
+		return 0;
+	}
+
+	/*
+	 * Reads the given number of packets from szedata2 channel given by queue
+	 * and copies the packet data into a newly allocated mbuf to return.
+	 */
+	for (i = 0; i < nb_pkts; i++) {
+		/* get the next sze packet */
+		if (sze->ct_rx_lck != NULL && !sze->ct_rx_rem_bytes &&
+				sze->ct_rx_lck->next == NULL) {
+			/* unlock old data */
+			szedata_rx_unlock_data(sze_q->sze, sze->ct_rx_lck_orig);
+			sze->ct_rx_lck_orig = NULL;
+			sze->ct_rx_lck = NULL;
+		}
+
+		if (!sze->ct_rx_rem_bytes && sze->ct_rx_lck_orig == NULL) {
+			/* nothing to read, lock new data */
+			sze->ct_rx_lck_orig = sze->ct_rx_lck =
+				szedata_rx_lock_data(sze_q->sze, ~0U);
+
+			if (sze->ct_rx_lck == NULL) {
+				/* nothing to lock */
+				break;
+			}
+
+			sze->ct_rx_cur_ptr = sze->ct_rx_lck->start;
+			sze->ct_rx_rem_bytes = sze->ct_rx_lck->len;
+
+			if (!sze->ct_rx_rem_bytes) {
+				break;
+			}
+		}
+
+		if (sze->ct_rx_rem_bytes < RTE_SZE2_PACKET_HEADER_SIZE) {
+			/* cut in header - copy parts of header to merge buffer */
+			if (sze->ct_rx_lck->next == NULL) {
+				break;
+			}
+
+			/* copy first part of header */
+			rte_memcpy(sze->ct_rx_buffer, sze->ct_rx_cur_ptr,
+					sze->ct_rx_rem_bytes);
+
+			/* copy second part of header */
+			sze->ct_rx_lck = sze->ct_rx_lck->next;
+			sze->ct_rx_cur_ptr = sze->ct_rx_lck->start;
+			rte_memcpy(sze->ct_rx_buffer + sze->ct_rx_rem_bytes,
+					sze->ct_rx_cur_ptr,
+					RTE_SZE2_PACKET_HEADER_SIZE - sze->ct_rx_rem_bytes);
+
+			sze->ct_rx_cur_ptr += RTE_SZE2_PACKET_HEADER_SIZE -
+				sze->ct_rx_rem_bytes;
+			sze->ct_rx_rem_bytes = sze->ct_rx_lck->len -
+				RTE_SZE2_PACKET_HEADER_SIZE + sze->ct_rx_rem_bytes;
+
+			header_ptr = (uint8_t *) sze->ct_rx_buffer;
+		} else {
+			/* not cut */
+			header_ptr = (uint8_t *) sze->ct_rx_cur_ptr;
+			sze->ct_rx_cur_ptr += RTE_SZE2_PACKET_HEADER_SIZE;
+			sze->ct_rx_rem_bytes -= RTE_SZE2_PACKET_HEADER_SIZE;
+		}
+
+		sg_size = le16toh(*((uint16_t *)header_ptr));
+		hw_size = le16toh(*(((uint16_t *)header_ptr)+1));
+		packet_size = sg_size -
+			RTE_SZE2_ALIGN8(RTE_SZE2_PACKET_HEADER_SIZE + hw_size);
+
+
+		/* checks if packet all right */
+		if (!sg_size) {
+			errx(5, "Zero segsize");
+		}
+
+		/* check sg_size and hwsize */
+		if (hw_size > sg_size - RTE_SZE2_PACKET_HEADER_SIZE) {
+			errx(10, "Hwsize bigger than expected. Segsize: %d, hwsize: %d",
+					sg_size, hw_size);
+		}
+
+		hw_data_align =
+			RTE_SZE2_ALIGN8((RTE_SZE2_PACKET_HEADER_SIZE + hw_size)) -
+			RTE_SZE2_PACKET_HEADER_SIZE;
+
+		if (sze->ct_rx_rem_bytes >=
+				(uint16_t)(sg_size - RTE_SZE2_PACKET_HEADER_SIZE)) {
+			/* no cut */
+			/* one packet ready - go to another */
+			packet_ptr1 = sze->ct_rx_cur_ptr + hw_data_align;
+			packet_len1 = packet_size;
+			packet_ptr2 = NULL;
+			packet_len2 = 0;
+
+			sze->ct_rx_cur_ptr += RTE_SZE2_ALIGN8(sg_size) -
+				RTE_SZE2_PACKET_HEADER_SIZE;
+			sze->ct_rx_rem_bytes -= RTE_SZE2_ALIGN8(sg_size) -
+				RTE_SZE2_PACKET_HEADER_SIZE;
+		} else {
+			/* cut in data */
+			if (sze->ct_rx_lck->next == NULL) {
+				errx(6, "Need \"next\" lock, but it is missing: %u",
+						sze->ct_rx_rem_bytes);
+			}
+
+			/* skip hw data */
+			if (sze->ct_rx_rem_bytes <= hw_data_align) {
+				uint16_t rem_size = hw_data_align - sze->ct_rx_rem_bytes;
+
+				/* MOVE to next lock */
+				sze->ct_rx_lck = sze->ct_rx_lck->next;
+				sze->ct_rx_cur_ptr =
+					(void *) (((uint8_t *)(sze->ct_rx_lck->start)) + rem_size);
+
+				packet_ptr1 = sze->ct_rx_cur_ptr;
+				packet_len1 = packet_size;
+				packet_ptr2 = NULL;
+				packet_len2 = 0;
+
+				sze->ct_rx_cur_ptr += RTE_SZE2_ALIGN8(packet_size);
+				sze->ct_rx_rem_bytes = sze->ct_rx_lck->len -
+					rem_size - RTE_SZE2_ALIGN8(packet_size);
+			} else {
+				/* get pointer and length from first part of data */
+				packet_ptr1 = sze->ct_rx_cur_ptr + hw_data_align;
+				packet_len1 = sze->ct_rx_rem_bytes - hw_data_align;
+
+				/* MOVE to next lock */
+				sze->ct_rx_lck = sze->ct_rx_lck->next;
+				sze->ct_rx_cur_ptr = sze->ct_rx_lck->start;
+
+				/* get pointer and length from second part of data */
+				packet_ptr2 = sze->ct_rx_cur_ptr;
+				packet_len2 = packet_size - packet_len1;
+
+				sze->ct_rx_cur_ptr += RTE_SZE2_ALIGN8(packet_size) -
+					packet_len1;
+				sze->ct_rx_rem_bytes = sze->ct_rx_lck->len -
+					(RTE_SZE2_ALIGN8(packet_size) - packet_len1);
+			}
+		}
+
+		if (unlikely(packet_ptr1 == NULL)) {
+			break;
+		} else {
+			mbuf = rte_pktmbuf_alloc(sze_q->mb_pool);
+		}
+
+		if (unlikely(mbuf == NULL)) {
+			break;
+		}
+
+		/* get the space available for data in the mbuf */
+		mbp_priv = rte_mempool_get_priv(sze_q->mb_pool);
+		buf_size = (uint16_t) (mbp_priv->mbuf_data_room_size -
+				RTE_PKTMBUF_HEADROOM);
+
+		if (packet_size <= buf_size) {
+			/* sze packet will fit in the mbuf, go ahead and copy */
+			rte_memcpy(rte_pktmbuf_mtod(mbuf, void *),
+					packet_ptr1, packet_len1);
+			if (packet_ptr2 != NULL) {
+				rte_memcpy((void *)(rte_pktmbuf_mtod(mbuf, uint8_t *) +
+							packet_len1), packet_ptr2, packet_len2);
+			}
+			mbuf->data_len = (uint16_t)packet_size;
+			mbuf->pkt_len = mbuf->data_len;
+			mbuf->port = sze_q->in_port;
+			bufs[num_rx] = mbuf;
+			num_rx++;
+			num_bytes += packet_size;
+		} else {
+			/* sze packet will not fit in the mbuf, drop it */
+			RTE_LOG(ERR, PMD,
+					"SZE segment %d bytes will not fit in mbuf (%d bytes)\n",
+					packet_size, buf_size);
+			rte_pktmbuf_free(mbuf);
+		}
+	}
+
+	sze_q->rx_pkts += num_rx;
+	sze_q->rx_bytes += num_bytes;
+	return num_rx;
+}
+
+static uint16_t
+eth_szedata2_tx(void *queue,
+		struct rte_mbuf **bufs,
+		uint16_t nb_pkts)
+{
+	unsigned i;
+	struct rte_mbuf *mbuf;
+	struct szedata2_tx_queue *sze_q = queue;
+	uint16_t num_tx = 0;
+	uint64_t num_bytes = 0;
+
+	const struct szedata_lock *lck;
+	uint32_t lock_size;
+	uint32_t lock_size2;
+	void *dst;
+	uint32_t pkt_len;
+	uint32_t hwpkt_len;
+	uint32_t unlock_size;
+	uint32_t rem_len;
+	uint32_t write_len;
+
+	if (sze_q->sze == NULL || nb_pkts == 0)
+		return 0;
+
+
+	for (i = 0; i < nb_pkts; i++) {
+lock_again:
+		unlock_size = 0;
+		lck = szedata_tx_lock_data(sze_q->sze, RTE_ETH_SZEDATA2_TX_LOCK_SIZE,
+				sze_q->tx_channel);
+		if (lck == NULL) {
+			goto lock_again;
+		}
+
+		dst = lck->start;
+		lock_size = lck->len;
+		lock_size2 = lck->next ? lck->next->len : 0;
+
+next_packet:
+		mbuf = bufs[i];
+
+		pkt_len = mbuf->data_len;
+
+		hwpkt_len = RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED +
+			RTE_SZE2_ALIGN8(pkt_len);
+
+		if (lock_size + lock_size2 < hwpkt_len) {
+			szedata_tx_unlock_data(sze_q->sze, lck, unlock_size);
+			goto lock_again;
+		}
+
+		num_bytes += pkt_len;
+
+		if (lock_size > hwpkt_len) {
+			rem_len = 0;
+			/* write packet length at first 2 bytes in 8B header */
+			*((uint16_t *) dst) = htole16(RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED +
+					pkt_len);
+			*(((uint16_t *) dst) + 1) = htole16(0);
+			/* copy packet from mbuf */
+			rte_memcpy((void *)(((uint8_t *)(dst)) +
+						RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED),
+					rte_pktmbuf_mtod(mbuf, const void *), pkt_len);
+
+
+			dst = ((uint8_t *)dst) + hwpkt_len;
+			unlock_size += hwpkt_len;
+			lock_size -= hwpkt_len;
+
+			rte_pktmbuf_free(mbuf);
+			num_tx++;
+			i++;
+			if (i == nb_pkts) {
+				szedata_tx_unlock_data(sze_q->sze, lck, unlock_size);
+				break;
+			}
+			goto next_packet;
+		} else if (lock_size + lock_size2 >= hwpkt_len) {
+			/* write packet length at first 2 bytes in 8B header */
+			*((uint16_t *) dst) = htole16(RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED +
+					pkt_len);
+			*(((uint16_t *) dst) + 1) = htole16(0);
+
+			/*
+			 * If the raw packet (pkt_len) is smaller than lock_size,
+			 * get the correct length for memcpy
+			 */
+			write_len =
+				pkt_len < lock_size - RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED ?
+				pkt_len : lock_size - RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED;
+
+			/* copy first part of packet */
+			rte_memcpy((void *)(((uint8_t *)(dst)) +
+						RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED),
+					rte_pktmbuf_mtod(mbuf, const void *), write_len);
+
+			rem_len = hwpkt_len - lock_size;
+			if (lck->next)
+				dst = lck->next->start;
+
+			rte_memcpy(dst,
+					(const void *) (rte_pktmbuf_mtod(mbuf, const uint8_t *) +
+						write_len), pkt_len - write_len);
+
+			dst = ((uint8_t *)dst) + rem_len;
+			unlock_size += hwpkt_len;
+			lock_size = lock_size2 - rem_len;
+			lock_size2 = 0;
+
+			rte_pktmbuf_free(mbuf);
+			num_tx++;
+		}
+
+		szedata_tx_unlock_data(sze_q->sze, lck, unlock_size);
+	}
+
+	sze_q->tx_pkts += num_tx;
+	sze_q->err_pkts += nb_pkts - num_tx;
+	sze_q->tx_bytes += num_bytes;
+	return num_tx;
+}
+
+static int
+eth_dev_start(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	int ret;
+	unsigned i;
+	uint32_t x;
+	uint32_t rx;
+	uint32_t tx;
+	uint32_t num_rx_sub = 0;
+	uint32_t num_tx_sub = 0;
+
+	if (internals->nb_rx_queues == 0) {
+		rx = internals->sze_rx_req;
+		tx = 0;
+
+		for (i = 0; i < internals->num_of_rx; i++) {
+			/*
+			 * Open, subscribe rx,tx channels and start device
+			 */
+			internals->rx_queue[num_rx_sub].sze =
+				szedata_open(internals->sze_dev);
+			if (internals->rx_queue[num_rx_sub].sze == NULL)
+				goto err_rx;
+
+			x = rx & ((~rx)+1); /* separate least significant non-zero bit */
+
+			ret = szedata_subscribe3(internals->rx_queue[num_rx_sub].sze,
+					&x, &tx);
+			if (ret)
+				goto err_rx;
+
+			if (x) {
+				ret = szedata_start(internals->rx_queue[num_rx_sub].sze);
+				if (ret)
+					goto err_rx;
+
+				/*
+				 * set to 1 all bits lower than bit set to 1
+				 * and that bit to 0
+				 */
+				x -= 1;
+				internals->rx_queue[num_rx_sub].rx_channel = count_set_bits(x);
+				num_rx_sub++;
+			} else {
+				szedata_close(internals->rx_queue[num_rx_sub].sze);
+				internals->rx_queue[num_rx_sub].sze = NULL;
+			}
+
+			rx = rx & (rx-1); /* set least significant non-zero bit to zero */
+		}
+
+		internals->nb_rx_queues = num_rx_sub;
+		dev->data->nb_rx_queues = (uint16_t) num_rx_sub;
+	}
+
+	if (internals->nb_tx_queues == 0) {
+		rx = 0;
+		tx = internals->sze_tx_req;
+
+		for (i = 0; i < internals->num_of_tx; i++) {
+			/*
+			 * Open, subscribe rx,tx channels and start device
+			 */
+			internals->tx_queue[num_tx_sub].sze =
+				szedata_open(internals->sze_dev);
+			if (internals->tx_queue[num_tx_sub].sze == NULL)
+				goto err_tx;
+
+			x = tx & ((~tx)+1); /* separate least significant non-zero bit */
+
+			ret = szedata_subscribe3(internals->tx_queue[num_tx_sub].sze,
+					&rx, &x);
+			if (ret)
+				goto err_tx;
+
+			if (x) {
+				ret = szedata_start(internals->tx_queue[num_tx_sub].sze);
+				if (ret)
+					goto err_tx;
+
+				/*
+				 * set to 1 all bits lower than bit set to 1
+				 * and that bit to 0
+				 */
+				x -= 1;
+				internals->tx_queue[num_tx_sub].tx_channel = count_set_bits(x);
+				num_tx_sub++;
+			} else {
+				szedata_close(internals->tx_queue[num_tx_sub].sze);
+				internals->tx_queue[num_tx_sub].sze = NULL;
+			}
+
+			tx = tx & (tx-1); /* set least significant non-zero bit to zero */
+		}
+
+		internals->nb_tx_queues = num_tx_sub;
+		dev->data->nb_tx_queues = (uint16_t) num_tx_sub;
+	}
+
+	dev->data->dev_link.link_status = 1;
+	return 0;
+err_tx: /* close sze for tx and rx queues */
+	for (i = 0; i < num_tx_sub; i++) {
+		if (internals->tx_queue[num_tx_sub].sze != NULL) {
+			szedata_close(internals->tx_queue[num_tx_sub].sze);
+			internals->tx_queue[num_tx_sub].sze = NULL;
+		}
+	}
+	/* set number of rx queues to zero */
+	internals->nb_rx_queues = 0;
+	dev->data->nb_rx_queues = (uint16_t) 0;
+err_rx: /* close sze only for rx queues */
+	for (i = 0; i < num_rx_sub; i++) {
+		if (internals->rx_queue[num_rx_sub].sze != NULL) {
+			szedata_close(internals->rx_queue[num_rx_sub].sze);
+			internals->tx_queue[num_rx_sub].sze = NULL;
+		}
+	}
+	return -1;
+}
+
+static void
+eth_dev_stop(struct rte_eth_dev *dev)
+{
+	unsigned i;
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	for (i = 0; i < internals->nb_rx_queues; i++) {
+		if (internals->rx_queue[i].sze != NULL) {
+			szedata_close(internals->rx_queue[i].sze);
+			internals->rx_queue[i].sze = NULL;
+		}
+	}
+
+	for (i = 0; i < internals->nb_tx_queues; i++) {
+		if (internals->tx_queue[i].sze != NULL) {
+			szedata_close(internals->tx_queue[i].sze);
+			internals->tx_queue[i].sze = NULL;
+		}
+	}
+
+	internals->nb_rx_queues = 0;
+	internals->nb_tx_queues = 0;
+
+	dev->data->nb_rx_queues = (uint16_t) 0;
+	dev->data->nb_tx_queues = (uint16_t) 0;
+
+	dev->data->dev_link.link_status = 0;
+}
+
+static int
+eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+static void
+eth_dev_info(struct rte_eth_dev *dev,
+		struct rte_eth_dev_info *dev_info)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	dev_info->driver_name = drivername;
+	dev_info->if_index = internals->if_index;
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t) -1;
+	dev_info->max_rx_queues = (uint16_t)internals->nb_rx_queues;
+	dev_info->max_tx_queues = (uint16_t)internals->nb_tx_queues;
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = NULL;
+}
+
+static void
+eth_stats_get(struct rte_eth_dev *dev,
+		struct rte_eth_stats *igb_stats)
+{
+	unsigned i;
+	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;
+	const struct pmd_internals *internal = dev->data->dev_private;
+
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS && i < internal->nb_rx_queues;
+			i++) {
+		igb_stats->q_ipackets[i] = internal->rx_queue[i].rx_pkts;
+		igb_stats->q_ibytes[i] = internal->rx_queue[i].rx_bytes;
+		rx_total += igb_stats->q_ipackets[i];
+		rx_total_bytes += igb_stats->q_ibytes[i];
+	}
+
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS && i < internal->nb_tx_queues;
+			i++) {
+		igb_stats->q_opackets[i] = internal->tx_queue[i].tx_pkts;
+		igb_stats->q_errors[i] = internal->tx_queue[i].err_pkts;
+		igb_stats->q_obytes[i] = internal->tx_queue[i].tx_bytes;
+		tx_total += igb_stats->q_opackets[i];
+		tx_err_total += igb_stats->q_errors[i];
+		tx_total_bytes += igb_stats->q_obytes[i];
+	}
+
+	igb_stats->ipackets = rx_total;
+	igb_stats->opackets = tx_total;
+	igb_stats->ibytes = rx_total_bytes;
+	igb_stats->obytes = tx_total_bytes;
+	igb_stats->oerrors = tx_err_total;
+}
+
+static void
+eth_stats_reset(struct rte_eth_dev *dev)
+{
+	unsigned i;
+	struct pmd_internals *internal = dev->data->dev_private;
+	for (i = 0; i < internal->nb_rx_queues; i++) {
+		internal->rx_queue[i].rx_pkts = 0;
+		internal->rx_queue[i].rx_bytes = 0;
+	}
+	for (i = 0; i < internal->nb_tx_queues; i++) {
+		internal->tx_queue[i].tx_pkts = 0;
+		internal->tx_queue[i].err_pkts = 0;
+		internal->tx_queue[i].tx_bytes = 0;
+	}
+}
+
+static void
+eth_dev_close(struct rte_eth_dev *dev)
+{
+	unsigned i;
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	for (i = 0; i < internals->nb_rx_queues; i++) {
+		if (internals->rx_queue[i].sze != NULL) {
+			szedata_close(internals->rx_queue[i].sze);
+			internals->rx_queue[i].sze = NULL;
+		}
+	}
+
+	for (i = 0; i < internals->nb_tx_queues; i++) {
+		if (internals->tx_queue[i].sze != NULL) {
+			szedata_close(internals->tx_queue[i].sze);
+			internals->tx_queue[i].sze = NULL;
+		}
+	}
+
+	internals->nb_rx_queues = 0;
+	internals->nb_tx_queues = 0;
+
+	dev->data->nb_rx_queues = (uint16_t) 0;
+	dev->data->nb_tx_queues = (uint16_t) 0;
+}
+
+static void
+eth_queue_release(void *q __rte_unused)
+{
+}
+
+static int
+eth_link_update(struct rte_eth_dev *dev __rte_unused,
+		int wait_to_complete __rte_unused)
+{
+	return 0;
+}
+
+static int
+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 __rte_unused,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	struct szedata2_rx_queue *szedata2_q = &internals->rx_queue[rx_queue_id];
+	szedata2_q->mb_pool = mb_pool;
+	dev->data->rx_queues[rx_queue_id] = szedata2_q;
+	szedata2_q->in_port = dev->data->port_id;
+	return 0;
+}
+
+static int
+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 __rte_unused,
+		const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+
+	struct pmd_internals *internals = dev->data->dev_private;
+	dev->data->tx_queues[tx_queue_id] = &internals->tx_queue[tx_queue_id];
+	return 0;
+}
+
+static struct eth_dev_ops ops = {
+		.dev_start          = eth_dev_start,
+		.dev_stop           = eth_dev_stop,
+		.dev_close          = eth_dev_close,
+		.dev_configure      = eth_dev_configure,
+		.dev_infos_get      = eth_dev_info,
+		.rx_queue_setup     = eth_rx_queue_setup,
+		.tx_queue_setup     = eth_tx_queue_setup,
+		.rx_queue_release   = eth_queue_release,
+		.tx_queue_release   = eth_queue_release,
+		.link_update        = eth_link_update,
+		.stats_get          = eth_stats_get,
+		.stats_reset        = eth_stats_reset,
+};
+
+static int
+get_mask(const char *mask_str, uint32_t *mask_num)
+{
+	char *endptr;
+	long int value;
+
+	value = strtol(mask_str, &endptr, 0);
+	if (*endptr != '\0' || value > UINT32_MAX || value < 0)
+		return -1;
+
+	*mask_num = (uint32_t) value;
+	return 0;
+}
+
+static int
+add_rx_mask(const char *key __rte_unused, const char *value, void *extra_args)
+{
+	struct rxtx_szedata2 *szedata2 = extra_args;
+	uint32_t mask;
+
+	if (get_mask(value, &mask) != 0)
+		return -1;
+
+	szedata2->sze_rx_mask_req |= mask;
+	return 0;
+}
+
+static int
+add_tx_mask(const char *key __rte_unused, const char *value, void *extra_args)
+{
+	struct rxtx_szedata2 *szedata2 = extra_args;
+	uint32_t mask;
+
+	if (get_mask(value, &mask) != 0)
+		return -1;
+
+	szedata2->sze_tx_mask_req |= mask;
+	return 0;
+}
+
+static int
+rte_pmd_init_internals(const char *name, const unsigned nb_rx_queues,
+		const unsigned nb_tx_queues,
+		const unsigned numa_node,
+		struct pmd_internals **internals,
+		struct rte_eth_dev **eth_dev)
+{
+	struct rte_eth_dev_data *data = NULL;
+	struct rte_pci_device *pci_dev = NULL;
+
+	RTE_LOG(INFO, PMD,
+			"Creating szedata2-backed ethdev on numa socket %u\n", numa_node);
+
+	/*
+	 * now do all data allocation - for eth_dev structure, dummy pci driver
+	 * and internal (private) data
+	 */
+	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
+	if (data == NULL)
+		goto error;
+
+	pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, numa_node);
+	if (pci_dev == NULL)
+		goto error;
+
+	*internals = rte_zmalloc_socket(name, sizeof(**internals), 0, numa_node);
+	if (*internals == NULL)
+		goto error;
+
+	/* reserve an ethdev entry */
+	*eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL);
+	if (*eth_dev == NULL)
+		goto error;
+
+	/*
+	 * now put it all together
+	 * - store queue data in internals,
+	 * - store numa_node info in pci_driver
+	 * - point eth_dev_data to internals and pci_driver
+	 * - and point eth_dev structure to new eth_dev_data structure
+	 *
+	 * NOTE: we'll replace the data element, of originally allocated eth_dev
+	 * so the rings are local per-process
+	 */
+
+	(*internals)->nb_rx_queues = nb_rx_queues;
+	(*internals)->nb_tx_queues = nb_tx_queues;
+
+	(*internals)->if_index = 0;
+
+	pci_dev->numa_node = numa_node;
+
+	data->dev_private = *internals;
+	data->port_id = (*eth_dev)->data->port_id;
+	snprintf(data->name, sizeof(data->name), "%s", (*eth_dev)->data->name);
+	data->nb_rx_queues = (uint16_t)nb_rx_queues;
+	data->nb_tx_queues = (uint16_t)nb_tx_queues;
+	data->dev_link = pmd_link;
+	data->mac_addrs = &eth_addr;
+
+	(*eth_dev)->data = data;
+	(*eth_dev)->dev_ops = &ops;
+	(*eth_dev)->pci_dev = pci_dev;
+
+	return 0;
+
+error:
+	if (data)
+		rte_free(data);
+	if (pci_dev)
+		rte_free(pci_dev);
+	if (*internals)
+		rte_free(*internals);
+	return -1;
+}
+
+static int
+rte_eth_from_szedata2(const char *name,
+		struct rxtx_szedata2 *szedata2,
+		const unsigned numa_node)
+{
+	struct pmd_internals *internals = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+	int ret;
+	unsigned i;
+	uint32_t x;
+	uint32_t rx;
+	uint32_t tx;
+	uint32_t num_rx_sub = 0;
+	uint32_t num_tx_sub = 0;
+
+	if (rte_pmd_init_internals(name, 0, 0, numa_node,
+			&internals, &eth_dev) < 0)
+		return -1;
+
+	internals->sze_dev = szedata2->sze_dev;
+	internals->sze_rx_req = szedata2->sze_rx_mask_req;
+	internals->sze_tx_req = szedata2->sze_tx_mask_req;
+	internals->num_of_rx = szedata2->num_of_rx;
+	internals->num_of_tx = szedata2->num_of_tx;
+
+	RTE_LOG(INFO, PMD, "Number of rx channels to open: %u mask: 0x%x\n",
+			internals->num_of_rx, internals->sze_rx_req);
+	RTE_LOG(INFO, PMD, "Number of tx channels to open: %u mask: 0x%x\n",
+			internals->num_of_tx, internals->sze_tx_req);
+
+	rx = internals->sze_rx_req;
+	tx = 0;
+
+	for (i = 0; i < internals->num_of_rx; i++) {
+		/*
+		 * Open, subscribe rx,tx channels and start device
+		 */
+		RTE_LOG(INFO, PMD, "Opening SZE device %u. time\n", i);
+
+		internals->rx_queue[num_rx_sub].sze = szedata_open(internals->sze_dev);
+		if (internals->rx_queue[num_rx_sub].sze == NULL)
+			return -1;
+
+		x = rx & ((~rx)+1); /* separate least significant non-zero bit */
+
+		RTE_LOG(INFO, PMD, "Subscribing rx channel: 0x%x tx channel: 0x%x\n",
+				x, tx);
+
+		ret = szedata_subscribe3(internals->rx_queue[num_rx_sub].sze, &x, &tx);
+		if (ret) {
+			szedata_close(internals->rx_queue[num_rx_sub].sze);
+			internals->rx_queue[num_rx_sub].sze = NULL;
+			return -1;
+		}
+
+		RTE_LOG(INFO, PMD, "Subscribed rx channel: 0x%x tx channel: 0x%x\n",
+				x, tx);
+
+		if (x) {
+			RTE_LOG(INFO, PMD, "Starting SZE device for rx queue: %u\n",
+					num_rx_sub);
+
+			ret = szedata_start(internals->rx_queue[num_rx_sub].sze);
+			if (ret) {
+				szedata_close(internals->rx_queue[num_rx_sub].sze);
+				internals->rx_queue[num_rx_sub].sze = NULL;
+				return -1;
+			}
+
+			/*
+			 * set to 1 all bits lower than bit set to 1
+			 * and that bit to 0
+			 */
+			x -= 1;
+			internals->rx_queue[num_rx_sub].rx_channel = count_set_bits(x);
+			RTE_LOG(INFO, PMD, "Subscribed rx channel no: %u\n",
+					internals->rx_queue[num_rx_sub].rx_channel);
+			num_rx_sub++;
+		} else {
+			RTE_LOG(INFO, PMD,
+				"Could not subscribe any rx channel. Closing SZE device\n");
+
+			szedata_close(internals->rx_queue[num_rx_sub].sze);
+			internals->rx_queue[num_rx_sub].sze = NULL;
+		}
+
+		rx = rx & (rx-1); /* set least significant non-zero bit to zero */
+	}
+
+	rx = 0;
+	tx = internals->sze_tx_req;
+
+	for (i = 0; i < internals->num_of_tx; i++) {
+		/*
+		 * Open, subscribe rx,tx channels and start device
+		 */
+		RTE_LOG(INFO, PMD, "Opening SZE device %u. time\n",
+				i + internals->num_of_rx);
+
+		internals->tx_queue[num_tx_sub].sze = szedata_open(internals->sze_dev);
+		if (internals->tx_queue[num_tx_sub].sze == NULL)
+			return -1;
+
+		x = tx & ((~tx)+1); /* separate least significant non-zero bit */
+
+		RTE_LOG(INFO, PMD, "Subscribing rx channel: 0x%x tx channel: 0x%x\n",
+				rx, x);
+
+		ret = szedata_subscribe3(internals->tx_queue[num_tx_sub].sze, &rx, &x);
+		if (ret) {
+			szedata_close(internals->tx_queue[num_tx_sub].sze);
+			internals->tx_queue[num_tx_sub].sze = NULL;
+			return -1;
+		}
+
+		RTE_LOG(INFO, PMD, "Subscribed rx channel: 0x%x tx channel: 0x%x\n",
+				rx, x);
+
+		if (x) {
+			RTE_LOG(INFO, PMD, "Starting SZE device for tx queue: %u\n",
+					num_tx_sub);
+
+			ret = szedata_start(internals->tx_queue[num_tx_sub].sze);
+			if (ret) {
+				szedata_close(internals->tx_queue[num_tx_sub].sze);
+				internals->tx_queue[num_tx_sub].sze = NULL;
+				return -1;
+			}
+
+			/*
+			 * set to 1 all bits lower than bit set to 1
+			 * and that bit to 0
+			 */
+			x -= 1;
+			internals->tx_queue[num_tx_sub].tx_channel = count_set_bits(x);
+			num_tx_sub++;
+		} else {
+			RTE_LOG(INFO, PMD,
+				"Could not subscribe any tx channel. Closing SZE device\n");
+
+			szedata_close(internals->tx_queue[num_tx_sub].sze);
+			internals->tx_queue[num_tx_sub].sze = NULL;
+		}
+
+		tx = tx & (tx-1); /* set least significant non-zero bit to zero */
+	}
+
+	RTE_LOG(INFO, PMD, "Successfully opened rx channels: %u\n",
+			num_rx_sub);
+	RTE_LOG(INFO, PMD, "Successfully opened tx channels: %u\n",
+			num_tx_sub);
+
+	internals->nb_rx_queues = num_rx_sub;
+	internals->nb_tx_queues = num_tx_sub;
+
+	eth_dev->data->nb_rx_queues = (uint16_t) num_rx_sub;
+	eth_dev->data->nb_tx_queues = (uint16_t) num_tx_sub;
+
+	eth_dev->rx_pkt_burst = eth_szedata2_rx;
+	eth_dev->tx_pkt_burst = eth_szedata2_tx;
+
+	return 0;
+}
+
+
+static int
+rte_pmd_szedata2_devinit(const char *name, const char *params)
+{
+	unsigned numa_node;
+	int ret;
+	struct rte_kvargs *kvlist;
+	unsigned k_idx;
+	struct rte_kvargs_pair *pair = NULL;
+	struct rxtx_szedata2 szedata2 = { 0, 0, 0, 0, NULL };
+	bool dev_path_missing = true;
+
+	RTE_LOG(INFO, PMD, "Initializing pmd_szedata2 for %s\n", name);
+
+	numa_node = rte_socket_id();
+
+	kvlist = rte_kvargs_parse(params, valid_arguments);
+	if (kvlist == NULL)
+		return -1;
+
+	/*
+	 * Get szedata2 device path and rx,tx channels from passed arguments.
+	 */
+
+	if (rte_kvargs_count(kvlist, RTE_ETH_SZEDATA2_DEV_PATH_ARG) != 1)
+		goto err;
+
+	if (rte_kvargs_count(kvlist, RTE_ETH_SZEDATA2_RX_IFACES_ARG) < 1)
+		goto err;
+
+	if (rte_kvargs_count(kvlist, RTE_ETH_SZEDATA2_TX_IFACES_ARG) < 1)
+		goto err;
+
+	for (k_idx = 0; k_idx < kvlist->count; k_idx++) {
+		pair = &kvlist->pairs[k_idx];
+		if (strstr(pair->key, RTE_ETH_SZEDATA2_DEV_PATH_ARG) != NULL) {
+			szedata2.sze_dev = pair->value;
+			dev_path_missing = false;
+			break;
+		}
+	}
+
+	if (dev_path_missing)
+		goto err;
+
+	ret = rte_kvargs_process(kvlist, RTE_ETH_SZEDATA2_RX_IFACES_ARG,
+			&add_rx_mask, &szedata2);
+	if (ret < 0)
+		goto err;
+
+	ret = rte_kvargs_process(kvlist, RTE_ETH_SZEDATA2_TX_IFACES_ARG,
+			&add_tx_mask, &szedata2);
+	if (ret < 0)
+		goto err;
+
+	szedata2.num_of_rx = count_set_bits(szedata2.sze_rx_mask_req);
+	szedata2.num_of_tx = count_set_bits(szedata2.sze_tx_mask_req);
+
+	RTE_LOG(INFO, PMD, "SZE device found at path %s\n", szedata2.sze_dev);
+
+	return rte_eth_from_szedata2(name, &szedata2, numa_node);
+err:
+	rte_kvargs_free(kvlist);
+	return -1;
+}
+
+static struct rte_driver pmd_szedata2_drv = {
+	.name = "eth_szedata2",
+	.type = PMD_VDEV,
+	.init = rte_pmd_szedata2_devinit,
+};
+
+PMD_REGISTER_DRIVER(pmd_szedata2_drv);
diff --git a/drivers/net/szedata2/rte_eth_szedata2.h b/drivers/net/szedata2/rte_eth_szedata2.h
new file mode 100644
index 0000000..cf4f1c9
--- /dev/null
+++ b/drivers/net/szedata2/rte_eth_szedata2.h
@@ -0,0 +1,96 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (c) 2015 CESNET
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of CESNET nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RTE_PMD_SZEDATA2_H_
+#define RTE_PMD_SZEDATA2_H_
+
+/* szedata2_packet header length == 4 bytes == 2B segment size + 2B hw size */
+#define RTE_SZE2_PACKET_HEADER_SIZE 4
+
+#define RTE_SZE2_MMIO_MAX 10
+
+/*!
+ * Round 'what' to the nearest larger (or equal) multiple of '8'
+ * (szedata2 packet is aligned to 8 bytes)
+ */
+#define RTE_SZE2_ALIGN8(what) (((what) + ((8)-1)) & (~((8)-1)))
+
+/*! main handle structure */
+struct szedata {
+	int fd;
+	struct sze2_instance_info *info;
+	uint32_t *write_size;
+	void *space[RTE_SZE2_MMIO_MAX];
+	struct szedata_lock lock[2][2];
+
+	__u32 *rx_asize, *tx_asize;
+
+	/* szedata_read_next variables - to keep context (ct) */
+
+	/*
+	 * rx
+	 */
+	/** initial sze lock ptr */
+	const struct szedata_lock   *ct_rx_lck_orig;
+	/** current sze lock ptr (initial or next) */
+	const struct szedata_lock   *ct_rx_lck;
+	/** remaining bytes (not read) within current lock */
+	unsigned int                ct_rx_rem_bytes;
+	/** current pointer to locked memory */
+	unsigned char               *ct_rx_cur_ptr;
+	/** allocated buffer to store RX packet if it was split into 2 buffers */
+	unsigned char               *ct_rx_buffer;
+	/** registered function to provide filtering based on hwdata */
+	int (* ct_rx_filter)(u_int16_t hwdata_len, u_char *hwdata);
+
+	/*
+	 * tx
+	 */
+	/** buffer for tx - packet is prepared here (in future for burst write) */
+	unsigned char               *ct_tx_buffer;
+	/** initial sze TX lock ptrs - number according to TX interfaces */
+	const struct szedata_lock   **ct_tx_lck_orig;
+	/** current sze TX lock ptrs - number according to TX interfaces */
+	const struct szedata_lock   **ct_tx_lck;
+	/** already written bytes in both locks */
+	unsigned int                *ct_tx_written_bytes;
+	/** remaining bytes (not written) within current lock */
+	unsigned int                *ct_tx_rem_bytes;
+	/** current pointers to locked memory */
+	unsigned char               **ct_tx_cur_ptr;
+	/** NUMA node closest to PCIe device, or -1 */
+	int                         numa_node;
+};
+
+
+#endif
diff --git a/drivers/net/szedata2/rte_pmd_szedata2_version.map b/drivers/net/szedata2/rte_pmd_szedata2_version.map
new file mode 100644
index 0000000..ef35398
--- /dev/null
+++ b/drivers/net/szedata2/rte_pmd_szedata2_version.map
@@ -0,0 +1,4 @@
+DPDK_2.0 {
+
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 1a2043a..f9ef4b1 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -92,6 +92,8 @@ endif # ! CONFIG_RTE_BUILD_COMBINE_LIBS
 
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_PCAP)       += -lpcap
 
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lsze2
+
 ifeq ($(CONFIG_RTE_LIBRTE_VHOST_USER),n)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VHOST)          += -lfuse
 endif
@@ -132,6 +134,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_RING)       += -lrte_pmd_ring
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_PCAP)       += -lrte_pmd_pcap
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_AF_PACKET)  += -lrte_pmd_af_packet
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NULL)       += -lrte_pmd_null
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2
 
 endif # ! $(CONFIG_RTE_BUILD_SHARED_LIB)
 
-- 
Matej Vido
Software Developer
CESNET, a. l. e.

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

* [PATCH 2/2] doc: added documentation for szedata2 PMD
  2015-06-19  8:24 [PATCH 0/2] Virtual PMD using sze2 layer for COMBO cards Matej Vido
  2015-06-19  8:25 ` [PATCH 1/2] szedata2: new poll mode driver Matej Vido
@ 2015-06-19  8:25 ` Matej Vido
  2015-09-18  8:32 ` [PATCH v2 0/5] Virtual PMD using sze2 layer for COMBO cards Matej Vido
  2 siblings, 0 replies; 36+ messages in thread
From: Matej Vido @ 2015-06-19  8:25 UTC (permalink / raw)
  To: dev

Signed-off-by: Matej Vido <vido@cesnet.cz>
---
 doc/guides/nics/index.rst            |   1 +
 doc/guides/nics/szedata2.rst         | 105 +++++++++++++++++++++++++++++++++++
 doc/guides/prog_guide/source_org.rst |   1 +
 3 files changed, 107 insertions(+)
 create mode 100644 doc/guides/nics/szedata2.rst

diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index 1ee67fa..4218f90 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -44,6 +44,7 @@ Network Interface Controller Drivers
     ixgbe
     intel_vf
     mlx4
+    szedata2
     virtio
     vmxnet3
     pcap_ring
diff --git a/doc/guides/nics/szedata2.rst b/doc/guides/nics/szedata2.rst
new file mode 100644
index 0000000..05864c5
--- /dev/null
+++ b/doc/guides/nics/szedata2.rst
@@ -0,0 +1,105 @@
+..  BSD LICENSE
+    Copyright 2015 CESNET
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+    * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+    * Neither the name of CESNET nor the names of its
+    contributors may be used to endorse or promote products derived
+    from this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+SZEDATA2 PMD
+============
+
+SZEDATA2 PMD is virtual PMD which uses sze2 layer to communicate with COMBO
+cards (COMBO-80G, COMBO-100G) using interface provided by libsze2 library.
+
+.. note::
+
+   This driver has external dependencies. Therefore it is disabled in default
+   configuration files. It can be enabled by setting CONFIG_RTE_LIBRTE_PMD_SZEDATA2=y
+   and recompiling.
+
+Prerequisities
+--------------
+
+This PMD requires kernel modules which are responsible for initialization and
+allocation of resources needed for sze2 layer function. Communication between
+PMD and kernel modules is mediated by libsze2 library. These kernel modules and
+library are not part of DPDK and must be installed separately:
+
+- **libsze2**
+
+  This library provides API for initialization of sze2 transfers, receiving and
+  transmitting data segments.
+
+- **Kernel modules**
+
+  These kernel modules manage initialization of hardware, allocation and sharing
+  of resources for user space applications:
+
+  - combov3
+  - szedata2_cv3
+
+Using PMD
+---------
+
+SZEDATA2 PMD can be created by passing --vdev= option to EAL in the following
+format:
+
+.. code-block:: console
+
+    --vdev 'DEVICE_NAME,dev_path=PATH_TO_SZEDATA2_DEVICE,rx_ifaces=RX_MASK,tx_ifaces=TX_MASK'
+
+DEVICE_NAME and options dev_path, rx_ifaces, tx_ifaces are mandatory and must
+be separated by commas.
+
+*   DEVICE_NAME: contains prefix eth_szedata2 followed by numbers or letters,
+    must be unique for each virtual device
+
+*   dev_path: Defines path to szedata2 device.
+    Value is valid path to szedata2 device.
+
+        dev_path=/dev/szedataII0
+
+*   rx_ifaces: Defines which receive channels will be used.
+    For each channel is created one queue. Value is mask for selecting which
+    receive channels are required.
+
+        rx_ifaces=0x3
+
+*   tx_ifaces: Defines which transmit channels will be used.
+    For each channel is created one queue. Value is mask for selecting which
+    transmit channels are required.
+
+        tx_ifaces=0x3
+
+Example of usage
+^^^^^^^^^^^^^^^^
+
+Read packets from 0. and 1. receive channel and write them to 0. and 1. transmit
+channel
+
+.. code-block:: console
+
+    $RTE_TARGET/app/testpmd -c 0xf -n 2 --vdev 'eth_szedata20,dev_path=/dev/szedataII0,rx_ifaces=0x3,tx_ifaces=0x3' -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2
diff --git a/doc/guides/prog_guide/source_org.rst b/doc/guides/prog_guide/source_org.rst
index 4f6f489..e43d8c1 100644
--- a/doc/guides/prog_guide/source_org.rst
+++ b/doc/guides/prog_guide/source_org.rst
@@ -106,6 +106,7 @@ The drivers directory has a net subdirectory which contains::
     +-- null               # NULL poll mode driver for testing
     +-- pcap               # PCAP poll mode driver
     +-- ring               # ring poll mode driver
+    +-- szedata2           # szedata2 poll mode driver
     +-- virtio             # virtio poll mode driver
     +-- vmxnet3            # VMXNET3 poll mode driver
     +-- xenvirt            # Xen virtio poll mode driver
-- 
Matej Vido
Software Developer
CESNET, a. l. e.

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

* [PATCH v2 0/5] Virtual PMD using sze2 layer for COMBO cards
  2015-06-19  8:24 [PATCH 0/2] Virtual PMD using sze2 layer for COMBO cards Matej Vido
  2015-06-19  8:25 ` [PATCH 1/2] szedata2: new poll mode driver Matej Vido
  2015-06-19  8:25 ` [PATCH 2/2] doc: added documentation for szedata2 PMD Matej Vido
@ 2015-09-18  8:32 ` Matej Vido
  2015-09-18  8:32   ` [PATCH v2 1/5] szedata2: add new poll mode driver Matej Vido
                     ` (5 more replies)
  2 siblings, 6 replies; 36+ messages in thread
From: Matej Vido @ 2015-09-18  8:32 UTC (permalink / raw)
  To: dev

This is virtual PMD which communicates with COMBO-80G and COMBO-100G
cards through sze2 layer. Communication with COMBO card is managed
through interface provided by libsze2 library and kernel modules
(combov3, szedata2_cv3).

To compile and use PMD, it is necessary to have libsze2 library installed and
kernel modules (combov3, szedata2_cv3) loaded.
Therefore in default configuration PMD compilation is disabled. To compile
szedata2 PMD, it is necessary to enable CONFIG_RTE_LIBRTE_PMD_SZEDATA2=y.

v2:
code cleanup
add handling scattered packets
update release notes

Matej Vido (5):
  szedata2: add new poll mode driver
  szedata2: add handling of scattered packets in RX
  szedata2: add handling of scattered packets in TX
  doc: add documentation for szedata2 PMD
  doc: update 2.2 release notes

 config/common_bsdapp                              |    5 +
 config/common_linuxapp                            |    5 +
 doc/guides/nics/index.rst                         |    1 +
 doc/guides/nics/szedata2.rst                      |  105 ++
 doc/guides/prog_guide/source_org.rst              |    1 +
 doc/guides/rel_notes/release_2_2.rst              |    4 +
 drivers/net/Makefile                              |    1 +
 drivers/net/szedata2/Makefile                     |   62 +
 drivers/net/szedata2/rte_eth_szedata2.c           | 1638 +++++++++++++++++++++
 drivers/net/szedata2/rte_eth_szedata2.h           |   96 ++
 drivers/net/szedata2/rte_pmd_szedata2_version.map |    4 +
 mk/rte.app.mk                                     |    3 +
 12 files changed, 1925 insertions(+)
 create mode 100644 doc/guides/nics/szedata2.rst
 create mode 100644 drivers/net/szedata2/Makefile
 create mode 100644 drivers/net/szedata2/rte_eth_szedata2.c
 create mode 100644 drivers/net/szedata2/rte_eth_szedata2.h
 create mode 100644 drivers/net/szedata2/rte_pmd_szedata2_version.map

-- 
1.9.1

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

* [PATCH v2 1/5] szedata2: add new poll mode driver
  2015-09-18  8:32 ` [PATCH v2 0/5] Virtual PMD using sze2 layer for COMBO cards Matej Vido
@ 2015-09-18  8:32   ` Matej Vido
  2015-10-26 15:10     ` Thomas Monjalon
  2015-09-18  8:32   ` [PATCH v2 2/5] szedata2: add handling of scattered packets in RX Matej Vido
                     ` (4 subsequent siblings)
  5 siblings, 1 reply; 36+ messages in thread
From: Matej Vido @ 2015-09-18  8:32 UTC (permalink / raw)
  To: dev

Add virtual PMD which communicates with COMBO cards through sze2
layer using libsze2 library.

Since link_speed is uint16_t, there can not be used number for 100G
speed, therefore link_speed is set to ETH_LINK_SPEED_10G until the
type of link_speed is solved.

v2:
Code cleanup.
Fix error handling by initialization of rx, tx dma channels.
Add uninit function.

Signed-off-by: Matej Vido <matejvido@gmail.com>
Reviewed-by: Jan Viktorin <viktorin@rehivetech.com>
---
 config/common_bsdapp                              |    5 +
 config/common_linuxapp                            |    5 +
 drivers/net/Makefile                              |    1 +
 drivers/net/szedata2/Makefile                     |   62 ++
 drivers/net/szedata2/rte_eth_szedata2.c           | 1212 +++++++++++++++++++++
 drivers/net/szedata2/rte_eth_szedata2.h           |   96 ++
 drivers/net/szedata2/rte_pmd_szedata2_version.map |    4 +
 mk/rte.app.mk                                     |    3 +
 8 files changed, 1388 insertions(+)
 create mode 100644 drivers/net/szedata2/Makefile
 create mode 100644 drivers/net/szedata2/rte_eth_szedata2.c
 create mode 100644 drivers/net/szedata2/rte_eth_szedata2.h
 create mode 100644 drivers/net/szedata2/rte_pmd_szedata2_version.map

diff --git a/config/common_bsdapp b/config/common_bsdapp
index b37dcf4..d2b6f4f 100644
--- a/config/common_bsdapp
+++ b/config/common_bsdapp
@@ -272,6 +272,11 @@ CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
 CONFIG_RTE_LIBRTE_PMD_PCAP=y
 
 #
+# Compile software PMD backed by SZEDATA2 device
+#
+CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
+
+#
 # Compile link bonding PMD library
 #
 CONFIG_RTE_LIBRTE_PMD_BOND=y
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 0de43d5..f5963e7 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -270,6 +270,11 @@ CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
 CONFIG_RTE_LIBRTE_PMD_PCAP=n
 
 #
+# Compile software PMD backed by SZEDATA2 device
+#
+CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
+
+#
 # Compile link bonding PMD library
 #
 CONFIG_RTE_LIBRTE_PMD_BOND=y
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 5ebf963..7499d1e 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -48,6 +48,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_RING) += ring
 DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio
 DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += vmxnet3
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += xenvirt
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += szedata2
 
 include $(RTE_SDK)/mk/rte.sharelib.mk
 include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/drivers/net/szedata2/Makefile b/drivers/net/szedata2/Makefile
new file mode 100644
index 0000000..c3c42e5
--- /dev/null
+++ b/drivers/net/szedata2/Makefile
@@ -0,0 +1,62 @@
+#   BSD LICENSE
+#
+#   Copyright (c) 2015 CESNET
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of CESNET nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_szedata2.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+EXPORT_MAP := rte_pmd_szedata2_version.map
+
+LIBABIVER := 1
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += rte_eth_szedata2.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += lib/librte_malloc
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += lib/librte_kvargs
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/szedata2/rte_eth_szedata2.c b/drivers/net/szedata2/rte_eth_szedata2.c
new file mode 100644
index 0000000..4db1287
--- /dev/null
+++ b/drivers/net/szedata2/rte_eth_szedata2.c
@@ -0,0 +1,1212 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (c) 2015 CESNET
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of CESNET nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+
+#include <libsze2.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_kvargs.h>
+#include <rte_dev.h>
+
+#include "rte_eth_szedata2.h"
+
+#define RTE_ETH_SZEDATA2_DEV_PATH_ARG "dev_path"
+#define RTE_ETH_SZEDATA2_RX_IFACES_ARG "rx_ifaces"
+#define RTE_ETH_SZEDATA2_TX_IFACES_ARG "tx_ifaces"
+
+#define RTE_ETH_SZEDATA2_MAX_RX_QUEUES 32
+#define RTE_ETH_SZEDATA2_MAX_TX_QUEUES 32
+#define RTE_ETH_SZEDATA2_TX_LOCK_SIZE (32*1024*1024)
+
+/**
+ * size of szedata2_packet header with alignment
+ */
+#define RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED 8
+
+struct szedata2_rx_queue {
+	struct szedata * sze;
+	uint8_t rx_channel;
+	uint8_t in_port;
+	struct rte_mempool *mb_pool;
+	volatile uint64_t rx_pkts;
+	volatile uint64_t rx_bytes;
+	volatile uint64_t err_pkts;
+};
+
+struct szedata2_tx_queue {
+	struct szedata * sze;
+	uint8_t tx_channel;
+	volatile uint64_t tx_pkts;
+	volatile uint64_t err_pkts;
+	volatile uint64_t tx_bytes;
+};
+
+struct rxtx_szedata2 {
+	uint32_t num_of_rx;
+	uint32_t num_of_tx;
+	uint32_t sze_rx_mask_req;
+	uint32_t sze_tx_mask_req;
+	char * sze_dev;
+};
+
+struct pmd_internals {
+	struct szedata2_rx_queue rx_queue[RTE_ETH_SZEDATA2_MAX_RX_QUEUES];
+	struct szedata2_tx_queue tx_queue[RTE_ETH_SZEDATA2_MAX_TX_QUEUES];
+	unsigned nb_rx_queues;
+	unsigned nb_tx_queues;
+	uint32_t num_of_rx;
+	uint32_t num_of_tx;
+	uint32_t sze_rx_req;
+	uint32_t sze_tx_req;
+	int if_index;
+	char * sze_dev;
+};
+
+static const char *valid_arguments[] = {
+	RTE_ETH_SZEDATA2_DEV_PATH_ARG,
+	RTE_ETH_SZEDATA2_RX_IFACES_ARG,
+	RTE_ETH_SZEDATA2_TX_IFACES_ARG,
+	NULL
+};
+
+static struct ether_addr eth_addr = {
+	.addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
+};
+static const char *drivername = "SZEdata2 PMD";
+static struct rte_eth_link pmd_link = {
+		.link_speed = ETH_LINK_SPEED_10G,
+		.link_duplex = ETH_LINK_FULL_DUPLEX,
+		.link_status = 0
+};
+
+
+static uint32_t
+count_ones(uint32_t num)
+{
+	num = num - ((num >> 1) & 0x55555555); /* reuse input as temporary */
+	num = (num & 0x33333333) + ((num >> 2) & 0x33333333);        /* temp */
+	return (((num + (num >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; /* count */
+}
+
+static uint16_t
+eth_szedata2_rx(void *queue,
+		struct rte_mbuf **bufs,
+		uint16_t nb_pkts)
+{
+	unsigned int i;
+	struct rte_mbuf *mbuf;
+	struct szedata2_rx_queue *sze_q = queue;
+	struct rte_pktmbuf_pool_private *mbp_priv;
+	uint16_t num_rx = 0;
+	uint16_t buf_size;
+	uint16_t sg_size;
+	uint16_t hw_size;
+	uint16_t packet_size;
+	uint64_t num_bytes = 0;
+	struct szedata * sze = sze_q->sze;
+	uint8_t * header_ptr = NULL; /* header of packet */
+	uint8_t * packet_ptr1 = NULL;
+	uint8_t * packet_ptr2 = NULL;
+	uint16_t packet_len1 = 0;
+	uint16_t packet_len2 = 0;
+	uint16_t hw_data_align;
+
+	if (unlikely(sze_q->sze == NULL || nb_pkts == 0)) {
+		return 0;
+	}
+
+	/*
+	 * Reads the given number of packets from szedata2 channel given
+	 * by queue and copies the packet data into a newly allocated mbuf
+	 * to return.
+	 */
+	for (i = 0; i < nb_pkts; i++) {
+		mbuf = rte_pktmbuf_alloc(sze_q->mb_pool);
+
+		if (unlikely(mbuf == NULL)) {
+			break;
+		}
+
+		/* get the next sze packet */
+		if (sze->ct_rx_lck != NULL && !sze->ct_rx_rem_bytes &&
+				sze->ct_rx_lck->next == NULL) {
+			/* unlock old data */
+			szedata_rx_unlock_data(sze_q->sze, sze->ct_rx_lck_orig);
+			sze->ct_rx_lck_orig = NULL;
+			sze->ct_rx_lck = NULL;
+		}
+
+		if (!sze->ct_rx_rem_bytes && sze->ct_rx_lck_orig == NULL) {
+			/* nothing to read, lock new data */
+			sze->ct_rx_lck_orig = sze->ct_rx_lck =
+				szedata_rx_lock_data(sze_q->sze, ~0U);
+
+			if (sze->ct_rx_lck == NULL) {
+				/* nothing to lock */
+				rte_pktmbuf_free(mbuf);
+				break;
+			}
+
+			sze->ct_rx_cur_ptr = sze->ct_rx_lck->start;
+			sze->ct_rx_rem_bytes = sze->ct_rx_lck->len;
+
+			if (!sze->ct_rx_rem_bytes) {
+				rte_pktmbuf_free(mbuf);
+				break;
+			}
+		}
+
+		if (sze->ct_rx_rem_bytes < RTE_SZE2_PACKET_HEADER_SIZE) {
+			/*
+			 * cut in header
+			 * copy parts of header to merge buffer
+			 */
+			if (sze->ct_rx_lck->next == NULL) {
+				rte_pktmbuf_free(mbuf);
+				break;
+			}
+
+			/* copy first part of header */
+			rte_memcpy(sze->ct_rx_buffer, sze->ct_rx_cur_ptr,
+					sze->ct_rx_rem_bytes);
+
+			/* copy second part of header */
+			sze->ct_rx_lck = sze->ct_rx_lck->next;
+			sze->ct_rx_cur_ptr = sze->ct_rx_lck->start;
+			rte_memcpy(sze->ct_rx_buffer + sze->ct_rx_rem_bytes,
+				sze->ct_rx_cur_ptr,
+				RTE_SZE2_PACKET_HEADER_SIZE -
+				sze->ct_rx_rem_bytes);
+
+			sze->ct_rx_cur_ptr += RTE_SZE2_PACKET_HEADER_SIZE -
+				sze->ct_rx_rem_bytes;
+			sze->ct_rx_rem_bytes = sze->ct_rx_lck->len -
+				RTE_SZE2_PACKET_HEADER_SIZE +
+				sze->ct_rx_rem_bytes;
+
+			header_ptr = (uint8_t *) sze->ct_rx_buffer;
+		} else {
+			/* not cut */
+			header_ptr = (uint8_t *) sze->ct_rx_cur_ptr;
+			sze->ct_rx_cur_ptr += RTE_SZE2_PACKET_HEADER_SIZE;
+			sze->ct_rx_rem_bytes -= RTE_SZE2_PACKET_HEADER_SIZE;
+		}
+
+		sg_size = le16toh(*((uint16_t *)header_ptr));
+		hw_size = le16toh(*(((uint16_t *)header_ptr)+1));
+		packet_size = sg_size -
+			RTE_SZE2_ALIGN8(RTE_SZE2_PACKET_HEADER_SIZE + hw_size);
+
+
+		/* checks if packet all right */
+		if (!sg_size) {
+			errx(5, "Zero segsize");
+		}
+
+		/* check sg_size and hwsize */
+		if (hw_size > sg_size - RTE_SZE2_PACKET_HEADER_SIZE) {
+			errx(10, "Hwsize bigger than expected. Segsize: %d, "
+				"hwsize: %d", sg_size, hw_size);
+		}
+
+		hw_data_align =
+			RTE_SZE2_ALIGN8(RTE_SZE2_PACKET_HEADER_SIZE + hw_size) -
+			RTE_SZE2_PACKET_HEADER_SIZE;
+
+		if (sze->ct_rx_rem_bytes >=
+				(uint16_t)(sg_size -
+				RTE_SZE2_PACKET_HEADER_SIZE)) {
+			/* no cut */
+			/* one packet ready - go to another */
+			packet_ptr1 = sze->ct_rx_cur_ptr + hw_data_align;
+			packet_len1 = packet_size;
+			packet_ptr2 = NULL;
+			packet_len2 = 0;
+
+			sze->ct_rx_cur_ptr += RTE_SZE2_ALIGN8(sg_size) -
+				RTE_SZE2_PACKET_HEADER_SIZE;
+			sze->ct_rx_rem_bytes -= RTE_SZE2_ALIGN8(sg_size) -
+				RTE_SZE2_PACKET_HEADER_SIZE;
+		} else {
+			/* cut in data */
+			if (sze->ct_rx_lck->next == NULL) {
+				errx(6, "Need \"next\" lock, "
+					"but it is missing: %u",
+					sze->ct_rx_rem_bytes);
+			}
+
+			/* skip hw data */
+			if (sze->ct_rx_rem_bytes <= hw_data_align) {
+				uint16_t rem_size = hw_data_align -
+					sze->ct_rx_rem_bytes;
+
+				/* MOVE to next lock */
+				sze->ct_rx_lck = sze->ct_rx_lck->next;
+				sze->ct_rx_cur_ptr =
+					(void *) (((uint8_t *)
+					(sze->ct_rx_lck->start)) + rem_size);
+
+				packet_ptr1 = sze->ct_rx_cur_ptr;
+				packet_len1 = packet_size;
+				packet_ptr2 = NULL;
+				packet_len2 = 0;
+
+				sze->ct_rx_cur_ptr +=
+					RTE_SZE2_ALIGN8(packet_size);
+				sze->ct_rx_rem_bytes = sze->ct_rx_lck->len -
+					rem_size - RTE_SZE2_ALIGN8(packet_size);
+			} else {
+				/* get pointer and length from first part */
+				packet_ptr1 = sze->ct_rx_cur_ptr +
+					hw_data_align;
+				packet_len1 = sze->ct_rx_rem_bytes -
+					hw_data_align;
+
+				/* MOVE to next lock */
+				sze->ct_rx_lck = sze->ct_rx_lck->next;
+				sze->ct_rx_cur_ptr = sze->ct_rx_lck->start;
+
+				/* get pointer and length from second part */
+				packet_ptr2 = sze->ct_rx_cur_ptr;
+				packet_len2 = packet_size - packet_len1;
+
+				sze->ct_rx_cur_ptr +=
+					RTE_SZE2_ALIGN8(packet_size) -
+					packet_len1;
+				sze->ct_rx_rem_bytes = sze->ct_rx_lck->len -
+					(RTE_SZE2_ALIGN8(packet_size) -
+					 packet_len1);
+			}
+		}
+
+		if (unlikely(packet_ptr1 == NULL)) {
+			rte_pktmbuf_free(mbuf);
+			break;
+		}
+
+		/* get the space available for data in the mbuf */
+		mbp_priv = rte_mempool_get_priv(sze_q->mb_pool);
+		buf_size = (uint16_t) (mbp_priv->mbuf_data_room_size -
+				RTE_PKTMBUF_HEADROOM);
+
+		if (packet_size <= buf_size) {
+			/* sze packet will fit in one mbuf, go ahead and copy */
+			rte_memcpy(rte_pktmbuf_mtod(mbuf, void *),
+					packet_ptr1, packet_len1);
+			if (packet_ptr2 != NULL) {
+				rte_memcpy((void *)(rte_pktmbuf_mtod(mbuf,
+					uint8_t *) + packet_len1),
+					packet_ptr2, packet_len2);
+			}
+			mbuf->data_len = (uint16_t)packet_size;
+
+			mbuf->pkt_len = packet_size;
+			mbuf->port = sze_q->in_port;
+			bufs[num_rx] = mbuf;
+			num_rx++;
+			num_bytes += packet_size;
+		} else {
+			/*
+			 * sze packet will not fit in one mbuf,
+			 * scattered mode is not enabled, drop packet
+			 */
+			RTE_LOG(ERR, PMD,
+				"SZE 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);
+		}
+	}
+
+	sze_q->rx_pkts += num_rx;
+	sze_q->rx_bytes += num_bytes;
+	return num_rx;
+}
+
+static uint16_t
+eth_szedata2_tx(void *queue,
+		struct rte_mbuf **bufs,
+		uint16_t nb_pkts)
+{
+	struct rte_mbuf *mbuf;
+	struct szedata2_tx_queue *sze_q = queue;
+	uint16_t num_tx = 0;
+	uint64_t num_bytes = 0;
+
+	const struct szedata_lock *lck;
+	uint32_t lock_size;
+	uint32_t lock_size2;
+	void *dst;
+	uint32_t pkt_len;
+	uint32_t hwpkt_len;
+	uint32_t unlock_size;
+	uint32_t rem_len;
+	uint8_t mbuf_segs;
+	uint16_t pkt_left = nb_pkts;
+
+	if (sze_q->sze == NULL || nb_pkts == 0)
+		return 0;
+
+	while (pkt_left > 0) {
+		unlock_size = 0;
+		lck = szedata_tx_lock_data(sze_q->sze,
+			RTE_ETH_SZEDATA2_TX_LOCK_SIZE,
+			sze_q->tx_channel);
+		if (lck == NULL)
+			continue;
+
+		dst = lck->start;
+		lock_size = lck->len;
+		lock_size2 = lck->next ? lck->next->len : 0;
+
+next_packet:
+		mbuf = bufs[nb_pkts - pkt_left];
+
+		pkt_len = mbuf->data_len;
+		mbuf_segs = mbuf->nb_segs;
+
+		hwpkt_len = RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED +
+			RTE_SZE2_ALIGN8(pkt_len);
+
+		if (lock_size + lock_size2 < hwpkt_len) {
+			szedata_tx_unlock_data(sze_q->sze, lck, unlock_size);
+			continue;
+		}
+
+		num_bytes += pkt_len;
+
+		if (lock_size > hwpkt_len) {
+			void * tmp_dst;
+
+			rem_len = 0;
+
+			/* write packet length at first 2 bytes in 8B header */
+			*((uint16_t *) dst) = htole16(
+					RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED +
+					pkt_len);
+			*(((uint16_t *) dst) + 1) = htole16(0);
+
+			/* copy packet from mbuf */
+			tmp_dst = ((uint8_t *)(dst)) +
+				RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED;
+			rte_memcpy(tmp_dst,
+				rte_pktmbuf_mtod(mbuf, const void *),
+				pkt_len);
+
+			dst = ((uint8_t *)dst) + hwpkt_len;
+			unlock_size += hwpkt_len;
+			lock_size -= hwpkt_len;
+
+			rte_pktmbuf_free(mbuf);
+			num_tx++;
+			pkt_left--;
+			if (pkt_left == 0) {
+				szedata_tx_unlock_data(sze_q->sze, lck,
+					unlock_size);
+				break;
+			}
+			goto next_packet;
+		} else if (lock_size + lock_size2 >= hwpkt_len) {
+			void * tmp_dst;
+			uint16_t write_len;
+
+			/* write packet length at first 2 bytes in 8B header */
+			*((uint16_t *) dst) =
+				htole16(RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED +
+					pkt_len);
+			*(((uint16_t *) dst) + 1) = htole16(0);
+
+			/*
+			 * If the raw packet (pkt_len) is smaller than lock_size
+			 * get the correct length for memcpy
+			 */
+			write_len =
+				pkt_len < lock_size -
+				RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED ?
+				pkt_len :
+				lock_size - RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED;
+
+			rem_len = hwpkt_len - lock_size;
+
+			tmp_dst = ((uint8_t *)(dst)) +
+				RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED;
+			/* copy part of packet to first area */
+			rte_memcpy(tmp_dst,
+				rte_pktmbuf_mtod(mbuf, const void *),
+				write_len);
+
+			if (lck->next)
+				dst = lck->next->start;
+
+			/* copy part of packet to second area */
+			rte_memcpy(dst,
+				(const void *) (rte_pktmbuf_mtod(mbuf,
+						const uint8_t *) +
+				write_len), pkt_len - write_len);
+
+			dst = ((uint8_t *)dst) + rem_len;
+			unlock_size += hwpkt_len;
+			lock_size = lock_size2 - rem_len;
+			lock_size2 = 0;
+
+			rte_pktmbuf_free(mbuf);
+			num_tx++;
+		}
+
+		szedata_tx_unlock_data(sze_q->sze, lck, unlock_size);
+		pkt_left--;
+	}
+
+	sze_q->tx_pkts += num_tx;
+	sze_q->err_pkts += nb_pkts - num_tx;
+	sze_q->tx_bytes += num_bytes;
+	return num_tx;
+}
+
+static int
+init_rx_channels(struct rte_eth_dev *dev, int v)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	int ret;
+	uint32_t i;
+	uint32_t count = internals->num_of_rx;
+	uint32_t num_sub = 0;
+	uint32_t x;
+	uint32_t rx;
+	uint32_t tx;
+
+	rx = internals->sze_rx_req;
+	tx = 0;
+
+	for (i = 0; i < count; i++) {
+		/*
+		 * Open, subscribe rx,tx channels and start device
+		 */
+		if (v)
+			RTE_LOG(INFO, PMD, "Opening SZE device %u. time\n", i);
+
+		internals->rx_queue[num_sub].sze =
+			szedata_open(internals->sze_dev);
+		if (internals->rx_queue[num_sub].sze == NULL)
+			return -1;
+
+		/* separate least significant non-zero bit */
+		x = rx & ((~rx)+1);
+
+		if (v)
+			RTE_LOG(INFO, PMD, "Subscribing rx channel: 0x%x "
+				"tx channel: 0x%x\n", x, tx);
+
+		ret = szedata_subscribe3(internals->rx_queue[num_sub].sze,
+				&x, &tx);
+		if (ret) {
+			szedata_close(internals->rx_queue[num_sub].sze);
+			internals->rx_queue[num_sub].sze = NULL;
+			return -1;
+		}
+
+		if (v)
+			RTE_LOG(INFO, PMD, "Subscribed rx channel: 0x%x "
+				"tx channel: 0x%x\n", x, tx);
+
+		if (x) {
+			if (v)
+				RTE_LOG(INFO, PMD, "Starting SZE device for "
+					"rx queue: %u\n", num_sub);
+
+			ret = szedata_start(internals->rx_queue[num_sub].sze);
+			if (ret) {
+				szedata_close(internals->rx_queue[num_sub].sze);
+				internals->rx_queue[num_sub].sze = NULL;
+				return -1;
+			}
+
+			/*
+			 * set to 1 all bits lower than bit set to 1
+			 * and that bit to 0
+			 */
+			x -= 1;
+			internals->rx_queue[num_sub].rx_channel =
+				count_ones(x);
+
+			if (v)
+				RTE_LOG(INFO, PMD, "Subscribed rx channel "
+					"no: %u\n",
+					internals->rx_queue[num_sub].rx_channel);
+
+			num_sub++;
+			internals->nb_rx_queues = num_sub;
+		} else {
+			if (v)
+				RTE_LOG(INFO, PMD,
+					"Could not subscribe any rx channel. "
+					"Closing SZE device\n");
+
+			szedata_close(internals->rx_queue[num_sub].sze);
+			internals->rx_queue[num_sub].sze = NULL;
+		}
+
+		/* set least significant non-zero bit to zero */
+		rx = rx & (rx-1);
+	}
+
+	dev->data->nb_rx_queues = (uint16_t) num_sub;
+
+	if (v)
+		RTE_LOG(INFO, PMD, "Successfully opened rx channels: %u\n",
+			num_sub);
+
+	return 0;
+}
+
+static int
+init_tx_channels(struct rte_eth_dev *dev, int v)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	int ret;
+	uint32_t i;
+	uint32_t count = internals->num_of_tx;
+	uint32_t num_sub = 0;
+	uint32_t x;
+	uint32_t rx;
+	uint32_t tx;
+
+	rx = 0;
+	tx = internals->sze_tx_req;
+
+	for (i = 0; i < count; i++) {
+		/*
+		 * Open, subscribe rx,tx channels and start device
+		 */
+		if (v)
+			RTE_LOG(INFO, PMD, "Opening SZE device %u. time\n",
+				i + internals->num_of_rx);
+
+		internals->tx_queue[num_sub].sze =
+			szedata_open(internals->sze_dev);
+		if (internals->tx_queue[num_sub].sze == NULL)
+			return -1;
+
+		/* separate least significant non-zero bit */
+		x = tx & ((~tx)+1);
+
+		if (v)
+			RTE_LOG(INFO, PMD, "Subscribing rx channel: 0x%x "
+				"tx channel: 0x%x\n", rx, x);
+
+		ret = szedata_subscribe3(internals->tx_queue[num_sub].sze,
+				&rx, &x);
+		if (ret) {
+			szedata_close(internals->tx_queue[num_sub].sze);
+			internals->tx_queue[num_sub].sze = NULL;
+			return -1;
+		}
+
+		if (v)
+			RTE_LOG(INFO, PMD, "Subscribed rx channel: 0x%x "
+				"tx channel: 0x%x\n", rx, x);
+
+		if (x) {
+			if (v)
+				RTE_LOG(INFO, PMD, "Starting SZE device for "
+					"tx queue: %u\n", num_sub);
+
+			ret = szedata_start(internals->tx_queue[num_sub].sze);
+			if (ret) {
+				szedata_close(internals->tx_queue[num_sub].sze);
+				internals->tx_queue[num_sub].sze = NULL;
+				return -1;
+			}
+
+			/*
+			 * set to 1 all bits lower than bit set to 1
+			 * and that bit to 0
+			 */
+			x -= 1;
+			internals->tx_queue[num_sub].tx_channel =
+				count_ones(x);
+
+			if (v)
+				RTE_LOG(INFO, PMD, "Subscribed tx channel "
+					"no: %u\n",
+					internals->tx_queue[num_sub].tx_channel);
+
+			num_sub++;
+			internals->nb_tx_queues = num_sub;
+		} else {
+			if (v)
+				RTE_LOG(INFO, PMD,
+					"Could not subscribe any tx channel. "
+					"Closing SZE device\n");
+
+			szedata_close(internals->tx_queue[num_sub].sze);
+			internals->tx_queue[num_sub].sze = NULL;
+		}
+
+		/* set least significant non-zero bit to zero */
+		tx = tx & (tx-1);
+	}
+
+	dev->data->nb_tx_queues = (uint16_t) num_sub;
+
+	if (v)
+		RTE_LOG(INFO, PMD, "Successfully opened tx channels: %u\n",
+			num_sub);
+
+	return 0;
+}
+
+static void
+close_rx_channels(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	uint32_t i;
+	uint32_t num_sub = internals->nb_rx_queues;
+
+	for (i = 0; i < num_sub; i++) {
+		if (internals->rx_queue[i].sze != NULL) {
+			szedata_close(internals->rx_queue[i].sze);
+			internals->rx_queue[i].sze = NULL;
+		}
+	}
+	/* set number of rx queues to zero */
+	internals->nb_rx_queues = 0;
+	dev->data->nb_rx_queues = (uint16_t) 0;
+}
+
+static void
+close_tx_channels(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	uint32_t i;
+	uint32_t num_sub = internals->nb_tx_queues;
+
+	for (i = 0; i < num_sub; i++) {
+		if (internals->tx_queue[i].sze != NULL) {
+			szedata_close(internals->tx_queue[i].sze);
+			internals->tx_queue[i].sze = NULL;
+		}
+	}
+	/* set number of rx queues to zero */
+	internals->nb_tx_queues = 0;
+	dev->data->nb_tx_queues = (uint16_t) 0;
+}
+
+static int
+eth_dev_start(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	int ret;
+
+	if (internals->nb_rx_queues == 0) {
+		ret = init_rx_channels(dev, 0);
+		if (ret != 0) {
+			close_rx_channels(dev);
+			return -1;
+		}
+	}
+
+	if (internals->nb_tx_queues == 0) {
+		ret = init_tx_channels(dev, 0);
+		if (ret != 0) {
+			close_tx_channels(dev);
+			close_rx_channels(dev);
+			return -1;
+		}
+	}
+
+	dev->data->dev_link.link_status = 1;
+	return 0;
+}
+
+static void
+eth_dev_stop(struct rte_eth_dev *dev)
+{
+	unsigned i;
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	for (i = 0; i < internals->nb_rx_queues; i++) {
+		if (internals->rx_queue[i].sze != NULL) {
+			szedata_close(internals->rx_queue[i].sze);
+			internals->rx_queue[i].sze = NULL;
+		}
+	}
+
+	for (i = 0; i < internals->nb_tx_queues; i++) {
+		if (internals->tx_queue[i].sze != NULL) {
+			szedata_close(internals->tx_queue[i].sze);
+			internals->tx_queue[i].sze = NULL;
+		}
+	}
+
+	internals->nb_rx_queues = 0;
+	internals->nb_tx_queues = 0;
+
+	dev->data->nb_rx_queues = (uint16_t) 0;
+	dev->data->nb_tx_queues = (uint16_t) 0;
+
+	dev->data->dev_link.link_status = 0;
+}
+
+static int
+eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+static void
+eth_dev_info(struct rte_eth_dev *dev,
+		struct rte_eth_dev_info *dev_info)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	dev_info->driver_name = drivername;
+	dev_info->if_index = internals->if_index;
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t) -1;
+	dev_info->max_rx_queues = (uint16_t)internals->nb_rx_queues;
+	dev_info->max_tx_queues = (uint16_t)internals->nb_tx_queues;
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = NULL;
+}
+
+static void
+eth_stats_get(struct rte_eth_dev *dev,
+		struct rte_eth_stats *igb_stats)
+{
+	unsigned i;
+	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;
+	const struct pmd_internals *internal = dev->data->dev_private;
+
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_rx_queues; i++) {
+		igb_stats->q_ipackets[i] = internal->rx_queue[i].rx_pkts;
+		igb_stats->q_ibytes[i] = internal->rx_queue[i].rx_bytes;
+		rx_total += igb_stats->q_ipackets[i];
+		rx_total_bytes += igb_stats->q_ibytes[i];
+	}
+
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_tx_queues; i++) {
+		igb_stats->q_opackets[i] = internal->tx_queue[i].tx_pkts;
+		igb_stats->q_errors[i] = internal->tx_queue[i].err_pkts;
+		igb_stats->q_obytes[i] = internal->tx_queue[i].tx_bytes;
+		tx_total += igb_stats->q_opackets[i];
+		tx_err_total += igb_stats->q_errors[i];
+		tx_total_bytes += igb_stats->q_obytes[i];
+	}
+
+	igb_stats->ipackets = rx_total;
+	igb_stats->opackets = tx_total;
+	igb_stats->ibytes = rx_total_bytes;
+	igb_stats->obytes = tx_total_bytes;
+	igb_stats->oerrors = tx_err_total;
+}
+
+static void
+eth_stats_reset(struct rte_eth_dev *dev)
+{
+	unsigned i;
+	struct pmd_internals *internal = dev->data->dev_private;
+	for (i = 0; i < internal->nb_rx_queues; i++) {
+		internal->rx_queue[i].rx_pkts = 0;
+		internal->rx_queue[i].rx_bytes = 0;
+	}
+	for (i = 0; i < internal->nb_tx_queues; i++) {
+		internal->tx_queue[i].tx_pkts = 0;
+		internal->tx_queue[i].err_pkts = 0;
+		internal->tx_queue[i].tx_bytes = 0;
+	}
+}
+
+static void
+eth_dev_close(struct rte_eth_dev *dev)
+{
+	unsigned i;
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	for (i = 0; i < internals->nb_rx_queues; i++) {
+		if (internals->rx_queue[i].sze != NULL) {
+			szedata_close(internals->rx_queue[i].sze);
+			internals->rx_queue[i].sze = NULL;
+		}
+	}
+
+	for (i = 0; i < internals->nb_tx_queues; i++) {
+		if (internals->tx_queue[i].sze != NULL) {
+			szedata_close(internals->tx_queue[i].sze);
+			internals->tx_queue[i].sze = NULL;
+		}
+	}
+
+	internals->nb_rx_queues = 0;
+	internals->nb_tx_queues = 0;
+
+	dev->data->nb_rx_queues = (uint16_t) 0;
+	dev->data->nb_tx_queues = (uint16_t) 0;
+}
+
+static void
+eth_queue_release(void *q __rte_unused)
+{
+}
+
+static int
+eth_link_update(struct rte_eth_dev *dev __rte_unused,
+		int wait_to_complete __rte_unused)
+{
+	return 0;
+}
+
+static int
+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 __rte_unused,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	struct szedata2_rx_queue *szedata2_q =
+		&internals->rx_queue[rx_queue_id];
+	szedata2_q->mb_pool = mb_pool;
+	dev->data->rx_queues[rx_queue_id] = szedata2_q;
+	szedata2_q->in_port = dev->data->port_id;
+	return 0;
+}
+
+static int
+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 __rte_unused,
+		const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	dev->data->tx_queues[tx_queue_id] = &internals->tx_queue[tx_queue_id];
+	return 0;
+}
+
+static void
+eth_mac_addr_set(struct rte_eth_dev *dev __rte_unused,
+		struct ether_addr *mac_addr __rte_unused)
+{
+}
+
+static struct eth_dev_ops ops = {
+		.dev_start          = eth_dev_start,
+		.dev_stop           = eth_dev_stop,
+		.dev_close          = eth_dev_close,
+		.dev_configure      = eth_dev_configure,
+		.dev_infos_get      = eth_dev_info,
+		.rx_queue_setup     = eth_rx_queue_setup,
+		.tx_queue_setup     = eth_tx_queue_setup,
+		.rx_queue_release   = eth_queue_release,
+		.tx_queue_release   = eth_queue_release,
+		.link_update        = eth_link_update,
+		.stats_get          = eth_stats_get,
+		.stats_reset        = eth_stats_reset,
+		.mac_addr_set       = eth_mac_addr_set,
+};
+
+static int
+parse_mask(const char *mask_str, uint32_t *mask_num)
+{
+	char *endptr;
+	long int value;
+
+	value = strtol(mask_str, &endptr, 0);
+	if (*endptr != '\0' || value > UINT32_MAX || value < 0)
+		return -1;
+
+	*mask_num = (uint32_t) value;
+	return 0;
+}
+
+static int
+add_rx_mask(const char *key __rte_unused, const char *value, void *extra_args)
+{
+	struct rxtx_szedata2 *szedata2 = extra_args;
+	uint32_t mask;
+
+	if (parse_mask(value, &mask) != 0)
+		return -1;
+
+	szedata2->sze_rx_mask_req |= mask;
+	return 0;
+}
+
+static int
+add_tx_mask(const char *key __rte_unused, const char *value, void *extra_args)
+{
+	struct rxtx_szedata2 *szedata2 = extra_args;
+	uint32_t mask;
+
+	if (parse_mask(value, &mask) != 0)
+		return -1;
+
+	szedata2->sze_tx_mask_req |= mask;
+	return 0;
+}
+
+static int
+rte_pmd_init_internals(const char *name, const unsigned nb_rx_queues,
+		const unsigned nb_tx_queues,
+		const unsigned numa_node,
+		struct pmd_internals **internals,
+		struct rte_eth_dev **eth_dev)
+{
+	struct rte_eth_dev_data *data = NULL;
+	struct rte_pci_device *pci_dev = NULL;
+
+	RTE_LOG(INFO, PMD,
+			"Creating szedata2-backed ethdev on numa socket %u\n",
+			numa_node);
+
+	/*
+	 * now do all data allocation - for eth_dev structure, dummy pci driver
+	 * and internal (private) data
+	 */
+	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
+	if (data == NULL)
+		goto error;
+
+	pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, numa_node);
+	if (pci_dev == NULL)
+		goto error;
+
+	*internals = rte_zmalloc_socket(name, sizeof(**internals), 0,
+			numa_node);
+	if (*internals == NULL)
+		goto error;
+
+	/* reserve an ethdev entry */
+	*eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL);
+	if (*eth_dev == NULL)
+		goto error;
+
+	/*
+	 * now put it all together
+	 * - store queue data in internals,
+	 * - store numa_node info in pci_driver
+	 * - point eth_dev_data to internals and pci_driver
+	 * - and point eth_dev structure to new eth_dev_data structure
+	 *
+	 * NOTE: we'll replace the data element, of originally allocated eth_dev
+	 * so the rings are local per-process
+	 */
+
+	(*internals)->nb_rx_queues = nb_rx_queues;
+	(*internals)->nb_tx_queues = nb_tx_queues;
+
+	(*internals)->if_index = 0;
+
+	pci_dev->numa_node = numa_node;
+
+	data->dev_private = *internals;
+	data->port_id = (*eth_dev)->data->port_id;
+	snprintf(data->name, sizeof(data->name), "%s", (*eth_dev)->data->name);
+	data->nb_rx_queues = (uint16_t)nb_rx_queues;
+	data->nb_tx_queues = (uint16_t)nb_tx_queues;
+	data->dev_link = pmd_link;
+	data->mac_addrs = &eth_addr;
+
+	(*eth_dev)->data = data;
+	(*eth_dev)->dev_ops = &ops;
+	(*eth_dev)->pci_dev = pci_dev;
+
+	return 0;
+
+error:
+	if (data)
+		rte_free(data);
+	if (pci_dev)
+		rte_free(pci_dev);
+	if (*internals)
+		rte_free(*internals);
+	return -1;
+}
+
+static int
+rte_eth_from_szedata2(const char *name,
+		struct rxtx_szedata2 *szedata2,
+		const unsigned numa_node)
+{
+	struct pmd_internals *internals = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+	struct rte_eth_dev_data *data = NULL;
+	int ret;
+
+	if (rte_pmd_init_internals(name, 0, 0, numa_node,
+			&internals, &eth_dev) < 0)
+		return -1;
+
+	data = eth_dev->data;
+
+	internals->sze_dev = szedata2->sze_dev;
+	internals->sze_rx_req = szedata2->sze_rx_mask_req;
+	internals->sze_tx_req = szedata2->sze_tx_mask_req;
+	internals->num_of_rx = szedata2->num_of_rx;
+	internals->num_of_tx = szedata2->num_of_tx;
+
+	RTE_LOG(INFO, PMD, "Number of rx channels to open: %u mask: 0x%x\n",
+			internals->num_of_rx, internals->sze_rx_req);
+	RTE_LOG(INFO, PMD, "Number of tx channels to open: %u mask: 0x%x\n",
+			internals->num_of_tx, internals->sze_tx_req);
+
+	ret = init_rx_channels(eth_dev, 1);
+	if (ret != 0) {
+		close_rx_channels(eth_dev);
+		return -1;
+	}
+
+	ret = init_tx_channels(eth_dev, 1);
+	if (ret != 0) {
+		close_tx_channels(eth_dev);
+		close_rx_channels(eth_dev);
+		return -1;
+	}
+
+	eth_dev->rx_pkt_burst = eth_szedata2_rx;
+	eth_dev->tx_pkt_burst = eth_szedata2_tx;
+
+	return 0;
+}
+
+
+static int
+rte_pmd_szedata2_devinit(const char *name, const char *params)
+{
+	unsigned numa_node;
+	int ret;
+	struct rte_kvargs *kvlist;
+	unsigned k_idx;
+	struct rte_kvargs_pair *pair = NULL;
+	struct rxtx_szedata2 szedata2 = { 0, 0, 0, 0, NULL };
+	bool dev_path_missing = true;
+
+	RTE_LOG(INFO, PMD, "Initializing pmd_szedata2 for %s\n", name);
+
+	numa_node = rte_socket_id();
+
+	kvlist = rte_kvargs_parse(params, valid_arguments);
+	if (kvlist == NULL)
+		return -1;
+
+	/*
+	 * Get szedata2 device path and rx,tx channels from passed arguments.
+	 */
+
+	if (rte_kvargs_count(kvlist, RTE_ETH_SZEDATA2_DEV_PATH_ARG) != 1)
+		goto err;
+
+	if (rte_kvargs_count(kvlist, RTE_ETH_SZEDATA2_RX_IFACES_ARG) < 1)
+		goto err;
+
+	if (rte_kvargs_count(kvlist, RTE_ETH_SZEDATA2_TX_IFACES_ARG) < 1)
+		goto err;
+
+	for (k_idx = 0; k_idx < kvlist->count; k_idx++) {
+		pair = &kvlist->pairs[k_idx];
+		if (strstr(pair->key, RTE_ETH_SZEDATA2_DEV_PATH_ARG) != NULL) {
+			szedata2.sze_dev = pair->value;
+			dev_path_missing = false;
+			break;
+		}
+	}
+
+	if (dev_path_missing)
+		goto err;
+
+	ret = rte_kvargs_process(kvlist, RTE_ETH_SZEDATA2_RX_IFACES_ARG,
+			&add_rx_mask, &szedata2);
+	if (ret < 0)
+		goto err;
+
+	ret = rte_kvargs_process(kvlist, RTE_ETH_SZEDATA2_TX_IFACES_ARG,
+			&add_tx_mask, &szedata2);
+	if (ret < 0)
+		goto err;
+
+	szedata2.num_of_rx = count_ones(szedata2.sze_rx_mask_req);
+	szedata2.num_of_tx = count_ones(szedata2.sze_tx_mask_req);
+
+	RTE_LOG(INFO, PMD, "SZE device found at path %s\n", szedata2.sze_dev);
+
+	return rte_eth_from_szedata2(name, &szedata2, numa_node);
+err:
+	rte_kvargs_free(kvlist);
+	return -1;
+}
+
+static int
+rte_pmd_szedata2_devuninit(const char *name)
+{
+	struct rte_eth_dev *dev = NULL;
+
+	RTE_LOG(INFO, PMD, "Uninitializing pmd_szedata2 for %s"
+			"on numa socket %u\n", name, rte_socket_id());
+
+	if (name == NULL)
+		return -1;
+
+	dev = rte_eth_dev_allocated(name);
+	if (dev == NULL)
+		return -1;
+
+	rte_free(dev->data->dev_private);
+	rte_free(dev->data);
+	rte_free(dev->pci_dev);
+	rte_eth_dev_release_port(dev);
+	return 0;
+}
+
+static struct rte_driver pmd_szedata2_drv = {
+	.name = "eth_szedata2",
+	.type = PMD_VDEV,
+	.init = rte_pmd_szedata2_devinit,
+	.uninit = rte_pmd_szedata2_devuninit,
+};
+
+PMD_REGISTER_DRIVER(pmd_szedata2_drv);
diff --git a/drivers/net/szedata2/rte_eth_szedata2.h b/drivers/net/szedata2/rte_eth_szedata2.h
new file mode 100644
index 0000000..cf4f1c9
--- /dev/null
+++ b/drivers/net/szedata2/rte_eth_szedata2.h
@@ -0,0 +1,96 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (c) 2015 CESNET
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of CESNET nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RTE_PMD_SZEDATA2_H_
+#define RTE_PMD_SZEDATA2_H_
+
+/* szedata2_packet header length == 4 bytes == 2B segment size + 2B hw size */
+#define RTE_SZE2_PACKET_HEADER_SIZE 4
+
+#define RTE_SZE2_MMIO_MAX 10
+
+/*!
+ * Round 'what' to the nearest larger (or equal) multiple of '8'
+ * (szedata2 packet is aligned to 8 bytes)
+ */
+#define RTE_SZE2_ALIGN8(what) (((what) + ((8)-1)) & (~((8)-1)))
+
+/*! main handle structure */
+struct szedata {
+	int fd;
+	struct sze2_instance_info *info;
+	uint32_t *write_size;
+	void *space[RTE_SZE2_MMIO_MAX];
+	struct szedata_lock lock[2][2];
+
+	__u32 *rx_asize, *tx_asize;
+
+	/* szedata_read_next variables - to keep context (ct) */
+
+	/*
+	 * rx
+	 */
+	/** initial sze lock ptr */
+	const struct szedata_lock   *ct_rx_lck_orig;
+	/** current sze lock ptr (initial or next) */
+	const struct szedata_lock   *ct_rx_lck;
+	/** remaining bytes (not read) within current lock */
+	unsigned int                ct_rx_rem_bytes;
+	/** current pointer to locked memory */
+	unsigned char               *ct_rx_cur_ptr;
+	/** allocated buffer to store RX packet if it was split into 2 buffers */
+	unsigned char               *ct_rx_buffer;
+	/** registered function to provide filtering based on hwdata */
+	int (* ct_rx_filter)(u_int16_t hwdata_len, u_char *hwdata);
+
+	/*
+	 * tx
+	 */
+	/** buffer for tx - packet is prepared here (in future for burst write) */
+	unsigned char               *ct_tx_buffer;
+	/** initial sze TX lock ptrs - number according to TX interfaces */
+	const struct szedata_lock   **ct_tx_lck_orig;
+	/** current sze TX lock ptrs - number according to TX interfaces */
+	const struct szedata_lock   **ct_tx_lck;
+	/** already written bytes in both locks */
+	unsigned int                *ct_tx_written_bytes;
+	/** remaining bytes (not written) within current lock */
+	unsigned int                *ct_tx_rem_bytes;
+	/** current pointers to locked memory */
+	unsigned char               **ct_tx_cur_ptr;
+	/** NUMA node closest to PCIe device, or -1 */
+	int                         numa_node;
+};
+
+
+#endif
diff --git a/drivers/net/szedata2/rte_pmd_szedata2_version.map b/drivers/net/szedata2/rte_pmd_szedata2_version.map
new file mode 100644
index 0000000..bd8138a
--- /dev/null
+++ b/drivers/net/szedata2/rte_pmd_szedata2_version.map
@@ -0,0 +1,4 @@
+DPDK_2.1 {
+
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 9e1909e..f6d4a5c 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -92,6 +92,8 @@ endif # ! CONFIG_RTE_BUILD_COMBINE_LIBS
 
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_PCAP)       += -lpcap
 
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lsze2
+
 ifeq ($(CONFIG_RTE_LIBRTE_VHOST_NUMA),y)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VHOST)          += -lnuma
 endif
@@ -142,6 +144,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_RING)       += -lrte_pmd_ring
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_PCAP)       += -lrte_pmd_pcap
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_AF_PACKET)  += -lrte_pmd_af_packet
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NULL)       += -lrte_pmd_null
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2
 
 endif # ! $(CONFIG_RTE_BUILD_SHARED_LIB)
 
-- 
1.9.1

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

* [PATCH v2 2/5] szedata2: add handling of scattered packets in RX
  2015-09-18  8:32 ` [PATCH v2 0/5] Virtual PMD using sze2 layer for COMBO cards Matej Vido
  2015-09-18  8:32   ` [PATCH v2 1/5] szedata2: add new poll mode driver Matej Vido
@ 2015-09-18  8:32   ` Matej Vido
  2015-09-18  8:32   ` [PATCH v2 3/5] szedata2: add handling of scattered packets in TX Matej Vido
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 36+ messages in thread
From: Matej Vido @ 2015-09-18  8:32 UTC (permalink / raw)
  To: dev

Add new RX function for handling scattered packets.

Signed-off-by: Matej Vido <matejvido@gmail.com>
Reviewed-by: Jan Viktorin <viktorin@rehivetech.com>
---
 drivers/net/szedata2/rte_eth_szedata2.c | 356 +++++++++++++++++++++++++++++++-
 1 file changed, 354 insertions(+), 2 deletions(-)

diff --git a/drivers/net/szedata2/rte_eth_szedata2.c b/drivers/net/szedata2/rte_eth_szedata2.c
index 4db1287..ddb45e4 100644
--- a/drivers/net/szedata2/rte_eth_szedata2.c
+++ b/drivers/net/szedata2/rte_eth_szedata2.c
@@ -362,6 +362,343 @@ eth_szedata2_rx(void *queue,
 }
 
 static uint16_t
+eth_szedata2_rx_scattered(void *queue,
+		struct rte_mbuf **bufs,
+		uint16_t nb_pkts)
+{
+	unsigned int i;
+	struct rte_mbuf *mbuf;
+	struct szedata2_rx_queue *sze_q = queue;
+	struct rte_pktmbuf_pool_private *mbp_priv;
+	uint16_t num_rx = 0;
+	uint16_t buf_size;
+	uint16_t sg_size;
+	uint16_t hw_size;
+	uint16_t packet_size;
+	uint64_t num_bytes = 0;
+	struct szedata * sze = sze_q->sze;
+	uint8_t * header_ptr = NULL; /* header of packet */
+	uint8_t * packet_ptr1 = NULL;
+	uint8_t * packet_ptr2 = NULL;
+	uint16_t packet_len1 = 0;
+	uint16_t packet_len2 = 0;
+	uint16_t hw_data_align;
+
+	if (unlikely(sze_q->sze == NULL || nb_pkts == 0)) {
+		return 0;
+	}
+
+	/*
+	 * Reads the given number of packets from szedata2 channel given
+	 * by queue and copies the packet data into a newly allocated mbuf
+	 * to return.
+	 */
+	for (i = 0; i < nb_pkts; i++) {
+		const struct szedata_lock * ct_rx_lck_backup;
+		unsigned int ct_rx_rem_bytes_backup;
+		unsigned char * ct_rx_cur_ptr_backup;
+
+		/* get the next sze packet */
+		if (sze->ct_rx_lck != NULL && !sze->ct_rx_rem_bytes &&
+				sze->ct_rx_lck->next == NULL) {
+			/* unlock old data */
+			szedata_rx_unlock_data(sze_q->sze, sze->ct_rx_lck_orig);
+			sze->ct_rx_lck_orig = NULL;
+			sze->ct_rx_lck = NULL;
+		}
+
+		/*
+		 * Store items from sze structure which can be changed
+		 * before mbuf allocating. Use these items in case of mbuf
+		 * allocating failure.
+		 */
+		ct_rx_lck_backup = sze->ct_rx_lck;
+		ct_rx_rem_bytes_backup = sze->ct_rx_rem_bytes;
+		ct_rx_cur_ptr_backup = sze->ct_rx_cur_ptr;
+
+		if (!sze->ct_rx_rem_bytes && sze->ct_rx_lck_orig == NULL) {
+			/* nothing to read, lock new data */
+			sze->ct_rx_lck_orig = sze->ct_rx_lck =
+				szedata_rx_lock_data(sze_q->sze, ~0U);
+
+			/*
+			 * Backup items from sze structure must be updated
+			 * after locking to contain pointers to new locks.
+			 */
+			ct_rx_lck_backup = sze->ct_rx_lck;
+			ct_rx_rem_bytes_backup = sze->ct_rx_rem_bytes;
+			ct_rx_cur_ptr_backup = sze->ct_rx_cur_ptr;
+
+			if (sze->ct_rx_lck == NULL) {
+				/* nothing to lock */
+				break;
+			}
+
+			sze->ct_rx_cur_ptr = sze->ct_rx_lck->start;
+			sze->ct_rx_rem_bytes = sze->ct_rx_lck->len;
+
+			if (!sze->ct_rx_rem_bytes) {
+				break;
+			}
+		}
+
+		if (sze->ct_rx_rem_bytes < RTE_SZE2_PACKET_HEADER_SIZE) {
+			/*
+			 * cut in header - copy parts of header to merge buffer
+			 */
+			if (sze->ct_rx_lck->next == NULL) {
+				break;
+			}
+
+			/* copy first part of header */
+			rte_memcpy(sze->ct_rx_buffer, sze->ct_rx_cur_ptr,
+					sze->ct_rx_rem_bytes);
+
+			/* copy second part of header */
+			sze->ct_rx_lck = sze->ct_rx_lck->next;
+			sze->ct_rx_cur_ptr = sze->ct_rx_lck->start;
+			rte_memcpy(sze->ct_rx_buffer + sze->ct_rx_rem_bytes,
+				sze->ct_rx_cur_ptr,
+				RTE_SZE2_PACKET_HEADER_SIZE -
+				sze->ct_rx_rem_bytes);
+
+			sze->ct_rx_cur_ptr += RTE_SZE2_PACKET_HEADER_SIZE -
+				sze->ct_rx_rem_bytes;
+			sze->ct_rx_rem_bytes = sze->ct_rx_lck->len -
+				RTE_SZE2_PACKET_HEADER_SIZE +
+				sze->ct_rx_rem_bytes;
+
+			header_ptr = (uint8_t *) sze->ct_rx_buffer;
+		} else {
+			/* not cut */
+			header_ptr = (uint8_t *) sze->ct_rx_cur_ptr;
+			sze->ct_rx_cur_ptr += RTE_SZE2_PACKET_HEADER_SIZE;
+			sze->ct_rx_rem_bytes -= RTE_SZE2_PACKET_HEADER_SIZE;
+		}
+
+		sg_size = le16toh(*((uint16_t *)header_ptr));
+		hw_size = le16toh(*(((uint16_t *)header_ptr)+1));
+		packet_size = sg_size -
+			RTE_SZE2_ALIGN8(RTE_SZE2_PACKET_HEADER_SIZE + hw_size);
+
+
+		/* checks if packet all right */
+		if (!sg_size) {
+			errx(5, "Zero segsize");
+		}
+
+		/* check sg_size and hwsize */
+		if (hw_size > sg_size - RTE_SZE2_PACKET_HEADER_SIZE) {
+			errx(10, "Hwsize bigger than expected. Segsize: %d, "
+					"hwsize: %d", sg_size, hw_size);
+		}
+
+		hw_data_align =
+			RTE_SZE2_ALIGN8((RTE_SZE2_PACKET_HEADER_SIZE +
+			hw_size)) - RTE_SZE2_PACKET_HEADER_SIZE;
+
+		if (sze->ct_rx_rem_bytes >=
+				(uint16_t)(sg_size -
+				RTE_SZE2_PACKET_HEADER_SIZE)) {
+			/* no cut */
+			/* one packet ready - go to another */
+			packet_ptr1 = sze->ct_rx_cur_ptr + hw_data_align;
+			packet_len1 = packet_size;
+			packet_ptr2 = NULL;
+			packet_len2 = 0;
+
+			sze->ct_rx_cur_ptr += RTE_SZE2_ALIGN8(sg_size) -
+				RTE_SZE2_PACKET_HEADER_SIZE;
+			sze->ct_rx_rem_bytes -= RTE_SZE2_ALIGN8(sg_size) -
+				RTE_SZE2_PACKET_HEADER_SIZE;
+		} else {
+			/* cut in data */
+			if (sze->ct_rx_lck->next == NULL) {
+				errx(6, "Need \"next\" lock, but it is "
+					"missing: %u", sze->ct_rx_rem_bytes);
+			}
+
+			/* skip hw data */
+			if (sze->ct_rx_rem_bytes <= hw_data_align) {
+				uint16_t rem_size = hw_data_align -
+					sze->ct_rx_rem_bytes;
+
+				/* MOVE to next lock */
+				sze->ct_rx_lck = sze->ct_rx_lck->next;
+				sze->ct_rx_cur_ptr =
+					(void *) (((uint8_t *)
+					(sze->ct_rx_lck->start)) + rem_size);
+
+				packet_ptr1 = sze->ct_rx_cur_ptr;
+				packet_len1 = packet_size;
+				packet_ptr2 = NULL;
+				packet_len2 = 0;
+
+				sze->ct_rx_cur_ptr +=
+					RTE_SZE2_ALIGN8(packet_size);
+				sze->ct_rx_rem_bytes = sze->ct_rx_lck->len -
+					rem_size - RTE_SZE2_ALIGN8(packet_size);
+			} else {
+				/* get pointer and length from first part */
+				packet_ptr1 = sze->ct_rx_cur_ptr +
+					hw_data_align;
+				packet_len1 = sze->ct_rx_rem_bytes -
+					hw_data_align;
+
+				/* MOVE to next lock */
+				sze->ct_rx_lck = sze->ct_rx_lck->next;
+				sze->ct_rx_cur_ptr = sze->ct_rx_lck->start;
+
+				/* get pointer and length from second part */
+				packet_ptr2 = sze->ct_rx_cur_ptr;
+				packet_len2 = packet_size - packet_len1;
+
+				sze->ct_rx_cur_ptr +=
+					RTE_SZE2_ALIGN8(packet_size) -
+					packet_len1;
+				sze->ct_rx_rem_bytes = sze->ct_rx_lck->len -
+					(RTE_SZE2_ALIGN8(packet_size) -
+					 packet_len1);
+			}
+		}
+
+		if (unlikely(packet_ptr1 == NULL)) {
+			break;
+		}
+
+		mbuf = rte_pktmbuf_alloc(sze_q->mb_pool);
+
+		if (unlikely(mbuf == NULL)) {
+			/*
+			 * Restore items from sze structure to state after
+			 * unlocking (eventually locking).
+			 */
+			sze->ct_rx_lck = ct_rx_lck_backup;
+			sze->ct_rx_rem_bytes = ct_rx_rem_bytes_backup;
+			sze->ct_rx_cur_ptr = ct_rx_cur_ptr_backup;
+			break;
+		}
+
+		/* get the space available for data in the mbuf */
+		mbp_priv = rte_mempool_get_priv(sze_q->mb_pool);
+		buf_size = (uint16_t) (mbp_priv->mbuf_data_room_size -
+				RTE_PKTMBUF_HEADROOM);
+
+		if (packet_size <= buf_size) {
+			/* sze packet will fit in one mbuf, go ahead and copy */
+			rte_memcpy(rte_pktmbuf_mtod(mbuf, void *),
+					packet_ptr1, packet_len1);
+			if (packet_ptr2 != NULL) {
+				rte_memcpy((void *)
+					(rte_pktmbuf_mtod(mbuf, uint8_t *) +
+					packet_len1), packet_ptr2, packet_len2);
+			}
+			mbuf->data_len = (uint16_t)packet_size;
+		} else {
+			/*
+			 * sze packet will not fit in one mbuf,
+			 * scatter packet into more mbufs
+			 */
+			struct rte_mbuf * m = mbuf;
+			uint16_t len = rte_pktmbuf_tailroom(mbuf);
+
+			/* copy first part of packet */
+			/* fill first mbuf */
+			rte_memcpy(rte_pktmbuf_append(mbuf, len), packet_ptr1,
+				len);
+			packet_len1 -= len;
+			packet_ptr1 = ((uint8_t *)packet_ptr1) + len;
+
+			while (packet_len1 > 0) {
+				/* fill new mbufs */
+				m->next = rte_pktmbuf_alloc(sze_q->mb_pool);
+
+				if (unlikely(m->next == NULL)) {
+					rte_pktmbuf_free(mbuf);
+					/*
+					 * Restore items from sze structure
+					 * to state after unlocking (eventually
+					 * locking).
+					 */
+					sze->ct_rx_lck = ct_rx_lck_backup;
+					sze->ct_rx_rem_bytes =
+						ct_rx_rem_bytes_backup;
+					sze->ct_rx_cur_ptr =
+						ct_rx_cur_ptr_backup;
+					goto finish;
+				}
+
+				m = m->next;
+
+				len = RTE_MIN(rte_pktmbuf_tailroom(m),
+					packet_len1);
+				rte_memcpy(rte_pktmbuf_append(mbuf, len),
+					packet_ptr1, len);
+
+				(mbuf->nb_segs)++;
+				packet_len1 -= len;
+				packet_ptr1 = ((uint8_t *)packet_ptr1) + len;
+			}
+
+			if (packet_ptr2 != NULL) {
+				/* copy second part of packet, if exists */
+				/* fill the rest of currently last mbuf */
+				len = rte_pktmbuf_tailroom(m);
+				rte_memcpy(rte_pktmbuf_append(mbuf, len),
+					packet_ptr2, len);
+				packet_len2 -= len;
+				packet_ptr2 = ((uint8_t *)packet_ptr2) + len;
+
+				while (packet_len2 > 0) {
+					/* fill new mbufs */
+					m->next = rte_pktmbuf_alloc(
+							sze_q->mb_pool);
+
+					if (unlikely(m->next == NULL)) {
+						rte_pktmbuf_free(mbuf);
+						/*
+						 * Restore items from sze
+						 * structure to state after
+						 * unlocking (eventually
+						 * locking).
+						 */
+						sze->ct_rx_lck =
+							ct_rx_lck_backup;
+						sze->ct_rx_rem_bytes =
+							ct_rx_rem_bytes_backup;
+						sze->ct_rx_cur_ptr =
+							ct_rx_cur_ptr_backup;
+						goto finish;
+					}
+
+					m = m->next;
+
+					len = RTE_MIN(rte_pktmbuf_tailroom(m),
+						packet_len2);
+					rte_memcpy(rte_pktmbuf_append(mbuf,len),
+							packet_ptr2, len);
+
+					(mbuf->nb_segs)++;
+					packet_len2 -= len;
+					packet_ptr2 = ((uint8_t *)packet_ptr2) +
+						len;
+				}
+			}
+		}
+		mbuf->pkt_len = packet_size;
+		mbuf->port = sze_q->in_port;
+		bufs[num_rx] = mbuf;
+		num_rx++;
+		num_bytes += packet_size;
+	}
+
+finish:
+	sze_q->rx_pkts += num_rx;
+	sze_q->rx_bytes += num_bytes;
+	return num_rx;
+}
+
+static uint16_t
 eth_szedata2_tx(void *queue,
 		struct rte_mbuf **bufs,
 		uint16_t nb_pkts)
@@ -787,8 +1124,16 @@ eth_dev_stop(struct rte_eth_dev *dev)
 }
 
 static int
-eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
+eth_dev_configure(struct rte_eth_dev *dev)
 {
+	struct rte_eth_dev_data * data = dev->data;
+	if (data->dev_conf.rxmode.enable_scatter == 1) {
+		dev->rx_pkt_burst = eth_szedata2_rx_scattered;
+		data->scattered_rx = 1;
+	} else {
+		dev->rx_pkt_burst = eth_szedata2_rx;
+		data->scattered_rx = 0;
+	}
 	return 0;
 }
 
@@ -1108,7 +1453,14 @@ rte_eth_from_szedata2(const char *name,
 		return -1;
 	}
 
-	eth_dev->rx_pkt_burst = eth_szedata2_rx;
+	if (data->dev_conf.rxmode.enable_scatter == 1 ||
+		data->scattered_rx == 1) {
+		eth_dev->rx_pkt_burst = eth_szedata2_rx_scattered;
+		data->scattered_rx = 1;
+	} else {
+		eth_dev->rx_pkt_burst = eth_szedata2_rx;
+		data->scattered_rx = 0;
+	}
 	eth_dev->tx_pkt_burst = eth_szedata2_tx;
 
 	return 0;
-- 
1.9.1

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

* [PATCH v2 3/5] szedata2: add handling of scattered packets in TX
  2015-09-18  8:32 ` [PATCH v2 0/5] Virtual PMD using sze2 layer for COMBO cards Matej Vido
  2015-09-18  8:32   ` [PATCH v2 1/5] szedata2: add new poll mode driver Matej Vido
  2015-09-18  8:32   ` [PATCH v2 2/5] szedata2: add handling of scattered packets in RX Matej Vido
@ 2015-09-18  8:32   ` Matej Vido
  2015-10-26 14:55     ` Thomas Monjalon
  2015-09-18  8:32   ` [PATCH v2 4/5] doc: add documentation for szedata2 PMD Matej Vido
                     ` (2 subsequent siblings)
  5 siblings, 1 reply; 36+ messages in thread
From: Matej Vido @ 2015-09-18  8:32 UTC (permalink / raw)
  To: dev

TX function modified to handle chained mbufs.

Signed-off-by: Matej Vido <matejvido@gmail.com>
Reviewed-by: Jan Viktorin <viktorin@rehivetech.com>
---
 drivers/net/szedata2/rte_eth_szedata2.c | 108 +++++++++++++++++++++++++++-----
 1 file changed, 91 insertions(+), 17 deletions(-)

diff --git a/drivers/net/szedata2/rte_eth_szedata2.c b/drivers/net/szedata2/rte_eth_szedata2.c
index ddb45e4..e2d6501 100644
--- a/drivers/net/szedata2/rte_eth_szedata2.c
+++ b/drivers/net/szedata2/rte_eth_szedata2.c
@@ -737,7 +737,7 @@ eth_szedata2_tx(void *queue,
 next_packet:
 		mbuf = bufs[nb_pkts - pkt_left];
 
-		pkt_len = mbuf->data_len;
+		pkt_len = mbuf->pkt_len;
 		mbuf_segs = mbuf->nb_segs;
 
 		hwpkt_len = RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED +
@@ -764,9 +764,28 @@ next_packet:
 			/* copy packet from mbuf */
 			tmp_dst = ((uint8_t *)(dst)) +
 				RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED;
-			rte_memcpy(tmp_dst,
-				rte_pktmbuf_mtod(mbuf, const void *),
-				pkt_len);
+			if (likely(mbuf_segs == 1)) {
+				/*
+				 * non-scattered packet,
+				 * transmit from one mbuf
+				 */
+				rte_memcpy(tmp_dst,
+					rte_pktmbuf_mtod(mbuf, const void *),
+					pkt_len);
+			} else {
+				/* scattered packet, transmit from more mbufs */
+				struct rte_mbuf * m = mbuf;
+				while (m) {
+					rte_memcpy(tmp_dst,
+						rte_pktmbuf_mtod(m,
+						const void *),
+						m->data_len);
+					tmp_dst = ((uint8_t *)(tmp_dst)) +
+						m->data_len;
+					m = m->next;
+				}
+			}
+
 
 			dst = ((uint8_t *)dst) + hwpkt_len;
 			unlock_size += hwpkt_len;
@@ -805,19 +824,74 @@ next_packet:
 
 			tmp_dst = ((uint8_t *)(dst)) +
 				RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED;
-			/* copy part of packet to first area */
-			rte_memcpy(tmp_dst,
-				rte_pktmbuf_mtod(mbuf, const void *),
-				write_len);
-
-			if (lck->next)
-				dst = lck->next->start;
-
-			/* copy part of packet to second area */
-			rte_memcpy(dst,
-				(const void *) (rte_pktmbuf_mtod(mbuf,
-						const uint8_t *) +
-				write_len), pkt_len - write_len);
+			if (likely(mbuf_segs == 1)) {
+				/*
+				 * non-scattered packet,
+				 * transmit from one mbuf
+				 */
+				/* copy part of packet to first area */
+				rte_memcpy(tmp_dst,
+					rte_pktmbuf_mtod(mbuf, const void *),
+					write_len);
+
+				if (lck->next)
+					dst = lck->next->start;
+
+				/* copy part of packet to second area */
+				rte_memcpy(dst,
+					(const void *) (rte_pktmbuf_mtod(mbuf,
+							const uint8_t *) +
+					write_len), pkt_len - write_len);
+			} else {
+				/* scattered packet, transmit from more mbufs */
+				struct rte_mbuf * m = mbuf;
+				uint16_t written = 0;
+				uint16_t to_write = 0;
+				bool new_mbuf = true;
+				uint16_t write_off = 0;
+
+				/* copy part of packet to first area */
+				while (m && written < write_len) {
+					to_write = RTE_MIN(m->data_len,
+							write_len - written);
+					rte_memcpy(tmp_dst,
+						rte_pktmbuf_mtod(m,
+							const void *),
+						to_write);
+
+					tmp_dst = ((uint8_t *)(tmp_dst)) +
+						to_write;
+					if (m->data_len <= write_len -
+							written) {
+						m = m->next;
+						new_mbuf = true;
+					} else {
+						new_mbuf = false;
+					}
+					written += to_write;
+				}
+
+				if (lck->next)
+					dst = lck->next->start;
+
+				tmp_dst = dst;
+				written = 0;
+				write_off = new_mbuf ? 0 : to_write;
+
+				/* copy part of packet to second area */
+				while (m && written < pkt_len - write_len) {
+					rte_memcpy(tmp_dst, (const void *)
+						(rte_pktmbuf_mtod(m,
+						uint8_t *) + write_off),
+						m->data_len - write_off);
+
+					tmp_dst = ((uint8_t *)(tmp_dst)) +
+						(m->data_len - write_off);
+					written += m->data_len - write_off;
+					m = m->next;
+					write_off = 0;
+				}
+			}
 
 			dst = ((uint8_t *)dst) + rem_len;
 			unlock_size += hwpkt_len;
-- 
1.9.1

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

* [PATCH v2 4/5] doc: add documentation for szedata2 PMD
  2015-09-18  8:32 ` [PATCH v2 0/5] Virtual PMD using sze2 layer for COMBO cards Matej Vido
                     ` (2 preceding siblings ...)
  2015-09-18  8:32   ` [PATCH v2 3/5] szedata2: add handling of scattered packets in TX Matej Vido
@ 2015-09-18  8:32   ` Matej Vido
  2015-10-26 15:00     ` Thomas Monjalon
                       ` (2 more replies)
  2015-09-18  8:32   ` [PATCH v2 5/5] doc: update 2.2 release notes Matej Vido
  2015-11-10 14:18   ` [PATCH v3 0/6] Virtual PMD using sze2 layer for COMBO cards Matej Vido
  5 siblings, 3 replies; 36+ messages in thread
From: Matej Vido @ 2015-09-18  8:32 UTC (permalink / raw)
  To: dev

Signed-off-by: Matej Vido <matejvido@gmail.com>
Reviewed-by: Jan Viktorin <viktorin@rehivetech.com>
---
 doc/guides/nics/index.rst            |   1 +
 doc/guides/nics/szedata2.rst         | 105 +++++++++++++++++++++++++++++++++++
 doc/guides/prog_guide/source_org.rst |   1 +
 3 files changed, 107 insertions(+)
 create mode 100644 doc/guides/nics/szedata2.rst

diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index d1a92f8..fcbf8dd 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -45,6 +45,7 @@ Network Interface Controller Drivers
     ixgbe
     intel_vf
     mlx4
+    szedata2
     virtio
     vmxnet3
     pcap_ring
diff --git a/doc/guides/nics/szedata2.rst b/doc/guides/nics/szedata2.rst
new file mode 100644
index 0000000..05864c5
--- /dev/null
+++ b/doc/guides/nics/szedata2.rst
@@ -0,0 +1,105 @@
+..  BSD LICENSE
+    Copyright 2015 CESNET
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+    * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+    * Neither the name of CESNET nor the names of its
+    contributors may be used to endorse or promote products derived
+    from this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+SZEDATA2 PMD
+============
+
+SZEDATA2 PMD is virtual PMD which uses sze2 layer to communicate with COMBO
+cards (COMBO-80G, COMBO-100G) using interface provided by libsze2 library.
+
+.. note::
+
+   This driver has external dependencies. Therefore it is disabled in default
+   configuration files. It can be enabled by setting CONFIG_RTE_LIBRTE_PMD_SZEDATA2=y
+   and recompiling.
+
+Prerequisities
+--------------
+
+This PMD requires kernel modules which are responsible for initialization and
+allocation of resources needed for sze2 layer function. Communication between
+PMD and kernel modules is mediated by libsze2 library. These kernel modules and
+library are not part of DPDK and must be installed separately:
+
+- **libsze2**
+
+  This library provides API for initialization of sze2 transfers, receiving and
+  transmitting data segments.
+
+- **Kernel modules**
+
+  These kernel modules manage initialization of hardware, allocation and sharing
+  of resources for user space applications:
+
+  - combov3
+  - szedata2_cv3
+
+Using PMD
+---------
+
+SZEDATA2 PMD can be created by passing --vdev= option to EAL in the following
+format:
+
+.. code-block:: console
+
+    --vdev 'DEVICE_NAME,dev_path=PATH_TO_SZEDATA2_DEVICE,rx_ifaces=RX_MASK,tx_ifaces=TX_MASK'
+
+DEVICE_NAME and options dev_path, rx_ifaces, tx_ifaces are mandatory and must
+be separated by commas.
+
+*   DEVICE_NAME: contains prefix eth_szedata2 followed by numbers or letters,
+    must be unique for each virtual device
+
+*   dev_path: Defines path to szedata2 device.
+    Value is valid path to szedata2 device.
+
+        dev_path=/dev/szedataII0
+
+*   rx_ifaces: Defines which receive channels will be used.
+    For each channel is created one queue. Value is mask for selecting which
+    receive channels are required.
+
+        rx_ifaces=0x3
+
+*   tx_ifaces: Defines which transmit channels will be used.
+    For each channel is created one queue. Value is mask for selecting which
+    transmit channels are required.
+
+        tx_ifaces=0x3
+
+Example of usage
+^^^^^^^^^^^^^^^^
+
+Read packets from 0. and 1. receive channel and write them to 0. and 1. transmit
+channel
+
+.. code-block:: console
+
+    $RTE_TARGET/app/testpmd -c 0xf -n 2 --vdev 'eth_szedata20,dev_path=/dev/szedataII0,rx_ifaces=0x3,tx_ifaces=0x3' -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2
diff --git a/doc/guides/prog_guide/source_org.rst b/doc/guides/prog_guide/source_org.rst
index ae11b3b..2393002 100644
--- a/doc/guides/prog_guide/source_org.rst
+++ b/doc/guides/prog_guide/source_org.rst
@@ -106,6 +106,7 @@ The drivers directory has a *net* subdirectory which contains::
     +-- null               # NULL poll mode driver for testing
     +-- pcap               # PCAP poll mode driver
     +-- ring               # Ring poll mode driver
+    +-- szedata2           # szedata2 poll mode driver
     +-- virtio             # Virtio poll mode driver
     +-- vmxnet3            # VMXNET3 poll mode driver
     +-- xenvirt            # Xen virtio poll mode driver
-- 
1.9.1

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

* [PATCH v2 5/5] doc: update 2.2 release notes
  2015-09-18  8:32 ` [PATCH v2 0/5] Virtual PMD using sze2 layer for COMBO cards Matej Vido
                     ` (3 preceding siblings ...)
  2015-09-18  8:32   ` [PATCH v2 4/5] doc: add documentation for szedata2 PMD Matej Vido
@ 2015-09-18  8:32   ` Matej Vido
  2015-09-24 16:23     ` [PATCH v2] doc: update the dpdk " John McNamara
  2015-11-10 14:18   ` [PATCH v3 0/6] Virtual PMD using sze2 layer for COMBO cards Matej Vido
  5 siblings, 1 reply; 36+ messages in thread
From: Matej Vido @ 2015-09-18  8:32 UTC (permalink / raw)
  To: dev

Add szedata2 PMD to 2.2 release notes.

Signed-off-by: Matej Vido <matejvido@gmail.com>
Reviewed-by: Jan Viktorin <viktorin@rehivetech.com>
---
 doc/guides/rel_notes/release_2_2.rst | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/doc/guides/rel_notes/release_2_2.rst b/doc/guides/rel_notes/release_2_2.rst
index 682f468..c78f94d 100644
--- a/doc/guides/rel_notes/release_2_2.rst
+++ b/doc/guides/rel_notes/release_2_2.rst
@@ -4,6 +4,10 @@ DPDK Release 2.2
 New Features
 ------------
 
+* **Added virtual szedata2 driver for COMBO cards.**
+
+  Added virtual PMD for COMBO-100G and COMBO-80G cards.
+  PMD is disabled in default configuration.
 
 Resolved Issues
 ---------------
-- 
1.9.1

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

* [PATCH v2] doc: update the dpdk 2.2 release notes
  2015-09-18  8:32   ` [PATCH v2 5/5] doc: update 2.2 release notes Matej Vido
@ 2015-09-24 16:23     ` John McNamara
  2015-09-24 21:14       ` Thomas Monjalon
  0 siblings, 1 reply; 36+ messages in thread
From: John McNamara @ 2015-09-24 16:23 UTC (permalink / raw)
  To: dev

Update the DPDK 2.2 release notes with recent fixes:

  7e01e3 i40e: fix base driver allocation when not using first numa node
  5e73f4 ixgbe: remove burst size restriction of vector Rx
  7fcd13 ixgbe: fix X550 DCB
  d49e0f hash: fix memory allocation of cuckoo key table
  9db649 eal/linux: fix epoll timeout

Signed-off-by: John McNamara <john.mcnamara@intel.com>
---

V2
* Added section headers to Resolved Issues.


 doc/guides/rel_notes/release_2_2.rst | 47 ++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/doc/guides/rel_notes/release_2_2.rst b/doc/guides/rel_notes/release_2_2.rst
index 682f468..547c071 100644
--- a/doc/guides/rel_notes/release_2_2.rst
+++ b/doc/guides/rel_notes/release_2_2.rst
@@ -8,6 +8,53 @@ New Features
 Resolved Issues
 ---------------
 
+EAL
+~~~
+
+* **eal/linux: Fixed epoll timeout.**
+
+  Fixed issue where the ``rte_epoll_wait()`` function didn't return when the
+  underlying call to ``epoll_wait()`` timed out.
+
+
+Libraries
+~~~~~~~~~
+
+* **hash: Fixed memory allocation of Cuckoo Hash key table.**
+
+  Fixed issue where an incorrect Cuckoo Hash key table size could be
+  calculated limiting the size to 4GB.
+
+  Fixes: 48a399119619 ("hash: replace with cuckoo hash implementation")
+
+
+Drivers
+~~~~~~~
+
+* **i40e: Fixed base driver allocation when not using first numa node.**
+
+  Fixed i40e issue that occurred when a DPDK application didn't initialize
+  ports if memory wasn't available on socket 0.
+
+
+* **ixgbe: Fixed issue with X550 DCB.**
+
+  Fixed a DCB issue with x550 where for 8 TCs (Traffic Classes), if a packet
+  with user priority 6 or 7 was injected to the NIC, then the NIC would only
+  put 3 packets into the queue. There was also a similar issue for 4 TCs.
+
+* **ixgbe: Removed burst size restriction of vector RX.**
+
+  Fixed issue where a burst size less than 32 didn't receive anything.
+
+
+Examples
+~~~~~~~~
+
+
+Other
+~~~~~
+
 
 Known Issues
 ------------
-- 
1.8.1.4

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

* Re: [PATCH v2] doc: update the dpdk 2.2 release notes
  2015-09-24 16:23     ` [PATCH v2] doc: update the dpdk " John McNamara
@ 2015-09-24 21:14       ` Thomas Monjalon
  0 siblings, 0 replies; 36+ messages in thread
From: Thomas Monjalon @ 2015-09-24 21:14 UTC (permalink / raw)
  To: John McNamara; +Cc: dev

2015-09-24 17:23, John McNamara:
> Update the DPDK 2.2 release notes with recent fixes:
> 
>   7e01e3 i40e: fix base driver allocation when not using first numa node
>   5e73f4 ixgbe: remove burst size restriction of vector Rx
>   7fcd13 ixgbe: fix X550 DCB
>   d49e0f hash: fix memory allocation of cuckoo key table
>   9db649 eal/linux: fix epoll timeout
> 
> Signed-off-by: John McNamara <john.mcnamara@intel.com>

Applied with small changes and one more recent fix.

I think we should not include Fixes: tags in the release notes.
It looks better to keep it small with focus on what was fixed.

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

* Re: [PATCH v2 3/5] szedata2: add handling of scattered packets in TX
  2015-09-18  8:32   ` [PATCH v2 3/5] szedata2: add handling of scattered packets in TX Matej Vido
@ 2015-10-26 14:55     ` Thomas Monjalon
  2015-10-27 17:40       ` Matej Vido
  0 siblings, 1 reply; 36+ messages in thread
From: Thomas Monjalon @ 2015-10-26 14:55 UTC (permalink / raw)
  To: Matej Vido; +Cc: dev

Hi Matej,

2015-09-18 10:32, Matej Vido:
> -			rte_memcpy(tmp_dst,
> -				rte_pktmbuf_mtod(mbuf, const void *),
> -				pkt_len);
> +			if (likely(mbuf_segs == 1)) {
> +				/*
> +				 * non-scattered packet,
> +				 * transmit from one mbuf
> +				 */
> +				rte_memcpy(tmp_dst,
> +					rte_pktmbuf_mtod(mbuf, const void *),
> +					pkt_len);

You could avoid this change by keeping "if (likely(mbuf_segs == 1))"
in the first patch.
By the way, it seems to be an abusive use of "likely".

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

* Re: [PATCH v2 4/5] doc: add documentation for szedata2 PMD
  2015-09-18  8:32   ` [PATCH v2 4/5] doc: add documentation for szedata2 PMD Matej Vido
@ 2015-10-26 15:00     ` Thomas Monjalon
  2015-10-26 15:09     ` Thomas Monjalon
  2015-10-30 12:16     ` Mcnamara, John
  2 siblings, 0 replies; 36+ messages in thread
From: Thomas Monjalon @ 2015-10-26 15:00 UTC (permalink / raw)
  To: john.mcnamara; +Cc: dev, Matej Vido

2015-09-18 10:32, Matej Vido:
> Signed-off-by: Matej Vido <matejvido@gmail.com>
> Reviewed-by: Jan Viktorin <viktorin@rehivetech.com>

Please John, could you review this new doc?
Thanks

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

* Re: [PATCH v2 4/5] doc: add documentation for szedata2 PMD
  2015-09-18  8:32   ` [PATCH v2 4/5] doc: add documentation for szedata2 PMD Matej Vido
  2015-10-26 15:00     ` Thomas Monjalon
@ 2015-10-26 15:09     ` Thomas Monjalon
  2015-10-27 17:33       ` Matej Vido
  2015-10-30 12:16     ` Mcnamara, John
  2 siblings, 1 reply; 36+ messages in thread
From: Thomas Monjalon @ 2015-10-26 15:09 UTC (permalink / raw)
  To: Matej Vido; +Cc: dev

Hi Matej,

Thanks for providing a documentation.
I'm sorry to give a late feedback and I would like that other contributors
have reviewed it. There are a lot of PMD developers around. Please help.


2015-09-18 10:32, Matej Vido:
> +- **libsze2**
> +
> +  This library provides API for initialization of sze2 transfers, receiving and
> +  transmitting data segments.

Please provide more information to help installing the dependencies.

> +SZEDATA2 PMD can be created by passing --vdev= option to EAL in the following
> +format:
> +
> +.. code-block:: console
> +
> +    --vdev 'DEVICE_NAME,dev_path=PATH_TO_SZEDATA2_DEVICE,rx_ifaces=RX_MASK,tx_ifaces=TX_MASK'

SZEDATA2 is not a vdev. Is it possible to probe it as a standard PCI device?

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

* Re: [PATCH v2 1/5] szedata2: add new poll mode driver
  2015-09-18  8:32   ` [PATCH v2 1/5] szedata2: add new poll mode driver Matej Vido
@ 2015-10-26 15:10     ` Thomas Monjalon
  0 siblings, 0 replies; 36+ messages in thread
From: Thomas Monjalon @ 2015-10-26 15:10 UTC (permalink / raw)
  To: Matej Vido; +Cc: dev

2015-09-18 10:32, Matej Vido:
> Add virtual PMD which communicates with COMBO cards through sze2
> layer using libsze2 library.
> 
> Since link_speed is uint16_t, there can not be used number for 100G
> speed, therefore link_speed is set to ETH_LINK_SPEED_10G until the
> type of link_speed is solved.
> 
> v2:
> Code cleanup.
> Fix error handling by initialization of rx, tx dma channels.
> Add uninit function.

There are some warnings raised by checkpatch.pl. Please check.

When sending a new version, it would be appreciated to introduce Rx/Tx
in another patch.

Thanks

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

* Re: [PATCH v2 4/5] doc: add documentation for szedata2 PMD
  2015-10-26 15:09     ` Thomas Monjalon
@ 2015-10-27 17:33       ` Matej Vido
  2015-10-27 18:00         ` Thomas Monjalon
  0 siblings, 1 reply; 36+ messages in thread
From: Matej Vido @ 2015-10-27 17:33 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

Hi Thomas,

thank you for feedback.

2015-10-26 16:09 GMT+01:00 Thomas Monjalon <thomas.monjalon@6wind.com>:

> Hi Matej,
>
> Thanks for providing a documentation.
> I'm sorry to give a late feedback and I would like that other contributors
> have reviewed it. There are a lot of PMD developers around. Please help.
>
>
> 2015-09-18 10:32, Matej Vido:
> > +- **libsze2**
> > +
> > +  This library provides API for initialization of sze2 transfers,
> receiving and
> > +  transmitting data segments.
>
> Please provide more information to help installing the dependencies.
>

Dependencies can be installed from RPM packages. I will add those
information in new patch version.


>
> > +SZEDATA2 PMD can be created by passing --vdev= option to EAL in the
> following
> > +format:
> > +
> > +.. code-block:: console
> > +
> > +    --vdev
> 'DEVICE_NAME,dev_path=PATH_TO_SZEDATA2_DEVICE,rx_ifaces=RX_MASK,tx_ifaces=TX_MASK'
>
> SZEDATA2 is not a vdev. Is it possible to probe it as a standard PCI
> device?
>
>
 It would be possible to probe it as a standard PCI device, but as this
szedata2 driver uses libsze2 library it needs to pass some parameters to
the library and we thought that using vdev would be the easiest solution.
Is there a way how to provide parameters to pdev driver?
We also work on a new PMD which will eliminate dependencies on kernel
modules and libsze2, and using this PMD COMBO card will be probed as a
standard PCI device.

Best regards,
Matej Vido

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

* Re: [PATCH v2 3/5] szedata2: add handling of scattered packets in TX
  2015-10-26 14:55     ` Thomas Monjalon
@ 2015-10-27 17:40       ` Matej Vido
  0 siblings, 0 replies; 36+ messages in thread
From: Matej Vido @ 2015-10-27 17:40 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

Hi Thomas,

2015-10-26 15:55 GMT+01:00 Thomas Monjalon <thomas.monjalon@6wind.com>:

> Hi Matej,
>
> 2015-09-18 10:32, Matej Vido:
> > -                     rte_memcpy(tmp_dst,
> > -                             rte_pktmbuf_mtod(mbuf, const void *),
> > -                             pkt_len);
> > +                     if (likely(mbuf_segs == 1)) {
> > +                             /*
> > +                              * non-scattered packet,
> > +                              * transmit from one mbuf
> > +                              */
> > +                             rte_memcpy(tmp_dst,
> > +                                     rte_pktmbuf_mtod(mbuf, const void
> *),
> > +                                     pkt_len);
>
> You could avoid this change by keeping "if (likely(mbuf_segs == 1))"
> in the first patch.
> By the way, it seems to be an abusive use of "likely".
>
>
I will edit it in v3. Thanks.

Best regards,
Matej Vido

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

* Re: [PATCH v2 4/5] doc: add documentation for szedata2 PMD
  2015-10-27 17:33       ` Matej Vido
@ 2015-10-27 18:00         ` Thomas Monjalon
  2015-11-02 14:26           ` Matej Vido
  0 siblings, 1 reply; 36+ messages in thread
From: Thomas Monjalon @ 2015-10-27 18:00 UTC (permalink / raw)
  To: Matej Vido; +Cc: dev

2015-10-27 18:33, Matej Vido:
> 2015-10-26 16:09 GMT+01:00 Thomas Monjalon <thomas.monjalon@6wind.com>:
> > SZEDATA2 is not a vdev. Is it possible to probe it as a standard PCI
> > device?
> >
> It would be possible to probe it as a standard PCI device, but as this
> szedata2 driver uses libsze2 library it needs to pass some parameters to
> the library and we thought that using vdev would be the easiest solution.
> Is there a way how to provide parameters to pdev driver?

No, but it could be added by working on unifying pdev and vdev.

> We also work on a new PMD which will eliminate dependencies on kernel
> modules and libsze2, and using this PMD COMBO card will be probed as a
> standard PCI device.

I think it's better to wait for your new implementation.
It would be nice to have it in the release 2.2.
Do you think it could be submitted in the coming weeks?

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

* Re: [PATCH v2 4/5] doc: add documentation for szedata2 PMD
  2015-09-18  8:32   ` [PATCH v2 4/5] doc: add documentation for szedata2 PMD Matej Vido
  2015-10-26 15:00     ` Thomas Monjalon
  2015-10-26 15:09     ` Thomas Monjalon
@ 2015-10-30 12:16     ` Mcnamara, John
  2015-11-06 14:34       ` Matej Vido
  2 siblings, 1 reply; 36+ messages in thread
From: Mcnamara, John @ 2015-10-30 12:16 UTC (permalink / raw)
  To: Matej Vido, dev

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Matej Vido
> Sent: Friday, September 18, 2015 9:33 AM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v2 4/5] doc: add documentation for szedata2 PMD
> 
> Signed-off-by: Matej Vido <matejvido@gmail.com>
> Reviewed-by: Jan Viktorin <viktorin@rehivetech.com>

Hi,

Thanks for the new PMD and the documentation.

The DPDJ documentation guidelines provide some guidance on how to format and build the DPDK documentation:

    http://dpdk.org/doc/guides/contributing/documentation.html

In terms of documentation for a PMD the Mellanox MLX4 docs are a good example:

    http://dpdk.org/doc/guides/nics/mlx4.html

Some other comments below:




> +SZEDATA2 PMD
> +============

No need for an acronym in the title. Follow the MLX4 example and use something like " SZEDATA2 poll mode driver library".



> +SZEDATA2 PMD is virtual PMD which uses sze2 layer to communicate with
> +COMBO cards (COMBO-80G, COMBO-100G) using interface provided by libsze2
> library.

The introduction can be brief but should include enough information to explain the PMD for someone encountering it for the first time.

Some links would help with this. See the MLX4 doc as an example:


> +
> +.. note::
> +
> +   This driver has external dependencies. Therefore it is disabled in
> default
> +   configuration files. It can be enabled by setting
> CONFIG_RTE_LIBRTE_PMD_SZEDATA2=y

Format configuration items as verbatim text with  double backquotes:`` CONFIG_RTE_LIBRTE_PMD_SZEDATA2=y ``


> +
> +Using PMD
> +---------

Better: Using the Szedata PMD



> +
> +SZEDATA2 PMD can be created by passing --vdev= option to EAL in the

Again format --vdev as ``--vdev``. Also apply to other similar cases.



> +following format:
> +
> +.. code-block:: console
> +
> +    --vdev
> 'DEVICE_NAME,dev_path=PATH_TO_SZEDATA2_DEVICE,rx_ifaces=RX_MASK,tx_ifaces=
> TX_MASK'

This code line exceeds 80 chars and will exceed the page width in the PDF docs. If possible see if it can be shortened. Maybe use DEVICE instead of DEVICE_NAME and PATH instead of PATH_TO. The next section has an explanation anyway.


> +
> +DEVICE_NAME and options dev_path, rx_ifaces, tx_ifaces are mandatory
> +and must be separated by commas.

Use the ```` quotes again.


> +
> +*   DEVICE_NAME: contains prefix eth_szedata2 followed by numbers or
> letters,
> +    must be unique for each virtual device
> +
> +*   dev_path: Defines path to szedata2 device.
> +    Value is valid path to szedata2 device.
> +
> +        dev_path=/dev/szedataII0

Code blocks should be prefixed by :: to render them correctly. See the guidelines and also view the output from "make doc-guides-html".

Same for the other items below.


> +
> +Example of usage
> +^^^^^^^^^^^^^^^^

The convention is to use ~~~~~ for third level headings (see the guidelines). However, this could probably be a second level heading.


> +
> +Read packets from 0. and 1. receive channel and write them to 0. and 1.
> +transmit channel
> +
> +.. code-block:: console
> +
> +    $RTE_TARGET/app/testpmd -c 0xf -n 2 --vdev
> + 'eth_szedata20,dev_path=/dev/szedataII0,rx_ifaces=0x3,tx_ifaces=0x3'
> + -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2


Again this code line is >80 chars and won't look good in the PDF. I'd suggest the following:

testpmd -c 0xf -n 2 \
 --vdev 'eth_szedata20,dev_path=/dev/szedataII0,rx_ifaces=3,tx_ifaces=3' \
 -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2



> diff --git a/doc/guides/prog_guide/source_org.rst
> b/doc/guides/prog_guide/source_org.rst
> index ae11b3b..2393002 100644
> --- a/doc/guides/prog_guide/source_org.rst
> +++ b/doc/guides/prog_guide/source_org.rst
> @@ -106,6 +106,7 @@ The drivers directory has a *net* subdirectory which
> contains::
>      +-- null               # NULL poll mode driver for testing
>      +-- pcap               # PCAP poll mode driver
>      +-- ring               # Ring poll mode driver
> +    +-- szedata2           # szedata2 poll mode driver
>      +-- virtio             # Virtio poll mode driver
>      +-- vmxnet3            # VMXNET3 poll mode driver
>      +-- xenvirt            # Xen virtio poll mode driver

It isn't necessary to update this section. It is meant to be representative rather than comprehensive (at least to me). However if you leave it in then captilize the name like the others.


Thanks,

John

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

* Re: [PATCH v2 4/5] doc: add documentation for szedata2 PMD
  2015-10-27 18:00         ` Thomas Monjalon
@ 2015-11-02 14:26           ` Matej Vido
  0 siblings, 0 replies; 36+ messages in thread
From: Matej Vido @ 2015-11-02 14:26 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

Hi Thomas,

2015-10-27 19:00 GMT+01:00 Thomas Monjalon <thomas.monjalon@6wind.com>:

> 2015-10-27 18:33, Matej Vido:
> > 2015-10-26 16:09 GMT+01:00 Thomas Monjalon <thomas.monjalon@6wind.com>:
> > > SZEDATA2 is not a vdev. Is it possible to probe it as a standard PCI
> > > device?
> > >
> > It would be possible to probe it as a standard PCI device, but as this
> > szedata2 driver uses libsze2 library it needs to pass some parameters to
> > the library and we thought that using vdev would be the easiest solution.
> > Is there a way how to provide parameters to pdev driver?
>
> No, but it could be added by working on unifying pdev and vdev.
>
> > We also work on a new PMD which will eliminate dependencies on kernel
> > modules and libsze2, and using this PMD COMBO card will be probed as a
> > standard PCI device.
>
> I think it's better to wait for your new implementation.
> It would be nice to have it in the release 2.2.
> Do you think it could be submitted in the coming weeks?
>


We will not manage to submit the new driver implementation in the release
2.2. Any chance to get this virtual driver into 2.2?

Matej Vido

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

* Re: [PATCH v2 4/5] doc: add documentation for szedata2 PMD
  2015-10-30 12:16     ` Mcnamara, John
@ 2015-11-06 14:34       ` Matej Vido
  0 siblings, 0 replies; 36+ messages in thread
From: Matej Vido @ 2015-11-06 14:34 UTC (permalink / raw)
  To: Mcnamara, John; +Cc: dev

Hi John,

Thank you for your comments and advice. I will follow them in the new
version.

Regards,
Matej Vido


2015-10-30 13:16 GMT+01:00 Mcnamara, John <john.mcnamara@intel.com>:

> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Matej Vido
> > Sent: Friday, September 18, 2015 9:33 AM
> > To: dev@dpdk.org
> > Subject: [dpdk-dev] [PATCH v2 4/5] doc: add documentation for szedata2
> PMD
> >
> > Signed-off-by: Matej Vido <matejvido@gmail.com>
> > Reviewed-by: Jan Viktorin <viktorin@rehivetech.com>
>
> Hi,
>
> Thanks for the new PMD and the documentation.
>
> The DPDJ documentation guidelines provide some guidance on how to format
> and build the DPDK documentation:
>
>     http://dpdk.org/doc/guides/contributing/documentation.html
>
> In terms of documentation for a PMD the Mellanox MLX4 docs are a good
> example:
>
>     http://dpdk.org/doc/guides/nics/mlx4.html
>
> Some other comments below:
>
>
>
>
> > +SZEDATA2 PMD
> > +============
>
> No need for an acronym in the title. Follow the MLX4 example and use
> something like " SZEDATA2 poll mode driver library".
>
>
>
> > +SZEDATA2 PMD is virtual PMD which uses sze2 layer to communicate with
> > +COMBO cards (COMBO-80G, COMBO-100G) using interface provided by libsze2
> > library.
>
> The introduction can be brief but should include enough information to
> explain the PMD for someone encountering it for the first time.
>
> Some links would help with this. See the MLX4 doc as an example:
>
>
> > +
> > +.. note::
> > +
> > +   This driver has external dependencies. Therefore it is disabled in
> > default
> > +   configuration files. It can be enabled by setting
> > CONFIG_RTE_LIBRTE_PMD_SZEDATA2=y
>
> Format configuration items as verbatim text with  double backquotes:``
> CONFIG_RTE_LIBRTE_PMD_SZEDATA2=y ``
>
>
> > +
> > +Using PMD
> > +---------
>
> Better: Using the Szedata PMD
>
>
>
> > +
> > +SZEDATA2 PMD can be created by passing --vdev= option to EAL in the
>
> Again format --vdev as ``--vdev``. Also apply to other similar cases.
>
>
>
> > +following format:
> > +
> > +.. code-block:: console
> > +
> > +    --vdev
> >
> 'DEVICE_NAME,dev_path=PATH_TO_SZEDATA2_DEVICE,rx_ifaces=RX_MASK,tx_ifaces=
> > TX_MASK'
>
> This code line exceeds 80 chars and will exceed the page width in the PDF
> docs. If possible see if it can be shortened. Maybe use DEVICE instead of
> DEVICE_NAME and PATH instead of PATH_TO. The next section has an
> explanation anyway.
>
>
> > +
> > +DEVICE_NAME and options dev_path, rx_ifaces, tx_ifaces are mandatory
> > +and must be separated by commas.
>
> Use the ```` quotes again.
>
>
> > +
> > +*   DEVICE_NAME: contains prefix eth_szedata2 followed by numbers or
> > letters,
> > +    must be unique for each virtual device
> > +
> > +*   dev_path: Defines path to szedata2 device.
> > +    Value is valid path to szedata2 device.
> > +
> > +        dev_path=/dev/szedataII0
>
> Code blocks should be prefixed by :: to render them correctly. See the
> guidelines and also view the output from "make doc-guides-html".
>
> Same for the other items below.
>
>
> > +
> > +Example of usage
> > +^^^^^^^^^^^^^^^^
>
> The convention is to use ~~~~~ for third level headings (see the
> guidelines). However, this could probably be a second level heading.
>
>
> > +
> > +Read packets from 0. and 1. receive channel and write them to 0. and 1.
> > +transmit channel
> > +
> > +.. code-block:: console
> > +
> > +    $RTE_TARGET/app/testpmd -c 0xf -n 2 --vdev
> > + 'eth_szedata20,dev_path=/dev/szedataII0,rx_ifaces=0x3,tx_ifaces=0x3'
> > + -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2
>
>
> Again this code line is >80 chars and won't look good in the PDF. I'd
> suggest the following:
>
> testpmd -c 0xf -n 2 \
>  --vdev 'eth_szedata20,dev_path=/dev/szedataII0,rx_ifaces=3,tx_ifaces=3' \
>  -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2
>
>
>
> > diff --git a/doc/guides/prog_guide/source_org.rst
> > b/doc/guides/prog_guide/source_org.rst
> > index ae11b3b..2393002 100644
> > --- a/doc/guides/prog_guide/source_org.rst
> > +++ b/doc/guides/prog_guide/source_org.rst
> > @@ -106,6 +106,7 @@ The drivers directory has a *net* subdirectory which
> > contains::
> >      +-- null               # NULL poll mode driver for testing
> >      +-- pcap               # PCAP poll mode driver
> >      +-- ring               # Ring poll mode driver
> > +    +-- szedata2           # szedata2 poll mode driver
> >      +-- virtio             # Virtio poll mode driver
> >      +-- vmxnet3            # VMXNET3 poll mode driver
> >      +-- xenvirt            # Xen virtio poll mode driver
>
> It isn't necessary to update this section. It is meant to be
> representative rather than comprehensive (at least to me). However if you
> leave it in then captilize the name like the others.
>
>
> Thanks,
>
> John
>

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

* [PATCH v3 0/6] Virtual PMD using sze2 layer for COMBO cards
  2015-09-18  8:32 ` [PATCH v2 0/5] Virtual PMD using sze2 layer for COMBO cards Matej Vido
                     ` (4 preceding siblings ...)
  2015-09-18  8:32   ` [PATCH v2 5/5] doc: update 2.2 release notes Matej Vido
@ 2015-11-10 14:18   ` Matej Vido
  2015-11-10 14:18     ` [PATCH v3 1/6] szedata2: add new poll mode driver Matej Vido
                       ` (6 more replies)
  5 siblings, 7 replies; 36+ messages in thread
From: Matej Vido @ 2015-11-10 14:18 UTC (permalink / raw)
  To: dev

This is virtual PMD which communicates with COMBO-80G and COMBO-100G
cards through sze2 layer. Communication with COMBO card is managed
through interface provided by libsze2 library and kernel modules
(combov3, szedata2_cv3).

To compile and use PMD, it is necessary to have libsze2 library installed and
kernel modules (combov3, szedata2_cv3) loaded.
Therefore in default configuration PMD compilation is disabled. To compile
szedata2 PMD, it is necessary to enable CONFIG_RTE_LIBRTE_PMD_SZEDATA2=y.

v3:
Fix checkpatch.pl issues.
Edit documentation.
Introduce RX and TX in separate patches.

v2:
code cleanup
add handling scattered packets
update release notes

Matej Vido (6):
  szedata2: add new poll mode driver
  szedata2: add non-scattered RX function
  szedata2: add TX function
  szedata2: add support for scattered packets in RX
  doc: add documentation for szedata2 PMD
  doc: update 2.2 release notes

 config/common_bsdapp                              |    5 +
 config/common_linuxapp                            |    5 +
 doc/guides/nics/index.rst                         |    1 +
 doc/guides/nics/szedata2.rst                      |  127 ++
 doc/guides/prog_guide/source_org.rst              |    1 +
 doc/guides/rel_notes/release_2_2.rst              |    4 +
 drivers/net/Makefile                              |    1 +
 drivers/net/szedata2/Makefile                     |   62 +
 drivers/net/szedata2/rte_eth_szedata2.c           | 1624 +++++++++++++++++++++
 drivers/net/szedata2/rte_eth_szedata2.h           |  102 ++
 drivers/net/szedata2/rte_pmd_szedata2_version.map |    3 +
 mk/rte.app.mk                                     |    3 +
 12 files changed, 1938 insertions(+)
 create mode 100644 doc/guides/nics/szedata2.rst
 create mode 100644 drivers/net/szedata2/Makefile
 create mode 100644 drivers/net/szedata2/rte_eth_szedata2.c
 create mode 100644 drivers/net/szedata2/rte_eth_szedata2.h
 create mode 100644 drivers/net/szedata2/rte_pmd_szedata2_version.map

-- 
1.9.1

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

* [PATCH v3 1/6] szedata2: add new poll mode driver
  2015-11-10 14:18   ` [PATCH v3 0/6] Virtual PMD using sze2 layer for COMBO cards Matej Vido
@ 2015-11-10 14:18     ` Matej Vido
  2015-11-20 15:04       ` Thomas Monjalon
  2015-11-10 14:18     ` [PATCH v3 2/6] szedata2: add non-scattered RX function Matej Vido
                       ` (5 subsequent siblings)
  6 siblings, 1 reply; 36+ messages in thread
From: Matej Vido @ 2015-11-10 14:18 UTC (permalink / raw)
  To: dev

Add virtual PMD which communicates with COMBO cards through sze2
layer using libsze2 library.

Since link_speed is uint16_t, there can not be used number for 100G
speed, therefore link_speed is set to ETH_LINK_SPEED_10G until the
type of link_speed is solved.

v3:
Fix checkpatch.pl issues.
Move RX, TX functions to separate patches.

v2:
Code cleanup.
Fix error handling by initialization of rx, tx dma channels.
Add uninit function.

Signed-off-by: Matej Vido <matejvido@gmail.com>
---
 config/common_bsdapp                              |   5 +
 config/common_linuxapp                            |   5 +
 drivers/net/Makefile                              |   1 +
 drivers/net/szedata2/Makefile                     |  62 ++
 drivers/net/szedata2/rte_eth_szedata2.c           | 830 ++++++++++++++++++++++
 drivers/net/szedata2/rte_eth_szedata2.h           | 102 +++
 drivers/net/szedata2/rte_pmd_szedata2_version.map |   3 +
 mk/rte.app.mk                                     |   3 +
 8 files changed, 1011 insertions(+)
 create mode 100644 drivers/net/szedata2/Makefile
 create mode 100644 drivers/net/szedata2/rte_eth_szedata2.c
 create mode 100644 drivers/net/szedata2/rte_eth_szedata2.h
 create mode 100644 drivers/net/szedata2/rte_pmd_szedata2_version.map

diff --git a/config/common_bsdapp b/config/common_bsdapp
index fba29e5..cd856ad 100644
--- a/config/common_bsdapp
+++ b/config/common_bsdapp
@@ -284,6 +284,11 @@ CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
 CONFIG_RTE_LIBRTE_PMD_PCAP=y
 
 #
+# Compile software PMD backed by SZEDATA2 device
+#
+CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
+
+#
 # Compile link bonding PMD library
 #
 CONFIG_RTE_LIBRTE_PMD_BOND=y
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 7248262..fef5bde 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -282,6 +282,11 @@ CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
 CONFIG_RTE_LIBRTE_PMD_PCAP=n
 
 #
+# Compile software PMD backed by SZEDATA2 device
+#
+CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n
+
+#
 # Compile link bonding PMD library
 #
 CONFIG_RTE_LIBRTE_PMD_BOND=y
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 6da1ce2..e05d2e5 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -49,6 +49,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_RING) += ring
 DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio
 DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += vmxnet3
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += xenvirt
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += szedata2
 
 include $(RTE_SDK)/mk/rte.sharelib.mk
 include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/drivers/net/szedata2/Makefile b/drivers/net/szedata2/Makefile
new file mode 100644
index 0000000..c3c42e5
--- /dev/null
+++ b/drivers/net/szedata2/Makefile
@@ -0,0 +1,62 @@
+#   BSD LICENSE
+#
+#   Copyright (c) 2015 CESNET
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of CESNET nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_szedata2.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+EXPORT_MAP := rte_pmd_szedata2_version.map
+
+LIBABIVER := 1
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += rte_eth_szedata2.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += lib/librte_malloc
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += lib/librte_kvargs
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/szedata2/rte_eth_szedata2.c b/drivers/net/szedata2/rte_eth_szedata2.c
new file mode 100644
index 0000000..7edaefc
--- /dev/null
+++ b/drivers/net/szedata2/rte_eth_szedata2.c
@@ -0,0 +1,830 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (c) 2015 CESNET
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of CESNET nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <err.h>
+
+#include <libsze2.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_kvargs.h>
+#include <rte_dev.h>
+
+#include "rte_eth_szedata2.h"
+
+#define RTE_ETH_SZEDATA2_DEV_PATH_ARG "dev_path"
+#define RTE_ETH_SZEDATA2_RX_IFACES_ARG "rx_ifaces"
+#define RTE_ETH_SZEDATA2_TX_IFACES_ARG "tx_ifaces"
+
+#define RTE_ETH_SZEDATA2_MAX_RX_QUEUES 32
+#define RTE_ETH_SZEDATA2_MAX_TX_QUEUES 32
+#define RTE_ETH_SZEDATA2_TX_LOCK_SIZE (32 * 1024 * 1024)
+
+/**
+ * size of szedata2_packet header with alignment
+ */
+#define RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED 8
+
+struct szedata2_rx_queue {
+	struct szedata *sze;
+	uint8_t rx_channel;
+	uint8_t in_port;
+	struct rte_mempool *mb_pool;
+	volatile uint64_t rx_pkts;
+	volatile uint64_t rx_bytes;
+	volatile uint64_t err_pkts;
+};
+
+struct szedata2_tx_queue {
+	struct szedata *sze;
+	uint8_t tx_channel;
+	volatile uint64_t tx_pkts;
+	volatile uint64_t err_pkts;
+	volatile uint64_t tx_bytes;
+};
+
+struct rxtx_szedata2 {
+	uint32_t num_of_rx;
+	uint32_t num_of_tx;
+	uint32_t sze_rx_mask_req;
+	uint32_t sze_tx_mask_req;
+	char *sze_dev;
+};
+
+struct pmd_internals {
+	struct szedata2_rx_queue rx_queue[RTE_ETH_SZEDATA2_MAX_RX_QUEUES];
+	struct szedata2_tx_queue tx_queue[RTE_ETH_SZEDATA2_MAX_TX_QUEUES];
+	unsigned nb_rx_queues;
+	unsigned nb_tx_queues;
+	uint32_t num_of_rx;
+	uint32_t num_of_tx;
+	uint32_t sze_rx_req;
+	uint32_t sze_tx_req;
+	int if_index;
+	char *sze_dev;
+};
+
+static const char *valid_arguments[] = {
+	RTE_ETH_SZEDATA2_DEV_PATH_ARG,
+	RTE_ETH_SZEDATA2_RX_IFACES_ARG,
+	RTE_ETH_SZEDATA2_TX_IFACES_ARG,
+	NULL
+};
+
+static struct ether_addr eth_addr = {
+	.addr_bytes = { 0x00, 0x11, 0x17, 0x00, 0x00, 0x00 }
+};
+static const char *drivername = "SZEdata2 PMD";
+static struct rte_eth_link pmd_link = {
+		.link_speed = ETH_LINK_SPEED_10G,
+		.link_duplex = ETH_LINK_FULL_DUPLEX,
+		.link_status = 0
+};
+
+
+static uint32_t
+count_ones(uint32_t num)
+{
+	num = num - ((num >> 1) & 0x55555555); /* reuse input as temporary */
+	num = (num & 0x33333333) + ((num >> 2) & 0x33333333);        /* temp */
+	return (((num + (num >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; /* count */
+}
+
+static int
+init_rx_channels(struct rte_eth_dev *dev, int v)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	int ret;
+	uint32_t i;
+	uint32_t count = internals->num_of_rx;
+	uint32_t num_sub = 0;
+	uint32_t x;
+	uint32_t rx;
+	uint32_t tx;
+
+	rx = internals->sze_rx_req;
+	tx = 0;
+
+	for (i = 0; i < count; i++) {
+		/*
+		 * Open, subscribe rx,tx channels and start device
+		 */
+		if (v)
+			RTE_LOG(INFO, PMD, "Opening SZE device %u. time\n", i);
+
+		internals->rx_queue[num_sub].sze =
+			szedata_open(internals->sze_dev);
+		if (internals->rx_queue[num_sub].sze == NULL)
+			return -1;
+
+		/* separate least significant non-zero bit */
+		x = rx & ((~rx) + 1);
+
+		if (v)
+			RTE_LOG(INFO, PMD, "Subscribing rx channel: 0x%x "
+				"tx channel: 0x%x\n", x, tx);
+
+		ret = szedata_subscribe3(internals->rx_queue[num_sub].sze,
+				&x, &tx);
+		if (ret) {
+			szedata_close(internals->rx_queue[num_sub].sze);
+			internals->rx_queue[num_sub].sze = NULL;
+			return -1;
+		}
+
+		if (v)
+			RTE_LOG(INFO, PMD, "Subscribed rx channel: 0x%x "
+				"tx channel: 0x%x\n", x, tx);
+
+		if (x) {
+			if (v)
+				RTE_LOG(INFO, PMD, "Starting SZE device for "
+					"rx queue: %u\n", num_sub);
+
+			ret = szedata_start(internals->rx_queue[num_sub].sze);
+			if (ret) {
+				szedata_close(internals->rx_queue[num_sub].sze);
+				internals->rx_queue[num_sub].sze = NULL;
+				return -1;
+			}
+
+			/*
+			 * set to 1 all bits lower than bit set to 1
+			 * and that bit to 0
+			 */
+			x -= 1;
+			internals->rx_queue[num_sub].rx_channel =
+				count_ones(x);
+
+			if (v)
+				RTE_LOG(INFO, PMD, "Subscribed rx channel "
+					"no: %u\n",
+					internals->rx_queue[num_sub].rx_channel
+					);
+
+			num_sub++;
+			internals->nb_rx_queues = num_sub;
+		} else {
+			if (v)
+				RTE_LOG(INFO, PMD,
+					"Could not subscribe any rx channel. "
+					"Closing SZE device\n");
+
+			szedata_close(internals->rx_queue[num_sub].sze);
+			internals->rx_queue[num_sub].sze = NULL;
+		}
+
+		/* set least significant non-zero bit to zero */
+		rx = rx & (rx - 1);
+	}
+
+	dev->data->nb_rx_queues = (uint16_t)num_sub;
+
+	if (v)
+		RTE_LOG(INFO, PMD, "Successfully opened rx channels: %u\n",
+			num_sub);
+
+	return 0;
+}
+
+static int
+init_tx_channels(struct rte_eth_dev *dev, int v)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	int ret;
+	uint32_t i;
+	uint32_t count = internals->num_of_tx;
+	uint32_t num_sub = 0;
+	uint32_t x;
+	uint32_t rx;
+	uint32_t tx;
+
+	rx = 0;
+	tx = internals->sze_tx_req;
+
+	for (i = 0; i < count; i++) {
+		/*
+		 * Open, subscribe rx,tx channels and start device
+		 */
+		if (v)
+			RTE_LOG(INFO, PMD, "Opening SZE device %u. time\n",
+				i + internals->num_of_rx);
+
+		internals->tx_queue[num_sub].sze =
+			szedata_open(internals->sze_dev);
+		if (internals->tx_queue[num_sub].sze == NULL)
+			return -1;
+
+		/* separate least significant non-zero bit */
+		x = tx & ((~tx) + 1);
+
+		if (v)
+			RTE_LOG(INFO, PMD, "Subscribing rx channel: 0x%x "
+				"tx channel: 0x%x\n", rx, x);
+
+		ret = szedata_subscribe3(internals->tx_queue[num_sub].sze,
+				&rx, &x);
+		if (ret) {
+			szedata_close(internals->tx_queue[num_sub].sze);
+			internals->tx_queue[num_sub].sze = NULL;
+			return -1;
+		}
+
+		if (v)
+			RTE_LOG(INFO, PMD, "Subscribed rx channel: 0x%x "
+				"tx channel: 0x%x\n", rx, x);
+
+		if (x) {
+			if (v)
+				RTE_LOG(INFO, PMD, "Starting SZE device for "
+					"tx queue: %u\n", num_sub);
+
+			ret = szedata_start(internals->tx_queue[num_sub].sze);
+			if (ret) {
+				szedata_close(internals->tx_queue[num_sub].sze);
+				internals->tx_queue[num_sub].sze = NULL;
+				return -1;
+			}
+
+			/*
+			 * set to 1 all bits lower than bit set to 1
+			 * and that bit to 0
+			 */
+			x -= 1;
+			internals->tx_queue[num_sub].tx_channel =
+				count_ones(x);
+
+			if (v)
+				RTE_LOG(INFO, PMD, "Subscribed tx channel "
+					"no: %u\n",
+					internals->tx_queue[num_sub].tx_channel
+					);
+
+			num_sub++;
+			internals->nb_tx_queues = num_sub;
+		} else {
+			if (v)
+				RTE_LOG(INFO, PMD,
+					"Could not subscribe any tx channel. "
+					"Closing SZE device\n");
+
+			szedata_close(internals->tx_queue[num_sub].sze);
+			internals->tx_queue[num_sub].sze = NULL;
+		}
+
+		/* set least significant non-zero bit to zero */
+		tx = tx & (tx - 1);
+	}
+
+	dev->data->nb_tx_queues = (uint16_t)num_sub;
+
+	if (v)
+		RTE_LOG(INFO, PMD, "Successfully opened tx channels: %u\n",
+			num_sub);
+
+	return 0;
+}
+
+static void
+close_rx_channels(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	uint32_t i;
+	uint32_t num_sub = internals->nb_rx_queues;
+
+	for (i = 0; i < num_sub; i++) {
+		if (internals->rx_queue[i].sze != NULL) {
+			szedata_close(internals->rx_queue[i].sze);
+			internals->rx_queue[i].sze = NULL;
+		}
+	}
+	/* set number of rx queues to zero */
+	internals->nb_rx_queues = 0;
+	dev->data->nb_rx_queues = (uint16_t)0;
+}
+
+static void
+close_tx_channels(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	uint32_t i;
+	uint32_t num_sub = internals->nb_tx_queues;
+
+	for (i = 0; i < num_sub; i++) {
+		if (internals->tx_queue[i].sze != NULL) {
+			szedata_close(internals->tx_queue[i].sze);
+			internals->tx_queue[i].sze = NULL;
+		}
+	}
+	/* set number of rx queues to zero */
+	internals->nb_tx_queues = 0;
+	dev->data->nb_tx_queues = (uint16_t)0;
+}
+
+static int
+eth_dev_start(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	int ret;
+
+	if (internals->nb_rx_queues == 0) {
+		ret = init_rx_channels(dev, 0);
+		if (ret != 0) {
+			close_rx_channels(dev);
+			return -1;
+		}
+	}
+
+	if (internals->nb_tx_queues == 0) {
+		ret = init_tx_channels(dev, 0);
+		if (ret != 0) {
+			close_tx_channels(dev);
+			close_rx_channels(dev);
+			return -1;
+		}
+	}
+
+	dev->data->dev_link.link_status = 1;
+	return 0;
+}
+
+static void
+eth_dev_stop(struct rte_eth_dev *dev)
+{
+	unsigned i;
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	for (i = 0; i < internals->nb_rx_queues; i++) {
+		if (internals->rx_queue[i].sze != NULL) {
+			szedata_close(internals->rx_queue[i].sze);
+			internals->rx_queue[i].sze = NULL;
+		}
+	}
+
+	for (i = 0; i < internals->nb_tx_queues; i++) {
+		if (internals->tx_queue[i].sze != NULL) {
+			szedata_close(internals->tx_queue[i].sze);
+			internals->tx_queue[i].sze = NULL;
+		}
+	}
+
+	internals->nb_rx_queues = 0;
+	internals->nb_tx_queues = 0;
+
+	dev->data->nb_rx_queues = (uint16_t)0;
+	dev->data->nb_tx_queues = (uint16_t)0;
+
+	dev->data->dev_link.link_status = 0;
+}
+
+static int
+eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+static void
+eth_dev_info(struct rte_eth_dev *dev,
+		struct rte_eth_dev_info *dev_info)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	dev_info->driver_name = drivername;
+	dev_info->if_index = internals->if_index;
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = (uint16_t)internals->nb_rx_queues;
+	dev_info->max_tx_queues = (uint16_t)internals->nb_tx_queues;
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = NULL;
+}
+
+static void
+eth_stats_get(struct rte_eth_dev *dev,
+		struct rte_eth_stats *igb_stats)
+{
+	unsigned i;
+	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;
+	const struct pmd_internals *internal = dev->data->dev_private;
+
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_rx_queues; i++) {
+		igb_stats->q_ipackets[i] = internal->rx_queue[i].rx_pkts;
+		igb_stats->q_ibytes[i] = internal->rx_queue[i].rx_bytes;
+		rx_total += igb_stats->q_ipackets[i];
+		rx_total_bytes += igb_stats->q_ibytes[i];
+	}
+
+	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
+			i < internal->nb_tx_queues; i++) {
+		igb_stats->q_opackets[i] = internal->tx_queue[i].tx_pkts;
+		igb_stats->q_errors[i] = internal->tx_queue[i].err_pkts;
+		igb_stats->q_obytes[i] = internal->tx_queue[i].tx_bytes;
+		tx_total += igb_stats->q_opackets[i];
+		tx_err_total += igb_stats->q_errors[i];
+		tx_total_bytes += igb_stats->q_obytes[i];
+	}
+
+	igb_stats->ipackets = rx_total;
+	igb_stats->opackets = tx_total;
+	igb_stats->ibytes = rx_total_bytes;
+	igb_stats->obytes = tx_total_bytes;
+	igb_stats->oerrors = tx_err_total;
+}
+
+static void
+eth_stats_reset(struct rte_eth_dev *dev)
+{
+	unsigned i;
+	struct pmd_internals *internal = dev->data->dev_private;
+	for (i = 0; i < internal->nb_rx_queues; i++) {
+		internal->rx_queue[i].rx_pkts = 0;
+		internal->rx_queue[i].rx_bytes = 0;
+	}
+	for (i = 0; i < internal->nb_tx_queues; i++) {
+		internal->tx_queue[i].tx_pkts = 0;
+		internal->tx_queue[i].err_pkts = 0;
+		internal->tx_queue[i].tx_bytes = 0;
+	}
+}
+
+static void
+eth_dev_close(struct rte_eth_dev *dev)
+{
+	unsigned i;
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	for (i = 0; i < internals->nb_rx_queues; i++) {
+		if (internals->rx_queue[i].sze != NULL) {
+			szedata_close(internals->rx_queue[i].sze);
+			internals->rx_queue[i].sze = NULL;
+		}
+	}
+
+	for (i = 0; i < internals->nb_tx_queues; i++) {
+		if (internals->tx_queue[i].sze != NULL) {
+			szedata_close(internals->tx_queue[i].sze);
+			internals->tx_queue[i].sze = NULL;
+		}
+	}
+
+	internals->nb_rx_queues = 0;
+	internals->nb_tx_queues = 0;
+
+	dev->data->nb_rx_queues = (uint16_t)0;
+	dev->data->nb_tx_queues = (uint16_t)0;
+}
+
+static void
+eth_queue_release(void *q __rte_unused)
+{
+}
+
+static int
+eth_link_update(struct rte_eth_dev *dev __rte_unused,
+		int wait_to_complete __rte_unused)
+{
+	return 0;
+}
+
+static int
+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 __rte_unused,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	struct szedata2_rx_queue *szedata2_q =
+		&internals->rx_queue[rx_queue_id];
+	szedata2_q->mb_pool = mb_pool;
+	dev->data->rx_queues[rx_queue_id] = szedata2_q;
+	szedata2_q->in_port = dev->data->port_id;
+	return 0;
+}
+
+static int
+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 __rte_unused,
+		const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	dev->data->tx_queues[tx_queue_id] = &internals->tx_queue[tx_queue_id];
+	return 0;
+}
+
+static void
+eth_mac_addr_set(struct rte_eth_dev *dev __rte_unused,
+		struct ether_addr *mac_addr __rte_unused)
+{
+}
+
+static struct eth_dev_ops ops = {
+		.dev_start          = eth_dev_start,
+		.dev_stop           = eth_dev_stop,
+		.dev_close          = eth_dev_close,
+		.dev_configure      = eth_dev_configure,
+		.dev_infos_get      = eth_dev_info,
+		.rx_queue_setup     = eth_rx_queue_setup,
+		.tx_queue_setup     = eth_tx_queue_setup,
+		.rx_queue_release   = eth_queue_release,
+		.tx_queue_release   = eth_queue_release,
+		.link_update        = eth_link_update,
+		.stats_get          = eth_stats_get,
+		.stats_reset        = eth_stats_reset,
+		.mac_addr_set       = eth_mac_addr_set,
+};
+
+static int
+parse_mask(const char *mask_str, uint32_t *mask_num)
+{
+	char *endptr;
+	long int value;
+
+	value = strtol(mask_str, &endptr, 0);
+	if (*endptr != '\0' || value > UINT32_MAX || value < 0)
+		return -1;
+
+	*mask_num = (uint32_t)value;
+	return 0;
+}
+
+static int
+add_rx_mask(const char *key __rte_unused, const char *value, void *extra_args)
+{
+	struct rxtx_szedata2 *szedata2 = extra_args;
+	uint32_t mask;
+
+	if (parse_mask(value, &mask) != 0)
+		return -1;
+
+	szedata2->sze_rx_mask_req |= mask;
+	return 0;
+}
+
+static int
+add_tx_mask(const char *key __rte_unused, const char *value, void *extra_args)
+{
+	struct rxtx_szedata2 *szedata2 = extra_args;
+	uint32_t mask;
+
+	if (parse_mask(value, &mask) != 0)
+		return -1;
+
+	szedata2->sze_tx_mask_req |= mask;
+	return 0;
+}
+
+static int
+rte_pmd_init_internals(const char *name, const unsigned nb_rx_queues,
+		const unsigned nb_tx_queues,
+		const unsigned numa_node,
+		struct pmd_internals **internals,
+		struct rte_eth_dev **eth_dev)
+{
+	struct rte_eth_dev_data *data = NULL;
+
+	RTE_LOG(INFO, PMD,
+			"Creating szedata2-backed ethdev on numa socket %u\n",
+			numa_node);
+
+	/*
+	 * now do all data allocation - for eth_dev structure
+	 * and internal (private) data
+	 */
+	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
+	if (data == NULL)
+		goto error;
+
+	*internals = rte_zmalloc_socket(name, sizeof(**internals), 0,
+			numa_node);
+	if (*internals == NULL)
+		goto error;
+
+	/* reserve an ethdev entry */
+	*eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL);
+	if (*eth_dev == NULL)
+		goto error;
+
+	/*
+	 * now put it all together
+	 * - store queue data in internals,
+	 * - store numa_node info in pci_driver
+	 * - point eth_dev_data to internals
+	 * - and point eth_dev structure to new eth_dev_data structure
+	 *
+	 * NOTE: we'll replace the data element, of originally allocated eth_dev
+	 * so the rings are local per-process
+	 */
+
+	(*internals)->nb_rx_queues = nb_rx_queues;
+	(*internals)->nb_tx_queues = nb_tx_queues;
+
+	(*internals)->if_index = 0;
+
+	data->dev_private = *internals;
+	data->port_id = (*eth_dev)->data->port_id;
+	snprintf(data->name, sizeof(data->name), "%s", (*eth_dev)->data->name);
+	data->nb_rx_queues = (uint16_t)nb_rx_queues;
+	data->nb_tx_queues = (uint16_t)nb_tx_queues;
+	data->dev_link = pmd_link;
+	data->mac_addrs = &eth_addr;
+
+	(*eth_dev)->data = data;
+	(*eth_dev)->dev_ops = &ops;
+	(*eth_dev)->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
+	(*eth_dev)->driver = NULL;
+	(*eth_dev)->data->kdrv = RTE_KDRV_NONE;
+	(*eth_dev)->data->drv_name = drivername;
+	(*eth_dev)->data->numa_node = numa_node;
+
+	return 0;
+
+error:
+	rte_free(data);
+	rte_free(*internals);
+	return -1;
+}
+
+static int
+rte_eth_from_szedata2(const char *name,
+		struct rxtx_szedata2 *szedata2,
+		const unsigned numa_node)
+{
+	struct pmd_internals *internals = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+	struct rte_eth_dev_data *data = NULL;
+	int ret;
+
+	if (rte_pmd_init_internals(name, 0, 0, numa_node,
+			&internals, &eth_dev) < 0)
+		return -1;
+
+	data = eth_dev->data;
+
+	internals->sze_dev = szedata2->sze_dev;
+	internals->sze_rx_req = szedata2->sze_rx_mask_req;
+	internals->sze_tx_req = szedata2->sze_tx_mask_req;
+	internals->num_of_rx = szedata2->num_of_rx;
+	internals->num_of_tx = szedata2->num_of_tx;
+
+	RTE_LOG(INFO, PMD, "Number of rx channels to open: %u mask: 0x%x\n",
+			internals->num_of_rx, internals->sze_rx_req);
+	RTE_LOG(INFO, PMD, "Number of tx channels to open: %u mask: 0x%x\n",
+			internals->num_of_tx, internals->sze_tx_req);
+
+	ret = init_rx_channels(eth_dev, 1);
+	if (ret != 0) {
+		close_rx_channels(eth_dev);
+		return -1;
+	}
+
+	ret = init_tx_channels(eth_dev, 1);
+	if (ret != 0) {
+		close_tx_channels(eth_dev);
+		close_rx_channels(eth_dev);
+		return -1;
+	}
+
+	eth_dev->rx_pkt_burst = NULL;
+	eth_dev->tx_pkt_burst = NULL;
+
+	return 0;
+}
+
+
+static int
+rte_pmd_szedata2_devinit(const char *name, const char *params)
+{
+	unsigned numa_node;
+	int ret;
+	struct rte_kvargs *kvlist;
+	unsigned k_idx;
+	struct rte_kvargs_pair *pair = NULL;
+	struct rxtx_szedata2 szedata2 = { 0, 0, 0, 0, NULL };
+	bool dev_path_missing = true;
+
+	RTE_LOG(INFO, PMD, "Initializing pmd_szedata2 for %s\n", name);
+
+	numa_node = rte_socket_id();
+
+	kvlist = rte_kvargs_parse(params, valid_arguments);
+	if (kvlist == NULL)
+		return -1;
+
+	/*
+	 * Get szedata2 device path and rx,tx channels from passed arguments.
+	 */
+
+	if (rte_kvargs_count(kvlist, RTE_ETH_SZEDATA2_DEV_PATH_ARG) != 1)
+		goto err;
+
+	if (rte_kvargs_count(kvlist, RTE_ETH_SZEDATA2_RX_IFACES_ARG) < 1)
+		goto err;
+
+	if (rte_kvargs_count(kvlist, RTE_ETH_SZEDATA2_TX_IFACES_ARG) < 1)
+		goto err;
+
+	for (k_idx = 0; k_idx < kvlist->count; k_idx++) {
+		pair = &kvlist->pairs[k_idx];
+		if (strstr(pair->key, RTE_ETH_SZEDATA2_DEV_PATH_ARG) != NULL) {
+			szedata2.sze_dev = pair->value;
+			dev_path_missing = false;
+			break;
+		}
+	}
+
+	if (dev_path_missing)
+		goto err;
+
+	ret = rte_kvargs_process(kvlist, RTE_ETH_SZEDATA2_RX_IFACES_ARG,
+			&add_rx_mask, &szedata2);
+	if (ret < 0)
+		goto err;
+
+	ret = rte_kvargs_process(kvlist, RTE_ETH_SZEDATA2_TX_IFACES_ARG,
+			&add_tx_mask, &szedata2);
+	if (ret < 0)
+		goto err;
+
+	szedata2.num_of_rx = count_ones(szedata2.sze_rx_mask_req);
+	szedata2.num_of_tx = count_ones(szedata2.sze_tx_mask_req);
+
+	RTE_LOG(INFO, PMD, "SZE device found at path %s\n", szedata2.sze_dev);
+
+	return rte_eth_from_szedata2(name, &szedata2, numa_node);
+err:
+	rte_kvargs_free(kvlist);
+	return -1;
+}
+
+static int
+rte_pmd_szedata2_devuninit(const char *name)
+{
+	struct rte_eth_dev *dev = NULL;
+
+	RTE_LOG(INFO, PMD, "Uninitializing pmd_szedata2 for %s "
+			"on numa socket %u\n", name, rte_socket_id());
+
+	if (name == NULL)
+		return -1;
+
+	dev = rte_eth_dev_allocated(name);
+	if (dev == NULL)
+		return -1;
+
+	rte_free(dev->data->dev_private);
+	rte_free(dev->data);
+	rte_eth_dev_release_port(dev);
+	return 0;
+}
+
+static struct rte_driver pmd_szedata2_drv = {
+	.name = "eth_szedata2",
+	.type = PMD_VDEV,
+	.init = rte_pmd_szedata2_devinit,
+	.uninit = rte_pmd_szedata2_devuninit,
+};
+
+PMD_REGISTER_DRIVER(pmd_szedata2_drv);
diff --git a/drivers/net/szedata2/rte_eth_szedata2.h b/drivers/net/szedata2/rte_eth_szedata2.h
new file mode 100644
index 0000000..4d09a98
--- /dev/null
+++ b/drivers/net/szedata2/rte_eth_szedata2.h
@@ -0,0 +1,102 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (c) 2015 CESNET
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of CESNET nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RTE_PMD_SZEDATA2_H_
+#define RTE_PMD_SZEDATA2_H_
+
+/* szedata2_packet header length == 4 bytes == 2B segment size + 2B hw size */
+#define RTE_SZE2_PACKET_HEADER_SIZE 4
+
+#define RTE_SZE2_MMIO_MAX 10
+
+/*!
+ * Round 'what' to the nearest larger (or equal) multiple of '8'
+ * (szedata2 packet is aligned to 8 bytes)
+ */
+#define RTE_SZE2_ALIGN8(what) (((what) + ((8) - 1)) & (~((8) - 1)))
+
+/*! main handle structure */
+struct szedata {
+	int fd;
+	struct sze2_instance_info *info;
+	uint32_t *write_size;
+	void *space[RTE_SZE2_MMIO_MAX];
+	struct szedata_lock lock[2][2];
+
+	__u32 *rx_asize, *tx_asize;
+
+	/* szedata_read_next variables - to keep context (ct) */
+
+	/*
+	 * rx
+	 */
+	/** initial sze lock ptr */
+	const struct szedata_lock   *ct_rx_lck_orig;
+	/** current sze lock ptr (initial or next) */
+	const struct szedata_lock   *ct_rx_lck;
+	/** remaining bytes (not read) within current lock */
+	unsigned int                ct_rx_rem_bytes;
+	/** current pointer to locked memory */
+	unsigned char               *ct_rx_cur_ptr;
+	/**
+	 * allocated buffer to store RX packet if it was split
+	 * into 2 buffers
+	 */
+	unsigned char               *ct_rx_buffer;
+	/** registered function to provide filtering based on hwdata */
+	int (*ct_rx_filter)(u_int16_t hwdata_len, u_char *hwdata);
+
+	/*
+	 * tx
+	 */
+	/**
+	 * buffer for tx - packet is prepared here
+	 * (in future for burst write)
+	 */
+	unsigned char               *ct_tx_buffer;
+	/** initial sze TX lock ptrs - number according to TX interfaces */
+	const struct szedata_lock   **ct_tx_lck_orig;
+	/** current sze TX lock ptrs - number according to TX interfaces */
+	const struct szedata_lock   **ct_tx_lck;
+	/** already written bytes in both locks */
+	unsigned int                *ct_tx_written_bytes;
+	/** remaining bytes (not written) within current lock */
+	unsigned int                *ct_tx_rem_bytes;
+	/** current pointers to locked memory */
+	unsigned char               **ct_tx_cur_ptr;
+	/** NUMA node closest to PCIe device, or -1 */
+	int                         numa_node;
+};
+
+
+#endif
diff --git a/drivers/net/szedata2/rte_pmd_szedata2_version.map b/drivers/net/szedata2/rte_pmd_szedata2_version.map
new file mode 100644
index 0000000..ad607bb
--- /dev/null
+++ b/drivers/net/szedata2/rte_pmd_szedata2_version.map
@@ -0,0 +1,3 @@
+DPDK_2.2 {
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 724efa7..0bac99b 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -92,6 +92,8 @@ endif # ! CONFIG_RTE_BUILD_COMBINE_LIBS
 
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_PCAP)       += -lpcap
 
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lsze2
+
 ifeq ($(CONFIG_RTE_LIBRTE_VHOST_NUMA),y)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VHOST)          += -lnuma
 endif
@@ -147,6 +149,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_RING)       += -lrte_pmd_ring
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_PCAP)       += -lrte_pmd_pcap
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_AF_PACKET)  += -lrte_pmd_af_packet
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NULL)       += -lrte_pmd_null
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2
 
 endif # ! $(CONFIG_RTE_BUILD_SHARED_LIB)
 
-- 
1.9.1

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

* [PATCH v3 2/6] szedata2: add non-scattered RX function
  2015-11-10 14:18   ` [PATCH v3 0/6] Virtual PMD using sze2 layer for COMBO cards Matej Vido
  2015-11-10 14:18     ` [PATCH v3 1/6] szedata2: add new poll mode driver Matej Vido
@ 2015-11-10 14:18     ` Matej Vido
  2015-11-10 14:18     ` [PATCH v3 3/6] szedata2: add TX function Matej Vido
                       ` (4 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Matej Vido @ 2015-11-10 14:18 UTC (permalink / raw)
  To: dev

Signed-off-by: Matej Vido <matejvido@gmail.com>
---
 drivers/net/szedata2/rte_eth_szedata2.c | 235 +++++++++++++++++++++++++++++++-
 1 file changed, 234 insertions(+), 1 deletion(-)

diff --git a/drivers/net/szedata2/rte_eth_szedata2.c b/drivers/net/szedata2/rte_eth_szedata2.c
index 7edaefc..785ac88 100644
--- a/drivers/net/szedata2/rte_eth_szedata2.c
+++ b/drivers/net/szedata2/rte_eth_szedata2.c
@@ -125,6 +125,239 @@ count_ones(uint32_t num)
 	return (((num + (num >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; /* count */
 }
 
+static uint16_t
+eth_szedata2_rx(void *queue,
+		struct rte_mbuf **bufs,
+		uint16_t nb_pkts)
+{
+	unsigned int i;
+	struct rte_mbuf *mbuf;
+	struct szedata2_rx_queue *sze_q = queue;
+	struct rte_pktmbuf_pool_private *mbp_priv;
+	uint16_t num_rx = 0;
+	uint16_t buf_size;
+	uint16_t sg_size;
+	uint16_t hw_size;
+	uint16_t packet_size;
+	uint64_t num_bytes = 0;
+	struct szedata *sze = sze_q->sze;
+	uint8_t *header_ptr = NULL; /* header of packet */
+	uint8_t *packet_ptr1 = NULL;
+	uint8_t *packet_ptr2 = NULL;
+	uint16_t packet_len1 = 0;
+	uint16_t packet_len2 = 0;
+	uint16_t hw_data_align;
+
+	if (unlikely(sze_q->sze == NULL || nb_pkts == 0))
+		return 0;
+
+	/*
+	 * Reads the given number of packets from szedata2 channel given
+	 * by queue and copies the packet data into a newly allocated mbuf
+	 * to return.
+	 */
+	for (i = 0; i < nb_pkts; i++) {
+		mbuf = rte_pktmbuf_alloc(sze_q->mb_pool);
+
+		if (unlikely(mbuf == NULL))
+			break;
+
+		/* get the next sze packet */
+		if (sze->ct_rx_lck != NULL && !sze->ct_rx_rem_bytes &&
+				sze->ct_rx_lck->next == NULL) {
+			/* unlock old data */
+			szedata_rx_unlock_data(sze_q->sze, sze->ct_rx_lck_orig);
+			sze->ct_rx_lck_orig = NULL;
+			sze->ct_rx_lck = NULL;
+		}
+
+		if (!sze->ct_rx_rem_bytes && sze->ct_rx_lck_orig == NULL) {
+			/* nothing to read, lock new data */
+			sze->ct_rx_lck = szedata_rx_lock_data(sze_q->sze, ~0U);
+			sze->ct_rx_lck_orig = sze->ct_rx_lck;
+
+			if (sze->ct_rx_lck == NULL) {
+				/* nothing to lock */
+				rte_pktmbuf_free(mbuf);
+				break;
+			}
+
+			sze->ct_rx_cur_ptr = sze->ct_rx_lck->start;
+			sze->ct_rx_rem_bytes = sze->ct_rx_lck->len;
+
+			if (!sze->ct_rx_rem_bytes) {
+				rte_pktmbuf_free(mbuf);
+				break;
+			}
+		}
+
+		if (sze->ct_rx_rem_bytes < RTE_SZE2_PACKET_HEADER_SIZE) {
+			/*
+			 * cut in header
+			 * copy parts of header to merge buffer
+			 */
+			if (sze->ct_rx_lck->next == NULL) {
+				rte_pktmbuf_free(mbuf);
+				break;
+			}
+
+			/* copy first part of header */
+			rte_memcpy(sze->ct_rx_buffer, sze->ct_rx_cur_ptr,
+					sze->ct_rx_rem_bytes);
+
+			/* copy second part of header */
+			sze->ct_rx_lck = sze->ct_rx_lck->next;
+			sze->ct_rx_cur_ptr = sze->ct_rx_lck->start;
+			rte_memcpy(sze->ct_rx_buffer + sze->ct_rx_rem_bytes,
+				sze->ct_rx_cur_ptr,
+				RTE_SZE2_PACKET_HEADER_SIZE -
+				sze->ct_rx_rem_bytes);
+
+			sze->ct_rx_cur_ptr += RTE_SZE2_PACKET_HEADER_SIZE -
+				sze->ct_rx_rem_bytes;
+			sze->ct_rx_rem_bytes = sze->ct_rx_lck->len -
+				RTE_SZE2_PACKET_HEADER_SIZE +
+				sze->ct_rx_rem_bytes;
+
+			header_ptr = (uint8_t *)sze->ct_rx_buffer;
+		} else {
+			/* not cut */
+			header_ptr = (uint8_t *)sze->ct_rx_cur_ptr;
+			sze->ct_rx_cur_ptr += RTE_SZE2_PACKET_HEADER_SIZE;
+			sze->ct_rx_rem_bytes -= RTE_SZE2_PACKET_HEADER_SIZE;
+		}
+
+		sg_size = le16toh(*((uint16_t *)header_ptr));
+		hw_size = le16toh(*(((uint16_t *)header_ptr) + 1));
+		packet_size = sg_size -
+			RTE_SZE2_ALIGN8(RTE_SZE2_PACKET_HEADER_SIZE + hw_size);
+
+
+		/* checks if packet all right */
+		if (!sg_size)
+			errx(5, "Zero segsize");
+
+		/* check sg_size and hwsize */
+		if (hw_size > sg_size - RTE_SZE2_PACKET_HEADER_SIZE) {
+			errx(10, "Hwsize bigger than expected. Segsize: %d, "
+				"hwsize: %d", sg_size, hw_size);
+		}
+
+		hw_data_align =
+			RTE_SZE2_ALIGN8(RTE_SZE2_PACKET_HEADER_SIZE + hw_size) -
+			RTE_SZE2_PACKET_HEADER_SIZE;
+
+		if (sze->ct_rx_rem_bytes >=
+				(uint16_t)(sg_size -
+				RTE_SZE2_PACKET_HEADER_SIZE)) {
+			/* no cut */
+			/* one packet ready - go to another */
+			packet_ptr1 = sze->ct_rx_cur_ptr + hw_data_align;
+			packet_len1 = packet_size;
+			packet_ptr2 = NULL;
+			packet_len2 = 0;
+
+			sze->ct_rx_cur_ptr += RTE_SZE2_ALIGN8(sg_size) -
+				RTE_SZE2_PACKET_HEADER_SIZE;
+			sze->ct_rx_rem_bytes -= RTE_SZE2_ALIGN8(sg_size) -
+				RTE_SZE2_PACKET_HEADER_SIZE;
+		} else {
+			/* cut in data */
+			if (sze->ct_rx_lck->next == NULL) {
+				errx(6, "Need \"next\" lock, "
+					"but it is missing: %u",
+					sze->ct_rx_rem_bytes);
+			}
+
+			/* skip hw data */
+			if (sze->ct_rx_rem_bytes <= hw_data_align) {
+				uint16_t rem_size = hw_data_align -
+					sze->ct_rx_rem_bytes;
+
+				/* MOVE to next lock */
+				sze->ct_rx_lck = sze->ct_rx_lck->next;
+				sze->ct_rx_cur_ptr =
+					(void *)(((uint8_t *)
+					(sze->ct_rx_lck->start)) + rem_size);
+
+				packet_ptr1 = sze->ct_rx_cur_ptr;
+				packet_len1 = packet_size;
+				packet_ptr2 = NULL;
+				packet_len2 = 0;
+
+				sze->ct_rx_cur_ptr +=
+					RTE_SZE2_ALIGN8(packet_size);
+				sze->ct_rx_rem_bytes = sze->ct_rx_lck->len -
+					rem_size - RTE_SZE2_ALIGN8(packet_size);
+			} else {
+				/* get pointer and length from first part */
+				packet_ptr1 = sze->ct_rx_cur_ptr +
+					hw_data_align;
+				packet_len1 = sze->ct_rx_rem_bytes -
+					hw_data_align;
+
+				/* MOVE to next lock */
+				sze->ct_rx_lck = sze->ct_rx_lck->next;
+				sze->ct_rx_cur_ptr = sze->ct_rx_lck->start;
+
+				/* get pointer and length from second part */
+				packet_ptr2 = sze->ct_rx_cur_ptr;
+				packet_len2 = packet_size - packet_len1;
+
+				sze->ct_rx_cur_ptr +=
+					RTE_SZE2_ALIGN8(packet_size) -
+					packet_len1;
+				sze->ct_rx_rem_bytes = sze->ct_rx_lck->len -
+					(RTE_SZE2_ALIGN8(packet_size) -
+					 packet_len1);
+			}
+		}
+
+		if (unlikely(packet_ptr1 == NULL)) {
+			rte_pktmbuf_free(mbuf);
+			break;
+		}
+
+		/* get the space available for data in the mbuf */
+		mbp_priv = rte_mempool_get_priv(sze_q->mb_pool);
+		buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size -
+				RTE_PKTMBUF_HEADROOM);
+
+		if (packet_size <= buf_size) {
+			/* sze packet will fit in one mbuf, go ahead and copy */
+			rte_memcpy(rte_pktmbuf_mtod(mbuf, void *),
+					packet_ptr1, packet_len1);
+			if (packet_ptr2 != NULL) {
+				rte_memcpy((void *)(rte_pktmbuf_mtod(mbuf,
+					uint8_t *) + packet_len1),
+					packet_ptr2, packet_len2);
+			}
+			mbuf->data_len = (uint16_t)packet_size;
+
+			mbuf->pkt_len = packet_size;
+			mbuf->port = sze_q->in_port;
+			bufs[num_rx] = mbuf;
+			num_rx++;
+			num_bytes += packet_size;
+		} else {
+			/*
+			 * sze packet will not fit in one mbuf,
+			 * scattered mode is not enabled, drop packet
+			 */
+			RTE_LOG(ERR, PMD,
+				"SZE 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);
+		}
+	}
+
+	sze_q->rx_pkts += num_rx;
+	sze_q->rx_bytes += num_bytes;
+	return num_rx;
+}
+
 static int
 init_rx_channels(struct rte_eth_dev *dev, int v)
 {
@@ -727,7 +960,7 @@ rte_eth_from_szedata2(const char *name,
 		return -1;
 	}
 
-	eth_dev->rx_pkt_burst = NULL;
+	eth_dev->rx_pkt_burst = eth_szedata2_rx;
 	eth_dev->tx_pkt_burst = NULL;
 
 	return 0;
-- 
1.9.1

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

* [PATCH v3 3/6] szedata2: add TX function
  2015-11-10 14:18   ` [PATCH v3 0/6] Virtual PMD using sze2 layer for COMBO cards Matej Vido
  2015-11-10 14:18     ` [PATCH v3 1/6] szedata2: add new poll mode driver Matej Vido
  2015-11-10 14:18     ` [PATCH v3 2/6] szedata2: add non-scattered RX function Matej Vido
@ 2015-11-10 14:18     ` Matej Vido
  2015-11-10 14:18     ` [PATCH v3 4/6] szedata2: add support for scattered packets in RX Matej Vido
                       ` (3 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Matej Vido @ 2015-11-10 14:18 UTC (permalink / raw)
  To: dev

TX function handles scattered and non-scattered packets.

Signed-off-by: Matej Vido <matejvido@gmail.com>
---
 drivers/net/szedata2/rte_eth_szedata2.c | 216 +++++++++++++++++++++++++++++++-
 1 file changed, 215 insertions(+), 1 deletion(-)

diff --git a/drivers/net/szedata2/rte_eth_szedata2.c b/drivers/net/szedata2/rte_eth_szedata2.c
index 785ac88..3213a20 100644
--- a/drivers/net/szedata2/rte_eth_szedata2.c
+++ b/drivers/net/szedata2/rte_eth_szedata2.c
@@ -358,6 +358,220 @@ eth_szedata2_rx(void *queue,
 	return num_rx;
 }
 
+static uint16_t
+eth_szedata2_tx(void *queue,
+		struct rte_mbuf **bufs,
+		uint16_t nb_pkts)
+{
+	struct rte_mbuf *mbuf;
+	struct szedata2_tx_queue *sze_q = queue;
+	uint16_t num_tx = 0;
+	uint64_t num_bytes = 0;
+
+	const struct szedata_lock *lck;
+	uint32_t lock_size;
+	uint32_t lock_size2;
+	void *dst;
+	uint32_t pkt_len;
+	uint32_t hwpkt_len;
+	uint32_t unlock_size;
+	uint32_t rem_len;
+	uint8_t mbuf_segs;
+	uint16_t pkt_left = nb_pkts;
+
+	if (sze_q->sze == NULL || nb_pkts == 0)
+		return 0;
+
+	while (pkt_left > 0) {
+		unlock_size = 0;
+		lck = szedata_tx_lock_data(sze_q->sze,
+			RTE_ETH_SZEDATA2_TX_LOCK_SIZE,
+			sze_q->tx_channel);
+		if (lck == NULL)
+			continue;
+
+		dst = lck->start;
+		lock_size = lck->len;
+		lock_size2 = lck->next ? lck->next->len : 0;
+
+next_packet:
+		mbuf = bufs[nb_pkts - pkt_left];
+
+		pkt_len = mbuf->pkt_len;
+		mbuf_segs = mbuf->nb_segs;
+
+		hwpkt_len = RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED +
+			RTE_SZE2_ALIGN8(pkt_len);
+
+		if (lock_size + lock_size2 < hwpkt_len) {
+			szedata_tx_unlock_data(sze_q->sze, lck, unlock_size);
+			continue;
+		}
+
+		num_bytes += pkt_len;
+
+		if (lock_size > hwpkt_len) {
+			void *tmp_dst;
+
+			rem_len = 0;
+
+			/* write packet length at first 2 bytes in 8B header */
+			*((uint16_t *)dst) = htole16(
+					RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED +
+					pkt_len);
+			*(((uint16_t *)dst) + 1) = htole16(0);
+
+			/* copy packet from mbuf */
+			tmp_dst = ((uint8_t *)(dst)) +
+				RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED;
+			if (mbuf_segs == 1) {
+				/*
+				 * non-scattered packet,
+				 * transmit from one mbuf
+				 */
+				rte_memcpy(tmp_dst,
+					rte_pktmbuf_mtod(mbuf, const void *),
+					pkt_len);
+			} else {
+				/* scattered packet, transmit from more mbufs */
+				struct rte_mbuf *m = mbuf;
+				while (m) {
+					rte_memcpy(tmp_dst,
+						rte_pktmbuf_mtod(m,
+						const void *),
+						m->data_len);
+					tmp_dst = ((uint8_t *)(tmp_dst)) +
+						m->data_len;
+					m = m->next;
+				}
+			}
+
+
+			dst = ((uint8_t *)dst) + hwpkt_len;
+			unlock_size += hwpkt_len;
+			lock_size -= hwpkt_len;
+
+			rte_pktmbuf_free(mbuf);
+			num_tx++;
+			pkt_left--;
+			if (pkt_left == 0) {
+				szedata_tx_unlock_data(sze_q->sze, lck,
+					unlock_size);
+				break;
+			}
+			goto next_packet;
+		} else if (lock_size + lock_size2 >= hwpkt_len) {
+			void *tmp_dst;
+			uint16_t write_len;
+
+			/* write packet length at first 2 bytes in 8B header */
+			*((uint16_t *)dst) =
+				htole16(RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED +
+					pkt_len);
+			*(((uint16_t *)dst) + 1) = htole16(0);
+
+			/*
+			 * If the raw packet (pkt_len) is smaller than lock_size
+			 * get the correct length for memcpy
+			 */
+			write_len =
+				pkt_len < lock_size -
+				RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED ?
+				pkt_len :
+				lock_size - RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED;
+
+			rem_len = hwpkt_len - lock_size;
+
+			tmp_dst = ((uint8_t *)(dst)) +
+				RTE_SZE2_PACKET_HEADER_SIZE_ALIGNED;
+			if (mbuf_segs == 1) {
+				/*
+				 * non-scattered packet,
+				 * transmit from one mbuf
+				 */
+				/* copy part of packet to first area */
+				rte_memcpy(tmp_dst,
+					rte_pktmbuf_mtod(mbuf, const void *),
+					write_len);
+
+				if (lck->next)
+					dst = lck->next->start;
+
+				/* copy part of packet to second area */
+				rte_memcpy(dst,
+					(const void *)(rte_pktmbuf_mtod(mbuf,
+							const uint8_t *) +
+					write_len), pkt_len - write_len);
+			} else {
+				/* scattered packet, transmit from more mbufs */
+				struct rte_mbuf *m = mbuf;
+				uint16_t written = 0;
+				uint16_t to_write = 0;
+				bool new_mbuf = true;
+				uint16_t write_off = 0;
+
+				/* copy part of packet to first area */
+				while (m && written < write_len) {
+					to_write = RTE_MIN(m->data_len,
+							write_len - written);
+					rte_memcpy(tmp_dst,
+						rte_pktmbuf_mtod(m,
+							const void *),
+						to_write);
+
+					tmp_dst = ((uint8_t *)(tmp_dst)) +
+						to_write;
+					if (m->data_len <= write_len -
+							written) {
+						m = m->next;
+						new_mbuf = true;
+					} else {
+						new_mbuf = false;
+					}
+					written += to_write;
+				}
+
+				if (lck->next)
+					dst = lck->next->start;
+
+				tmp_dst = dst;
+				written = 0;
+				write_off = new_mbuf ? 0 : to_write;
+
+				/* copy part of packet to second area */
+				while (m && written < pkt_len - write_len) {
+					rte_memcpy(tmp_dst, (const void *)
+						(rte_pktmbuf_mtod(m,
+						uint8_t *) + write_off),
+						m->data_len - write_off);
+
+					tmp_dst = ((uint8_t *)(tmp_dst)) +
+						(m->data_len - write_off);
+					written += m->data_len - write_off;
+					m = m->next;
+					write_off = 0;
+				}
+			}
+
+			dst = ((uint8_t *)dst) + rem_len;
+			unlock_size += hwpkt_len;
+			lock_size = lock_size2 - rem_len;
+			lock_size2 = 0;
+
+			rte_pktmbuf_free(mbuf);
+			num_tx++;
+		}
+
+		szedata_tx_unlock_data(sze_q->sze, lck, unlock_size);
+		pkt_left--;
+	}
+
+	sze_q->tx_pkts += num_tx;
+	sze_q->err_pkts += nb_pkts - num_tx;
+	sze_q->tx_bytes += num_bytes;
+	return num_tx;
+}
+
 static int
 init_rx_channels(struct rte_eth_dev *dev, int v)
 {
@@ -961,7 +1175,7 @@ rte_eth_from_szedata2(const char *name,
 	}
 
 	eth_dev->rx_pkt_burst = eth_szedata2_rx;
-	eth_dev->tx_pkt_burst = NULL;
+	eth_dev->tx_pkt_burst = eth_szedata2_tx;
 
 	return 0;
 }
-- 
1.9.1

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

* [PATCH v3 4/6] szedata2: add support for scattered packets in RX
  2015-11-10 14:18   ` [PATCH v3 0/6] Virtual PMD using sze2 layer for COMBO cards Matej Vido
                       ` (2 preceding siblings ...)
  2015-11-10 14:18     ` [PATCH v3 3/6] szedata2: add TX function Matej Vido
@ 2015-11-10 14:18     ` Matej Vido
  2015-11-10 14:18     ` [PATCH v3 5/6] doc: add documentation for szedata2 PMD Matej Vido
                       ` (2 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Matej Vido @ 2015-11-10 14:18 UTC (permalink / raw)
  To: dev

Add new RX function for handling scattered packets.

Signed-off-by: Matej Vido <matejvido@gmail.com>
---
 drivers/net/szedata2/rte_eth_szedata2.c | 351 +++++++++++++++++++++++++++++++-
 1 file changed, 349 insertions(+), 2 deletions(-)

diff --git a/drivers/net/szedata2/rte_eth_szedata2.c b/drivers/net/szedata2/rte_eth_szedata2.c
index 3213a20..22c99e4 100644
--- a/drivers/net/szedata2/rte_eth_szedata2.c
+++ b/drivers/net/szedata2/rte_eth_szedata2.c
@@ -359,6 +359,338 @@ eth_szedata2_rx(void *queue,
 }
 
 static uint16_t
+eth_szedata2_rx_scattered(void *queue,
+		struct rte_mbuf **bufs,
+		uint16_t nb_pkts)
+{
+	unsigned int i;
+	struct rte_mbuf *mbuf;
+	struct szedata2_rx_queue *sze_q = queue;
+	struct rte_pktmbuf_pool_private *mbp_priv;
+	uint16_t num_rx = 0;
+	uint16_t buf_size;
+	uint16_t sg_size;
+	uint16_t hw_size;
+	uint16_t packet_size;
+	uint64_t num_bytes = 0;
+	struct szedata *sze = sze_q->sze;
+	uint8_t *header_ptr = NULL; /* header of packet */
+	uint8_t *packet_ptr1 = NULL;
+	uint8_t *packet_ptr2 = NULL;
+	uint16_t packet_len1 = 0;
+	uint16_t packet_len2 = 0;
+	uint16_t hw_data_align;
+
+	if (unlikely(sze_q->sze == NULL || nb_pkts == 0))
+		return 0;
+
+	/*
+	 * Reads the given number of packets from szedata2 channel given
+	 * by queue and copies the packet data into a newly allocated mbuf
+	 * to return.
+	 */
+	for (i = 0; i < nb_pkts; i++) {
+		const struct szedata_lock *ct_rx_lck_backup;
+		unsigned int ct_rx_rem_bytes_backup;
+		unsigned char *ct_rx_cur_ptr_backup;
+
+		/* get the next sze packet */
+		if (sze->ct_rx_lck != NULL && !sze->ct_rx_rem_bytes &&
+				sze->ct_rx_lck->next == NULL) {
+			/* unlock old data */
+			szedata_rx_unlock_data(sze_q->sze, sze->ct_rx_lck_orig);
+			sze->ct_rx_lck_orig = NULL;
+			sze->ct_rx_lck = NULL;
+		}
+
+		/*
+		 * Store items from sze structure which can be changed
+		 * before mbuf allocating. Use these items in case of mbuf
+		 * allocating failure.
+		 */
+		ct_rx_lck_backup = sze->ct_rx_lck;
+		ct_rx_rem_bytes_backup = sze->ct_rx_rem_bytes;
+		ct_rx_cur_ptr_backup = sze->ct_rx_cur_ptr;
+
+		if (!sze->ct_rx_rem_bytes && sze->ct_rx_lck_orig == NULL) {
+			/* nothing to read, lock new data */
+			sze->ct_rx_lck = szedata_rx_lock_data(sze_q->sze, ~0U);
+			sze->ct_rx_lck_orig = sze->ct_rx_lck;
+
+			/*
+			 * Backup items from sze structure must be updated
+			 * after locking to contain pointers to new locks.
+			 */
+			ct_rx_lck_backup = sze->ct_rx_lck;
+			ct_rx_rem_bytes_backup = sze->ct_rx_rem_bytes;
+			ct_rx_cur_ptr_backup = sze->ct_rx_cur_ptr;
+
+			if (sze->ct_rx_lck == NULL)
+				/* nothing to lock */
+				break;
+
+			sze->ct_rx_cur_ptr = sze->ct_rx_lck->start;
+			sze->ct_rx_rem_bytes = sze->ct_rx_lck->len;
+
+			if (!sze->ct_rx_rem_bytes)
+				break;
+		}
+
+		if (sze->ct_rx_rem_bytes < RTE_SZE2_PACKET_HEADER_SIZE) {
+			/*
+			 * cut in header - copy parts of header to merge buffer
+			 */
+			if (sze->ct_rx_lck->next == NULL)
+				break;
+
+			/* copy first part of header */
+			rte_memcpy(sze->ct_rx_buffer, sze->ct_rx_cur_ptr,
+					sze->ct_rx_rem_bytes);
+
+			/* copy second part of header */
+			sze->ct_rx_lck = sze->ct_rx_lck->next;
+			sze->ct_rx_cur_ptr = sze->ct_rx_lck->start;
+			rte_memcpy(sze->ct_rx_buffer + sze->ct_rx_rem_bytes,
+				sze->ct_rx_cur_ptr,
+				RTE_SZE2_PACKET_HEADER_SIZE -
+				sze->ct_rx_rem_bytes);
+
+			sze->ct_rx_cur_ptr += RTE_SZE2_PACKET_HEADER_SIZE -
+				sze->ct_rx_rem_bytes;
+			sze->ct_rx_rem_bytes = sze->ct_rx_lck->len -
+				RTE_SZE2_PACKET_HEADER_SIZE +
+				sze->ct_rx_rem_bytes;
+
+			header_ptr = (uint8_t *)sze->ct_rx_buffer;
+		} else {
+			/* not cut */
+			header_ptr = (uint8_t *)sze->ct_rx_cur_ptr;
+			sze->ct_rx_cur_ptr += RTE_SZE2_PACKET_HEADER_SIZE;
+			sze->ct_rx_rem_bytes -= RTE_SZE2_PACKET_HEADER_SIZE;
+		}
+
+		sg_size = le16toh(*((uint16_t *)header_ptr));
+		hw_size = le16toh(*(((uint16_t *)header_ptr) + 1));
+		packet_size = sg_size -
+			RTE_SZE2_ALIGN8(RTE_SZE2_PACKET_HEADER_SIZE + hw_size);
+
+
+		/* checks if packet all right */
+		if (!sg_size)
+			errx(5, "Zero segsize");
+
+		/* check sg_size and hwsize */
+		if (hw_size > sg_size - RTE_SZE2_PACKET_HEADER_SIZE) {
+			errx(10, "Hwsize bigger than expected. Segsize: %d, "
+					"hwsize: %d", sg_size, hw_size);
+		}
+
+		hw_data_align =
+			RTE_SZE2_ALIGN8((RTE_SZE2_PACKET_HEADER_SIZE +
+			hw_size)) - RTE_SZE2_PACKET_HEADER_SIZE;
+
+		if (sze->ct_rx_rem_bytes >=
+				(uint16_t)(sg_size -
+				RTE_SZE2_PACKET_HEADER_SIZE)) {
+			/* no cut */
+			/* one packet ready - go to another */
+			packet_ptr1 = sze->ct_rx_cur_ptr + hw_data_align;
+			packet_len1 = packet_size;
+			packet_ptr2 = NULL;
+			packet_len2 = 0;
+
+			sze->ct_rx_cur_ptr += RTE_SZE2_ALIGN8(sg_size) -
+				RTE_SZE2_PACKET_HEADER_SIZE;
+			sze->ct_rx_rem_bytes -= RTE_SZE2_ALIGN8(sg_size) -
+				RTE_SZE2_PACKET_HEADER_SIZE;
+		} else {
+			/* cut in data */
+			if (sze->ct_rx_lck->next == NULL) {
+				errx(6, "Need \"next\" lock, but it is "
+					"missing: %u", sze->ct_rx_rem_bytes);
+			}
+
+			/* skip hw data */
+			if (sze->ct_rx_rem_bytes <= hw_data_align) {
+				uint16_t rem_size = hw_data_align -
+					sze->ct_rx_rem_bytes;
+
+				/* MOVE to next lock */
+				sze->ct_rx_lck = sze->ct_rx_lck->next;
+				sze->ct_rx_cur_ptr =
+					(void *)(((uint8_t *)
+					(sze->ct_rx_lck->start)) + rem_size);
+
+				packet_ptr1 = sze->ct_rx_cur_ptr;
+				packet_len1 = packet_size;
+				packet_ptr2 = NULL;
+				packet_len2 = 0;
+
+				sze->ct_rx_cur_ptr +=
+					RTE_SZE2_ALIGN8(packet_size);
+				sze->ct_rx_rem_bytes = sze->ct_rx_lck->len -
+					rem_size - RTE_SZE2_ALIGN8(packet_size);
+			} else {
+				/* get pointer and length from first part */
+				packet_ptr1 = sze->ct_rx_cur_ptr +
+					hw_data_align;
+				packet_len1 = sze->ct_rx_rem_bytes -
+					hw_data_align;
+
+				/* MOVE to next lock */
+				sze->ct_rx_lck = sze->ct_rx_lck->next;
+				sze->ct_rx_cur_ptr = sze->ct_rx_lck->start;
+
+				/* get pointer and length from second part */
+				packet_ptr2 = sze->ct_rx_cur_ptr;
+				packet_len2 = packet_size - packet_len1;
+
+				sze->ct_rx_cur_ptr +=
+					RTE_SZE2_ALIGN8(packet_size) -
+					packet_len1;
+				sze->ct_rx_rem_bytes = sze->ct_rx_lck->len -
+					(RTE_SZE2_ALIGN8(packet_size) -
+					 packet_len1);
+			}
+		}
+
+		if (unlikely(packet_ptr1 == NULL))
+			break;
+
+		mbuf = rte_pktmbuf_alloc(sze_q->mb_pool);
+
+		if (unlikely(mbuf == NULL)) {
+			/*
+			 * Restore items from sze structure to state after
+			 * unlocking (eventually locking).
+			 */
+			sze->ct_rx_lck = ct_rx_lck_backup;
+			sze->ct_rx_rem_bytes = ct_rx_rem_bytes_backup;
+			sze->ct_rx_cur_ptr = ct_rx_cur_ptr_backup;
+			break;
+		}
+
+		/* get the space available for data in the mbuf */
+		mbp_priv = rte_mempool_get_priv(sze_q->mb_pool);
+		buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size -
+				RTE_PKTMBUF_HEADROOM);
+
+		if (packet_size <= buf_size) {
+			/* sze packet will fit in one mbuf, go ahead and copy */
+			rte_memcpy(rte_pktmbuf_mtod(mbuf, void *),
+					packet_ptr1, packet_len1);
+			if (packet_ptr2 != NULL) {
+				rte_memcpy((void *)
+					(rte_pktmbuf_mtod(mbuf, uint8_t *) +
+					packet_len1), packet_ptr2, packet_len2);
+			}
+			mbuf->data_len = (uint16_t)packet_size;
+		} else {
+			/*
+			 * sze packet will not fit in one mbuf,
+			 * scatter packet into more mbufs
+			 */
+			struct rte_mbuf *m = mbuf;
+			uint16_t len = rte_pktmbuf_tailroom(mbuf);
+
+			/* copy first part of packet */
+			/* fill first mbuf */
+			rte_memcpy(rte_pktmbuf_append(mbuf, len), packet_ptr1,
+				len);
+			packet_len1 -= len;
+			packet_ptr1 = ((uint8_t *)packet_ptr1) + len;
+
+			while (packet_len1 > 0) {
+				/* fill new mbufs */
+				m->next = rte_pktmbuf_alloc(sze_q->mb_pool);
+
+				if (unlikely(m->next == NULL)) {
+					rte_pktmbuf_free(mbuf);
+					/*
+					 * Restore items from sze structure
+					 * to state after unlocking (eventually
+					 * locking).
+					 */
+					sze->ct_rx_lck = ct_rx_lck_backup;
+					sze->ct_rx_rem_bytes =
+						ct_rx_rem_bytes_backup;
+					sze->ct_rx_cur_ptr =
+						ct_rx_cur_ptr_backup;
+					goto finish;
+				}
+
+				m = m->next;
+
+				len = RTE_MIN(rte_pktmbuf_tailroom(m),
+					packet_len1);
+				rte_memcpy(rte_pktmbuf_append(mbuf, len),
+					packet_ptr1, len);
+
+				(mbuf->nb_segs)++;
+				packet_len1 -= len;
+				packet_ptr1 = ((uint8_t *)packet_ptr1) + len;
+			}
+
+			if (packet_ptr2 != NULL) {
+				/* copy second part of packet, if exists */
+				/* fill the rest of currently last mbuf */
+				len = rte_pktmbuf_tailroom(m);
+				rte_memcpy(rte_pktmbuf_append(mbuf, len),
+					packet_ptr2, len);
+				packet_len2 -= len;
+				packet_ptr2 = ((uint8_t *)packet_ptr2) + len;
+
+				while (packet_len2 > 0) {
+					/* fill new mbufs */
+					m->next = rte_pktmbuf_alloc(
+							sze_q->mb_pool);
+
+					if (unlikely(m->next == NULL)) {
+						rte_pktmbuf_free(mbuf);
+						/*
+						 * Restore items from sze
+						 * structure to state after
+						 * unlocking (eventually
+						 * locking).
+						 */
+						sze->ct_rx_lck =
+							ct_rx_lck_backup;
+						sze->ct_rx_rem_bytes =
+							ct_rx_rem_bytes_backup;
+						sze->ct_rx_cur_ptr =
+							ct_rx_cur_ptr_backup;
+						goto finish;
+					}
+
+					m = m->next;
+
+					len = RTE_MIN(rte_pktmbuf_tailroom(m),
+						packet_len2);
+					rte_memcpy(
+						rte_pktmbuf_append(mbuf, len),
+						packet_ptr2, len);
+
+					(mbuf->nb_segs)++;
+					packet_len2 -= len;
+					packet_ptr2 = ((uint8_t *)packet_ptr2) +
+						len;
+				}
+			}
+		}
+		mbuf->pkt_len = packet_size;
+		mbuf->port = sze_q->in_port;
+		bufs[num_rx] = mbuf;
+		num_rx++;
+		num_bytes += packet_size;
+	}
+
+finish:
+	sze_q->rx_pkts += num_rx;
+	sze_q->rx_bytes += num_bytes;
+	return num_rx;
+}
+
+static uint16_t
 eth_szedata2_tx(void *queue,
 		struct rte_mbuf **bufs,
 		uint16_t nb_pkts)
@@ -860,8 +1192,16 @@ eth_dev_stop(struct rte_eth_dev *dev)
 }
 
 static int
-eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
+eth_dev_configure(struct rte_eth_dev *dev)
 {
+	struct rte_eth_dev_data *data = dev->data;
+	if (data->dev_conf.rxmode.enable_scatter == 1) {
+		dev->rx_pkt_burst = eth_szedata2_rx_scattered;
+		data->scattered_rx = 1;
+	} else {
+		dev->rx_pkt_burst = eth_szedata2_rx;
+		data->scattered_rx = 0;
+	}
 	return 0;
 }
 
@@ -1174,7 +1514,14 @@ rte_eth_from_szedata2(const char *name,
 		return -1;
 	}
 
-	eth_dev->rx_pkt_burst = eth_szedata2_rx;
+	if (data->dev_conf.rxmode.enable_scatter == 1 ||
+		data->scattered_rx == 1) {
+		eth_dev->rx_pkt_burst = eth_szedata2_rx_scattered;
+		data->scattered_rx = 1;
+	} else {
+		eth_dev->rx_pkt_burst = eth_szedata2_rx;
+		data->scattered_rx = 0;
+	}
 	eth_dev->tx_pkt_burst = eth_szedata2_tx;
 
 	return 0;
-- 
1.9.1

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

* [PATCH v3 5/6] doc: add documentation for szedata2 PMD
  2015-11-10 14:18   ` [PATCH v3 0/6] Virtual PMD using sze2 layer for COMBO cards Matej Vido
                       ` (3 preceding siblings ...)
  2015-11-10 14:18     ` [PATCH v3 4/6] szedata2: add support for scattered packets in RX Matej Vido
@ 2015-11-10 14:18     ` Matej Vido
  2015-11-10 14:55       ` Mcnamara, John
  2015-11-10 14:18     ` [PATCH v3 6/6] doc: update 2.2 release notes Matej Vido
  2015-11-20 16:19     ` [PATCH v3 0/6] Virtual PMD using sze2 layer for COMBO cards Thomas Monjalon
  6 siblings, 1 reply; 36+ messages in thread
From: Matej Vido @ 2015-11-10 14:18 UTC (permalink / raw)
  To: dev

v3:
Edit formatting.
Add links.

Signed-off-by: Matej Vido <matejvido@gmail.com>
---
 doc/guides/nics/index.rst            |   1 +
 doc/guides/nics/szedata2.rst         | 127 +++++++++++++++++++++++++++++++++++
 doc/guides/prog_guide/source_org.rst |   1 +
 3 files changed, 129 insertions(+)
 create mode 100644 doc/guides/nics/szedata2.rst

diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index 2d4936d..0a0b724 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -46,6 +46,7 @@ Network Interface Controller Drivers
     intel_vf
     mlx4
     mlx5
+    szedata2
     virtio
     vmxnet3
     pcap_ring
diff --git a/doc/guides/nics/szedata2.rst b/doc/guides/nics/szedata2.rst
new file mode 100644
index 0000000..b952b46
--- /dev/null
+++ b/doc/guides/nics/szedata2.rst
@@ -0,0 +1,127 @@
+..  BSD LICENSE
+    Copyright 2015 CESNET
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+    * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+    * Neither the name of CESNET nor the names of its
+    contributors may be used to endorse or promote products derived
+    from this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+SZEDATA2 poll mode driver library
+=================================
+
+The SZEDATA2 poll mode driver library implements support for cards from COMBO
+family (**COMBO-80G**, **COMBO-100G**).
+The SZEDATA2 PMD is virtual PMD which uses interface provided by libsze2
+library to communicate with COMBO cards over sze2 layer.
+
+More information about family of
+`COMBO cards <https://www.liberouter.org/technologies/cards/>`_
+and used technology
+(`NetCOPE platform <https://www.liberouter.org/technologies/netcope/>`_) can be
+found on the `Liberouter website <https://www.liberouter.org/>`_.
+
+.. note::
+
+   This driver has external dependencies.
+   Therefore it is disabled in default configuration files.
+   It can be enabled by setting ``CONFIG_RTE_LIBRTE_PMD_SZEDATA2=y``
+   and recompiling.
+
+Prerequisities
+--------------
+
+This PMD requires kernel modules which are responsible for initialization and
+allocation of resources needed for sze2 layer function.
+Communication between PMD and kernel modules is mediated by libsze2 library.
+These kernel modules and library are not part of DPDK and must be installed
+separately:
+
+*  **libsze2 library**
+
+   The library provides API for initialization of sze2 transfers, receiving and
+   transmitting data segments.
+
+*  **Kernel modules**
+
+   * combov3
+   * szedata2_cv3
+
+   Kernel modules manage initialization of hardware, allocation and
+   sharing of resources for user space applications:
+
+Information about getting the dependencies can be found `here
+<https://www.liberouter.org/technologies/netcope/access-to-libsze2-library/>`_.
+
+
+Using the SZEDATA2 PMD
+----------------------
+
+SZEDATA2 PMD can be created by passing ``--vdev=`` option to EAL in the
+following format:
+
+.. code-block:: console
+
+   --vdev 'DEVICE,dev_path=PATH,rx_ifaces=RX_MASK,tx_ifaces=TX_MASK'
+
+``DEVICE`` and options ``dev_path``, ``rx_ifaces``, ``tx_ifaces`` are mandatory
+and must be separated by commas.
+
+*  ``DEVICE``: contains prefix ``eth_szedata2`` followed by numbers or letters,
+   must be unique for each virtual device
+
+*  ``dev_path``: Defines path to szedata2 device.
+   Value is valid path to szedata2 device. Example:
+
+   .. code-block:: console
+
+      dev_path=/dev/szedataII0
+
+*  ``rx_ifaces``: Defines which receive channels will be used.
+   For each channel is created one queue. Value is mask for selecting which
+   receive channels are required. Example:
+
+   .. code-block:: console
+
+      rx_ifaces=0x3
+
+*  ``tx_ifaces``: Defines which transmit channels will be used.
+   For each channel is created one queue. Value is mask for selecting which
+   transmit channels are required. Example:
+
+   .. code-block:: console
+
+      tx_ifaces=0x3
+
+Example of usage
+----------------
+
+Read packets from 0. and 1. receive channel and write them to 0. and 1.
+transmit channel:
+
+.. code-block:: console
+
+   $RTE_TARGET/app/testpmd -c 0xf -n 2 \
+   --vdev 'eth_szedata20,dev_path=/dev/szedataII0,rx_ifaces=0x3,tx_ifaces=0x3' \
+   -- --port-topology=chained --rxq=2 --txq=2 --nb-cores=2
diff --git a/doc/guides/prog_guide/source_org.rst b/doc/guides/prog_guide/source_org.rst
index ae11b3b..0c06d47 100644
--- a/doc/guides/prog_guide/source_org.rst
+++ b/doc/guides/prog_guide/source_org.rst
@@ -106,6 +106,7 @@ The drivers directory has a *net* subdirectory which contains::
     +-- null               # NULL poll mode driver for testing
     +-- pcap               # PCAP poll mode driver
     +-- ring               # Ring poll mode driver
+    +-- szedata2           # SZEDATA2 poll mode driver
     +-- virtio             # Virtio poll mode driver
     +-- vmxnet3            # VMXNET3 poll mode driver
     +-- xenvirt            # Xen virtio poll mode driver
-- 
1.9.1

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

* [PATCH v3 6/6] doc: update 2.2 release notes
  2015-11-10 14:18   ` [PATCH v3 0/6] Virtual PMD using sze2 layer for COMBO cards Matej Vido
                       ` (4 preceding siblings ...)
  2015-11-10 14:18     ` [PATCH v3 5/6] doc: add documentation for szedata2 PMD Matej Vido
@ 2015-11-10 14:18     ` Matej Vido
  2015-11-16 14:22       ` Mcnamara, John
  2015-11-20 16:19     ` [PATCH v3 0/6] Virtual PMD using sze2 layer for COMBO cards Thomas Monjalon
  6 siblings, 1 reply; 36+ messages in thread
From: Matej Vido @ 2015-11-10 14:18 UTC (permalink / raw)
  To: dev

Add szedata2 PMD to 2.2 release notes.

Signed-off-by: Matej Vido <matejvido@gmail.com>
---
 doc/guides/rel_notes/release_2_2.rst | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/doc/guides/rel_notes/release_2_2.rst b/doc/guides/rel_notes/release_2_2.rst
index ca8471b..2ae9ba3 100644
--- a/doc/guides/rel_notes/release_2_2.rst
+++ b/doc/guides/rel_notes/release_2_2.rst
@@ -90,6 +90,10 @@ New Features
 
 * **Added port hotplug support to xenvirt.**
 
+* **Added virtual szedata2 driver for COMBO cards.**
+
+  Added virtual PMD for COMBO-100G and COMBO-80G cards.
+  PMD is disabled in default configuration.
 
 Resolved Issues
 ---------------
-- 
1.9.1

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

* Re: [PATCH v3 5/6] doc: add documentation for szedata2 PMD
  2015-11-10 14:18     ` [PATCH v3 5/6] doc: add documentation for szedata2 PMD Matej Vido
@ 2015-11-10 14:55       ` Mcnamara, John
  0 siblings, 0 replies; 36+ messages in thread
From: Mcnamara, John @ 2015-11-10 14:55 UTC (permalink / raw)
  To: Matej Vido, dev

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Matej Vido
> Sent: Tuesday, November 10, 2015 2:18 PM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v3 5/6] doc: add documentation for szedata2 PMD
> 
> v3:
> Edit formatting.
> Add links.
> 
> Signed-off-by: Matej Vido <matejvido@gmail.com>

Acked-by: John McNamara <john.mcnamara@intel.com>

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

* Re: [PATCH v3 6/6] doc: update 2.2 release notes
  2015-11-10 14:18     ` [PATCH v3 6/6] doc: update 2.2 release notes Matej Vido
@ 2015-11-16 14:22       ` Mcnamara, John
  0 siblings, 0 replies; 36+ messages in thread
From: Mcnamara, John @ 2015-11-16 14:22 UTC (permalink / raw)
  To: Matej Vido, dev



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Matej Vido
> Sent: Tuesday, November 10, 2015 2:18 PM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v3 6/6] doc: update 2.2 release notes
> 
> Add szedata2 PMD to 2.2 release notes.
> 
> Signed-off-by: Matej Vido <matejvido@gmail.com>

Acked-by: John McNamara <john.mcnamara@intel.com>

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

* Re: [PATCH v3 1/6] szedata2: add new poll mode driver
  2015-11-10 14:18     ` [PATCH v3 1/6] szedata2: add new poll mode driver Matej Vido
@ 2015-11-20 15:04       ` Thomas Monjalon
  2015-11-20 19:25         ` Matej Vido
  0 siblings, 1 reply; 36+ messages in thread
From: Thomas Monjalon @ 2015-11-20 15:04 UTC (permalink / raw)
  To: Matej Vido; +Cc: dev, Viktor Pus

Hi,

I'm doing some last checks before merging.

The libsze2 depends on libcommlbr so it would be better to list it on
https://www.liberouter.org/technologies/netcope/access-to-libsze2-library

A patch is needed in mk/ to allow linking these dependencies from a
non-standard directory: http://dpdk.org/dev/patchwork/patch/9023

As only 64-bit versions of the libraries are provided, I guess we
could mention it is currently supported only on x86-64.


2015-11-10 15:18, Matej Vido:
> +static void
> +eth_stats_get(struct rte_eth_dev *dev,
> +		struct rte_eth_stats *igb_stats)
> +{

igb_stats is a name inherited from old times. It is related to the first
DPDK driver (igb).
I will rename it to "stats".

[...]
> +       long int value;
> +
> +       value = strtol(mask_str, &endptr, 0);
> +       if (*endptr != '\0' || value > UINT32_MAX || value < 0)

This check would not compile in 32-bit environment (which is not supported).

[...]
> +static int
> +rte_eth_from_szedata2(const char *name,
> +               struct rxtx_szedata2 *szedata2,
> +               const unsigned numa_node)
> +{
> +       struct pmd_internals *internals = NULL;
> +       struct rte_eth_dev *eth_dev = NULL;
> +       struct rte_eth_dev_data *data = NULL;

This data variable is not used before the patch 4/6.
I will move it.

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

* Re: [PATCH v3 0/6] Virtual PMD using sze2 layer for COMBO cards
  2015-11-10 14:18   ` [PATCH v3 0/6] Virtual PMD using sze2 layer for COMBO cards Matej Vido
                       ` (5 preceding siblings ...)
  2015-11-10 14:18     ` [PATCH v3 6/6] doc: update 2.2 release notes Matej Vido
@ 2015-11-20 16:19     ` Thomas Monjalon
  6 siblings, 0 replies; 36+ messages in thread
From: Thomas Monjalon @ 2015-11-20 16:19 UTC (permalink / raw)
  To: Matej Vido; +Cc: dev

2015-11-10 15:18, Matej Vido:
> This is virtual PMD which communicates with COMBO-80G and COMBO-100G
> cards through sze2 layer. Communication with COMBO card is managed
> through interface provided by libsze2 library and kernel modules
> (combov3, szedata2_cv3).
> 
> To compile and use PMD, it is necessary to have libsze2 library installed and
> kernel modules (combov3, szedata2_cv3) loaded.
> Therefore in default configuration PMD compilation is disabled. To compile
> szedata2 PMD, it is necessary to enable CONFIG_RTE_LIBRTE_PMD_SZEDATA2=y.

Applied with few cleanups, thanks

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

* Re: [PATCH v3 1/6] szedata2: add new poll mode driver
  2015-11-20 15:04       ` Thomas Monjalon
@ 2015-11-20 19:25         ` Matej Vido
  2015-11-21 10:27           ` Thomas Monjalon
  0 siblings, 1 reply; 36+ messages in thread
From: Matej Vido @ 2015-11-20 19:25 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev, Viktor Pus

Hi,

2015-11-20 16:04 GMT+01:00 Thomas Monjalon <thomas.monjalon@6wind.com>:

> Hi,
>
> I'm doing some last checks before merging.
>
> The libsze2 depends on libcommlbr so it would be better to list it on
> https://www.liberouter.org/technologies/netcope/access-to-libsze2-library


Thank you for reminding, I will edit it.


>
>
> A patch is needed in mk/ to allow linking these dependencies from a
> non-standard directory: http://dpdk.org/dev/patchwork/patch/9023
>
> As only 64-bit versions of the libraries are provided, I guess we
> could mention it is currently supported only on x86-64.
>

I agree. Should I update the documentation and send a patch?


>
>
> 2015-11-10 15:18, Matej Vido:
> > +static void
> > +eth_stats_get(struct rte_eth_dev *dev,
> > +             struct rte_eth_stats *igb_stats)
> > +{
>
> igb_stats is a name inherited from old times. It is related to the first
> DPDK driver (igb).
> I will rename it to "stats".
>
> [...]
> > +       long int value;
> > +
> > +       value = strtol(mask_str, &endptr, 0);
> > +       if (*endptr != '\0' || value > UINT32_MAX || value < 0)
>
> This check would not compile in 32-bit environment (which is not
> supported).
>
> [...]
> > +static int
> > +rte_eth_from_szedata2(const char *name,
> > +               struct rxtx_szedata2 *szedata2,
> > +               const unsigned numa_node)
> > +{
> > +       struct pmd_internals *internals = NULL;
> > +       struct rte_eth_dev *eth_dev = NULL;
> > +       struct rte_eth_dev_data *data = NULL;
>
> This data variable is not used before the patch 4/6.
> I will move it.
>

Thanks for handling these changes.


Regards,
Matej

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

* Re: [PATCH v3 1/6] szedata2: add new poll mode driver
  2015-11-20 19:25         ` Matej Vido
@ 2015-11-21 10:27           ` Thomas Monjalon
  0 siblings, 0 replies; 36+ messages in thread
From: Thomas Monjalon @ 2015-11-21 10:27 UTC (permalink / raw)
  To: Matej Vido; +Cc: dev, Viktor Pus

2015-11-20 20:25, Matej Vido:
> > As only 64-bit versions of the libraries are provided, I guess we
> > could mention it is currently supported only on x86-64.
> 
> I agree. Should I update the documentation and send a patch?

Yes please.

Another note: I use -rpath= in EXTRA_LDFLAGS to find the dependency of the dependency ;)

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

* Re: [PATCH 1/2] szedata2: new poll mode driver
  2015-06-19  8:25 ` [PATCH 1/2] szedata2: new poll mode driver Matej Vido
@ 2016-03-21 17:45   ` Stephen Hemminger
  2016-03-24 17:52     ` Matej Vido
  0 siblings, 1 reply; 36+ messages in thread
From: Stephen Hemminger @ 2016-03-21 17:45 UTC (permalink / raw)
  To: Matej Vido; +Cc: dev

On Fri, 19 Jun 2015 10:25:00 +0200
Matej Vido <vido@cesnet.cz> wrote:

> +static struct ether_addr eth_addr = {
> +	.addr_bytes = { 0, 0, 0, 0x1, 0x2, 0x3 }
> +};
...

> static int
> rte_szedata2_eth_dev_init(struct rte_eth_dev *dev)
> {
.. 
> 	/* 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");
> 		munmap(dev->pci_dev->mem_resource[PCI_RESOURCE_NUMBER].addr,
> 			dev->pci_dev->mem_resource[PCI_RESOURCE_NUMBER].len);
> 		return -EINVAL;
> 	}
> 
> 	ether_addr_copy(&eth_addr, data->mac_addrs);

If your hardware has no permanent MAC address, then please use eth_random_addr()
to make one on boot, rather than having a bogus static value.

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

* Re: [PATCH 1/2] szedata2: new poll mode driver
  2016-03-21 17:45   ` Stephen Hemminger
@ 2016-03-24 17:52     ` Matej Vido
  0 siblings, 0 replies; 36+ messages in thread
From: Matej Vido @ 2016-03-24 17:52 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev

Dňa 21.03.2016 o 18:45 Stephen Hemminger napísal(a):
> On Fri, 19 Jun 2015 10:25:00 +0200
> Matej Vido <vido@cesnet.cz> wrote:
>
>> +static struct ether_addr eth_addr = {
>> +	.addr_bytes = { 0, 0, 0, 0x1, 0x2, 0x3 }
>> +};
> ...
>
>> static int
>> rte_szedata2_eth_dev_init(struct rte_eth_dev *dev)
>> {
> ..
>> 	/* 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");
>> 		munmap(dev->pci_dev->mem_resource[PCI_RESOURCE_NUMBER].addr,
>> 			dev->pci_dev->mem_resource[PCI_RESOURCE_NUMBER].len);
>> 		return -EINVAL;
>> 	}
>>
>> 	ether_addr_copy(&eth_addr, data->mac_addrs);
> If your hardware has no permanent MAC address, then please use eth_random_addr()
> to make one on boot, rather than having a bogus static value.
Hi,

I will use it.

Thanks,
Matej

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

end of thread, other threads:[~2016-03-24 17:52 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-19  8:24 [PATCH 0/2] Virtual PMD using sze2 layer for COMBO cards Matej Vido
2015-06-19  8:25 ` [PATCH 1/2] szedata2: new poll mode driver Matej Vido
2016-03-21 17:45   ` Stephen Hemminger
2016-03-24 17:52     ` Matej Vido
2015-06-19  8:25 ` [PATCH 2/2] doc: added documentation for szedata2 PMD Matej Vido
2015-09-18  8:32 ` [PATCH v2 0/5] Virtual PMD using sze2 layer for COMBO cards Matej Vido
2015-09-18  8:32   ` [PATCH v2 1/5] szedata2: add new poll mode driver Matej Vido
2015-10-26 15:10     ` Thomas Monjalon
2015-09-18  8:32   ` [PATCH v2 2/5] szedata2: add handling of scattered packets in RX Matej Vido
2015-09-18  8:32   ` [PATCH v2 3/5] szedata2: add handling of scattered packets in TX Matej Vido
2015-10-26 14:55     ` Thomas Monjalon
2015-10-27 17:40       ` Matej Vido
2015-09-18  8:32   ` [PATCH v2 4/5] doc: add documentation for szedata2 PMD Matej Vido
2015-10-26 15:00     ` Thomas Monjalon
2015-10-26 15:09     ` Thomas Monjalon
2015-10-27 17:33       ` Matej Vido
2015-10-27 18:00         ` Thomas Monjalon
2015-11-02 14:26           ` Matej Vido
2015-10-30 12:16     ` Mcnamara, John
2015-11-06 14:34       ` Matej Vido
2015-09-18  8:32   ` [PATCH v2 5/5] doc: update 2.2 release notes Matej Vido
2015-09-24 16:23     ` [PATCH v2] doc: update the dpdk " John McNamara
2015-09-24 21:14       ` Thomas Monjalon
2015-11-10 14:18   ` [PATCH v3 0/6] Virtual PMD using sze2 layer for COMBO cards Matej Vido
2015-11-10 14:18     ` [PATCH v3 1/6] szedata2: add new poll mode driver Matej Vido
2015-11-20 15:04       ` Thomas Monjalon
2015-11-20 19:25         ` Matej Vido
2015-11-21 10:27           ` Thomas Monjalon
2015-11-10 14:18     ` [PATCH v3 2/6] szedata2: add non-scattered RX function Matej Vido
2015-11-10 14:18     ` [PATCH v3 3/6] szedata2: add TX function Matej Vido
2015-11-10 14:18     ` [PATCH v3 4/6] szedata2: add support for scattered packets in RX Matej Vido
2015-11-10 14:18     ` [PATCH v3 5/6] doc: add documentation for szedata2 PMD Matej Vido
2015-11-10 14:55       ` Mcnamara, John
2015-11-10 14:18     ` [PATCH v3 6/6] doc: update 2.2 release notes Matej Vido
2015-11-16 14:22       ` Mcnamara, John
2015-11-20 16:19     ` [PATCH v3 0/6] Virtual PMD using sze2 layer for COMBO cards Thomas Monjalon

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.