All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/8] add net/crypto mrvl pmd drivers
@ 2017-09-26  9:39 Tomasz Duszynski
  2017-09-26  9:39 ` [PATCH 1/8] app: link the whole rte_cfgfile library Tomasz Duszynski
                   ` (10 more replies)
  0 siblings, 11 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-26  9:39 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Tomasz Duszynski

Hello,

This patch series introduces net/crypto drivers for Marvell Armada 7k/8k
SoCs along with documentation and crypto driver pmd tests.

Below you can find the list of features which net/crypto pmds support.

Net pmd features:
* Speed capabilities
* Link status
* Queue start/stop
* MTU update
* Jumbo frame
* Promiscuous mode
* Allmulticast mode
* Unicast MAC filter
* Multicast MAC filter
* RSS hash
* VLAN filter
* CRC offload
* L3 checksum offload
* L4 checksum offload
* Packet type parsing
* Basic stats
* Stats per queue

Cryto pmd features:
* Symmetric crypto
* Sym operation chaining
* AES CBC (128)
* AES CBC (192)
* AES CBC (256)
* AES CTR (128)
* AES CTR (192)
* AES CTR (256)
* 3DES CBC
* 3DES CTR
* MD5
* MD5 HMAC
* SHA1
* SHA1 HMAC
* SHA256
* SHA256 HMAC
* SHA384
* SHA384 HMAC
* SHA512
* SHA512 HMAC
* AES GCM (128)

Tomasz Duszynski (8):
  app: link the whole rte_cfgfile library
  net/mrvl: add mrvl net pmd driver
  doc: add mrvl net pmd documentation
  maintainers: add maintainers for the mrvl net pmd
  crypto/mrvl: add mrvl crypto pmd driver
  doc: add mrvl crypto pmd documentation
  maintainers: add maintainers for the mrvl crypto pmd
  test: add mrvl crypto pmd unit tests

 MAINTAINERS                                  |   20 +
 config/common_base                           |   13 +
 doc/guides/cryptodevs/features/mrvl.ini      |   42 +
 doc/guides/cryptodevs/index.rst              |    1 +
 doc/guides/cryptodevs/mrvl.rst               |  198 +++
 doc/guides/nics/features/mrvl.ini            |   24 +
 doc/guides/nics/index.rst                    |    1 +
 doc/guides/nics/mrvl.rst                     |  151 ++
 drivers/crypto/Makefile                      |    2 +
 drivers/crypto/mrvl/Makefile                 |   63 +
 drivers/crypto/mrvl/rte_mrvl_compat.h        |   48 +
 drivers/crypto/mrvl/rte_mrvl_pmd.c           |  866 ++++++++++
 drivers/crypto/mrvl/rte_mrvl_pmd_ops.c       |  787 +++++++++
 drivers/crypto/mrvl/rte_mrvl_pmd_private.h   |  121 ++
 drivers/crypto/mrvl/rte_mrvl_pmd_version.map |    3 +
 drivers/net/Makefile                         |    2 +
 drivers/net/mrvl/Makefile                    |   69 +
 drivers/net/mrvl/mrvl_ethdev.c               | 2277 ++++++++++++++++++++++++++
 drivers/net/mrvl/mrvl_ethdev.h               |  115 ++
 drivers/net/mrvl/mrvl_qos.c                  |  627 +++++++
 drivers/net/mrvl/mrvl_qos.h                  |  112 ++
 drivers/net/mrvl/rte_pmd_mrvl_version.map    |    3 +
 mk/rte.app.mk                                |    4 +-
 test/test/test_cryptodev.c                   |  168 ++
 test/test/test_cryptodev.h                   |    1 +
 test/test/test_cryptodev_aes_test_vectors.h  |   72 +-
 test/test/test_cryptodev_blockcipher.c       |    9 +-
 test/test/test_cryptodev_blockcipher.h       |    1 +
 test/test/test_cryptodev_des_test_vectors.h  |   24 +-
 29 files changed, 5790 insertions(+), 34 deletions(-)
 create mode 100644 doc/guides/cryptodevs/features/mrvl.ini
 create mode 100644 doc/guides/cryptodevs/mrvl.rst
 create mode 100644 doc/guides/nics/features/mrvl.ini
 create mode 100644 doc/guides/nics/mrvl.rst
 create mode 100644 drivers/crypto/mrvl/Makefile
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_compat.h
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd.c
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_private.h
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_version.map
 create mode 100644 drivers/net/mrvl/Makefile
 create mode 100644 drivers/net/mrvl/mrvl_ethdev.c
 create mode 100644 drivers/net/mrvl/mrvl_ethdev.h
 create mode 100644 drivers/net/mrvl/mrvl_qos.c
 create mode 100644 drivers/net/mrvl/mrvl_qos.h
 create mode 100644 drivers/net/mrvl/rte_pmd_mrvl_version.map

--
2.7.4

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

* [PATCH 1/8] app: link the whole rte_cfgfile library
  2017-09-26  9:39 [PATCH 0/8] add net/crypto mrvl pmd drivers Tomasz Duszynski
@ 2017-09-26  9:39 ` Tomasz Duszynski
  2017-09-26 14:31   ` Bruce Richardson
  2017-09-26  9:39 ` [PATCH 2/8] net/mrvl: add mrvl net pmd driver Tomasz Duszynski
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-26  9:39 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Tomasz Duszynski, Jacek Siuda

Since MRVL NET PMD needs librte_cfgfile to parse QoS configuration file
link it as the whole library.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 mk/rte.app.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index c25fdd9..94568a8 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -81,10 +81,10 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)          += -lrte_power
 
 _LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)            += -lrte_efd
-_LDLIBS-$(CONFIG_RTE_LIBRTE_CFGFILE)        += -lrte_cfgfile
 
 _LDLIBS-y += --whole-archive
 
+_LDLIBS-$(CONFIG_RTE_LIBRTE_CFGFILE)        += -lrte_cfgfile
 _LDLIBS-$(CONFIG_RTE_LIBRTE_HASH)           += -lrte_hash
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VHOST)          += -lrte_vhost
 _LDLIBS-$(CONFIG_RTE_LIBRTE_KVARGS)         += -lrte_kvargs
-- 
2.7.4

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

* [PATCH 2/8] net/mrvl: add mrvl net pmd driver
  2017-09-26  9:39 [PATCH 0/8] add net/crypto mrvl pmd drivers Tomasz Duszynski
  2017-09-26  9:39 ` [PATCH 1/8] app: link the whole rte_cfgfile library Tomasz Duszynski
@ 2017-09-26  9:39 ` Tomasz Duszynski
  2017-09-26  9:40 ` [PATCH 3/8] doc: add mrvl net pmd documentation Tomasz Duszynski
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-26  9:39 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Tomasz Duszynski, Jacek Siuda

Add support for the Marvell PPv2 (Packet Processor v2) 1/10 Gbps adapter.
Driver is based on external, publicly available, light-weight Marvell
MUSDK library that provides access to network packet processor.

Driver comes with support for the following features:

* Speed capabilities
* Link status
* Queue start/stop
* MTU update
* Jumbo frame
* Promiscuous mode
* Allmulticast mode
* Unicast MAC filter
* Multicast MAC filter
* RSS hash
* VLAN filter
* CRC offload
* L3 checksum offload
* L4 checksum offload
* Packet type parsing
* Basic stats
* Stats per queue

Driver was engineered cooperatively by Semihalf and Marvell teams.

Semihalf:
Jacek Siuda <jck@semihalf.com>
Tomasz Duszynski <tdu@semihalf.com>

Marvell:
Dmitri Epshtein <dima@marvell.com>
Natalie Samsonov <nsamsono@marvell.com>

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 config/common_base                        |    7 +
 drivers/net/Makefile                      |    2 +
 drivers/net/mrvl/Makefile                 |   69 +
 drivers/net/mrvl/mrvl_ethdev.c            | 2277 +++++++++++++++++++++++++++++
 drivers/net/mrvl/mrvl_ethdev.h            |  115 ++
 drivers/net/mrvl/mrvl_qos.c               |  627 ++++++++
 drivers/net/mrvl/mrvl_qos.h               |  112 ++
 drivers/net/mrvl/rte_pmd_mrvl_version.map |    3 +
 mk/rte.app.mk                             |    1 +
 9 files changed, 3213 insertions(+)
 create mode 100644 drivers/net/mrvl/Makefile
 create mode 100644 drivers/net/mrvl/mrvl_ethdev.c
 create mode 100644 drivers/net/mrvl/mrvl_ethdev.h
 create mode 100644 drivers/net/mrvl/mrvl_qos.c
 create mode 100644 drivers/net/mrvl/mrvl_qos.h
 create mode 100644 drivers/net/mrvl/rte_pmd_mrvl_version.map

diff --git a/config/common_base b/config/common_base
index 5e97a08..d05a60c 100644
--- a/config/common_base
+++ b/config/common_base
@@ -262,6 +262,13 @@ CONFIG_RTE_LIBRTE_NFP_PMD=n
 CONFIG_RTE_LIBRTE_NFP_DEBUG=n
 
 #
+# Compile Marvell PMD driver
+#
+CONFIG_RTE_LIBRTE_MRVL_PMD=n
+CONFIG_RTE_LIBRTE_MRVL_DEBUG=n
+CONFIG_RTE_MRVL_MUSDK_DMA_MEMSIZE=41943040
+
+#
 # Compile burst-oriented Broadcom BNXT PMD driver
 #
 CONFIG_RTE_LIBRTE_BNXT_PMD=y
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index d33c959..4a3a205 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -73,6 +73,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4
 DEPDIRS-mlx4 = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5
 DEPDIRS-mlx5 = $(core-libs)
+DIRS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl
+DEPDIRS-mrvl = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_NFP_PMD) += nfp
 DEPDIRS-nfp = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt
diff --git a/drivers/net/mrvl/Makefile b/drivers/net/mrvl/Makefile
new file mode 100644
index 0000000..ab53f49
--- /dev/null
+++ b/drivers/net/mrvl/Makefile
@@ -0,0 +1,69 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2017 Semihalf. 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 Semihalf 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
+
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),config)
+ifeq ($(LIBMUSDK_PATH),)
+$(error "Please define LIBMUSDK_PATH environment variable")
+endif
+ifeq ($(CONFIG_RTE_LIBRTE_CFGFILE),n)
+$(error "RTE_LIBRTE_CFGFILE must be enabled in configuration!")
+endif
+endif
+endif
+
+# library name
+LIB = librte_pmd_mrvl.a
+
+# library version
+LIBABIVER := 1
+
+# versioning export map
+EXPORT_MAP := rte_pmd_mrvl_version.map
+
+# external library dependencies
+CFLAGS += -I$(LIBMUSDK_PATH)/include
+CFLAGS += -DMVCONF_ARCH_DMA_ADDR_T_64BIT
+CFLAGS += -DCONF_PP2_BPOOL_COOKIE_SIZE=32
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -O3
+LDLIBS += -L$(LIBMUSDK_PATH)/lib
+LDLIBS += -lmusdk
+
+# library source files
+SRCS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl_qos.c
+
+# library dependencies
+DEPDIRS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += lib/librte_cfgfile
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/mrvl/mrvl_ethdev.c b/drivers/net/mrvl/mrvl_ethdev.c
new file mode 100644
index 0000000..6ef9a32
--- /dev/null
+++ b/drivers/net/mrvl/mrvl_ethdev.c
@@ -0,0 +1,2277 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Semihalf. 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 Semihalf 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_ethdev.h>
+#include <rte_kvargs.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_vdev.h>
+#include <rte_cycles.h>
+
+/* Unluckily, container_of is defined by both DPDK and MUSDK,
+ * we'll declare only one version.
+ *
+ * Note that it is not used in this PMD anyway.
+ */
+#ifdef container_of
+#undef container_of
+#endif
+
+#include <drivers/mv_pp2.h>
+#include <drivers/mv_pp2_bpool.h>
+#include <drivers/mv_pp2_hif.h>
+
+#include <assert.h>
+#include <fcntl.h>
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "mrvl_ethdev.h"
+#include "mrvl_qos.h"
+
+/* bitmask with reserved hifs */
+#define MRVL_MUSDK_HIFS_RESERVED 0x0F
+/* bitmask with reserved bpools */
+#define MRVL_MUSDK_BPOOLS_RESERVED 0x07
+/* bitmask with reserved kernel RSS tables */
+#define MRVL_MUSDK_RSS_RESERVED 0x01
+/* maximum number of available hifs */
+#define MRVL_MUSDK_HIFS_MAX 9
+
+/* prefetch shift */
+#define MRVL_MUSDK_PREFETCH_SHIFT 2
+
+/* TCAM has 25 entries reserved for uc/mc filter entries */
+#define MRVL_MAC_ADDRS_MAX 25
+#define MRVL_MATCH_LEN 16
+#define MRVL_PKT_EFFEC_OFFS (MRVL_PKT_OFFS + MV_MH_SIZE)
+/* Maximum allowable packet size */
+#define MRVL_PKT_SIZE_MAX (10240 - MV_MH_SIZE)
+
+#define MRVL_IFACE_NAME_ARG "iface"
+#define MRVL_CFG_ARG "cfg"
+
+#define MRVL_BURST_SIZE 64
+
+#define MRVL_ARP_LENGTH 28
+
+#define MRVL_COOKIE_ADDR_INVALID ~0ULL
+
+#define MRVL_COOKIE_HIGH_ADDR_SHIFT	(sizeof(pp2_cookie_t) * 8)
+#define MRVL_COOKIE_HIGH_ADDR_MASK	(~0ULL << MRVL_COOKIE_HIGH_ADDR_SHIFT)
+
+static const char * const valid_args[] = {
+	MRVL_IFACE_NAME_ARG,
+	MRVL_CFG_ARG,
+	NULL
+};
+
+static int used_hifs = MRVL_MUSDK_HIFS_RESERVED;
+static struct pp2_hif *hifs[RTE_MAX_LCORE];
+static int used_bpools[PP2_NUM_PKT_PROC] = {
+	MRVL_MUSDK_BPOOLS_RESERVED,
+	MRVL_MUSDK_BPOOLS_RESERVED
+};
+
+struct pp2_bpool *mrvl_port_to_bpool_lookup[RTE_MAX_ETHPORTS];
+int mrvl_port_bpool_size[PP2_NUM_PKT_PROC][PP2_BPOOL_NUM_POOLS][RTE_MAX_LCORE];
+uint64_t cookie_addr_high = MRVL_COOKIE_ADDR_INVALID;
+
+/*
+ * To use buffer harvesting based on loopback port shadow queue structure
+ * was introduced for buffers information bookkeeping.
+ *
+ * Before sending the packet, related buffer information (pp2_buff_inf) is
+ * stored in shadow queue. After packet is transmitted no longer used
+ * packet buffer is released back to it's original hardware pool,
+ * on condition it originated from interface.
+ * In case it  was generated by application itself i.e: mbuf->port field is
+ * 0xff then its released to software mempool.
+ */
+struct mrvl_shadow_txq {
+	int head;           /* write index - used when sending buffers */
+	int tail;           /* read index - used when releasing buffers */
+	u16 size;           /* queue occupied size */
+	u16 num_to_release; /* number of buffers sent, that can be released */
+	struct buff_release_entry ent[MRVL_PP2_TX_SHADOWQ_SIZE]; /* q entries */
+};
+
+struct mrvl_rxq;
+struct mrvl_txq;
+
+struct mrvl_rxq {
+	struct mrvl_priv *priv;
+	struct rte_mempool *mp;
+	int queue_id;
+	int port_id;
+	int cksum_enabled;
+	uint64_t bytes_recv;
+	uint64_t drop_mac;
+};
+
+struct mrvl_txq {
+	struct mrvl_priv *priv;
+	int queue_id;
+	int port_id;
+	uint64_t bytes_sent;
+};
+
+/*
+ * Every tx queue should have dedicated shadow tx queue.
+ *
+ * Ports assigned by DPDK might not start at zero or be continuous so
+ * as a workaround define shadow queues for each possible port so that
+ * we eventually fit somewhere.
+ */
+struct mrvl_shadow_txq shadow_txqs[RTE_MAX_ETHPORTS][RTE_MAX_LCORE];
+
+/** Number of ports configured. */
+int mrvl_ports_nb;
+static int mrvl_lcore_first;
+static int mrvl_lcore_last;
+
+static inline int
+mrvl_get_bpool_size(int	pp2_id, int pool_id)
+{
+	int i;
+	int size = 0;
+
+	for (i = mrvl_lcore_first; i <= mrvl_lcore_last; i++)
+		size += mrvl_port_bpool_size[pp2_id][pool_id][i];
+
+	return size;
+}
+
+
+static inline int
+mrvl_reserve_bit(int *bitmap, int max)
+{
+	int n = sizeof(*bitmap) * 8 - __builtin_clz(*bitmap);
+	if (n >= max)
+		return -1;
+
+	*bitmap |= 1 << n;
+
+	return n;
+}
+
+/**
+ * Configure rss based on dpdk rss configuration.
+ *
+ * @param priv
+ *   Pointer to private structure.
+ * @param rss_conf
+ *   Pointer to RSS configuration.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_configure_rss(struct mrvl_priv *priv, struct rte_eth_rss_conf *rss_conf)
+{
+	if (rss_conf->rss_key)
+		RTE_LOG(WARNING, PMD, "Changing hash key is not supported\n");
+
+	if (rss_conf->rss_hf == 0) {
+		priv->ppio_params.inqs_params.hash_type = PP2_PPIO_HASH_T_NONE;
+	} else if (rss_conf->rss_hf & ETH_RSS_IPV4) {
+		priv->ppio_params.inqs_params.hash_type =
+			PP2_PPIO_HASH_T_2_TUPLE;
+	} else if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV4_TCP) {
+		priv->ppio_params.inqs_params.hash_type =
+			PP2_PPIO_HASH_T_5_TUPLE;
+		priv->rss_hf_tcp = 1;
+	} else if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV4_UDP) {
+		priv->ppio_params.inqs_params.hash_type =
+			PP2_PPIO_HASH_T_5_TUPLE;
+		priv->rss_hf_tcp = 0;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * Ethernet device configuration.
+ *
+ * Prepare the driver for a given number of TX and RX queues and
+ * configure RSS.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_dev_configure(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	if (dev->data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_NONE &&
+	    dev->data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_RSS) {
+		RTE_LOG(INFO, PMD, "Unsupported rx multi queue mode %d\n",
+			dev->data->dev_conf.rxmode.mq_mode);
+		return -EINVAL;
+	}
+
+	if (!dev->data->dev_conf.rxmode.hw_strip_crc) {
+		RTE_LOG(INFO, PMD,
+			"L2 CRC stripping is always enabled in hw\n");
+		dev->data->dev_conf.rxmode.hw_strip_crc = 1;
+	}
+
+	if (dev->data->dev_conf.rxmode.hw_vlan_strip) {
+		RTE_LOG(INFO, PMD, "VLAN stripping not supported\n");
+		return -EINVAL;
+	}
+
+	if (dev->data->dev_conf.rxmode.split_hdr_size) {
+		RTE_LOG(INFO, PMD, "Split headers not supported\n");
+		return -EINVAL;
+	}
+
+	if (dev->data->dev_conf.rxmode.enable_scatter) {
+		RTE_LOG(INFO, PMD, "RX Scatter/Gather not supported\n");
+		return -EINVAL;
+	}
+
+	if (dev->data->dev_conf.rxmode.enable_lro) {
+		RTE_LOG(INFO, PMD, "LRO not supported\n");
+		return -EINVAL;
+	}
+
+	if (dev->data->dev_conf.rxmode.jumbo_frame)
+		dev->data->mtu = dev->data->dev_conf.rxmode.max_rx_pkt_len -
+				 ETHER_HDR_LEN - ETHER_CRC_LEN;
+
+	ret = mrvl_configure_rxqs(priv, dev->data->port_id,
+		dev->data->nb_rx_queues);
+	if (ret < 0)
+		return ret;
+
+
+	priv->ppio_params.outqs_params.num_outqs = dev->data->nb_tx_queues;
+	priv->ppio_params.maintain_stats = 1;
+	priv->nb_rx_queues = dev->data->nb_rx_queues;
+
+	if (dev->data->nb_rx_queues == 1 &&
+	    dev->data->dev_conf.rxmode.mq_mode == ETH_MQ_RX_RSS) {
+		RTE_LOG(WARNING, PMD, "Disabling hash for 1 rx queue\n");
+		priv->ppio_params.inqs_params.hash_type = PP2_PPIO_HASH_T_NONE;
+
+		return 0;
+	}
+
+	return mrvl_configure_rss(priv,
+				  &dev->data->dev_conf.rx_adv_conf.rss_conf);
+}
+
+/**
+ * DPDK callback to change the MTU.
+ *
+ * Setting the MTU affects hardware MRU (packets larger than the MRU
+ * will be dropped).
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mtu
+ *   New MTU.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	/* extra MV_MH_SIZE bytes are required for Marvell tag */
+	uint16_t mru = mtu + MV_MH_SIZE + ETHER_HDR_LEN + ETHER_CRC_LEN;
+	int ret;
+
+	if ((mtu < ETHER_MIN_MTU) || (mru > MRVL_PKT_SIZE_MAX))
+		return -EINVAL;
+
+	ret = pp2_ppio_set_mru(priv->ppio, mru);
+	if (ret)
+		return ret;
+
+	return pp2_ppio_set_mtu(priv->ppio, mtu);
+}
+
+/**
+ * DPDK callback to bring the link up.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_dev_set_link_up(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_enable(priv->ppio);
+	if (ret)
+		return ret;
+
+	/*
+	 * mtu/mru can be updated if pp2_ppio_enable() was called at least once
+	 * as pp2_ppio_enable() changes port->t_mode from default 0 to
+	 * PP2_TRAFFIC_INGRESS_EGRESS.
+	 *
+	 * Set mtu to default DPDK value here.
+	 */
+	ret = mrvl_mtu_set(dev, dev->data->mtu);
+	if (ret)
+		pp2_ppio_disable(priv->ppio);
+
+	dev->data->dev_link.link_status = ETH_LINK_UP;
+
+	return ret;
+}
+
+/**
+ * DPDK callback to bring the link down.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_dev_set_link_down(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_disable(priv->ppio);
+	if (ret)
+		return ret;
+
+	dev->data->dev_link.link_status = ETH_LINK_DOWN;
+
+	return ret;
+}
+
+/**
+ * DPDK callback to start the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, negative errno value on failure.
+ */
+static int
+mrvl_dev_start(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	char match[MRVL_MATCH_LEN];
+	int ret;
+
+	snprintf(match, sizeof(match), "ppio-%d:%d",
+		 priv->pp_id, priv->ppio_id);
+	priv->ppio_params.match = match;
+
+	/*
+	 * Calculate the maximum bpool size for refill feature to 1.5 of the
+	 * configured size. In case the bpool size will exceed this value,
+	 * superfluous buffers will be removed
+	 */
+	priv->bpool_max_size = priv->bpool_init_size +
+			      (priv->bpool_init_size >> 1);
+	/*
+	 * Calculate the minimum bpool size for refill feature as follows:
+	 * 2 default burst sizes multiply by number of rx queues.
+	 * If the bpool size will be below this value, new buffers will
+	 * be added to the pool.
+	 */
+	priv->bpool_min_size = priv->nb_rx_queues * MRVL_BURST_SIZE * 2;
+
+	ret = pp2_ppio_init(&priv->ppio_params, &priv->ppio);
+	if (ret)
+		return ret;
+
+	/*
+	 * In case there are some some stale uc/mc mac addresses flush them
+	 * here. It cannot be done during mrvl_dev_close() as port information
+	 * is already gone at that point (due to pp2_ppio_deinit() in
+	 * mrvl_dev_stop()).
+	 */
+	if (!priv->uc_mc_flushed) {
+		ret = pp2_ppio_flush_mac_addrs(priv->ppio, 1, 1);
+		if (ret) {
+			RTE_LOG(ERR, PMD,
+				"Failed to flush uc/mc filter list\n");
+			goto out;
+		}
+		priv->uc_mc_flushed = 1;
+	}
+
+	if (!priv->vlan_flushed) {
+		ret = pp2_ppio_flush_vlan(priv->ppio);
+		if (ret) {
+			RTE_LOG(ERR, PMD, "Failed to flush vlan list\n");
+			/*
+			 * TODO
+			 * once pp2_ppio_flush_vlan() is supported jump to out
+			 * goto out;
+			 */
+		}
+		priv->vlan_flushed = 1;
+	}
+
+	/* For default QoS config, don't start classifier. */
+	if (mrvl_qos_cfg != NULL) {
+		ret = mrvl_start_qos_mapping(priv);
+		if (ret) {
+			pp2_ppio_deinit(priv->ppio);
+			return ret;
+		}
+	}
+
+	ret = mrvl_dev_set_link_up(dev);
+	if (ret)
+		goto out;
+
+	return 0;
+out:
+	pp2_ppio_deinit(priv->ppio);
+	return ret;
+}
+
+/**
+ * Flush receive queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_flush_rx_queues(struct rte_eth_dev *dev)
+{
+	int i;
+
+	RTE_LOG(INFO, PMD, "Flushing rx queues\n");
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		int ret, num;
+
+		do {
+			struct mrvl_rxq *q = dev->data->rx_queues[i];
+			struct pp2_ppio_desc descs[MRVL_PP2_RXD_MAX];
+
+			num = MRVL_PP2_RXD_MAX;
+			ret = pp2_ppio_recv(q->priv->ppio,
+					    q->priv->rxq_map[q->queue_id].tc,
+					    q->priv->rxq_map[q->queue_id].inq,
+					    descs, (uint16_t *)&num);
+		} while (ret == 0 && num);
+	}
+}
+
+/**
+ * Flush transmit shadow queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_flush_tx_shadow_queues(struct rte_eth_dev *dev)
+{
+	int i;
+
+	RTE_LOG(INFO, PMD, "Flushing tx shadow queues\n");
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		struct mrvl_shadow_txq *sq =
+			&shadow_txqs[dev->data->port_id][i];
+
+		while (sq->tail != sq->head) {
+			uint64_t addr = cookie_addr_high |
+					sq->ent[sq->tail].buff.cookie;
+			rte_pktmbuf_free((struct rte_mbuf *)addr);
+			sq->tail = (sq->tail + 1) & MRVL_PP2_TX_SHADOWQ_MASK;
+		}
+
+		memset(sq, 0, sizeof(*sq));
+	}
+}
+
+/**
+ * Flush hardware bpool (buffer-pool).
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_flush_bpool(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	uint32_t num;
+	int ret;
+
+	ret = pp2_bpool_get_num_buffs(priv->bpool, &num);
+	if (ret) {
+		RTE_LOG(ERR, PMD, "Failed to get bpool buffers number\n");
+		return;
+	}
+
+	while (num--) {
+		struct pp2_buff_inf inf;
+		uint64_t addr;
+
+		ret = pp2_bpool_get_buff(hifs[rte_lcore_id()], priv->bpool,
+					 &inf);
+		if (ret)
+			break;
+
+		addr = cookie_addr_high | inf.cookie;
+		rte_pktmbuf_free((struct rte_mbuf *)addr);
+	}
+}
+
+/**
+ * DPDK callback to stop the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_dev_stop(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	mrvl_dev_set_link_down(dev);
+	mrvl_flush_rx_queues(dev);
+	mrvl_flush_tx_shadow_queues(dev);
+	if (priv->qos_tbl)
+		pp2_cls_qos_tbl_deinit(priv->qos_tbl);
+	pp2_ppio_deinit(priv->ppio);
+	priv->ppio = NULL;
+}
+
+/**
+ * DPDK callback to close the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_dev_close(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	size_t i;
+
+	for (i = 0; i < priv->ppio_params.inqs_params.num_tcs; ++i)
+		if (priv->ppio_params.inqs_params.tcs_params[i].inqs_params) {
+			rte_free(priv->ppio_params.inqs_params.
+				tcs_params[i].inqs_params);
+			priv->ppio_params.inqs_params.
+				tcs_params[i].inqs_params = NULL;
+		}
+
+	mrvl_flush_bpool(dev);
+}
+
+/**
+ * DPDK callback to retrieve physical link information.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param wait_to_complete
+ *   Wait for request completion (ignored).
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_link_update(struct rte_eth_dev *dev, int wait_to_complete __rte_unused)
+{
+	/*
+	 * TODO
+	 * once MUSDK provides necessary API use it here
+	 */
+	struct ethtool_cmd edata;
+	struct ifreq req;
+	int ret, fd;
+
+	edata.cmd = ETHTOOL_GSET;
+
+	strcpy(req.ifr_name, dev->data->name);
+	req.ifr_data = (void *)&edata;
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd == -1)
+		return -EFAULT;
+
+	ret = ioctl(fd, SIOCETHTOOL, &req);
+	if (ret == -1) {
+		close(fd);
+		return -EFAULT;
+	}
+
+	close(fd);
+
+	switch (ethtool_cmd_speed(&edata)) {
+	case SPEED_10:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_10M;
+		break;
+	case SPEED_100:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_100M;
+		break;
+	case SPEED_1000:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_1G;
+		break;
+	case SPEED_10000:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_10G;
+		break;
+	default:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_NONE;
+	}
+
+	dev->data->dev_link.link_duplex = edata.duplex ? ETH_LINK_FULL_DUPLEX :
+							 ETH_LINK_HALF_DUPLEX;
+	dev->data->dev_link.link_autoneg = edata.autoneg ? ETH_LINK_AUTONEG :
+							   ETH_LINK_FIXED;
+
+	return 0;
+}
+
+/**
+ * DPDK callback to enable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_promiscuous_enable(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_set_uc_promisc(priv->ppio, 1);
+	if (ret)
+		RTE_LOG(ERR, PMD, "Failed to enable promiscuous mode\n");
+}
+
+/**
+ * DPDK callback to enable allmulti mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_allmulticast_enable(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_set_mc_promisc(priv->ppio, 1);
+	if (ret)
+		RTE_LOG(ERR, PMD, "Failed enable all-multicast mode\n");
+}
+
+/**
+ * DPDK callback to disable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_set_uc_promisc(priv->ppio, 0);
+	if (ret)
+		RTE_LOG(ERR, PMD, "Failed to disable promiscuous mode\n");
+}
+
+/**
+ * DPDK callback to disable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_allmulticast_disable(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_set_mc_promisc(priv->ppio, 0);
+	if (ret)
+		RTE_LOG(ERR, PMD, "Failed to disable all-multicast mode\n");
+}
+
+/**
+ * DPDK callback to remove a MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param index
+ *   MAC address index.
+ */
+static void
+mrvl_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	char buf[ETHER_ADDR_FMT_SIZE];
+	int ret;
+
+	ret = pp2_ppio_remove_mac_addr(priv->ppio,
+				       dev->data->mac_addrs[index].addr_bytes);
+	if (ret) {
+		ether_format_addr(buf, sizeof(buf),
+				  &dev->data->mac_addrs[index]);
+		RTE_LOG(ERR, PMD, "Failed to remove mac %s\n", buf);
+	}
+}
+
+/**
+ * DPDK callback to add a MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ * @param index
+ *   MAC address index.
+ * @param vmdq
+ *   VMDq pool index to associate address with (unused).
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
+		  uint32_t index, uint32_t vmdq __rte_unused)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	char buf[ETHER_ADDR_FMT_SIZE];
+	int ret;
+
+	if (index == 0)
+		/* For setting index 0, mrvl_mac_addr_set() should be used.*/
+		return -1;
+
+	/*
+	 * Maximum number of uc addresses can be tuned via kernel module mvpp2x
+	 * parameter uc_filter_max. Maximum number of mc addresses is then
+	 * MRVL_MAC_ADDRS_MAX - uc_filter_max. Currently it defaults to 4 and
+	 * 21 respectively.
+	 *
+	 * If more than uc_filter_max uc addresses were added to filter list
+	 * then NIC will switch to promiscuous mode automatically.
+	 *
+	 * If more than MRVL_MAC_ADDRS_MAX - uc_filter_max number mc addresses
+	 * were added to filter list then NIC will switch to all-multicast mode
+	 * automatically.
+	 */
+	ret = pp2_ppio_add_mac_addr(priv->ppio, mac_addr->addr_bytes);
+	if (ret) {
+		ether_format_addr(buf, sizeof(buf), mac_addr);
+		RTE_LOG(ERR, PMD, "Failed to add mac %s\n", buf);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * DPDK callback to set the primary MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ */
+static void
+mrvl_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	pp2_ppio_set_mac_addr(priv->ppio, mac_addr->addr_bytes);
+	/*
+	 * TODO
+	 * Port stops sending packets if pp2_ppio_set_mac_addr()
+	 * was called after pp2_ppio_enable(). As a quick fix issue
+	 * enable port once again.
+	 */
+	pp2_ppio_enable(priv->ppio);
+}
+
+/**
+ * DPDK callback to get device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param stats
+ *   Stats structure output buffer.
+ */
+static void
+mrvl_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct pp2_ppio_statistics ppio_stats;
+	uint64_t drop_mac = 0;
+	unsigned int i, idx, ret;
+
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		struct mrvl_rxq *rxq = dev->data->rx_queues[i];
+		struct pp2_ppio_inq_statistics rx_stats;
+
+		if (!rxq)
+			continue;
+
+		idx = rxq->queue_id;
+		if (unlikely(idx >= RTE_ETHDEV_QUEUE_STAT_CNTRS)) {
+			RTE_LOG(ERR, PMD,
+				"rx queue %d stats out of range (0 - %d)\n",
+				idx, RTE_ETHDEV_QUEUE_STAT_CNTRS - 1);
+			continue;
+		}
+
+		ret = pp2_ppio_inq_get_statistics(priv->ppio,
+			priv->rxq_map[idx].tc, priv->rxq_map[idx].inq,
+			&rx_stats, 0);
+		if (unlikely(ret)) {
+			RTE_LOG(ERR, PMD,
+				"Failed to update rx queue %d stats\n", idx);
+			break;
+		}
+
+		stats->q_ibytes[idx] = rxq->bytes_recv;
+		stats->q_ipackets[idx] = rx_stats.enq_desc - rxq->drop_mac;
+		stats->q_errors[idx] = rx_stats.drop_early +
+				       rx_stats.drop_fullq +
+				       rx_stats.drop_bm +
+				       rxq->drop_mac;
+		stats->ibytes += rxq->bytes_recv;
+		drop_mac += rxq->drop_mac;
+	}
+
+	for (i = 0; i < dev->data->nb_tx_queues; i++) {
+		struct mrvl_txq *txq = dev->data->tx_queues[i];
+		struct pp2_ppio_outq_statistics tx_stats;
+
+		if (!txq)
+			continue;
+
+		idx = txq->queue_id;
+		if (unlikely(idx >= RTE_ETHDEV_QUEUE_STAT_CNTRS)) {
+			RTE_LOG(ERR, PMD,
+				"tx queue %d stats out of range (0 - %d)\n",
+				idx, RTE_ETHDEV_QUEUE_STAT_CNTRS - 1);
+		}
+
+		ret = pp2_ppio_outq_get_statistics(priv->ppio, idx,
+						   &tx_stats, 0);
+		if (unlikely(ret)) {
+			RTE_LOG(ERR, PMD,
+				"Failed to update tx queue %d stats\n", idx);
+			break;
+		}
+
+		stats->q_opackets[idx] = tx_stats.deq_desc;
+		stats->q_obytes[idx] = txq->bytes_sent;
+		stats->obytes += txq->bytes_sent;
+	}
+
+	ret = pp2_ppio_get_statistics(priv->ppio, &ppio_stats, 0);
+	if (unlikely(ret)) {
+		RTE_LOG(ERR, PMD, "Failed to update port statistics\n");
+		return;
+	}
+
+	stats->ipackets += ppio_stats.rx_packets - drop_mac;
+	stats->opackets += ppio_stats.tx_packets;
+	stats->imissed += ppio_stats.rx_fullq_dropped +
+			  ppio_stats.rx_bm_dropped +
+			  ppio_stats.rx_early_dropped +
+			  ppio_stats.rx_fifo_dropped +
+			  ppio_stats.rx_cls_dropped;
+	stats->ierrors = drop_mac;
+}
+
+/**
+ * DPDK callback to clear device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_stats_reset(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int i;
+
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		struct mrvl_rxq *rxq = dev->data->rx_queues[i];
+
+		pp2_ppio_inq_get_statistics(priv->ppio,
+			priv->rxq_map[i].tc, priv->rxq_map[i].inq, NULL, 1);
+		rxq->bytes_recv = 0;
+		rxq->drop_mac = 0;
+	}
+
+	for (i = 0; i < dev->data->nb_tx_queues; i++) {
+		struct mrvl_txq *txq = dev->data->tx_queues[i];
+
+		pp2_ppio_outq_get_statistics(priv->ppio, i, NULL, 1);
+		txq->bytes_sent = 0;
+	}
+
+	pp2_ppio_get_statistics(priv->ppio, NULL, 1);
+}
+
+/**
+ * DPDK callback to get information about the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure (unused).
+ * @param info
+ *   Info structure output buffer.
+ */
+static void
+mrvl_dev_infos_get(struct rte_eth_dev *dev __rte_unused,
+		    struct rte_eth_dev_info *info)
+{
+	info->max_rx_queues = MRVL_PP2_RXQ_MAX;
+	info->max_tx_queues = MRVL_PP2_TXQ_MAX;
+	info->max_mac_addrs = MRVL_MAC_ADDRS_MAX;
+
+	info->rx_desc_lim.nb_max = MRVL_PP2_RXD_MAX;
+	info->rx_desc_lim.nb_min = MRVL_PP2_RXD_MIN;
+	info->rx_desc_lim.nb_align = MRVL_PP2_RXD_ALIGN;
+
+	info->tx_desc_lim.nb_max = MRVL_PP2_TXD_MAX;
+	info->tx_desc_lim.nb_min = MRVL_PP2_TXD_MIN;
+	info->tx_desc_lim.nb_align = MRVL_PP2_TXD_ALIGN;
+
+	info->rx_offload_capa = DEV_RX_OFFLOAD_IPV4_CKSUM |
+				DEV_RX_OFFLOAD_UDP_CKSUM |
+				DEV_RX_OFFLOAD_TCP_CKSUM;
+
+	info->tx_offload_capa = DEV_TX_OFFLOAD_IPV4_CKSUM |
+				DEV_TX_OFFLOAD_UDP_CKSUM |
+				DEV_TX_OFFLOAD_TCP_CKSUM;
+
+	info->flow_type_rss_offloads = ETH_RSS_IPV4 |
+				       ETH_RSS_NONFRAG_IPV4_TCP |
+				       ETH_RSS_NONFRAG_IPV4_UDP;
+
+	/* By default packets are dropped if no descriptors are available */
+	info->default_rxconf.rx_drop_en = 1;
+
+	info->max_rx_pktlen = MRVL_PKT_SIZE_MAX;
+}
+
+/**
+ * Return supported packet types.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure (unused).
+ *
+ * @return
+ *   Const pointer to the table with supported packet types.
+ */
+static const uint32_t *
+mrvl_dev_supported_ptypes_get(struct rte_eth_dev *dev __rte_unused)
+{
+	static const uint32_t ptypes[] = {
+		RTE_PTYPE_L2_ETHER,
+		RTE_PTYPE_L3_IPV4,
+		RTE_PTYPE_L3_IPV4_EXT,
+		RTE_PTYPE_L3_IPV4_EXT_UNKNOWN,
+		RTE_PTYPE_L3_IPV6,
+		RTE_PTYPE_L3_IPV6_EXT,
+		RTE_PTYPE_L2_ETHER_ARP,
+		RTE_PTYPE_L4_TCP,
+		RTE_PTYPE_L4_UDP
+	};
+
+	return ptypes;
+}
+
+/**
+ * DPDK callback to get information about specific receive queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param rx_queue_id
+ *   Receive queue index.
+ * @param qinfo
+ *   Receive queue information structure.
+ */
+static void mrvl_rxq_info_get(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+			      struct rte_eth_rxq_info *qinfo)
+{
+	struct mrvl_rxq *q = dev->data->rx_queues[rx_queue_id];
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int inq = priv->rxq_map[rx_queue_id].inq;
+	int tc = priv->rxq_map[rx_queue_id].tc;
+
+	qinfo->mp = q->mp;
+	qinfo->nb_desc = priv->ppio_params.inqs_params.
+			 tcs_params[tc].inqs_params[inq].size;
+}
+
+/**
+ * DPDK callback to get information about specific transmit queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param tx_queue_id
+ *   Transmit queue index.
+ * @param qinfo
+ *   Transmit queue information structure.
+ */
+static void mrvl_txq_info_get(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+			      struct rte_eth_txq_info *qinfo)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	qinfo->nb_desc =
+		priv->ppio_params.outqs_params.outqs_params[tx_queue_id].size;
+}
+
+/**
+ * DPDK callback to Configure a VLAN filter.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param vlan_id
+ *   VLAN ID to filter.
+ * @param on
+ *   Toggle filter.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	return on ? pp2_ppio_add_vlan(priv->ppio, vlan_id) :
+		    pp2_ppio_remove_vlan(priv->ppio, vlan_id);
+}
+
+/**
+ * Release buffers to hardware bpool (buffer-pool)
+ *
+ * @param rxq
+ *   Receive queue pointer.
+ * @param num
+ *   Number of buffers to release to bpool.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_fill_bpool(struct mrvl_rxq *rxq, int num)
+{
+	struct buff_release_entry entries[MRVL_PP2_TXD_MAX];
+	struct rte_mbuf *mbufs[MRVL_PP2_TXD_MAX];
+	int i, ret;
+	unsigned int core_id = rte_lcore_id();
+	struct pp2_hif *hif = hifs[core_id];
+	struct pp2_bpool *bpool = rxq->priv->bpool;
+
+	ret = rte_pktmbuf_alloc_bulk(rxq->mp, mbufs, num);
+	if (ret)
+		return ret;
+
+	if (cookie_addr_high == MRVL_COOKIE_ADDR_INVALID)
+		cookie_addr_high =
+			(uint64_t)mbufs[0] & MRVL_COOKIE_HIGH_ADDR_MASK;
+
+	for (i = 0; i < num; i++) {
+		if (((uint64_t)mbufs[i] & MRVL_COOKIE_HIGH_ADDR_MASK)
+			!= cookie_addr_high) {
+			RTE_LOG(ERR, PMD,
+				"mbuf virtual addr high 0x%lx out of range\n",
+				(uint64_t)mbufs[i] >> 32);
+			goto out;
+		}
+
+		entries[i].buff.addr =
+			rte_mbuf_data_dma_addr_default(mbufs[i]);
+		entries[i].buff.cookie = (pp2_cookie_t)(uint64_t)mbufs[i];
+		entries[i].bpool = bpool;
+	}
+
+	pp2_bpool_put_buffs(hif, entries, (uint16_t *)&i);
+	mrvl_port_bpool_size[bpool->pp2_id][bpool->id][core_id] += i;
+
+	if (i != num)
+		goto out;
+
+	return 0;
+out:
+	for (; i < num; i++)
+		rte_pktmbuf_free(mbufs[i]);
+
+	return -1;
+}
+
+/**
+ * DPDK callback to configure the receive queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param conf
+ *   Thresholds parameters (unused_).
+ * @param mp
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
+		    unsigned int socket,
+		    const struct rte_eth_rxconf *conf __rte_unused,
+		    struct rte_mempool *mp)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_rxq *rxq;
+	uint32_t min_size,
+		 max_rx_pkt_len = dev->data->dev_conf.rxmode.max_rx_pkt_len;
+	int ret;
+
+	if (priv->rxq_map[idx].tc == MRVL_UNKNOWN_TC) {
+		/*
+		 * Unknown TC mapping, mapping will not have a correct queue.
+		 */
+		RTE_LOG(ERR, PMD, "Unknown TC mapping for queue %hu eth%hhu\n",
+				idx, priv->ppio_id);
+		return -EFAULT;
+	}
+
+	min_size = rte_pktmbuf_data_room_size(mp) - RTE_PKTMBUF_HEADROOM -
+		   MRVL_PKT_EFFEC_OFFS;
+	if (min_size < max_rx_pkt_len) {
+		RTE_LOG(ERR, PMD, "Mbuf size must be increased to %u bytes"
+				  " to hold up to %u bytes of data.\n",
+			max_rx_pkt_len + RTE_PKTMBUF_HEADROOM +
+			MRVL_PKT_EFFEC_OFFS,
+			max_rx_pkt_len);
+		return -EINVAL;
+	}
+
+	if (dev->data->rx_queues[idx]) {
+		rte_free(dev->data->rx_queues[idx]);
+		dev->data->rx_queues[idx] = NULL;
+	}
+
+	rxq = rte_zmalloc_socket("rxq", sizeof(*rxq), 0, socket);
+	if (!rxq)
+		return -ENOMEM;
+
+	rxq->priv = priv;
+	rxq->mp = mp;
+	rxq->cksum_enabled = dev->data->dev_conf.rxmode.hw_ip_checksum;
+	rxq->queue_id = idx;
+	rxq->port_id = dev->data->port_id;
+	mrvl_port_to_bpool_lookup[rxq->port_id] = priv->bpool;
+
+	priv->ppio_params.inqs_params.
+		tcs_params[priv->rxq_map[rxq->queue_id].tc].
+		inqs_params[priv->rxq_map[rxq->queue_id].inq].size = desc;
+
+	ret = mrvl_fill_bpool(rxq, desc);
+	if (ret) {
+		rte_free(rxq);
+		return ret;
+	}
+
+	priv->bpool_init_size += desc;
+
+	dev->data->rx_queues[idx] = rxq;
+
+	return 0;
+}
+
+/**
+ * DPDK callback to release the receive queue.
+ *
+ * @param rxq
+ *   Generic receive queue pointer.
+ */
+static void
+mrvl_rx_queue_release(void *rxq)
+{
+	struct mrvl_rxq *q = rxq;
+	int i, num;
+
+	if (!q)
+		return;
+
+	num = q->priv->ppio_params.inqs_params.
+			tcs_params[q->priv->rxq_map[q->queue_id].tc].
+			inqs_params[q->priv->rxq_map[q->queue_id].inq].size;
+	for (i = 0; i < num; i++) {
+		struct pp2_buff_inf inf;
+		uint64_t addr;
+
+		pp2_bpool_get_buff(hifs[rte_lcore_id()], q->priv->bpool, &inf);
+		addr = cookie_addr_high | inf.cookie;
+		rte_pktmbuf_free((struct rte_mbuf *)addr);
+	}
+
+	rte_free(q);
+}
+
+/**
+ * DPDK callback to configure the transmit queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   Transmit queue index.
+ * @param desc
+ *   Number of descriptors to configure in the queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param conf
+ *   Thresholds parameters (unused).
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
+		    unsigned int socket,
+		    const struct rte_eth_txconf *conf __rte_unused)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_txq *txq;
+
+	if (dev->data->tx_queues[idx]) {
+		rte_free(dev->data->tx_queues[idx]);
+		dev->data->tx_queues[idx] = NULL;
+	}
+
+	txq = rte_zmalloc_socket("txq", sizeof(*txq), 0, socket);
+	if (!txq)
+		return -ENOMEM;
+
+	txq->priv = priv;
+	txq->queue_id = idx;
+	txq->port_id = dev->data->port_id;
+	dev->data->tx_queues[idx] = txq;
+
+	priv->ppio_params.outqs_params.outqs_params[idx].size = desc;
+	priv->ppio_params.outqs_params.outqs_params[idx].weight = 1;
+
+	return 0;
+}
+
+/**
+ * DPDK callback to release the transmit queue.
+ *
+ * @param txq
+ *   Generic transmit queue pointer.
+ */
+static void
+mrvl_tx_queue_release(void *txq)
+{
+	struct mrvl_txq *q = txq;
+
+	if (!q)
+		return;
+
+	rte_free(q);
+}
+
+/**
+ * Update RSS hash configuration
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param rss_conf
+ *   Pointer to RSS configuration.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_rss_hash_update(struct rte_eth_dev *dev,
+		     struct rte_eth_rss_conf *rss_conf)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	return mrvl_configure_rss(priv, rss_conf);
+}
+
+/**
+ * DPDK callback to get RSS hash configuration.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @rss_conf
+ *   Pointer to RSS configuration.
+ *
+ * @return
+ *   Always 0.
+ */
+static int
+mrvl_rss_hash_conf_get(struct rte_eth_dev *dev,
+		       struct rte_eth_rss_conf *rss_conf)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	enum pp2_ppio_hash_type hash_type =
+		priv->ppio_params.inqs_params.hash_type;
+
+	rss_conf->rss_key = NULL;
+
+	if (hash_type == PP2_PPIO_HASH_T_NONE)
+		rss_conf->rss_hf = 0;
+	else if (hash_type == PP2_PPIO_HASH_T_2_TUPLE)
+		rss_conf->rss_hf = ETH_RSS_IPV4;
+	else if (hash_type == PP2_PPIO_HASH_T_5_TUPLE && priv->rss_hf_tcp)
+		rss_conf->rss_hf = ETH_RSS_NONFRAG_IPV4_TCP;
+	else if (hash_type == PP2_PPIO_HASH_T_5_TUPLE && !priv->rss_hf_tcp)
+		rss_conf->rss_hf = ETH_RSS_NONFRAG_IPV4_UDP;
+
+	return 0;
+}
+
+static const struct eth_dev_ops mrvl_ops = {
+	.dev_configure = mrvl_dev_configure,
+	.dev_start = mrvl_dev_start,
+	.dev_stop = mrvl_dev_stop,
+	.dev_set_link_up = mrvl_dev_set_link_up,
+	.dev_set_link_down = mrvl_dev_set_link_down,
+	.dev_close = mrvl_dev_close,
+	.link_update = mrvl_link_update,
+	.promiscuous_enable = mrvl_promiscuous_enable,
+	.allmulticast_enable = mrvl_allmulticast_enable,
+	.promiscuous_disable = mrvl_promiscuous_disable,
+	.allmulticast_disable = mrvl_allmulticast_disable,
+	.mac_addr_remove = mrvl_mac_addr_remove,
+	.mac_addr_add = mrvl_mac_addr_add,
+	.mac_addr_set = mrvl_mac_addr_set,
+	.mtu_set = mrvl_mtu_set,
+	.stats_get = mrvl_stats_get,
+	.stats_reset = mrvl_stats_reset,
+	.dev_infos_get = mrvl_dev_infos_get,
+	.dev_supported_ptypes_get = mrvl_dev_supported_ptypes_get,
+	.rxq_info_get = mrvl_rxq_info_get,
+	.txq_info_get = mrvl_txq_info_get,
+	.vlan_filter_set = mrvl_vlan_filter_set,
+	.rx_queue_setup = mrvl_rx_queue_setup,
+	.rx_queue_release = mrvl_rx_queue_release,
+	.tx_queue_setup = mrvl_tx_queue_setup,
+	.tx_queue_release = mrvl_tx_queue_release,
+	.rss_hash_update = mrvl_rss_hash_update,
+	.rss_hash_conf_get = mrvl_rss_hash_conf_get,
+};
+
+/**
+ * Return packet type information and l3/l4 offsets.
+ *
+ * @param desc
+ *   Pointer to the received packet descriptor.
+ * @param l3_offset
+ *   l3 packet offset.
+ * @param l4_offset
+ *   l4 packet offset.
+ *
+ * @return
+ *   Packet type information.
+ */
+static inline uint32_t
+mrvl_desc_to_packet_type_and_offset(struct pp2_ppio_desc *desc,
+				    uint8_t *l3_offset, uint8_t *l4_offset)
+{
+	enum pp2_inq_l3_type l3_type;
+	enum pp2_inq_l4_type l4_type;
+	uint64_t packet_type;
+
+	pp2_ppio_inq_desc_get_l3_info(desc, &l3_type, l3_offset);
+	pp2_ppio_inq_desc_get_l4_info(desc, &l4_type, l4_offset);
+
+	packet_type = RTE_PTYPE_L2_ETHER;
+
+	switch (l3_type) {
+	case PP2_INQ_L3_TYPE_IPV4_NO_OPTS:
+		packet_type |= RTE_PTYPE_L3_IPV4;
+		break;
+	case PP2_INQ_L3_TYPE_IPV4_OK:
+		packet_type |= RTE_PTYPE_L3_IPV4_EXT;
+		break;
+	case PP2_INQ_L3_TYPE_IPV4_TTL_ZERO:
+		packet_type |= RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
+		break;
+	case PP2_INQ_L3_TYPE_IPV6_NO_EXT:
+		packet_type |= RTE_PTYPE_L3_IPV6;
+		break;
+	case PP2_INQ_L3_TYPE_IPV6_EXT:
+		packet_type |= RTE_PTYPE_L3_IPV6_EXT;
+		break;
+	case PP2_INQ_L3_TYPE_ARP:
+		packet_type |= RTE_PTYPE_L2_ETHER_ARP;
+		/*
+		 * In case of ARP l4_offset is set to wrong value.
+		 * Set it to proper one so that later on mbuf->l3_len can be
+		 * calculated subtracting l4_offset and l3_offset.
+		 */
+		*l4_offset = *l3_offset + MRVL_ARP_LENGTH;
+		break;
+	default:
+		RTE_LOG(DEBUG, PMD, "Failed to recognise l3 packet type\n");
+		break;
+	}
+
+	switch (l4_type) {
+	case PP2_INQ_L4_TYPE_TCP:
+		packet_type |= RTE_PTYPE_L4_TCP;
+		break;
+	case PP2_INQ_L4_TYPE_UDP:
+		packet_type |= RTE_PTYPE_L4_UDP;
+		break;
+	default:
+		RTE_LOG(DEBUG, PMD, "Failed to recognise l4 packet type\n");
+		break;
+	}
+
+	return packet_type;
+}
+
+/**
+ * Get offload information from the received packet descriptor.
+ *
+ * @param desc
+ *   Pointer to the received packet descriptor.
+ *
+ * @return
+ *   Mbuf offload flags.
+ */
+static inline uint64_t
+mrvl_desc_to_ol_flags(struct pp2_ppio_desc *desc)
+{
+	uint64_t flags;
+	enum pp2_inq_desc_status status;
+
+	status = pp2_ppio_inq_desc_get_l3_pkt_error(desc);
+	if (unlikely(status != PP2_DESC_ERR_OK))
+		flags = PKT_RX_IP_CKSUM_BAD;
+	else
+		flags = PKT_RX_IP_CKSUM_GOOD;
+
+	status = pp2_ppio_inq_desc_get_l4_pkt_error(desc);
+	if (unlikely(status != PP2_DESC_ERR_OK))
+		flags |= PKT_RX_L4_CKSUM_BAD;
+	else
+		flags |= PKT_RX_L4_CKSUM_GOOD;
+
+	return flags;
+}
+
+/**
+ * DPDK callback for receive.
+ *
+ * @param rxq
+ *   Generic pointer to the receive queue.
+ * @param rx_pkts
+ *   Array to store received packets.
+ * @param nb_pkts
+ *   Maximum number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully received.
+ */
+static uint16_t
+mrvl_rx_pkt_burst(void *rxq, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
+{
+	struct mrvl_rxq *q = rxq;
+	struct pp2_ppio_desc descs[nb_pkts];
+	struct pp2_bpool *bpool;
+	int i, ret, rx_done = 0;
+	int num;
+	unsigned int core_id = rte_lcore_id();
+
+	if (unlikely(!q->priv->ppio))
+		return 0;
+
+	bpool = q->priv->bpool;
+
+	ret = pp2_ppio_recv(q->priv->ppio,
+			q->priv->rxq_map[q->queue_id].tc,
+			q->priv->rxq_map[q->queue_id].inq,
+			descs,
+			&nb_pkts);
+	if (unlikely(ret < 0)) {
+		RTE_LOG(ERR, PMD, "Failed to receive packets\n");
+		return 0;
+	}
+	mrvl_port_bpool_size[bpool->pp2_id][bpool->id][core_id] -= nb_pkts;
+
+	for (i = 0; i < nb_pkts; i++) {
+		struct rte_mbuf *mbuf;
+		uint8_t l3_offset, l4_offset;
+		enum pp2_inq_desc_status status;
+		uint64_t addr;
+
+		if (likely((nb_pkts - i) > MRVL_MUSDK_PREFETCH_SHIFT)) {
+			struct pp2_ppio_desc *pref_desc;
+			u64 pref_addr;
+
+			pref_desc = &descs[i + MRVL_MUSDK_PREFETCH_SHIFT];
+			pref_addr = cookie_addr_high |
+				    pp2_ppio_inq_desc_get_cookie(pref_desc);
+			rte_mbuf_prefetch_part1((struct rte_mbuf *)(pref_addr));
+			rte_mbuf_prefetch_part2((struct rte_mbuf *)(pref_addr));
+		}
+
+		addr = cookie_addr_high |
+		       pp2_ppio_inq_desc_get_cookie(&descs[i]);
+		mbuf = (struct rte_mbuf *)addr;
+		rte_pktmbuf_reset(mbuf);
+
+		/* drop packet in case of mac, overrun or resource error */
+		status = pp2_ppio_inq_desc_get_l2_pkt_error(&descs[i]);
+		if (unlikely(status != PP2_DESC_ERR_OK)) {
+			struct pp2_buff_inf binf = {
+				.addr = rte_mbuf_data_dma_addr_default(mbuf),
+				.cookie = (pp2_cookie_t)(uint64_t)mbuf,
+			};
+
+			pp2_bpool_put_buff(hifs[core_id], bpool, &binf);
+			mrvl_port_bpool_size
+				[bpool->pp2_id][bpool->id][core_id]++;
+			q->drop_mac++;
+			continue;
+		}
+
+		mbuf->data_off += MRVL_PKT_EFFEC_OFFS;
+		mbuf->pkt_len = pp2_ppio_inq_desc_get_pkt_len(&descs[i]);
+		mbuf->data_len = mbuf->pkt_len;
+		mbuf->port = q->port_id;
+		mbuf->packet_type =
+			mrvl_desc_to_packet_type_and_offset(&descs[i],
+							    &l3_offset,
+							    &l4_offset);
+		mbuf->l2_len = l3_offset;
+		mbuf->l3_len = l4_offset - l3_offset;
+
+		if (likely(q->cksum_enabled))
+			mbuf->ol_flags = mrvl_desc_to_ol_flags(&descs[i]);
+
+		rx_pkts[rx_done++] = mbuf;
+		q->bytes_recv += mbuf->pkt_len;
+	}
+
+	if (rte_spinlock_trylock(&q->priv->lock) == 1) {
+		num = mrvl_get_bpool_size(bpool->pp2_id, bpool->id);
+
+		if (unlikely((num <= q->priv->bpool_min_size) ||
+			 (!rx_done && (num < q->priv->bpool_init_size)))) {
+			ret = mrvl_fill_bpool(q, MRVL_BURST_SIZE);
+			if (ret)
+				RTE_LOG(ERR, PMD, "Failed to fill bpool\n");
+		} else if (unlikely(num > q->priv->bpool_max_size)) {
+			int i;
+			int pkt_to_remove = num - q->priv->bpool_init_size;
+			struct rte_mbuf *mbuf;
+			struct pp2_buff_inf buff;
+
+			RTE_LOG(DEBUG, PMD, "\nport-%d:%d: bpool %d oversize -"
+				" remove %d buffers (pool size: %d -> %d)\n",
+				bpool->pp2_id, q->priv->ppio->port_id,
+				bpool->id, pkt_to_remove, num,
+				q->priv->bpool_init_size);
+
+			for (i = 0; i < pkt_to_remove; i++) {
+				pp2_bpool_get_buff(hifs[core_id], bpool, &buff);
+				mbuf = (struct rte_mbuf *)
+					(cookie_addr_high | buff.cookie);
+				rte_pktmbuf_free(mbuf);
+			}
+			mrvl_port_bpool_size
+				[bpool->pp2_id][bpool->id][core_id] -=
+								pkt_to_remove;
+		}
+		rte_spinlock_unlock(&q->priv->lock);
+	}
+
+	return rx_done;
+}
+
+/**
+ * Prepare offload information.
+ *
+ * @param ol_flags
+ *   Offload flags.
+ * @param packet_type
+ *   Packet type bitfield.
+ * @param l3_type
+ *   Pointer to the pp2_ouq_l3_type structure.
+ * @param l4_type
+ *   Pointer to the pp2_outq_l4_type structure.
+ * @param gen_l3_cksum
+ *   Will be set to 1 in case l3 checksum is computed.
+ * @param l4_cksum
+ *   Will be set to 1 in case l4 checksum is computed.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static inline int
+mrvl_prepare_proto_info(uint64_t ol_flags, uint32_t packet_type,
+			enum pp2_outq_l3_type *l3_type,
+			enum pp2_outq_l4_type *l4_type,
+			int *gen_l3_cksum,
+			int *gen_l4_cksum)
+{
+	/*
+	 * Based on ol_flags prepare information
+	 * for pp2_ppio_outq_desc_set_proto_info() which setups descriptor
+	 * for offloading.
+	 */
+	if (ol_flags & PKT_TX_IPV4) {
+		*l3_type = PP2_OUTQ_L3_TYPE_IPV4;
+		*gen_l3_cksum = ol_flags & PKT_TX_IP_CKSUM ? 1 : 0;
+	} else if (ol_flags & PKT_TX_IPV6) {
+		*l3_type = PP2_OUTQ_L3_TYPE_IPV6;
+		/* no checksum for ipv6 header */
+		*gen_l3_cksum = 0;
+	} else {
+		/* if something different then stop processing */
+		return -1;
+	}
+
+	ol_flags &= PKT_TX_L4_MASK;
+	if ((packet_type & RTE_PTYPE_L4_TCP) &&
+	    (ol_flags == PKT_TX_TCP_CKSUM)) {
+		*l4_type = PP2_OUTQ_L4_TYPE_TCP;
+		*gen_l4_cksum = 1;
+	} else if ((packet_type & RTE_PTYPE_L4_UDP) &&
+		   (ol_flags == PKT_TX_UDP_CKSUM)) {
+		*l4_type = PP2_OUTQ_L4_TYPE_UDP;
+		*gen_l4_cksum = 1;
+	} else {
+		*l4_type = PP2_OUTQ_L4_TYPE_OTHER;
+		/* no checksum for other type */
+		*gen_l4_cksum = 0;
+	}
+
+	return 0;
+}
+
+/**
+ * Release already sent buffers to bpool (buffer-pool).
+ *
+ * @param ppio
+ *   Pointer to the port structure.
+ * @param hif
+ *   Pointer to the MUSDK hardware interface.
+ * @param sq
+ *   Pointer to the shadow queue.
+ * @param qid
+ *   Queue id number.
+ * @param force
+ *   Force releasing packets.
+ */
+static inline void
+mrvl_free_sent_buffers(struct pp2_ppio *ppio, struct pp2_hif *hif,
+			struct mrvl_shadow_txq *sq, int qid, int force)
+{
+	struct buff_release_entry *entry;
+	uint16_t nb_done = 0, num = 0, skip_bufs = 0;
+	int i, core_id = rte_lcore_id();
+
+	pp2_ppio_get_num_outq_done(ppio, hif, qid, &nb_done);
+
+	sq->num_to_release += nb_done;
+
+	if (likely(!force &&
+		   (sq->num_to_release < MRVL_PP2_BUF_RELEASE_BURST_SIZE)))
+		return;
+
+	nb_done = sq->num_to_release;
+	sq->num_to_release = 0;
+
+	for (i = 0; i < nb_done; i++) {
+		entry = &sq->ent[sq->tail + num];
+		if (unlikely(!entry->buff.addr)) {
+			RTE_LOG(ERR, PMD,
+				"Shadow memory @%d: cookie(%lx), pa(%lx)!\n",
+				sq->tail, (u64)entry->buff.cookie,
+				(u64)entry->buff.addr);
+			skip_bufs = 1;
+			goto skip;
+		}
+
+		if (unlikely(!entry->bpool)) {
+			struct rte_mbuf *mbuf;
+
+			mbuf = (struct rte_mbuf *)
+			       (cookie_addr_high | entry->buff.cookie);
+			rte_pktmbuf_free(mbuf);
+			skip_bufs = 1;
+			goto skip;
+		}
+
+		mrvl_port_bpool_size
+			[entry->bpool->pp2_id][entry->bpool->id][core_id]++;
+		num++;
+		if (unlikely(sq->tail + num == MRVL_PP2_TX_SHADOWQ_SIZE))
+			goto skip;
+		continue;
+skip:
+		if (likely(num))
+			pp2_bpool_put_buffs(hif, &sq->ent[sq->tail], &num);
+		num += skip_bufs;
+		sq->tail = (sq->tail + num) & MRVL_PP2_TX_SHADOWQ_MASK;
+		sq->size -= num;
+		num = 0;
+	}
+
+	if (likely(num)) {
+		pp2_bpool_put_buffs(hif, &sq->ent[sq->tail], &num);
+		sq->tail = (sq->tail + num) & MRVL_PP2_TX_SHADOWQ_MASK;
+		sq->size -= num;
+	}
+}
+
+/**
+ * DPDK callback for transmit.
+ *
+ * @param txq
+ *   Generic pointer transmit queue.
+ * @param tx_pkts
+ *   Packets to transmit.
+ * @param nb_pkts
+ *   Number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully transmitted.
+ */
+static uint16_t
+mrvl_tx_pkt_burst(void *txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+	struct mrvl_txq *q = txq;
+	struct mrvl_shadow_txq *sq = &shadow_txqs[q->port_id][rte_lcore_id()];
+	struct pp2_hif *hif = hifs[rte_lcore_id()];
+	struct pp2_ppio_desc descs[nb_pkts];
+	int i, ret, bytes_sent = 0;
+	uint16_t num, sq_free_size;
+	uint64_t addr;
+
+	if (unlikely(!q->priv->ppio))
+		return 0;
+
+	if (sq->size)
+		mrvl_free_sent_buffers(q->priv->ppio, hif, sq, q->queue_id, 0);
+
+	sq_free_size = MRVL_PP2_TX_SHADOWQ_SIZE - sq->size - 1;
+	if (unlikely(nb_pkts > sq_free_size)) {
+		RTE_LOG(DEBUG, PMD,
+			"No room in shadow queue for %d packets!!!"
+			"%d packets will be sent.\n",
+			nb_pkts, sq_free_size);
+		nb_pkts = sq_free_size;
+	}
+
+	for (i = 0; i < nb_pkts; i++) {
+		struct rte_mbuf *mbuf = tx_pkts[i];
+		int gen_l3_cksum, gen_l4_cksum;
+		enum pp2_outq_l3_type l3_type;
+		enum pp2_outq_l4_type l4_type;
+
+		if (likely((nb_pkts - i) > MRVL_MUSDK_PREFETCH_SHIFT)) {
+			struct rte_mbuf *pref_pkt_hdr;
+
+			pref_pkt_hdr = tx_pkts[i + MRVL_MUSDK_PREFETCH_SHIFT];
+			rte_mbuf_prefetch_part1(pref_pkt_hdr);
+			rte_mbuf_prefetch_part2(pref_pkt_hdr);
+		}
+
+		sq->ent[sq->head].buff.cookie = (pp2_cookie_t)(uint64_t)mbuf;
+		sq->ent[sq->head].buff.addr =
+			rte_mbuf_data_dma_addr_default(mbuf);
+		sq->ent[sq->head].bpool =
+			(unlikely(mbuf->port == 0xff || mbuf->refcnt > 1)) ?
+			 NULL : mrvl_port_to_bpool_lookup[mbuf->port];
+		sq->head = (sq->head + 1) & MRVL_PP2_TX_SHADOWQ_MASK;
+		sq->size++;
+
+		pp2_ppio_outq_desc_reset(&descs[i]);
+		pp2_ppio_outq_desc_set_phys_addr(&descs[i],
+						 rte_pktmbuf_mtophys(mbuf));
+		pp2_ppio_outq_desc_set_pkt_offset(&descs[i], 0);
+		pp2_ppio_outq_desc_set_pkt_len(&descs[i],
+					       rte_pktmbuf_pkt_len(mbuf));
+
+		bytes_sent += rte_pktmbuf_pkt_len(mbuf);
+		/*
+		 * in case unsupported ol_flags were passed
+		 * do not update descriptor offload information
+		 */
+		ret = mrvl_prepare_proto_info(mbuf->ol_flags, mbuf->packet_type,
+					      &l3_type, &l4_type, &gen_l3_cksum,
+					      &gen_l4_cksum);
+		if (unlikely(ret))
+			continue;
+
+		pp2_ppio_outq_desc_set_proto_info(&descs[i], l3_type, l4_type,
+						  mbuf->l2_len,
+						  mbuf->l2_len + mbuf->l3_len,
+						  gen_l3_cksum, gen_l4_cksum);
+	}
+
+	num = nb_pkts;
+	pp2_ppio_send(q->priv->ppio, hif, q->queue_id,
+			    descs, &nb_pkts);
+	/* number of packets that were not sent */
+	if (unlikely(num > nb_pkts)) {
+		for (i = nb_pkts; i < num; i++) {
+			sq->head = (MRVL_PP2_TX_SHADOWQ_SIZE + sq->head - 1) &
+				MRVL_PP2_TX_SHADOWQ_MASK;
+			addr = cookie_addr_high |
+			       sq->ent[sq->head].buff.cookie;
+			bytes_sent -=
+				rte_pktmbuf_pkt_len((struct rte_mbuf *)addr);
+		}
+		sq->size -= num - nb_pkts;
+	}
+
+	q->bytes_sent += bytes_sent;
+
+	return nb_pkts;
+}
+
+/**
+ * Initialize packet processor.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_init_pp2(void)
+{
+	struct pp2_init_params init_params;
+
+	memset(&init_params, 0, sizeof(init_params));
+	init_params.hif_reserved_map = MRVL_MUSDK_HIFS_RESERVED;
+	init_params.bm_pool_reserved_map = MRVL_MUSDK_BPOOLS_RESERVED;
+	init_params.rss_tbl_reserved_map = MRVL_MUSDK_RSS_RESERVED;
+
+	return pp2_init(&init_params);
+}
+
+/**
+ * Deinitialize packet processor.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static void
+mrvl_deinit_pp2(void)
+{
+	pp2_deinit();
+}
+
+/**
+ * Create private device structure.
+ *
+ * @param dev_name
+ *   Pointer to the port name passed in the initialization parameters.
+ *
+ * @return
+ *   Pointer to the newly allocated private device structure.
+ */
+static struct mrvl_priv *
+mrvl_priv_create(const char *dev_name)
+{
+	struct pp2_bpool_params bpool_params;
+	char match[MRVL_MATCH_LEN];
+	struct mrvl_priv *priv;
+	int ret, bpool_bit;
+
+	priv = rte_zmalloc_socket(dev_name, sizeof(*priv), 0, rte_socket_id());
+	if (!priv)
+		return NULL;
+
+	ret = pp2_netdev_get_ppio_info((char *)(uintptr_t)dev_name,
+				       &priv->pp_id, &priv->ppio_id);
+	if (ret)
+		goto out_free_priv;
+
+	bpool_bit = mrvl_reserve_bit(&used_bpools[priv->pp_id],
+			PP2_BPOOL_NUM_POOLS);
+	if (bpool_bit < 0)
+		goto out_free_priv;
+	priv->bpool_bit = bpool_bit;
+
+	snprintf(match, sizeof(match), "pool-%d:%d", priv->pp_id,
+		 priv->bpool_bit);
+	memset(&bpool_params, 0, sizeof(bpool_params));
+	bpool_params.match = match;
+	bpool_params.buff_len = MRVL_PKT_SIZE_MAX + MRVL_PKT_EFFEC_OFFS;
+	ret = pp2_bpool_init(&bpool_params, &priv->bpool);
+	if (ret)
+		goto out_clear_bpool_bit;
+
+	priv->ppio_params.type = PP2_PPIO_T_NIC;
+	rte_spinlock_init(&priv->lock);
+
+	return priv;
+out_clear_bpool_bit:
+	used_bpools[priv->pp_id] &= ~(1 << priv->bpool_bit);
+out_free_priv:
+	rte_free(priv);
+	return NULL;
+}
+
+/**
+ * Create device representing Ethernet port.
+ *
+ * @param name
+ *   Pointer to the port's name.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_eth_dev_create(struct rte_vdev_device *vdev, const char *name)
+{
+	int ret, fd = socket(AF_INET, SOCK_DGRAM, 0);
+	struct rte_eth_dev *eth_dev;
+	struct mrvl_priv *priv;
+	struct ifreq req;
+
+	eth_dev = rte_eth_dev_allocate(name);
+	if (!eth_dev)
+		return -ENOMEM;
+
+	priv = mrvl_priv_create(name);
+	if (!priv) {
+		ret = -ENOMEM;
+		goto out_free_dev;
+	}
+
+	eth_dev->data->mac_addrs = rte_zmalloc("mac_addrs",
+			ETHER_ADDR_LEN * MRVL_MAC_ADDRS_MAX, 0);
+	if (!eth_dev->data->mac_addrs) {
+		RTE_LOG(ERR, PMD, "Failed to allocate space for eth addrs\n");
+		ret = -ENOMEM;
+		goto out_free_priv;
+	}
+
+	memset(&req, 0, sizeof(req));
+	strcpy(req.ifr_name, name);
+	ret = ioctl(fd, SIOCGIFHWADDR, &req);
+	if (ret)
+		goto out_free_mac;
+
+	memcpy(eth_dev->data->mac_addrs[0].addr_bytes,
+	       req.ifr_addr.sa_data, ETHER_ADDR_LEN);
+
+
+	eth_dev->rx_pkt_burst = mrvl_rx_pkt_burst;
+	eth_dev->tx_pkt_burst = mrvl_tx_pkt_burst;
+	eth_dev->data->dev_private = priv;
+	eth_dev->device = &vdev->device;
+	eth_dev->dev_ops = &mrvl_ops;
+
+	return 0;
+out_free_mac:
+	rte_free(eth_dev->data->mac_addrs);
+out_free_dev:
+	rte_eth_dev_release_port(eth_dev);
+out_free_priv:
+	rte_free(priv);
+
+	return ret;
+}
+
+/**
+ * Cleanup previously created device representing Ethernet port.
+ *
+ * @param name
+ *   Pointer to the port name.
+ */
+static void
+mrvl_eth_dev_destroy(const char *name)
+{
+	struct rte_eth_dev *eth_dev;
+	struct mrvl_priv *priv;
+
+	eth_dev = rte_eth_dev_allocated(name);
+	if (!eth_dev)
+		return;
+
+	priv = eth_dev->data->dev_private;
+	pp2_bpool_deinit(priv->bpool);
+	rte_free(priv);
+	rte_free(eth_dev->data->mac_addrs);
+	rte_eth_dev_release_port(eth_dev);
+}
+
+/**
+ * Callback used by rte_kvargs_process() during argument parsing.
+ *
+ * @param key
+ *   Pointer to the parsed key (unused).
+ * @param value
+ *   Pointer to the parsed value.
+ * @param extra_args
+ *   Pointer to the extra arguments which contains address of the
+ *   table of pointers to parsed interface names.
+ *
+ * @return
+ *   Always 0.
+ */
+static int
+mrvl_get_ifnames(const char *key __rte_unused, const char *value,
+		 void *extra_args)
+{
+	const char **ifnames = extra_args;
+
+	ifnames[mrvl_ports_nb++] = value;
+
+	return 0;
+}
+
+/**
+ * Initialize per-lcore MUSDK hardware interfaces (hifs).
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_init_hifs(void)
+{
+	struct pp2_hif_params params;
+	char match[MRVL_MATCH_LEN];
+	int i, ret;
+
+	RTE_LCORE_FOREACH(i) {
+		ret = mrvl_reserve_bit(&used_hifs, MRVL_MUSDK_HIFS_MAX);
+		if (ret < 0)
+			return ret;
+
+		snprintf(match, sizeof(match), "hif-%d", ret);
+		memset(&params, 0, sizeof(params));
+		params.match = match;
+		params.out_size = MRVL_PP2_AGGR_TXQD_MAX;
+		ret = pp2_hif_init(&params, &hifs[i]);
+		if (ret) {
+			RTE_LOG(ERR, PMD, "Failed to initialize hif %d\n", i);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Deinitialize per-lcore MUSDK hardware interfaces (hifs).
+ */
+static void
+mrvl_deinit_hifs(void)
+{
+	int i;
+
+	RTE_LCORE_FOREACH(i) {
+		if (hifs[i])
+			pp2_hif_deinit(hifs[i]);
+	}
+}
+
+static void mrvl_set_first_last_cores(int core_id)
+{
+	if (core_id < mrvl_lcore_first)
+		mrvl_lcore_first = core_id;
+
+	if (core_id > mrvl_lcore_last)
+		mrvl_lcore_last = core_id;
+}
+
+/**
+ * DPDK callback to register the virtual device.
+ *
+ * @param vdev
+ *   Pointer to the virtual device.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+rte_pmd_mrvl_probe(struct rte_vdev_device *vdev)
+{
+	struct rte_kvargs *kvlist;
+	const char *ifnames[PP2_NUM_ETH_PPIO * PP2_NUM_PKT_PROC];
+	int ret = -EINVAL;
+	uint32_t i, ifnum, cfgnum, core_id;
+	const char *params;
+
+	params = rte_vdev_device_args(vdev);
+	if (!params)
+		return -EINVAL;
+
+	kvlist = rte_kvargs_parse(params, valid_args);
+	if (!kvlist)
+		return -EINVAL;
+
+	ifnum = rte_kvargs_count(kvlist, MRVL_IFACE_NAME_ARG);
+	if (ifnum > RTE_DIM(ifnames))
+		goto out_free_kvlist;
+
+	rte_kvargs_process(kvlist, MRVL_IFACE_NAME_ARG,
+			   mrvl_get_ifnames, &ifnames);
+
+	cfgnum = rte_kvargs_count(kvlist, MRVL_CFG_ARG);
+	if (cfgnum > 1) {
+		RTE_LOG(ERR, PMD, "Cannot handle more than one config file!\n");
+		goto out_free_kvlist;
+	} else if (cfgnum == 1) {
+		rte_kvargs_process(kvlist, MRVL_CFG_ARG,
+				   mrvl_get_qoscfg, &mrvl_qos_cfg);
+	}
+
+	/*
+	 * ret == -EEXIST is correct, it means DMA
+	 * has been already initialized (by another PMD).
+	 */
+	ret = mv_sys_dma_mem_init(RTE_MRVL_MUSDK_DMA_MEMSIZE);
+	if ((ret < 0) && (ret != -EEXIST))
+		goto out_free_kvlist;
+
+	ret = mrvl_init_pp2();
+	if (ret) {
+		RTE_LOG(ERR, PMD, "Failed to init PP!\n");
+		goto out_deinit_dma;
+	}
+
+	ret = mrvl_init_hifs();
+	if (ret)
+		goto out_deinit_hifs;
+
+	for (i = 0; i < ifnum; i++) {
+		RTE_LOG(INFO, PMD, "Creating %s\n", ifnames[i]);
+		ret = mrvl_eth_dev_create(vdev, ifnames[i]);
+		if (ret)
+			goto out_cleanup;
+	}
+
+	rte_kvargs_free(kvlist);
+
+	memset(mrvl_port_bpool_size, 0, sizeof(mrvl_port_bpool_size));
+
+	mrvl_lcore_first = RTE_MAX_LCORE;
+	mrvl_lcore_last = 0;
+
+	RTE_LCORE_FOREACH(core_id) {
+		mrvl_set_first_last_cores(core_id);
+	}
+
+	return 0;
+out_cleanup:
+	for (; i > 0; i--)
+		mrvl_eth_dev_destroy(ifnames[i]);
+out_deinit_hifs:
+	mrvl_deinit_hifs();
+	mrvl_deinit_pp2();
+out_deinit_dma:
+	mv_sys_dma_mem_destroy();
+out_free_kvlist:
+	rte_kvargs_free(kvlist);
+
+	return ret;
+}
+
+/**
+ * DPDK callback to remove virtual device.
+ *
+ * @param vdev
+ *   Pointer to the removed virtual device.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+rte_pmd_mrvl_remove(struct rte_vdev_device *vdev)
+{
+	int i;
+	const char *name;
+
+	name = rte_vdev_device_name(vdev);
+	if (!name)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Removing %s\n", name);
+
+	for (i = 0; i < rte_eth_dev_count(); i++) {
+		char ifname[RTE_ETH_NAME_MAX_LEN];
+
+		rte_eth_dev_get_name_by_port(i, ifname);
+		mrvl_eth_dev_destroy(ifname);
+	}
+
+	mrvl_deinit_hifs();
+	mrvl_deinit_pp2();
+	mv_sys_dma_mem_destroy();
+
+	return 0;
+}
+
+static struct rte_vdev_driver pmd_mrvl_drv = {
+	.probe = rte_pmd_mrvl_probe,
+	.remove = rte_pmd_mrvl_remove,
+};
+
+RTE_PMD_REGISTER_VDEV(net_mrvl, pmd_mrvl_drv);
+RTE_PMD_REGISTER_ALIAS(net_mrvl, eth_mrvl);
diff --git a/drivers/net/mrvl/mrvl_ethdev.h b/drivers/net/mrvl/mrvl_ethdev.h
new file mode 100644
index 0000000..9fc9624
--- /dev/null
+++ b/drivers/net/mrvl/mrvl_ethdev.h
@@ -0,0 +1,115 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Semihalf. 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 Semihalf 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 _MRVL_ETHDEV_H_
+#define _MRVL_ETHDEV_H_
+
+#include <rte_spinlock.h>
+#include <drivers/mv_pp2_cls.h>
+#include <drivers/mv_pp2_ppio.h>
+
+
+/** Maximum number of rx queues per port */
+#define MRVL_PP2_RXQ_MAX 32
+
+/** Maximum number of tx queues per port */
+#define MRVL_PP2_TXQ_MAX 8
+
+/** Minimum number of descriptors in tx queue */
+#define MRVL_PP2_TXD_MIN 16
+
+/** Maximum number of descriptors in tx queue */
+#define MRVL_PP2_TXD_MAX 2048
+
+/** Tx queue descriptors alignment */
+#define MRVL_PP2_TXD_ALIGN 16
+
+/** Minimum number of descriptors in rx queue */
+#define MRVL_PP2_RXD_MIN 16
+
+/** Maximum number of descriptors in rx queue */
+#define MRVL_PP2_RXD_MAX 2048
+
+/** Rx queue descriptors alignment */
+#define MRVL_PP2_RXD_ALIGN 16
+
+/** Maximum number of descriptors in tx aggregated queue */
+#define MRVL_PP2_AGGR_TXQD_MAX 2048
+
+/** Maximum number of Traffic Classes. */
+#define MRVL_PP2_TC_MAX 8
+
+/** Packet offset inside RX buffer. */
+#define MRVL_PKT_OFFS 64
+
+/** Maximum number of descriptors in shadow queue. Must be power of 2 */
+#define MRVL_PP2_TX_SHADOWQ_SIZE MRVL_PP2_TXD_MAX
+
+/** Shadow queue size mask (since shadow queue size is power of 2) */
+#define MRVL_PP2_TX_SHADOWQ_MASK (MRVL_PP2_TX_SHADOWQ_SIZE - 1)
+
+/** Minimum number of sent buffers to release from shadow queue to BM */
+#define MRVL_PP2_BUF_RELEASE_BURST_SIZE	64
+
+struct mrvl_priv {
+	/* Hot fields, used in fast path. */
+	struct pp2_bpool *bpool;  /**< BPool pointer */
+	struct pp2_ppio	*ppio;    /**< Port handler pointer */
+	rte_spinlock_t lock;	  /**< Spinlock for checking bpool status */
+	uint16_t bpool_max_size;  /**< BPool maximum size */
+	uint16_t bpool_min_size;  /**< BPool minimum size  */
+	uint16_t bpool_init_size; /**< Configured BPool size  */
+
+	/** Mapping for DPDK rx queue->(TC, MRVL relative inq) */
+	struct {
+		uint8_t tc;  /**< Traffic Class */
+		uint8_t inq; /**< Relative in-queue number */
+	} rxq_map[MRVL_PP2_RXQ_MAX] __rte_cache_aligned;
+
+	/* Configuration data, used sporadically. */
+	uint8_t pp_id;
+	uint8_t ppio_id;
+	uint8_t bpool_bit;
+	uint8_t rss_hf_tcp;
+	uint8_t uc_mc_flushed;
+	uint8_t vlan_flushed;
+
+	struct pp2_ppio_params ppio_params;
+	struct pp2_cls_qos_tbl_params qos_tbl_params;
+	struct pp2_cls_tbl *qos_tbl;
+	uint16_t nb_rx_queues;
+};
+
+/** Number of ports configured. */
+extern int mrvl_ports_nb;
+
+#endif /* _MRVL_ETHDEV_H_ */
diff --git a/drivers/net/mrvl/mrvl_qos.c b/drivers/net/mrvl/mrvl_qos.c
new file mode 100644
index 0000000..049ef97
--- /dev/null
+++ b/drivers/net/mrvl/mrvl_qos.c
@@ -0,0 +1,627 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Semihalf. 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 Semihalf 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 <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_cfgfile.h>
+#include <rte_log.h>
+#include <rte_lcore.h>
+#include <rte_malloc.h>
+#include <rte_string_fns.h>
+
+/* Unluckily, container_of is defined by both DPDK and MUSDK,
+ * we'll declare only one version.
+ *
+ * Note that it is not used in this PMD anyway.
+ */
+#ifdef container_of
+#undef container_of
+#endif
+
+#include "mrvl_qos.h"
+
+/* Parsing tokens. Defined conveniently, so that any correction is easy. */
+#define MRVL_TOK_DEFAULT "default"
+#define MRVL_TOK_DEFAULT_TC "default_tc"
+#define MRVL_TOK_DSCP "dscp"
+#define MRVL_TOK_MAPPING_PRIORITY "mapping_priority"
+#define MRVL_TOK_IP "ip"
+#define MRVL_TOK_IP_VLAN "ip/vlan"
+#define MRVL_TOK_PCP "pcp"
+#define MRVL_TOK_PORT "port"
+#define MRVL_TOK_RXQ "rxq"
+#define MRVL_TOK_SP "SP"
+#define MRVL_TOK_TC "tc"
+#define MRVL_TOK_TXQ "txq"
+#define MRVL_TOK_VLAN "vlan"
+#define MRVL_TOK_VLAN_IP "vlan/ip"
+#define MRVL_TOK_WEIGHT "weight"
+
+/** Number of tokens in range a-b = 2. */
+#define MAX_RNG_TOKENS 2
+
+/** Maximum possible value of PCP. */
+#define MAX_PCP 7
+
+/** Maximum possible value of DSCP. */
+#define MAX_DSCP 63
+
+/** Global QoS configuration. */
+struct mrvl_qos_cfg *mrvl_qos_cfg;
+
+/**
+ * Convert string to uint32_t with extra checks for result correctness.
+ *
+ * @param string String to convert.
+ * @param val Conversion result.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+get_val_securely(const char *string, uint32_t *val)
+{
+	char *endptr;
+	size_t len = strlen(string);
+
+	if (len == 0)
+		return -1;
+
+	*val = strtoul(string, &endptr, 0);
+	if ((errno != 0) || (RTE_PTR_DIFF(endptr, string) != len))
+		return -2;
+
+	return 0;
+}
+
+/**
+ * Read out-queue configuration from file.
+ *
+ * @param file Path to the configuration file.
+ * @param port Port number.
+ * @param outq Out queue number.
+ * @param cfg Pointer to the Marvell QoS configuration structure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+get_outq_cfg(struct rte_cfgfile *file, int port, int outq,
+		struct mrvl_qos_cfg *cfg)
+{
+	char sec_name[32];
+	const char *entry;
+	uint32_t val;
+
+	snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
+		MRVL_TOK_PORT, port, MRVL_TOK_TXQ, outq);
+
+	/* Skip non-existing */
+	if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
+		return 0;
+
+	entry = rte_cfgfile_get_entry(file, sec_name,
+			MRVL_TOK_WEIGHT);
+	if (entry) {
+		if (get_val_securely(entry, &val) < 0)
+			return -1;
+		cfg->port[port].outq[outq].weight = (uint8_t)val;
+	}
+
+	return 0;
+}
+
+/**
+ * Gets multiple-entry values and places them in table.
+ *
+ * Entry can be anything, e.g. "1 2-3 5 6 7-9". This needs to be converted to
+ * table entries, respectively: {1, 2, 3, 5, 6, 7, 8, 9}.
+ * As all result table's elements are always 1-byte long, we
+ * won't overcomplicate the function, but we'll keep API generic,
+ * check if someone hasn't changed element size and make it simple
+ * to extend to other sizes.
+ *
+ * This function is purely utilitary, it does not print any error, only returns
+ * different error numbers.
+ *
+ * @param entry[in] Values string to parse.
+ * @param tab[out] Results table.
+ * @param elem_sz[in] Element size (in bytes).
+ * @param max_elems[in] Number of results table elements available.
+ * @param max val[in] Maximum value allowed.
+ * @returns Number of correctly parsed elements in case of success.
+ * @retval -1 Wrong element size.
+ * @retval -2 More tokens than result table allows.
+ * @retval -3 Wrong range syntax.
+ * @retval -4 Wrong range values.
+ * @retval -5 Maximum value exceeded.
+ */
+static int
+get_entry_values(const char *entry, uint8_t *tab,
+	size_t elem_sz, uint8_t max_elems, uint8_t max_val)
+{
+	/* There should not be more tokens than max elements.
+	 * Add 1 for error trap.
+	 */
+	char *tokens[max_elems + 1];
+
+	/* Begin, End + error trap = 3. */
+	char *rng_tokens[MAX_RNG_TOKENS + 1];
+	long beg, end;
+	uint32_t token_val;
+	int nb_tokens, nb_rng_tokens;
+	int i;
+	int values = 0;
+	char val;
+	char entry_cpy[CFG_VALUE_LEN];
+
+	if (elem_sz != 1)
+		return -1;
+
+	/* Copy the entry to safely use rte_strsplit(). */
+	snprintf(entry_cpy, RTE_DIM(entry_cpy), "%s", entry);
+
+	/*
+	 * If there are more tokens than array size, rte_strsplit will
+	 * not return error, just array size.
+	 */
+	nb_tokens = rte_strsplit(entry_cpy, strlen(entry_cpy),
+		tokens, max_elems + 1, ' ');
+
+	/* Quick check, will be refined later. */
+	if (nb_tokens > max_elems)
+		return -2;
+
+	for (i = 0; i < nb_tokens; ++i) {
+		if (strchr(tokens[i], '-') != NULL) {
+			/*
+			 * Split to begin and end tokens.
+			 * We want to catch error cases too, thus we leave
+			 * option for number of tokens to be more than 2.
+			 */
+			nb_rng_tokens = rte_strsplit(tokens[i],
+					strlen(tokens[i]), rng_tokens,
+					RTE_DIM(rng_tokens), '-');
+			if (nb_rng_tokens != 2)
+				return -3;
+
+			/* Range and sanity checks. */
+			if (get_val_securely(rng_tokens[0], &token_val) < 0)
+				return -4;
+			beg = (char)token_val;
+			if (get_val_securely(rng_tokens[1], &token_val) < 0)
+				return -4;
+			end = (char)token_val;
+			if ((beg < 0) || (beg > UCHAR_MAX) ||
+				(end < 0) || (end > UCHAR_MAX) || (end < beg))
+				return -4;
+
+			for (val = beg; val <= end; ++val) {
+				if (val > max_val)
+					return -5;
+
+				*tab = val;
+				tab = RTE_PTR_ADD(tab, elem_sz);
+				++values;
+				if (values >= max_elems)
+					return -2;
+			}
+		} else {
+			/* Single values. */
+			if (get_val_securely(tokens[i], &token_val) < 0)
+				return -5;
+			val = (char)token_val;
+			if (val > max_val)
+				return -5;
+
+			*tab = val;
+			tab = RTE_PTR_ADD(tab, elem_sz);
+			++values;
+			if (values >= max_elems)
+				return -2;
+		}
+	}
+
+	return values;
+}
+
+/**
+ * Parse Traffic Class'es mapping configuration.
+ *
+ * @param file Config file handle.
+ * @param port Which port to look for.
+ * @param tc Which Traffic Class to look for.
+ * @param cfg[out] Parsing results.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
+		struct mrvl_qos_cfg *cfg)
+{
+	char sec_name[32];
+	const char *entry;
+	int n;
+
+	snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
+		MRVL_TOK_PORT, port, MRVL_TOK_TC, tc);
+
+	/* Skip non-existing */
+	if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
+		return 0;
+
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RXQ);
+	if (entry) {
+		n = get_entry_values(entry,
+			cfg->port[port].tc[tc].inq,
+			sizeof(cfg->port[port].tc[tc].inq[0]),
+			RTE_DIM(cfg->port[port].tc[tc].inq),
+			MRVL_PP2_RXQ_MAX);
+		if (n < 0) {
+			RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n",
+				n, entry);
+			return n;
+		}
+		cfg->port[port].tc[tc].inqs = n;
+	}
+
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PCP);
+	if (entry) {
+		n = get_entry_values(entry,
+			cfg->port[port].tc[tc].pcp,
+			sizeof(cfg->port[port].tc[tc].pcp[0]),
+			RTE_DIM(cfg->port[port].tc[tc].pcp),
+			MAX_PCP);
+		if (n < 0) {
+			RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n",
+				n, entry);
+			return n;
+		}
+		cfg->port[port].tc[tc].pcps = n;
+	}
+
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_DSCP);
+	if (entry) {
+		n = get_entry_values(entry,
+			cfg->port[port].tc[tc].dscp,
+			sizeof(cfg->port[port].tc[tc].dscp[0]),
+			RTE_DIM(cfg->port[port].tc[tc].dscp),
+			MAX_DSCP);
+		if (n < 0) {
+			RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n",
+				n, entry);
+			return n;
+		}
+		cfg->port[port].tc[tc].dscps = n;
+	}
+	return 0;
+}
+
+/**
+ * Parse QoS configuration - rte_kvargs_process handler.
+ *
+ * Opens configuration file and parses its content.
+ *
+ * @param key Unused.
+ * @param path Path to config file.
+ * @param extra_args Pointer to configuration structure.
+ * @returns 0 in case of success, exits otherwise.
+ */
+int
+mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
+		void *extra_args)
+{
+	struct mrvl_qos_cfg **cfg = extra_args;
+	struct rte_cfgfile *file = rte_cfgfile_load(path, 0);
+	uint32_t val;
+	int n, i, ret;
+	const char *entry;
+	char sec_name[32];
+
+	if (file == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot load configuration %s\n", path);
+
+	/* Create configuration. This is never accessed on the fast path,
+	 * so we can ignore socket.
+	 */
+	*cfg = rte_zmalloc("mrvl_qos_cfg", sizeof(struct mrvl_qos_cfg), 0);
+	if (*cfg == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot allocate configuration %s\n",
+			path);
+
+	n = rte_cfgfile_num_sections(file, MRVL_TOK_PORT,
+		sizeof(MRVL_TOK_PORT) - 1);
+
+	if (n == 0) {
+		/* This is weird, but not bad. */
+		RTE_LOG(WARNING, PMD, "Empty configuration file?\n");
+		return 0;
+	}
+
+	/* Use the number of ports given as vdev parameters. */
+	for (n = 0; n < mrvl_ports_nb; ++n) {
+		snprintf(sec_name, sizeof(sec_name), "%s %d %s",
+			MRVL_TOK_PORT, n, MRVL_TOK_DEFAULT);
+
+		/* Skip ports non-existing in configuration. */
+		if (rte_cfgfile_num_sections(file, sec_name,
+				strlen(sec_name)) <= 0) {
+			(*cfg)->port[n].use_global_defaults = 1;
+			(*cfg)->port[n].mapping_priority =
+				PP2_CLS_QOS_TBL_VLAN_IP_PRI;
+			continue;
+		}
+
+		entry = rte_cfgfile_get_entry(file, sec_name,
+				MRVL_TOK_DEFAULT_TC);
+		if (entry) {
+			if ((get_val_securely(entry, &val) < 0) ||
+				(val > USHRT_MAX))
+				return -1;
+			(*cfg)->port[n].default_tc = (uint8_t)val;
+		} else {
+			RTE_LOG(ERR, PMD,
+				"Default Traffic Class required in custom configuration!\n");
+			return -1;
+		}
+
+		entry = rte_cfgfile_get_entry(file, sec_name,
+				MRVL_TOK_MAPPING_PRIORITY);
+		if (entry) {
+			if (!strncmp(entry, MRVL_TOK_VLAN_IP,
+				sizeof(MRVL_TOK_VLAN_IP)))
+				(*cfg)->port[n].mapping_priority =
+					PP2_CLS_QOS_TBL_VLAN_IP_PRI;
+			else if (!strncmp(entry, MRVL_TOK_IP_VLAN,
+				sizeof(MRVL_TOK_IP_VLAN)))
+				(*cfg)->port[n].mapping_priority =
+					PP2_CLS_QOS_TBL_IP_VLAN_PRI;
+			else if (!strncmp(entry, MRVL_TOK_IP,
+				sizeof(MRVL_TOK_IP)))
+				(*cfg)->port[n].mapping_priority =
+					PP2_CLS_QOS_TBL_IP_PRI;
+			else if (!strncmp(entry, MRVL_TOK_VLAN,
+				sizeof(MRVL_TOK_VLAN)))
+				(*cfg)->port[n].mapping_priority =
+					PP2_CLS_QOS_TBL_VLAN_PRI;
+			else
+				rte_exit(EXIT_FAILURE,
+					"Error in parsing %s value (%s)!\n",
+					MRVL_TOK_MAPPING_PRIORITY, entry);
+		} else {
+			(*cfg)->port[n].mapping_priority =
+				PP2_CLS_QOS_TBL_VLAN_IP_PRI;
+		}
+
+		for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) {
+			ret = get_outq_cfg(file, n, i, *cfg);
+			if (ret < 0)
+				rte_exit(EXIT_FAILURE,
+					"Error %d parsing port %d outq %d!\n",
+					ret, n, i);
+		}
+
+		for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
+			ret = parse_tc_cfg(file, n, i, *cfg);
+			if (ret < 0)
+				rte_exit(EXIT_FAILURE,
+					"Error %d parsing port %d tc %d!\n",
+					ret, n, i);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Setup Traffic Class.
+ *
+ * Fill in TC parameters in single MUSDK TC config entry.
+ * @param param TC parameters entry.
+ * @param inqs Number of MUSDK in-queues in this TC.
+ * @param bpool Bpool for this TC.
+ * @returns 0 in case of success, exits otherwise.
+ */
+static int
+setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
+	struct pp2_bpool *bpool)
+{
+	struct pp2_ppio_inq_params *inq_params;
+
+	param->pkt_offset = MRVL_PKT_OFFS;
+	param->pools[0] = bpool;
+
+	inq_params = rte_zmalloc_socket("inq_params",
+		inqs * sizeof(*inq_params),
+		0, rte_socket_id());
+	if (!inq_params)
+		return -ENOMEM;
+
+	param->num_in_qs = inqs;
+
+	/* Release old config if necessary. */
+	if (param->inqs_params)
+		rte_free(param->inqs_params);
+
+	param->inqs_params = inq_params;
+
+	return 0;
+}
+
+/**
+ * Configure RX Queues in a given port.
+ *
+ * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
+ *
+ * @param priv Port's private data
+ * @param portid DPDK port ID
+ * @param max_queues Maximum number of queues to configure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+int
+mrvl_configure_rxqs(struct mrvl_priv *priv, uint8_t portid,
+	uint16_t max_queues)
+{
+	size_t i, tc;
+
+	if ((mrvl_qos_cfg == NULL) ||
+		(mrvl_qos_cfg->port[portid].use_global_defaults)) {
+		/* No port configuration, use default: 1 TC, no QoS. */
+		priv->ppio_params.inqs_params.num_tcs = 1;
+		setup_tc(&priv->ppio_params.inqs_params.tcs_params[0],
+			max_queues, priv->bpool);
+
+		/* Direct mapping of queues i.e. 0->0, 1->1 etc. */
+		for (i = 0; i < max_queues; ++i) {
+			priv->rxq_map[i].tc = 0;
+			priv->rxq_map[i].inq = i;
+		}
+		return 0;
+	}
+
+	/* We need only a subset of configuration. */
+	struct port_cfg *port_cfg = &mrvl_qos_cfg->port[portid];
+
+	priv->qos_tbl_params.type = port_cfg->mapping_priority;
+
+	/*
+	 * We need to reverse mapping, from tc->pcp (better from usability
+	 * point of view) to pcp->tc (configurable in MUSDK).
+	 * First, set all map elements to "default".
+	 */
+	for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
+		priv->qos_tbl_params.pcp_cos_map[i].tc = port_cfg->default_tc;
+
+	/* Then, fill in all known values. */
+	for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
+		if (port_cfg->tc[tc].pcps > RTE_DIM(port_cfg->tc[0].pcp)) {
+			/* Better safe than sorry. */
+			RTE_LOG(ERR, PMD,
+				"Too many PCPs configured in TC %zu!\n", tc);
+			return -1;
+		}
+		for (i = 0; i < port_cfg->tc[tc].pcps; ++i) {
+			priv->qos_tbl_params.pcp_cos_map[
+			  port_cfg->tc[tc].pcp[i]].tc = tc;
+		}
+	}
+
+	/*
+	 * The same logic goes with DSCP.
+	 * First, set all map elements to "default".
+	 */
+	for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
+		priv->qos_tbl_params.dscp_cos_map[i].tc =
+			port_cfg->default_tc;
+
+	/* Fill in all known values. */
+	for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
+		if (port_cfg->tc[tc].dscps > RTE_DIM(port_cfg->tc[0].dscp)) {
+			/* Better safe than sorry. */
+			RTE_LOG(ERR, PMD,
+				"Too many DSCPs configured in TC %zu!\n", tc);
+			return -1;
+		}
+		for (i = 0; i < port_cfg->tc[tc].dscps; ++i) {
+			priv->qos_tbl_params.dscp_cos_map[
+			  port_cfg->tc[tc].dscp[i]].tc = tc;
+		}
+	}
+
+	/*
+	 * Surprisingly, similar logic goes with queue mapping.
+	 * We need only to store qid->tc mapping,
+	 * to know TC when queue is read.
+	 */
+	for (i = 0; i < RTE_DIM(priv->rxq_map); ++i)
+		priv->rxq_map[i].tc = MRVL_UNKNOWN_TC;
+
+	/* Set up DPDKq->(TC,inq) mapping. */
+	for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
+		if (port_cfg->tc[tc].inqs > RTE_DIM(port_cfg->tc[0].inq)) {
+			/* Overflow. */
+			RTE_LOG(ERR, PMD,
+				"Too many RX queues configured per TC %zu!\n",
+				tc);
+			return -1;
+		}
+		for (i = 0; i < port_cfg->tc[tc].inqs; ++i) {
+			uint8_t idx = port_cfg->tc[tc].inq[i];
+			priv->rxq_map[idx].tc = tc;
+			priv->rxq_map[idx].inq = i;
+		}
+	}
+
+	/*
+	 * Set up TC configuration. TCs need to be sequenced: 0, 1, 2
+	 * with no gaps. Empty TC means end of processing.
+	 */
+	for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
+		if (port_cfg->tc[i].inqs == 0)
+			break;
+		setup_tc(&priv->ppio_params.inqs_params.tcs_params[i],
+				port_cfg->tc[i].inqs,
+				priv->bpool);
+	}
+
+	priv->ppio_params.inqs_params.num_tcs = i;
+
+	return 0;
+}
+
+/**
+ * Start QoS mapping.
+ *
+ * Finalize QoS table configuration and initialize it in SDK. It can be done
+ * only after port is started, so we have a valid ppio reference.
+ *
+ * @param priv Port's private (configuration) data.
+ * @returns 0 in case of success, exits otherwise.
+ */
+int
+mrvl_start_qos_mapping(struct mrvl_priv *priv)
+{
+	size_t i;
+
+	if (priv->ppio == NULL) {
+		RTE_LOG(ERR, PMD, "ppio must not be NULL here!\n");
+		return -1;
+	}
+
+	for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
+		priv->qos_tbl_params.pcp_cos_map[i].ppio = priv->ppio;
+
+	for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
+		priv->qos_tbl_params.dscp_cos_map[i].ppio = priv->ppio;
+
+	/* Initialize Classifier QoS table. */
+
+	return pp2_cls_qos_tbl_init(&priv->qos_tbl_params, &priv->qos_tbl);
+}
diff --git a/drivers/net/mrvl/mrvl_qos.h b/drivers/net/mrvl/mrvl_qos.h
new file mode 100644
index 0000000..8542db6
--- /dev/null
+++ b/drivers/net/mrvl/mrvl_qos.h
@@ -0,0 +1,112 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Semihalf. 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 Semihalf 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 _MRVL_QOS_H_
+#define _MRVL_QOS_H_
+
+#include <rte_common.h>
+#include <rte_config.h>
+
+#include "mrvl_ethdev.h"
+
+/** Code Points per Traffic Class. Equals max(DSCP, PCP). */
+#define MRVL_CP_PER_TC (64)
+
+/** Value used as "unknown". */
+#define MRVL_UNKNOWN_TC (0xFF)
+
+/* QoS config. */
+struct mrvl_qos_cfg {
+	struct port_cfg {
+		struct {
+			uint8_t inq[MRVL_PP2_RXQ_MAX];
+			uint8_t dscp[MRVL_CP_PER_TC];
+			uint8_t pcp[MRVL_CP_PER_TC];
+			uint8_t inqs;
+			uint8_t dscps;
+			uint8_t pcps;
+		} tc[MRVL_PP2_TC_MAX];
+		struct {
+			uint8_t weight;
+		} outq[MRVL_PP2_RXQ_MAX];
+		enum pp2_cls_qos_tbl_type mapping_priority;
+		uint16_t inqs;
+		uint16_t outqs;
+		uint8_t default_tc;
+		uint8_t use_global_defaults;
+	} port[RTE_MAX_ETHPORTS];
+};
+
+/** Global QoS configuration. */
+extern struct mrvl_qos_cfg *mrvl_qos_cfg;
+
+/**
+ * Parse QoS configuration - rte_kvargs_process handler.
+ *
+ * Opens configuration file and parses its content.
+ *
+ * @param key Unused.
+ * @param path Path to config file.
+ * @param extra_args Pointer to configuration structure.
+ * @returns 0 in case of success, exits otherwise.
+ */
+int
+mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
+		void *extra_args);
+
+/**
+ * Configure RX Queues in a given port.
+ *
+ * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
+ *
+ * @param priv Port's private data
+ * @param portid DPDK port ID
+ * @param max_queues Maximum number of queues to configure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+int
+mrvl_configure_rxqs(struct mrvl_priv *priv, uint8_t portid,
+		uint16_t max_queues);
+
+/**
+ * Start QoS mapping.
+ *
+ * Finalize QoS table configuration and initialize it in SDK. It can be done
+ * only after port is started, so we have a valid ppio reference.
+ *
+ * @param priv Port's private (configuration) data.
+ * @returns 0 in case of success, exits otherwise.
+ */
+int
+mrvl_start_qos_mapping(struct mrvl_priv *priv);
+
+#endif /* _MRVL_QOS_H_ */
diff --git a/drivers/net/mrvl/rte_pmd_mrvl_version.map b/drivers/net/mrvl/rte_pmd_mrvl_version.map
new file mode 100644
index 0000000..a753031
--- /dev/null
+++ b/drivers/net/mrvl/rte_pmd_mrvl_version.map
@@ -0,0 +1,3 @@
+DPDK_17.11 {
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 94568a8..8df74bb 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -130,6 +130,7 @@ endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_LIO_PMD)        += -lrte_pmd_lio
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -libverbs
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD)       += -lrte_pmd_mlx5 -libverbs
+_LDLIBS-$(CONFIG_RTE_LIBRTE_MRVL_PMD)       += -lrte_pmd_mrvl -L$(LIBMUSDK_PATH)/lib -lmusdk
 _LDLIBS-$(CONFIG_RTE_LIBRTE_NFP_PMD)        += -lrte_pmd_nfp
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NULL)       += -lrte_pmd_null
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_PCAP)       += -lrte_pmd_pcap -lpcap
-- 
2.7.4

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

* [PATCH 3/8] doc: add mrvl net pmd documentation
  2017-09-26  9:39 [PATCH 0/8] add net/crypto mrvl pmd drivers Tomasz Duszynski
  2017-09-26  9:39 ` [PATCH 1/8] app: link the whole rte_cfgfile library Tomasz Duszynski
  2017-09-26  9:39 ` [PATCH 2/8] net/mrvl: add mrvl net pmd driver Tomasz Duszynski
@ 2017-09-26  9:40 ` Tomasz Duszynski
  2017-09-26  9:40 ` [PATCH 4/8] maintainers: add maintainers for the mrvl net pmd Tomasz Duszynski
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-26  9:40 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Tomasz Duszynski, Jacek Siuda

Add documentation for the MRVL NET PMD driver.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <jck@semihalf.com>
---
 doc/guides/nics/features/mrvl.ini |  24 ++++++
 doc/guides/nics/index.rst         |   1 +
 doc/guides/nics/mrvl.rst          | 151 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 176 insertions(+)
 create mode 100644 doc/guides/nics/features/mrvl.ini
 create mode 100644 doc/guides/nics/mrvl.rst

diff --git a/doc/guides/nics/features/mrvl.ini b/doc/guides/nics/features/mrvl.ini
new file mode 100644
index 0000000..781d6dc
--- /dev/null
+++ b/doc/guides/nics/features/mrvl.ini
@@ -0,0 +1,24 @@
+;
+; Supported features of the 'mrvl' network poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Speed capabilities   = Y
+Link status          = Y
+MTU update           = Y
+Jumbo frame          = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Unicast MAC filter   = Y
+Multicast MAC filter = Y
+RSS hash             = Y
+VLAN filter          = Y
+CRC offload          = Y
+L3 checksum offload  = Y
+L4 checksum offload  = Y
+Packet type parsing  = Y
+Basic stats          = Y
+Stats per queue      = Y
+ARMv8                = Y
+Usage doc            = Y
diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index 36f4f3f..7192f63 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -55,6 +55,7 @@ Network Interface Controller Drivers
     liquidio
     mlx4
     mlx5
+    mrvl
     nfp
     qede
     sfc_efx
diff --git a/doc/guides/nics/mrvl.rst b/doc/guides/nics/mrvl.rst
new file mode 100644
index 0000000..241d89b
--- /dev/null
+++ b/doc/guides/nics/mrvl.rst
@@ -0,0 +1,151 @@
+..  BSD LICENSE
+    Copyright(c) 2017 Semihalf. All rights reserved.
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in
+        the documentation and/or other materials provided with the
+        distribution.
+      * Neither the name of Semihalf 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.
+
+MRVL Poll Mode Driver
+======================
+
+The MRVL PMD (librte_pmd_mrvl) provides poll mode driver support
+for the Marvell PPv2 (Packet Processor v2) 1/10 Gbps adapter.
+
+.. Note::
+
+   Due to external dependencies, this driver is disabled by default. It must
+   be enabled manually by setting relevant configuration option manually.
+   Please refer to `Config File Options`_ section for further details.
+
+
+Features
+--------
+
+Features of the MRVL PMD are:
+
+- Speed capabilities
+- Link status
+- Queue start/stop
+- MTU update
+- Jumbo frame
+- Promiscuous mode
+- Allmulticast mode
+- Unicast MAC filter
+- Multicast MAC filter
+- RSS hash
+- VLAN filter
+- CRC offload
+- L3 checksum offload
+- L4 checksum offload
+- Packet type parsing
+- Basic stats
+- Stats per queue
+
+
+Limitations
+-----------
+
+- Number of lcores is limited to 9 by MUSDK internal design. If more lcores
+  need to be allocated, locking will have to be considered. Number of available
+  lcores can be changed via ``MRVL_MUSDK_HIFS_RESERVED`` define in
+  ``mrvl_ethdev.c`` source file.
+
+- Flushing vlans added for filtering is not possible due to MUSDK missing
+  functionality. Current workaround is to reset board so that PPv2 has a
+  chance to start in a sane state.
+
+
+Prerequisites
+-------------
+
+- MUSDK (Marvell User-Space SDK) sources available
+  `here <https://github.com/MarvellEmbeddedProcessors/musdk-marvell/tree/musdk-armada-17.08>`_.
+
+    MUSDK is a light-weight library that provides direct access to Marvell's
+    PPv2 (Packet Processor v2). Alternatively prebuilt MUSDK library can be
+    requested from `Marvell Extranet <https://extranet.marvell.com>`_. Once
+    approval has been granted, library can be found by typing ``musdk`` in
+    search box.
+
+- DPDK environment
+
+    Follow the DPDK :ref:`Getting Started Guide for Linux <linux_gsg>` to setup
+    DPDK environment.
+
+
+Config File Options
+-------------------
+
+The following options can be modified in the ``config`` file.
+
+- ``CONFIG_RTE_LIBRTE_MRVL_PMD`` (default ``n``)
+
+    Toggle compilation of the librte_pmd_mrvl driver.
+
+- ``CONFIG_RTE_LIBRTE_MRVL_DEBUG`` (default ``n``)
+
+    Toggle display of debugging messages.
+
+- ``CONFIG_RTE_MRVL_MUSDK_DMA_MEMSIZE`` (default ``41943040``)
+
+    Size in bytes of the contiguous memory region that MUSDK will allocate
+    for run-time DMA-able data buffers.
+
+
+Building DPDK
+-------------
+
+Driver needs precompiled MUSDK library during compilation. Detailed build
+process is described in library's documentation under ``doc`` directory.
+
+Before the DPDK build process the environmental variable ``LIBMUSDK_PATH`` with
+the path to the MUSDK installation directory needs to be exported.
+
+Usage Example
+-------------
+
+MRVL PMD requires extra kernel modules to function properly:
+
+.. code-block:: console
+
+   insmod musdk_uio.ko
+   insmod mv_pp_uio.ko
+   insmod mvpp2x_sysfs.ko
+
+Additionally interfaces used by DPDK application need to be put up:
+
+.. code-block:: console
+
+   ip link set eth0 up
+   ip link set eth1 up
+
+In order to run testpmd example application following command can be used:
+
+.. code-block:: console
+
+   ./testpmd --vdev=eth_mrvl,iface=eth0,iface=eth2 -c 7 -- \
+     --burst=128 --txd=2048 --rxd=1024 --rxq=2 --txq=2  --nb-cores=2 \
+     -i -a --disable-hw-vlan-strip --rss-udp
-- 
2.7.4

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

* [PATCH 4/8] maintainers: add maintainers for the mrvl net pmd
  2017-09-26  9:39 [PATCH 0/8] add net/crypto mrvl pmd drivers Tomasz Duszynski
                   ` (2 preceding siblings ...)
  2017-09-26  9:40 ` [PATCH 3/8] doc: add mrvl net pmd documentation Tomasz Duszynski
@ 2017-09-26  9:40 ` Tomasz Duszynski
  2017-09-26  9:40 ` [PATCH 5/8] crypto/mrvl: add mrvl crypto pmd driver Tomasz Duszynski
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-26  9:40 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Tomasz Duszynski, Jacek Siuda

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 MAINTAINERS | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index a0cd75e..d4810cf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -393,6 +393,16 @@ F: drivers/net/mlx5/
 F: doc/guides/nics/mlx5.rst
 F: doc/guides/nics/features/mlx5.ini
 
+Marvell mrvl
+M: Jacek Siuda <jck@semihalf.com>
+M: Tomasz Duszynski <tdu@semihalf.com>
+M: Dmitri Epshtein <dima@marvell.com>
+M: Natalie Samsonov <nsamsono@marvell.com>
+M: Jianbo Liu <jianbo.liu@linaro.org>
+F: drivers/net/mrvl/
+F: doc/guides/nics/mrvl.rst
+F: doc/guides/nics/features/mrvl.ini
+
 Netcope szedata2
 M: Matej Vido <vido@cesnet.cz>
 F: drivers/net/szedata2/
-- 
2.7.4

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

* [PATCH 5/8] crypto/mrvl: add mrvl crypto pmd driver
  2017-09-26  9:39 [PATCH 0/8] add net/crypto mrvl pmd drivers Tomasz Duszynski
                   ` (3 preceding siblings ...)
  2017-09-26  9:40 ` [PATCH 4/8] maintainers: add maintainers for the mrvl net pmd Tomasz Duszynski
@ 2017-09-26  9:40 ` Tomasz Duszynski
  2017-09-26  9:40 ` [PATCH 6/8] doc: add mrvl crypto pmd documentation Tomasz Duszynski
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-26  9:40 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Tomasz Duszynski, Jacek Siuda

Add support for the Marvell Security Crypto Accelerator EIP197.
Driver is based on external, publicly available, Marvell MUSDK
library that provides access to the hardware with minimum overhead
and high performance.

Driver comes with support for the following features:

* Symmetric crypto
* Sym operation chaining
* AES CBC (128)
* AES CBC (192)
* AES CBC (256)
* AES CTR (128)
* AES CTR (192)
* AES CTR (256)
* 3DES CBC
* 3DES CTR
* MD5
* MD5 HMAC
* SHA1
* SHA1 HMAC
* SHA256
* SHA256 HMAC
* SHA384
* SHA384 HMAC
* SHA512
* SHA512 HMAC
* AES GCM (128)

Driver was engineered cooperatively by Semihalf and Marvell teams.

Semihalf:
Jacek Siuda <jck@semihalf.com>
Tomasz Duszynski <tdu@semihalf.com>

Marvell:
Dmitri Epshtein <dima@marvell.com>
Natalie Samsonov <nsamsono@marvell.com>

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 config/common_base                           |   6 +
 drivers/crypto/Makefile                      |   2 +
 drivers/crypto/mrvl/Makefile                 |  63 ++
 drivers/crypto/mrvl/rte_mrvl_compat.h        |  48 ++
 drivers/crypto/mrvl/rte_mrvl_pmd.c           | 866 +++++++++++++++++++++++++++
 drivers/crypto/mrvl/rte_mrvl_pmd_ops.c       | 787 ++++++++++++++++++++++++
 drivers/crypto/mrvl/rte_mrvl_pmd_private.h   | 121 ++++
 drivers/crypto/mrvl/rte_mrvl_pmd_version.map |   3 +
 mk/rte.app.mk                                |   1 +
 9 files changed, 1897 insertions(+)
 create mode 100644 drivers/crypto/mrvl/Makefile
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_compat.h
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd.c
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_private.h
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_version.map

diff --git a/config/common_base b/config/common_base
index d05a60c..e9b181e 100644
--- a/config/common_base
+++ b/config/common_base
@@ -521,6 +521,12 @@ CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER_DEBUG=n
 CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO=y
 
 #
+# Compile PMD for Marvell Crypto device
+#
+CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO=n
+CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO_DEBUG=n
+
+#
 # Compile generic event device library
 #
 CONFIG_RTE_LIBRTE_EVENTDEV=y
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 7a719b9..1d7db5b 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -51,6 +51,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_KASUMI) += kasumi
 DEPDIRS-kasumi = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_ZUC) += zuc
 DEPDIRS-zuc = $(core-libs)
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO) += mrvl
+DEPDIRS-mrvl = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO) += null
 DEPDIRS-null = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_SEC) += dpaa2_sec
diff --git a/drivers/crypto/mrvl/Makefile b/drivers/crypto/mrvl/Makefile
new file mode 100644
index 0000000..a00a19e
--- /dev/null
+++ b/drivers/crypto/mrvl/Makefile
@@ -0,0 +1,63 @@
+#   BSD LICENSE
+#
+#   Copyright (C) Semihalf 2017. 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 Semihalf 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
+
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),config)
+ifeq ($(LIBMUSDK_PATH),)
+$(error "Please define LIBMUSDK_PATH environment variable")
+endif
+endif
+endif
+
+# library name
+LIB = librte_pmd_mrvl_crypto.a
+
+# build flags
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -I$(LIBMUSDK_PATH)/include
+CFLAGS += -DMVCONF_ARCH_DMA_ADDR_T_64BIT
+
+# library version
+LIBABIVER := 1
+
+# versioning export map
+EXPORT_MAP := rte_mrvl_pmd_version.map
+
+# external library dependencies
+LDLIBS += -L$(LIBMUSDK_PATH)/lib -lmusdk
+
+# library source files
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO) += rte_mrvl_pmd.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO) += rte_mrvl_pmd_ops.c
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/crypto/mrvl/rte_mrvl_compat.h b/drivers/crypto/mrvl/rte_mrvl_compat.h
new file mode 100644
index 0000000..11d53fc
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_mrvl_compat.h
@@ -0,0 +1,48 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) Semihalf 2017. 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 Semihalf 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_MRVL_COMPAT_H_
+#define _RTE_MRVL_COMPAT_H_
+
+/* Unluckily, container_of is defined by both DPDK and MUSDK,
+ * we'll declare only one version.
+ *
+ * Note that it is not used in this PMD anyway.
+ */
+#ifdef container_of
+#undef container_of
+#endif
+#include "drivers/mv_sam.h"
+#include "drivers/mv_sam_cio.h"
+#include "drivers/mv_sam_session.h"
+
+#endif /* _RTE_MRVL_COMPAT_H_ */
diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd.c b/drivers/crypto/mrvl/rte_mrvl_pmd.c
new file mode 100644
index 0000000..4a0156c
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_mrvl_pmd.c
@@ -0,0 +1,866 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) Semihalf 2017. 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 Semihalf 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_common.h>
+#include <rte_hexdump.h>
+#include <rte_cryptodev.h>
+#include <rte_cryptodev_pmd.h>
+#include <rte_cryptodev_vdev.h>
+#include <rte_vdev.h>
+#include <rte_malloc.h>
+#include <rte_cpuflags.h>
+
+#include "rte_mrvl_pmd_private.h"
+
+static uint8_t cryptodev_driver_id;
+
+/**
+ * Flag if particular crypto algorithm is supported by PMD/MUSDK.
+ *
+ * The idea is to have Not Supported value as default (0).
+ * This way we need only to define proper map sizes,
+ * non-initialized entries will be by default not supported.
+ */
+enum algo_supported {
+	ALGO_NOT_SUPPORTED = 0,
+	ALGO_SUPPORTED = 1,
+};
+
+/** Map elements for cipher mapping.*/
+struct cipher_params_mapping {
+	enum algo_supported  supported;   /**< On/Off switch */
+	enum sam_cipher_alg  cipher_alg;  /**< Cipher algorithm */
+	enum sam_cipher_mode cipher_mode; /**< Cipher mode */
+	unsigned int max_key_len;         /**< Maximum key length (in bytes)*/
+}
+/* We want to squeeze in multiple maps into the cache line. */
+__rte_aligned(32);
+
+/** Map elements for auth mapping.*/
+struct auth_params_mapping {
+	enum algo_supported supported;  /**< On/off switch */
+	enum sam_auth_alg   auth_alg;   /**< Auth algorithm */
+}
+/* We want to squeeze in multiple maps into the cache line. */
+__rte_aligned(32);
+
+/**
+ * Map of supported cipher algorithms.
+ */
+static const
+struct cipher_params_mapping cipher_map[RTE_CRYPTO_CIPHER_LIST_END] = {
+	[RTE_CRYPTO_CIPHER_3DES_CBC] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_3DES,
+		.cipher_mode = SAM_CIPHER_CBC,
+		.max_key_len = BITS2BYTES(192) },
+	[RTE_CRYPTO_CIPHER_3DES_CTR] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_3DES,
+		.cipher_mode = SAM_CIPHER_CTR,
+		.max_key_len = BITS2BYTES(192) },
+	[RTE_CRYPTO_CIPHER_3DES_ECB] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_3DES,
+		.cipher_mode = SAM_CIPHER_ECB,
+		.max_key_len = BITS2BYTES(192) },
+	[RTE_CRYPTO_CIPHER_AES_CBC] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_AES,
+		.cipher_mode = SAM_CIPHER_CBC,
+		.max_key_len = BITS2BYTES(256) },
+	[RTE_CRYPTO_CIPHER_AES_CTR] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_AES,
+		.cipher_mode = SAM_CIPHER_CTR,
+		.max_key_len = BITS2BYTES(256) },
+};
+
+/**
+ * Map of supported auth algorithms.
+ */
+static const
+struct auth_params_mapping auth_map[RTE_CRYPTO_AUTH_LIST_END] = {
+	[RTE_CRYPTO_AUTH_MD5_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_MD5 },
+	[RTE_CRYPTO_AUTH_MD5] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_MD5 },
+	[RTE_CRYPTO_AUTH_SHA1_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_SHA1 },
+	[RTE_CRYPTO_AUTH_SHA1] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA1 },
+	[RTE_CRYPTO_AUTH_SHA224] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA2_224 },
+	[RTE_CRYPTO_AUTH_SHA256_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_SHA2_256 },
+	[RTE_CRYPTO_AUTH_SHA256] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA2_256 },
+	[RTE_CRYPTO_AUTH_SHA384_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_SHA2_384 },
+	[RTE_CRYPTO_AUTH_SHA384] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA2_384 },
+	[RTE_CRYPTO_AUTH_SHA512_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_SHA2_512 },
+	[RTE_CRYPTO_AUTH_SHA512] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA2_512 },
+	[RTE_CRYPTO_AUTH_AES_GMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_AES_GMAC },
+};
+
+/**
+ * Map of supported aead algorithms.
+ */
+static const
+struct cipher_params_mapping aead_map[RTE_CRYPTO_AEAD_LIST_END] = {
+	[RTE_CRYPTO_AEAD_AES_GCM] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_AES,
+		.cipher_mode = SAM_CIPHER_GCM,
+		.max_key_len = BITS2BYTES(256) },
+};
+
+/*
+ *-----------------------------------------------------------------------------
+ * Forward declarations.
+ *-----------------------------------------------------------------------------
+ */
+static int cryptodev_mrvl_crypto_uninit(struct rte_vdev_device *vdev);
+
+/*
+ *-----------------------------------------------------------------------------
+ * Session Preparation.
+ *-----------------------------------------------------------------------------
+ */
+
+/**
+ * Get xform chain order.
+ *
+ * @param xform Pointer to configuration structure chain for crypto operations.
+ * @returns Order of crypto operations.
+ */
+static enum mrvl_crypto_chain_order
+mrvl_crypto_get_chain_order(const struct rte_crypto_sym_xform *xform)
+{
+	/* Currently, Marvell supports max 2 operations in chain */
+	if (xform->next != NULL && xform->next->next != NULL)
+		return MRVL_CRYPTO_CHAIN_NOT_SUPPORTED;
+
+	if (xform->next != NULL) {
+		if ((xform->type == RTE_CRYPTO_SYM_XFORM_AUTH) &&
+			(xform->next->type == RTE_CRYPTO_SYM_XFORM_CIPHER))
+			return MRVL_CRYPTO_CHAIN_AUTH_CIPHER;
+
+		if ((xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER) &&
+			(xform->next->type == RTE_CRYPTO_SYM_XFORM_AUTH))
+			return MRVL_CRYPTO_CHAIN_CIPHER_AUTH;
+	} else {
+		if (xform->type == RTE_CRYPTO_SYM_XFORM_AUTH)
+			return MRVL_CRYPTO_CHAIN_AUTH_ONLY;
+
+		if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER)
+			return MRVL_CRYPTO_CHAIN_CIPHER_ONLY;
+
+		if (xform->type == RTE_CRYPTO_SYM_XFORM_AEAD)
+			return MRVL_CRYPTO_CHAIN_COMBINED;
+	}
+	return MRVL_CRYPTO_CHAIN_NOT_SUPPORTED;
+}
+
+/**
+ * Set session parameters for cipher part.
+ *
+ * @param sess Crypto session pointer.
+ * @param cipher_xform Pointer to configuration structure for cipher operations.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+mrvl_crypto_set_cipher_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *cipher_xform)
+{
+	/* Make sure we've got proper struct */
+	if (cipher_xform->type != RTE_CRYPTO_SYM_XFORM_CIPHER) {
+		MRVL_CRYPTO_LOG_ERR("Wrong xform struct provided!");
+		return -EINVAL;
+	}
+
+	/* See if map data is present and valid */
+	if ((cipher_xform->cipher.algo > RTE_DIM(cipher_map)) ||
+		(cipher_map[cipher_xform->cipher.algo].supported
+			!= ALGO_SUPPORTED)) {
+		MRVL_CRYPTO_LOG_ERR("Cipher algorithm not supported!");
+		return -EINVAL;
+	}
+
+	sess->cipher_iv_offset = cipher_xform->cipher.iv.offset;
+
+	sess->sam_sess_params.dir =
+		(cipher_xform->cipher.op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) ?
+		SAM_DIR_ENCRYPT : SAM_DIR_DECRYPT;
+	sess->sam_sess_params.cipher_alg =
+		cipher_map[cipher_xform->cipher.algo].cipher_alg;
+	sess->sam_sess_params.cipher_mode =
+		cipher_map[cipher_xform->cipher.algo].cipher_mode;
+
+	/* Assume IV will be passed together with data. */
+	sess->sam_sess_params.cipher_iv = NULL;
+
+	/* Get max key length. */
+	if (cipher_xform->cipher.key.length >
+		cipher_map[cipher_xform->cipher.algo].max_key_len) {
+		MRVL_CRYPTO_LOG_ERR("Wrong key length!");
+		return -EINVAL;
+	}
+
+	sess->sam_sess_params.cipher_key_len = cipher_xform->cipher.key.length;
+	sess->sam_sess_params.cipher_key = cipher_xform->cipher.key.data;
+
+	return 0;
+}
+
+/**
+ * Set session parameters for authentication part.
+ *
+ * @param sess Crypto session pointer.
+ * @param auth_xform Pointer to configuration structure for auth operations.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+mrvl_crypto_set_auth_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *auth_xform)
+{
+	/* Make sure we've got proper struct */
+	if (auth_xform->type != RTE_CRYPTO_SYM_XFORM_AUTH) {
+		MRVL_CRYPTO_LOG_ERR("Wrong xform struct provided!");
+		return -EINVAL;
+	}
+
+	/* See if map data is present and valid */
+	if ((auth_xform->auth.algo > RTE_DIM(auth_map)) ||
+		(auth_map[auth_xform->auth.algo].supported != ALGO_SUPPORTED)) {
+		MRVL_CRYPTO_LOG_ERR("Auth algorithm not supported!");
+		return -EINVAL;
+	}
+
+	sess->sam_sess_params.dir =
+		(auth_xform->auth.op == RTE_CRYPTO_AUTH_OP_GENERATE) ?
+		SAM_DIR_ENCRYPT : SAM_DIR_DECRYPT;
+	sess->sam_sess_params.auth_alg =
+		auth_map[auth_xform->auth.algo].auth_alg;
+	sess->sam_sess_params.u.basic.auth_icv_len =
+		auth_xform->auth.digest_length;
+	/* auth_key must be NULL if auth algorithm does not use HMAC */
+	sess->sam_sess_params.auth_key = auth_xform->auth.key.length ?
+					 auth_xform->auth.key.data : NULL;
+	sess->sam_sess_params.auth_key_len = auth_xform->auth.key.length;
+
+	return 0;
+}
+
+/**
+ * Set session parameters for aead part.
+ *
+ * @param sess Crypto session pointer.
+ * @param aead_xform Pointer to configuration structure for aead operations.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+mrvl_crypto_set_aead_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *aead_xform)
+{
+	/* Make sure we've got proper struct */
+	if (aead_xform->type != RTE_CRYPTO_SYM_XFORM_AEAD) {
+		MRVL_CRYPTO_LOG_ERR("Wrong xform struct provided!");
+		return -EINVAL;
+	}
+
+	/* See if map data is present and valid */
+	if ((aead_xform->aead.algo > RTE_DIM(aead_map)) ||
+		(aead_map[aead_xform->aead.algo].supported
+			!= ALGO_SUPPORTED)) {
+		MRVL_CRYPTO_LOG_ERR("AEAD algorithm not supported!");
+		return -EINVAL;
+	}
+
+	sess->sam_sess_params.dir =
+		(aead_xform->aead.op == RTE_CRYPTO_AEAD_OP_ENCRYPT) ?
+		SAM_DIR_ENCRYPT : SAM_DIR_DECRYPT;
+	sess->sam_sess_params.cipher_alg =
+		aead_map[aead_xform->aead.algo].cipher_alg;
+	sess->sam_sess_params.cipher_mode =
+		aead_map[aead_xform->aead.algo].cipher_mode;
+
+	/* Assume IV will be passed together with data. */
+	sess->sam_sess_params.cipher_iv = NULL;
+
+	/* Get max key length. */
+	if (aead_xform->aead.key.length >
+		aead_map[aead_xform->aead.algo].max_key_len) {
+		MRVL_CRYPTO_LOG_ERR("Wrong key length!");
+		return -EINVAL;
+	}
+
+	sess->sam_sess_params.cipher_key = aead_xform->aead.key.data;
+	sess->sam_sess_params.cipher_key_len = aead_xform->aead.key.length;
+
+	if (sess->sam_sess_params.cipher_mode == SAM_CIPHER_GCM)
+		sess->sam_sess_params.auth_alg = SAM_AUTH_AES_GCM;
+
+	sess->sam_sess_params.u.basic.auth_icv_len =
+		aead_xform->aead.digest_length;
+
+	sess->sam_sess_params.u.basic.auth_aad_len =
+		aead_xform->aead.aad_length;
+
+	return 0;
+}
+
+/**
+ * Parse crypto transform chain and setup session parameters.
+ *
+ * @param dev Pointer to crypto device
+ * @param sess Poiner to crypto session
+ * @param xform Pointer to configuration structure chain for crypto operations.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+int
+mrvl_crypto_set_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *xform)
+{
+	const struct rte_crypto_sym_xform *cipher_xform = NULL;
+	const struct rte_crypto_sym_xform *auth_xform = NULL;
+	const struct rte_crypto_sym_xform *aead_xform = NULL;
+
+	/* Filter out spurious/broken requests */
+	if (xform == NULL)
+		return -EINVAL;
+
+	sess->chain_order = mrvl_crypto_get_chain_order(xform);
+	switch (sess->chain_order) {
+	case MRVL_CRYPTO_CHAIN_CIPHER_AUTH:
+		cipher_xform = xform;
+		auth_xform = xform->next;
+		break;
+	case MRVL_CRYPTO_CHAIN_AUTH_CIPHER:
+		auth_xform = xform;
+		cipher_xform = xform->next;
+		break;
+	case MRVL_CRYPTO_CHAIN_CIPHER_ONLY:
+		cipher_xform = xform;
+		break;
+	case MRVL_CRYPTO_CHAIN_AUTH_ONLY:
+		auth_xform = xform;
+		break;
+	case MRVL_CRYPTO_CHAIN_COMBINED:
+		aead_xform = xform;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if ((cipher_xform != NULL) &&
+		(mrvl_crypto_set_cipher_session_parameters(
+			sess, cipher_xform) < 0)) {
+		MRVL_CRYPTO_LOG_ERR("Invalid/unsupported cipher parameters");
+		return -EINVAL;
+	}
+
+	if ((auth_xform != NULL) &&
+		(mrvl_crypto_set_auth_session_parameters(
+			sess, auth_xform) < 0)) {
+		MRVL_CRYPTO_LOG_ERR("Invalid/unsupported auth parameters");
+		return -EINVAL;
+	}
+
+	if ((aead_xform != NULL) &&
+		(mrvl_crypto_set_aead_session_parameters(
+			sess, aead_xform) < 0)) {
+		MRVL_CRYPTO_LOG_ERR("Invalid/unsupported aead parameters");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Process Operations
+ *-----------------------------------------------------------------------------
+ */
+
+/**
+ * Prepare a single request.
+ *
+ * This function basically translates DPDK crypto request into one
+ * understandable by MUDSK's SAM. If this is a first request in a session,
+ * it starts the session.
+ *
+ * @param request Pointer to pre-allocated && reset request buffer [Out].
+ * @param src_bd Pointer to pre-allocated source descriptor [Out].
+ * @param dst_bd Pointer to pre-allocated destination descriptor [Out].
+ * @param op Pointer to DPDK crypto operation struct [In].
+ */
+static inline int
+mrvl_request_prepare(struct sam_cio_op_params *request,
+		struct sam_buf_info *src_bd,
+		struct sam_buf_info *dst_bd,
+		struct rte_crypto_op *op)
+{
+	struct mrvl_crypto_session *sess;
+	struct rte_mbuf *dst_mbuf;
+	uint8_t *digest;
+
+	if (unlikely(op->sess_type == RTE_CRYPTO_OP_SESSIONLESS)) {
+		MRVL_CRYPTO_LOG_ERR("MRVL CRYPTO PMD only supports session "
+				"oriented requests, op (%p) is sessionless.",
+				op);
+		return -EINVAL;
+	}
+
+	sess = (struct mrvl_crypto_session *)get_session_private_data(
+			op->sym->session, cryptodev_driver_id);
+	if (unlikely(sess == NULL)) {
+		MRVL_CRYPTO_LOG_ERR("Session was not created for this device");
+		return -EINVAL;
+	}
+
+	/*
+	 * If application delivered us null dst buffer, it means it expects
+	 * us to deliver the result in src buffer.
+	 */
+	dst_mbuf = op->sym->m_dst ? op->sym->m_dst : op->sym->m_src;
+
+	request->sa = sess->sam_sess;
+	request->cookie = op;
+
+	/* Single buffers only, sorry. */
+	request->num_bufs = 1;
+	request->src = src_bd;
+	src_bd->vaddr = rte_pktmbuf_mtod(op->sym->m_src, void *);
+	src_bd->paddr = rte_pktmbuf_mtophys(op->sym->m_src);
+	src_bd->len = rte_pktmbuf_data_len(op->sym->m_src);
+
+	/* Empty source. */
+	if (rte_pktmbuf_data_len(op->sym->m_src) == 0) {
+		/* EIP does not support 0 length buffers. */
+		MRVL_CRYPTO_LOG_ERR("Buffer length == 0 not supported!");
+		return -1;
+	}
+
+	/* Empty destination. */
+	if (rte_pktmbuf_data_len(dst_mbuf) == 0) {
+		/* Make dst buffer fit at least source data. */
+		if (rte_pktmbuf_append(dst_mbuf,
+			rte_pktmbuf_data_len(op->sym->m_src)) == NULL) {
+			MRVL_CRYPTO_LOG_ERR("Unable to set big enough dst buffer!");
+			return -1;
+		}
+	}
+
+	request->dst = dst_bd;
+	dst_bd->vaddr = rte_pktmbuf_mtod(dst_mbuf, void *);
+	dst_bd->paddr = rte_pktmbuf_mtophys(dst_mbuf);
+
+	/*
+	 * We can use all available space in dst_mbuf,
+	 * not only what's used currently.
+	 */
+	dst_bd->len = dst_mbuf->buf_len - rte_pktmbuf_headroom(dst_mbuf);
+
+	if (sess->chain_order == MRVL_CRYPTO_CHAIN_COMBINED) {
+		request->cipher_len = op->sym->aead.data.length;
+		request->cipher_offset = op->sym->aead.data.offset;
+		request->cipher_iv = rte_crypto_op_ctod_offset(op, uint8_t *,
+			sess->cipher_iv_offset);
+
+		request->auth_aad = op->sym->aead.aad.data;
+		request->auth_offset = request->cipher_offset;
+		request->auth_len = request->cipher_len;
+	} else {
+		request->cipher_len = op->sym->cipher.data.length;
+		request->cipher_offset = op->sym->cipher.data.offset;
+		request->cipher_iv = rte_crypto_op_ctod_offset(op, uint8_t *,
+				sess->cipher_iv_offset);
+
+		request->auth_offset = op->sym->auth.data.offset;
+		request->auth_len = op->sym->auth.data.length;
+	}
+
+	digest = sess->chain_order == MRVL_CRYPTO_CHAIN_COMBINED ?
+		op->sym->aead.digest.data : op->sym->auth.digest.data;
+	if (digest == NULL) {
+		/* No auth - no worry. */
+		return 0;
+	}
+
+	request->auth_icv_offset = request->auth_offset + request->auth_len;
+
+	/*
+	 * EIP supports only scenarios where ICV(digest buffer) is placed at
+	 * auth_icv_offset. Any other placement means risking errors.
+	 */
+	if (sess->sam_sess_params.dir == SAM_DIR_ENCRYPT) {
+		/*
+		 * This should be the most common case anyway,
+		 * EIP will overwrite DST buffer at auth_icv_offset.
+		 */
+		if (rte_pktmbuf_mtod_offset(
+				dst_mbuf, uint8_t *,
+				request->auth_icv_offset) == digest) {
+			return 0;
+		}
+	} else {/* sess->sam_sess_params.dir == SAM_DIR_DECRYPT */
+		/*
+		 * EIP will look for digest at auth_icv_offset
+		 * offset in SRC buffer.
+		 */
+		if (rte_pktmbuf_mtod_offset(
+				op->sym->m_src, uint8_t *,
+				request->auth_icv_offset) == digest) {
+			return 0;
+		}
+	}
+
+	/*
+	 * If we landed here it means that digest pointer is
+	 * at different than expected place.
+	 */
+	return -1;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * PMD Framework handlers
+ *-----------------------------------------------------------------------------
+ */
+
+/**
+ * Enqueue burst.
+ *
+ * @param queue_pair Pointer to queue pair.
+ * @param ops Pointer to ops requests array.
+ * @param nb_ops Number of elements in ops requests array.
+ * @returns Number of elements consumed from ops.
+ */
+static uint16_t
+mrvl_crypto_pmd_enqueue_burst(void *queue_pair, struct rte_crypto_op **ops,
+		uint16_t nb_ops)
+{
+	uint16_t iter_ops = 0;
+	uint16_t to_enq = 0;
+	uint16_t consumed = 0;
+	int ret;
+	struct sam_cio_op_params requests[nb_ops];
+	/*
+	 * DPDK uses single fragment buffers, so we can KISS descriptors.
+	 * SAM does not store bd pointers, so on-stack scope will be enough.
+	 */
+	struct sam_buf_info src_bd[nb_ops];
+	struct sam_buf_info dst_bd[nb_ops];
+	struct mrvl_crypto_qp *qp = (struct mrvl_crypto_qp *)queue_pair;
+
+	if (nb_ops == 0)
+		return 0;
+
+	/* Prepare the burst. */
+	memset(&requests, 0, sizeof(requests));
+
+	/* Iterate through */
+	for (; iter_ops < nb_ops; ++iter_ops) {
+		if (mrvl_request_prepare(&requests[iter_ops],
+					&src_bd[iter_ops],
+					&dst_bd[iter_ops],
+					ops[iter_ops]) < 0) {
+			MRVL_CRYPTO_LOG_ERR(
+				"Error while parameters preparation!");
+			qp->stats.enqueue_err_count++;
+			ops[iter_ops]->status = RTE_CRYPTO_OP_STATUS_ERROR;
+
+			/*
+			 * Number of handled ops is increased
+			 * (even if the result of handling is error).
+			 */
+			++consumed;
+			break;
+		}
+
+		ops[iter_ops]->status =
+			RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
+
+		/* Increase the number of ops to enqueue. */
+		++to_enq;
+	} /* for (; iter_ops < nb_ops;... */
+
+	if (to_enq > 0) {
+		/* Send the burst */
+		ret = sam_cio_enq(qp->cio, requests, &to_enq);
+		consumed += to_enq;
+		if (ret < 0) {
+			/*
+			 * Trust SAM that in this case returned value will be at
+			 * some point correct (now it is returned unmodified).
+			 */
+			qp->stats.enqueue_err_count += to_enq;
+			for (iter_ops = 0; iter_ops < to_enq; ++iter_ops)
+				ops[iter_ops]->status =
+					RTE_CRYPTO_OP_STATUS_ERROR;
+		}
+	}
+
+	qp->stats.enqueued_count += to_enq;
+	return consumed;
+}
+
+/**
+ * Dequeue burst.
+ *
+ * @param queue_pair Pointer to queue pair.
+ * @param ops Pointer to ops requests array.
+ * @param nb_ops Number of elements in ops requests array.
+ * @returns Number of elements dequeued.
+ */
+static uint16_t
+mrvl_crypto_pmd_dequeue_burst(void *queue_pair,
+		struct rte_crypto_op **ops,
+		uint16_t nb_ops)
+{
+	int ret;
+	struct mrvl_crypto_qp *qp = queue_pair;
+	struct sam_cio *cio = qp->cio;
+	struct sam_cio_op_result results[nb_ops];
+	uint16_t i;
+
+	ret = sam_cio_deq(cio, results, &nb_ops);
+	if (ret < 0) {
+		/* Count all dequeued as error. */
+		qp->stats.dequeue_err_count += nb_ops;
+
+		/* But act as they were dequeued anyway*/
+		qp->stats.dequeued_count += nb_ops;
+
+		return 0;
+	}
+
+	/* Unpack and check results. */
+	for (i = 0; i < nb_ops; ++i) {
+		ops[i] = results[i].cookie;
+
+		switch (results[i].status) {
+		case SAM_CIO_OK:
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
+			break;
+		case SAM_CIO_ERR_ICV:
+			MRVL_CRYPTO_LOG_DBG("CIO returned SAM_CIO_ERR_ICV.");
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
+			break;
+		default:
+			MRVL_CRYPTO_LOG_DBG(
+				"CIO returned Error: %d", results[i].status);
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_ERROR;
+			break;
+		}
+	}
+
+	qp->stats.dequeued_count += nb_ops;
+	return nb_ops;
+}
+
+/**
+ * Create a new crypto device.
+ *
+ * @param name Driver name.
+ * @param vdev Pointer to device structure.
+ * @param init_params Pointer to initialization parameters.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+cryptodev_mrvl_crypto_create(const char *name,
+		struct rte_vdev_device *vdev,
+		struct rte_crypto_vdev_init_params *init_params)
+{
+	struct rte_cryptodev *dev;
+	struct mrvl_crypto_private *internals;
+	struct sam_init_params	sam_params;
+	int ret;
+
+	if (init_params->name[0] == '\0') {
+		ret = rte_cryptodev_pmd_create_dev_name(
+				init_params->name, name);
+
+		if (ret < 0) {
+			MRVL_CRYPTO_LOG_ERR("failed to create unique name");
+			return ret;
+		}
+	}
+
+	dev = rte_cryptodev_vdev_pmd_init(init_params->name,
+				sizeof(struct mrvl_crypto_private),
+				init_params->socket_id, vdev);
+	if (dev == NULL) {
+		MRVL_CRYPTO_LOG_ERR("failed to create cryptodev vdev");
+		goto init_error;
+	}
+
+	dev->driver_id = cryptodev_driver_id;
+	dev->dev_ops = rte_mrvl_crypto_pmd_ops;
+
+	/* Register rx/tx burst functions for data path. */
+	dev->enqueue_burst = mrvl_crypto_pmd_enqueue_burst;
+	dev->dequeue_burst = mrvl_crypto_pmd_dequeue_burst;
+
+	dev->feature_flags = RTE_CRYPTODEV_FF_SYMMETRIC_CRYPTO |
+			RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING |
+			RTE_CRYPTODEV_FF_HW_ACCELERATED;
+
+	/* Set vector instructions mode supported */
+	internals = dev->data->dev_private;
+
+	internals->max_nb_qpairs = init_params->max_nb_queue_pairs;
+	internals->max_nb_sessions = init_params->max_nb_sessions;
+
+	/*
+	 * ret == -EEXIST is correct, it means DMA
+	 * has been already initialized.
+	 */
+	ret = mv_sys_dma_mem_init(RTE_MRVL_MUSDK_DMA_MEMSIZE);
+	if ((ret < 0) && (ret != -EEXIST))
+		return ret;
+
+	sam_params.max_num_sessions = internals->max_nb_sessions;
+
+	return sam_init(&sam_params);
+
+init_error:
+	MRVL_CRYPTO_LOG_ERR(
+		"driver %s: %s failed", init_params->name, __func__);
+
+	cryptodev_mrvl_crypto_uninit(vdev);
+	return -EFAULT;
+}
+
+/**
+ * Initialize the crypto device.
+ *
+ * @param vdev Pointer to device structure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+cryptodev_mrvl_crypto_init(struct rte_vdev_device *vdev)
+{
+	struct rte_crypto_vdev_init_params init_params = { };
+	const char *name;
+	const char *input_args;
+	int ret;
+
+	name = rte_vdev_device_name(vdev);
+	if (name == NULL)
+		return -EINVAL;
+	input_args = rte_vdev_device_args(vdev);
+
+	if (!input_args)
+		return -EINVAL;
+
+	init_params.max_nb_queue_pairs = sam_get_num_inst() * SAM_HW_RING_NUM;
+	init_params.max_nb_sessions =
+		RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_SESSIONS;
+	init_params.socket_id = rte_socket_id();
+
+	ret = rte_cryptodev_vdev_parse_init_params(&init_params, input_args);
+	if (ret) {
+		RTE_LOG(ERR, PMD, "Failed to parse input arguments\n");
+		return ret;
+	}
+
+	RTE_LOG(INFO, PMD, "Initialising %s on NUMA node %d\n", name,
+			init_params.socket_id);
+	if (init_params.name[0] != '\0') {
+		RTE_LOG(INFO, PMD, "  User defined name = %s\n",
+			init_params.name);
+	}
+	RTE_LOG(INFO, PMD, "  Max number of queue pairs = %d\n",
+			init_params.max_nb_queue_pairs);
+	RTE_LOG(INFO, PMD, "  Max number of sessions = %d\n",
+			init_params.max_nb_sessions);
+
+	return cryptodev_mrvl_crypto_create(name, vdev, &init_params);
+}
+
+/**
+ * Uninitialize the crypto device
+ *
+ * @param vdev Pointer to device structure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+cryptodev_mrvl_crypto_uninit(struct rte_vdev_device *vdev)
+{
+	const char *name = rte_vdev_device_name(vdev);
+
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD,
+		"Closing Marvell crypto device %s on numa socket %u\n",
+		name, rte_socket_id());
+
+	sam_deinit();
+
+	return 0;
+}
+
+/**
+ * Basic driver handlers for use in the constructor.
+ */
+static struct rte_vdev_driver cryptodev_mrvl_pmd_drv = {
+	.probe = cryptodev_mrvl_crypto_init,
+	.remove = cryptodev_mrvl_crypto_uninit
+};
+
+/* Register the driver in constructor. */
+RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_MRVL_PMD, cryptodev_mrvl_pmd_drv);
+RTE_PMD_REGISTER_ALIAS(CRYPTODEV_NAME_MRVL_PMD, cryptodev_mrvl_pmd);
+RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_MRVL_PMD,
+	"max_nb_queue_pairs=<int> "
+	"max_nb_sessions=<int> "
+	"socket_id=<int>");
+RTE_PMD_REGISTER_CRYPTO_DRIVER(cryptodev_mrvl_pmd_drv, cryptodev_driver_id);
diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd_ops.c b/drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
new file mode 100644
index 0000000..f7374f8
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
@@ -0,0 +1,787 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) Semihalf 2017. 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 Semihalf 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 <string.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_cryptodev_pmd.h>
+
+#include "rte_mrvl_pmd_private.h"
+
+/**
+ * Capabilities list to be used in reporting to DPDK.
+ */
+static const struct rte_cryptodev_capabilities
+	mrvl_crypto_pmd_capabilities[] = {
+	{	/* MD5 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_MD5_HMAC,
+				.block_size = 64,
+				.key_size = {
+					.min = 64,
+					.max = 64,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.aad_size = { 0 }
+			}, }
+		}, }
+	},
+	{	/* MD5 */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+				{.auth = {
+					.algo = RTE_CRYPTO_AUTH_MD5,
+					.block_size = 64,
+					.key_size = {
+						.min = 0,
+						.max = 0,
+						.increment = 0
+					},
+					.digest_size = {
+						.min = 16,
+						.max = 16,
+						.increment = 0
+					},
+					.aad_size = { 0 }
+				}, }
+			}, }
+	},
+	{	/* SHA1 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+				{.auth = {
+					.algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+					.block_size = 64,
+					.key_size = {
+						.min = 16,
+						.max = 128,
+						.increment = 0
+					},
+					.digest_size = {
+						.min = 20,
+						.max = 20,
+						.increment = 0
+					},
+					.aad_size = { 0 }
+				}, }
+			}, }
+	},
+	{	/* SHA1 */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA1,
+				.block_size = 64,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 20,
+					.max = 20,
+					.increment = 0
+				},
+				.aad_size = { 0 }
+			}, }
+		}, }
+	},
+	{	/* SHA224 */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA224,
+				.block_size = 64,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 28,
+					.max = 28,
+					.increment = 0
+				},
+				.aad_size = { 0 }
+			}, }
+		}, }
+	},
+	{	/* SHA256 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+				{.auth = {
+					.algo = RTE_CRYPTO_AUTH_SHA256_HMAC,
+					.block_size = 64,
+					.key_size = {
+						.min = 1,
+						.max = 128,
+						.increment = 0
+					},
+					.digest_size = {
+						.min = 32,
+						.max = 32,
+						.increment = 0
+					},
+					.aad_size = { 0 }
+				}, }
+			}, }
+	},
+	{	/* SHA256 */
+			.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+				{.auth = {
+					.algo = RTE_CRYPTO_AUTH_SHA256,
+					.block_size = 64,
+					.key_size = {
+						.min = 0,
+						.max = 0,
+						.increment = 0
+					},
+					.digest_size = {
+						.min = 32,
+						.max = 32,
+						.increment = 0
+					},
+					.aad_size = { 0 }
+				}, }
+			}, }
+		},
+	{	/* SHA384 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA384_HMAC,
+				.block_size = 128,
+				.key_size = {
+					.min = 128,
+					.max = 128,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 48,
+					.max = 48,
+					.increment = 0
+				},
+				.aad_size = { 0 }
+			}, }
+		}, }
+	},
+	{	/* SHA384 */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA384,
+				.block_size = 128,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 48,
+					.max = 48,
+					.increment = 0
+				},
+				.aad_size = { 0 }
+			}, }
+		}, }
+	},
+	{	/* SHA512 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA512_HMAC,
+				.block_size = 128,
+				.key_size = {
+					.min = 128,
+					.max = 128,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 64,
+					.max = 64,
+					.increment = 0
+				},
+				.aad_size = { 0 }
+			}, }
+		}, }
+	},
+	{	/* SHA512  */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA512,
+				.block_size = 128,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 64,
+					.max = 64,
+					.increment = 0
+				},
+				.aad_size = { 0 }
+			}, }
+		}, }
+	},
+	{	/* AES CBC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+				{.cipher = {
+					.algo = RTE_CRYPTO_CIPHER_AES_CBC,
+					.block_size = 16,
+					.key_size = {
+						.min = 16,
+						.max = 32,
+						.increment = 8
+					},
+					.iv_size = {
+						.min = 16,
+						.max = 16,
+						.increment = 0
+					}
+				}, }
+			}, }
+	},
+	{	/* AES CTR */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_AES_CTR,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 32,
+					.increment = 8
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* AES GCM */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AEAD,
+			{.aead = {
+				.algo = RTE_CRYPTO_AEAD_AES_GCM,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 32,
+					.increment = 8
+				},
+				.digest_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.aad_size = {
+					.min = 8,
+					.max = 12,
+					.increment = 4
+				},
+				.iv_size = {
+					.min = 12,
+					.max = 16,
+					.increment = 4
+				}
+			}, }
+		}, }
+	},
+	{	/* AES GMAC (AUTH) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_AES_GMAC,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 32,
+					.increment = 8
+				},
+				.digest_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 8,
+					.max = 65532,
+					.increment = 4
+				}
+			}, }
+		}, }
+	},
+	{	/* 3DES CBC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_3DES_CBC,
+				.block_size = 8,
+				.key_size = {
+					.min = 24,
+					.max = 24,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 8,
+					.max = 8,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* 3DES CTR */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_3DES_CTR,
+				.block_size = 8,
+				.key_size = {
+					.min = 24,
+					.max = 24,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 8,
+					.max = 8,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+
+	RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
+};
+
+
+/**
+ * Configure device (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param config Pointer to configuration structure.
+ * @returns 0. Always.
+ */
+static int
+mrvl_crypto_pmd_config(__rte_unused struct rte_cryptodev *dev,
+		__rte_unused struct rte_cryptodev_config *config)
+{
+	return 0;
+}
+
+/**
+ * Start device (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @returns 0. Always.
+ */
+static int
+mrvl_crypto_pmd_start(__rte_unused struct rte_cryptodev *dev)
+{
+	return 0;
+}
+
+/**
+ * Stop device (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @returns 0. Always.
+ */
+static void
+mrvl_crypto_pmd_stop(__rte_unused struct rte_cryptodev *dev)
+{
+}
+
+/**
+ * Get device statistics (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param stats Pointer to statistics structure [out].
+ */
+static void
+mrvl_crypto_pmd_stats_get(struct rte_cryptodev *dev,
+		struct rte_cryptodev_stats *stats)
+{
+	int qp_id;
+
+	for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++) {
+		struct mrvl_crypto_qp *qp = dev->data->queue_pairs[qp_id];
+
+		stats->enqueued_count += qp->stats.enqueued_count;
+		stats->dequeued_count += qp->stats.dequeued_count;
+
+		stats->enqueue_err_count += qp->stats.enqueue_err_count;
+		stats->dequeue_err_count += qp->stats.dequeue_err_count;
+	}
+}
+
+/**
+ * Reset device statistics (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ */
+static void
+mrvl_crypto_pmd_stats_reset(struct rte_cryptodev *dev)
+{
+	int qp_id;
+
+	for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++) {
+		struct mrvl_crypto_qp *qp = dev->data->queue_pairs[qp_id];
+
+		memset(&qp->stats, 0, sizeof(qp->stats));
+	}
+}
+
+/**
+ * Get device info (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param dev_info Pointer to the device info structure [out].
+ */
+static void
+mrvl_crypto_pmd_info_get(struct rte_cryptodev *dev,
+		struct rte_cryptodev_info *dev_info)
+{
+	struct mrvl_crypto_private *internals = dev->data->dev_private;
+
+	if (dev_info != NULL) {
+		dev_info->driver_id = dev->driver_id;
+		dev_info->feature_flags = dev->feature_flags;
+		dev_info->capabilities = mrvl_crypto_pmd_capabilities;
+		dev_info->max_nb_queue_pairs = internals->max_nb_qpairs;
+		dev_info->sym.max_nb_sessions = internals->max_nb_sessions;
+	}
+}
+
+/**
+ * Release queue pair (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param qp_id ID of Queue Pair to release.
+ * @returns 0. Always.
+ */
+static int
+mrvl_crypto_pmd_qp_release(struct rte_cryptodev *dev, uint16_t qp_id)
+{
+	struct mrvl_crypto_qp *qp =
+			(struct mrvl_crypto_qp *)dev->data->queue_pairs[qp_id];
+
+	if (dev->data->queue_pairs[qp_id] != NULL) {
+		sam_cio_flush(qp->cio);
+		sam_cio_deinit(qp->cio);
+		rte_free(dev->data->queue_pairs[qp_id]);
+		dev->data->queue_pairs[qp_id] = NULL;
+	}
+
+	return 0;
+}
+
+/**
+ * Close device (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @returns 0. Always.
+ */
+static int
+mrvl_crypto_pmd_close(struct rte_cryptodev *dev)
+{
+	int qp_id;
+
+	for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++)
+		mrvl_crypto_pmd_qp_release(dev, qp_id);
+
+	return 0;
+}
+
+/**
+ * Setup a queue pair (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param qp_id ID of the Queue Pair.
+ * @param qp_conf Queue pair configuration (nb of descriptors).
+ * @param socket_id NUMA socket to allocate memory on.
+ * @returns 0 upon success, negative value otherwise.
+ */
+static int
+mrvl_crypto_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
+		const struct rte_cryptodev_qp_conf *qp_conf,
+		int socket_id, struct rte_mempool *session_pool)
+{
+	struct mrvl_crypto_qp *qp = NULL;
+	char match[RTE_CRYPTODEV_NAME_LEN];
+	unsigned int n;
+
+	/* Allocate the queue pair data structure. */
+	qp = rte_zmalloc_socket("MRVL Crypto PMD Queue Pair", sizeof(*qp),
+					RTE_CACHE_LINE_SIZE, socket_id);
+	if (qp == NULL)
+		return -ENOMEM;
+
+	/* Free old qp prior setup if needed. */
+	if (dev->data->queue_pairs[qp_id] != NULL)
+		mrvl_crypto_pmd_qp_release(dev, qp_id);
+
+	do { /* Error handling block */
+
+		/*
+		 * This extra check is necessary due to a bug in
+		 * crypto library.
+		 */
+		int num = sam_get_num_inst();
+		if (num == 0) {
+			MRVL_CRYPTO_LOG_ERR("No crypto engines detected.\n");
+			return -1;
+		}
+
+		/*
+		 * In case two crypto engines are enabled qps will
+		 * be evenly spread among them. Even and odd qps will
+		 * be handled by cio-0 and cio-1 respectively. qp-cio mapping
+		 * will look as follows:
+		 *
+		 * qp:      0        1        2        3
+		 * cio-x:y: cio-0:0, cio-1:0, cio-0:1, cio-1:1
+		 *
+		 * qp:      4        5        6        7
+		 * cio-x:y: cio-0:2, cio-1:2, cio-0:3, cio-1:3
+		 *
+		 * In case just one engine is enabled mapping will look as
+		 * follows:
+		 * qp:      0        1        2        3
+		 * cio-x:y: cio-0:0, cio-0:1, cio-0:2, cio-0:3
+		 */
+		n = snprintf(match, sizeof(match), "cio-%u:%u",
+				qp_id % num, qp_id / num);
+
+		if (n >= sizeof(match))
+			break;
+
+		qp->cio_params.match = match;
+		qp->cio_params.size = qp_conf->nb_descriptors;
+
+		if (sam_cio_init(&qp->cio_params, &qp->cio) < 0)
+			break;
+
+		qp->sess_mp = session_pool;
+
+		memset(&qp->stats, 0, sizeof(qp->stats));
+		dev->data->queue_pairs[qp_id] = qp;
+		return 0;
+	} while (0);
+
+	rte_free(qp);
+	return -1;
+}
+
+/** Start queue pair (PMD ops callback) - not supported.
+ *
+ * @param dev Pointer to the device structure.
+ * @param qp_id ID of the Queue Pair.
+ * @returns -ENOTSUP. Always.
+ */
+static int
+mrvl_crypto_pmd_qp_start(__rte_unused struct rte_cryptodev *dev,
+		__rte_unused uint16_t queue_pair_id)
+{
+	return -ENOTSUP;
+}
+
+/** Stop queue pair (PMD ops callback) - not supported.
+ *
+ * @param dev Pointer to the device structure.
+ * @param qp_id ID of the Queue Pair.
+ * @returns -ENOTSUP. Always.
+ */
+static int
+mrvl_crypto_pmd_qp_stop(__rte_unused struct rte_cryptodev *dev,
+		__rte_unused uint16_t queue_pair_id)
+{
+	return -ENOTSUP;
+}
+
+/** Return the number of allocated queue pairs (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @returns Number of allocated queue pairs.
+ */
+static uint32_t
+mrvl_crypto_pmd_qp_count(struct rte_cryptodev *dev)
+{
+	return dev->data->nb_queue_pairs;
+}
+
+/** Returns the size of the session structure (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure [Unused].
+ * @returns Size of Marvell crypto session.
+ */
+static unsigned
+mrvl_crypto_pmd_session_get_size(__rte_unused struct rte_cryptodev *dev)
+{
+	return sizeof(struct mrvl_crypto_session);
+}
+
+/** Configure the session from a crypto xform chain (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param xform Pointer to the crytpo configuration structure.
+ * @param sess Pointer to the empty session structure.
+ * @returns 0 upon success, negative value otherwise.
+ */
+static int
+mrvl_crypto_pmd_session_configure(__rte_unused struct rte_cryptodev *dev,
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mp)
+{
+	struct mrvl_crypto_session *mrvl_sess;
+	void *sess_private_data;
+	int ret;
+
+	if (sess == NULL) {
+		MRVL_CRYPTO_LOG_ERR("Invalid session struct.");
+		return -EINVAL;
+	}
+
+	if (rte_mempool_get(mp, &sess_private_data)) {
+		CDEV_LOG_ERR("Couldn't get object from session mempool.");
+		return -ENOMEM;
+	}
+
+	ret = mrvl_crypto_set_session_parameters(sess_private_data, xform);
+	if (ret != 0) {
+		MRVL_CRYPTO_LOG_ERR("Failed to configure session parameters.");
+
+		/* Return session to mempool */
+		rte_mempool_put(mp, sess_private_data);
+		return ret;
+	}
+
+	set_session_private_data(sess, dev->driver_id, sess_private_data);
+
+	mrvl_sess = (struct mrvl_crypto_session *)sess_private_data;
+	if (sam_session_create(&mrvl_sess->sam_sess_params,
+				&mrvl_sess->sam_sess) < 0) {
+		MRVL_CRYPTO_LOG_DBG("Failed to create session!");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ * Clear the memory of session so it doesn't leave key material behind.
+ *
+ * @param dev Pointer to the device structure.
+ * @returns 0. Always.
+ */
+static void
+mrvl_crypto_pmd_session_clear(struct rte_cryptodev *dev,
+		struct rte_cryptodev_sym_session *sess)
+{
+
+	uint8_t index = dev->driver_id;
+	void *sess_priv = get_session_private_data(sess, index);
+
+	/* Zero out the whole structure */
+	if (sess_priv) {
+		struct mrvl_crypto_session *mrvl_sess =
+			(struct mrvl_crypto_session *)sess_priv;
+
+		if (mrvl_sess->sam_sess &&
+		    sam_session_destroy(mrvl_sess->sam_sess) < 0) {
+			MRVL_CRYPTO_LOG_INFO("Error while destroying session!");
+		}
+
+		memset(sess, 0, sizeof(struct mrvl_crypto_session));
+		struct rte_mempool *sess_mp = rte_mempool_from_obj(sess_priv);
+		set_session_private_data(sess, index, NULL);
+		rte_mempool_put(sess_mp, sess_priv);
+	}
+}
+
+/**
+ * PMD handlers for crypto ops.
+ */
+static struct rte_cryptodev_ops mrvl_crypto_pmd_ops = {
+		.dev_configure		= mrvl_crypto_pmd_config,
+		.dev_start		= mrvl_crypto_pmd_start,
+		.dev_stop		= mrvl_crypto_pmd_stop,
+		.dev_close		= mrvl_crypto_pmd_close,
+
+		.dev_infos_get		= mrvl_crypto_pmd_info_get,
+
+		.stats_get		= mrvl_crypto_pmd_stats_get,
+		.stats_reset		= mrvl_crypto_pmd_stats_reset,
+
+		.queue_pair_setup	= mrvl_crypto_pmd_qp_setup,
+		.queue_pair_release	= mrvl_crypto_pmd_qp_release,
+		.queue_pair_start	= mrvl_crypto_pmd_qp_start,
+		.queue_pair_stop	= mrvl_crypto_pmd_qp_stop,
+		.queue_pair_count	= mrvl_crypto_pmd_qp_count,
+
+		.session_get_size	= mrvl_crypto_pmd_session_get_size,
+		.session_configure	= mrvl_crypto_pmd_session_configure,
+		.session_clear		= mrvl_crypto_pmd_session_clear
+};
+
+struct rte_cryptodev_ops *rte_mrvl_crypto_pmd_ops = &mrvl_crypto_pmd_ops;
diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd_private.h b/drivers/crypto/mrvl/rte_mrvl_pmd_private.h
new file mode 100644
index 0000000..2da14b8
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_mrvl_pmd_private.h
@@ -0,0 +1,121 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) Semihalf 2017. 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 Semihalf 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_MRVL_PMD_PRIVATE_H_
+#define _RTE_MRVL_PMD_PRIVATE_H_
+
+#include "rte_mrvl_compat.h"
+
+#define CRYPTODEV_NAME_MRVL_PMD crypto_mrvl
+/**< Marvell PMD device name */
+
+#define MRVL_CRYPTO_LOG_ERR(fmt, args...) \
+	RTE_LOG(ERR, CRYPTODEV, "[%s] %s() line %u: " fmt "\n",  \
+			RTE_STR(CRYPTODEV_NAME_MRVL_CRYPTO_PMD), \
+			__func__, __LINE__, ## args)
+
+#ifdef RTE_LIBRTE_MRVL_CRYPTO_DEBUG
+#define MRVL_CRYPTO_LOG_INFO(fmt, args...) \
+	RTE_LOG(INFO, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+			RTE_STR(CRYPTODEV_NAME_MRVL_CRYPTO_PMD), \
+			__func__, __LINE__, ## args)
+
+#define MRVL_CRYPTO_LOG_DBG(fmt, args...) \
+	RTE_LOG(DEBUG, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+			RTE_STR(CRYPTODEV_NAME_MRVL_CRYPTO_PMD), \
+			__func__, __LINE__, ## args)
+
+#else
+#define MRVL_CRYPTO_LOG_INFO(fmt, args...)
+#define MRVL_CRYPTO_LOG_DBG(fmt, args...)
+#endif
+
+/**
+ * Handy bits->bytes conversion macro.
+ */
+#define BITS2BYTES(x) ((x) >> 3)
+
+/** The operation order mode enumerator. */
+enum mrvl_crypto_chain_order {
+	MRVL_CRYPTO_CHAIN_CIPHER_ONLY,
+	MRVL_CRYPTO_CHAIN_AUTH_ONLY,
+	MRVL_CRYPTO_CHAIN_CIPHER_AUTH,
+	MRVL_CRYPTO_CHAIN_AUTH_CIPHER,
+	MRVL_CRYPTO_CHAIN_COMBINED,
+	MRVL_CRYPTO_CHAIN_NOT_SUPPORTED,
+};
+
+/** Private data structure for each crypto device. */
+struct mrvl_crypto_private {
+	unsigned int max_nb_qpairs;	/**< Max number of queue pairs */
+	unsigned int max_nb_sessions;	/**< Max number of sessions */
+};
+
+/** MRVL crypto queue pair structure. */
+struct mrvl_crypto_qp {
+	/** SAM CIO (MUSDK Queue Pair equivalent).*/
+	struct sam_cio *cio;
+
+	/** Session Mempool. */
+	struct rte_mempool *sess_mp;
+
+	/** Queue pair statistics. */
+	struct rte_cryptodev_stats stats;
+
+	/** CIO initialization parameters.*/
+	struct sam_cio_params cio_params;
+} __rte_cache_aligned;
+
+/** MRVL crypto private session structure. */
+struct mrvl_crypto_session {
+	/** Crypto operations chain order. */
+	enum mrvl_crypto_chain_order chain_order;
+
+	/** Session initialization parameters. */
+	struct sam_session_params sam_sess_params;
+
+	/** SAM session pointer. */
+	struct sam_sa *sam_sess;
+
+	/** Cipher IV offset. */
+	uint16_t cipher_iv_offset;
+} __rte_cache_aligned;
+
+/** Set and validate MRVL crypto session parameters */
+extern int
+mrvl_crypto_set_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *xform);
+
+/** device specific operations function pointer structure */
+extern struct rte_cryptodev_ops *rte_mrvl_crypto_pmd_ops;
+
+#endif /* _RTE_MRVL_PMD_PRIVATE_H_ */
diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd_version.map b/drivers/crypto/mrvl/rte_mrvl_pmd_version.map
new file mode 100644
index 0000000..a753031
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_mrvl_pmd_version.map
@@ -0,0 +1,3 @@
+DPDK_17.11 {
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 8df74bb..0f121ee 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -163,6 +163,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_ZUC)         += -lrte_pmd_zuc
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_ZUC)         += -L$(LIBSSO_ZUC_PATH)/build -lsso_zuc
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO)    += -lrte_pmd_armv8
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO)    += -L$(ARMV8_CRYPTO_LIB_PATH) -larmv8_crypto
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO) += -L$(LIBMUSDK_PATH)/lib -lrte_pmd_mrvl_crypto -lmusdk
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER) += -lrte_pmd_crypto_scheduler
 ifeq ($(CONFIG_RTE_LIBRTE_FSLMC_BUS),y)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_SEC)   += -lrte_pmd_dpaa2_sec
-- 
2.7.4

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

* [PATCH 6/8] doc: add mrvl crypto pmd documentation
  2017-09-26  9:39 [PATCH 0/8] add net/crypto mrvl pmd drivers Tomasz Duszynski
                   ` (4 preceding siblings ...)
  2017-09-26  9:40 ` [PATCH 5/8] crypto/mrvl: add mrvl crypto pmd driver Tomasz Duszynski
@ 2017-09-26  9:40 ` Tomasz Duszynski
  2017-09-26  9:40 ` [PATCH 7/8] maintainers: add maintainers for the mrvl crypto pmd Tomasz Duszynski
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-26  9:40 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Tomasz Duszynski, Jacek Siuda

Add documentation for the MRVL CRYPTO PMD driver.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <jck@semihalf.com>
---
 doc/guides/cryptodevs/features/mrvl.ini |  42 +++++++
 doc/guides/cryptodevs/index.rst         |   1 +
 doc/guides/cryptodevs/mrvl.rst          | 198 ++++++++++++++++++++++++++++++++
 3 files changed, 241 insertions(+)
 create mode 100644 doc/guides/cryptodevs/features/mrvl.ini
 create mode 100644 doc/guides/cryptodevs/mrvl.rst

diff --git a/doc/guides/cryptodevs/features/mrvl.ini b/doc/guides/cryptodevs/features/mrvl.ini
new file mode 100644
index 0000000..6d2fe6a
--- /dev/null
+++ b/doc/guides/cryptodevs/features/mrvl.ini
@@ -0,0 +1,42 @@
+; Supported features of the 'mrvl' crypto driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Symmetric crypto       = Y
+Sym operation chaining = Y
+
+;
+; Supported crypto algorithms of a default crypto driver.
+;
+[Cipher]
+AES CBC (128)  = Y
+AES CBC (192)  = Y
+AES CBC (256)  = Y
+AES CTR (128)  = Y
+AES CTR (192)  = Y
+AES CTR (256)  = Y
+3DES CBC       = Y
+3DES CTR       = Y
+
+;
+; Supported authentication algorithms of a default crypto driver.
+;
+[Auth]
+MD5          = Y
+MD5 HMAC     = Y
+SHA1         = Y
+SHA1 HMAC    = Y
+SHA256       = Y
+SHA256 HMAC  = Y
+SHA384       = Y
+SHA384 HMAC  = Y
+SHA512       = Y
+SHA512 HMAC  = Y
+AES GMAC     = Y
+
+;
+; Supported AEAD algorithms of a default crypto driver.
+;
+[AEAD]
+AES GCM (128) = Y
diff --git a/doc/guides/cryptodevs/index.rst b/doc/guides/cryptodevs/index.rst
index 361b82d..a8ee0eb 100644
--- a/doc/guides/cryptodevs/index.rst
+++ b/doc/guides/cryptodevs/index.rst
@@ -42,6 +42,7 @@ Crypto Device Drivers
     dpaa2_sec
     kasumi
     openssl
+    mrvl
     null
     scheduler
     snow3g
diff --git a/doc/guides/cryptodevs/mrvl.rst b/doc/guides/cryptodevs/mrvl.rst
new file mode 100644
index 0000000..f5a83dc
--- /dev/null
+++ b/doc/guides/cryptodevs/mrvl.rst
@@ -0,0 +1,198 @@
+..  BSD LICENSE
+    Copyright(c) 2017 Semihalf. All rights reserved.
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in
+        the documentation and/or other materials provided with the
+        distribution.
+      * Neither the name of Semihalf 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.
+
+MRVL Crypto Poll Mode Driver
+============================
+
+The MRVL CRYPTO PMD (**librte_crypto_mrvl_pmd**) provides poll mode crypto driver
+support by utilizing MUSDK library, which provides cryptographic operations
+acceleration by using Security Acceleration Engine (EIP197) directly from
+user-space with minimum overhead and high performance.
+
+Features
+--------
+
+MRVL CRYPTO PMD has support for:
+
+* Symmetric crypto
+* Sym operation chaining
+* AES CBC (128)
+* AES CBC (192)
+* AES CBC (256)
+* AES CTR (128)
+* AES CTR (192)
+* AES CTR (256)
+* 3DES CBC
+* 3DES CTR
+* MD5
+* MD5 HMAC
+* SHA1
+* SHA1 HMAC
+* SHA256
+* SHA256 HMAC
+* SHA384
+* SHA384 HMAC
+* SHA512
+* SHA512 HMAC
+* AES GCM (128)
+
+Limitations
+-----------
+
+* Hardware only supports scenarios where ICV (digest buffer) is placed just
+  after the authenticated data. Other placement will result in error.
+
+Installation
+------------
+
+MRVL CRYPTO PMD driver compilation is disabled by default due to external dependencies.
+Currently there are two driver specific compilation options in
+``config/common_base`` available:
+
+- ``CONFIG_RTE_LIBRTE_MRVL_CRYPTO`` (default ``n``)
+
+    Toggle compilation of the librte_pmd_mrvl driver.
+
+- ``CONFIG_RTE_LIBRTE_MRVL_CRYPTO_DEBUG`` (default ``n``)
+
+    Toggle display of debugging messages.
+
+During compilation external MUSDK library, which provides direct access
+to Marvell's EIP197 cryptographic engine, is necessary. Library sources are
+available `here <https://github.com/MarvellEmbeddedProcessors/musdk-marvell/tree/musdk-armada-17.08>`_.
+
+Alternatively, prebuilt library can be downloaded from
+`Marvell Extranet <https://extranet.marvell.com>`_. Once approval has been
+granted, library can be found by typing ``musdk`` in the search box.
+
+For MUSDK library build instruction please refer to ``doc/musdk_get_started.txt``
+in library sources directory.
+
+Initialization
+--------------
+
+After successfully building MRVL CRYPTO PMD, the following modules need to be
+loaded:
+
+.. code-block:: console
+
+   insmod musdk_uio.ko
+   insmod mvpp2x_sysfs.ko
+   insmod mv_pp_uio.ko
+   insmod mv_sam_uio.ko
+   insmod crypto_safexcel.ko
+
+The following parameters (all optional) are exported by the driver:
+
+* max_nb_queue_pairs: maximum number of queue pairs in the device (8 by default).
+* max_nb_sessions: maximum number of sessions that can be created (2048 by default).
+* socket_id: socket on which to allocate the device resources on.
+
+l2fwd-crypto example application can be used to verify MRVL CRYPTO PMD
+operation:
+
+.. code-block:: console
+
+   ./l2fwd-crypto -c 0x3 --vdev=eth_mrvl,iface=eth0 --vdev=cryptodev_mrvl_pmd
+
+Example output:
+
+.. code-block:: console
+
+   [...]
+   PMD:   Max number of queue pairs = 8
+   PMD:   Max number of sessions = 2048
+   [ERROR] Dma object already exits.
+   [INFO] DMA buffers allocated for 2048 sessions (256 bytes)
+   Initializing port 0... [ERROR] [pp2_ppio_flush_vlan] routine not supported yet!
+   PMD: Failed to flush vlan list
+   [INFO] PORT: Port0 - link is up
+   [INFO] ---- GOP ID 0 configuration ----
+   [INFO] Port mode               : KR
+   [INFO] MAC status              : disabled
+   [INFO] Link status             : link up
+   [INFO] Port speed              : 10G
+   [INFO] Port duplex             : full
+   [INFO] Port: Egress enable tx_port_num=16 qmap=0x1
+   [INFO] PORT: Port0 - link is up
+   [INFO] ---- GOP ID 0 configuration ----
+   [INFO] Port mode               : KR
+   [INFO] MAC status              : disabled
+   [INFO] Link status             : link up
+   [INFO] Port speed              : 10G
+   [INFO] Port duplex             : full
+   [INFO] Port: Egress enable tx_port_num=16 qmap=0x1
+   [INFO] PORT: Port0 - link is down
+   [INFO] ---- GOP ID 0 configuration ----
+   [INFO] Port mode               : KR
+   [INFO] MAC status              : disabled
+   [INFO] Link status             : link down
+   [INFO] Port speed              : 10G
+   [INFO] Port duplex             : full
+   [INFO] Port: Egress enable tx_port_num=16 qmap=0x1
+   Port 0, MAC address: 00:50:43:02:21:20
+
+
+   Checking link statusdone
+   Port 0 Link Up - speed 0 Mbps - full-duplex
+   Lcore 0: RX port 0
+   [INFO] eip197: 0:0 registers: paddr: 0xf2880000, vaddr: 0x0x7f25480000
+   [INFO] DMA buffer (16448 bytes) for CDR #0 allocated: paddr = 0xb0525e00, \
+   vaddr = 0x7f21b24e00
+   [INFO] DMA buffer (16448 bytes) for RDR #0 allocated: paddr = 0xb0529f00, \
+   vaddr = 0x7f21b28f00
+   [INFO] DMA buffers allocated for 257 operations. Tokens - 256 bytes
+   Lcore 0: cryptodev 0
+   L2FWD: lcore 1 has nothing to do
+   L2FWD: entering main loop on lcore 0
+   L2FWD:  -- lcoreid=0 portid=0
+   L2FWD:  -- lcoreid=0 cryptoid=0
+   Options:-
+   nportmask: ffffffff
+   ports per lcore: 1
+   refresh period : 10000
+   single lcore mode: disabled
+   stats_printing: enabled
+   sessionless crypto: disabled
+
+   Crypto chain: Input --> Encrypt --> Auth generate --> Output
+
+   ---- Cipher information ---
+   Algorithm: aes-cbc
+   Cipher key: at [0x7f253cee80], len=16
+   00000000: C2 B1 90 57 16 32 A8 56 5A 16 CD A5 D1 24 64 C3 | ...W.2.VZ....$d.
+   IV: at [0x7f253cec80], len=16
+   00000000: F7 98 65 93 94 22 2C 8F A6 3C F1 F2 7C 88 FF 5D | ..e..",..<..|..]
+
+   ---- Authentication information ---
+   Algorithm: sha1-hmac
+   Auth key: at [0x7f253ced80], len=16
+   00000000: 8B 32 09 22 BF A7 AA 0D 0C 65 A3 2E 64 6E 74 44 | .2.".....e..dntD
+   AAD: at [0x7f253ceb80], len=
-- 
2.7.4

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

* [PATCH 7/8] maintainers: add maintainers for the mrvl crypto pmd
  2017-09-26  9:39 [PATCH 0/8] add net/crypto mrvl pmd drivers Tomasz Duszynski
                   ` (5 preceding siblings ...)
  2017-09-26  9:40 ` [PATCH 6/8] doc: add mrvl crypto pmd documentation Tomasz Duszynski
@ 2017-09-26  9:40 ` Tomasz Duszynski
  2017-09-26  9:40 ` [PATCH 8/8] test: add mrvl crypto pmd unit tests Tomasz Duszynski
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-26  9:40 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Tomasz Duszynski, Jacek Siuda

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 MAINTAINERS | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index d4810cf..93800d2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -561,6 +561,16 @@ F: drivers/crypto/dpaa2_sec/
 F: doc/guides/cryptodevs/dpaa2_sec.rst
 F: doc/guides/cryptodevs/features/dpaa2_sec.ini
 
+MARVELL MRVL PMD
+M: Jacek Siuda <jck@semihalf.com>
+M: Tomasz Duszynski <tdu@semihalf.com>
+M: Dmitri Epshtein <dima@marvell.com>
+M: Natalie Samsonov <nsamsono@marvell.com>
+M: Jianbo Liu <jianbo.liu@linaro.org>
+F: drivers/crypto/mrvl/
+F: doc/guides/cryptodevs/mrvl.rst
+F: doc/guides/cryptodevs/mrvl.ini
+
 SNOW 3G PMD
 M: Pablo de Lara <pablo.de.lara.guarch@intel.com>
 F: drivers/crypto/snow3g/
-- 
2.7.4

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

* [PATCH 8/8] test: add mrvl crypto pmd unit tests
  2017-09-26  9:39 [PATCH 0/8] add net/crypto mrvl pmd drivers Tomasz Duszynski
                   ` (6 preceding siblings ...)
  2017-09-26  9:40 ` [PATCH 7/8] maintainers: add maintainers for the mrvl crypto pmd Tomasz Duszynski
@ 2017-09-26  9:40 ` Tomasz Duszynski
  2017-09-27  9:40 ` [PATCH 0/8] add net/crypto mrvl pmd drivers De Lara Guarch, Pablo
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-26  9:40 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Tomasz Duszynski, Jacek Siuda

Add unit tests for MRVL CRYPTO PMD driver.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <jck@semihalf.com>
---
 test/test/test_cryptodev.c                  | 168 ++++++++++++++++++++++++++++
 test/test/test_cryptodev.h                  |   1 +
 test/test/test_cryptodev_aes_test_vectors.h |  72 ++++++++----
 test/test/test_cryptodev_blockcipher.c      |   9 +-
 test/test/test_cryptodev_blockcipher.h      |   1 +
 test/test/test_cryptodev_des_test_vectors.h |  24 ++--
 6 files changed, 242 insertions(+), 33 deletions(-)

diff --git a/test/test/test_cryptodev.c b/test/test/test_cryptodev.c
index a4116c6..9fb6a2c 100644
--- a/test/test/test_cryptodev.c
+++ b/test/test/test_cryptodev.c
@@ -341,6 +341,28 @@ testsuite_setup(void)
 		}
 	}
 
+	/* Create a MRVL device if required */
+	if (gbl_driver_id == rte_cryptodev_driver_id_get(
+			RTE_STR(CRYPTODEV_MRVL_PMD))) {
+#ifndef RTE_LIBRTE_PMD_MRVL_CRYPTO
+		RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO must be"
+			" enabled in config file to run this testsuite.\n");
+		return TEST_FAILED;
+#endif
+		nb_devs = rte_cryptodev_device_count_by_driver(
+				rte_cryptodev_driver_id_get(
+				RTE_STR(CRYPTODEV_NAME_MRVL_PMD)));
+		if (nb_devs < 1) {
+			ret = rte_vdev_init(
+				RTE_STR(CRYPTODEV_NAME_MRVL_PMD),
+				NULL);
+
+			TEST_ASSERT(ret == 0, "Failed to create "
+				"instance of pmd : %s",
+				RTE_STR(CRYPTODEV_NAME_MRVL_PMD));
+		}
+	}
+
 #ifdef RTE_LIBRTE_PMD_CRYPTO_SCHEDULER
 	if (gbl_driver_id == rte_cryptodev_driver_id_get(
 			RTE_STR(CRYPTODEV_NAME_SCHEDULER_PMD))) {
@@ -1862,6 +1884,101 @@ test_AES_chain_armv8_all(void)
 	return TEST_SUCCESS;
 }
 
+static int
+test_AES_chain_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_AES_CHAIN_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_AES_cipheronly_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_AES_CIPHERONLY_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_authonly_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_AUTHONLY_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_3DES_chain_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_3DES_CHAIN_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_3DES_cipheronly_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_3DES_CIPHERONLY_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
 /* ***** SNOW 3G Tests ***** */
 static int
 create_wireless_algo_hash_session(uint8_t dev_id,
@@ -8939,6 +9056,40 @@ static struct unit_test_suite cryptodev_armv8_testsuite  = {
 	}
 };
 
+static struct unit_test_suite cryptodev_mrvl_testsuite  = {
+	.suite_name = "Crypto Device Marvell Component Test Suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASE_ST(ut_setup, ut_teardown, test_multi_session),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_multi_session_random_usage),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_AES_chain_mrvl_all),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_AES_cipheronly_mrvl_all),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_authonly_mrvl_all),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_3DES_chain_mrvl_all),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_3DES_cipheronly_mrvl_all),
+
+		/** Negative tests */
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			authentication_verify_HMAC_SHA1_fail_data_corrupt),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			authentication_verify_HMAC_SHA1_fail_tag_corrupt),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			auth_decryption_AES128CBC_HMAC_SHA1_fail_data_corrupt),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			auth_decryption_AES128CBC_HMAC_SHA1_fail_tag_corrupt),
+
+		TEST_CASES_END() /**< NULL terminate unit test array */
+	}
+};
+
+
 static int
 test_cryptodev_qat(void /*argv __rte_unused, int argc __rte_unused*/)
 {
@@ -9083,6 +9234,22 @@ test_cryptodev_armv8(void)
 	return unit_test_suite_runner(&cryptodev_armv8_testsuite);
 }
 
+static int
+test_cryptodev_mrvl(void)
+{
+	gbl_driver_id = rte_cryptodev_driver_id_get(
+			RTE_STR(CRYPTODEV_NAME_MRVL_PMD));
+
+	if (gbl_driver_id == -1) {
+		RTE_LOG(ERR, USER1, "MRVL PMD must be loaded. Check if "
+				"CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO is enabled "
+				"in config file to run this testsuite.\n");
+		return TEST_FAILED;
+	}
+
+	return unit_test_suite_runner(&cryptodev_mrvl_testsuite);
+}
+
 #ifdef RTE_LIBRTE_PMD_CRYPTO_SCHEDULER
 
 static int
@@ -9136,4 +9303,5 @@ REGISTER_TEST_COMMAND(cryptodev_sw_snow3g_autotest, test_cryptodev_sw_snow3g);
 REGISTER_TEST_COMMAND(cryptodev_sw_kasumi_autotest, test_cryptodev_sw_kasumi);
 REGISTER_TEST_COMMAND(cryptodev_sw_zuc_autotest, test_cryptodev_sw_zuc);
 REGISTER_TEST_COMMAND(cryptodev_sw_armv8_autotest, test_cryptodev_armv8);
+REGISTER_TEST_COMMAND(cryptodev_sw_mrvl_autotest, test_cryptodev_mrvl);
 REGISTER_TEST_COMMAND(cryptodev_dpaa2_sec_autotest, test_cryptodev_dpaa2_sec);
diff --git a/test/test/test_cryptodev.h b/test/test/test_cryptodev.h
index 4509a09..2e9eb0b 100644
--- a/test/test/test_cryptodev.h
+++ b/test/test/test_cryptodev.h
@@ -88,6 +88,7 @@
 #define CRYPTODEV_NAME_ARMV8_PMD	crypto_armv8
 #define CRYPTODEV_NAME_DPAA2_SEC_PMD	crypto_dpaa2_sec
 #define CRYPTODEV_NAME_SCHEDULER_PMD	crypto_scheduler
+#define CRYPTODEV_NAME_MRVL_PMD		crypto_mrvl
 
 /**
  * Write (spread) data from buffer to mbuf data
diff --git a/test/test/test_cryptodev_aes_test_vectors.h b/test/test/test_cryptodev_aes_test_vectors.h
index e410018..0af50fd 100644
--- a/test/test/test_cryptodev_aes_test_vectors.h
+++ b/test/test/test_cryptodev_aes_test_vectors.h
@@ -1197,7 +1197,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CTR HMAC-SHA1 Decryption Digest "
@@ -1208,7 +1209,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-192-CTR XCBC Encryption Digest",
@@ -1245,7 +1247,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-256-CTR HMAC-SHA1 Decryption Digest "
@@ -1256,7 +1259,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest",
@@ -1267,14 +1271,16 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest "
 			"(short buffers)",
 		.test_data = &aes_test_data_13,
 		.op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest "
@@ -1298,14 +1304,16 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Decryption Digest "
 			"Verify (short buffers)",
 		.test_data = &aes_test_data_13,
 		.op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA256 Encryption Digest",
@@ -1316,14 +1324,16 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA256 Encryption Digest "
 			"(short buffers)",
 		.test_data = &aes_test_data_12,
 		.op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA256 Decryption Digest "
@@ -1335,14 +1345,16 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA256 Decryption Digest "
 			"Verify (short buffers)",
 		.test_data = &aes_test_data_12,
 		.op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA512 Encryption Digest",
@@ -1352,7 +1364,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA512 Encryption Digest "
@@ -1383,7 +1396,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA512 Decryption Digest "
@@ -1462,7 +1476,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA384 Decryption Digest "
@@ -1473,7 +1488,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest "
@@ -1505,7 +1521,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC Decryption",
@@ -1515,7 +1532,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-192-CBC Encryption",
@@ -1553,7 +1571,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-256-CBC Decryption",
@@ -1563,7 +1582,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-256-CBC OOP Encryption",
@@ -1589,7 +1609,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CTR Decryption",
@@ -1599,7 +1620,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-192-CTR Encryption",
@@ -1629,7 +1651,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-256-CTR Decryption",
@@ -1639,7 +1662,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CTR Encryption (12-byte IV)",
diff --git a/test/test/test_cryptodev_blockcipher.c b/test/test/test_cryptodev_blockcipher.c
index 6089af4..01fe136 100644
--- a/test/test/test_cryptodev_blockcipher.c
+++ b/test/test/test_cryptodev_blockcipher.c
@@ -92,6 +92,8 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 			RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD));
 	int dpaa2_sec_pmd = rte_cryptodev_driver_id_get(
 			RTE_STR(CRYPTODEV_NAME_DPAA2_SEC_PMD));
+	int mrvl_pmd = rte_cryptodev_driver_id_get(
+			RTE_STR(CRYPTODEV_NAME_MRVL_PMD));
 
 	int nb_segs = 1;
 
@@ -116,7 +118,8 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 	if (driver_id == dpaa2_sec_pmd ||
 			driver_id == qat_pmd ||
 			driver_id == openssl_pmd ||
-			driver_id == armv8_pmd) { /* Fall through */
+			driver_id == armv8_pmd ||
+			driver_id == mrvl_pmd) { /* Fall through */
 		digest_len = tdata->digest.len;
 	} else if (driver_id == aesni_mb_pmd ||
 			driver_id == scheduler_pmd) {
@@ -612,6 +615,8 @@ test_blockcipher_all_tests(struct rte_mempool *mbuf_pool,
 			RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD));
 	int qat_pmd = rte_cryptodev_driver_id_get(
 			RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD));
+	int mrvl_pmd = rte_cryptodev_driver_id_get(
+			RTE_STR(CRYPTODEV_NAME_MRVL_PMD));
 
 	switch (test_type) {
 	case BLKCIPHER_AES_CHAIN_TYPE:
@@ -670,6 +675,8 @@ test_blockcipher_all_tests(struct rte_mempool *mbuf_pool,
 		target_pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER;
 	else if (driver_id == dpaa2_pmd)
 		target_pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC;
+	else if (driver_id == mrvl_pmd)
+		target_pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MRVL;
 	else
 		TEST_ASSERT(0, "Unrecognized cryptodev type");
 
diff --git a/test/test/test_cryptodev_blockcipher.h b/test/test/test_cryptodev_blockcipher.h
index 22b8d20..6919336 100644
--- a/test/test/test_cryptodev_blockcipher.h
+++ b/test/test/test_cryptodev_blockcipher.h
@@ -53,6 +53,7 @@
 #define BLOCKCIPHER_TEST_TARGET_PMD_ARMV8	0x0008 /* ARMv8 flag */
 #define BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER	0x0010 /* Scheduler */
 #define BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC	0x0020 /* DPAA2_SEC flag */
+#define BLOCKCIPHER_TEST_TARGET_PMD_MRVL	0x0040 /* Marvell flag */
 
 #define BLOCKCIPHER_TEST_OP_CIPHER	(BLOCKCIPHER_TEST_OP_ENCRYPT | \
 					BLOCKCIPHER_TEST_OP_DECRYPT)
diff --git a/test/test/test_cryptodev_des_test_vectors.h b/test/test/test_cryptodev_des_test_vectors.h
index 0b6e0b8..ffcf657 100644
--- a/test/test/test_cryptodev_des_test_vectors.h
+++ b/test/test/test_cryptodev_des_test_vectors.h
@@ -851,13 +851,15 @@ static const struct blockcipher_test_case des_cipheronly_test_cases[] = {
 		.test_descr = "DES-CBC Encryption",
 		.test_data = &des_cbc_test_vector,
 		.op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "DES-CBC Decryption",
 		.test_data = &des_cbc_test_vector,
 		.op_mask = BLOCKCIPHER_TEST_OP_DECRYPT,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 
 };
@@ -1087,7 +1089,8 @@ static const struct blockcipher_test_case triple_des_chain_test_cases[] = {
 		.op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
 		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-192-CBC HMAC-SHA1 Decryption Digest Verify",
@@ -1095,19 +1098,22 @@ static const struct blockcipher_test_case triple_des_chain_test_cases[] = {
 		.op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC,
 		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-192-CBC SHA1 Encryption Digest",
 		.test_data = &triple_des192cbc_sha1_test_vector,
 		.op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-192-CBC SHA1 Decryption Digest Verify",
 		.test_data = &triple_des192cbc_sha1_test_vector,
 		.op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-128-CTR HMAC-SHA1 Encryption Digest",
@@ -1220,7 +1226,8 @@ static const struct blockcipher_test_case triple_des_cipheronly_test_cases[] = {
 		.op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT,
 		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-192-CBC Decryption",
@@ -1228,7 +1235,8 @@ static const struct blockcipher_test_case triple_des_cipheronly_test_cases[] = {
 		.op_mask = BLOCKCIPHER_TEST_OP_DECRYPT,
 		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-128-CTR Encryption",
-- 
2.7.4

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

* Re: [PATCH 1/8] app: link the whole rte_cfgfile library
  2017-09-26  9:39 ` [PATCH 1/8] app: link the whole rte_cfgfile library Tomasz Duszynski
@ 2017-09-26 14:31   ` Bruce Richardson
  2017-09-27  7:36     ` Tomasz Duszynski
  0 siblings, 1 reply; 110+ messages in thread
From: Bruce Richardson @ 2017-09-26 14:31 UTC (permalink / raw)
  To: Tomasz Duszynski; +Cc: dev, mw, dima, nsamsono, Jacek Siuda

On Tue, Sep 26, 2017 at 11:39:58AM +0200, Tomasz Duszynski wrote:
> Since MRVL NET PMD needs librte_cfgfile to parse QoS configuration file
> link it as the whole library.
> 
> Signed-off-by: Jacek Siuda <jck@semihalf.com>
> Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
> ---

Can you clarify a bit more why this is needed? For a static build, the
cfgfile should be linked in to the after the PMDs, so the dependencies
in the driver should be satisfied in the link. For a dynamic build, the
PMD should depend upon the cfgfile directly, and use it at runtime
appropriately. 
Am I missing something?

/Bruce

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

* Re: [PATCH 1/8] app: link the whole rte_cfgfile library
  2017-09-26 14:31   ` Bruce Richardson
@ 2017-09-27  7:36     ` Tomasz Duszynski
  2017-09-27 12:01       ` Bruce Richardson
  0 siblings, 1 reply; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-27  7:36 UTC (permalink / raw)
  To: Bruce Richardson; +Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jacek Siuda

On Tue, Sep 26, 2017 at 03:31:18PM +0100, Bruce Richardson wrote:
> On Tue, Sep 26, 2017 at 11:39:58AM +0200, Tomasz Duszynski wrote:
> > Since MRVL NET PMD needs librte_cfgfile to parse QoS configuration file
> > link it as the whole library.
> >
> > Signed-off-by: Jacek Siuda <jck@semihalf.com>
> > Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
> > ---
>
> Can you clarify a bit more why this is needed? For a static build, the
> cfgfile should be linked in to the after the PMDs, so the dependencies
> in the driver should be satisfied in the link. For a dynamic build, the
> PMD should depend upon the cfgfile directly, and use it at runtime
> appropriately.
> Am I missing something?
>
> /Bruce
Hi Bruce,

You are correct, all dependencies in the driver will be satisfied.
The reason this change was introduced is that, librte_pmd_mrvl.a
contains undefined symbols from librte_cfgfile.a thus linking
applications under app/ directory will fail as librte_cfgfile.a comes
before librte_pmd_mrvl.a during the linking stage.

Linking librte_cfgfile.a with --whole-archive solves the issue.

--
- Tomasz Duszyński

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

* Re: [PATCH 0/8] add net/crypto mrvl pmd drivers
  2017-09-26  9:39 [PATCH 0/8] add net/crypto mrvl pmd drivers Tomasz Duszynski
                   ` (7 preceding siblings ...)
  2017-09-26  9:40 ` [PATCH 8/8] test: add mrvl crypto pmd unit tests Tomasz Duszynski
@ 2017-09-27  9:40 ` De Lara Guarch, Pablo
  2017-09-27 10:59   ` Tomasz Duszynski
  2017-09-28 10:22 ` [PATCH v2 0/4] add net mrvl pmd driver Tomasz Duszynski
  2017-09-28 10:23 ` [PATCH v2 0/4] add crypto " Tomasz Duszynski
  10 siblings, 1 reply; 110+ messages in thread
From: De Lara Guarch, Pablo @ 2017-09-27  9:40 UTC (permalink / raw)
  To: Tomasz Duszynski, dev; +Cc: mw, dima, nsamsono



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Tomasz Duszynski
> Sent: Tuesday, September 26, 2017 10:40 AM
> To: dev@dpdk.org
> Cc: mw@semihalf.com; dima@marvell.com; nsamsono@marvell.com;
> Tomasz Duszynski <tdu@semihalf.com>
> Subject: [dpdk-dev] [PATCH 0/8] add net/crypto mrvl pmd drivers
> 
> Hello,
> 
> This patch series introduces net/crypto drivers for Marvell Armada 7k/8k
> SoCs along with documentation and crypto driver pmd tests.
> 
> Below you can find the list of features which net/crypto pmds support.
> 

Could you split this patchset into two? I think the network and crypto PMDs should be separated,
as they are targetting different subtrees.

Thanks,
Pablo

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

* Re: [PATCH 0/8] add net/crypto mrvl pmd drivers
  2017-09-27  9:40 ` [PATCH 0/8] add net/crypto mrvl pmd drivers De Lara Guarch, Pablo
@ 2017-09-27 10:59   ` Tomasz Duszynski
  0 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-27 10:59 UTC (permalink / raw)
  To: De Lara Guarch, Pablo; +Cc: Tomasz Duszynski, dev, mw, dima, nsamsono

On Wed, Sep 27, 2017 at 09:40:52AM +0000, De Lara Guarch, Pablo wrote:
>
>
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Tomasz Duszynski
> > Sent: Tuesday, September 26, 2017 10:40 AM
> > To: dev@dpdk.org
> > Cc: mw@semihalf.com; dima@marvell.com; nsamsono@marvell.com;
> > Tomasz Duszynski <tdu@semihalf.com>
> > Subject: [dpdk-dev] [PATCH 0/8] add net/crypto mrvl pmd drivers
> >
> > Hello,
> >
> > This patch series introduces net/crypto drivers for Marvell Armada 7k/8k
> > SoCs along with documentation and crypto driver pmd tests.
> >
> > Below you can find the list of features which net/crypto pmds support.
> >
>
> Could you split this patchset into two? I think the network and crypto PMDs should be separated,
> as they are targetting different subtrees.
>
> Thanks,
> Pablo
If that's a hard requirement I am fine with splitting the patch series.
Drivers were put into the same patchset because they have common
CONFIG dependency.

E.g. applying just crypto pmd patches and changing
CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO to 'y' would break compilation
as it depends on CONFIG introduced by net pmd patches.

--
- Tomasz Duszyński

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

* Re: [PATCH 1/8] app: link the whole rte_cfgfile library
  2017-09-27  7:36     ` Tomasz Duszynski
@ 2017-09-27 12:01       ` Bruce Richardson
  0 siblings, 0 replies; 110+ messages in thread
From: Bruce Richardson @ 2017-09-27 12:01 UTC (permalink / raw)
  To: Tomasz Duszynski; +Cc: dev, mw, dima, nsamsono, Jacek Siuda

On Wed, Sep 27, 2017 at 09:36:03AM +0200, Tomasz Duszynski wrote:
> On Tue, Sep 26, 2017 at 03:31:18PM +0100, Bruce Richardson wrote:
> > On Tue, Sep 26, 2017 at 11:39:58AM +0200, Tomasz Duszynski wrote:
> > > Since MRVL NET PMD needs librte_cfgfile to parse QoS configuration file
> > > link it as the whole library.
> > >
> > > Signed-off-by: Jacek Siuda <jck@semihalf.com>
> > > Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
> > > ---
> >
> > Can you clarify a bit more why this is needed? For a static build, the
> > cfgfile should be linked in to the after the PMDs, so the dependencies
> > in the driver should be satisfied in the link. For a dynamic build, the
> > PMD should depend upon the cfgfile directly, and use it at runtime
> > appropriately.
> > Am I missing something?
> >
> > /Bruce
> Hi Bruce,
> 
> You are correct, all dependencies in the driver will be satisfied.
> The reason this change was introduced is that, librte_pmd_mrvl.a
> contains undefined symbols from librte_cfgfile.a thus linking
> applications under app/ directory will fail as librte_cfgfile.a comes
> before librte_pmd_mrvl.a during the linking stage.
> 
> Linking librte_cfgfile.a with --whole-archive solves the issue.
> 
> --
Thanks for the explanation.

I believe the proper fix in this case is to ensure that when linking
apps that cfgfile comes after librte_pmd_mrvl. The drivers should always
come first when linking, then the DPDK libs.

/Bruce

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

* [PATCH v2 0/4] add net mrvl pmd driver
  2017-09-26  9:39 [PATCH 0/8] add net/crypto mrvl pmd drivers Tomasz Duszynski
                   ` (8 preceding siblings ...)
  2017-09-27  9:40 ` [PATCH 0/8] add net/crypto mrvl pmd drivers De Lara Guarch, Pablo
@ 2017-09-28 10:22 ` Tomasz Duszynski
  2017-09-28 10:22   ` [PATCH v2 1/4] app: link the whole rte_cfgfile library Tomasz Duszynski
                     ` (4 more replies)
  2017-09-28 10:23 ` [PATCH v2 0/4] add crypto " Tomasz Duszynski
  10 siblings, 5 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-28 10:22 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski

Hello,

This patch series introduces the net driver for Marvell Armada 7k/8k
SoCs along with documentation.

Below you can find the list of features which net pmd supports:
* Speed capabilities
* Link status
* Queue start/stop
* MTU update
* Jumbo frame
* Promiscuous mode
* Allmulticast mode
* Unicast MAC filter
* Multicast MAC filter
* RSS hash
* VLAN filter
* CRC offload
* L3 checksum offload
* L4 checksum offload
* Packet type parsing
* Basic stats
* Stats per queue

Tomasz Duszynski (4):
  app: link the whole rte_cfgfile library
  net/mrvl: add mrvl net pmd driver
  doc: add mrvl net pmd documentation
  maintainers: add maintainers for the mrvl net pmd

 MAINTAINERS                               |   10 +
 config/common_base                        |    7 +
 doc/guides/nics/features/mrvl.ini         |   24 +
 doc/guides/nics/index.rst                 |    1 +
 doc/guides/nics/mrvl.rst                  |  151 ++
 drivers/net/Makefile                      |    2 +
 drivers/net/mrvl/Makefile                 |   69 +
 drivers/net/mrvl/mrvl_ethdev.c            | 2277 +++++++++++++++++++++++++++++
 drivers/net/mrvl/mrvl_ethdev.h            |  115 ++
 drivers/net/mrvl/mrvl_qos.c               |  627 ++++++++
 drivers/net/mrvl/mrvl_qos.h               |  112 ++
 drivers/net/mrvl/rte_pmd_mrvl_version.map |    3 +
 mk/rte.app.mk                             |    3 +-
 13 files changed, 3400 insertions(+), 1 deletion(-)
 create mode 100644 doc/guides/nics/features/mrvl.ini
 create mode 100644 doc/guides/nics/mrvl.rst
 create mode 100644 drivers/net/mrvl/Makefile
 create mode 100644 drivers/net/mrvl/mrvl_ethdev.c
 create mode 100644 drivers/net/mrvl/mrvl_ethdev.h
 create mode 100644 drivers/net/mrvl/mrvl_qos.c
 create mode 100644 drivers/net/mrvl/mrvl_qos.h
 create mode 100644 drivers/net/mrvl/rte_pmd_mrvl_version.map

--
2.7.4

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

* [PATCH v2 1/4] app: link the whole rte_cfgfile library
  2017-09-28 10:22 ` [PATCH v2 0/4] add net mrvl pmd driver Tomasz Duszynski
@ 2017-09-28 10:22   ` Tomasz Duszynski
  2017-10-03 11:51     ` [PATCH v3 0/4] add net mrvl pmd driver Tomasz Duszynski
  2017-09-28 10:22   ` [PATCH v2 2/4] net/mrvl: add mrvl net " Tomasz Duszynski
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-28 10:22 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

MRVL net pmd needs rte_cfgfile to parse QoS configuration file thus
librte_pmd_mrvl.a contains undefined symbols from librte_cfgfile.a.

As a result linking applications under app/ directory will fail
because librte_cfgfile.a comes before librte_pmd_mrvl.a during
the linking stage.

Linking the whole librte_cfgfile.a solves the issue.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 v2:
 * Changed commit message to explain problem better.

 mk/rte.app.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index c25fdd9..94568a8 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -81,10 +81,10 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)          += -lrte_power

 _LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)            += -lrte_efd
-_LDLIBS-$(CONFIG_RTE_LIBRTE_CFGFILE)        += -lrte_cfgfile

 _LDLIBS-y += --whole-archive

+_LDLIBS-$(CONFIG_RTE_LIBRTE_CFGFILE)        += -lrte_cfgfile
 _LDLIBS-$(CONFIG_RTE_LIBRTE_HASH)           += -lrte_hash
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VHOST)          += -lrte_vhost
 _LDLIBS-$(CONFIG_RTE_LIBRTE_KVARGS)         += -lrte_kvargs
--
2.7.4

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

* [PATCH v2 2/4] net/mrvl: add mrvl net pmd driver
  2017-09-28 10:22 ` [PATCH v2 0/4] add net mrvl pmd driver Tomasz Duszynski
  2017-09-28 10:22   ` [PATCH v2 1/4] app: link the whole rte_cfgfile library Tomasz Duszynski
@ 2017-09-28 10:22   ` Tomasz Duszynski
  2017-09-29 15:38     ` Stephen Hemminger
  2017-09-28 10:22   ` [PATCH v2 3/4] doc: add mrvl net pmd documentation Tomasz Duszynski
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-28 10:22 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add support for the Marvell PPv2 (Packet Processor v2) 1/10 Gbps adapter.
Driver is based on external, publicly available, light-weight Marvell
MUSDK library that provides access to network packet processor.

Driver comes with support for the following features:

* Speed capabilities
* Link status
* Queue start/stop
* MTU update
* Jumbo frame
* Promiscuous mode
* Allmulticast mode
* Unicast MAC filter
* Multicast MAC filter
* RSS hash
* VLAN filter
* CRC offload
* L3 checksum offload
* L4 checksum offload
* Packet type parsing
* Basic stats
* Stats per queue

Driver was engineered cooperatively by Semihalf and Marvell teams.

Semihalf:
Jacek Siuda <jck@semihalf.com>
Tomasz Duszynski <tdu@semihalf.com>

Marvell:
Dmitri Epshtein <dima@marvell.com>
Natalie Samsonov <nsamsono@marvell.com>

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 v2:
 * Removed bunch of checkpatch warnings about unnecessary parentheses.

 config/common_base                        |    7 +
 drivers/net/Makefile                      |    2 +
 drivers/net/mrvl/Makefile                 |   69 +
 drivers/net/mrvl/mrvl_ethdev.c            | 2277 +++++++++++++++++++++++++++++
 drivers/net/mrvl/mrvl_ethdev.h            |  115 ++
 drivers/net/mrvl/mrvl_qos.c               |  627 ++++++++
 drivers/net/mrvl/mrvl_qos.h               |  112 ++
 drivers/net/mrvl/rte_pmd_mrvl_version.map |    3 +
 mk/rte.app.mk                             |    1 +
 9 files changed, 3213 insertions(+)
 create mode 100644 drivers/net/mrvl/Makefile
 create mode 100644 drivers/net/mrvl/mrvl_ethdev.c
 create mode 100644 drivers/net/mrvl/mrvl_ethdev.h
 create mode 100644 drivers/net/mrvl/mrvl_qos.c
 create mode 100644 drivers/net/mrvl/mrvl_qos.h
 create mode 100644 drivers/net/mrvl/rte_pmd_mrvl_version.map

diff --git a/config/common_base b/config/common_base
index 5e97a08..d05a60c 100644
--- a/config/common_base
+++ b/config/common_base
@@ -262,6 +262,13 @@ CONFIG_RTE_LIBRTE_NFP_PMD=n
 CONFIG_RTE_LIBRTE_NFP_DEBUG=n

 #
+# Compile Marvell PMD driver
+#
+CONFIG_RTE_LIBRTE_MRVL_PMD=n
+CONFIG_RTE_LIBRTE_MRVL_DEBUG=n
+CONFIG_RTE_MRVL_MUSDK_DMA_MEMSIZE=41943040
+
+#
 # Compile burst-oriented Broadcom BNXT PMD driver
 #
 CONFIG_RTE_LIBRTE_BNXT_PMD=y
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index d33c959..4a3a205 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -73,6 +73,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4
 DEPDIRS-mlx4 = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5
 DEPDIRS-mlx5 = $(core-libs)
+DIRS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl
+DEPDIRS-mrvl = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_NFP_PMD) += nfp
 DEPDIRS-nfp = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt
diff --git a/drivers/net/mrvl/Makefile b/drivers/net/mrvl/Makefile
new file mode 100644
index 0000000..ab53f49
--- /dev/null
+++ b/drivers/net/mrvl/Makefile
@@ -0,0 +1,69 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2017 Semihalf. 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 Semihalf 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
+
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),config)
+ifeq ($(LIBMUSDK_PATH),)
+$(error "Please define LIBMUSDK_PATH environment variable")
+endif
+ifeq ($(CONFIG_RTE_LIBRTE_CFGFILE),n)
+$(error "RTE_LIBRTE_CFGFILE must be enabled in configuration!")
+endif
+endif
+endif
+
+# library name
+LIB = librte_pmd_mrvl.a
+
+# library version
+LIBABIVER := 1
+
+# versioning export map
+EXPORT_MAP := rte_pmd_mrvl_version.map
+
+# external library dependencies
+CFLAGS += -I$(LIBMUSDK_PATH)/include
+CFLAGS += -DMVCONF_ARCH_DMA_ADDR_T_64BIT
+CFLAGS += -DCONF_PP2_BPOOL_COOKIE_SIZE=32
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -O3
+LDLIBS += -L$(LIBMUSDK_PATH)/lib
+LDLIBS += -lmusdk
+
+# library source files
+SRCS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl_qos.c
+
+# library dependencies
+DEPDIRS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += lib/librte_cfgfile
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/mrvl/mrvl_ethdev.c b/drivers/net/mrvl/mrvl_ethdev.c
new file mode 100644
index 0000000..2084461
--- /dev/null
+++ b/drivers/net/mrvl/mrvl_ethdev.c
@@ -0,0 +1,2277 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Semihalf. 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 Semihalf 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_ethdev.h>
+#include <rte_kvargs.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_vdev.h>
+#include <rte_cycles.h>
+
+/* Unluckily, container_of is defined by both DPDK and MUSDK,
+ * we'll declare only one version.
+ *
+ * Note that it is not used in this PMD anyway.
+ */
+#ifdef container_of
+#undef container_of
+#endif
+
+#include <drivers/mv_pp2.h>
+#include <drivers/mv_pp2_bpool.h>
+#include <drivers/mv_pp2_hif.h>
+
+#include <assert.h>
+#include <fcntl.h>
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "mrvl_ethdev.h"
+#include "mrvl_qos.h"
+
+/* bitmask with reserved hifs */
+#define MRVL_MUSDK_HIFS_RESERVED 0x0F
+/* bitmask with reserved bpools */
+#define MRVL_MUSDK_BPOOLS_RESERVED 0x07
+/* bitmask with reserved kernel RSS tables */
+#define MRVL_MUSDK_RSS_RESERVED 0x01
+/* maximum number of available hifs */
+#define MRVL_MUSDK_HIFS_MAX 9
+
+/* prefetch shift */
+#define MRVL_MUSDK_PREFETCH_SHIFT 2
+
+/* TCAM has 25 entries reserved for uc/mc filter entries */
+#define MRVL_MAC_ADDRS_MAX 25
+#define MRVL_MATCH_LEN 16
+#define MRVL_PKT_EFFEC_OFFS (MRVL_PKT_OFFS + MV_MH_SIZE)
+/* Maximum allowable packet size */
+#define MRVL_PKT_SIZE_MAX (10240 - MV_MH_SIZE)
+
+#define MRVL_IFACE_NAME_ARG "iface"
+#define MRVL_CFG_ARG "cfg"
+
+#define MRVL_BURST_SIZE 64
+
+#define MRVL_ARP_LENGTH 28
+
+#define MRVL_COOKIE_ADDR_INVALID ~0ULL
+
+#define MRVL_COOKIE_HIGH_ADDR_SHIFT	(sizeof(pp2_cookie_t) * 8)
+#define MRVL_COOKIE_HIGH_ADDR_MASK	(~0ULL << MRVL_COOKIE_HIGH_ADDR_SHIFT)
+
+static const char * const valid_args[] = {
+	MRVL_IFACE_NAME_ARG,
+	MRVL_CFG_ARG,
+	NULL
+};
+
+static int used_hifs = MRVL_MUSDK_HIFS_RESERVED;
+static struct pp2_hif *hifs[RTE_MAX_LCORE];
+static int used_bpools[PP2_NUM_PKT_PROC] = {
+	MRVL_MUSDK_BPOOLS_RESERVED,
+	MRVL_MUSDK_BPOOLS_RESERVED
+};
+
+struct pp2_bpool *mrvl_port_to_bpool_lookup[RTE_MAX_ETHPORTS];
+int mrvl_port_bpool_size[PP2_NUM_PKT_PROC][PP2_BPOOL_NUM_POOLS][RTE_MAX_LCORE];
+uint64_t cookie_addr_high = MRVL_COOKIE_ADDR_INVALID;
+
+/*
+ * To use buffer harvesting based on loopback port shadow queue structure
+ * was introduced for buffers information bookkeeping.
+ *
+ * Before sending the packet, related buffer information (pp2_buff_inf) is
+ * stored in shadow queue. After packet is transmitted no longer used
+ * packet buffer is released back to it's original hardware pool,
+ * on condition it originated from interface.
+ * In case it  was generated by application itself i.e: mbuf->port field is
+ * 0xff then its released to software mempool.
+ */
+struct mrvl_shadow_txq {
+	int head;           /* write index - used when sending buffers */
+	int tail;           /* read index - used when releasing buffers */
+	u16 size;           /* queue occupied size */
+	u16 num_to_release; /* number of buffers sent, that can be released */
+	struct buff_release_entry ent[MRVL_PP2_TX_SHADOWQ_SIZE]; /* q entries */
+};
+
+struct mrvl_rxq;
+struct mrvl_txq;
+
+struct mrvl_rxq {
+	struct mrvl_priv *priv;
+	struct rte_mempool *mp;
+	int queue_id;
+	int port_id;
+	int cksum_enabled;
+	uint64_t bytes_recv;
+	uint64_t drop_mac;
+};
+
+struct mrvl_txq {
+	struct mrvl_priv *priv;
+	int queue_id;
+	int port_id;
+	uint64_t bytes_sent;
+};
+
+/*
+ * Every tx queue should have dedicated shadow tx queue.
+ *
+ * Ports assigned by DPDK might not start at zero or be continuous so
+ * as a workaround define shadow queues for each possible port so that
+ * we eventually fit somewhere.
+ */
+struct mrvl_shadow_txq shadow_txqs[RTE_MAX_ETHPORTS][RTE_MAX_LCORE];
+
+/** Number of ports configured. */
+int mrvl_ports_nb;
+static int mrvl_lcore_first;
+static int mrvl_lcore_last;
+
+static inline int
+mrvl_get_bpool_size(int	pp2_id, int pool_id)
+{
+	int i;
+	int size = 0;
+
+	for (i = mrvl_lcore_first; i <= mrvl_lcore_last; i++)
+		size += mrvl_port_bpool_size[pp2_id][pool_id][i];
+
+	return size;
+}
+
+
+static inline int
+mrvl_reserve_bit(int *bitmap, int max)
+{
+	int n = sizeof(*bitmap) * 8 - __builtin_clz(*bitmap);
+	if (n >= max)
+		return -1;
+
+	*bitmap |= 1 << n;
+
+	return n;
+}
+
+/**
+ * Configure rss based on dpdk rss configuration.
+ *
+ * @param priv
+ *   Pointer to private structure.
+ * @param rss_conf
+ *   Pointer to RSS configuration.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_configure_rss(struct mrvl_priv *priv, struct rte_eth_rss_conf *rss_conf)
+{
+	if (rss_conf->rss_key)
+		RTE_LOG(WARNING, PMD, "Changing hash key is not supported\n");
+
+	if (rss_conf->rss_hf == 0) {
+		priv->ppio_params.inqs_params.hash_type = PP2_PPIO_HASH_T_NONE;
+	} else if (rss_conf->rss_hf & ETH_RSS_IPV4) {
+		priv->ppio_params.inqs_params.hash_type =
+			PP2_PPIO_HASH_T_2_TUPLE;
+	} else if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV4_TCP) {
+		priv->ppio_params.inqs_params.hash_type =
+			PP2_PPIO_HASH_T_5_TUPLE;
+		priv->rss_hf_tcp = 1;
+	} else if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV4_UDP) {
+		priv->ppio_params.inqs_params.hash_type =
+			PP2_PPIO_HASH_T_5_TUPLE;
+		priv->rss_hf_tcp = 0;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * Ethernet device configuration.
+ *
+ * Prepare the driver for a given number of TX and RX queues and
+ * configure RSS.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_dev_configure(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	if (dev->data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_NONE &&
+	    dev->data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_RSS) {
+		RTE_LOG(INFO, PMD, "Unsupported rx multi queue mode %d\n",
+			dev->data->dev_conf.rxmode.mq_mode);
+		return -EINVAL;
+	}
+
+	if (!dev->data->dev_conf.rxmode.hw_strip_crc) {
+		RTE_LOG(INFO, PMD,
+			"L2 CRC stripping is always enabled in hw\n");
+		dev->data->dev_conf.rxmode.hw_strip_crc = 1;
+	}
+
+	if (dev->data->dev_conf.rxmode.hw_vlan_strip) {
+		RTE_LOG(INFO, PMD, "VLAN stripping not supported\n");
+		return -EINVAL;
+	}
+
+	if (dev->data->dev_conf.rxmode.split_hdr_size) {
+		RTE_LOG(INFO, PMD, "Split headers not supported\n");
+		return -EINVAL;
+	}
+
+	if (dev->data->dev_conf.rxmode.enable_scatter) {
+		RTE_LOG(INFO, PMD, "RX Scatter/Gather not supported\n");
+		return -EINVAL;
+	}
+
+	if (dev->data->dev_conf.rxmode.enable_lro) {
+		RTE_LOG(INFO, PMD, "LRO not supported\n");
+		return -EINVAL;
+	}
+
+	if (dev->data->dev_conf.rxmode.jumbo_frame)
+		dev->data->mtu = dev->data->dev_conf.rxmode.max_rx_pkt_len -
+				 ETHER_HDR_LEN - ETHER_CRC_LEN;
+
+	ret = mrvl_configure_rxqs(priv, dev->data->port_id,
+		dev->data->nb_rx_queues);
+	if (ret < 0)
+		return ret;
+
+
+	priv->ppio_params.outqs_params.num_outqs = dev->data->nb_tx_queues;
+	priv->ppio_params.maintain_stats = 1;
+	priv->nb_rx_queues = dev->data->nb_rx_queues;
+
+	if (dev->data->nb_rx_queues == 1 &&
+	    dev->data->dev_conf.rxmode.mq_mode == ETH_MQ_RX_RSS) {
+		RTE_LOG(WARNING, PMD, "Disabling hash for 1 rx queue\n");
+		priv->ppio_params.inqs_params.hash_type = PP2_PPIO_HASH_T_NONE;
+
+		return 0;
+	}
+
+	return mrvl_configure_rss(priv,
+				  &dev->data->dev_conf.rx_adv_conf.rss_conf);
+}
+
+/**
+ * DPDK callback to change the MTU.
+ *
+ * Setting the MTU affects hardware MRU (packets larger than the MRU
+ * will be dropped).
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mtu
+ *   New MTU.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	/* extra MV_MH_SIZE bytes are required for Marvell tag */
+	uint16_t mru = mtu + MV_MH_SIZE + ETHER_HDR_LEN + ETHER_CRC_LEN;
+	int ret;
+
+	if (mtu < ETHER_MIN_MTU || mru > MRVL_PKT_SIZE_MAX)
+		return -EINVAL;
+
+	ret = pp2_ppio_set_mru(priv->ppio, mru);
+	if (ret)
+		return ret;
+
+	return pp2_ppio_set_mtu(priv->ppio, mtu);
+}
+
+/**
+ * DPDK callback to bring the link up.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_dev_set_link_up(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_enable(priv->ppio);
+	if (ret)
+		return ret;
+
+	/*
+	 * mtu/mru can be updated if pp2_ppio_enable() was called at least once
+	 * as pp2_ppio_enable() changes port->t_mode from default 0 to
+	 * PP2_TRAFFIC_INGRESS_EGRESS.
+	 *
+	 * Set mtu to default DPDK value here.
+	 */
+	ret = mrvl_mtu_set(dev, dev->data->mtu);
+	if (ret)
+		pp2_ppio_disable(priv->ppio);
+
+	dev->data->dev_link.link_status = ETH_LINK_UP;
+
+	return ret;
+}
+
+/**
+ * DPDK callback to bring the link down.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_dev_set_link_down(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_disable(priv->ppio);
+	if (ret)
+		return ret;
+
+	dev->data->dev_link.link_status = ETH_LINK_DOWN;
+
+	return ret;
+}
+
+/**
+ * DPDK callback to start the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, negative errno value on failure.
+ */
+static int
+mrvl_dev_start(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	char match[MRVL_MATCH_LEN];
+	int ret;
+
+	snprintf(match, sizeof(match), "ppio-%d:%d",
+		 priv->pp_id, priv->ppio_id);
+	priv->ppio_params.match = match;
+
+	/*
+	 * Calculate the maximum bpool size for refill feature to 1.5 of the
+	 * configured size. In case the bpool size will exceed this value,
+	 * superfluous buffers will be removed
+	 */
+	priv->bpool_max_size = priv->bpool_init_size +
+			      (priv->bpool_init_size >> 1);
+	/*
+	 * Calculate the minimum bpool size for refill feature as follows:
+	 * 2 default burst sizes multiply by number of rx queues.
+	 * If the bpool size will be below this value, new buffers will
+	 * be added to the pool.
+	 */
+	priv->bpool_min_size = priv->nb_rx_queues * MRVL_BURST_SIZE * 2;
+
+	ret = pp2_ppio_init(&priv->ppio_params, &priv->ppio);
+	if (ret)
+		return ret;
+
+	/*
+	 * In case there are some some stale uc/mc mac addresses flush them
+	 * here. It cannot be done during mrvl_dev_close() as port information
+	 * is already gone at that point (due to pp2_ppio_deinit() in
+	 * mrvl_dev_stop()).
+	 */
+	if (!priv->uc_mc_flushed) {
+		ret = pp2_ppio_flush_mac_addrs(priv->ppio, 1, 1);
+		if (ret) {
+			RTE_LOG(ERR, PMD,
+				"Failed to flush uc/mc filter list\n");
+			goto out;
+		}
+		priv->uc_mc_flushed = 1;
+	}
+
+	if (!priv->vlan_flushed) {
+		ret = pp2_ppio_flush_vlan(priv->ppio);
+		if (ret) {
+			RTE_LOG(ERR, PMD, "Failed to flush vlan list\n");
+			/*
+			 * TODO
+			 * once pp2_ppio_flush_vlan() is supported jump to out
+			 * goto out;
+			 */
+		}
+		priv->vlan_flushed = 1;
+	}
+
+	/* For default QoS config, don't start classifier. */
+	if (mrvl_qos_cfg != NULL) {
+		ret = mrvl_start_qos_mapping(priv);
+		if (ret) {
+			pp2_ppio_deinit(priv->ppio);
+			return ret;
+		}
+	}
+
+	ret = mrvl_dev_set_link_up(dev);
+	if (ret)
+		goto out;
+
+	return 0;
+out:
+	pp2_ppio_deinit(priv->ppio);
+	return ret;
+}
+
+/**
+ * Flush receive queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_flush_rx_queues(struct rte_eth_dev *dev)
+{
+	int i;
+
+	RTE_LOG(INFO, PMD, "Flushing rx queues\n");
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		int ret, num;
+
+		do {
+			struct mrvl_rxq *q = dev->data->rx_queues[i];
+			struct pp2_ppio_desc descs[MRVL_PP2_RXD_MAX];
+
+			num = MRVL_PP2_RXD_MAX;
+			ret = pp2_ppio_recv(q->priv->ppio,
+					    q->priv->rxq_map[q->queue_id].tc,
+					    q->priv->rxq_map[q->queue_id].inq,
+					    descs, (uint16_t *)&num);
+		} while (ret == 0 && num);
+	}
+}
+
+/**
+ * Flush transmit shadow queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_flush_tx_shadow_queues(struct rte_eth_dev *dev)
+{
+	int i;
+
+	RTE_LOG(INFO, PMD, "Flushing tx shadow queues\n");
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		struct mrvl_shadow_txq *sq =
+			&shadow_txqs[dev->data->port_id][i];
+
+		while (sq->tail != sq->head) {
+			uint64_t addr = cookie_addr_high |
+					sq->ent[sq->tail].buff.cookie;
+			rte_pktmbuf_free((struct rte_mbuf *)addr);
+			sq->tail = (sq->tail + 1) & MRVL_PP2_TX_SHADOWQ_MASK;
+		}
+
+		memset(sq, 0, sizeof(*sq));
+	}
+}
+
+/**
+ * Flush hardware bpool (buffer-pool).
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_flush_bpool(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	uint32_t num;
+	int ret;
+
+	ret = pp2_bpool_get_num_buffs(priv->bpool, &num);
+	if (ret) {
+		RTE_LOG(ERR, PMD, "Failed to get bpool buffers number\n");
+		return;
+	}
+
+	while (num--) {
+		struct pp2_buff_inf inf;
+		uint64_t addr;
+
+		ret = pp2_bpool_get_buff(hifs[rte_lcore_id()], priv->bpool,
+					 &inf);
+		if (ret)
+			break;
+
+		addr = cookie_addr_high | inf.cookie;
+		rte_pktmbuf_free((struct rte_mbuf *)addr);
+	}
+}
+
+/**
+ * DPDK callback to stop the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_dev_stop(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	mrvl_dev_set_link_down(dev);
+	mrvl_flush_rx_queues(dev);
+	mrvl_flush_tx_shadow_queues(dev);
+	if (priv->qos_tbl)
+		pp2_cls_qos_tbl_deinit(priv->qos_tbl);
+	pp2_ppio_deinit(priv->ppio);
+	priv->ppio = NULL;
+}
+
+/**
+ * DPDK callback to close the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_dev_close(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	size_t i;
+
+	for (i = 0; i < priv->ppio_params.inqs_params.num_tcs; ++i)
+		if (priv->ppio_params.inqs_params.tcs_params[i].inqs_params) {
+			rte_free(priv->ppio_params.inqs_params.
+				tcs_params[i].inqs_params);
+			priv->ppio_params.inqs_params.
+				tcs_params[i].inqs_params = NULL;
+		}
+
+	mrvl_flush_bpool(dev);
+}
+
+/**
+ * DPDK callback to retrieve physical link information.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param wait_to_complete
+ *   Wait for request completion (ignored).
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_link_update(struct rte_eth_dev *dev, int wait_to_complete __rte_unused)
+{
+	/*
+	 * TODO
+	 * once MUSDK provides necessary API use it here
+	 */
+	struct ethtool_cmd edata;
+	struct ifreq req;
+	int ret, fd;
+
+	edata.cmd = ETHTOOL_GSET;
+
+	strcpy(req.ifr_name, dev->data->name);
+	req.ifr_data = (void *)&edata;
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd == -1)
+		return -EFAULT;
+
+	ret = ioctl(fd, SIOCETHTOOL, &req);
+	if (ret == -1) {
+		close(fd);
+		return -EFAULT;
+	}
+
+	close(fd);
+
+	switch (ethtool_cmd_speed(&edata)) {
+	case SPEED_10:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_10M;
+		break;
+	case SPEED_100:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_100M;
+		break;
+	case SPEED_1000:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_1G;
+		break;
+	case SPEED_10000:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_10G;
+		break;
+	default:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_NONE;
+	}
+
+	dev->data->dev_link.link_duplex = edata.duplex ? ETH_LINK_FULL_DUPLEX :
+							 ETH_LINK_HALF_DUPLEX;
+	dev->data->dev_link.link_autoneg = edata.autoneg ? ETH_LINK_AUTONEG :
+							   ETH_LINK_FIXED;
+
+	return 0;
+}
+
+/**
+ * DPDK callback to enable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_promiscuous_enable(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_set_uc_promisc(priv->ppio, 1);
+	if (ret)
+		RTE_LOG(ERR, PMD, "Failed to enable promiscuous mode\n");
+}
+
+/**
+ * DPDK callback to enable allmulti mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_allmulticast_enable(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_set_mc_promisc(priv->ppio, 1);
+	if (ret)
+		RTE_LOG(ERR, PMD, "Failed enable all-multicast mode\n");
+}
+
+/**
+ * DPDK callback to disable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_set_uc_promisc(priv->ppio, 0);
+	if (ret)
+		RTE_LOG(ERR, PMD, "Failed to disable promiscuous mode\n");
+}
+
+/**
+ * DPDK callback to disable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_allmulticast_disable(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_set_mc_promisc(priv->ppio, 0);
+	if (ret)
+		RTE_LOG(ERR, PMD, "Failed to disable all-multicast mode\n");
+}
+
+/**
+ * DPDK callback to remove a MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param index
+ *   MAC address index.
+ */
+static void
+mrvl_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	char buf[ETHER_ADDR_FMT_SIZE];
+	int ret;
+
+	ret = pp2_ppio_remove_mac_addr(priv->ppio,
+				       dev->data->mac_addrs[index].addr_bytes);
+	if (ret) {
+		ether_format_addr(buf, sizeof(buf),
+				  &dev->data->mac_addrs[index]);
+		RTE_LOG(ERR, PMD, "Failed to remove mac %s\n", buf);
+	}
+}
+
+/**
+ * DPDK callback to add a MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ * @param index
+ *   MAC address index.
+ * @param vmdq
+ *   VMDq pool index to associate address with (unused).
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
+		  uint32_t index, uint32_t vmdq __rte_unused)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	char buf[ETHER_ADDR_FMT_SIZE];
+	int ret;
+
+	if (index == 0)
+		/* For setting index 0, mrvl_mac_addr_set() should be used.*/
+		return -1;
+
+	/*
+	 * Maximum number of uc addresses can be tuned via kernel module mvpp2x
+	 * parameter uc_filter_max. Maximum number of mc addresses is then
+	 * MRVL_MAC_ADDRS_MAX - uc_filter_max. Currently it defaults to 4 and
+	 * 21 respectively.
+	 *
+	 * If more than uc_filter_max uc addresses were added to filter list
+	 * then NIC will switch to promiscuous mode automatically.
+	 *
+	 * If more than MRVL_MAC_ADDRS_MAX - uc_filter_max number mc addresses
+	 * were added to filter list then NIC will switch to all-multicast mode
+	 * automatically.
+	 */
+	ret = pp2_ppio_add_mac_addr(priv->ppio, mac_addr->addr_bytes);
+	if (ret) {
+		ether_format_addr(buf, sizeof(buf), mac_addr);
+		RTE_LOG(ERR, PMD, "Failed to add mac %s\n", buf);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * DPDK callback to set the primary MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ */
+static void
+mrvl_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	pp2_ppio_set_mac_addr(priv->ppio, mac_addr->addr_bytes);
+	/*
+	 * TODO
+	 * Port stops sending packets if pp2_ppio_set_mac_addr()
+	 * was called after pp2_ppio_enable(). As a quick fix issue
+	 * enable port once again.
+	 */
+	pp2_ppio_enable(priv->ppio);
+}
+
+/**
+ * DPDK callback to get device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param stats
+ *   Stats structure output buffer.
+ */
+static void
+mrvl_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct pp2_ppio_statistics ppio_stats;
+	uint64_t drop_mac = 0;
+	unsigned int i, idx, ret;
+
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		struct mrvl_rxq *rxq = dev->data->rx_queues[i];
+		struct pp2_ppio_inq_statistics rx_stats;
+
+		if (!rxq)
+			continue;
+
+		idx = rxq->queue_id;
+		if (unlikely(idx >= RTE_ETHDEV_QUEUE_STAT_CNTRS)) {
+			RTE_LOG(ERR, PMD,
+				"rx queue %d stats out of range (0 - %d)\n",
+				idx, RTE_ETHDEV_QUEUE_STAT_CNTRS - 1);
+			continue;
+		}
+
+		ret = pp2_ppio_inq_get_statistics(priv->ppio,
+			priv->rxq_map[idx].tc, priv->rxq_map[idx].inq,
+			&rx_stats, 0);
+		if (unlikely(ret)) {
+			RTE_LOG(ERR, PMD,
+				"Failed to update rx queue %d stats\n", idx);
+			break;
+		}
+
+		stats->q_ibytes[idx] = rxq->bytes_recv;
+		stats->q_ipackets[idx] = rx_stats.enq_desc - rxq->drop_mac;
+		stats->q_errors[idx] = rx_stats.drop_early +
+				       rx_stats.drop_fullq +
+				       rx_stats.drop_bm +
+				       rxq->drop_mac;
+		stats->ibytes += rxq->bytes_recv;
+		drop_mac += rxq->drop_mac;
+	}
+
+	for (i = 0; i < dev->data->nb_tx_queues; i++) {
+		struct mrvl_txq *txq = dev->data->tx_queues[i];
+		struct pp2_ppio_outq_statistics tx_stats;
+
+		if (!txq)
+			continue;
+
+		idx = txq->queue_id;
+		if (unlikely(idx >= RTE_ETHDEV_QUEUE_STAT_CNTRS)) {
+			RTE_LOG(ERR, PMD,
+				"tx queue %d stats out of range (0 - %d)\n",
+				idx, RTE_ETHDEV_QUEUE_STAT_CNTRS - 1);
+		}
+
+		ret = pp2_ppio_outq_get_statistics(priv->ppio, idx,
+						   &tx_stats, 0);
+		if (unlikely(ret)) {
+			RTE_LOG(ERR, PMD,
+				"Failed to update tx queue %d stats\n", idx);
+			break;
+		}
+
+		stats->q_opackets[idx] = tx_stats.deq_desc;
+		stats->q_obytes[idx] = txq->bytes_sent;
+		stats->obytes += txq->bytes_sent;
+	}
+
+	ret = pp2_ppio_get_statistics(priv->ppio, &ppio_stats, 0);
+	if (unlikely(ret)) {
+		RTE_LOG(ERR, PMD, "Failed to update port statistics\n");
+		return;
+	}
+
+	stats->ipackets += ppio_stats.rx_packets - drop_mac;
+	stats->opackets += ppio_stats.tx_packets;
+	stats->imissed += ppio_stats.rx_fullq_dropped +
+			  ppio_stats.rx_bm_dropped +
+			  ppio_stats.rx_early_dropped +
+			  ppio_stats.rx_fifo_dropped +
+			  ppio_stats.rx_cls_dropped;
+	stats->ierrors = drop_mac;
+}
+
+/**
+ * DPDK callback to clear device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_stats_reset(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int i;
+
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		struct mrvl_rxq *rxq = dev->data->rx_queues[i];
+
+		pp2_ppio_inq_get_statistics(priv->ppio,
+			priv->rxq_map[i].tc, priv->rxq_map[i].inq, NULL, 1);
+		rxq->bytes_recv = 0;
+		rxq->drop_mac = 0;
+	}
+
+	for (i = 0; i < dev->data->nb_tx_queues; i++) {
+		struct mrvl_txq *txq = dev->data->tx_queues[i];
+
+		pp2_ppio_outq_get_statistics(priv->ppio, i, NULL, 1);
+		txq->bytes_sent = 0;
+	}
+
+	pp2_ppio_get_statistics(priv->ppio, NULL, 1);
+}
+
+/**
+ * DPDK callback to get information about the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure (unused).
+ * @param info
+ *   Info structure output buffer.
+ */
+static void
+mrvl_dev_infos_get(struct rte_eth_dev *dev __rte_unused,
+		    struct rte_eth_dev_info *info)
+{
+	info->max_rx_queues = MRVL_PP2_RXQ_MAX;
+	info->max_tx_queues = MRVL_PP2_TXQ_MAX;
+	info->max_mac_addrs = MRVL_MAC_ADDRS_MAX;
+
+	info->rx_desc_lim.nb_max = MRVL_PP2_RXD_MAX;
+	info->rx_desc_lim.nb_min = MRVL_PP2_RXD_MIN;
+	info->rx_desc_lim.nb_align = MRVL_PP2_RXD_ALIGN;
+
+	info->tx_desc_lim.nb_max = MRVL_PP2_TXD_MAX;
+	info->tx_desc_lim.nb_min = MRVL_PP2_TXD_MIN;
+	info->tx_desc_lim.nb_align = MRVL_PP2_TXD_ALIGN;
+
+	info->rx_offload_capa = DEV_RX_OFFLOAD_IPV4_CKSUM |
+				DEV_RX_OFFLOAD_UDP_CKSUM |
+				DEV_RX_OFFLOAD_TCP_CKSUM;
+
+	info->tx_offload_capa = DEV_TX_OFFLOAD_IPV4_CKSUM |
+				DEV_TX_OFFLOAD_UDP_CKSUM |
+				DEV_TX_OFFLOAD_TCP_CKSUM;
+
+	info->flow_type_rss_offloads = ETH_RSS_IPV4 |
+				       ETH_RSS_NONFRAG_IPV4_TCP |
+				       ETH_RSS_NONFRAG_IPV4_UDP;
+
+	/* By default packets are dropped if no descriptors are available */
+	info->default_rxconf.rx_drop_en = 1;
+
+	info->max_rx_pktlen = MRVL_PKT_SIZE_MAX;
+}
+
+/**
+ * Return supported packet types.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure (unused).
+ *
+ * @return
+ *   Const pointer to the table with supported packet types.
+ */
+static const uint32_t *
+mrvl_dev_supported_ptypes_get(struct rte_eth_dev *dev __rte_unused)
+{
+	static const uint32_t ptypes[] = {
+		RTE_PTYPE_L2_ETHER,
+		RTE_PTYPE_L3_IPV4,
+		RTE_PTYPE_L3_IPV4_EXT,
+		RTE_PTYPE_L3_IPV4_EXT_UNKNOWN,
+		RTE_PTYPE_L3_IPV6,
+		RTE_PTYPE_L3_IPV6_EXT,
+		RTE_PTYPE_L2_ETHER_ARP,
+		RTE_PTYPE_L4_TCP,
+		RTE_PTYPE_L4_UDP
+	};
+
+	return ptypes;
+}
+
+/**
+ * DPDK callback to get information about specific receive queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param rx_queue_id
+ *   Receive queue index.
+ * @param qinfo
+ *   Receive queue information structure.
+ */
+static void mrvl_rxq_info_get(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+			      struct rte_eth_rxq_info *qinfo)
+{
+	struct mrvl_rxq *q = dev->data->rx_queues[rx_queue_id];
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int inq = priv->rxq_map[rx_queue_id].inq;
+	int tc = priv->rxq_map[rx_queue_id].tc;
+
+	qinfo->mp = q->mp;
+	qinfo->nb_desc = priv->ppio_params.inqs_params.
+			 tcs_params[tc].inqs_params[inq].size;
+}
+
+/**
+ * DPDK callback to get information about specific transmit queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param tx_queue_id
+ *   Transmit queue index.
+ * @param qinfo
+ *   Transmit queue information structure.
+ */
+static void mrvl_txq_info_get(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+			      struct rte_eth_txq_info *qinfo)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	qinfo->nb_desc =
+		priv->ppio_params.outqs_params.outqs_params[tx_queue_id].size;
+}
+
+/**
+ * DPDK callback to Configure a VLAN filter.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param vlan_id
+ *   VLAN ID to filter.
+ * @param on
+ *   Toggle filter.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	return on ? pp2_ppio_add_vlan(priv->ppio, vlan_id) :
+		    pp2_ppio_remove_vlan(priv->ppio, vlan_id);
+}
+
+/**
+ * Release buffers to hardware bpool (buffer-pool)
+ *
+ * @param rxq
+ *   Receive queue pointer.
+ * @param num
+ *   Number of buffers to release to bpool.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_fill_bpool(struct mrvl_rxq *rxq, int num)
+{
+	struct buff_release_entry entries[MRVL_PP2_TXD_MAX];
+	struct rte_mbuf *mbufs[MRVL_PP2_TXD_MAX];
+	int i, ret;
+	unsigned int core_id = rte_lcore_id();
+	struct pp2_hif *hif = hifs[core_id];
+	struct pp2_bpool *bpool = rxq->priv->bpool;
+
+	ret = rte_pktmbuf_alloc_bulk(rxq->mp, mbufs, num);
+	if (ret)
+		return ret;
+
+	if (cookie_addr_high == MRVL_COOKIE_ADDR_INVALID)
+		cookie_addr_high =
+			(uint64_t)mbufs[0] & MRVL_COOKIE_HIGH_ADDR_MASK;
+
+	for (i = 0; i < num; i++) {
+		if (((uint64_t)mbufs[i] & MRVL_COOKIE_HIGH_ADDR_MASK)
+			!= cookie_addr_high) {
+			RTE_LOG(ERR, PMD,
+				"mbuf virtual addr high 0x%lx out of range\n",
+				(uint64_t)mbufs[i] >> 32);
+			goto out;
+		}
+
+		entries[i].buff.addr =
+			rte_mbuf_data_dma_addr_default(mbufs[i]);
+		entries[i].buff.cookie = (pp2_cookie_t)(uint64_t)mbufs[i];
+		entries[i].bpool = bpool;
+	}
+
+	pp2_bpool_put_buffs(hif, entries, (uint16_t *)&i);
+	mrvl_port_bpool_size[bpool->pp2_id][bpool->id][core_id] += i;
+
+	if (i != num)
+		goto out;
+
+	return 0;
+out:
+	for (; i < num; i++)
+		rte_pktmbuf_free(mbufs[i]);
+
+	return -1;
+}
+
+/**
+ * DPDK callback to configure the receive queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param conf
+ *   Thresholds parameters (unused_).
+ * @param mp
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
+		    unsigned int socket,
+		    const struct rte_eth_rxconf *conf __rte_unused,
+		    struct rte_mempool *mp)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_rxq *rxq;
+	uint32_t min_size,
+		 max_rx_pkt_len = dev->data->dev_conf.rxmode.max_rx_pkt_len;
+	int ret;
+
+	if (priv->rxq_map[idx].tc == MRVL_UNKNOWN_TC) {
+		/*
+		 * Unknown TC mapping, mapping will not have a correct queue.
+		 */
+		RTE_LOG(ERR, PMD, "Unknown TC mapping for queue %hu eth%hhu\n",
+				idx, priv->ppio_id);
+		return -EFAULT;
+	}
+
+	min_size = rte_pktmbuf_data_room_size(mp) - RTE_PKTMBUF_HEADROOM -
+		   MRVL_PKT_EFFEC_OFFS;
+	if (min_size < max_rx_pkt_len) {
+		RTE_LOG(ERR, PMD, "Mbuf size must be increased to %u bytes"
+				  " to hold up to %u bytes of data.\n",
+			max_rx_pkt_len + RTE_PKTMBUF_HEADROOM +
+			MRVL_PKT_EFFEC_OFFS,
+			max_rx_pkt_len);
+		return -EINVAL;
+	}
+
+	if (dev->data->rx_queues[idx]) {
+		rte_free(dev->data->rx_queues[idx]);
+		dev->data->rx_queues[idx] = NULL;
+	}
+
+	rxq = rte_zmalloc_socket("rxq", sizeof(*rxq), 0, socket);
+	if (!rxq)
+		return -ENOMEM;
+
+	rxq->priv = priv;
+	rxq->mp = mp;
+	rxq->cksum_enabled = dev->data->dev_conf.rxmode.hw_ip_checksum;
+	rxq->queue_id = idx;
+	rxq->port_id = dev->data->port_id;
+	mrvl_port_to_bpool_lookup[rxq->port_id] = priv->bpool;
+
+	priv->ppio_params.inqs_params.
+		tcs_params[priv->rxq_map[rxq->queue_id].tc].
+		inqs_params[priv->rxq_map[rxq->queue_id].inq].size = desc;
+
+	ret = mrvl_fill_bpool(rxq, desc);
+	if (ret) {
+		rte_free(rxq);
+		return ret;
+	}
+
+	priv->bpool_init_size += desc;
+
+	dev->data->rx_queues[idx] = rxq;
+
+	return 0;
+}
+
+/**
+ * DPDK callback to release the receive queue.
+ *
+ * @param rxq
+ *   Generic receive queue pointer.
+ */
+static void
+mrvl_rx_queue_release(void *rxq)
+{
+	struct mrvl_rxq *q = rxq;
+	int i, num;
+
+	if (!q)
+		return;
+
+	num = q->priv->ppio_params.inqs_params.
+			tcs_params[q->priv->rxq_map[q->queue_id].tc].
+			inqs_params[q->priv->rxq_map[q->queue_id].inq].size;
+	for (i = 0; i < num; i++) {
+		struct pp2_buff_inf inf;
+		uint64_t addr;
+
+		pp2_bpool_get_buff(hifs[rte_lcore_id()], q->priv->bpool, &inf);
+		addr = cookie_addr_high | inf.cookie;
+		rte_pktmbuf_free((struct rte_mbuf *)addr);
+	}
+
+	rte_free(q);
+}
+
+/**
+ * DPDK callback to configure the transmit queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   Transmit queue index.
+ * @param desc
+ *   Number of descriptors to configure in the queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param conf
+ *   Thresholds parameters (unused).
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
+		    unsigned int socket,
+		    const struct rte_eth_txconf *conf __rte_unused)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_txq *txq;
+
+	if (dev->data->tx_queues[idx]) {
+		rte_free(dev->data->tx_queues[idx]);
+		dev->data->tx_queues[idx] = NULL;
+	}
+
+	txq = rte_zmalloc_socket("txq", sizeof(*txq), 0, socket);
+	if (!txq)
+		return -ENOMEM;
+
+	txq->priv = priv;
+	txq->queue_id = idx;
+	txq->port_id = dev->data->port_id;
+	dev->data->tx_queues[idx] = txq;
+
+	priv->ppio_params.outqs_params.outqs_params[idx].size = desc;
+	priv->ppio_params.outqs_params.outqs_params[idx].weight = 1;
+
+	return 0;
+}
+
+/**
+ * DPDK callback to release the transmit queue.
+ *
+ * @param txq
+ *   Generic transmit queue pointer.
+ */
+static void
+mrvl_tx_queue_release(void *txq)
+{
+	struct mrvl_txq *q = txq;
+
+	if (!q)
+		return;
+
+	rte_free(q);
+}
+
+/**
+ * Update RSS hash configuration
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param rss_conf
+ *   Pointer to RSS configuration.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_rss_hash_update(struct rte_eth_dev *dev,
+		     struct rte_eth_rss_conf *rss_conf)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	return mrvl_configure_rss(priv, rss_conf);
+}
+
+/**
+ * DPDK callback to get RSS hash configuration.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @rss_conf
+ *   Pointer to RSS configuration.
+ *
+ * @return
+ *   Always 0.
+ */
+static int
+mrvl_rss_hash_conf_get(struct rte_eth_dev *dev,
+		       struct rte_eth_rss_conf *rss_conf)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	enum pp2_ppio_hash_type hash_type =
+		priv->ppio_params.inqs_params.hash_type;
+
+	rss_conf->rss_key = NULL;
+
+	if (hash_type == PP2_PPIO_HASH_T_NONE)
+		rss_conf->rss_hf = 0;
+	else if (hash_type == PP2_PPIO_HASH_T_2_TUPLE)
+		rss_conf->rss_hf = ETH_RSS_IPV4;
+	else if (hash_type == PP2_PPIO_HASH_T_5_TUPLE && priv->rss_hf_tcp)
+		rss_conf->rss_hf = ETH_RSS_NONFRAG_IPV4_TCP;
+	else if (hash_type == PP2_PPIO_HASH_T_5_TUPLE && !priv->rss_hf_tcp)
+		rss_conf->rss_hf = ETH_RSS_NONFRAG_IPV4_UDP;
+
+	return 0;
+}
+
+static const struct eth_dev_ops mrvl_ops = {
+	.dev_configure = mrvl_dev_configure,
+	.dev_start = mrvl_dev_start,
+	.dev_stop = mrvl_dev_stop,
+	.dev_set_link_up = mrvl_dev_set_link_up,
+	.dev_set_link_down = mrvl_dev_set_link_down,
+	.dev_close = mrvl_dev_close,
+	.link_update = mrvl_link_update,
+	.promiscuous_enable = mrvl_promiscuous_enable,
+	.allmulticast_enable = mrvl_allmulticast_enable,
+	.promiscuous_disable = mrvl_promiscuous_disable,
+	.allmulticast_disable = mrvl_allmulticast_disable,
+	.mac_addr_remove = mrvl_mac_addr_remove,
+	.mac_addr_add = mrvl_mac_addr_add,
+	.mac_addr_set = mrvl_mac_addr_set,
+	.mtu_set = mrvl_mtu_set,
+	.stats_get = mrvl_stats_get,
+	.stats_reset = mrvl_stats_reset,
+	.dev_infos_get = mrvl_dev_infos_get,
+	.dev_supported_ptypes_get = mrvl_dev_supported_ptypes_get,
+	.rxq_info_get = mrvl_rxq_info_get,
+	.txq_info_get = mrvl_txq_info_get,
+	.vlan_filter_set = mrvl_vlan_filter_set,
+	.rx_queue_setup = mrvl_rx_queue_setup,
+	.rx_queue_release = mrvl_rx_queue_release,
+	.tx_queue_setup = mrvl_tx_queue_setup,
+	.tx_queue_release = mrvl_tx_queue_release,
+	.rss_hash_update = mrvl_rss_hash_update,
+	.rss_hash_conf_get = mrvl_rss_hash_conf_get,
+};
+
+/**
+ * Return packet type information and l3/l4 offsets.
+ *
+ * @param desc
+ *   Pointer to the received packet descriptor.
+ * @param l3_offset
+ *   l3 packet offset.
+ * @param l4_offset
+ *   l4 packet offset.
+ *
+ * @return
+ *   Packet type information.
+ */
+static inline uint32_t
+mrvl_desc_to_packet_type_and_offset(struct pp2_ppio_desc *desc,
+				    uint8_t *l3_offset, uint8_t *l4_offset)
+{
+	enum pp2_inq_l3_type l3_type;
+	enum pp2_inq_l4_type l4_type;
+	uint64_t packet_type;
+
+	pp2_ppio_inq_desc_get_l3_info(desc, &l3_type, l3_offset);
+	pp2_ppio_inq_desc_get_l4_info(desc, &l4_type, l4_offset);
+
+	packet_type = RTE_PTYPE_L2_ETHER;
+
+	switch (l3_type) {
+	case PP2_INQ_L3_TYPE_IPV4_NO_OPTS:
+		packet_type |= RTE_PTYPE_L3_IPV4;
+		break;
+	case PP2_INQ_L3_TYPE_IPV4_OK:
+		packet_type |= RTE_PTYPE_L3_IPV4_EXT;
+		break;
+	case PP2_INQ_L3_TYPE_IPV4_TTL_ZERO:
+		packet_type |= RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
+		break;
+	case PP2_INQ_L3_TYPE_IPV6_NO_EXT:
+		packet_type |= RTE_PTYPE_L3_IPV6;
+		break;
+	case PP2_INQ_L3_TYPE_IPV6_EXT:
+		packet_type |= RTE_PTYPE_L3_IPV6_EXT;
+		break;
+	case PP2_INQ_L3_TYPE_ARP:
+		packet_type |= RTE_PTYPE_L2_ETHER_ARP;
+		/*
+		 * In case of ARP l4_offset is set to wrong value.
+		 * Set it to proper one so that later on mbuf->l3_len can be
+		 * calculated subtracting l4_offset and l3_offset.
+		 */
+		*l4_offset = *l3_offset + MRVL_ARP_LENGTH;
+		break;
+	default:
+		RTE_LOG(DEBUG, PMD, "Failed to recognise l3 packet type\n");
+		break;
+	}
+
+	switch (l4_type) {
+	case PP2_INQ_L4_TYPE_TCP:
+		packet_type |= RTE_PTYPE_L4_TCP;
+		break;
+	case PP2_INQ_L4_TYPE_UDP:
+		packet_type |= RTE_PTYPE_L4_UDP;
+		break;
+	default:
+		RTE_LOG(DEBUG, PMD, "Failed to recognise l4 packet type\n");
+		break;
+	}
+
+	return packet_type;
+}
+
+/**
+ * Get offload information from the received packet descriptor.
+ *
+ * @param desc
+ *   Pointer to the received packet descriptor.
+ *
+ * @return
+ *   Mbuf offload flags.
+ */
+static inline uint64_t
+mrvl_desc_to_ol_flags(struct pp2_ppio_desc *desc)
+{
+	uint64_t flags;
+	enum pp2_inq_desc_status status;
+
+	status = pp2_ppio_inq_desc_get_l3_pkt_error(desc);
+	if (unlikely(status != PP2_DESC_ERR_OK))
+		flags = PKT_RX_IP_CKSUM_BAD;
+	else
+		flags = PKT_RX_IP_CKSUM_GOOD;
+
+	status = pp2_ppio_inq_desc_get_l4_pkt_error(desc);
+	if (unlikely(status != PP2_DESC_ERR_OK))
+		flags |= PKT_RX_L4_CKSUM_BAD;
+	else
+		flags |= PKT_RX_L4_CKSUM_GOOD;
+
+	return flags;
+}
+
+/**
+ * DPDK callback for receive.
+ *
+ * @param rxq
+ *   Generic pointer to the receive queue.
+ * @param rx_pkts
+ *   Array to store received packets.
+ * @param nb_pkts
+ *   Maximum number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully received.
+ */
+static uint16_t
+mrvl_rx_pkt_burst(void *rxq, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
+{
+	struct mrvl_rxq *q = rxq;
+	struct pp2_ppio_desc descs[nb_pkts];
+	struct pp2_bpool *bpool;
+	int i, ret, rx_done = 0;
+	int num;
+	unsigned int core_id = rte_lcore_id();
+
+	if (unlikely(!q->priv->ppio))
+		return 0;
+
+	bpool = q->priv->bpool;
+
+	ret = pp2_ppio_recv(q->priv->ppio,
+			q->priv->rxq_map[q->queue_id].tc,
+			q->priv->rxq_map[q->queue_id].inq,
+			descs,
+			&nb_pkts);
+	if (unlikely(ret < 0)) {
+		RTE_LOG(ERR, PMD, "Failed to receive packets\n");
+		return 0;
+	}
+	mrvl_port_bpool_size[bpool->pp2_id][bpool->id][core_id] -= nb_pkts;
+
+	for (i = 0; i < nb_pkts; i++) {
+		struct rte_mbuf *mbuf;
+		uint8_t l3_offset, l4_offset;
+		enum pp2_inq_desc_status status;
+		uint64_t addr;
+
+		if (likely((nb_pkts - i) > MRVL_MUSDK_PREFETCH_SHIFT)) {
+			struct pp2_ppio_desc *pref_desc;
+			u64 pref_addr;
+
+			pref_desc = &descs[i + MRVL_MUSDK_PREFETCH_SHIFT];
+			pref_addr = cookie_addr_high |
+				    pp2_ppio_inq_desc_get_cookie(pref_desc);
+			rte_mbuf_prefetch_part1((struct rte_mbuf *)(pref_addr));
+			rte_mbuf_prefetch_part2((struct rte_mbuf *)(pref_addr));
+		}
+
+		addr = cookie_addr_high |
+		       pp2_ppio_inq_desc_get_cookie(&descs[i]);
+		mbuf = (struct rte_mbuf *)addr;
+		rte_pktmbuf_reset(mbuf);
+
+		/* drop packet in case of mac, overrun or resource error */
+		status = pp2_ppio_inq_desc_get_l2_pkt_error(&descs[i]);
+		if (unlikely(status != PP2_DESC_ERR_OK)) {
+			struct pp2_buff_inf binf = {
+				.addr = rte_mbuf_data_dma_addr_default(mbuf),
+				.cookie = (pp2_cookie_t)(uint64_t)mbuf,
+			};
+
+			pp2_bpool_put_buff(hifs[core_id], bpool, &binf);
+			mrvl_port_bpool_size
+				[bpool->pp2_id][bpool->id][core_id]++;
+			q->drop_mac++;
+			continue;
+		}
+
+		mbuf->data_off += MRVL_PKT_EFFEC_OFFS;
+		mbuf->pkt_len = pp2_ppio_inq_desc_get_pkt_len(&descs[i]);
+		mbuf->data_len = mbuf->pkt_len;
+		mbuf->port = q->port_id;
+		mbuf->packet_type =
+			mrvl_desc_to_packet_type_and_offset(&descs[i],
+							    &l3_offset,
+							    &l4_offset);
+		mbuf->l2_len = l3_offset;
+		mbuf->l3_len = l4_offset - l3_offset;
+
+		if (likely(q->cksum_enabled))
+			mbuf->ol_flags = mrvl_desc_to_ol_flags(&descs[i]);
+
+		rx_pkts[rx_done++] = mbuf;
+		q->bytes_recv += mbuf->pkt_len;
+	}
+
+	if (rte_spinlock_trylock(&q->priv->lock) == 1) {
+		num = mrvl_get_bpool_size(bpool->pp2_id, bpool->id);
+
+		if (unlikely(num <= q->priv->bpool_min_size ||
+			 (!rx_done && num < q->priv->bpool_init_size))) {
+			ret = mrvl_fill_bpool(q, MRVL_BURST_SIZE);
+			if (ret)
+				RTE_LOG(ERR, PMD, "Failed to fill bpool\n");
+		} else if (unlikely(num > q->priv->bpool_max_size)) {
+			int i;
+			int pkt_to_remove = num - q->priv->bpool_init_size;
+			struct rte_mbuf *mbuf;
+			struct pp2_buff_inf buff;
+
+			RTE_LOG(DEBUG, PMD, "\nport-%d:%d: bpool %d oversize -"
+				" remove %d buffers (pool size: %d -> %d)\n",
+				bpool->pp2_id, q->priv->ppio->port_id,
+				bpool->id, pkt_to_remove, num,
+				q->priv->bpool_init_size);
+
+			for (i = 0; i < pkt_to_remove; i++) {
+				pp2_bpool_get_buff(hifs[core_id], bpool, &buff);
+				mbuf = (struct rte_mbuf *)
+					(cookie_addr_high | buff.cookie);
+				rte_pktmbuf_free(mbuf);
+			}
+			mrvl_port_bpool_size
+				[bpool->pp2_id][bpool->id][core_id] -=
+								pkt_to_remove;
+		}
+		rte_spinlock_unlock(&q->priv->lock);
+	}
+
+	return rx_done;
+}
+
+/**
+ * Prepare offload information.
+ *
+ * @param ol_flags
+ *   Offload flags.
+ * @param packet_type
+ *   Packet type bitfield.
+ * @param l3_type
+ *   Pointer to the pp2_ouq_l3_type structure.
+ * @param l4_type
+ *   Pointer to the pp2_outq_l4_type structure.
+ * @param gen_l3_cksum
+ *   Will be set to 1 in case l3 checksum is computed.
+ * @param l4_cksum
+ *   Will be set to 1 in case l4 checksum is computed.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static inline int
+mrvl_prepare_proto_info(uint64_t ol_flags, uint32_t packet_type,
+			enum pp2_outq_l3_type *l3_type,
+			enum pp2_outq_l4_type *l4_type,
+			int *gen_l3_cksum,
+			int *gen_l4_cksum)
+{
+	/*
+	 * Based on ol_flags prepare information
+	 * for pp2_ppio_outq_desc_set_proto_info() which setups descriptor
+	 * for offloading.
+	 */
+	if (ol_flags & PKT_TX_IPV4) {
+		*l3_type = PP2_OUTQ_L3_TYPE_IPV4;
+		*gen_l3_cksum = ol_flags & PKT_TX_IP_CKSUM ? 1 : 0;
+	} else if (ol_flags & PKT_TX_IPV6) {
+		*l3_type = PP2_OUTQ_L3_TYPE_IPV6;
+		/* no checksum for ipv6 header */
+		*gen_l3_cksum = 0;
+	} else {
+		/* if something different then stop processing */
+		return -1;
+	}
+
+	ol_flags &= PKT_TX_L4_MASK;
+	if ((packet_type & RTE_PTYPE_L4_TCP) &&
+	    ol_flags == PKT_TX_TCP_CKSUM) {
+		*l4_type = PP2_OUTQ_L4_TYPE_TCP;
+		*gen_l4_cksum = 1;
+	} else if ((packet_type & RTE_PTYPE_L4_UDP) &&
+		   (ol_flags == PKT_TX_UDP_CKSUM)) {
+		*l4_type = PP2_OUTQ_L4_TYPE_UDP;
+		*gen_l4_cksum = 1;
+	} else {
+		*l4_type = PP2_OUTQ_L4_TYPE_OTHER;
+		/* no checksum for other type */
+		*gen_l4_cksum = 0;
+	}
+
+	return 0;
+}
+
+/**
+ * Release already sent buffers to bpool (buffer-pool).
+ *
+ * @param ppio
+ *   Pointer to the port structure.
+ * @param hif
+ *   Pointer to the MUSDK hardware interface.
+ * @param sq
+ *   Pointer to the shadow queue.
+ * @param qid
+ *   Queue id number.
+ * @param force
+ *   Force releasing packets.
+ */
+static inline void
+mrvl_free_sent_buffers(struct pp2_ppio *ppio, struct pp2_hif *hif,
+			struct mrvl_shadow_txq *sq, int qid, int force)
+{
+	struct buff_release_entry *entry;
+	uint16_t nb_done = 0, num = 0, skip_bufs = 0;
+	int i, core_id = rte_lcore_id();
+
+	pp2_ppio_get_num_outq_done(ppio, hif, qid, &nb_done);
+
+	sq->num_to_release += nb_done;
+
+	if (likely(!force &&
+		   sq->num_to_release < MRVL_PP2_BUF_RELEASE_BURST_SIZE))
+		return;
+
+	nb_done = sq->num_to_release;
+	sq->num_to_release = 0;
+
+	for (i = 0; i < nb_done; i++) {
+		entry = &sq->ent[sq->tail + num];
+		if (unlikely(!entry->buff.addr)) {
+			RTE_LOG(ERR, PMD,
+				"Shadow memory @%d: cookie(%lx), pa(%lx)!\n",
+				sq->tail, (u64)entry->buff.cookie,
+				(u64)entry->buff.addr);
+			skip_bufs = 1;
+			goto skip;
+		}
+
+		if (unlikely(!entry->bpool)) {
+			struct rte_mbuf *mbuf;
+
+			mbuf = (struct rte_mbuf *)
+			       (cookie_addr_high | entry->buff.cookie);
+			rte_pktmbuf_free(mbuf);
+			skip_bufs = 1;
+			goto skip;
+		}
+
+		mrvl_port_bpool_size
+			[entry->bpool->pp2_id][entry->bpool->id][core_id]++;
+		num++;
+		if (unlikely(sq->tail + num == MRVL_PP2_TX_SHADOWQ_SIZE))
+			goto skip;
+		continue;
+skip:
+		if (likely(num))
+			pp2_bpool_put_buffs(hif, &sq->ent[sq->tail], &num);
+		num += skip_bufs;
+		sq->tail = (sq->tail + num) & MRVL_PP2_TX_SHADOWQ_MASK;
+		sq->size -= num;
+		num = 0;
+	}
+
+	if (likely(num)) {
+		pp2_bpool_put_buffs(hif, &sq->ent[sq->tail], &num);
+		sq->tail = (sq->tail + num) & MRVL_PP2_TX_SHADOWQ_MASK;
+		sq->size -= num;
+	}
+}
+
+/**
+ * DPDK callback for transmit.
+ *
+ * @param txq
+ *   Generic pointer transmit queue.
+ * @param tx_pkts
+ *   Packets to transmit.
+ * @param nb_pkts
+ *   Number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully transmitted.
+ */
+static uint16_t
+mrvl_tx_pkt_burst(void *txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+	struct mrvl_txq *q = txq;
+	struct mrvl_shadow_txq *sq = &shadow_txqs[q->port_id][rte_lcore_id()];
+	struct pp2_hif *hif = hifs[rte_lcore_id()];
+	struct pp2_ppio_desc descs[nb_pkts];
+	int i, ret, bytes_sent = 0;
+	uint16_t num, sq_free_size;
+	uint64_t addr;
+
+	if (unlikely(!q->priv->ppio))
+		return 0;
+
+	if (sq->size)
+		mrvl_free_sent_buffers(q->priv->ppio, hif, sq, q->queue_id, 0);
+
+	sq_free_size = MRVL_PP2_TX_SHADOWQ_SIZE - sq->size - 1;
+	if (unlikely(nb_pkts > sq_free_size)) {
+		RTE_LOG(DEBUG, PMD,
+			"No room in shadow queue for %d packets!!!"
+			"%d packets will be sent.\n",
+			nb_pkts, sq_free_size);
+		nb_pkts = sq_free_size;
+	}
+
+	for (i = 0; i < nb_pkts; i++) {
+		struct rte_mbuf *mbuf = tx_pkts[i];
+		int gen_l3_cksum, gen_l4_cksum;
+		enum pp2_outq_l3_type l3_type;
+		enum pp2_outq_l4_type l4_type;
+
+		if (likely((nb_pkts - i) > MRVL_MUSDK_PREFETCH_SHIFT)) {
+			struct rte_mbuf *pref_pkt_hdr;
+
+			pref_pkt_hdr = tx_pkts[i + MRVL_MUSDK_PREFETCH_SHIFT];
+			rte_mbuf_prefetch_part1(pref_pkt_hdr);
+			rte_mbuf_prefetch_part2(pref_pkt_hdr);
+		}
+
+		sq->ent[sq->head].buff.cookie = (pp2_cookie_t)(uint64_t)mbuf;
+		sq->ent[sq->head].buff.addr =
+			rte_mbuf_data_dma_addr_default(mbuf);
+		sq->ent[sq->head].bpool =
+			(unlikely(mbuf->port == 0xff || mbuf->refcnt > 1)) ?
+			 NULL : mrvl_port_to_bpool_lookup[mbuf->port];
+		sq->head = (sq->head + 1) & MRVL_PP2_TX_SHADOWQ_MASK;
+		sq->size++;
+
+		pp2_ppio_outq_desc_reset(&descs[i]);
+		pp2_ppio_outq_desc_set_phys_addr(&descs[i],
+						 rte_pktmbuf_mtophys(mbuf));
+		pp2_ppio_outq_desc_set_pkt_offset(&descs[i], 0);
+		pp2_ppio_outq_desc_set_pkt_len(&descs[i],
+					       rte_pktmbuf_pkt_len(mbuf));
+
+		bytes_sent += rte_pktmbuf_pkt_len(mbuf);
+		/*
+		 * in case unsupported ol_flags were passed
+		 * do not update descriptor offload information
+		 */
+		ret = mrvl_prepare_proto_info(mbuf->ol_flags, mbuf->packet_type,
+					      &l3_type, &l4_type, &gen_l3_cksum,
+					      &gen_l4_cksum);
+		if (unlikely(ret))
+			continue;
+
+		pp2_ppio_outq_desc_set_proto_info(&descs[i], l3_type, l4_type,
+						  mbuf->l2_len,
+						  mbuf->l2_len + mbuf->l3_len,
+						  gen_l3_cksum, gen_l4_cksum);
+	}
+
+	num = nb_pkts;
+	pp2_ppio_send(q->priv->ppio, hif, q->queue_id,
+			    descs, &nb_pkts);
+	/* number of packets that were not sent */
+	if (unlikely(num > nb_pkts)) {
+		for (i = nb_pkts; i < num; i++) {
+			sq->head = (MRVL_PP2_TX_SHADOWQ_SIZE + sq->head - 1) &
+				MRVL_PP2_TX_SHADOWQ_MASK;
+			addr = cookie_addr_high |
+			       sq->ent[sq->head].buff.cookie;
+			bytes_sent -=
+				rte_pktmbuf_pkt_len((struct rte_mbuf *)addr);
+		}
+		sq->size -= num - nb_pkts;
+	}
+
+	q->bytes_sent += bytes_sent;
+
+	return nb_pkts;
+}
+
+/**
+ * Initialize packet processor.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_init_pp2(void)
+{
+	struct pp2_init_params init_params;
+
+	memset(&init_params, 0, sizeof(init_params));
+	init_params.hif_reserved_map = MRVL_MUSDK_HIFS_RESERVED;
+	init_params.bm_pool_reserved_map = MRVL_MUSDK_BPOOLS_RESERVED;
+	init_params.rss_tbl_reserved_map = MRVL_MUSDK_RSS_RESERVED;
+
+	return pp2_init(&init_params);
+}
+
+/**
+ * Deinitialize packet processor.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static void
+mrvl_deinit_pp2(void)
+{
+	pp2_deinit();
+}
+
+/**
+ * Create private device structure.
+ *
+ * @param dev_name
+ *   Pointer to the port name passed in the initialization parameters.
+ *
+ * @return
+ *   Pointer to the newly allocated private device structure.
+ */
+static struct mrvl_priv *
+mrvl_priv_create(const char *dev_name)
+{
+	struct pp2_bpool_params bpool_params;
+	char match[MRVL_MATCH_LEN];
+	struct mrvl_priv *priv;
+	int ret, bpool_bit;
+
+	priv = rte_zmalloc_socket(dev_name, sizeof(*priv), 0, rte_socket_id());
+	if (!priv)
+		return NULL;
+
+	ret = pp2_netdev_get_ppio_info((char *)(uintptr_t)dev_name,
+				       &priv->pp_id, &priv->ppio_id);
+	if (ret)
+		goto out_free_priv;
+
+	bpool_bit = mrvl_reserve_bit(&used_bpools[priv->pp_id],
+			PP2_BPOOL_NUM_POOLS);
+	if (bpool_bit < 0)
+		goto out_free_priv;
+	priv->bpool_bit = bpool_bit;
+
+	snprintf(match, sizeof(match), "pool-%d:%d", priv->pp_id,
+		 priv->bpool_bit);
+	memset(&bpool_params, 0, sizeof(bpool_params));
+	bpool_params.match = match;
+	bpool_params.buff_len = MRVL_PKT_SIZE_MAX + MRVL_PKT_EFFEC_OFFS;
+	ret = pp2_bpool_init(&bpool_params, &priv->bpool);
+	if (ret)
+		goto out_clear_bpool_bit;
+
+	priv->ppio_params.type = PP2_PPIO_T_NIC;
+	rte_spinlock_init(&priv->lock);
+
+	return priv;
+out_clear_bpool_bit:
+	used_bpools[priv->pp_id] &= ~(1 << priv->bpool_bit);
+out_free_priv:
+	rte_free(priv);
+	return NULL;
+}
+
+/**
+ * Create device representing Ethernet port.
+ *
+ * @param name
+ *   Pointer to the port's name.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_eth_dev_create(struct rte_vdev_device *vdev, const char *name)
+{
+	int ret, fd = socket(AF_INET, SOCK_DGRAM, 0);
+	struct rte_eth_dev *eth_dev;
+	struct mrvl_priv *priv;
+	struct ifreq req;
+
+	eth_dev = rte_eth_dev_allocate(name);
+	if (!eth_dev)
+		return -ENOMEM;
+
+	priv = mrvl_priv_create(name);
+	if (!priv) {
+		ret = -ENOMEM;
+		goto out_free_dev;
+	}
+
+	eth_dev->data->mac_addrs = rte_zmalloc("mac_addrs",
+			ETHER_ADDR_LEN * MRVL_MAC_ADDRS_MAX, 0);
+	if (!eth_dev->data->mac_addrs) {
+		RTE_LOG(ERR, PMD, "Failed to allocate space for eth addrs\n");
+		ret = -ENOMEM;
+		goto out_free_priv;
+	}
+
+	memset(&req, 0, sizeof(req));
+	strcpy(req.ifr_name, name);
+	ret = ioctl(fd, SIOCGIFHWADDR, &req);
+	if (ret)
+		goto out_free_mac;
+
+	memcpy(eth_dev->data->mac_addrs[0].addr_bytes,
+	       req.ifr_addr.sa_data, ETHER_ADDR_LEN);
+
+
+	eth_dev->rx_pkt_burst = mrvl_rx_pkt_burst;
+	eth_dev->tx_pkt_burst = mrvl_tx_pkt_burst;
+	eth_dev->data->dev_private = priv;
+	eth_dev->device = &vdev->device;
+	eth_dev->dev_ops = &mrvl_ops;
+
+	return 0;
+out_free_mac:
+	rte_free(eth_dev->data->mac_addrs);
+out_free_dev:
+	rte_eth_dev_release_port(eth_dev);
+out_free_priv:
+	rte_free(priv);
+
+	return ret;
+}
+
+/**
+ * Cleanup previously created device representing Ethernet port.
+ *
+ * @param name
+ *   Pointer to the port name.
+ */
+static void
+mrvl_eth_dev_destroy(const char *name)
+{
+	struct rte_eth_dev *eth_dev;
+	struct mrvl_priv *priv;
+
+	eth_dev = rte_eth_dev_allocated(name);
+	if (!eth_dev)
+		return;
+
+	priv = eth_dev->data->dev_private;
+	pp2_bpool_deinit(priv->bpool);
+	rte_free(priv);
+	rte_free(eth_dev->data->mac_addrs);
+	rte_eth_dev_release_port(eth_dev);
+}
+
+/**
+ * Callback used by rte_kvargs_process() during argument parsing.
+ *
+ * @param key
+ *   Pointer to the parsed key (unused).
+ * @param value
+ *   Pointer to the parsed value.
+ * @param extra_args
+ *   Pointer to the extra arguments which contains address of the
+ *   table of pointers to parsed interface names.
+ *
+ * @return
+ *   Always 0.
+ */
+static int
+mrvl_get_ifnames(const char *key __rte_unused, const char *value,
+		 void *extra_args)
+{
+	const char **ifnames = extra_args;
+
+	ifnames[mrvl_ports_nb++] = value;
+
+	return 0;
+}
+
+/**
+ * Initialize per-lcore MUSDK hardware interfaces (hifs).
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_init_hifs(void)
+{
+	struct pp2_hif_params params;
+	char match[MRVL_MATCH_LEN];
+	int i, ret;
+
+	RTE_LCORE_FOREACH(i) {
+		ret = mrvl_reserve_bit(&used_hifs, MRVL_MUSDK_HIFS_MAX);
+		if (ret < 0)
+			return ret;
+
+		snprintf(match, sizeof(match), "hif-%d", ret);
+		memset(&params, 0, sizeof(params));
+		params.match = match;
+		params.out_size = MRVL_PP2_AGGR_TXQD_MAX;
+		ret = pp2_hif_init(&params, &hifs[i]);
+		if (ret) {
+			RTE_LOG(ERR, PMD, "Failed to initialize hif %d\n", i);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Deinitialize per-lcore MUSDK hardware interfaces (hifs).
+ */
+static void
+mrvl_deinit_hifs(void)
+{
+	int i;
+
+	RTE_LCORE_FOREACH(i) {
+		if (hifs[i])
+			pp2_hif_deinit(hifs[i]);
+	}
+}
+
+static void mrvl_set_first_last_cores(int core_id)
+{
+	if (core_id < mrvl_lcore_first)
+		mrvl_lcore_first = core_id;
+
+	if (core_id > mrvl_lcore_last)
+		mrvl_lcore_last = core_id;
+}
+
+/**
+ * DPDK callback to register the virtual device.
+ *
+ * @param vdev
+ *   Pointer to the virtual device.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+rte_pmd_mrvl_probe(struct rte_vdev_device *vdev)
+{
+	struct rte_kvargs *kvlist;
+	const char *ifnames[PP2_NUM_ETH_PPIO * PP2_NUM_PKT_PROC];
+	int ret = -EINVAL;
+	uint32_t i, ifnum, cfgnum, core_id;
+	const char *params;
+
+	params = rte_vdev_device_args(vdev);
+	if (!params)
+		return -EINVAL;
+
+	kvlist = rte_kvargs_parse(params, valid_args);
+	if (!kvlist)
+		return -EINVAL;
+
+	ifnum = rte_kvargs_count(kvlist, MRVL_IFACE_NAME_ARG);
+	if (ifnum > RTE_DIM(ifnames))
+		goto out_free_kvlist;
+
+	rte_kvargs_process(kvlist, MRVL_IFACE_NAME_ARG,
+			   mrvl_get_ifnames, &ifnames);
+
+	cfgnum = rte_kvargs_count(kvlist, MRVL_CFG_ARG);
+	if (cfgnum > 1) {
+		RTE_LOG(ERR, PMD, "Cannot handle more than one config file!\n");
+		goto out_free_kvlist;
+	} else if (cfgnum == 1) {
+		rte_kvargs_process(kvlist, MRVL_CFG_ARG,
+				   mrvl_get_qoscfg, &mrvl_qos_cfg);
+	}
+
+	/*
+	 * ret == -EEXIST is correct, it means DMA
+	 * has been already initialized (by another PMD).
+	 */
+	ret = mv_sys_dma_mem_init(RTE_MRVL_MUSDK_DMA_MEMSIZE);
+	if (ret < 0 && (ret != -EEXIST))
+		goto out_free_kvlist;
+
+	ret = mrvl_init_pp2();
+	if (ret) {
+		RTE_LOG(ERR, PMD, "Failed to init PP!\n");
+		goto out_deinit_dma;
+	}
+
+	ret = mrvl_init_hifs();
+	if (ret)
+		goto out_deinit_hifs;
+
+	for (i = 0; i < ifnum; i++) {
+		RTE_LOG(INFO, PMD, "Creating %s\n", ifnames[i]);
+		ret = mrvl_eth_dev_create(vdev, ifnames[i]);
+		if (ret)
+			goto out_cleanup;
+	}
+
+	rte_kvargs_free(kvlist);
+
+	memset(mrvl_port_bpool_size, 0, sizeof(mrvl_port_bpool_size));
+
+	mrvl_lcore_first = RTE_MAX_LCORE;
+	mrvl_lcore_last = 0;
+
+	RTE_LCORE_FOREACH(core_id) {
+		mrvl_set_first_last_cores(core_id);
+	}
+
+	return 0;
+out_cleanup:
+	for (; i > 0; i--)
+		mrvl_eth_dev_destroy(ifnames[i]);
+out_deinit_hifs:
+	mrvl_deinit_hifs();
+	mrvl_deinit_pp2();
+out_deinit_dma:
+	mv_sys_dma_mem_destroy();
+out_free_kvlist:
+	rte_kvargs_free(kvlist);
+
+	return ret;
+}
+
+/**
+ * DPDK callback to remove virtual device.
+ *
+ * @param vdev
+ *   Pointer to the removed virtual device.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+rte_pmd_mrvl_remove(struct rte_vdev_device *vdev)
+{
+	int i;
+	const char *name;
+
+	name = rte_vdev_device_name(vdev);
+	if (!name)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Removing %s\n", name);
+
+	for (i = 0; i < rte_eth_dev_count(); i++) {
+		char ifname[RTE_ETH_NAME_MAX_LEN];
+
+		rte_eth_dev_get_name_by_port(i, ifname);
+		mrvl_eth_dev_destroy(ifname);
+	}
+
+	mrvl_deinit_hifs();
+	mrvl_deinit_pp2();
+	mv_sys_dma_mem_destroy();
+
+	return 0;
+}
+
+static struct rte_vdev_driver pmd_mrvl_drv = {
+	.probe = rte_pmd_mrvl_probe,
+	.remove = rte_pmd_mrvl_remove,
+};
+
+RTE_PMD_REGISTER_VDEV(net_mrvl, pmd_mrvl_drv);
+RTE_PMD_REGISTER_ALIAS(net_mrvl, eth_mrvl);
diff --git a/drivers/net/mrvl/mrvl_ethdev.h b/drivers/net/mrvl/mrvl_ethdev.h
new file mode 100644
index 0000000..9fc9624
--- /dev/null
+++ b/drivers/net/mrvl/mrvl_ethdev.h
@@ -0,0 +1,115 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Semihalf. 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 Semihalf 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 _MRVL_ETHDEV_H_
+#define _MRVL_ETHDEV_H_
+
+#include <rte_spinlock.h>
+#include <drivers/mv_pp2_cls.h>
+#include <drivers/mv_pp2_ppio.h>
+
+
+/** Maximum number of rx queues per port */
+#define MRVL_PP2_RXQ_MAX 32
+
+/** Maximum number of tx queues per port */
+#define MRVL_PP2_TXQ_MAX 8
+
+/** Minimum number of descriptors in tx queue */
+#define MRVL_PP2_TXD_MIN 16
+
+/** Maximum number of descriptors in tx queue */
+#define MRVL_PP2_TXD_MAX 2048
+
+/** Tx queue descriptors alignment */
+#define MRVL_PP2_TXD_ALIGN 16
+
+/** Minimum number of descriptors in rx queue */
+#define MRVL_PP2_RXD_MIN 16
+
+/** Maximum number of descriptors in rx queue */
+#define MRVL_PP2_RXD_MAX 2048
+
+/** Rx queue descriptors alignment */
+#define MRVL_PP2_RXD_ALIGN 16
+
+/** Maximum number of descriptors in tx aggregated queue */
+#define MRVL_PP2_AGGR_TXQD_MAX 2048
+
+/** Maximum number of Traffic Classes. */
+#define MRVL_PP2_TC_MAX 8
+
+/** Packet offset inside RX buffer. */
+#define MRVL_PKT_OFFS 64
+
+/** Maximum number of descriptors in shadow queue. Must be power of 2 */
+#define MRVL_PP2_TX_SHADOWQ_SIZE MRVL_PP2_TXD_MAX
+
+/** Shadow queue size mask (since shadow queue size is power of 2) */
+#define MRVL_PP2_TX_SHADOWQ_MASK (MRVL_PP2_TX_SHADOWQ_SIZE - 1)
+
+/** Minimum number of sent buffers to release from shadow queue to BM */
+#define MRVL_PP2_BUF_RELEASE_BURST_SIZE	64
+
+struct mrvl_priv {
+	/* Hot fields, used in fast path. */
+	struct pp2_bpool *bpool;  /**< BPool pointer */
+	struct pp2_ppio	*ppio;    /**< Port handler pointer */
+	rte_spinlock_t lock;	  /**< Spinlock for checking bpool status */
+	uint16_t bpool_max_size;  /**< BPool maximum size */
+	uint16_t bpool_min_size;  /**< BPool minimum size  */
+	uint16_t bpool_init_size; /**< Configured BPool size  */
+
+	/** Mapping for DPDK rx queue->(TC, MRVL relative inq) */
+	struct {
+		uint8_t tc;  /**< Traffic Class */
+		uint8_t inq; /**< Relative in-queue number */
+	} rxq_map[MRVL_PP2_RXQ_MAX] __rte_cache_aligned;
+
+	/* Configuration data, used sporadically. */
+	uint8_t pp_id;
+	uint8_t ppio_id;
+	uint8_t bpool_bit;
+	uint8_t rss_hf_tcp;
+	uint8_t uc_mc_flushed;
+	uint8_t vlan_flushed;
+
+	struct pp2_ppio_params ppio_params;
+	struct pp2_cls_qos_tbl_params qos_tbl_params;
+	struct pp2_cls_tbl *qos_tbl;
+	uint16_t nb_rx_queues;
+};
+
+/** Number of ports configured. */
+extern int mrvl_ports_nb;
+
+#endif /* _MRVL_ETHDEV_H_ */
diff --git a/drivers/net/mrvl/mrvl_qos.c b/drivers/net/mrvl/mrvl_qos.c
new file mode 100644
index 0000000..c73750f
--- /dev/null
+++ b/drivers/net/mrvl/mrvl_qos.c
@@ -0,0 +1,627 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Semihalf. 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 Semihalf 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 <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_cfgfile.h>
+#include <rte_log.h>
+#include <rte_lcore.h>
+#include <rte_malloc.h>
+#include <rte_string_fns.h>
+
+/* Unluckily, container_of is defined by both DPDK and MUSDK,
+ * we'll declare only one version.
+ *
+ * Note that it is not used in this PMD anyway.
+ */
+#ifdef container_of
+#undef container_of
+#endif
+
+#include "mrvl_qos.h"
+
+/* Parsing tokens. Defined conveniently, so that any correction is easy. */
+#define MRVL_TOK_DEFAULT "default"
+#define MRVL_TOK_DEFAULT_TC "default_tc"
+#define MRVL_TOK_DSCP "dscp"
+#define MRVL_TOK_MAPPING_PRIORITY "mapping_priority"
+#define MRVL_TOK_IP "ip"
+#define MRVL_TOK_IP_VLAN "ip/vlan"
+#define MRVL_TOK_PCP "pcp"
+#define MRVL_TOK_PORT "port"
+#define MRVL_TOK_RXQ "rxq"
+#define MRVL_TOK_SP "SP"
+#define MRVL_TOK_TC "tc"
+#define MRVL_TOK_TXQ "txq"
+#define MRVL_TOK_VLAN "vlan"
+#define MRVL_TOK_VLAN_IP "vlan/ip"
+#define MRVL_TOK_WEIGHT "weight"
+
+/** Number of tokens in range a-b = 2. */
+#define MAX_RNG_TOKENS 2
+
+/** Maximum possible value of PCP. */
+#define MAX_PCP 7
+
+/** Maximum possible value of DSCP. */
+#define MAX_DSCP 63
+
+/** Global QoS configuration. */
+struct mrvl_qos_cfg *mrvl_qos_cfg;
+
+/**
+ * Convert string to uint32_t with extra checks for result correctness.
+ *
+ * @param string String to convert.
+ * @param val Conversion result.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+get_val_securely(const char *string, uint32_t *val)
+{
+	char *endptr;
+	size_t len = strlen(string);
+
+	if (len == 0)
+		return -1;
+
+	*val = strtoul(string, &endptr, 0);
+	if (errno != 0 || (RTE_PTR_DIFF(endptr, string) != len))
+		return -2;
+
+	return 0;
+}
+
+/**
+ * Read out-queue configuration from file.
+ *
+ * @param file Path to the configuration file.
+ * @param port Port number.
+ * @param outq Out queue number.
+ * @param cfg Pointer to the Marvell QoS configuration structure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+get_outq_cfg(struct rte_cfgfile *file, int port, int outq,
+		struct mrvl_qos_cfg *cfg)
+{
+	char sec_name[32];
+	const char *entry;
+	uint32_t val;
+
+	snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
+		MRVL_TOK_PORT, port, MRVL_TOK_TXQ, outq);
+
+	/* Skip non-existing */
+	if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
+		return 0;
+
+	entry = rte_cfgfile_get_entry(file, sec_name,
+			MRVL_TOK_WEIGHT);
+	if (entry) {
+		if (get_val_securely(entry, &val) < 0)
+			return -1;
+		cfg->port[port].outq[outq].weight = (uint8_t)val;
+	}
+
+	return 0;
+}
+
+/**
+ * Gets multiple-entry values and places them in table.
+ *
+ * Entry can be anything, e.g. "1 2-3 5 6 7-9". This needs to be converted to
+ * table entries, respectively: {1, 2, 3, 5, 6, 7, 8, 9}.
+ * As all result table's elements are always 1-byte long, we
+ * won't overcomplicate the function, but we'll keep API generic,
+ * check if someone hasn't changed element size and make it simple
+ * to extend to other sizes.
+ *
+ * This function is purely utilitary, it does not print any error, only returns
+ * different error numbers.
+ *
+ * @param entry[in] Values string to parse.
+ * @param tab[out] Results table.
+ * @param elem_sz[in] Element size (in bytes).
+ * @param max_elems[in] Number of results table elements available.
+ * @param max val[in] Maximum value allowed.
+ * @returns Number of correctly parsed elements in case of success.
+ * @retval -1 Wrong element size.
+ * @retval -2 More tokens than result table allows.
+ * @retval -3 Wrong range syntax.
+ * @retval -4 Wrong range values.
+ * @retval -5 Maximum value exceeded.
+ */
+static int
+get_entry_values(const char *entry, uint8_t *tab,
+	size_t elem_sz, uint8_t max_elems, uint8_t max_val)
+{
+	/* There should not be more tokens than max elements.
+	 * Add 1 for error trap.
+	 */
+	char *tokens[max_elems + 1];
+
+	/* Begin, End + error trap = 3. */
+	char *rng_tokens[MAX_RNG_TOKENS + 1];
+	long beg, end;
+	uint32_t token_val;
+	int nb_tokens, nb_rng_tokens;
+	int i;
+	int values = 0;
+	char val;
+	char entry_cpy[CFG_VALUE_LEN];
+
+	if (elem_sz != 1)
+		return -1;
+
+	/* Copy the entry to safely use rte_strsplit(). */
+	snprintf(entry_cpy, RTE_DIM(entry_cpy), "%s", entry);
+
+	/*
+	 * If there are more tokens than array size, rte_strsplit will
+	 * not return error, just array size.
+	 */
+	nb_tokens = rte_strsplit(entry_cpy, strlen(entry_cpy),
+		tokens, max_elems + 1, ' ');
+
+	/* Quick check, will be refined later. */
+	if (nb_tokens > max_elems)
+		return -2;
+
+	for (i = 0; i < nb_tokens; ++i) {
+		if (strchr(tokens[i], '-') != NULL) {
+			/*
+			 * Split to begin and end tokens.
+			 * We want to catch error cases too, thus we leave
+			 * option for number of tokens to be more than 2.
+			 */
+			nb_rng_tokens = rte_strsplit(tokens[i],
+					strlen(tokens[i]), rng_tokens,
+					RTE_DIM(rng_tokens), '-');
+			if (nb_rng_tokens != 2)
+				return -3;
+
+			/* Range and sanity checks. */
+			if (get_val_securely(rng_tokens[0], &token_val) < 0)
+				return -4;
+			beg = (char)token_val;
+			if (get_val_securely(rng_tokens[1], &token_val) < 0)
+				return -4;
+			end = (char)token_val;
+			if (beg < 0 || beg > UCHAR_MAX ||
+				end < 0 || end > UCHAR_MAX || end < beg)
+				return -4;
+
+			for (val = beg; val <= end; ++val) {
+				if (val > max_val)
+					return -5;
+
+				*tab = val;
+				tab = RTE_PTR_ADD(tab, elem_sz);
+				++values;
+				if (values >= max_elems)
+					return -2;
+			}
+		} else {
+			/* Single values. */
+			if (get_val_securely(tokens[i], &token_val) < 0)
+				return -5;
+			val = (char)token_val;
+			if (val > max_val)
+				return -5;
+
+			*tab = val;
+			tab = RTE_PTR_ADD(tab, elem_sz);
+			++values;
+			if (values >= max_elems)
+				return -2;
+		}
+	}
+
+	return values;
+}
+
+/**
+ * Parse Traffic Class'es mapping configuration.
+ *
+ * @param file Config file handle.
+ * @param port Which port to look for.
+ * @param tc Which Traffic Class to look for.
+ * @param cfg[out] Parsing results.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
+		struct mrvl_qos_cfg *cfg)
+{
+	char sec_name[32];
+	const char *entry;
+	int n;
+
+	snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
+		MRVL_TOK_PORT, port, MRVL_TOK_TC, tc);
+
+	/* Skip non-existing */
+	if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
+		return 0;
+
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RXQ);
+	if (entry) {
+		n = get_entry_values(entry,
+			cfg->port[port].tc[tc].inq,
+			sizeof(cfg->port[port].tc[tc].inq[0]),
+			RTE_DIM(cfg->port[port].tc[tc].inq),
+			MRVL_PP2_RXQ_MAX);
+		if (n < 0) {
+			RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n",
+				n, entry);
+			return n;
+		}
+		cfg->port[port].tc[tc].inqs = n;
+	}
+
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PCP);
+	if (entry) {
+		n = get_entry_values(entry,
+			cfg->port[port].tc[tc].pcp,
+			sizeof(cfg->port[port].tc[tc].pcp[0]),
+			RTE_DIM(cfg->port[port].tc[tc].pcp),
+			MAX_PCP);
+		if (n < 0) {
+			RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n",
+				n, entry);
+			return n;
+		}
+		cfg->port[port].tc[tc].pcps = n;
+	}
+
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_DSCP);
+	if (entry) {
+		n = get_entry_values(entry,
+			cfg->port[port].tc[tc].dscp,
+			sizeof(cfg->port[port].tc[tc].dscp[0]),
+			RTE_DIM(cfg->port[port].tc[tc].dscp),
+			MAX_DSCP);
+		if (n < 0) {
+			RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n",
+				n, entry);
+			return n;
+		}
+		cfg->port[port].tc[tc].dscps = n;
+	}
+	return 0;
+}
+
+/**
+ * Parse QoS configuration - rte_kvargs_process handler.
+ *
+ * Opens configuration file and parses its content.
+ *
+ * @param key Unused.
+ * @param path Path to config file.
+ * @param extra_args Pointer to configuration structure.
+ * @returns 0 in case of success, exits otherwise.
+ */
+int
+mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
+		void *extra_args)
+{
+	struct mrvl_qos_cfg **cfg = extra_args;
+	struct rte_cfgfile *file = rte_cfgfile_load(path, 0);
+	uint32_t val;
+	int n, i, ret;
+	const char *entry;
+	char sec_name[32];
+
+	if (file == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot load configuration %s\n", path);
+
+	/* Create configuration. This is never accessed on the fast path,
+	 * so we can ignore socket.
+	 */
+	*cfg = rte_zmalloc("mrvl_qos_cfg", sizeof(struct mrvl_qos_cfg), 0);
+	if (*cfg == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot allocate configuration %s\n",
+			path);
+
+	n = rte_cfgfile_num_sections(file, MRVL_TOK_PORT,
+		sizeof(MRVL_TOK_PORT) - 1);
+
+	if (n == 0) {
+		/* This is weird, but not bad. */
+		RTE_LOG(WARNING, PMD, "Empty configuration file?\n");
+		return 0;
+	}
+
+	/* Use the number of ports given as vdev parameters. */
+	for (n = 0; n < mrvl_ports_nb; ++n) {
+		snprintf(sec_name, sizeof(sec_name), "%s %d %s",
+			MRVL_TOK_PORT, n, MRVL_TOK_DEFAULT);
+
+		/* Skip ports non-existing in configuration. */
+		if (rte_cfgfile_num_sections(file, sec_name,
+				strlen(sec_name)) <= 0) {
+			(*cfg)->port[n].use_global_defaults = 1;
+			(*cfg)->port[n].mapping_priority =
+				PP2_CLS_QOS_TBL_VLAN_IP_PRI;
+			continue;
+		}
+
+		entry = rte_cfgfile_get_entry(file, sec_name,
+				MRVL_TOK_DEFAULT_TC);
+		if (entry) {
+			if ((get_val_securely(entry, &val) < 0) ||
+				val > USHRT_MAX)
+				return -1;
+			(*cfg)->port[n].default_tc = (uint8_t)val;
+		} else {
+			RTE_LOG(ERR, PMD,
+				"Default Traffic Class required in custom configuration!\n");
+			return -1;
+		}
+
+		entry = rte_cfgfile_get_entry(file, sec_name,
+				MRVL_TOK_MAPPING_PRIORITY);
+		if (entry) {
+			if (!strncmp(entry, MRVL_TOK_VLAN_IP,
+				sizeof(MRVL_TOK_VLAN_IP)))
+				(*cfg)->port[n].mapping_priority =
+					PP2_CLS_QOS_TBL_VLAN_IP_PRI;
+			else if (!strncmp(entry, MRVL_TOK_IP_VLAN,
+				sizeof(MRVL_TOK_IP_VLAN)))
+				(*cfg)->port[n].mapping_priority =
+					PP2_CLS_QOS_TBL_IP_VLAN_PRI;
+			else if (!strncmp(entry, MRVL_TOK_IP,
+				sizeof(MRVL_TOK_IP)))
+				(*cfg)->port[n].mapping_priority =
+					PP2_CLS_QOS_TBL_IP_PRI;
+			else if (!strncmp(entry, MRVL_TOK_VLAN,
+				sizeof(MRVL_TOK_VLAN)))
+				(*cfg)->port[n].mapping_priority =
+					PP2_CLS_QOS_TBL_VLAN_PRI;
+			else
+				rte_exit(EXIT_FAILURE,
+					"Error in parsing %s value (%s)!\n",
+					MRVL_TOK_MAPPING_PRIORITY, entry);
+		} else {
+			(*cfg)->port[n].mapping_priority =
+				PP2_CLS_QOS_TBL_VLAN_IP_PRI;
+		}
+
+		for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) {
+			ret = get_outq_cfg(file, n, i, *cfg);
+			if (ret < 0)
+				rte_exit(EXIT_FAILURE,
+					"Error %d parsing port %d outq %d!\n",
+					ret, n, i);
+		}
+
+		for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
+			ret = parse_tc_cfg(file, n, i, *cfg);
+			if (ret < 0)
+				rte_exit(EXIT_FAILURE,
+					"Error %d parsing port %d tc %d!\n",
+					ret, n, i);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Setup Traffic Class.
+ *
+ * Fill in TC parameters in single MUSDK TC config entry.
+ * @param param TC parameters entry.
+ * @param inqs Number of MUSDK in-queues in this TC.
+ * @param bpool Bpool for this TC.
+ * @returns 0 in case of success, exits otherwise.
+ */
+static int
+setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
+	struct pp2_bpool *bpool)
+{
+	struct pp2_ppio_inq_params *inq_params;
+
+	param->pkt_offset = MRVL_PKT_OFFS;
+	param->pools[0] = bpool;
+
+	inq_params = rte_zmalloc_socket("inq_params",
+		inqs * sizeof(*inq_params),
+		0, rte_socket_id());
+	if (!inq_params)
+		return -ENOMEM;
+
+	param->num_in_qs = inqs;
+
+	/* Release old config if necessary. */
+	if (param->inqs_params)
+		rte_free(param->inqs_params);
+
+	param->inqs_params = inq_params;
+
+	return 0;
+}
+
+/**
+ * Configure RX Queues in a given port.
+ *
+ * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
+ *
+ * @param priv Port's private data
+ * @param portid DPDK port ID
+ * @param max_queues Maximum number of queues to configure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+int
+mrvl_configure_rxqs(struct mrvl_priv *priv, uint8_t portid,
+	uint16_t max_queues)
+{
+	size_t i, tc;
+
+	if (mrvl_qos_cfg == NULL ||
+		mrvl_qos_cfg->port[portid].use_global_defaults) {
+		/* No port configuration, use default: 1 TC, no QoS. */
+		priv->ppio_params.inqs_params.num_tcs = 1;
+		setup_tc(&priv->ppio_params.inqs_params.tcs_params[0],
+			max_queues, priv->bpool);
+
+		/* Direct mapping of queues i.e. 0->0, 1->1 etc. */
+		for (i = 0; i < max_queues; ++i) {
+			priv->rxq_map[i].tc = 0;
+			priv->rxq_map[i].inq = i;
+		}
+		return 0;
+	}
+
+	/* We need only a subset of configuration. */
+	struct port_cfg *port_cfg = &mrvl_qos_cfg->port[portid];
+
+	priv->qos_tbl_params.type = port_cfg->mapping_priority;
+
+	/*
+	 * We need to reverse mapping, from tc->pcp (better from usability
+	 * point of view) to pcp->tc (configurable in MUSDK).
+	 * First, set all map elements to "default".
+	 */
+	for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
+		priv->qos_tbl_params.pcp_cos_map[i].tc = port_cfg->default_tc;
+
+	/* Then, fill in all known values. */
+	for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
+		if (port_cfg->tc[tc].pcps > RTE_DIM(port_cfg->tc[0].pcp)) {
+			/* Better safe than sorry. */
+			RTE_LOG(ERR, PMD,
+				"Too many PCPs configured in TC %zu!\n", tc);
+			return -1;
+		}
+		for (i = 0; i < port_cfg->tc[tc].pcps; ++i) {
+			priv->qos_tbl_params.pcp_cos_map[
+			  port_cfg->tc[tc].pcp[i]].tc = tc;
+		}
+	}
+
+	/*
+	 * The same logic goes with DSCP.
+	 * First, set all map elements to "default".
+	 */
+	for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
+		priv->qos_tbl_params.dscp_cos_map[i].tc =
+			port_cfg->default_tc;
+
+	/* Fill in all known values. */
+	for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
+		if (port_cfg->tc[tc].dscps > RTE_DIM(port_cfg->tc[0].dscp)) {
+			/* Better safe than sorry. */
+			RTE_LOG(ERR, PMD,
+				"Too many DSCPs configured in TC %zu!\n", tc);
+			return -1;
+		}
+		for (i = 0; i < port_cfg->tc[tc].dscps; ++i) {
+			priv->qos_tbl_params.dscp_cos_map[
+			  port_cfg->tc[tc].dscp[i]].tc = tc;
+		}
+	}
+
+	/*
+	 * Surprisingly, similar logic goes with queue mapping.
+	 * We need only to store qid->tc mapping,
+	 * to know TC when queue is read.
+	 */
+	for (i = 0; i < RTE_DIM(priv->rxq_map); ++i)
+		priv->rxq_map[i].tc = MRVL_UNKNOWN_TC;
+
+	/* Set up DPDKq->(TC,inq) mapping. */
+	for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
+		if (port_cfg->tc[tc].inqs > RTE_DIM(port_cfg->tc[0].inq)) {
+			/* Overflow. */
+			RTE_LOG(ERR, PMD,
+				"Too many RX queues configured per TC %zu!\n",
+				tc);
+			return -1;
+		}
+		for (i = 0; i < port_cfg->tc[tc].inqs; ++i) {
+			uint8_t idx = port_cfg->tc[tc].inq[i];
+			priv->rxq_map[idx].tc = tc;
+			priv->rxq_map[idx].inq = i;
+		}
+	}
+
+	/*
+	 * Set up TC configuration. TCs need to be sequenced: 0, 1, 2
+	 * with no gaps. Empty TC means end of processing.
+	 */
+	for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
+		if (port_cfg->tc[i].inqs == 0)
+			break;
+		setup_tc(&priv->ppio_params.inqs_params.tcs_params[i],
+				port_cfg->tc[i].inqs,
+				priv->bpool);
+	}
+
+	priv->ppio_params.inqs_params.num_tcs = i;
+
+	return 0;
+}
+
+/**
+ * Start QoS mapping.
+ *
+ * Finalize QoS table configuration and initialize it in SDK. It can be done
+ * only after port is started, so we have a valid ppio reference.
+ *
+ * @param priv Port's private (configuration) data.
+ * @returns 0 in case of success, exits otherwise.
+ */
+int
+mrvl_start_qos_mapping(struct mrvl_priv *priv)
+{
+	size_t i;
+
+	if (priv->ppio == NULL) {
+		RTE_LOG(ERR, PMD, "ppio must not be NULL here!\n");
+		return -1;
+	}
+
+	for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
+		priv->qos_tbl_params.pcp_cos_map[i].ppio = priv->ppio;
+
+	for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
+		priv->qos_tbl_params.dscp_cos_map[i].ppio = priv->ppio;
+
+	/* Initialize Classifier QoS table. */
+
+	return pp2_cls_qos_tbl_init(&priv->qos_tbl_params, &priv->qos_tbl);
+}
diff --git a/drivers/net/mrvl/mrvl_qos.h b/drivers/net/mrvl/mrvl_qos.h
new file mode 100644
index 0000000..8542db6
--- /dev/null
+++ b/drivers/net/mrvl/mrvl_qos.h
@@ -0,0 +1,112 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Semihalf. 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 Semihalf 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 _MRVL_QOS_H_
+#define _MRVL_QOS_H_
+
+#include <rte_common.h>
+#include <rte_config.h>
+
+#include "mrvl_ethdev.h"
+
+/** Code Points per Traffic Class. Equals max(DSCP, PCP). */
+#define MRVL_CP_PER_TC (64)
+
+/** Value used as "unknown". */
+#define MRVL_UNKNOWN_TC (0xFF)
+
+/* QoS config. */
+struct mrvl_qos_cfg {
+	struct port_cfg {
+		struct {
+			uint8_t inq[MRVL_PP2_RXQ_MAX];
+			uint8_t dscp[MRVL_CP_PER_TC];
+			uint8_t pcp[MRVL_CP_PER_TC];
+			uint8_t inqs;
+			uint8_t dscps;
+			uint8_t pcps;
+		} tc[MRVL_PP2_TC_MAX];
+		struct {
+			uint8_t weight;
+		} outq[MRVL_PP2_RXQ_MAX];
+		enum pp2_cls_qos_tbl_type mapping_priority;
+		uint16_t inqs;
+		uint16_t outqs;
+		uint8_t default_tc;
+		uint8_t use_global_defaults;
+	} port[RTE_MAX_ETHPORTS];
+};
+
+/** Global QoS configuration. */
+extern struct mrvl_qos_cfg *mrvl_qos_cfg;
+
+/**
+ * Parse QoS configuration - rte_kvargs_process handler.
+ *
+ * Opens configuration file and parses its content.
+ *
+ * @param key Unused.
+ * @param path Path to config file.
+ * @param extra_args Pointer to configuration structure.
+ * @returns 0 in case of success, exits otherwise.
+ */
+int
+mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
+		void *extra_args);
+
+/**
+ * Configure RX Queues in a given port.
+ *
+ * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
+ *
+ * @param priv Port's private data
+ * @param portid DPDK port ID
+ * @param max_queues Maximum number of queues to configure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+int
+mrvl_configure_rxqs(struct mrvl_priv *priv, uint8_t portid,
+		uint16_t max_queues);
+
+/**
+ * Start QoS mapping.
+ *
+ * Finalize QoS table configuration and initialize it in SDK. It can be done
+ * only after port is started, so we have a valid ppio reference.
+ *
+ * @param priv Port's private (configuration) data.
+ * @returns 0 in case of success, exits otherwise.
+ */
+int
+mrvl_start_qos_mapping(struct mrvl_priv *priv);
+
+#endif /* _MRVL_QOS_H_ */
diff --git a/drivers/net/mrvl/rte_pmd_mrvl_version.map b/drivers/net/mrvl/rte_pmd_mrvl_version.map
new file mode 100644
index 0000000..a753031
--- /dev/null
+++ b/drivers/net/mrvl/rte_pmd_mrvl_version.map
@@ -0,0 +1,3 @@
+DPDK_17.11 {
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 94568a8..8df74bb 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -130,6 +130,7 @@ endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_LIO_PMD)        += -lrte_pmd_lio
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -libverbs
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD)       += -lrte_pmd_mlx5 -libverbs
+_LDLIBS-$(CONFIG_RTE_LIBRTE_MRVL_PMD)       += -lrte_pmd_mrvl -L$(LIBMUSDK_PATH)/lib -lmusdk
 _LDLIBS-$(CONFIG_RTE_LIBRTE_NFP_PMD)        += -lrte_pmd_nfp
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NULL)       += -lrte_pmd_null
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_PCAP)       += -lrte_pmd_pcap -lpcap
--
2.7.4

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

* [PATCH v2 3/4] doc: add mrvl net pmd documentation
  2017-09-28 10:22 ` [PATCH v2 0/4] add net mrvl pmd driver Tomasz Duszynski
  2017-09-28 10:22   ` [PATCH v2 1/4] app: link the whole rte_cfgfile library Tomasz Duszynski
  2017-09-28 10:22   ` [PATCH v2 2/4] net/mrvl: add mrvl net " Tomasz Duszynski
@ 2017-09-28 10:22   ` Tomasz Duszynski
  2017-09-28 10:22   ` [PATCH v2 4/4] maintainers: add maintainers for the mrvl net pmd Tomasz Duszynski
  2017-09-28 11:06   ` [PATCH v2 0/4] add net mrvl pmd driver Ferruh Yigit
  4 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-28 10:22 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add documentation for the MRVL NET PMD driver.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <jck@semihalf.com>
---
 doc/guides/nics/features/mrvl.ini |  24 ++++++
 doc/guides/nics/index.rst         |   1 +
 doc/guides/nics/mrvl.rst          | 151 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 176 insertions(+)
 create mode 100644 doc/guides/nics/features/mrvl.ini
 create mode 100644 doc/guides/nics/mrvl.rst

diff --git a/doc/guides/nics/features/mrvl.ini b/doc/guides/nics/features/mrvl.ini
new file mode 100644
index 0000000..781d6dc
--- /dev/null
+++ b/doc/guides/nics/features/mrvl.ini
@@ -0,0 +1,24 @@
+;
+; Supported features of the 'mrvl' network poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Speed capabilities   = Y
+Link status          = Y
+MTU update           = Y
+Jumbo frame          = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Unicast MAC filter   = Y
+Multicast MAC filter = Y
+RSS hash             = Y
+VLAN filter          = Y
+CRC offload          = Y
+L3 checksum offload  = Y
+L4 checksum offload  = Y
+Packet type parsing  = Y
+Basic stats          = Y
+Stats per queue      = Y
+ARMv8                = Y
+Usage doc            = Y
diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index 36f4f3f..7192f63 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -55,6 +55,7 @@ Network Interface Controller Drivers
     liquidio
     mlx4
     mlx5
+    mrvl
     nfp
     qede
     sfc_efx
diff --git a/doc/guides/nics/mrvl.rst b/doc/guides/nics/mrvl.rst
new file mode 100644
index 0000000..241d89b
--- /dev/null
+++ b/doc/guides/nics/mrvl.rst
@@ -0,0 +1,151 @@
+..  BSD LICENSE
+    Copyright(c) 2017 Semihalf. All rights reserved.
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in
+        the documentation and/or other materials provided with the
+        distribution.
+      * Neither the name of Semihalf 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.
+
+MRVL Poll Mode Driver
+======================
+
+The MRVL PMD (librte_pmd_mrvl) provides poll mode driver support
+for the Marvell PPv2 (Packet Processor v2) 1/10 Gbps adapter.
+
+.. Note::
+
+   Due to external dependencies, this driver is disabled by default. It must
+   be enabled manually by setting relevant configuration option manually.
+   Please refer to `Config File Options`_ section for further details.
+
+
+Features
+--------
+
+Features of the MRVL PMD are:
+
+- Speed capabilities
+- Link status
+- Queue start/stop
+- MTU update
+- Jumbo frame
+- Promiscuous mode
+- Allmulticast mode
+- Unicast MAC filter
+- Multicast MAC filter
+- RSS hash
+- VLAN filter
+- CRC offload
+- L3 checksum offload
+- L4 checksum offload
+- Packet type parsing
+- Basic stats
+- Stats per queue
+
+
+Limitations
+-----------
+
+- Number of lcores is limited to 9 by MUSDK internal design. If more lcores
+  need to be allocated, locking will have to be considered. Number of available
+  lcores can be changed via ``MRVL_MUSDK_HIFS_RESERVED`` define in
+  ``mrvl_ethdev.c`` source file.
+
+- Flushing vlans added for filtering is not possible due to MUSDK missing
+  functionality. Current workaround is to reset board so that PPv2 has a
+  chance to start in a sane state.
+
+
+Prerequisites
+-------------
+
+- MUSDK (Marvell User-Space SDK) sources available
+  `here <https://github.com/MarvellEmbeddedProcessors/musdk-marvell/tree/musdk-armada-17.08>`_.
+
+    MUSDK is a light-weight library that provides direct access to Marvell's
+    PPv2 (Packet Processor v2). Alternatively prebuilt MUSDK library can be
+    requested from `Marvell Extranet <https://extranet.marvell.com>`_. Once
+    approval has been granted, library can be found by typing ``musdk`` in
+    search box.
+
+- DPDK environment
+
+    Follow the DPDK :ref:`Getting Started Guide for Linux <linux_gsg>` to setup
+    DPDK environment.
+
+
+Config File Options
+-------------------
+
+The following options can be modified in the ``config`` file.
+
+- ``CONFIG_RTE_LIBRTE_MRVL_PMD`` (default ``n``)
+
+    Toggle compilation of the librte_pmd_mrvl driver.
+
+- ``CONFIG_RTE_LIBRTE_MRVL_DEBUG`` (default ``n``)
+
+    Toggle display of debugging messages.
+
+- ``CONFIG_RTE_MRVL_MUSDK_DMA_MEMSIZE`` (default ``41943040``)
+
+    Size in bytes of the contiguous memory region that MUSDK will allocate
+    for run-time DMA-able data buffers.
+
+
+Building DPDK
+-------------
+
+Driver needs precompiled MUSDK library during compilation. Detailed build
+process is described in library's documentation under ``doc`` directory.
+
+Before the DPDK build process the environmental variable ``LIBMUSDK_PATH`` with
+the path to the MUSDK installation directory needs to be exported.
+
+Usage Example
+-------------
+
+MRVL PMD requires extra kernel modules to function properly:
+
+.. code-block:: console
+
+   insmod musdk_uio.ko
+   insmod mv_pp_uio.ko
+   insmod mvpp2x_sysfs.ko
+
+Additionally interfaces used by DPDK application need to be put up:
+
+.. code-block:: console
+
+   ip link set eth0 up
+   ip link set eth1 up
+
+In order to run testpmd example application following command can be used:
+
+.. code-block:: console
+
+   ./testpmd --vdev=eth_mrvl,iface=eth0,iface=eth2 -c 7 -- \
+     --burst=128 --txd=2048 --rxd=1024 --rxq=2 --txq=2  --nb-cores=2 \
+     -i -a --disable-hw-vlan-strip --rss-udp
-- 
2.7.4

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

* [PATCH v2 4/4] maintainers: add maintainers for the mrvl net pmd
  2017-09-28 10:22 ` [PATCH v2 0/4] add net mrvl pmd driver Tomasz Duszynski
                     ` (2 preceding siblings ...)
  2017-09-28 10:22   ` [PATCH v2 3/4] doc: add mrvl net pmd documentation Tomasz Duszynski
@ 2017-09-28 10:22   ` Tomasz Duszynski
  2017-09-28 11:06   ` [PATCH v2 0/4] add net mrvl pmd driver Ferruh Yigit
  4 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-28 10:22 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 MAINTAINERS | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index a0cd75e..d4810cf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -393,6 +393,16 @@ F: drivers/net/mlx5/
 F: doc/guides/nics/mlx5.rst
 F: doc/guides/nics/features/mlx5.ini
 
+Marvell mrvl
+M: Jacek Siuda <jck@semihalf.com>
+M: Tomasz Duszynski <tdu@semihalf.com>
+M: Dmitri Epshtein <dima@marvell.com>
+M: Natalie Samsonov <nsamsono@marvell.com>
+M: Jianbo Liu <jianbo.liu@linaro.org>
+F: drivers/net/mrvl/
+F: doc/guides/nics/mrvl.rst
+F: doc/guides/nics/features/mrvl.ini
+
 Netcope szedata2
 M: Matej Vido <vido@cesnet.cz>
 F: drivers/net/szedata2/
-- 
2.7.4

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

* [PATCH v2 0/4] add crypto mrvl pmd driver
  2017-09-26  9:39 [PATCH 0/8] add net/crypto mrvl pmd drivers Tomasz Duszynski
                   ` (9 preceding siblings ...)
  2017-09-28 10:22 ` [PATCH v2 0/4] add net mrvl pmd driver Tomasz Duszynski
@ 2017-09-28 10:23 ` Tomasz Duszynski
  2017-09-28 10:23   ` [PATCH v2 1/4] crypto/mrvl: add mrvl crypto " Tomasz Duszynski
                     ` (4 more replies)
  10 siblings, 5 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-28 10:23 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski

Hello,

This patch series introduces crypto driver for Marvell Armada 7k/8k
SoCs along with documentation and crypto pmd driver tests.

Below you can find the list of features which crypto pmd supports:
* Symmetric crypto
* Sym operation chaining
* AES CBC (128)
* AES CBC (192)
* AES CBC (256)
* AES CTR (128)
* AES CTR (192)
* AES CTR (256)
* 3DES CBC
* 3DES CTR
* MD5
* MD5 HMAC
* SHA1
* SHA1 HMAC
* SHA256
* SHA256 HMAC
* SHA384
* SHA384 HMAC
* SHA512
* SHA512 HMAC
* AES GCM (128)

Tomasz Duszynski (4):
  crypto/mrvl: add mrvl crypto pmd driver
  doc: add mrvl crypto pmd documentation
  maintainers: add maintainers for the mrvl crypto pmd
  test: add mrvl crypto pmd unit tests

 MAINTAINERS                                  |  10 +
 config/common_base                           |   6 +
 doc/guides/cryptodevs/features/mrvl.ini      |  42 ++
 doc/guides/cryptodevs/index.rst              |   1 +
 doc/guides/cryptodevs/mrvl.rst               | 198 ++++++
 drivers/crypto/Makefile                      |   2 +
 drivers/crypto/mrvl/Makefile                 |  63 ++
 drivers/crypto/mrvl/rte_mrvl_compat.h        |  48 ++
 drivers/crypto/mrvl/rte_mrvl_pmd.c           | 870 +++++++++++++++++++++++++++
 drivers/crypto/mrvl/rte_mrvl_pmd_ops.c       | 787 ++++++++++++++++++++++++
 drivers/crypto/mrvl/rte_mrvl_pmd_private.h   | 121 ++++
 drivers/crypto/mrvl/rte_mrvl_pmd_version.map |   3 +
 mk/rte.app.mk                                |   1 +
 test/test/test_cryptodev.c                   | 168 ++++++
 test/test/test_cryptodev.h                   |   1 +
 test/test/test_cryptodev_aes_test_vectors.h  |  72 ++-
 test/test/test_cryptodev_blockcipher.c       |   9 +-
 test/test/test_cryptodev_blockcipher.h       |   1 +
 test/test/test_cryptodev_des_test_vectors.h  |  24 +-
 19 files changed, 2394 insertions(+), 33 deletions(-)
 create mode 100644 doc/guides/cryptodevs/features/mrvl.ini
 create mode 100644 doc/guides/cryptodevs/mrvl.rst
 create mode 100644 drivers/crypto/mrvl/Makefile
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_compat.h
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd.c
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_private.h
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_version.map

--
2.7.4

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

* [PATCH v2 1/4] crypto/mrvl: add mrvl crypto pmd driver
  2017-09-28 10:23 ` [PATCH v2 0/4] add crypto " Tomasz Duszynski
@ 2017-09-28 10:23   ` Tomasz Duszynski
  2017-10-05 15:01     ` De Lara Guarch, Pablo
  2017-10-05 15:47     ` Bruce Richardson
  2017-09-28 10:23   ` [PATCH v2 2/4] doc: add mrvl crypto pmd documentation Tomasz Duszynski
                     ` (3 subsequent siblings)
  4 siblings, 2 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-28 10:23 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add support for the Marvell Security Crypto Accelerator EIP197.
Driver is based on external, publicly available, Marvell MUSDK
library that provides access to the hardware with minimum overhead
and high performance.

Driver comes with support for the following features:

* Symmetric crypto
* Sym operation chaining
* AES CBC (128)
* AES CBC (192)
* AES CBC (256)
* AES CTR (128)
* AES CTR (192)
* AES CTR (256)
* 3DES CBC
* 3DES CTR
* MD5
* MD5 HMAC
* SHA1
* SHA1 HMAC
* SHA256
* SHA256 HMAC
* SHA384
* SHA384 HMAC
* SHA512
* SHA512 HMAC
* AES GCM (128)

Driver was engineered cooperatively by Semihalf and Marvell teams.

Semihalf:
Jacek Siuda <jck@semihalf.com>
Tomasz Duszynski <tdu@semihalf.com>

Marvell:
Dmitri Epshtein <dima@marvell.com>
Natalie Samsonov <nsamsono@marvell.com>

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 config/common_base                           |   6 +
 drivers/crypto/Makefile                      |   2 +
 drivers/crypto/mrvl/Makefile                 |  63 ++
 drivers/crypto/mrvl/rte_mrvl_compat.h        |  48 ++
 drivers/crypto/mrvl/rte_mrvl_pmd.c           | 870 +++++++++++++++++++++++++++
 drivers/crypto/mrvl/rte_mrvl_pmd_ops.c       | 787 ++++++++++++++++++++++++
 drivers/crypto/mrvl/rte_mrvl_pmd_private.h   | 121 ++++
 drivers/crypto/mrvl/rte_mrvl_pmd_version.map |   3 +
 mk/rte.app.mk                                |   1 +
 9 files changed, 1901 insertions(+)
 create mode 100644 drivers/crypto/mrvl/Makefile
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_compat.h
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd.c
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_private.h
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_version.map

diff --git a/config/common_base b/config/common_base
index d05a60c..e9b181e 100644
--- a/config/common_base
+++ b/config/common_base
@@ -521,6 +521,12 @@ CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER_DEBUG=n
 CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO=y
 
 #
+# Compile PMD for Marvell Crypto device
+#
+CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO=n
+CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO_DEBUG=n
+
+#
 # Compile generic event device library
 #
 CONFIG_RTE_LIBRTE_EVENTDEV=y
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 7a719b9..1d7db5b 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -51,6 +51,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_KASUMI) += kasumi
 DEPDIRS-kasumi = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_ZUC) += zuc
 DEPDIRS-zuc = $(core-libs)
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO) += mrvl
+DEPDIRS-mrvl = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO) += null
 DEPDIRS-null = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_SEC) += dpaa2_sec
diff --git a/drivers/crypto/mrvl/Makefile b/drivers/crypto/mrvl/Makefile
new file mode 100644
index 0000000..a00a19e
--- /dev/null
+++ b/drivers/crypto/mrvl/Makefile
@@ -0,0 +1,63 @@
+#   BSD LICENSE
+#
+#   Copyright (C) Semihalf 2017. 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 Semihalf 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
+
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),config)
+ifeq ($(LIBMUSDK_PATH),)
+$(error "Please define LIBMUSDK_PATH environment variable")
+endif
+endif
+endif
+
+# library name
+LIB = librte_pmd_mrvl_crypto.a
+
+# build flags
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -I$(LIBMUSDK_PATH)/include
+CFLAGS += -DMVCONF_ARCH_DMA_ADDR_T_64BIT
+
+# library version
+LIBABIVER := 1
+
+# versioning export map
+EXPORT_MAP := rte_mrvl_pmd_version.map
+
+# external library dependencies
+LDLIBS += -L$(LIBMUSDK_PATH)/lib -lmusdk
+
+# library source files
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO) += rte_mrvl_pmd.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO) += rte_mrvl_pmd_ops.c
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/crypto/mrvl/rte_mrvl_compat.h b/drivers/crypto/mrvl/rte_mrvl_compat.h
new file mode 100644
index 0000000..11d53fc
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_mrvl_compat.h
@@ -0,0 +1,48 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) Semihalf 2017. 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 Semihalf 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_MRVL_COMPAT_H_
+#define _RTE_MRVL_COMPAT_H_
+
+/* Unluckily, container_of is defined by both DPDK and MUSDK,
+ * we'll declare only one version.
+ *
+ * Note that it is not used in this PMD anyway.
+ */
+#ifdef container_of
+#undef container_of
+#endif
+#include "drivers/mv_sam.h"
+#include "drivers/mv_sam_cio.h"
+#include "drivers/mv_sam_session.h"
+
+#endif /* _RTE_MRVL_COMPAT_H_ */
diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd.c b/drivers/crypto/mrvl/rte_mrvl_pmd.c
new file mode 100644
index 0000000..63f8daa
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_mrvl_pmd.c
@@ -0,0 +1,870 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) Semihalf 2017. 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 Semihalf 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_common.h>
+#include <rte_hexdump.h>
+#include <rte_cryptodev.h>
+#include <rte_cryptodev_pmd.h>
+#include <rte_cryptodev_vdev.h>
+#include <rte_vdev.h>
+#include <rte_malloc.h>
+#include <rte_cpuflags.h>
+
+#include "rte_mrvl_pmd_private.h"
+
+#ifndef RTE_MRVL_MUSDK_DMA_MEMSIZE
+#define RTE_MRVL_MUSDK_DMA_MEMSIZE 41943040
+#endif
+
+static uint8_t cryptodev_driver_id;
+
+/**
+ * Flag if particular crypto algorithm is supported by PMD/MUSDK.
+ *
+ * The idea is to have Not Supported value as default (0).
+ * This way we need only to define proper map sizes,
+ * non-initialized entries will be by default not supported.
+ */
+enum algo_supported {
+	ALGO_NOT_SUPPORTED = 0,
+	ALGO_SUPPORTED = 1,
+};
+
+/** Map elements for cipher mapping.*/
+struct cipher_params_mapping {
+	enum algo_supported  supported;   /**< On/Off switch */
+	enum sam_cipher_alg  cipher_alg;  /**< Cipher algorithm */
+	enum sam_cipher_mode cipher_mode; /**< Cipher mode */
+	unsigned int max_key_len;         /**< Maximum key length (in bytes)*/
+}
+/* We want to squeeze in multiple maps into the cache line. */
+__rte_aligned(32);
+
+/** Map elements for auth mapping.*/
+struct auth_params_mapping {
+	enum algo_supported supported;  /**< On/off switch */
+	enum sam_auth_alg   auth_alg;   /**< Auth algorithm */
+}
+/* We want to squeeze in multiple maps into the cache line. */
+__rte_aligned(32);
+
+/**
+ * Map of supported cipher algorithms.
+ */
+static const
+struct cipher_params_mapping cipher_map[RTE_CRYPTO_CIPHER_LIST_END] = {
+	[RTE_CRYPTO_CIPHER_3DES_CBC] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_3DES,
+		.cipher_mode = SAM_CIPHER_CBC,
+		.max_key_len = BITS2BYTES(192) },
+	[RTE_CRYPTO_CIPHER_3DES_CTR] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_3DES,
+		.cipher_mode = SAM_CIPHER_CTR,
+		.max_key_len = BITS2BYTES(192) },
+	[RTE_CRYPTO_CIPHER_3DES_ECB] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_3DES,
+		.cipher_mode = SAM_CIPHER_ECB,
+		.max_key_len = BITS2BYTES(192) },
+	[RTE_CRYPTO_CIPHER_AES_CBC] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_AES,
+		.cipher_mode = SAM_CIPHER_CBC,
+		.max_key_len = BITS2BYTES(256) },
+	[RTE_CRYPTO_CIPHER_AES_CTR] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_AES,
+		.cipher_mode = SAM_CIPHER_CTR,
+		.max_key_len = BITS2BYTES(256) },
+};
+
+/**
+ * Map of supported auth algorithms.
+ */
+static const
+struct auth_params_mapping auth_map[RTE_CRYPTO_AUTH_LIST_END] = {
+	[RTE_CRYPTO_AUTH_MD5_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_MD5 },
+	[RTE_CRYPTO_AUTH_MD5] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_MD5 },
+	[RTE_CRYPTO_AUTH_SHA1_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_SHA1 },
+	[RTE_CRYPTO_AUTH_SHA1] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA1 },
+	[RTE_CRYPTO_AUTH_SHA224] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA2_224 },
+	[RTE_CRYPTO_AUTH_SHA256_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_SHA2_256 },
+	[RTE_CRYPTO_AUTH_SHA256] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA2_256 },
+	[RTE_CRYPTO_AUTH_SHA384_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_SHA2_384 },
+	[RTE_CRYPTO_AUTH_SHA384] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA2_384 },
+	[RTE_CRYPTO_AUTH_SHA512_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_SHA2_512 },
+	[RTE_CRYPTO_AUTH_SHA512] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA2_512 },
+	[RTE_CRYPTO_AUTH_AES_GMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_AES_GMAC },
+};
+
+/**
+ * Map of supported aead algorithms.
+ */
+static const
+struct cipher_params_mapping aead_map[RTE_CRYPTO_AEAD_LIST_END] = {
+	[RTE_CRYPTO_AEAD_AES_GCM] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_AES,
+		.cipher_mode = SAM_CIPHER_GCM,
+		.max_key_len = BITS2BYTES(256) },
+};
+
+/*
+ *-----------------------------------------------------------------------------
+ * Forward declarations.
+ *-----------------------------------------------------------------------------
+ */
+static int cryptodev_mrvl_crypto_uninit(struct rte_vdev_device *vdev);
+
+/*
+ *-----------------------------------------------------------------------------
+ * Session Preparation.
+ *-----------------------------------------------------------------------------
+ */
+
+/**
+ * Get xform chain order.
+ *
+ * @param xform Pointer to configuration structure chain for crypto operations.
+ * @returns Order of crypto operations.
+ */
+static enum mrvl_crypto_chain_order
+mrvl_crypto_get_chain_order(const struct rte_crypto_sym_xform *xform)
+{
+	/* Currently, Marvell supports max 2 operations in chain */
+	if (xform->next != NULL && xform->next->next != NULL)
+		return MRVL_CRYPTO_CHAIN_NOT_SUPPORTED;
+
+	if (xform->next != NULL) {
+		if ((xform->type == RTE_CRYPTO_SYM_XFORM_AUTH) &&
+			(xform->next->type == RTE_CRYPTO_SYM_XFORM_CIPHER))
+			return MRVL_CRYPTO_CHAIN_AUTH_CIPHER;
+
+		if ((xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER) &&
+			(xform->next->type == RTE_CRYPTO_SYM_XFORM_AUTH))
+			return MRVL_CRYPTO_CHAIN_CIPHER_AUTH;
+	} else {
+		if (xform->type == RTE_CRYPTO_SYM_XFORM_AUTH)
+			return MRVL_CRYPTO_CHAIN_AUTH_ONLY;
+
+		if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER)
+			return MRVL_CRYPTO_CHAIN_CIPHER_ONLY;
+
+		if (xform->type == RTE_CRYPTO_SYM_XFORM_AEAD)
+			return MRVL_CRYPTO_CHAIN_COMBINED;
+	}
+	return MRVL_CRYPTO_CHAIN_NOT_SUPPORTED;
+}
+
+/**
+ * Set session parameters for cipher part.
+ *
+ * @param sess Crypto session pointer.
+ * @param cipher_xform Pointer to configuration structure for cipher operations.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+mrvl_crypto_set_cipher_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *cipher_xform)
+{
+	/* Make sure we've got proper struct */
+	if (cipher_xform->type != RTE_CRYPTO_SYM_XFORM_CIPHER) {
+		MRVL_CRYPTO_LOG_ERR("Wrong xform struct provided!");
+		return -EINVAL;
+	}
+
+	/* See if map data is present and valid */
+	if ((cipher_xform->cipher.algo > RTE_DIM(cipher_map)) ||
+		(cipher_map[cipher_xform->cipher.algo].supported
+			!= ALGO_SUPPORTED)) {
+		MRVL_CRYPTO_LOG_ERR("Cipher algorithm not supported!");
+		return -EINVAL;
+	}
+
+	sess->cipher_iv_offset = cipher_xform->cipher.iv.offset;
+
+	sess->sam_sess_params.dir =
+		(cipher_xform->cipher.op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) ?
+		SAM_DIR_ENCRYPT : SAM_DIR_DECRYPT;
+	sess->sam_sess_params.cipher_alg =
+		cipher_map[cipher_xform->cipher.algo].cipher_alg;
+	sess->sam_sess_params.cipher_mode =
+		cipher_map[cipher_xform->cipher.algo].cipher_mode;
+
+	/* Assume IV will be passed together with data. */
+	sess->sam_sess_params.cipher_iv = NULL;
+
+	/* Get max key length. */
+	if (cipher_xform->cipher.key.length >
+		cipher_map[cipher_xform->cipher.algo].max_key_len) {
+		MRVL_CRYPTO_LOG_ERR("Wrong key length!");
+		return -EINVAL;
+	}
+
+	sess->sam_sess_params.cipher_key_len = cipher_xform->cipher.key.length;
+	sess->sam_sess_params.cipher_key = cipher_xform->cipher.key.data;
+
+	return 0;
+}
+
+/**
+ * Set session parameters for authentication part.
+ *
+ * @param sess Crypto session pointer.
+ * @param auth_xform Pointer to configuration structure for auth operations.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+mrvl_crypto_set_auth_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *auth_xform)
+{
+	/* Make sure we've got proper struct */
+	if (auth_xform->type != RTE_CRYPTO_SYM_XFORM_AUTH) {
+		MRVL_CRYPTO_LOG_ERR("Wrong xform struct provided!");
+		return -EINVAL;
+	}
+
+	/* See if map data is present and valid */
+	if ((auth_xform->auth.algo > RTE_DIM(auth_map)) ||
+		(auth_map[auth_xform->auth.algo].supported != ALGO_SUPPORTED)) {
+		MRVL_CRYPTO_LOG_ERR("Auth algorithm not supported!");
+		return -EINVAL;
+	}
+
+	sess->sam_sess_params.dir =
+		(auth_xform->auth.op == RTE_CRYPTO_AUTH_OP_GENERATE) ?
+		SAM_DIR_ENCRYPT : SAM_DIR_DECRYPT;
+	sess->sam_sess_params.auth_alg =
+		auth_map[auth_xform->auth.algo].auth_alg;
+	sess->sam_sess_params.u.basic.auth_icv_len =
+		auth_xform->auth.digest_length;
+	/* auth_key must be NULL if auth algorithm does not use HMAC */
+	sess->sam_sess_params.auth_key = auth_xform->auth.key.length ?
+					 auth_xform->auth.key.data : NULL;
+	sess->sam_sess_params.auth_key_len = auth_xform->auth.key.length;
+
+	return 0;
+}
+
+/**
+ * Set session parameters for aead part.
+ *
+ * @param sess Crypto session pointer.
+ * @param aead_xform Pointer to configuration structure for aead operations.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+mrvl_crypto_set_aead_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *aead_xform)
+{
+	/* Make sure we've got proper struct */
+	if (aead_xform->type != RTE_CRYPTO_SYM_XFORM_AEAD) {
+		MRVL_CRYPTO_LOG_ERR("Wrong xform struct provided!");
+		return -EINVAL;
+	}
+
+	/* See if map data is present and valid */
+	if ((aead_xform->aead.algo > RTE_DIM(aead_map)) ||
+		(aead_map[aead_xform->aead.algo].supported
+			!= ALGO_SUPPORTED)) {
+		MRVL_CRYPTO_LOG_ERR("AEAD algorithm not supported!");
+		return -EINVAL;
+	}
+
+	sess->sam_sess_params.dir =
+		(aead_xform->aead.op == RTE_CRYPTO_AEAD_OP_ENCRYPT) ?
+		SAM_DIR_ENCRYPT : SAM_DIR_DECRYPT;
+	sess->sam_sess_params.cipher_alg =
+		aead_map[aead_xform->aead.algo].cipher_alg;
+	sess->sam_sess_params.cipher_mode =
+		aead_map[aead_xform->aead.algo].cipher_mode;
+
+	/* Assume IV will be passed together with data. */
+	sess->sam_sess_params.cipher_iv = NULL;
+
+	/* Get max key length. */
+	if (aead_xform->aead.key.length >
+		aead_map[aead_xform->aead.algo].max_key_len) {
+		MRVL_CRYPTO_LOG_ERR("Wrong key length!");
+		return -EINVAL;
+	}
+
+	sess->sam_sess_params.cipher_key = aead_xform->aead.key.data;
+	sess->sam_sess_params.cipher_key_len = aead_xform->aead.key.length;
+
+	if (sess->sam_sess_params.cipher_mode == SAM_CIPHER_GCM)
+		sess->sam_sess_params.auth_alg = SAM_AUTH_AES_GCM;
+
+	sess->sam_sess_params.u.basic.auth_icv_len =
+		aead_xform->aead.digest_length;
+
+	sess->sam_sess_params.u.basic.auth_aad_len =
+		aead_xform->aead.aad_length;
+
+	return 0;
+}
+
+/**
+ * Parse crypto transform chain and setup session parameters.
+ *
+ * @param dev Pointer to crypto device
+ * @param sess Poiner to crypto session
+ * @param xform Pointer to configuration structure chain for crypto operations.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+int
+mrvl_crypto_set_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *xform)
+{
+	const struct rte_crypto_sym_xform *cipher_xform = NULL;
+	const struct rte_crypto_sym_xform *auth_xform = NULL;
+	const struct rte_crypto_sym_xform *aead_xform = NULL;
+
+	/* Filter out spurious/broken requests */
+	if (xform == NULL)
+		return -EINVAL;
+
+	sess->chain_order = mrvl_crypto_get_chain_order(xform);
+	switch (sess->chain_order) {
+	case MRVL_CRYPTO_CHAIN_CIPHER_AUTH:
+		cipher_xform = xform;
+		auth_xform = xform->next;
+		break;
+	case MRVL_CRYPTO_CHAIN_AUTH_CIPHER:
+		auth_xform = xform;
+		cipher_xform = xform->next;
+		break;
+	case MRVL_CRYPTO_CHAIN_CIPHER_ONLY:
+		cipher_xform = xform;
+		break;
+	case MRVL_CRYPTO_CHAIN_AUTH_ONLY:
+		auth_xform = xform;
+		break;
+	case MRVL_CRYPTO_CHAIN_COMBINED:
+		aead_xform = xform;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if ((cipher_xform != NULL) &&
+		(mrvl_crypto_set_cipher_session_parameters(
+			sess, cipher_xform) < 0)) {
+		MRVL_CRYPTO_LOG_ERR("Invalid/unsupported cipher parameters");
+		return -EINVAL;
+	}
+
+	if ((auth_xform != NULL) &&
+		(mrvl_crypto_set_auth_session_parameters(
+			sess, auth_xform) < 0)) {
+		MRVL_CRYPTO_LOG_ERR("Invalid/unsupported auth parameters");
+		return -EINVAL;
+	}
+
+	if ((aead_xform != NULL) &&
+		(mrvl_crypto_set_aead_session_parameters(
+			sess, aead_xform) < 0)) {
+		MRVL_CRYPTO_LOG_ERR("Invalid/unsupported aead parameters");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Process Operations
+ *-----------------------------------------------------------------------------
+ */
+
+/**
+ * Prepare a single request.
+ *
+ * This function basically translates DPDK crypto request into one
+ * understandable by MUDSK's SAM. If this is a first request in a session,
+ * it starts the session.
+ *
+ * @param request Pointer to pre-allocated && reset request buffer [Out].
+ * @param src_bd Pointer to pre-allocated source descriptor [Out].
+ * @param dst_bd Pointer to pre-allocated destination descriptor [Out].
+ * @param op Pointer to DPDK crypto operation struct [In].
+ */
+static inline int
+mrvl_request_prepare(struct sam_cio_op_params *request,
+		struct sam_buf_info *src_bd,
+		struct sam_buf_info *dst_bd,
+		struct rte_crypto_op *op)
+{
+	struct mrvl_crypto_session *sess;
+	struct rte_mbuf *dst_mbuf;
+	uint8_t *digest;
+
+	if (unlikely(op->sess_type == RTE_CRYPTO_OP_SESSIONLESS)) {
+		MRVL_CRYPTO_LOG_ERR("MRVL CRYPTO PMD only supports session "
+				"oriented requests, op (%p) is sessionless.",
+				op);
+		return -EINVAL;
+	}
+
+	sess = (struct mrvl_crypto_session *)get_session_private_data(
+			op->sym->session, cryptodev_driver_id);
+	if (unlikely(sess == NULL)) {
+		MRVL_CRYPTO_LOG_ERR("Session was not created for this device");
+		return -EINVAL;
+	}
+
+	/*
+	 * If application delivered us null dst buffer, it means it expects
+	 * us to deliver the result in src buffer.
+	 */
+	dst_mbuf = op->sym->m_dst ? op->sym->m_dst : op->sym->m_src;
+
+	request->sa = sess->sam_sess;
+	request->cookie = op;
+
+	/* Single buffers only, sorry. */
+	request->num_bufs = 1;
+	request->src = src_bd;
+	src_bd->vaddr = rte_pktmbuf_mtod(op->sym->m_src, void *);
+	src_bd->paddr = rte_pktmbuf_mtophys(op->sym->m_src);
+	src_bd->len = rte_pktmbuf_data_len(op->sym->m_src);
+
+	/* Empty source. */
+	if (rte_pktmbuf_data_len(op->sym->m_src) == 0) {
+		/* EIP does not support 0 length buffers. */
+		MRVL_CRYPTO_LOG_ERR("Buffer length == 0 not supported!");
+		return -1;
+	}
+
+	/* Empty destination. */
+	if (rte_pktmbuf_data_len(dst_mbuf) == 0) {
+		/* Make dst buffer fit at least source data. */
+		if (rte_pktmbuf_append(dst_mbuf,
+			rte_pktmbuf_data_len(op->sym->m_src)) == NULL) {
+			MRVL_CRYPTO_LOG_ERR("Unable to set big enough dst buffer!");
+			return -1;
+		}
+	}
+
+	request->dst = dst_bd;
+	dst_bd->vaddr = rte_pktmbuf_mtod(dst_mbuf, void *);
+	dst_bd->paddr = rte_pktmbuf_mtophys(dst_mbuf);
+
+	/*
+	 * We can use all available space in dst_mbuf,
+	 * not only what's used currently.
+	 */
+	dst_bd->len = dst_mbuf->buf_len - rte_pktmbuf_headroom(dst_mbuf);
+
+	if (sess->chain_order == MRVL_CRYPTO_CHAIN_COMBINED) {
+		request->cipher_len = op->sym->aead.data.length;
+		request->cipher_offset = op->sym->aead.data.offset;
+		request->cipher_iv = rte_crypto_op_ctod_offset(op, uint8_t *,
+			sess->cipher_iv_offset);
+
+		request->auth_aad = op->sym->aead.aad.data;
+		request->auth_offset = request->cipher_offset;
+		request->auth_len = request->cipher_len;
+	} else {
+		request->cipher_len = op->sym->cipher.data.length;
+		request->cipher_offset = op->sym->cipher.data.offset;
+		request->cipher_iv = rte_crypto_op_ctod_offset(op, uint8_t *,
+				sess->cipher_iv_offset);
+
+		request->auth_offset = op->sym->auth.data.offset;
+		request->auth_len = op->sym->auth.data.length;
+	}
+
+	digest = sess->chain_order == MRVL_CRYPTO_CHAIN_COMBINED ?
+		op->sym->aead.digest.data : op->sym->auth.digest.data;
+	if (digest == NULL) {
+		/* No auth - no worry. */
+		return 0;
+	}
+
+	request->auth_icv_offset = request->auth_offset + request->auth_len;
+
+	/*
+	 * EIP supports only scenarios where ICV(digest buffer) is placed at
+	 * auth_icv_offset. Any other placement means risking errors.
+	 */
+	if (sess->sam_sess_params.dir == SAM_DIR_ENCRYPT) {
+		/*
+		 * This should be the most common case anyway,
+		 * EIP will overwrite DST buffer at auth_icv_offset.
+		 */
+		if (rte_pktmbuf_mtod_offset(
+				dst_mbuf, uint8_t *,
+				request->auth_icv_offset) == digest) {
+			return 0;
+		}
+	} else {/* sess->sam_sess_params.dir == SAM_DIR_DECRYPT */
+		/*
+		 * EIP will look for digest at auth_icv_offset
+		 * offset in SRC buffer.
+		 */
+		if (rte_pktmbuf_mtod_offset(
+				op->sym->m_src, uint8_t *,
+				request->auth_icv_offset) == digest) {
+			return 0;
+		}
+	}
+
+	/*
+	 * If we landed here it means that digest pointer is
+	 * at different than expected place.
+	 */
+	return -1;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * PMD Framework handlers
+ *-----------------------------------------------------------------------------
+ */
+
+/**
+ * Enqueue burst.
+ *
+ * @param queue_pair Pointer to queue pair.
+ * @param ops Pointer to ops requests array.
+ * @param nb_ops Number of elements in ops requests array.
+ * @returns Number of elements consumed from ops.
+ */
+static uint16_t
+mrvl_crypto_pmd_enqueue_burst(void *queue_pair, struct rte_crypto_op **ops,
+		uint16_t nb_ops)
+{
+	uint16_t iter_ops = 0;
+	uint16_t to_enq = 0;
+	uint16_t consumed = 0;
+	int ret;
+	struct sam_cio_op_params requests[nb_ops];
+	/*
+	 * DPDK uses single fragment buffers, so we can KISS descriptors.
+	 * SAM does not store bd pointers, so on-stack scope will be enough.
+	 */
+	struct sam_buf_info src_bd[nb_ops];
+	struct sam_buf_info dst_bd[nb_ops];
+	struct mrvl_crypto_qp *qp = (struct mrvl_crypto_qp *)queue_pair;
+
+	if (nb_ops == 0)
+		return 0;
+
+	/* Prepare the burst. */
+	memset(&requests, 0, sizeof(requests));
+
+	/* Iterate through */
+	for (; iter_ops < nb_ops; ++iter_ops) {
+		if (mrvl_request_prepare(&requests[iter_ops],
+					&src_bd[iter_ops],
+					&dst_bd[iter_ops],
+					ops[iter_ops]) < 0) {
+			MRVL_CRYPTO_LOG_ERR(
+				"Error while parameters preparation!");
+			qp->stats.enqueue_err_count++;
+			ops[iter_ops]->status = RTE_CRYPTO_OP_STATUS_ERROR;
+
+			/*
+			 * Number of handled ops is increased
+			 * (even if the result of handling is error).
+			 */
+			++consumed;
+			break;
+		}
+
+		ops[iter_ops]->status =
+			RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
+
+		/* Increase the number of ops to enqueue. */
+		++to_enq;
+	} /* for (; iter_ops < nb_ops;... */
+
+	if (to_enq > 0) {
+		/* Send the burst */
+		ret = sam_cio_enq(qp->cio, requests, &to_enq);
+		consumed += to_enq;
+		if (ret < 0) {
+			/*
+			 * Trust SAM that in this case returned value will be at
+			 * some point correct (now it is returned unmodified).
+			 */
+			qp->stats.enqueue_err_count += to_enq;
+			for (iter_ops = 0; iter_ops < to_enq; ++iter_ops)
+				ops[iter_ops]->status =
+					RTE_CRYPTO_OP_STATUS_ERROR;
+		}
+	}
+
+	qp->stats.enqueued_count += to_enq;
+	return consumed;
+}
+
+/**
+ * Dequeue burst.
+ *
+ * @param queue_pair Pointer to queue pair.
+ * @param ops Pointer to ops requests array.
+ * @param nb_ops Number of elements in ops requests array.
+ * @returns Number of elements dequeued.
+ */
+static uint16_t
+mrvl_crypto_pmd_dequeue_burst(void *queue_pair,
+		struct rte_crypto_op **ops,
+		uint16_t nb_ops)
+{
+	int ret;
+	struct mrvl_crypto_qp *qp = queue_pair;
+	struct sam_cio *cio = qp->cio;
+	struct sam_cio_op_result results[nb_ops];
+	uint16_t i;
+
+	ret = sam_cio_deq(cio, results, &nb_ops);
+	if (ret < 0) {
+		/* Count all dequeued as error. */
+		qp->stats.dequeue_err_count += nb_ops;
+
+		/* But act as they were dequeued anyway*/
+		qp->stats.dequeued_count += nb_ops;
+
+		return 0;
+	}
+
+	/* Unpack and check results. */
+	for (i = 0; i < nb_ops; ++i) {
+		ops[i] = results[i].cookie;
+
+		switch (results[i].status) {
+		case SAM_CIO_OK:
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
+			break;
+		case SAM_CIO_ERR_ICV:
+			MRVL_CRYPTO_LOG_DBG("CIO returned SAM_CIO_ERR_ICV.");
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
+			break;
+		default:
+			MRVL_CRYPTO_LOG_DBG(
+				"CIO returned Error: %d", results[i].status);
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_ERROR;
+			break;
+		}
+	}
+
+	qp->stats.dequeued_count += nb_ops;
+	return nb_ops;
+}
+
+/**
+ * Create a new crypto device.
+ *
+ * @param name Driver name.
+ * @param vdev Pointer to device structure.
+ * @param init_params Pointer to initialization parameters.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+cryptodev_mrvl_crypto_create(const char *name,
+		struct rte_vdev_device *vdev,
+		struct rte_crypto_vdev_init_params *init_params)
+{
+	struct rte_cryptodev *dev;
+	struct mrvl_crypto_private *internals;
+	struct sam_init_params	sam_params;
+	int ret;
+
+	if (init_params->name[0] == '\0') {
+		ret = rte_cryptodev_pmd_create_dev_name(
+				init_params->name, name);
+
+		if (ret < 0) {
+			MRVL_CRYPTO_LOG_ERR("failed to create unique name");
+			return ret;
+		}
+	}
+
+	dev = rte_cryptodev_vdev_pmd_init(init_params->name,
+				sizeof(struct mrvl_crypto_private),
+				init_params->socket_id, vdev);
+	if (dev == NULL) {
+		MRVL_CRYPTO_LOG_ERR("failed to create cryptodev vdev");
+		goto init_error;
+	}
+
+	dev->driver_id = cryptodev_driver_id;
+	dev->dev_ops = rte_mrvl_crypto_pmd_ops;
+
+	/* Register rx/tx burst functions for data path. */
+	dev->enqueue_burst = mrvl_crypto_pmd_enqueue_burst;
+	dev->dequeue_burst = mrvl_crypto_pmd_dequeue_burst;
+
+	dev->feature_flags = RTE_CRYPTODEV_FF_SYMMETRIC_CRYPTO |
+			RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING |
+			RTE_CRYPTODEV_FF_HW_ACCELERATED;
+
+	/* Set vector instructions mode supported */
+	internals = dev->data->dev_private;
+
+	internals->max_nb_qpairs = init_params->max_nb_queue_pairs;
+	internals->max_nb_sessions = init_params->max_nb_sessions;
+
+	/*
+	 * ret == -EEXIST is correct, it means DMA
+	 * has been already initialized.
+	 */
+	ret = mv_sys_dma_mem_init(RTE_MRVL_MUSDK_DMA_MEMSIZE);
+	if ((ret < 0) && (ret != -EEXIST))
+		return ret;
+
+	sam_params.max_num_sessions = internals->max_nb_sessions;
+
+	return sam_init(&sam_params);
+
+init_error:
+	MRVL_CRYPTO_LOG_ERR(
+		"driver %s: %s failed", init_params->name, __func__);
+
+	cryptodev_mrvl_crypto_uninit(vdev);
+	return -EFAULT;
+}
+
+/**
+ * Initialize the crypto device.
+ *
+ * @param vdev Pointer to device structure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+cryptodev_mrvl_crypto_init(struct rte_vdev_device *vdev)
+{
+	struct rte_crypto_vdev_init_params init_params = { };
+	const char *name;
+	const char *input_args;
+	int ret;
+
+	name = rte_vdev_device_name(vdev);
+	if (name == NULL)
+		return -EINVAL;
+	input_args = rte_vdev_device_args(vdev);
+
+	if (!input_args)
+		return -EINVAL;
+
+	init_params.max_nb_queue_pairs = sam_get_num_inst() * SAM_HW_RING_NUM;
+	init_params.max_nb_sessions =
+		RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_SESSIONS;
+	init_params.socket_id = rte_socket_id();
+
+	ret = rte_cryptodev_vdev_parse_init_params(&init_params, input_args);
+	if (ret) {
+		RTE_LOG(ERR, PMD, "Failed to parse input arguments\n");
+		return ret;
+	}
+
+	RTE_LOG(INFO, PMD, "Initialising %s on NUMA node %d\n", name,
+			init_params.socket_id);
+	if (init_params.name[0] != '\0') {
+		RTE_LOG(INFO, PMD, "  User defined name = %s\n",
+			init_params.name);
+	}
+	RTE_LOG(INFO, PMD, "  Max number of queue pairs = %d\n",
+			init_params.max_nb_queue_pairs);
+	RTE_LOG(INFO, PMD, "  Max number of sessions = %d\n",
+			init_params.max_nb_sessions);
+
+	return cryptodev_mrvl_crypto_create(name, vdev, &init_params);
+}
+
+/**
+ * Uninitialize the crypto device
+ *
+ * @param vdev Pointer to device structure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+cryptodev_mrvl_crypto_uninit(struct rte_vdev_device *vdev)
+{
+	const char *name = rte_vdev_device_name(vdev);
+
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD,
+		"Closing Marvell crypto device %s on numa socket %u\n",
+		name, rte_socket_id());
+
+	sam_deinit();
+
+	return 0;
+}
+
+/**
+ * Basic driver handlers for use in the constructor.
+ */
+static struct rte_vdev_driver cryptodev_mrvl_pmd_drv = {
+	.probe = cryptodev_mrvl_crypto_init,
+	.remove = cryptodev_mrvl_crypto_uninit
+};
+
+/* Register the driver in constructor. */
+RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_MRVL_PMD, cryptodev_mrvl_pmd_drv);
+RTE_PMD_REGISTER_ALIAS(CRYPTODEV_NAME_MRVL_PMD, cryptodev_mrvl_pmd);
+RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_MRVL_PMD,
+	"max_nb_queue_pairs=<int> "
+	"max_nb_sessions=<int> "
+	"socket_id=<int>");
+RTE_PMD_REGISTER_CRYPTO_DRIVER(cryptodev_mrvl_pmd_drv, cryptodev_driver_id);
diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd_ops.c b/drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
new file mode 100644
index 0000000..f7374f8
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
@@ -0,0 +1,787 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) Semihalf 2017. 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 Semihalf 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 <string.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_cryptodev_pmd.h>
+
+#include "rte_mrvl_pmd_private.h"
+
+/**
+ * Capabilities list to be used in reporting to DPDK.
+ */
+static const struct rte_cryptodev_capabilities
+	mrvl_crypto_pmd_capabilities[] = {
+	{	/* MD5 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_MD5_HMAC,
+				.block_size = 64,
+				.key_size = {
+					.min = 64,
+					.max = 64,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.aad_size = { 0 }
+			}, }
+		}, }
+	},
+	{	/* MD5 */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+				{.auth = {
+					.algo = RTE_CRYPTO_AUTH_MD5,
+					.block_size = 64,
+					.key_size = {
+						.min = 0,
+						.max = 0,
+						.increment = 0
+					},
+					.digest_size = {
+						.min = 16,
+						.max = 16,
+						.increment = 0
+					},
+					.aad_size = { 0 }
+				}, }
+			}, }
+	},
+	{	/* SHA1 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+				{.auth = {
+					.algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+					.block_size = 64,
+					.key_size = {
+						.min = 16,
+						.max = 128,
+						.increment = 0
+					},
+					.digest_size = {
+						.min = 20,
+						.max = 20,
+						.increment = 0
+					},
+					.aad_size = { 0 }
+				}, }
+			}, }
+	},
+	{	/* SHA1 */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA1,
+				.block_size = 64,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 20,
+					.max = 20,
+					.increment = 0
+				},
+				.aad_size = { 0 }
+			}, }
+		}, }
+	},
+	{	/* SHA224 */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA224,
+				.block_size = 64,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 28,
+					.max = 28,
+					.increment = 0
+				},
+				.aad_size = { 0 }
+			}, }
+		}, }
+	},
+	{	/* SHA256 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+				{.auth = {
+					.algo = RTE_CRYPTO_AUTH_SHA256_HMAC,
+					.block_size = 64,
+					.key_size = {
+						.min = 1,
+						.max = 128,
+						.increment = 0
+					},
+					.digest_size = {
+						.min = 32,
+						.max = 32,
+						.increment = 0
+					},
+					.aad_size = { 0 }
+				}, }
+			}, }
+	},
+	{	/* SHA256 */
+			.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+				{.auth = {
+					.algo = RTE_CRYPTO_AUTH_SHA256,
+					.block_size = 64,
+					.key_size = {
+						.min = 0,
+						.max = 0,
+						.increment = 0
+					},
+					.digest_size = {
+						.min = 32,
+						.max = 32,
+						.increment = 0
+					},
+					.aad_size = { 0 }
+				}, }
+			}, }
+		},
+	{	/* SHA384 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA384_HMAC,
+				.block_size = 128,
+				.key_size = {
+					.min = 128,
+					.max = 128,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 48,
+					.max = 48,
+					.increment = 0
+				},
+				.aad_size = { 0 }
+			}, }
+		}, }
+	},
+	{	/* SHA384 */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA384,
+				.block_size = 128,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 48,
+					.max = 48,
+					.increment = 0
+				},
+				.aad_size = { 0 }
+			}, }
+		}, }
+	},
+	{	/* SHA512 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA512_HMAC,
+				.block_size = 128,
+				.key_size = {
+					.min = 128,
+					.max = 128,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 64,
+					.max = 64,
+					.increment = 0
+				},
+				.aad_size = { 0 }
+			}, }
+		}, }
+	},
+	{	/* SHA512  */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA512,
+				.block_size = 128,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 64,
+					.max = 64,
+					.increment = 0
+				},
+				.aad_size = { 0 }
+			}, }
+		}, }
+	},
+	{	/* AES CBC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+				{.cipher = {
+					.algo = RTE_CRYPTO_CIPHER_AES_CBC,
+					.block_size = 16,
+					.key_size = {
+						.min = 16,
+						.max = 32,
+						.increment = 8
+					},
+					.iv_size = {
+						.min = 16,
+						.max = 16,
+						.increment = 0
+					}
+				}, }
+			}, }
+	},
+	{	/* AES CTR */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_AES_CTR,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 32,
+					.increment = 8
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* AES GCM */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AEAD,
+			{.aead = {
+				.algo = RTE_CRYPTO_AEAD_AES_GCM,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 32,
+					.increment = 8
+				},
+				.digest_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.aad_size = {
+					.min = 8,
+					.max = 12,
+					.increment = 4
+				},
+				.iv_size = {
+					.min = 12,
+					.max = 16,
+					.increment = 4
+				}
+			}, }
+		}, }
+	},
+	{	/* AES GMAC (AUTH) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_AES_GMAC,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 32,
+					.increment = 8
+				},
+				.digest_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 8,
+					.max = 65532,
+					.increment = 4
+				}
+			}, }
+		}, }
+	},
+	{	/* 3DES CBC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_3DES_CBC,
+				.block_size = 8,
+				.key_size = {
+					.min = 24,
+					.max = 24,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 8,
+					.max = 8,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* 3DES CTR */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_3DES_CTR,
+				.block_size = 8,
+				.key_size = {
+					.min = 24,
+					.max = 24,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 8,
+					.max = 8,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+
+	RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
+};
+
+
+/**
+ * Configure device (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param config Pointer to configuration structure.
+ * @returns 0. Always.
+ */
+static int
+mrvl_crypto_pmd_config(__rte_unused struct rte_cryptodev *dev,
+		__rte_unused struct rte_cryptodev_config *config)
+{
+	return 0;
+}
+
+/**
+ * Start device (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @returns 0. Always.
+ */
+static int
+mrvl_crypto_pmd_start(__rte_unused struct rte_cryptodev *dev)
+{
+	return 0;
+}
+
+/**
+ * Stop device (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @returns 0. Always.
+ */
+static void
+mrvl_crypto_pmd_stop(__rte_unused struct rte_cryptodev *dev)
+{
+}
+
+/**
+ * Get device statistics (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param stats Pointer to statistics structure [out].
+ */
+static void
+mrvl_crypto_pmd_stats_get(struct rte_cryptodev *dev,
+		struct rte_cryptodev_stats *stats)
+{
+	int qp_id;
+
+	for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++) {
+		struct mrvl_crypto_qp *qp = dev->data->queue_pairs[qp_id];
+
+		stats->enqueued_count += qp->stats.enqueued_count;
+		stats->dequeued_count += qp->stats.dequeued_count;
+
+		stats->enqueue_err_count += qp->stats.enqueue_err_count;
+		stats->dequeue_err_count += qp->stats.dequeue_err_count;
+	}
+}
+
+/**
+ * Reset device statistics (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ */
+static void
+mrvl_crypto_pmd_stats_reset(struct rte_cryptodev *dev)
+{
+	int qp_id;
+
+	for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++) {
+		struct mrvl_crypto_qp *qp = dev->data->queue_pairs[qp_id];
+
+		memset(&qp->stats, 0, sizeof(qp->stats));
+	}
+}
+
+/**
+ * Get device info (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param dev_info Pointer to the device info structure [out].
+ */
+static void
+mrvl_crypto_pmd_info_get(struct rte_cryptodev *dev,
+		struct rte_cryptodev_info *dev_info)
+{
+	struct mrvl_crypto_private *internals = dev->data->dev_private;
+
+	if (dev_info != NULL) {
+		dev_info->driver_id = dev->driver_id;
+		dev_info->feature_flags = dev->feature_flags;
+		dev_info->capabilities = mrvl_crypto_pmd_capabilities;
+		dev_info->max_nb_queue_pairs = internals->max_nb_qpairs;
+		dev_info->sym.max_nb_sessions = internals->max_nb_sessions;
+	}
+}
+
+/**
+ * Release queue pair (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param qp_id ID of Queue Pair to release.
+ * @returns 0. Always.
+ */
+static int
+mrvl_crypto_pmd_qp_release(struct rte_cryptodev *dev, uint16_t qp_id)
+{
+	struct mrvl_crypto_qp *qp =
+			(struct mrvl_crypto_qp *)dev->data->queue_pairs[qp_id];
+
+	if (dev->data->queue_pairs[qp_id] != NULL) {
+		sam_cio_flush(qp->cio);
+		sam_cio_deinit(qp->cio);
+		rte_free(dev->data->queue_pairs[qp_id]);
+		dev->data->queue_pairs[qp_id] = NULL;
+	}
+
+	return 0;
+}
+
+/**
+ * Close device (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @returns 0. Always.
+ */
+static int
+mrvl_crypto_pmd_close(struct rte_cryptodev *dev)
+{
+	int qp_id;
+
+	for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++)
+		mrvl_crypto_pmd_qp_release(dev, qp_id);
+
+	return 0;
+}
+
+/**
+ * Setup a queue pair (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param qp_id ID of the Queue Pair.
+ * @param qp_conf Queue pair configuration (nb of descriptors).
+ * @param socket_id NUMA socket to allocate memory on.
+ * @returns 0 upon success, negative value otherwise.
+ */
+static int
+mrvl_crypto_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
+		const struct rte_cryptodev_qp_conf *qp_conf,
+		int socket_id, struct rte_mempool *session_pool)
+{
+	struct mrvl_crypto_qp *qp = NULL;
+	char match[RTE_CRYPTODEV_NAME_LEN];
+	unsigned int n;
+
+	/* Allocate the queue pair data structure. */
+	qp = rte_zmalloc_socket("MRVL Crypto PMD Queue Pair", sizeof(*qp),
+					RTE_CACHE_LINE_SIZE, socket_id);
+	if (qp == NULL)
+		return -ENOMEM;
+
+	/* Free old qp prior setup if needed. */
+	if (dev->data->queue_pairs[qp_id] != NULL)
+		mrvl_crypto_pmd_qp_release(dev, qp_id);
+
+	do { /* Error handling block */
+
+		/*
+		 * This extra check is necessary due to a bug in
+		 * crypto library.
+		 */
+		int num = sam_get_num_inst();
+		if (num == 0) {
+			MRVL_CRYPTO_LOG_ERR("No crypto engines detected.\n");
+			return -1;
+		}
+
+		/*
+		 * In case two crypto engines are enabled qps will
+		 * be evenly spread among them. Even and odd qps will
+		 * be handled by cio-0 and cio-1 respectively. qp-cio mapping
+		 * will look as follows:
+		 *
+		 * qp:      0        1        2        3
+		 * cio-x:y: cio-0:0, cio-1:0, cio-0:1, cio-1:1
+		 *
+		 * qp:      4        5        6        7
+		 * cio-x:y: cio-0:2, cio-1:2, cio-0:3, cio-1:3
+		 *
+		 * In case just one engine is enabled mapping will look as
+		 * follows:
+		 * qp:      0        1        2        3
+		 * cio-x:y: cio-0:0, cio-0:1, cio-0:2, cio-0:3
+		 */
+		n = snprintf(match, sizeof(match), "cio-%u:%u",
+				qp_id % num, qp_id / num);
+
+		if (n >= sizeof(match))
+			break;
+
+		qp->cio_params.match = match;
+		qp->cio_params.size = qp_conf->nb_descriptors;
+
+		if (sam_cio_init(&qp->cio_params, &qp->cio) < 0)
+			break;
+
+		qp->sess_mp = session_pool;
+
+		memset(&qp->stats, 0, sizeof(qp->stats));
+		dev->data->queue_pairs[qp_id] = qp;
+		return 0;
+	} while (0);
+
+	rte_free(qp);
+	return -1;
+}
+
+/** Start queue pair (PMD ops callback) - not supported.
+ *
+ * @param dev Pointer to the device structure.
+ * @param qp_id ID of the Queue Pair.
+ * @returns -ENOTSUP. Always.
+ */
+static int
+mrvl_crypto_pmd_qp_start(__rte_unused struct rte_cryptodev *dev,
+		__rte_unused uint16_t queue_pair_id)
+{
+	return -ENOTSUP;
+}
+
+/** Stop queue pair (PMD ops callback) - not supported.
+ *
+ * @param dev Pointer to the device structure.
+ * @param qp_id ID of the Queue Pair.
+ * @returns -ENOTSUP. Always.
+ */
+static int
+mrvl_crypto_pmd_qp_stop(__rte_unused struct rte_cryptodev *dev,
+		__rte_unused uint16_t queue_pair_id)
+{
+	return -ENOTSUP;
+}
+
+/** Return the number of allocated queue pairs (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @returns Number of allocated queue pairs.
+ */
+static uint32_t
+mrvl_crypto_pmd_qp_count(struct rte_cryptodev *dev)
+{
+	return dev->data->nb_queue_pairs;
+}
+
+/** Returns the size of the session structure (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure [Unused].
+ * @returns Size of Marvell crypto session.
+ */
+static unsigned
+mrvl_crypto_pmd_session_get_size(__rte_unused struct rte_cryptodev *dev)
+{
+	return sizeof(struct mrvl_crypto_session);
+}
+
+/** Configure the session from a crypto xform chain (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param xform Pointer to the crytpo configuration structure.
+ * @param sess Pointer to the empty session structure.
+ * @returns 0 upon success, negative value otherwise.
+ */
+static int
+mrvl_crypto_pmd_session_configure(__rte_unused struct rte_cryptodev *dev,
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mp)
+{
+	struct mrvl_crypto_session *mrvl_sess;
+	void *sess_private_data;
+	int ret;
+
+	if (sess == NULL) {
+		MRVL_CRYPTO_LOG_ERR("Invalid session struct.");
+		return -EINVAL;
+	}
+
+	if (rte_mempool_get(mp, &sess_private_data)) {
+		CDEV_LOG_ERR("Couldn't get object from session mempool.");
+		return -ENOMEM;
+	}
+
+	ret = mrvl_crypto_set_session_parameters(sess_private_data, xform);
+	if (ret != 0) {
+		MRVL_CRYPTO_LOG_ERR("Failed to configure session parameters.");
+
+		/* Return session to mempool */
+		rte_mempool_put(mp, sess_private_data);
+		return ret;
+	}
+
+	set_session_private_data(sess, dev->driver_id, sess_private_data);
+
+	mrvl_sess = (struct mrvl_crypto_session *)sess_private_data;
+	if (sam_session_create(&mrvl_sess->sam_sess_params,
+				&mrvl_sess->sam_sess) < 0) {
+		MRVL_CRYPTO_LOG_DBG("Failed to create session!");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ * Clear the memory of session so it doesn't leave key material behind.
+ *
+ * @param dev Pointer to the device structure.
+ * @returns 0. Always.
+ */
+static void
+mrvl_crypto_pmd_session_clear(struct rte_cryptodev *dev,
+		struct rte_cryptodev_sym_session *sess)
+{
+
+	uint8_t index = dev->driver_id;
+	void *sess_priv = get_session_private_data(sess, index);
+
+	/* Zero out the whole structure */
+	if (sess_priv) {
+		struct mrvl_crypto_session *mrvl_sess =
+			(struct mrvl_crypto_session *)sess_priv;
+
+		if (mrvl_sess->sam_sess &&
+		    sam_session_destroy(mrvl_sess->sam_sess) < 0) {
+			MRVL_CRYPTO_LOG_INFO("Error while destroying session!");
+		}
+
+		memset(sess, 0, sizeof(struct mrvl_crypto_session));
+		struct rte_mempool *sess_mp = rte_mempool_from_obj(sess_priv);
+		set_session_private_data(sess, index, NULL);
+		rte_mempool_put(sess_mp, sess_priv);
+	}
+}
+
+/**
+ * PMD handlers for crypto ops.
+ */
+static struct rte_cryptodev_ops mrvl_crypto_pmd_ops = {
+		.dev_configure		= mrvl_crypto_pmd_config,
+		.dev_start		= mrvl_crypto_pmd_start,
+		.dev_stop		= mrvl_crypto_pmd_stop,
+		.dev_close		= mrvl_crypto_pmd_close,
+
+		.dev_infos_get		= mrvl_crypto_pmd_info_get,
+
+		.stats_get		= mrvl_crypto_pmd_stats_get,
+		.stats_reset		= mrvl_crypto_pmd_stats_reset,
+
+		.queue_pair_setup	= mrvl_crypto_pmd_qp_setup,
+		.queue_pair_release	= mrvl_crypto_pmd_qp_release,
+		.queue_pair_start	= mrvl_crypto_pmd_qp_start,
+		.queue_pair_stop	= mrvl_crypto_pmd_qp_stop,
+		.queue_pair_count	= mrvl_crypto_pmd_qp_count,
+
+		.session_get_size	= mrvl_crypto_pmd_session_get_size,
+		.session_configure	= mrvl_crypto_pmd_session_configure,
+		.session_clear		= mrvl_crypto_pmd_session_clear
+};
+
+struct rte_cryptodev_ops *rte_mrvl_crypto_pmd_ops = &mrvl_crypto_pmd_ops;
diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd_private.h b/drivers/crypto/mrvl/rte_mrvl_pmd_private.h
new file mode 100644
index 0000000..2da14b8
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_mrvl_pmd_private.h
@@ -0,0 +1,121 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) Semihalf 2017. 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 Semihalf 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_MRVL_PMD_PRIVATE_H_
+#define _RTE_MRVL_PMD_PRIVATE_H_
+
+#include "rte_mrvl_compat.h"
+
+#define CRYPTODEV_NAME_MRVL_PMD crypto_mrvl
+/**< Marvell PMD device name */
+
+#define MRVL_CRYPTO_LOG_ERR(fmt, args...) \
+	RTE_LOG(ERR, CRYPTODEV, "[%s] %s() line %u: " fmt "\n",  \
+			RTE_STR(CRYPTODEV_NAME_MRVL_CRYPTO_PMD), \
+			__func__, __LINE__, ## args)
+
+#ifdef RTE_LIBRTE_MRVL_CRYPTO_DEBUG
+#define MRVL_CRYPTO_LOG_INFO(fmt, args...) \
+	RTE_LOG(INFO, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+			RTE_STR(CRYPTODEV_NAME_MRVL_CRYPTO_PMD), \
+			__func__, __LINE__, ## args)
+
+#define MRVL_CRYPTO_LOG_DBG(fmt, args...) \
+	RTE_LOG(DEBUG, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+			RTE_STR(CRYPTODEV_NAME_MRVL_CRYPTO_PMD), \
+			__func__, __LINE__, ## args)
+
+#else
+#define MRVL_CRYPTO_LOG_INFO(fmt, args...)
+#define MRVL_CRYPTO_LOG_DBG(fmt, args...)
+#endif
+
+/**
+ * Handy bits->bytes conversion macro.
+ */
+#define BITS2BYTES(x) ((x) >> 3)
+
+/** The operation order mode enumerator. */
+enum mrvl_crypto_chain_order {
+	MRVL_CRYPTO_CHAIN_CIPHER_ONLY,
+	MRVL_CRYPTO_CHAIN_AUTH_ONLY,
+	MRVL_CRYPTO_CHAIN_CIPHER_AUTH,
+	MRVL_CRYPTO_CHAIN_AUTH_CIPHER,
+	MRVL_CRYPTO_CHAIN_COMBINED,
+	MRVL_CRYPTO_CHAIN_NOT_SUPPORTED,
+};
+
+/** Private data structure for each crypto device. */
+struct mrvl_crypto_private {
+	unsigned int max_nb_qpairs;	/**< Max number of queue pairs */
+	unsigned int max_nb_sessions;	/**< Max number of sessions */
+};
+
+/** MRVL crypto queue pair structure. */
+struct mrvl_crypto_qp {
+	/** SAM CIO (MUSDK Queue Pair equivalent).*/
+	struct sam_cio *cio;
+
+	/** Session Mempool. */
+	struct rte_mempool *sess_mp;
+
+	/** Queue pair statistics. */
+	struct rte_cryptodev_stats stats;
+
+	/** CIO initialization parameters.*/
+	struct sam_cio_params cio_params;
+} __rte_cache_aligned;
+
+/** MRVL crypto private session structure. */
+struct mrvl_crypto_session {
+	/** Crypto operations chain order. */
+	enum mrvl_crypto_chain_order chain_order;
+
+	/** Session initialization parameters. */
+	struct sam_session_params sam_sess_params;
+
+	/** SAM session pointer. */
+	struct sam_sa *sam_sess;
+
+	/** Cipher IV offset. */
+	uint16_t cipher_iv_offset;
+} __rte_cache_aligned;
+
+/** Set and validate MRVL crypto session parameters */
+extern int
+mrvl_crypto_set_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *xform);
+
+/** device specific operations function pointer structure */
+extern struct rte_cryptodev_ops *rte_mrvl_crypto_pmd_ops;
+
+#endif /* _RTE_MRVL_PMD_PRIVATE_H_ */
diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd_version.map b/drivers/crypto/mrvl/rte_mrvl_pmd_version.map
new file mode 100644
index 0000000..a753031
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_mrvl_pmd_version.map
@@ -0,0 +1,3 @@
+DPDK_17.11 {
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 8df74bb..0f121ee 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -163,6 +163,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_ZUC)         += -lrte_pmd_zuc
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_ZUC)         += -L$(LIBSSO_ZUC_PATH)/build -lsso_zuc
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO)    += -lrte_pmd_armv8
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO)    += -L$(ARMV8_CRYPTO_LIB_PATH) -larmv8_crypto
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO) += -L$(LIBMUSDK_PATH)/lib -lrte_pmd_mrvl_crypto -lmusdk
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER) += -lrte_pmd_crypto_scheduler
 ifeq ($(CONFIG_RTE_LIBRTE_FSLMC_BUS),y)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_SEC)   += -lrte_pmd_dpaa2_sec
-- 
2.7.4

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

* [PATCH v2 2/4] doc: add mrvl crypto pmd documentation
  2017-09-28 10:23 ` [PATCH v2 0/4] add crypto " Tomasz Duszynski
  2017-09-28 10:23   ` [PATCH v2 1/4] crypto/mrvl: add mrvl crypto " Tomasz Duszynski
@ 2017-09-28 10:23   ` Tomasz Duszynski
  2017-10-05 14:45     ` De Lara Guarch, Pablo
  2017-09-28 10:23   ` [PATCH v2 3/4] maintainers: add maintainers for the mrvl crypto pmd Tomasz Duszynski
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-28 10:23 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add documentation for the MRVL CRYPTO PMD driver.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <jck@semihalf.com>
---
 doc/guides/cryptodevs/features/mrvl.ini |  42 +++++++
 doc/guides/cryptodevs/index.rst         |   1 +
 doc/guides/cryptodevs/mrvl.rst          | 198 ++++++++++++++++++++++++++++++++
 3 files changed, 241 insertions(+)
 create mode 100644 doc/guides/cryptodevs/features/mrvl.ini
 create mode 100644 doc/guides/cryptodevs/mrvl.rst

diff --git a/doc/guides/cryptodevs/features/mrvl.ini b/doc/guides/cryptodevs/features/mrvl.ini
new file mode 100644
index 0000000..6d2fe6a
--- /dev/null
+++ b/doc/guides/cryptodevs/features/mrvl.ini
@@ -0,0 +1,42 @@
+; Supported features of the 'mrvl' crypto driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Symmetric crypto       = Y
+Sym operation chaining = Y
+
+;
+; Supported crypto algorithms of a default crypto driver.
+;
+[Cipher]
+AES CBC (128)  = Y
+AES CBC (192)  = Y
+AES CBC (256)  = Y
+AES CTR (128)  = Y
+AES CTR (192)  = Y
+AES CTR (256)  = Y
+3DES CBC       = Y
+3DES CTR       = Y
+
+;
+; Supported authentication algorithms of a default crypto driver.
+;
+[Auth]
+MD5          = Y
+MD5 HMAC     = Y
+SHA1         = Y
+SHA1 HMAC    = Y
+SHA256       = Y
+SHA256 HMAC  = Y
+SHA384       = Y
+SHA384 HMAC  = Y
+SHA512       = Y
+SHA512 HMAC  = Y
+AES GMAC     = Y
+
+;
+; Supported AEAD algorithms of a default crypto driver.
+;
+[AEAD]
+AES GCM (128) = Y
diff --git a/doc/guides/cryptodevs/index.rst b/doc/guides/cryptodevs/index.rst
index 361b82d..a8ee0eb 100644
--- a/doc/guides/cryptodevs/index.rst
+++ b/doc/guides/cryptodevs/index.rst
@@ -42,6 +42,7 @@ Crypto Device Drivers
     dpaa2_sec
     kasumi
     openssl
+    mrvl
     null
     scheduler
     snow3g
diff --git a/doc/guides/cryptodevs/mrvl.rst b/doc/guides/cryptodevs/mrvl.rst
new file mode 100644
index 0000000..f5a83dc
--- /dev/null
+++ b/doc/guides/cryptodevs/mrvl.rst
@@ -0,0 +1,198 @@
+..  BSD LICENSE
+    Copyright(c) 2017 Semihalf. All rights reserved.
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in
+        the documentation and/or other materials provided with the
+        distribution.
+      * Neither the name of Semihalf 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.
+
+MRVL Crypto Poll Mode Driver
+============================
+
+The MRVL CRYPTO PMD (**librte_crypto_mrvl_pmd**) provides poll mode crypto driver
+support by utilizing MUSDK library, which provides cryptographic operations
+acceleration by using Security Acceleration Engine (EIP197) directly from
+user-space with minimum overhead and high performance.
+
+Features
+--------
+
+MRVL CRYPTO PMD has support for:
+
+* Symmetric crypto
+* Sym operation chaining
+* AES CBC (128)
+* AES CBC (192)
+* AES CBC (256)
+* AES CTR (128)
+* AES CTR (192)
+* AES CTR (256)
+* 3DES CBC
+* 3DES CTR
+* MD5
+* MD5 HMAC
+* SHA1
+* SHA1 HMAC
+* SHA256
+* SHA256 HMAC
+* SHA384
+* SHA384 HMAC
+* SHA512
+* SHA512 HMAC
+* AES GCM (128)
+
+Limitations
+-----------
+
+* Hardware only supports scenarios where ICV (digest buffer) is placed just
+  after the authenticated data. Other placement will result in error.
+
+Installation
+------------
+
+MRVL CRYPTO PMD driver compilation is disabled by default due to external dependencies.
+Currently there are two driver specific compilation options in
+``config/common_base`` available:
+
+- ``CONFIG_RTE_LIBRTE_MRVL_CRYPTO`` (default ``n``)
+
+    Toggle compilation of the librte_pmd_mrvl driver.
+
+- ``CONFIG_RTE_LIBRTE_MRVL_CRYPTO_DEBUG`` (default ``n``)
+
+    Toggle display of debugging messages.
+
+During compilation external MUSDK library, which provides direct access
+to Marvell's EIP197 cryptographic engine, is necessary. Library sources are
+available `here <https://github.com/MarvellEmbeddedProcessors/musdk-marvell/tree/musdk-armada-17.08>`_.
+
+Alternatively, prebuilt library can be downloaded from
+`Marvell Extranet <https://extranet.marvell.com>`_. Once approval has been
+granted, library can be found by typing ``musdk`` in the search box.
+
+For MUSDK library build instruction please refer to ``doc/musdk_get_started.txt``
+in library sources directory.
+
+Initialization
+--------------
+
+After successfully building MRVL CRYPTO PMD, the following modules need to be
+loaded:
+
+.. code-block:: console
+
+   insmod musdk_uio.ko
+   insmod mvpp2x_sysfs.ko
+   insmod mv_pp_uio.ko
+   insmod mv_sam_uio.ko
+   insmod crypto_safexcel.ko
+
+The following parameters (all optional) are exported by the driver:
+
+* max_nb_queue_pairs: maximum number of queue pairs in the device (8 by default).
+* max_nb_sessions: maximum number of sessions that can be created (2048 by default).
+* socket_id: socket on which to allocate the device resources on.
+
+l2fwd-crypto example application can be used to verify MRVL CRYPTO PMD
+operation:
+
+.. code-block:: console
+
+   ./l2fwd-crypto -c 0x3 --vdev=eth_mrvl,iface=eth0 --vdev=cryptodev_mrvl_pmd
+
+Example output:
+
+.. code-block:: console
+
+   [...]
+   PMD:   Max number of queue pairs = 8
+   PMD:   Max number of sessions = 2048
+   [ERROR] Dma object already exits.
+   [INFO] DMA buffers allocated for 2048 sessions (256 bytes)
+   Initializing port 0... [ERROR] [pp2_ppio_flush_vlan] routine not supported yet!
+   PMD: Failed to flush vlan list
+   [INFO] PORT: Port0 - link is up
+   [INFO] ---- GOP ID 0 configuration ----
+   [INFO] Port mode               : KR
+   [INFO] MAC status              : disabled
+   [INFO] Link status             : link up
+   [INFO] Port speed              : 10G
+   [INFO] Port duplex             : full
+   [INFO] Port: Egress enable tx_port_num=16 qmap=0x1
+   [INFO] PORT: Port0 - link is up
+   [INFO] ---- GOP ID 0 configuration ----
+   [INFO] Port mode               : KR
+   [INFO] MAC status              : disabled
+   [INFO] Link status             : link up
+   [INFO] Port speed              : 10G
+   [INFO] Port duplex             : full
+   [INFO] Port: Egress enable tx_port_num=16 qmap=0x1
+   [INFO] PORT: Port0 - link is down
+   [INFO] ---- GOP ID 0 configuration ----
+   [INFO] Port mode               : KR
+   [INFO] MAC status              : disabled
+   [INFO] Link status             : link down
+   [INFO] Port speed              : 10G
+   [INFO] Port duplex             : full
+   [INFO] Port: Egress enable tx_port_num=16 qmap=0x1
+   Port 0, MAC address: 00:50:43:02:21:20
+
+
+   Checking link statusdone
+   Port 0 Link Up - speed 0 Mbps - full-duplex
+   Lcore 0: RX port 0
+   [INFO] eip197: 0:0 registers: paddr: 0xf2880000, vaddr: 0x0x7f25480000
+   [INFO] DMA buffer (16448 bytes) for CDR #0 allocated: paddr = 0xb0525e00, \
+   vaddr = 0x7f21b24e00
+   [INFO] DMA buffer (16448 bytes) for RDR #0 allocated: paddr = 0xb0529f00, \
+   vaddr = 0x7f21b28f00
+   [INFO] DMA buffers allocated for 257 operations. Tokens - 256 bytes
+   Lcore 0: cryptodev 0
+   L2FWD: lcore 1 has nothing to do
+   L2FWD: entering main loop on lcore 0
+   L2FWD:  -- lcoreid=0 portid=0
+   L2FWD:  -- lcoreid=0 cryptoid=0
+   Options:-
+   nportmask: ffffffff
+   ports per lcore: 1
+   refresh period : 10000
+   single lcore mode: disabled
+   stats_printing: enabled
+   sessionless crypto: disabled
+
+   Crypto chain: Input --> Encrypt --> Auth generate --> Output
+
+   ---- Cipher information ---
+   Algorithm: aes-cbc
+   Cipher key: at [0x7f253cee80], len=16
+   00000000: C2 B1 90 57 16 32 A8 56 5A 16 CD A5 D1 24 64 C3 | ...W.2.VZ....$d.
+   IV: at [0x7f253cec80], len=16
+   00000000: F7 98 65 93 94 22 2C 8F A6 3C F1 F2 7C 88 FF 5D | ..e..",..<..|..]
+
+   ---- Authentication information ---
+   Algorithm: sha1-hmac
+   Auth key: at [0x7f253ced80], len=16
+   00000000: 8B 32 09 22 BF A7 AA 0D 0C 65 A3 2E 64 6E 74 44 | .2.".....e..dntD
+   AAD: at [0x7f253ceb80], len=
-- 
2.7.4

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

* [PATCH v2 3/4] maintainers: add maintainers for the mrvl crypto pmd
  2017-09-28 10:23 ` [PATCH v2 0/4] add crypto " Tomasz Duszynski
  2017-09-28 10:23   ` [PATCH v2 1/4] crypto/mrvl: add mrvl crypto " Tomasz Duszynski
  2017-09-28 10:23   ` [PATCH v2 2/4] doc: add mrvl crypto pmd documentation Tomasz Duszynski
@ 2017-09-28 10:23   ` Tomasz Duszynski
  2017-09-28 10:23   ` [PATCH v2 4/4] test: add mrvl crypto pmd unit tests Tomasz Duszynski
  2017-10-07 20:28   ` [PATCH v3 0/4] add crypto mrvl pmd driver Tomasz Duszynski
  4 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-28 10:23 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 MAINTAINERS | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index d4810cf..93800d2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -561,6 +561,16 @@ F: drivers/crypto/dpaa2_sec/
 F: doc/guides/cryptodevs/dpaa2_sec.rst
 F: doc/guides/cryptodevs/features/dpaa2_sec.ini
 
+MARVELL MRVL PMD
+M: Jacek Siuda <jck@semihalf.com>
+M: Tomasz Duszynski <tdu@semihalf.com>
+M: Dmitri Epshtein <dima@marvell.com>
+M: Natalie Samsonov <nsamsono@marvell.com>
+M: Jianbo Liu <jianbo.liu@linaro.org>
+F: drivers/crypto/mrvl/
+F: doc/guides/cryptodevs/mrvl.rst
+F: doc/guides/cryptodevs/mrvl.ini
+
 SNOW 3G PMD
 M: Pablo de Lara <pablo.de.lara.guarch@intel.com>
 F: drivers/crypto/snow3g/
-- 
2.7.4

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

* [PATCH v2 4/4] test: add mrvl crypto pmd unit tests
  2017-09-28 10:23 ` [PATCH v2 0/4] add crypto " Tomasz Duszynski
                     ` (2 preceding siblings ...)
  2017-09-28 10:23   ` [PATCH v2 3/4] maintainers: add maintainers for the mrvl crypto pmd Tomasz Duszynski
@ 2017-09-28 10:23   ` Tomasz Duszynski
  2017-10-07 20:28   ` [PATCH v3 0/4] add crypto mrvl pmd driver Tomasz Duszynski
  4 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-09-28 10:23 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add unit tests for MRVL CRYPTO PMD driver.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <jck@semihalf.com>
---
 test/test/test_cryptodev.c                  | 168 ++++++++++++++++++++++++++++
 test/test/test_cryptodev.h                  |   1 +
 test/test/test_cryptodev_aes_test_vectors.h |  72 ++++++++----
 test/test/test_cryptodev_blockcipher.c      |   9 +-
 test/test/test_cryptodev_blockcipher.h      |   1 +
 test/test/test_cryptodev_des_test_vectors.h |  24 ++--
 6 files changed, 242 insertions(+), 33 deletions(-)

diff --git a/test/test/test_cryptodev.c b/test/test/test_cryptodev.c
index a4116c6..9fb6a2c 100644
--- a/test/test/test_cryptodev.c
+++ b/test/test/test_cryptodev.c
@@ -341,6 +341,28 @@ testsuite_setup(void)
 		}
 	}
 
+	/* Create a MRVL device if required */
+	if (gbl_driver_id == rte_cryptodev_driver_id_get(
+			RTE_STR(CRYPTODEV_MRVL_PMD))) {
+#ifndef RTE_LIBRTE_PMD_MRVL_CRYPTO
+		RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO must be"
+			" enabled in config file to run this testsuite.\n");
+		return TEST_FAILED;
+#endif
+		nb_devs = rte_cryptodev_device_count_by_driver(
+				rte_cryptodev_driver_id_get(
+				RTE_STR(CRYPTODEV_NAME_MRVL_PMD)));
+		if (nb_devs < 1) {
+			ret = rte_vdev_init(
+				RTE_STR(CRYPTODEV_NAME_MRVL_PMD),
+				NULL);
+
+			TEST_ASSERT(ret == 0, "Failed to create "
+				"instance of pmd : %s",
+				RTE_STR(CRYPTODEV_NAME_MRVL_PMD));
+		}
+	}
+
 #ifdef RTE_LIBRTE_PMD_CRYPTO_SCHEDULER
 	if (gbl_driver_id == rte_cryptodev_driver_id_get(
 			RTE_STR(CRYPTODEV_NAME_SCHEDULER_PMD))) {
@@ -1862,6 +1884,101 @@ test_AES_chain_armv8_all(void)
 	return TEST_SUCCESS;
 }
 
+static int
+test_AES_chain_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_AES_CHAIN_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_AES_cipheronly_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_AES_CIPHERONLY_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_authonly_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_AUTHONLY_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_3DES_chain_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_3DES_CHAIN_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_3DES_cipheronly_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_3DES_CIPHERONLY_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
 /* ***** SNOW 3G Tests ***** */
 static int
 create_wireless_algo_hash_session(uint8_t dev_id,
@@ -8939,6 +9056,40 @@ static struct unit_test_suite cryptodev_armv8_testsuite  = {
 	}
 };
 
+static struct unit_test_suite cryptodev_mrvl_testsuite  = {
+	.suite_name = "Crypto Device Marvell Component Test Suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASE_ST(ut_setup, ut_teardown, test_multi_session),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_multi_session_random_usage),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_AES_chain_mrvl_all),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_AES_cipheronly_mrvl_all),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_authonly_mrvl_all),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_3DES_chain_mrvl_all),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_3DES_cipheronly_mrvl_all),
+
+		/** Negative tests */
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			authentication_verify_HMAC_SHA1_fail_data_corrupt),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			authentication_verify_HMAC_SHA1_fail_tag_corrupt),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			auth_decryption_AES128CBC_HMAC_SHA1_fail_data_corrupt),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			auth_decryption_AES128CBC_HMAC_SHA1_fail_tag_corrupt),
+
+		TEST_CASES_END() /**< NULL terminate unit test array */
+	}
+};
+
+
 static int
 test_cryptodev_qat(void /*argv __rte_unused, int argc __rte_unused*/)
 {
@@ -9083,6 +9234,22 @@ test_cryptodev_armv8(void)
 	return unit_test_suite_runner(&cryptodev_armv8_testsuite);
 }
 
+static int
+test_cryptodev_mrvl(void)
+{
+	gbl_driver_id = rte_cryptodev_driver_id_get(
+			RTE_STR(CRYPTODEV_NAME_MRVL_PMD));
+
+	if (gbl_driver_id == -1) {
+		RTE_LOG(ERR, USER1, "MRVL PMD must be loaded. Check if "
+				"CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO is enabled "
+				"in config file to run this testsuite.\n");
+		return TEST_FAILED;
+	}
+
+	return unit_test_suite_runner(&cryptodev_mrvl_testsuite);
+}
+
 #ifdef RTE_LIBRTE_PMD_CRYPTO_SCHEDULER
 
 static int
@@ -9136,4 +9303,5 @@ REGISTER_TEST_COMMAND(cryptodev_sw_snow3g_autotest, test_cryptodev_sw_snow3g);
 REGISTER_TEST_COMMAND(cryptodev_sw_kasumi_autotest, test_cryptodev_sw_kasumi);
 REGISTER_TEST_COMMAND(cryptodev_sw_zuc_autotest, test_cryptodev_sw_zuc);
 REGISTER_TEST_COMMAND(cryptodev_sw_armv8_autotest, test_cryptodev_armv8);
+REGISTER_TEST_COMMAND(cryptodev_sw_mrvl_autotest, test_cryptodev_mrvl);
 REGISTER_TEST_COMMAND(cryptodev_dpaa2_sec_autotest, test_cryptodev_dpaa2_sec);
diff --git a/test/test/test_cryptodev.h b/test/test/test_cryptodev.h
index 4509a09..2e9eb0b 100644
--- a/test/test/test_cryptodev.h
+++ b/test/test/test_cryptodev.h
@@ -88,6 +88,7 @@
 #define CRYPTODEV_NAME_ARMV8_PMD	crypto_armv8
 #define CRYPTODEV_NAME_DPAA2_SEC_PMD	crypto_dpaa2_sec
 #define CRYPTODEV_NAME_SCHEDULER_PMD	crypto_scheduler
+#define CRYPTODEV_NAME_MRVL_PMD		crypto_mrvl
 
 /**
  * Write (spread) data from buffer to mbuf data
diff --git a/test/test/test_cryptodev_aes_test_vectors.h b/test/test/test_cryptodev_aes_test_vectors.h
index e410018..0af50fd 100644
--- a/test/test/test_cryptodev_aes_test_vectors.h
+++ b/test/test/test_cryptodev_aes_test_vectors.h
@@ -1197,7 +1197,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CTR HMAC-SHA1 Decryption Digest "
@@ -1208,7 +1209,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-192-CTR XCBC Encryption Digest",
@@ -1245,7 +1247,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-256-CTR HMAC-SHA1 Decryption Digest "
@@ -1256,7 +1259,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest",
@@ -1267,14 +1271,16 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest "
 			"(short buffers)",
 		.test_data = &aes_test_data_13,
 		.op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest "
@@ -1298,14 +1304,16 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Decryption Digest "
 			"Verify (short buffers)",
 		.test_data = &aes_test_data_13,
 		.op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA256 Encryption Digest",
@@ -1316,14 +1324,16 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA256 Encryption Digest "
 			"(short buffers)",
 		.test_data = &aes_test_data_12,
 		.op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA256 Decryption Digest "
@@ -1335,14 +1345,16 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA256 Decryption Digest "
 			"Verify (short buffers)",
 		.test_data = &aes_test_data_12,
 		.op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA512 Encryption Digest",
@@ -1352,7 +1364,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA512 Encryption Digest "
@@ -1383,7 +1396,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA512 Decryption Digest "
@@ -1462,7 +1476,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA384 Decryption Digest "
@@ -1473,7 +1488,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest "
@@ -1505,7 +1521,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC Decryption",
@@ -1515,7 +1532,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-192-CBC Encryption",
@@ -1553,7 +1571,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-256-CBC Decryption",
@@ -1563,7 +1582,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-256-CBC OOP Encryption",
@@ -1589,7 +1609,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CTR Decryption",
@@ -1599,7 +1620,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-192-CTR Encryption",
@@ -1629,7 +1651,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-256-CTR Decryption",
@@ -1639,7 +1662,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CTR Encryption (12-byte IV)",
diff --git a/test/test/test_cryptodev_blockcipher.c b/test/test/test_cryptodev_blockcipher.c
index 6089af4..01fe136 100644
--- a/test/test/test_cryptodev_blockcipher.c
+++ b/test/test/test_cryptodev_blockcipher.c
@@ -92,6 +92,8 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 			RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD));
 	int dpaa2_sec_pmd = rte_cryptodev_driver_id_get(
 			RTE_STR(CRYPTODEV_NAME_DPAA2_SEC_PMD));
+	int mrvl_pmd = rte_cryptodev_driver_id_get(
+			RTE_STR(CRYPTODEV_NAME_MRVL_PMD));
 
 	int nb_segs = 1;
 
@@ -116,7 +118,8 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 	if (driver_id == dpaa2_sec_pmd ||
 			driver_id == qat_pmd ||
 			driver_id == openssl_pmd ||
-			driver_id == armv8_pmd) { /* Fall through */
+			driver_id == armv8_pmd ||
+			driver_id == mrvl_pmd) { /* Fall through */
 		digest_len = tdata->digest.len;
 	} else if (driver_id == aesni_mb_pmd ||
 			driver_id == scheduler_pmd) {
@@ -612,6 +615,8 @@ test_blockcipher_all_tests(struct rte_mempool *mbuf_pool,
 			RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD));
 	int qat_pmd = rte_cryptodev_driver_id_get(
 			RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD));
+	int mrvl_pmd = rte_cryptodev_driver_id_get(
+			RTE_STR(CRYPTODEV_NAME_MRVL_PMD));
 
 	switch (test_type) {
 	case BLKCIPHER_AES_CHAIN_TYPE:
@@ -670,6 +675,8 @@ test_blockcipher_all_tests(struct rte_mempool *mbuf_pool,
 		target_pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER;
 	else if (driver_id == dpaa2_pmd)
 		target_pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC;
+	else if (driver_id == mrvl_pmd)
+		target_pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MRVL;
 	else
 		TEST_ASSERT(0, "Unrecognized cryptodev type");
 
diff --git a/test/test/test_cryptodev_blockcipher.h b/test/test/test_cryptodev_blockcipher.h
index 22b8d20..6919336 100644
--- a/test/test/test_cryptodev_blockcipher.h
+++ b/test/test/test_cryptodev_blockcipher.h
@@ -53,6 +53,7 @@
 #define BLOCKCIPHER_TEST_TARGET_PMD_ARMV8	0x0008 /* ARMv8 flag */
 #define BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER	0x0010 /* Scheduler */
 #define BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC	0x0020 /* DPAA2_SEC flag */
+#define BLOCKCIPHER_TEST_TARGET_PMD_MRVL	0x0040 /* Marvell flag */
 
 #define BLOCKCIPHER_TEST_OP_CIPHER	(BLOCKCIPHER_TEST_OP_ENCRYPT | \
 					BLOCKCIPHER_TEST_OP_DECRYPT)
diff --git a/test/test/test_cryptodev_des_test_vectors.h b/test/test/test_cryptodev_des_test_vectors.h
index 0b6e0b8..ffcf657 100644
--- a/test/test/test_cryptodev_des_test_vectors.h
+++ b/test/test/test_cryptodev_des_test_vectors.h
@@ -851,13 +851,15 @@ static const struct blockcipher_test_case des_cipheronly_test_cases[] = {
 		.test_descr = "DES-CBC Encryption",
 		.test_data = &des_cbc_test_vector,
 		.op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "DES-CBC Decryption",
 		.test_data = &des_cbc_test_vector,
 		.op_mask = BLOCKCIPHER_TEST_OP_DECRYPT,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 
 };
@@ -1087,7 +1089,8 @@ static const struct blockcipher_test_case triple_des_chain_test_cases[] = {
 		.op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
 		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-192-CBC HMAC-SHA1 Decryption Digest Verify",
@@ -1095,19 +1098,22 @@ static const struct blockcipher_test_case triple_des_chain_test_cases[] = {
 		.op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC,
 		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-192-CBC SHA1 Encryption Digest",
 		.test_data = &triple_des192cbc_sha1_test_vector,
 		.op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-192-CBC SHA1 Decryption Digest Verify",
 		.test_data = &triple_des192cbc_sha1_test_vector,
 		.op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-128-CTR HMAC-SHA1 Encryption Digest",
@@ -1220,7 +1226,8 @@ static const struct blockcipher_test_case triple_des_cipheronly_test_cases[] = {
 		.op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT,
 		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-192-CBC Decryption",
@@ -1228,7 +1235,8 @@ static const struct blockcipher_test_case triple_des_cipheronly_test_cases[] = {
 		.op_mask = BLOCKCIPHER_TEST_OP_DECRYPT,
 		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-128-CTR Encryption",
-- 
2.7.4

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

* Re: [PATCH v2 0/4] add net mrvl pmd driver
  2017-09-28 10:22 ` [PATCH v2 0/4] add net mrvl pmd driver Tomasz Duszynski
                     ` (3 preceding siblings ...)
  2017-09-28 10:22   ` [PATCH v2 4/4] maintainers: add maintainers for the mrvl net pmd Tomasz Duszynski
@ 2017-09-28 11:06   ` Ferruh Yigit
  2017-09-28 11:40     ` Amit Tomer
  4 siblings, 1 reply; 110+ messages in thread
From: Ferruh Yigit @ 2017-09-28 11:06 UTC (permalink / raw)
  To: Tomasz Duszynski, dev; +Cc: mw, dima, nsamsono, Jianbo.liu

On 9/28/2017 11:22 AM, Tomasz Duszynski wrote:
> Hello,
> 
> This patch series introduces the net driver for Marvell Armada 7k/8k
> SoCs along with documentation.
> 
> Below you can find the list of features which net pmd supports:
> * Speed capabilities
> * Link status
> * Queue start/stop
> * MTU update
> * Jumbo frame
> * Promiscuous mode
> * Allmulticast mode
> * Unicast MAC filter
> * Multicast MAC filter
> * RSS hash
> * VLAN filter
> * CRC offload
> * L3 checksum offload
> * L4 checksum offload
> * Packet type parsing
> * Basic stats
> * Stats per queue
> 
> Tomasz Duszynski (4):
>   app: link the whole rte_cfgfile library
>   net/mrvl: add mrvl net pmd driver
>   doc: add mrvl net pmd documentation
>   maintainers: add maintainers for the mrvl net pmd

Hi Tomasz,

Good to see more vendors are contributing, welcome!

This patchset arrived a little late for this release cycle, I still
would like to get it but priority will be the existing waiting drivers,
so no promises :)

Thanks,
ferruh

<...>

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

* Re: [PATCH v2 0/4] add net mrvl pmd driver
  2017-09-28 11:06   ` [PATCH v2 0/4] add net mrvl pmd driver Ferruh Yigit
@ 2017-09-28 11:40     ` Amit Tomer
  2017-09-28 12:01       ` Marcin Wojtas
  0 siblings, 1 reply; 110+ messages in thread
From: Amit Tomer @ 2017-09-28 11:40 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jianbo.liu

>> This patch series introduces the net driver for Marvell Armada 7k/8k
>> SoCs along with documentation.

Wondering, if it could be tested on Marvell Armada 3700 based
ESPRESSObin board ?

Thanks
Amit

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

* Re: [PATCH v2 0/4] add net mrvl pmd driver
  2017-09-28 11:40     ` Amit Tomer
@ 2017-09-28 12:01       ` Marcin Wojtas
  0 siblings, 0 replies; 110+ messages in thread
From: Marcin Wojtas @ 2017-09-28 12:01 UTC (permalink / raw)
  To: Amit Tomer
  Cc: Ferruh Yigit, Tomasz Duszynski, dev, Dmitri Epshtein, nsamsono,
	Jianbo.liu

Hi Amit,

2017-09-28 13:40 GMT+02:00 Amit Tomer <amittomer25@gmail.com>:
>
> >> This patch series introduces the net driver for Marvell Armada 7k/8k
> >> SoCs along with documentation.
>
> Wondering, if it could be tested on Marvell Armada 3700 based
> ESPRESSObin board ?
>

Different SoC. This one is intended to work with Armada 8040 MacchiatoBin board.

Best regards,
Marcin

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

* Re: [PATCH v2 2/4] net/mrvl: add mrvl net pmd driver
  2017-09-28 10:22   ` [PATCH v2 2/4] net/mrvl: add mrvl net " Tomasz Duszynski
@ 2017-09-29 15:38     ` Stephen Hemminger
  2017-10-02 11:08       ` Bruce Richardson
  2017-10-03  6:23       ` Tomasz Duszynski
  0 siblings, 2 replies; 110+ messages in thread
From: Stephen Hemminger @ 2017-09-29 15:38 UTC (permalink / raw)
  To: Tomasz Duszynski; +Cc: dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On Thu, 28 Sep 2017 12:22:36 +0200
Tomasz Duszynski <tdu@semihalf.com> wrote:

> +
> +struct mrvl_rxq;
> +struct mrvl_txq;

These forward decl should not be nececessary
> +static inline int
> +mrvl_get_bpool_size(int	pp2_id, int pool_id)
 No tab here please

Why does this need to be inlined?  Is it in critical path?


> +{
> +	int i;
> +	int size = 0;
> +
> +	for (i = mrvl_lcore_first; i <= mrvl_lcore_last; i++)
> +		size += mrvl_port_bpool_size[pp2_id][pool_id][i];
> +
> +	return size;
> +}
> +

Also, I prefer that the following restrictions from the kernel be
also applied to DPDK code.

### [dpdk-dev] [PATCH v2 2/4] net/mrvl: add mrvl net pmd driver

CHECK:LINE_SPACING: Please don't use multiple blank lines
#452: FILE: drivers/net/mrvl/mrvl_ethdev.c:180:
+
+

WARNING:LINE_SPACING: Missing a blank line after declarations
#457: FILE: drivers/net/mrvl/mrvl_ethdev.c:185:
+	int n = sizeof(*bitmap) * 8 - __builtin_clz(*bitmap);
+	if (n >= max)

CHECK:LINE_SPACING: Please don't use multiple blank lines
#562: FILE: drivers/net/mrvl/mrvl_ethdev.c:290:
+
+

WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'priv->ppio_params.inqs_params.tcs_params[i].inqs_params'
#880: FILE: drivers/net/mrvl/mrvl_ethdev.c:608:
+			rte_free(priv->ppio_params.inqs_params.
+				tcs_params[i].inqs_params);

WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'priv->ppio_params.inqs_params.tcs_params[i].inqs_params'
#882: FILE: drivers/net/mrvl/mrvl_ethdev.c:610:
+			priv->ppio_params.inqs_params.
+				tcs_params[i].inqs_params = NULL;

WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'priv->ppio_params.inqs_params.tcs_params[tc].inqs_params[inq].size'
#1330: FILE: drivers/net/mrvl/mrvl_ethdev.c:1058:
+	qinfo->nb_desc = priv->ppio_params.inqs_params.
+			 tcs_params[tc].inqs_params[inq].size;

WARNING:SPLIT_STRING: quoted string split across lines
#1476: FILE: drivers/net/mrvl/mrvl_ethdev.c:1204:
+		RTE_LOG(ERR, PMD, "Mbuf size must be increased to %u bytes"
+				  " to hold up to %u bytes of data.\n",

WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'priv->ppio_params.inqs_params.tcs_params[priv->rxq_map[rxq->queue_id].tc'
#1500: FILE: drivers/net/mrvl/mrvl_ethdev.c:1228:
+	priv->ppio_params.inqs_params.
+		tcs_params[priv->rxq_map[rxq->queue_id].tc].

WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'q->priv->ppio_params.inqs_params.tcs_params[q->priv->rxq_map[q->queue_id].tc'
#1532: FILE: drivers/net/mrvl/mrvl_ethdev.c:1260:
+	num = q->priv->ppio_params.inqs_params.
+			tcs_params[q->priv->rxq_map[q->queue_id].tc].

WARNING:SPLIT_STRING: quoted string split across lines
#1902: FILE: drivers/net/mrvl/mrvl_ethdev.c:1630:
+			RTE_LOG(DEBUG, PMD, "\nport-%d:%d: bpool %d oversize -"
+				" remove %d buffers (pool size: %d -> %d)\n",

WARNING:SPLIT_STRING: quoted string split across lines
#2094: FILE: drivers/net/mrvl/mrvl_ethdev.c:1822:
+			"No room in shadow queue for %d packets!!!"
+			"%d packets will be sent.\n",

CHECK:LINE_SPACING: Please don't use multiple blank lines
#2294: FILE: drivers/net/mrvl/mrvl_ethdev.c:2022:
+
+

CHECK:LINE_SPACING: Please don't use multiple blank lines
#2595: FILE: drivers/net/mrvl/mrvl_ethdev.h:40:
+
+

WARNING:LINE_SPACING: Missing a blank line after declarations
#3253: FILE: drivers/net/mrvl/mrvl_qos.c:577:
+			uint8_t idx = port_cfg->tc[tc].inq[i];
+			priv->rxq_map[idx].tc = tc;

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

* Re: [PATCH v2 2/4] net/mrvl: add mrvl net pmd driver
  2017-09-29 15:38     ` Stephen Hemminger
@ 2017-10-02 11:08       ` Bruce Richardson
  2017-10-03  6:33         ` Tomasz Duszynski
  2017-10-03  6:23       ` Tomasz Duszynski
  1 sibling, 1 reply; 110+ messages in thread
From: Bruce Richardson @ 2017-10-02 11:08 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On Fri, Sep 29, 2017 at 08:38:00AM -0700, Stephen Hemminger wrote:
> On Thu, 28 Sep 2017 12:22:36 +0200
> Tomasz Duszynski <tdu@semihalf.com> wrote:
> 
> > +
> > +struct mrvl_rxq;
> > +struct mrvl_txq;
> 
> These forward decl should not be nececessary
> > +static inline int
> > +mrvl_get_bpool_size(int	pp2_id, int pool_id)
>  No tab here please
> 
> Why does this need to be inlined?  Is it in critical path?
> 
> 
> > +{
> > +	int i;
> > +	int size = 0;
> > +
> > +	for (i = mrvl_lcore_first; i <= mrvl_lcore_last; i++)
> > +		size += mrvl_port_bpool_size[pp2_id][pool_id][i];
> > +
> > +	return size;
> > +}
> > +
> 
> Also, I prefer that the following restrictions from the kernel be
> also applied to DPDK code.
> 

+1 for LINE_SPACING (multiple blank lines), MULTILINE_DEREFERENCE and
SPLIT_STRING. [Is split string not already enforced?]

I'm a bit ambivilant about forcing a blank line after definitions, I
think it's a good idea in most cases, but I'm not sure it needs to be
enforced in all cases.

/Bruce

> ### [dpdk-dev] [PATCH v2 2/4] net/mrvl: add mrvl net pmd driver
> 
> CHECK:LINE_SPACING: Please don't use multiple blank lines
> #452: FILE: drivers/net/mrvl/mrvl_ethdev.c:180:
> +
> +
> 
> WARNING:LINE_SPACING: Missing a blank line after declarations
> #457: FILE: drivers/net/mrvl/mrvl_ethdev.c:185:
> +	int n = sizeof(*bitmap) * 8 - __builtin_clz(*bitmap);
> +	if (n >= max)
> 
> CHECK:LINE_SPACING: Please don't use multiple blank lines
> #562: FILE: drivers/net/mrvl/mrvl_ethdev.c:290:
> +
> +
> 
> WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'priv->ppio_params.inqs_params.tcs_params[i].inqs_params'
> #880: FILE: drivers/net/mrvl/mrvl_ethdev.c:608:
> +			rte_free(priv->ppio_params.inqs_params.
> +				tcs_params[i].inqs_params);
> 
> WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'priv->ppio_params.inqs_params.tcs_params[i].inqs_params'
> #882: FILE: drivers/net/mrvl/mrvl_ethdev.c:610:
> +			priv->ppio_params.inqs_params.
> +				tcs_params[i].inqs_params = NULL;
> 
> WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'priv->ppio_params.inqs_params.tcs_params[tc].inqs_params[inq].size'
> #1330: FILE: drivers/net/mrvl/mrvl_ethdev.c:1058:
> +	qinfo->nb_desc = priv->ppio_params.inqs_params.
> +			 tcs_params[tc].inqs_params[inq].size;
> 
> WARNING:SPLIT_STRING: quoted string split across lines
> #1476: FILE: drivers/net/mrvl/mrvl_ethdev.c:1204:
> +		RTE_LOG(ERR, PMD, "Mbuf size must be increased to %u bytes"
> +				  " to hold up to %u bytes of data.\n",
> 
> WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'priv->ppio_params.inqs_params.tcs_params[priv->rxq_map[rxq->queue_id].tc'
> #1500: FILE: drivers/net/mrvl/mrvl_ethdev.c:1228:
> +	priv->ppio_params.inqs_params.
> +		tcs_params[priv->rxq_map[rxq->queue_id].tc].
> 
> WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'q->priv->ppio_params.inqs_params.tcs_params[q->priv->rxq_map[q->queue_id].tc'
> #1532: FILE: drivers/net/mrvl/mrvl_ethdev.c:1260:
> +	num = q->priv->ppio_params.inqs_params.
> +			tcs_params[q->priv->rxq_map[q->queue_id].tc].
> 
> WARNING:SPLIT_STRING: quoted string split across lines
> #1902: FILE: drivers/net/mrvl/mrvl_ethdev.c:1630:
> +			RTE_LOG(DEBUG, PMD, "\nport-%d:%d: bpool %d oversize -"
> +				" remove %d buffers (pool size: %d -> %d)\n",
> 
> WARNING:SPLIT_STRING: quoted string split across lines
> #2094: FILE: drivers/net/mrvl/mrvl_ethdev.c:1822:
> +			"No room in shadow queue for %d packets!!!"
> +			"%d packets will be sent.\n",
> 
> CHECK:LINE_SPACING: Please don't use multiple blank lines
> #2294: FILE: drivers/net/mrvl/mrvl_ethdev.c:2022:
> +
> +
> 
> CHECK:LINE_SPACING: Please don't use multiple blank lines
> #2595: FILE: drivers/net/mrvl/mrvl_ethdev.h:40:
> +
> +
> 
> WARNING:LINE_SPACING: Missing a blank line after declarations
> #3253: FILE: drivers/net/mrvl/mrvl_qos.c:577:
> +			uint8_t idx = port_cfg->tc[tc].inq[i];
> +			priv->rxq_map[idx].tc = tc;
> 

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

* Re: [PATCH v2 2/4] net/mrvl: add mrvl net pmd driver
  2017-09-29 15:38     ` Stephen Hemminger
  2017-10-02 11:08       ` Bruce Richardson
@ 2017-10-03  6:23       ` Tomasz Duszynski
  1 sibling, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-03  6:23 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On Fri, Sep 29, 2017 at 08:38:00AM -0700, Stephen Hemminger wrote:
> On Thu, 28 Sep 2017 12:22:36 +0200
> Tomasz Duszynski <tdu@semihalf.com> wrote:
>
> > +
> > +struct mrvl_rxq;
> > +struct mrvl_txq;
>
> These forward decl should not be nececessary
ACK
> > +static inline int
> > +mrvl_get_bpool_size(int	pp2_id, int pool_id)
>  No tab here please
Good catch, thanks.
>
> Why does this need to be inlined?  Is it in critical path?
>
>
Right, in rx handler precisely.
> > +{
> > +	int i;
> > +	int size = 0;
> > +
> > +	for (i = mrvl_lcore_first; i <= mrvl_lcore_last; i++)
> > +		size += mrvl_port_bpool_size[pp2_id][pool_id][i];
> > +
> > +	return size;
> > +}
> > +
>
> Also, I prefer that the following restrictions from the kernel be
> also applied to DPDK code.
>
> ### [dpdk-dev] [PATCH v2 2/4] net/mrvl: add mrvl net pmd driver
>
> CHECK:LINE_SPACING: Please don't use multiple blank lines
> #452: FILE: drivers/net/mrvl/mrvl_ethdev.c:180:
> +
> +
>
> WARNING:LINE_SPACING: Missing a blank line after declarations
> #457: FILE: drivers/net/mrvl/mrvl_ethdev.c:185:
> +	int n = sizeof(*bitmap) * 8 - __builtin_clz(*bitmap);
> +	if (n >= max)
These were not triggered by the DPDK checkpatch wrapper. On the other
hand using kernel checkpatch will show them. That makes we wonder which
tool should actually be used? Anyway, will fix that in v3.
>
> CHECK:LINE_SPACING: Please don't use multiple blank lines
> #562: FILE: drivers/net/mrvl/mrvl_ethdev.c:290:
> +
> +
>
> WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'priv->ppio_params.inqs_params.tcs_params[i].inqs_params'
> #880: FILE: drivers/net/mrvl/mrvl_ethdev.c:608:
> +			rte_free(priv->ppio_params.inqs_params.
> +				tcs_params[i].inqs_params);
>
> WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'priv->ppio_params.inqs_params.tcs_params[i].inqs_params'
> #882: FILE: drivers/net/mrvl/mrvl_ethdev.c:610:
> +			priv->ppio_params.inqs_params.
> +				tcs_params[i].inqs_params = NULL;
>
> WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'priv->ppio_params.inqs_params.tcs_params[tc].inqs_params[inq].size'
> #1330: FILE: drivers/net/mrvl/mrvl_ethdev.c:1058:
> +	qinfo->nb_desc = priv->ppio_params.inqs_params.
> +			 tcs_params[tc].inqs_params[inq].size;
>
> WARNING:SPLIT_STRING: quoted string split across lines
> #1476: FILE: drivers/net/mrvl/mrvl_ethdev.c:1204:
> +		RTE_LOG(ERR, PMD, "Mbuf size must be increased to %u bytes"
> +				  " to hold up to %u bytes of data.\n",
Personally I would go with kernel checkpatch, but DPDK checker complained
about overly long lines thus such comments were split across lines.
>
> WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'priv->ppio_params.inqs_params.tcs_params[priv->rxq_map[rxq->queue_id].tc'
> #1500: FILE: drivers/net/mrvl/mrvl_ethdev.c:1228:
> +	priv->ppio_params.inqs_params.
> +		tcs_params[priv->rxq_map[rxq->queue_id].tc].
>
> WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'q->priv->ppio_params.inqs_params.tcs_params[q->priv->rxq_map[q->queue_id].tc'
> #1532: FILE: drivers/net/mrvl/mrvl_ethdev.c:1260:
> +	num = q->priv->ppio_params.inqs_params.
> +			tcs_params[q->priv->rxq_map[q->queue_id].tc].
>
> WARNING:SPLIT_STRING: quoted string split across lines
> #1902: FILE: drivers/net/mrvl/mrvl_ethdev.c:1630:
> +			RTE_LOG(DEBUG, PMD, "\nport-%d:%d: bpool %d oversize -"
> +				" remove %d buffers (pool size: %d -> %d)\n",
>
> WARNING:SPLIT_STRING: quoted string split across lines
> #2094: FILE: drivers/net/mrvl/mrvl_ethdev.c:1822:
> +			"No room in shadow queue for %d packets!!!"
> +			"%d packets will be sent.\n",
>
> CHECK:LINE_SPACING: Please don't use multiple blank lines
> #2294: FILE: drivers/net/mrvl/mrvl_ethdev.c:2022:
> +
> +
>
> CHECK:LINE_SPACING: Please don't use multiple blank lines
> #2595: FILE: drivers/net/mrvl/mrvl_ethdev.h:40:
> +
> +
>
> WARNING:LINE_SPACING: Missing a blank line after declarations
> #3253: FILE: drivers/net/mrvl/mrvl_qos.c:577:
> +			uint8_t idx = port_cfg->tc[tc].inq[i];
> +			priv->rxq_map[idx].tc = tc;
>

--
- Tomasz Duszyński

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

* Re: [PATCH v2 2/4] net/mrvl: add mrvl net pmd driver
  2017-10-02 11:08       ` Bruce Richardson
@ 2017-10-03  6:33         ` Tomasz Duszynski
  0 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-03  6:33 UTC (permalink / raw)
  To: Bruce Richardson
  Cc: Stephen Hemminger, Tomasz Duszynski, dev, mw, dima, nsamsono,
	Jianbo.liu, Jacek Siuda

On Mon, Oct 02, 2017 at 12:08:39PM +0100, Bruce Richardson wrote:
> On Fri, Sep 29, 2017 at 08:38:00AM -0700, Stephen Hemminger wrote:
> > On Thu, 28 Sep 2017 12:22:36 +0200
> > Tomasz Duszynski <tdu@semihalf.com> wrote:
> >
> > > +
> > > +struct mrvl_rxq;
> > > +struct mrvl_txq;
> >
> > These forward decl should not be nececessary
> > > +static inline int
> > > +mrvl_get_bpool_size(int	pp2_id, int pool_id)
> >  No tab here please
> >
> > Why does this need to be inlined?  Is it in critical path?
> >
> >
> > > +{
> > > +	int i;
> > > +	int size = 0;
> > > +
> > > +	for (i = mrvl_lcore_first; i <= mrvl_lcore_last; i++)
> > > +		size += mrvl_port_bpool_size[pp2_id][pool_id][i];
> > > +
> > > +	return size;
> > > +}
> > > +
> >
> > Also, I prefer that the following restrictions from the kernel be
> > also applied to DPDK code.
> >
>
> +1 for LINE_SPACING (multiple blank lines), MULTILINE_DEREFERENCE and
> SPLIT_STRING. [Is split string not already enforced?]
ACK
>
> I'm a bit ambivilant about forcing a blank line after definitions, I
> think it's a good idea in most cases, but I'm not sure it needs to be
> enforced in all cases.
Agree. In this case however adding a few extra blank lines after
definitions will not hurt, plus it will improve coding style consistency
across driver sources.
>
> /Bruce
>
> > ### [dpdk-dev] [PATCH v2 2/4] net/mrvl: add mrvl net pmd driver
> >
> > CHECK:LINE_SPACING: Please don't use multiple blank lines
> > #452: FILE: drivers/net/mrvl/mrvl_ethdev.c:180:
> > +
> > +
> >
> > WARNING:LINE_SPACING: Missing a blank line after declarations
> > #457: FILE: drivers/net/mrvl/mrvl_ethdev.c:185:
> > +	int n = sizeof(*bitmap) * 8 - __builtin_clz(*bitmap);
> > +	if (n >= max)
> >
> > CHECK:LINE_SPACING: Please don't use multiple blank lines
> > #562: FILE: drivers/net/mrvl/mrvl_ethdev.c:290:
> > +
> > +
> >
> > WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'priv->ppio_params.inqs_params.tcs_params[i].inqs_params'
> > #880: FILE: drivers/net/mrvl/mrvl_ethdev.c:608:
> > +			rte_free(priv->ppio_params.inqs_params.
> > +				tcs_params[i].inqs_params);
> >
> > WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'priv->ppio_params.inqs_params.tcs_params[i].inqs_params'
> > #882: FILE: drivers/net/mrvl/mrvl_ethdev.c:610:
> > +			priv->ppio_params.inqs_params.
> > +				tcs_params[i].inqs_params = NULL;
> >
> > WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'priv->ppio_params.inqs_params.tcs_params[tc].inqs_params[inq].size'
> > #1330: FILE: drivers/net/mrvl/mrvl_ethdev.c:1058:
> > +	qinfo->nb_desc = priv->ppio_params.inqs_params.
> > +			 tcs_params[tc].inqs_params[inq].size;
> >
> > WARNING:SPLIT_STRING: quoted string split across lines
> > #1476: FILE: drivers/net/mrvl/mrvl_ethdev.c:1204:
> > +		RTE_LOG(ERR, PMD, "Mbuf size must be increased to %u bytes"
> > +				  " to hold up to %u bytes of data.\n",
> >
> > WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'priv->ppio_params.inqs_params.tcs_params[priv->rxq_map[rxq->queue_id].tc'
> > #1500: FILE: drivers/net/mrvl/mrvl_ethdev.c:1228:
> > +	priv->ppio_params.inqs_params.
> > +		tcs_params[priv->rxq_map[rxq->queue_id].tc].
> >
> > WARNING:MULTILINE_DEREFERENCE: Avoid multiple line dereference - prefer 'q->priv->ppio_params.inqs_params.tcs_params[q->priv->rxq_map[q->queue_id].tc'
> > #1532: FILE: drivers/net/mrvl/mrvl_ethdev.c:1260:
> > +	num = q->priv->ppio_params.inqs_params.
> > +			tcs_params[q->priv->rxq_map[q->queue_id].tc].
> >
> > WARNING:SPLIT_STRING: quoted string split across lines
> > #1902: FILE: drivers/net/mrvl/mrvl_ethdev.c:1630:
> > +			RTE_LOG(DEBUG, PMD, "\nport-%d:%d: bpool %d oversize -"
> > +				" remove %d buffers (pool size: %d -> %d)\n",
> >
> > WARNING:SPLIT_STRING: quoted string split across lines
> > #2094: FILE: drivers/net/mrvl/mrvl_ethdev.c:1822:
> > +			"No room in shadow queue for %d packets!!!"
> > +			"%d packets will be sent.\n",
> >
> > CHECK:LINE_SPACING: Please don't use multiple blank lines
> > #2294: FILE: drivers/net/mrvl/mrvl_ethdev.c:2022:
> > +
> > +
> >
> > CHECK:LINE_SPACING: Please don't use multiple blank lines
> > #2595: FILE: drivers/net/mrvl/mrvl_ethdev.h:40:
> > +
> > +
> >
> > WARNING:LINE_SPACING: Missing a blank line after declarations
> > #3253: FILE: drivers/net/mrvl/mrvl_qos.c:577:
> > +			uint8_t idx = port_cfg->tc[tc].inq[i];
> > +			priv->rxq_map[idx].tc = tc;
> >

--
- Tomasz Duszyński

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

* [PATCH v3 0/4] add net mrvl pmd driver
  2017-09-28 10:22   ` [PATCH v2 1/4] app: link the whole rte_cfgfile library Tomasz Duszynski
@ 2017-10-03 11:51     ` Tomasz Duszynski
  2017-10-03 11:51       ` [PATCH v3 1/4] app: link the whole rte_cfgfile library Tomasz Duszynski
                         ` (4 more replies)
  0 siblings, 5 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-03 11:51 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski

Hello,

This patch series introduces the net driver for Marvell Armada 7k/8k
SoCs along with documentation.

Below you can find the list of features which net pmd supports:
* Speed capabilities
* Link status
* Queue start/stop
* MTU update
* Jumbo frame
* Promiscuous mode
* Allmulticast mode
* Unicast MAC filter
* Multicast MAC filter
* RSS hash
* VLAN filter
* CRC offload
* L3 checksum offload
* L4 checksum offload
* Packet type parsing
* Basic stats
* Stats per queue

Changes since v2:
* Removed LINE_SPACING, MULTILINE_DEREFERENCE and SPLIT_STRING
  checkpatch warnings.
* Removed unnecessary forward declarations.
* Fixed whitespace warnings.

Changes since v1:
* Changed commit message to explain problem better.
* Removed bunch of checkpatch warnings about unnecessary parentheses.

Tomasz Duszynski (4):
  app: link the whole rte_cfgfile library
  net/mrvl: add mrvl net pmd driver
  doc: add mrvl net pmd documentation
  maintainers: add maintainers for the mrvl net pmd

 MAINTAINERS                               |   10 +
 config/common_base                        |    7 +
 doc/guides/nics/features/mrvl.ini         |   24 +
 doc/guides/nics/index.rst                 |    1 +
 doc/guides/nics/mrvl.rst                  |  151 ++
 drivers/net/Makefile                      |    2 +
 drivers/net/mrvl/Makefile                 |   69 +
 drivers/net/mrvl/mrvl_ethdev.c            | 2277 +++++++++++++++++++++++++++++
 drivers/net/mrvl/mrvl_ethdev.h            |  114 ++
 drivers/net/mrvl/mrvl_qos.c               |  628 ++++++++
 drivers/net/mrvl/mrvl_qos.h               |  112 ++
 drivers/net/mrvl/rte_pmd_mrvl_version.map |    3 +
 mk/rte.app.mk                             |    3 +-
 13 files changed, 3400 insertions(+), 1 deletion(-)
 create mode 100644 doc/guides/nics/features/mrvl.ini
 create mode 100644 doc/guides/nics/mrvl.rst
 create mode 100644 drivers/net/mrvl/Makefile
 create mode 100644 drivers/net/mrvl/mrvl_ethdev.c
 create mode 100644 drivers/net/mrvl/mrvl_ethdev.h
 create mode 100644 drivers/net/mrvl/mrvl_qos.c
 create mode 100644 drivers/net/mrvl/mrvl_qos.h
 create mode 100644 drivers/net/mrvl/rte_pmd_mrvl_version.map

--
2.7.4

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

* [PATCH v3 1/4] app: link the whole rte_cfgfile library
  2017-10-03 11:51     ` [PATCH v3 0/4] add net mrvl pmd driver Tomasz Duszynski
@ 2017-10-03 11:51       ` Tomasz Duszynski
  2017-10-03 11:51       ` [PATCH v3 2/4] net/mrvl: add mrvl net pmd driver Tomasz Duszynski
                         ` (3 subsequent siblings)
  4 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-03 11:51 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

MRVL net pmd needs rte_cfgfile to parse QoS configuration file thus
librte_pmd_mrvl.a contains undefined symbols from librte_cfgfile.a.

As a result linking applications under app/ directory will fail
because librte_cfgfile.a comes before librte_pmd_mrvl.a during
the linking stage.

Linking the whole librte_cfgfile.a solves the issue.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 v2:
 * Changed commit message to explain problem better.

 mk/rte.app.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index c25fdd9..94568a8 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -81,10 +81,10 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)          += -lrte_power

 _LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)            += -lrte_efd
-_LDLIBS-$(CONFIG_RTE_LIBRTE_CFGFILE)        += -lrte_cfgfile

 _LDLIBS-y += --whole-archive

+_LDLIBS-$(CONFIG_RTE_LIBRTE_CFGFILE)        += -lrte_cfgfile
 _LDLIBS-$(CONFIG_RTE_LIBRTE_HASH)           += -lrte_hash
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VHOST)          += -lrte_vhost
 _LDLIBS-$(CONFIG_RTE_LIBRTE_KVARGS)         += -lrte_kvargs
--
2.7.4

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

* [PATCH v3 2/4] net/mrvl: add mrvl net pmd driver
  2017-10-03 11:51     ` [PATCH v3 0/4] add net mrvl pmd driver Tomasz Duszynski
  2017-10-03 11:51       ` [PATCH v3 1/4] app: link the whole rte_cfgfile library Tomasz Duszynski
@ 2017-10-03 11:51       ` Tomasz Duszynski
  2017-10-04  0:24         ` Ferruh Yigit
  2017-10-04  0:28         ` Ferruh Yigit
  2017-10-03 11:51       ` [PATCH v3 3/4] doc: add mrvl net pmd documentation Tomasz Duszynski
                         ` (2 subsequent siblings)
  4 siblings, 2 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-03 11:51 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add support for the Marvell PPv2 (Packet Processor v2) 1/10 Gbps adapter.
Driver is based on external, publicly available, light-weight Marvell
MUSDK library that provides access to network packet processor.

Driver comes with support for the following features:

* Speed capabilities
* Link status
* Queue start/stop
* MTU update
* Jumbo frame
* Promiscuous mode
* Allmulticast mode
* Unicast MAC filter
* Multicast MAC filter
* RSS hash
* VLAN filter
* CRC offload
* L3 checksum offload
* L4 checksum offload
* Packet type parsing
* Basic stats
* Stats per queue

Driver was engineered cooperatively by Semihalf and Marvell teams.

Semihalf:
Jacek Siuda <jck@semihalf.com>
Tomasz Duszynski <tdu@semihalf.com>

Marvell:
Dmitri Epshtein <dima@marvell.com>
Natalie Samsonov <nsamsono@marvell.com>

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 v3:
 * Removed LINE_SPACING, MULTILINE_DEREFERENCE and SPLIT_STRING
   checkpatch warnings.
 * Removed unnecessary forward declarations.
 * Fixed whitespace warnings.

 v2:
 * Removed bunch of checkpatch warnings about unnecessary parentheses.

 config/common_base                        |    7 +
 drivers/net/Makefile                      |    2 +
 drivers/net/mrvl/Makefile                 |   69 +
 drivers/net/mrvl/mrvl_ethdev.c            | 2274 +++++++++++++++++++++++++++++
 drivers/net/mrvl/mrvl_ethdev.h            |  114 ++
 drivers/net/mrvl/mrvl_qos.c               |  628 ++++++++
 drivers/net/mrvl/mrvl_qos.h               |  112 ++
 drivers/net/mrvl/rte_pmd_mrvl_version.map |    3 +
 mk/rte.app.mk                             |    1 +
 9 files changed, 3210 insertions(+)
 create mode 100644 drivers/net/mrvl/Makefile
 create mode 100644 drivers/net/mrvl/mrvl_ethdev.c
 create mode 100644 drivers/net/mrvl/mrvl_ethdev.h
 create mode 100644 drivers/net/mrvl/mrvl_qos.c
 create mode 100644 drivers/net/mrvl/mrvl_qos.h
 create mode 100644 drivers/net/mrvl/rte_pmd_mrvl_version.map

diff --git a/config/common_base b/config/common_base
index 5e97a08..d05a60c 100644
--- a/config/common_base
+++ b/config/common_base
@@ -262,6 +262,13 @@ CONFIG_RTE_LIBRTE_NFP_PMD=n
 CONFIG_RTE_LIBRTE_NFP_DEBUG=n

 #
+# Compile Marvell PMD driver
+#
+CONFIG_RTE_LIBRTE_MRVL_PMD=n
+CONFIG_RTE_LIBRTE_MRVL_DEBUG=n
+CONFIG_RTE_MRVL_MUSDK_DMA_MEMSIZE=41943040
+
+#
 # Compile burst-oriented Broadcom BNXT PMD driver
 #
 CONFIG_RTE_LIBRTE_BNXT_PMD=y
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index d33c959..4a3a205 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -73,6 +73,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4
 DEPDIRS-mlx4 = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5
 DEPDIRS-mlx5 = $(core-libs)
+DIRS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl
+DEPDIRS-mrvl = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_NFP_PMD) += nfp
 DEPDIRS-nfp = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt
diff --git a/drivers/net/mrvl/Makefile b/drivers/net/mrvl/Makefile
new file mode 100644
index 0000000..ab53f49
--- /dev/null
+++ b/drivers/net/mrvl/Makefile
@@ -0,0 +1,69 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2017 Semihalf. 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 Semihalf 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
+
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),config)
+ifeq ($(LIBMUSDK_PATH),)
+$(error "Please define LIBMUSDK_PATH environment variable")
+endif
+ifeq ($(CONFIG_RTE_LIBRTE_CFGFILE),n)
+$(error "RTE_LIBRTE_CFGFILE must be enabled in configuration!")
+endif
+endif
+endif
+
+# library name
+LIB = librte_pmd_mrvl.a
+
+# library version
+LIBABIVER := 1
+
+# versioning export map
+EXPORT_MAP := rte_pmd_mrvl_version.map
+
+# external library dependencies
+CFLAGS += -I$(LIBMUSDK_PATH)/include
+CFLAGS += -DMVCONF_ARCH_DMA_ADDR_T_64BIT
+CFLAGS += -DCONF_PP2_BPOOL_COOKIE_SIZE=32
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -O3
+LDLIBS += -L$(LIBMUSDK_PATH)/lib
+LDLIBS += -lmusdk
+
+# library source files
+SRCS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl_qos.c
+
+# library dependencies
+DEPDIRS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += lib/librte_cfgfile
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/mrvl/mrvl_ethdev.c b/drivers/net/mrvl/mrvl_ethdev.c
new file mode 100644
index 0000000..a260de5
--- /dev/null
+++ b/drivers/net/mrvl/mrvl_ethdev.c
@@ -0,0 +1,2274 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Semihalf. 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 Semihalf 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_ethdev.h>
+#include <rte_kvargs.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_vdev.h>
+#include <rte_cycles.h>
+
+/* Unluckily, container_of is defined by both DPDK and MUSDK,
+ * we'll declare only one version.
+ *
+ * Note that it is not used in this PMD anyway.
+ */
+#ifdef container_of
+#undef container_of
+#endif
+
+#include <drivers/mv_pp2.h>
+#include <drivers/mv_pp2_bpool.h>
+#include <drivers/mv_pp2_hif.h>
+
+#include <assert.h>
+#include <fcntl.h>
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "mrvl_ethdev.h"
+#include "mrvl_qos.h"
+
+/* bitmask with reserved hifs */
+#define MRVL_MUSDK_HIFS_RESERVED 0x0F
+/* bitmask with reserved bpools */
+#define MRVL_MUSDK_BPOOLS_RESERVED 0x07
+/* bitmask with reserved kernel RSS tables */
+#define MRVL_MUSDK_RSS_RESERVED 0x01
+/* maximum number of available hifs */
+#define MRVL_MUSDK_HIFS_MAX 9
+
+/* prefetch shift */
+#define MRVL_MUSDK_PREFETCH_SHIFT 2
+
+/* TCAM has 25 entries reserved for uc/mc filter entries */
+#define MRVL_MAC_ADDRS_MAX 25
+#define MRVL_MATCH_LEN 16
+#define MRVL_PKT_EFFEC_OFFS (MRVL_PKT_OFFS + MV_MH_SIZE)
+/* Maximum allowable packet size */
+#define MRVL_PKT_SIZE_MAX (10240 - MV_MH_SIZE)
+
+#define MRVL_IFACE_NAME_ARG "iface"
+#define MRVL_CFG_ARG "cfg"
+
+#define MRVL_BURST_SIZE 64
+
+#define MRVL_ARP_LENGTH 28
+
+#define MRVL_COOKIE_ADDR_INVALID ~0ULL
+
+#define MRVL_COOKIE_HIGH_ADDR_SHIFT	(sizeof(pp2_cookie_t) * 8)
+#define MRVL_COOKIE_HIGH_ADDR_MASK	(~0ULL << MRVL_COOKIE_HIGH_ADDR_SHIFT)
+
+static const char * const valid_args[] = {
+	MRVL_IFACE_NAME_ARG,
+	MRVL_CFG_ARG,
+	NULL
+};
+
+static int used_hifs = MRVL_MUSDK_HIFS_RESERVED;
+static struct pp2_hif *hifs[RTE_MAX_LCORE];
+static int used_bpools[PP2_NUM_PKT_PROC] = {
+	MRVL_MUSDK_BPOOLS_RESERVED,
+	MRVL_MUSDK_BPOOLS_RESERVED
+};
+
+struct pp2_bpool *mrvl_port_to_bpool_lookup[RTE_MAX_ETHPORTS];
+int mrvl_port_bpool_size[PP2_NUM_PKT_PROC][PP2_BPOOL_NUM_POOLS][RTE_MAX_LCORE];
+uint64_t cookie_addr_high = MRVL_COOKIE_ADDR_INVALID;
+
+/*
+ * To use buffer harvesting based on loopback port shadow queue structure
+ * was introduced for buffers information bookkeeping.
+ *
+ * Before sending the packet, related buffer information (pp2_buff_inf) is
+ * stored in shadow queue. After packet is transmitted no longer used
+ * packet buffer is released back to it's original hardware pool,
+ * on condition it originated from interface.
+ * In case it  was generated by application itself i.e: mbuf->port field is
+ * 0xff then its released to software mempool.
+ */
+struct mrvl_shadow_txq {
+	int head;           /* write index - used when sending buffers */
+	int tail;           /* read index - used when releasing buffers */
+	u16 size;           /* queue occupied size */
+	u16 num_to_release; /* number of buffers sent, that can be released */
+	struct buff_release_entry ent[MRVL_PP2_TX_SHADOWQ_SIZE]; /* q entries */
+};
+
+struct mrvl_rxq {
+	struct mrvl_priv *priv;
+	struct rte_mempool *mp;
+	int queue_id;
+	int port_id;
+	int cksum_enabled;
+	uint64_t bytes_recv;
+	uint64_t drop_mac;
+};
+
+struct mrvl_txq {
+	struct mrvl_priv *priv;
+	int queue_id;
+	int port_id;
+	uint64_t bytes_sent;
+};
+
+/*
+ * Every tx queue should have dedicated shadow tx queue.
+ *
+ * Ports assigned by DPDK might not start at zero or be continuous so
+ * as a workaround define shadow queues for each possible port so that
+ * we eventually fit somewhere.
+ */
+struct mrvl_shadow_txq shadow_txqs[RTE_MAX_ETHPORTS][RTE_MAX_LCORE];
+
+/** Number of ports configured. */
+int mrvl_ports_nb;
+static int mrvl_lcore_first;
+static int mrvl_lcore_last;
+
+static inline int
+mrvl_get_bpool_size(int pp2_id, int pool_id)
+{
+	int i;
+	int size = 0;
+
+	for (i = mrvl_lcore_first; i <= mrvl_lcore_last; i++)
+		size += mrvl_port_bpool_size[pp2_id][pool_id][i];
+
+	return size;
+}
+
+static inline int
+mrvl_reserve_bit(int *bitmap, int max)
+{
+	int n = sizeof(*bitmap) * 8 - __builtin_clz(*bitmap);
+
+	if (n >= max)
+		return -1;
+
+	*bitmap |= 1 << n;
+
+	return n;
+}
+
+/**
+ * Configure rss based on dpdk rss configuration.
+ *
+ * @param priv
+ *   Pointer to private structure.
+ * @param rss_conf
+ *   Pointer to RSS configuration.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_configure_rss(struct mrvl_priv *priv, struct rte_eth_rss_conf *rss_conf)
+{
+	if (rss_conf->rss_key)
+		RTE_LOG(WARNING, PMD, "Changing hash key is not supported\n");
+
+	if (rss_conf->rss_hf == 0) {
+		priv->ppio_params.inqs_params.hash_type = PP2_PPIO_HASH_T_NONE;
+	} else if (rss_conf->rss_hf & ETH_RSS_IPV4) {
+		priv->ppio_params.inqs_params.hash_type =
+			PP2_PPIO_HASH_T_2_TUPLE;
+	} else if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV4_TCP) {
+		priv->ppio_params.inqs_params.hash_type =
+			PP2_PPIO_HASH_T_5_TUPLE;
+		priv->rss_hf_tcp = 1;
+	} else if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV4_UDP) {
+		priv->ppio_params.inqs_params.hash_type =
+			PP2_PPIO_HASH_T_5_TUPLE;
+		priv->rss_hf_tcp = 0;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * Ethernet device configuration.
+ *
+ * Prepare the driver for a given number of TX and RX queues and
+ * configure RSS.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_dev_configure(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	if (dev->data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_NONE &&
+	    dev->data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_RSS) {
+		RTE_LOG(INFO, PMD, "Unsupported rx multi queue mode %d\n",
+			dev->data->dev_conf.rxmode.mq_mode);
+		return -EINVAL;
+	}
+
+	if (!dev->data->dev_conf.rxmode.hw_strip_crc) {
+		RTE_LOG(INFO, PMD,
+			"L2 CRC stripping is always enabled in hw\n");
+		dev->data->dev_conf.rxmode.hw_strip_crc = 1;
+	}
+
+	if (dev->data->dev_conf.rxmode.hw_vlan_strip) {
+		RTE_LOG(INFO, PMD, "VLAN stripping not supported\n");
+		return -EINVAL;
+	}
+
+	if (dev->data->dev_conf.rxmode.split_hdr_size) {
+		RTE_LOG(INFO, PMD, "Split headers not supported\n");
+		return -EINVAL;
+	}
+
+	if (dev->data->dev_conf.rxmode.enable_scatter) {
+		RTE_LOG(INFO, PMD, "RX Scatter/Gather not supported\n");
+		return -EINVAL;
+	}
+
+	if (dev->data->dev_conf.rxmode.enable_lro) {
+		RTE_LOG(INFO, PMD, "LRO not supported\n");
+		return -EINVAL;
+	}
+
+	if (dev->data->dev_conf.rxmode.jumbo_frame)
+		dev->data->mtu = dev->data->dev_conf.rxmode.max_rx_pkt_len -
+				 ETHER_HDR_LEN - ETHER_CRC_LEN;
+
+	ret = mrvl_configure_rxqs(priv, dev->data->port_id,
+				  dev->data->nb_rx_queues);
+	if (ret < 0)
+		return ret;
+
+	priv->ppio_params.outqs_params.num_outqs = dev->data->nb_tx_queues;
+	priv->ppio_params.maintain_stats = 1;
+	priv->nb_rx_queues = dev->data->nb_rx_queues;
+
+	if (dev->data->nb_rx_queues == 1 &&
+	    dev->data->dev_conf.rxmode.mq_mode == ETH_MQ_RX_RSS) {
+		RTE_LOG(WARNING, PMD, "Disabling hash for 1 rx queue\n");
+		priv->ppio_params.inqs_params.hash_type = PP2_PPIO_HASH_T_NONE;
+
+		return 0;
+	}
+
+	return mrvl_configure_rss(priv,
+				  &dev->data->dev_conf.rx_adv_conf.rss_conf);
+}
+
+/**
+ * DPDK callback to change the MTU.
+ *
+ * Setting the MTU affects hardware MRU (packets larger than the MRU
+ * will be dropped).
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mtu
+ *   New MTU.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	/* extra MV_MH_SIZE bytes are required for Marvell tag */
+	uint16_t mru = mtu + MV_MH_SIZE + ETHER_HDR_LEN + ETHER_CRC_LEN;
+	int ret;
+
+	if (mtu < ETHER_MIN_MTU || mru > MRVL_PKT_SIZE_MAX)
+		return -EINVAL;
+
+	ret = pp2_ppio_set_mru(priv->ppio, mru);
+	if (ret)
+		return ret;
+
+	return pp2_ppio_set_mtu(priv->ppio, mtu);
+}
+
+/**
+ * DPDK callback to bring the link up.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_dev_set_link_up(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_enable(priv->ppio);
+	if (ret)
+		return ret;
+
+	/*
+	 * mtu/mru can be updated if pp2_ppio_enable() was called at least once
+	 * as pp2_ppio_enable() changes port->t_mode from default 0 to
+	 * PP2_TRAFFIC_INGRESS_EGRESS.
+	 *
+	 * Set mtu to default DPDK value here.
+	 */
+	ret = mrvl_mtu_set(dev, dev->data->mtu);
+	if (ret)
+		pp2_ppio_disable(priv->ppio);
+
+	dev->data->dev_link.link_status = ETH_LINK_UP;
+
+	return ret;
+}
+
+/**
+ * DPDK callback to bring the link down.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_dev_set_link_down(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_disable(priv->ppio);
+	if (ret)
+		return ret;
+
+	dev->data->dev_link.link_status = ETH_LINK_DOWN;
+
+	return ret;
+}
+
+/**
+ * DPDK callback to start the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, negative errno value on failure.
+ */
+static int
+mrvl_dev_start(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	char match[MRVL_MATCH_LEN];
+	int ret;
+
+	snprintf(match, sizeof(match), "ppio-%d:%d",
+		 priv->pp_id, priv->ppio_id);
+	priv->ppio_params.match = match;
+
+	/*
+	 * Calculate the maximum bpool size for refill feature to 1.5 of the
+	 * configured size. In case the bpool size will exceed this value,
+	 * superfluous buffers will be removed
+	 */
+	priv->bpool_max_size = priv->bpool_init_size +
+			      (priv->bpool_init_size >> 1);
+	/*
+	 * Calculate the minimum bpool size for refill feature as follows:
+	 * 2 default burst sizes multiply by number of rx queues.
+	 * If the bpool size will be below this value, new buffers will
+	 * be added to the pool.
+	 */
+	priv->bpool_min_size = priv->nb_rx_queues * MRVL_BURST_SIZE * 2;
+
+	ret = pp2_ppio_init(&priv->ppio_params, &priv->ppio);
+	if (ret)
+		return ret;
+
+	/*
+	 * In case there are some some stale uc/mc mac addresses flush them
+	 * here. It cannot be done during mrvl_dev_close() as port information
+	 * is already gone at that point (due to pp2_ppio_deinit() in
+	 * mrvl_dev_stop()).
+	 */
+	if (!priv->uc_mc_flushed) {
+		ret = pp2_ppio_flush_mac_addrs(priv->ppio, 1, 1);
+		if (ret) {
+			RTE_LOG(ERR, PMD,
+				"Failed to flush uc/mc filter list\n");
+			goto out;
+		}
+		priv->uc_mc_flushed = 1;
+	}
+
+	if (!priv->vlan_flushed) {
+		ret = pp2_ppio_flush_vlan(priv->ppio);
+		if (ret) {
+			RTE_LOG(ERR, PMD, "Failed to flush vlan list\n");
+			/*
+			 * TODO
+			 * once pp2_ppio_flush_vlan() is supported jump to out
+			 * goto out;
+			 */
+		}
+		priv->vlan_flushed = 1;
+	}
+
+	/* For default QoS config, don't start classifier. */
+	if (mrvl_qos_cfg) {
+		ret = mrvl_start_qos_mapping(priv);
+		if (ret) {
+			pp2_ppio_deinit(priv->ppio);
+			return ret;
+		}
+	}
+
+	ret = mrvl_dev_set_link_up(dev);
+	if (ret)
+		goto out;
+
+	return 0;
+out:
+	pp2_ppio_deinit(priv->ppio);
+	return ret;
+}
+
+/**
+ * Flush receive queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_flush_rx_queues(struct rte_eth_dev *dev)
+{
+	int i;
+
+	RTE_LOG(INFO, PMD, "Flushing rx queues\n");
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		int ret, num;
+
+		do {
+			struct mrvl_rxq *q = dev->data->rx_queues[i];
+			struct pp2_ppio_desc descs[MRVL_PP2_RXD_MAX];
+
+			num = MRVL_PP2_RXD_MAX;
+			ret = pp2_ppio_recv(q->priv->ppio,
+					    q->priv->rxq_map[q->queue_id].tc,
+					    q->priv->rxq_map[q->queue_id].inq,
+					    descs, (uint16_t *)&num);
+		} while (ret == 0 && num);
+	}
+}
+
+/**
+ * Flush transmit shadow queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_flush_tx_shadow_queues(struct rte_eth_dev *dev)
+{
+	int i;
+
+	RTE_LOG(INFO, PMD, "Flushing tx shadow queues\n");
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		struct mrvl_shadow_txq *sq =
+			&shadow_txqs[dev->data->port_id][i];
+
+		while (sq->tail != sq->head) {
+			uint64_t addr = cookie_addr_high |
+					sq->ent[sq->tail].buff.cookie;
+			rte_pktmbuf_free((struct rte_mbuf *)addr);
+			sq->tail = (sq->tail + 1) & MRVL_PP2_TX_SHADOWQ_MASK;
+		}
+
+		memset(sq, 0, sizeof(*sq));
+	}
+}
+
+/**
+ * Flush hardware bpool (buffer-pool).
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_flush_bpool(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	uint32_t num;
+	int ret;
+
+	ret = pp2_bpool_get_num_buffs(priv->bpool, &num);
+	if (ret) {
+		RTE_LOG(ERR, PMD, "Failed to get bpool buffers number\n");
+		return;
+	}
+
+	while (num--) {
+		struct pp2_buff_inf inf;
+		uint64_t addr;
+
+		ret = pp2_bpool_get_buff(hifs[rte_lcore_id()], priv->bpool,
+					 &inf);
+		if (ret)
+			break;
+
+		addr = cookie_addr_high | inf.cookie;
+		rte_pktmbuf_free((struct rte_mbuf *)addr);
+	}
+}
+
+/**
+ * DPDK callback to stop the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_dev_stop(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	mrvl_dev_set_link_down(dev);
+	mrvl_flush_rx_queues(dev);
+	mrvl_flush_tx_shadow_queues(dev);
+	if (priv->qos_tbl)
+		pp2_cls_qos_tbl_deinit(priv->qos_tbl);
+	pp2_ppio_deinit(priv->ppio);
+	priv->ppio = NULL;
+}
+
+/**
+ * DPDK callback to close the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_dev_close(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	size_t i;
+
+	for (i = 0; i < priv->ppio_params.inqs_params.num_tcs; ++i) {
+		struct pp2_ppio_tc_params *tc_params =
+			&priv->ppio_params.inqs_params.tcs_params[i];
+
+		if (tc_params->inqs_params) {
+			rte_free(tc_params->inqs_params);
+			tc_params->inqs_params = NULL;
+		}
+	}
+
+	mrvl_flush_bpool(dev);
+}
+
+/**
+ * DPDK callback to retrieve physical link information.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param wait_to_complete
+ *   Wait for request completion (ignored).
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_link_update(struct rte_eth_dev *dev, int wait_to_complete __rte_unused)
+{
+	/*
+	 * TODO
+	 * once MUSDK provides necessary API use it here
+	 */
+	struct ethtool_cmd edata;
+	struct ifreq req;
+	int ret, fd;
+
+	edata.cmd = ETHTOOL_GSET;
+
+	strcpy(req.ifr_name, dev->data->name);
+	req.ifr_data = (void *)&edata;
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd == -1)
+		return -EFAULT;
+
+	ret = ioctl(fd, SIOCETHTOOL, &req);
+	if (ret == -1) {
+		close(fd);
+		return -EFAULT;
+	}
+
+	close(fd);
+
+	switch (ethtool_cmd_speed(&edata)) {
+	case SPEED_10:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_10M;
+		break;
+	case SPEED_100:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_100M;
+		break;
+	case SPEED_1000:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_1G;
+		break;
+	case SPEED_10000:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_10G;
+		break;
+	default:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_NONE;
+	}
+
+	dev->data->dev_link.link_duplex = edata.duplex ? ETH_LINK_FULL_DUPLEX :
+							 ETH_LINK_HALF_DUPLEX;
+	dev->data->dev_link.link_autoneg = edata.autoneg ? ETH_LINK_AUTONEG :
+							   ETH_LINK_FIXED;
+
+	return 0;
+}
+
+/**
+ * DPDK callback to enable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_promiscuous_enable(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_set_uc_promisc(priv->ppio, 1);
+	if (ret)
+		RTE_LOG(ERR, PMD, "Failed to enable promiscuous mode\n");
+}
+
+/**
+ * DPDK callback to enable allmulti mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_allmulticast_enable(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_set_mc_promisc(priv->ppio, 1);
+	if (ret)
+		RTE_LOG(ERR, PMD, "Failed enable all-multicast mode\n");
+}
+
+/**
+ * DPDK callback to disable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_set_uc_promisc(priv->ppio, 0);
+	if (ret)
+		RTE_LOG(ERR, PMD, "Failed to disable promiscuous mode\n");
+}
+
+/**
+ * DPDK callback to disable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_allmulticast_disable(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_set_mc_promisc(priv->ppio, 0);
+	if (ret)
+		RTE_LOG(ERR, PMD, "Failed to disable all-multicast mode\n");
+}
+
+/**
+ * DPDK callback to remove a MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param index
+ *   MAC address index.
+ */
+static void
+mrvl_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	char buf[ETHER_ADDR_FMT_SIZE];
+	int ret;
+
+	ret = pp2_ppio_remove_mac_addr(priv->ppio,
+				       dev->data->mac_addrs[index].addr_bytes);
+	if (ret) {
+		ether_format_addr(buf, sizeof(buf),
+				  &dev->data->mac_addrs[index]);
+		RTE_LOG(ERR, PMD, "Failed to remove mac %s\n", buf);
+	}
+}
+
+/**
+ * DPDK callback to add a MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ * @param index
+ *   MAC address index.
+ * @param vmdq
+ *   VMDq pool index to associate address with (unused).
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
+		  uint32_t index, uint32_t vmdq __rte_unused)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	char buf[ETHER_ADDR_FMT_SIZE];
+	int ret;
+
+	if (index == 0)
+		/* For setting index 0, mrvl_mac_addr_set() should be used.*/
+		return -1;
+
+	/*
+	 * Maximum number of uc addresses can be tuned via kernel module mvpp2x
+	 * parameter uc_filter_max. Maximum number of mc addresses is then
+	 * MRVL_MAC_ADDRS_MAX - uc_filter_max. Currently it defaults to 4 and
+	 * 21 respectively.
+	 *
+	 * If more than uc_filter_max uc addresses were added to filter list
+	 * then NIC will switch to promiscuous mode automatically.
+	 *
+	 * If more than MRVL_MAC_ADDRS_MAX - uc_filter_max number mc addresses
+	 * were added to filter list then NIC will switch to all-multicast mode
+	 * automatically.
+	 */
+	ret = pp2_ppio_add_mac_addr(priv->ppio, mac_addr->addr_bytes);
+	if (ret) {
+		ether_format_addr(buf, sizeof(buf), mac_addr);
+		RTE_LOG(ERR, PMD, "Failed to add mac %s\n", buf);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * DPDK callback to set the primary MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ */
+static void
+mrvl_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	pp2_ppio_set_mac_addr(priv->ppio, mac_addr->addr_bytes);
+	/*
+	 * TODO
+	 * Port stops sending packets if pp2_ppio_set_mac_addr()
+	 * was called after pp2_ppio_enable(). As a quick fix issue
+	 * enable port once again.
+	 */
+	pp2_ppio_enable(priv->ppio);
+}
+
+/**
+ * DPDK callback to get device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param stats
+ *   Stats structure output buffer.
+ */
+static void
+mrvl_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct pp2_ppio_statistics ppio_stats;
+	uint64_t drop_mac = 0;
+	unsigned int i, idx, ret;
+
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		struct mrvl_rxq *rxq = dev->data->rx_queues[i];
+		struct pp2_ppio_inq_statistics rx_stats;
+
+		if (!rxq)
+			continue;
+
+		idx = rxq->queue_id;
+		if (unlikely(idx >= RTE_ETHDEV_QUEUE_STAT_CNTRS)) {
+			RTE_LOG(ERR, PMD,
+				"rx queue %d stats out of range (0 - %d)\n",
+				idx, RTE_ETHDEV_QUEUE_STAT_CNTRS - 1);
+			continue;
+		}
+
+		ret = pp2_ppio_inq_get_statistics(priv->ppio,
+						  priv->rxq_map[idx].tc,
+						  priv->rxq_map[idx].inq,
+						  &rx_stats, 0);
+		if (unlikely(ret)) {
+			RTE_LOG(ERR, PMD,
+				"Failed to update rx queue %d stats\n", idx);
+			break;
+		}
+
+		stats->q_ibytes[idx] = rxq->bytes_recv;
+		stats->q_ipackets[idx] = rx_stats.enq_desc - rxq->drop_mac;
+		stats->q_errors[idx] = rx_stats.drop_early +
+				       rx_stats.drop_fullq +
+				       rx_stats.drop_bm +
+				       rxq->drop_mac;
+		stats->ibytes += rxq->bytes_recv;
+		drop_mac += rxq->drop_mac;
+	}
+
+	for (i = 0; i < dev->data->nb_tx_queues; i++) {
+		struct mrvl_txq *txq = dev->data->tx_queues[i];
+		struct pp2_ppio_outq_statistics tx_stats;
+
+		if (!txq)
+			continue;
+
+		idx = txq->queue_id;
+		if (unlikely(idx >= RTE_ETHDEV_QUEUE_STAT_CNTRS)) {
+			RTE_LOG(ERR, PMD,
+				"tx queue %d stats out of range (0 - %d)\n",
+				idx, RTE_ETHDEV_QUEUE_STAT_CNTRS - 1);
+		}
+
+		ret = pp2_ppio_outq_get_statistics(priv->ppio, idx,
+						   &tx_stats, 0);
+		if (unlikely(ret)) {
+			RTE_LOG(ERR, PMD,
+				"Failed to update tx queue %d stats\n", idx);
+			break;
+		}
+
+		stats->q_opackets[idx] = tx_stats.deq_desc;
+		stats->q_obytes[idx] = txq->bytes_sent;
+		stats->obytes += txq->bytes_sent;
+	}
+
+	ret = pp2_ppio_get_statistics(priv->ppio, &ppio_stats, 0);
+	if (unlikely(ret)) {
+		RTE_LOG(ERR, PMD, "Failed to update port statistics\n");
+		return;
+	}
+
+	stats->ipackets += ppio_stats.rx_packets - drop_mac;
+	stats->opackets += ppio_stats.tx_packets;
+	stats->imissed += ppio_stats.rx_fullq_dropped +
+			  ppio_stats.rx_bm_dropped +
+			  ppio_stats.rx_early_dropped +
+			  ppio_stats.rx_fifo_dropped +
+			  ppio_stats.rx_cls_dropped;
+	stats->ierrors = drop_mac;
+}
+
+/**
+ * DPDK callback to clear device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_stats_reset(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int i;
+
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		struct mrvl_rxq *rxq = dev->data->rx_queues[i];
+
+		pp2_ppio_inq_get_statistics(priv->ppio, priv->rxq_map[i].tc,
+					    priv->rxq_map[i].inq, NULL, 1);
+		rxq->bytes_recv = 0;
+		rxq->drop_mac = 0;
+	}
+
+	for (i = 0; i < dev->data->nb_tx_queues; i++) {
+		struct mrvl_txq *txq = dev->data->tx_queues[i];
+
+		pp2_ppio_outq_get_statistics(priv->ppio, i, NULL, 1);
+		txq->bytes_sent = 0;
+	}
+
+	pp2_ppio_get_statistics(priv->ppio, NULL, 1);
+}
+
+/**
+ * DPDK callback to get information about the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure (unused).
+ * @param info
+ *   Info structure output buffer.
+ */
+static void
+mrvl_dev_infos_get(struct rte_eth_dev *dev __rte_unused,
+		   struct rte_eth_dev_info *info)
+{
+	info->max_rx_queues = MRVL_PP2_RXQ_MAX;
+	info->max_tx_queues = MRVL_PP2_TXQ_MAX;
+	info->max_mac_addrs = MRVL_MAC_ADDRS_MAX;
+
+	info->rx_desc_lim.nb_max = MRVL_PP2_RXD_MAX;
+	info->rx_desc_lim.nb_min = MRVL_PP2_RXD_MIN;
+	info->rx_desc_lim.nb_align = MRVL_PP2_RXD_ALIGN;
+
+	info->tx_desc_lim.nb_max = MRVL_PP2_TXD_MAX;
+	info->tx_desc_lim.nb_min = MRVL_PP2_TXD_MIN;
+	info->tx_desc_lim.nb_align = MRVL_PP2_TXD_ALIGN;
+
+	info->rx_offload_capa = DEV_RX_OFFLOAD_IPV4_CKSUM |
+				DEV_RX_OFFLOAD_UDP_CKSUM |
+				DEV_RX_OFFLOAD_TCP_CKSUM;
+
+	info->tx_offload_capa = DEV_TX_OFFLOAD_IPV4_CKSUM |
+				DEV_TX_OFFLOAD_UDP_CKSUM |
+				DEV_TX_OFFLOAD_TCP_CKSUM;
+
+	info->flow_type_rss_offloads = ETH_RSS_IPV4 |
+				       ETH_RSS_NONFRAG_IPV4_TCP |
+				       ETH_RSS_NONFRAG_IPV4_UDP;
+
+	/* By default packets are dropped if no descriptors are available */
+	info->default_rxconf.rx_drop_en = 1;
+
+	info->max_rx_pktlen = MRVL_PKT_SIZE_MAX;
+}
+
+/**
+ * Return supported packet types.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure (unused).
+ *
+ * @return
+ *   Const pointer to the table with supported packet types.
+ */
+static const uint32_t *
+mrvl_dev_supported_ptypes_get(struct rte_eth_dev *dev __rte_unused)
+{
+	static const uint32_t ptypes[] = {
+		RTE_PTYPE_L2_ETHER,
+		RTE_PTYPE_L3_IPV4,
+		RTE_PTYPE_L3_IPV4_EXT,
+		RTE_PTYPE_L3_IPV4_EXT_UNKNOWN,
+		RTE_PTYPE_L3_IPV6,
+		RTE_PTYPE_L3_IPV6_EXT,
+		RTE_PTYPE_L2_ETHER_ARP,
+		RTE_PTYPE_L4_TCP,
+		RTE_PTYPE_L4_UDP
+	};
+
+	return ptypes;
+}
+
+/**
+ * DPDK callback to get information about specific receive queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param rx_queue_id
+ *   Receive queue index.
+ * @param qinfo
+ *   Receive queue information structure.
+ */
+static void mrvl_rxq_info_get(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+			      struct rte_eth_rxq_info *qinfo)
+{
+	struct mrvl_rxq *q = dev->data->rx_queues[rx_queue_id];
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int inq = priv->rxq_map[rx_queue_id].inq;
+	int tc = priv->rxq_map[rx_queue_id].tc;
+	struct pp2_ppio_tc_params *tc_params =
+		&priv->ppio_params.inqs_params.tcs_params[tc];
+
+	qinfo->mp = q->mp;
+	qinfo->nb_desc = tc_params->inqs_params[inq].size;
+}
+
+/**
+ * DPDK callback to get information about specific transmit queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param tx_queue_id
+ *   Transmit queue index.
+ * @param qinfo
+ *   Transmit queue information structure.
+ */
+static void mrvl_txq_info_get(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+			      struct rte_eth_txq_info *qinfo)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	qinfo->nb_desc =
+		priv->ppio_params.outqs_params.outqs_params[tx_queue_id].size;
+}
+
+/**
+ * DPDK callback to Configure a VLAN filter.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param vlan_id
+ *   VLAN ID to filter.
+ * @param on
+ *   Toggle filter.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	return on ? pp2_ppio_add_vlan(priv->ppio, vlan_id) :
+		    pp2_ppio_remove_vlan(priv->ppio, vlan_id);
+}
+
+/**
+ * Release buffers to hardware bpool (buffer-pool)
+ *
+ * @param rxq
+ *   Receive queue pointer.
+ * @param num
+ *   Number of buffers to release to bpool.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_fill_bpool(struct mrvl_rxq *rxq, int num)
+{
+	struct buff_release_entry entries[MRVL_PP2_TXD_MAX];
+	struct rte_mbuf *mbufs[MRVL_PP2_TXD_MAX];
+	int i, ret;
+	unsigned int core_id = rte_lcore_id();
+	struct pp2_hif *hif = hifs[core_id];
+	struct pp2_bpool *bpool = rxq->priv->bpool;
+
+	ret = rte_pktmbuf_alloc_bulk(rxq->mp, mbufs, num);
+	if (ret)
+		return ret;
+
+	if (cookie_addr_high == MRVL_COOKIE_ADDR_INVALID)
+		cookie_addr_high =
+			(uint64_t)mbufs[0] & MRVL_COOKIE_HIGH_ADDR_MASK;
+
+	for (i = 0; i < num; i++) {
+		if (((uint64_t)mbufs[i] & MRVL_COOKIE_HIGH_ADDR_MASK)
+			!= cookie_addr_high) {
+			RTE_LOG(ERR, PMD,
+				"mbuf virtual addr high 0x%lx out of range\n",
+				(uint64_t)mbufs[i] >> 32);
+			goto out;
+		}
+
+		entries[i].buff.addr =
+			rte_mbuf_data_dma_addr_default(mbufs[i]);
+		entries[i].buff.cookie = (pp2_cookie_t)(uint64_t)mbufs[i];
+		entries[i].bpool = bpool;
+	}
+
+	pp2_bpool_put_buffs(hif, entries, (uint16_t *)&i);
+	mrvl_port_bpool_size[bpool->pp2_id][bpool->id][core_id] += i;
+
+	if (i != num)
+		goto out;
+
+	return 0;
+out:
+	for (; i < num; i++)
+		rte_pktmbuf_free(mbufs[i]);
+
+	return -1;
+}
+
+/**
+ * DPDK callback to configure the receive queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param conf
+ *   Thresholds parameters (unused_).
+ * @param mp
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
+		    unsigned int socket,
+		    const struct rte_eth_rxconf *conf __rte_unused,
+		    struct rte_mempool *mp)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_rxq *rxq;
+	uint32_t min_size,
+		 max_rx_pkt_len = dev->data->dev_conf.rxmode.max_rx_pkt_len;
+	int ret, tc, inq;
+
+	if (priv->rxq_map[idx].tc == MRVL_UNKNOWN_TC) {
+		/*
+		 * Unknown TC mapping, mapping will not have a correct queue.
+		 */
+		RTE_LOG(ERR, PMD, "Unknown TC mapping for queue %hu eth%hhu\n",
+			idx, priv->ppio_id);
+		return -EFAULT;
+	}
+
+	min_size = rte_pktmbuf_data_room_size(mp) - RTE_PKTMBUF_HEADROOM -
+		   MRVL_PKT_EFFEC_OFFS;
+	if (min_size < max_rx_pkt_len) {
+		RTE_LOG(ERR, PMD,
+			"Mbuf size must be increased to %u bytes to hold up to %u bytes of data.\n",
+			max_rx_pkt_len + RTE_PKTMBUF_HEADROOM +
+			MRVL_PKT_EFFEC_OFFS,
+			max_rx_pkt_len);
+		return -EINVAL;
+	}
+
+	if (dev->data->rx_queues[idx]) {
+		rte_free(dev->data->rx_queues[idx]);
+		dev->data->rx_queues[idx] = NULL;
+	}
+
+	rxq = rte_zmalloc_socket("rxq", sizeof(*rxq), 0, socket);
+	if (!rxq)
+		return -ENOMEM;
+
+	rxq->priv = priv;
+	rxq->mp = mp;
+	rxq->cksum_enabled = dev->data->dev_conf.rxmode.hw_ip_checksum;
+	rxq->queue_id = idx;
+	rxq->port_id = dev->data->port_id;
+	mrvl_port_to_bpool_lookup[rxq->port_id] = priv->bpool;
+
+	tc = priv->rxq_map[rxq->queue_id].tc,
+	inq = priv->rxq_map[rxq->queue_id].inq;
+	priv->ppio_params.inqs_params.tcs_params[tc].inqs_params[inq].size =
+		desc;
+
+	ret = mrvl_fill_bpool(rxq, desc);
+	if (ret) {
+		rte_free(rxq);
+		return ret;
+	}
+
+	priv->bpool_init_size += desc;
+
+	dev->data->rx_queues[idx] = rxq;
+
+	return 0;
+}
+
+/**
+ * DPDK callback to release the receive queue.
+ *
+ * @param rxq
+ *   Generic receive queue pointer.
+ */
+static void
+mrvl_rx_queue_release(void *rxq)
+{
+	struct mrvl_rxq *q = rxq;
+	struct pp2_ppio_tc_params *tc_params;
+	int i, num, tc, inq;
+
+	if (!q)
+		return;
+
+	tc = q->priv->rxq_map[q->queue_id].tc;
+	inq = q->priv->rxq_map[q->queue_id].inq;
+	tc_params = &q->priv->ppio_params.inqs_params.tcs_params[tc];
+	num = tc_params->inqs_params[inq].size;
+	for (i = 0; i < num; i++) {
+		struct pp2_buff_inf inf;
+		uint64_t addr;
+
+		pp2_bpool_get_buff(hifs[rte_lcore_id()], q->priv->bpool, &inf);
+		addr = cookie_addr_high | inf.cookie;
+		rte_pktmbuf_free((struct rte_mbuf *)addr);
+	}
+
+	rte_free(q);
+}
+
+/**
+ * DPDK callback to configure the transmit queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   Transmit queue index.
+ * @param desc
+ *   Number of descriptors to configure in the queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param conf
+ *   Thresholds parameters (unused).
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
+		    unsigned int socket,
+		    const struct rte_eth_txconf *conf __rte_unused)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_txq *txq;
+
+	if (dev->data->tx_queues[idx]) {
+		rte_free(dev->data->tx_queues[idx]);
+		dev->data->tx_queues[idx] = NULL;
+	}
+
+	txq = rte_zmalloc_socket("txq", sizeof(*txq), 0, socket);
+	if (!txq)
+		return -ENOMEM;
+
+	txq->priv = priv;
+	txq->queue_id = idx;
+	txq->port_id = dev->data->port_id;
+	dev->data->tx_queues[idx] = txq;
+
+	priv->ppio_params.outqs_params.outqs_params[idx].size = desc;
+	priv->ppio_params.outqs_params.outqs_params[idx].weight = 1;
+
+	return 0;
+}
+
+/**
+ * DPDK callback to release the transmit queue.
+ *
+ * @param txq
+ *   Generic transmit queue pointer.
+ */
+static void
+mrvl_tx_queue_release(void *txq)
+{
+	struct mrvl_txq *q = txq;
+
+	if (!q)
+		return;
+
+	rte_free(q);
+}
+
+/**
+ * Update RSS hash configuration
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param rss_conf
+ *   Pointer to RSS configuration.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_rss_hash_update(struct rte_eth_dev *dev,
+		     struct rte_eth_rss_conf *rss_conf)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	return mrvl_configure_rss(priv, rss_conf);
+}
+
+/**
+ * DPDK callback to get RSS hash configuration.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @rss_conf
+ *   Pointer to RSS configuration.
+ *
+ * @return
+ *   Always 0.
+ */
+static int
+mrvl_rss_hash_conf_get(struct rte_eth_dev *dev,
+		       struct rte_eth_rss_conf *rss_conf)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	enum pp2_ppio_hash_type hash_type =
+		priv->ppio_params.inqs_params.hash_type;
+
+	rss_conf->rss_key = NULL;
+
+	if (hash_type == PP2_PPIO_HASH_T_NONE)
+		rss_conf->rss_hf = 0;
+	else if (hash_type == PP2_PPIO_HASH_T_2_TUPLE)
+		rss_conf->rss_hf = ETH_RSS_IPV4;
+	else if (hash_type == PP2_PPIO_HASH_T_5_TUPLE && priv->rss_hf_tcp)
+		rss_conf->rss_hf = ETH_RSS_NONFRAG_IPV4_TCP;
+	else if (hash_type == PP2_PPIO_HASH_T_5_TUPLE && !priv->rss_hf_tcp)
+		rss_conf->rss_hf = ETH_RSS_NONFRAG_IPV4_UDP;
+
+	return 0;
+}
+
+static const struct eth_dev_ops mrvl_ops = {
+	.dev_configure = mrvl_dev_configure,
+	.dev_start = mrvl_dev_start,
+	.dev_stop = mrvl_dev_stop,
+	.dev_set_link_up = mrvl_dev_set_link_up,
+	.dev_set_link_down = mrvl_dev_set_link_down,
+	.dev_close = mrvl_dev_close,
+	.link_update = mrvl_link_update,
+	.promiscuous_enable = mrvl_promiscuous_enable,
+	.allmulticast_enable = mrvl_allmulticast_enable,
+	.promiscuous_disable = mrvl_promiscuous_disable,
+	.allmulticast_disable = mrvl_allmulticast_disable,
+	.mac_addr_remove = mrvl_mac_addr_remove,
+	.mac_addr_add = mrvl_mac_addr_add,
+	.mac_addr_set = mrvl_mac_addr_set,
+	.mtu_set = mrvl_mtu_set,
+	.stats_get = mrvl_stats_get,
+	.stats_reset = mrvl_stats_reset,
+	.dev_infos_get = mrvl_dev_infos_get,
+	.dev_supported_ptypes_get = mrvl_dev_supported_ptypes_get,
+	.rxq_info_get = mrvl_rxq_info_get,
+	.txq_info_get = mrvl_txq_info_get,
+	.vlan_filter_set = mrvl_vlan_filter_set,
+	.rx_queue_setup = mrvl_rx_queue_setup,
+	.rx_queue_release = mrvl_rx_queue_release,
+	.tx_queue_setup = mrvl_tx_queue_setup,
+	.tx_queue_release = mrvl_tx_queue_release,
+	.rss_hash_update = mrvl_rss_hash_update,
+	.rss_hash_conf_get = mrvl_rss_hash_conf_get,
+};
+
+/**
+ * Return packet type information and l3/l4 offsets.
+ *
+ * @param desc
+ *   Pointer to the received packet descriptor.
+ * @param l3_offset
+ *   l3 packet offset.
+ * @param l4_offset
+ *   l4 packet offset.
+ *
+ * @return
+ *   Packet type information.
+ */
+static inline uint32_t
+mrvl_desc_to_packet_type_and_offset(struct pp2_ppio_desc *desc,
+				    uint8_t *l3_offset, uint8_t *l4_offset)
+{
+	enum pp2_inq_l3_type l3_type;
+	enum pp2_inq_l4_type l4_type;
+	uint64_t packet_type;
+
+	pp2_ppio_inq_desc_get_l3_info(desc, &l3_type, l3_offset);
+	pp2_ppio_inq_desc_get_l4_info(desc, &l4_type, l4_offset);
+
+	packet_type = RTE_PTYPE_L2_ETHER;
+
+	switch (l3_type) {
+	case PP2_INQ_L3_TYPE_IPV4_NO_OPTS:
+		packet_type |= RTE_PTYPE_L3_IPV4;
+		break;
+	case PP2_INQ_L3_TYPE_IPV4_OK:
+		packet_type |= RTE_PTYPE_L3_IPV4_EXT;
+		break;
+	case PP2_INQ_L3_TYPE_IPV4_TTL_ZERO:
+		packet_type |= RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
+		break;
+	case PP2_INQ_L3_TYPE_IPV6_NO_EXT:
+		packet_type |= RTE_PTYPE_L3_IPV6;
+		break;
+	case PP2_INQ_L3_TYPE_IPV6_EXT:
+		packet_type |= RTE_PTYPE_L3_IPV6_EXT;
+		break;
+	case PP2_INQ_L3_TYPE_ARP:
+		packet_type |= RTE_PTYPE_L2_ETHER_ARP;
+		/*
+		 * In case of ARP l4_offset is set to wrong value.
+		 * Set it to proper one so that later on mbuf->l3_len can be
+		 * calculated subtracting l4_offset and l3_offset.
+		 */
+		*l4_offset = *l3_offset + MRVL_ARP_LENGTH;
+		break;
+	default:
+		RTE_LOG(DEBUG, PMD, "Failed to recognise l3 packet type\n");
+		break;
+	}
+
+	switch (l4_type) {
+	case PP2_INQ_L4_TYPE_TCP:
+		packet_type |= RTE_PTYPE_L4_TCP;
+		break;
+	case PP2_INQ_L4_TYPE_UDP:
+		packet_type |= RTE_PTYPE_L4_UDP;
+		break;
+	default:
+		RTE_LOG(DEBUG, PMD, "Failed to recognise l4 packet type\n");
+		break;
+	}
+
+	return packet_type;
+}
+
+/**
+ * Get offload information from the received packet descriptor.
+ *
+ * @param desc
+ *   Pointer to the received packet descriptor.
+ *
+ * @return
+ *   Mbuf offload flags.
+ */
+static inline uint64_t
+mrvl_desc_to_ol_flags(struct pp2_ppio_desc *desc)
+{
+	uint64_t flags;
+	enum pp2_inq_desc_status status;
+
+	status = pp2_ppio_inq_desc_get_l3_pkt_error(desc);
+	if (unlikely(status != PP2_DESC_ERR_OK))
+		flags = PKT_RX_IP_CKSUM_BAD;
+	else
+		flags = PKT_RX_IP_CKSUM_GOOD;
+
+	status = pp2_ppio_inq_desc_get_l4_pkt_error(desc);
+	if (unlikely(status != PP2_DESC_ERR_OK))
+		flags |= PKT_RX_L4_CKSUM_BAD;
+	else
+		flags |= PKT_RX_L4_CKSUM_GOOD;
+
+	return flags;
+}
+
+/**
+ * DPDK callback for receive.
+ *
+ * @param rxq
+ *   Generic pointer to the receive queue.
+ * @param rx_pkts
+ *   Array to store received packets.
+ * @param nb_pkts
+ *   Maximum number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully received.
+ */
+static uint16_t
+mrvl_rx_pkt_burst(void *rxq, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
+{
+	struct mrvl_rxq *q = rxq;
+	struct pp2_ppio_desc descs[nb_pkts];
+	struct pp2_bpool *bpool;
+	int i, ret, rx_done = 0;
+	int num;
+	unsigned int core_id = rte_lcore_id();
+
+	if (unlikely(!q->priv->ppio))
+		return 0;
+
+	bpool = q->priv->bpool;
+
+	ret = pp2_ppio_recv(q->priv->ppio, q->priv->rxq_map[q->queue_id].tc,
+			    q->priv->rxq_map[q->queue_id].inq, descs, &nb_pkts);
+	if (unlikely(ret < 0)) {
+		RTE_LOG(ERR, PMD, "Failed to receive packets\n");
+		return 0;
+	}
+	mrvl_port_bpool_size[bpool->pp2_id][bpool->id][core_id] -= nb_pkts;
+
+	for (i = 0; i < nb_pkts; i++) {
+		struct rte_mbuf *mbuf;
+		uint8_t l3_offset, l4_offset;
+		enum pp2_inq_desc_status status;
+		uint64_t addr;
+
+		if (likely(nb_pkts - i > MRVL_MUSDK_PREFETCH_SHIFT)) {
+			struct pp2_ppio_desc *pref_desc;
+			u64 pref_addr;
+
+			pref_desc = &descs[i + MRVL_MUSDK_PREFETCH_SHIFT];
+			pref_addr = cookie_addr_high |
+				    pp2_ppio_inq_desc_get_cookie(pref_desc);
+			rte_mbuf_prefetch_part1((struct rte_mbuf *)(pref_addr));
+			rte_mbuf_prefetch_part2((struct rte_mbuf *)(pref_addr));
+		}
+
+		addr = cookie_addr_high |
+		       pp2_ppio_inq_desc_get_cookie(&descs[i]);
+		mbuf = (struct rte_mbuf *)addr;
+		rte_pktmbuf_reset(mbuf);
+
+		/* drop packet in case of mac, overrun or resource error */
+		status = pp2_ppio_inq_desc_get_l2_pkt_error(&descs[i]);
+		if (unlikely(status != PP2_DESC_ERR_OK)) {
+			struct pp2_buff_inf binf = {
+				.addr = rte_mbuf_data_dma_addr_default(mbuf),
+				.cookie = (pp2_cookie_t)(uint64_t)mbuf,
+			};
+
+			pp2_bpool_put_buff(hifs[core_id], bpool, &binf);
+			mrvl_port_bpool_size
+				[bpool->pp2_id][bpool->id][core_id]++;
+			q->drop_mac++;
+			continue;
+		}
+
+		mbuf->data_off += MRVL_PKT_EFFEC_OFFS;
+		mbuf->pkt_len = pp2_ppio_inq_desc_get_pkt_len(&descs[i]);
+		mbuf->data_len = mbuf->pkt_len;
+		mbuf->port = q->port_id;
+		mbuf->packet_type =
+			mrvl_desc_to_packet_type_and_offset(&descs[i],
+							    &l3_offset,
+							    &l4_offset);
+		mbuf->l2_len = l3_offset;
+		mbuf->l3_len = l4_offset - l3_offset;
+
+		if (likely(q->cksum_enabled))
+			mbuf->ol_flags = mrvl_desc_to_ol_flags(&descs[i]);
+
+		rx_pkts[rx_done++] = mbuf;
+		q->bytes_recv += mbuf->pkt_len;
+	}
+
+	if (rte_spinlock_trylock(&q->priv->lock) == 1) {
+		num = mrvl_get_bpool_size(bpool->pp2_id, bpool->id);
+
+		if (unlikely(num <= q->priv->bpool_min_size ||
+			     (!rx_done && num < q->priv->bpool_init_size))) {
+			ret = mrvl_fill_bpool(q, MRVL_BURST_SIZE);
+			if (ret)
+				RTE_LOG(ERR, PMD, "Failed to fill bpool\n");
+		} else if (unlikely(num > q->priv->bpool_max_size)) {
+			int i;
+			int pkt_to_remove = num - q->priv->bpool_init_size;
+			struct rte_mbuf *mbuf;
+			struct pp2_buff_inf buff;
+
+			RTE_LOG(DEBUG, PMD,
+				"\nport-%d:%d: bpool %d oversize - remove %d buffers (pool size: %d -> %d)\n",
+				bpool->pp2_id, q->priv->ppio->port_id,
+				bpool->id, pkt_to_remove, num,
+				q->priv->bpool_init_size);
+
+			for (i = 0; i < pkt_to_remove; i++) {
+				pp2_bpool_get_buff(hifs[core_id], bpool, &buff);
+				mbuf = (struct rte_mbuf *)
+					(cookie_addr_high | buff.cookie);
+				rte_pktmbuf_free(mbuf);
+			}
+			mrvl_port_bpool_size
+				[bpool->pp2_id][bpool->id][core_id] -=
+								pkt_to_remove;
+		}
+		rte_spinlock_unlock(&q->priv->lock);
+	}
+
+	return rx_done;
+}
+
+/**
+ * Prepare offload information.
+ *
+ * @param ol_flags
+ *   Offload flags.
+ * @param packet_type
+ *   Packet type bitfield.
+ * @param l3_type
+ *   Pointer to the pp2_ouq_l3_type structure.
+ * @param l4_type
+ *   Pointer to the pp2_outq_l4_type structure.
+ * @param gen_l3_cksum
+ *   Will be set to 1 in case l3 checksum is computed.
+ * @param l4_cksum
+ *   Will be set to 1 in case l4 checksum is computed.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static inline int
+mrvl_prepare_proto_info(uint64_t ol_flags, uint32_t packet_type,
+			enum pp2_outq_l3_type *l3_type,
+			enum pp2_outq_l4_type *l4_type,
+			int *gen_l3_cksum,
+			int *gen_l4_cksum)
+{
+	/*
+	 * Based on ol_flags prepare information
+	 * for pp2_ppio_outq_desc_set_proto_info() which setups descriptor
+	 * for offloading.
+	 */
+	if (ol_flags & PKT_TX_IPV4) {
+		*l3_type = PP2_OUTQ_L3_TYPE_IPV4;
+		*gen_l3_cksum = ol_flags & PKT_TX_IP_CKSUM ? 1 : 0;
+	} else if (ol_flags & PKT_TX_IPV6) {
+		*l3_type = PP2_OUTQ_L3_TYPE_IPV6;
+		/* no checksum for ipv6 header */
+		*gen_l3_cksum = 0;
+	} else {
+		/* if something different then stop processing */
+		return -1;
+	}
+
+	ol_flags &= PKT_TX_L4_MASK;
+	if ((packet_type & RTE_PTYPE_L4_TCP) &&
+	    ol_flags == PKT_TX_TCP_CKSUM) {
+		*l4_type = PP2_OUTQ_L4_TYPE_TCP;
+		*gen_l4_cksum = 1;
+	} else if ((packet_type & RTE_PTYPE_L4_UDP) &&
+		   ol_flags == PKT_TX_UDP_CKSUM) {
+		*l4_type = PP2_OUTQ_L4_TYPE_UDP;
+		*gen_l4_cksum = 1;
+	} else {
+		*l4_type = PP2_OUTQ_L4_TYPE_OTHER;
+		/* no checksum for other type */
+		*gen_l4_cksum = 0;
+	}
+
+	return 0;
+}
+
+/**
+ * Release already sent buffers to bpool (buffer-pool).
+ *
+ * @param ppio
+ *   Pointer to the port structure.
+ * @param hif
+ *   Pointer to the MUSDK hardware interface.
+ * @param sq
+ *   Pointer to the shadow queue.
+ * @param qid
+ *   Queue id number.
+ * @param force
+ *   Force releasing packets.
+ */
+static inline void
+mrvl_free_sent_buffers(struct pp2_ppio *ppio, struct pp2_hif *hif,
+		       struct mrvl_shadow_txq *sq, int qid, int force)
+{
+	struct buff_release_entry *entry;
+	uint16_t nb_done = 0, num = 0, skip_bufs = 0;
+	int i, core_id = rte_lcore_id();
+
+	pp2_ppio_get_num_outq_done(ppio, hif, qid, &nb_done);
+
+	sq->num_to_release += nb_done;
+
+	if (likely(!force &&
+		   sq->num_to_release < MRVL_PP2_BUF_RELEASE_BURST_SIZE))
+		return;
+
+	nb_done = sq->num_to_release;
+	sq->num_to_release = 0;
+
+	for (i = 0; i < nb_done; i++) {
+		entry = &sq->ent[sq->tail + num];
+		if (unlikely(!entry->buff.addr)) {
+			RTE_LOG(ERR, PMD,
+				"Shadow memory @%d: cookie(%lx), pa(%lx)!\n",
+				sq->tail, (u64)entry->buff.cookie,
+				(u64)entry->buff.addr);
+			skip_bufs = 1;
+			goto skip;
+		}
+
+		if (unlikely(!entry->bpool)) {
+			struct rte_mbuf *mbuf;
+
+			mbuf = (struct rte_mbuf *)
+			       (cookie_addr_high | entry->buff.cookie);
+			rte_pktmbuf_free(mbuf);
+			skip_bufs = 1;
+			goto skip;
+		}
+
+		mrvl_port_bpool_size
+			[entry->bpool->pp2_id][entry->bpool->id][core_id]++;
+		num++;
+		if (unlikely(sq->tail + num == MRVL_PP2_TX_SHADOWQ_SIZE))
+			goto skip;
+		continue;
+skip:
+		if (likely(num))
+			pp2_bpool_put_buffs(hif, &sq->ent[sq->tail], &num);
+		num += skip_bufs;
+		sq->tail = (sq->tail + num) & MRVL_PP2_TX_SHADOWQ_MASK;
+		sq->size -= num;
+		num = 0;
+	}
+
+	if (likely(num)) {
+		pp2_bpool_put_buffs(hif, &sq->ent[sq->tail], &num);
+		sq->tail = (sq->tail + num) & MRVL_PP2_TX_SHADOWQ_MASK;
+		sq->size -= num;
+	}
+}
+
+/**
+ * DPDK callback for transmit.
+ *
+ * @param txq
+ *   Generic pointer transmit queue.
+ * @param tx_pkts
+ *   Packets to transmit.
+ * @param nb_pkts
+ *   Number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully transmitted.
+ */
+static uint16_t
+mrvl_tx_pkt_burst(void *txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+	struct mrvl_txq *q = txq;
+	struct mrvl_shadow_txq *sq = &shadow_txqs[q->port_id][rte_lcore_id()];
+	struct pp2_hif *hif = hifs[rte_lcore_id()];
+	struct pp2_ppio_desc descs[nb_pkts];
+	int i, ret, bytes_sent = 0;
+	uint16_t num, sq_free_size;
+	uint64_t addr;
+
+	if (unlikely(!q->priv->ppio))
+		return 0;
+
+	if (sq->size)
+		mrvl_free_sent_buffers(q->priv->ppio, hif, sq, q->queue_id, 0);
+
+	sq_free_size = MRVL_PP2_TX_SHADOWQ_SIZE - sq->size - 1;
+	if (unlikely(nb_pkts > sq_free_size)) {
+		RTE_LOG(DEBUG, PMD,
+			"No room in shadow queue for %d packets! %d packets will be sent.\n",
+			nb_pkts, sq_free_size);
+		nb_pkts = sq_free_size;
+	}
+
+	for (i = 0; i < nb_pkts; i++) {
+		struct rte_mbuf *mbuf = tx_pkts[i];
+		int gen_l3_cksum, gen_l4_cksum;
+		enum pp2_outq_l3_type l3_type;
+		enum pp2_outq_l4_type l4_type;
+
+		if (likely(nb_pkts - i > MRVL_MUSDK_PREFETCH_SHIFT)) {
+			struct rte_mbuf *pref_pkt_hdr;
+
+			pref_pkt_hdr = tx_pkts[i + MRVL_MUSDK_PREFETCH_SHIFT];
+			rte_mbuf_prefetch_part1(pref_pkt_hdr);
+			rte_mbuf_prefetch_part2(pref_pkt_hdr);
+		}
+
+		sq->ent[sq->head].buff.cookie = (pp2_cookie_t)(uint64_t)mbuf;
+		sq->ent[sq->head].buff.addr =
+			rte_mbuf_data_dma_addr_default(mbuf);
+		sq->ent[sq->head].bpool =
+			(unlikely(mbuf->port == 0xff || mbuf->refcnt > 1)) ?
+			 NULL : mrvl_port_to_bpool_lookup[mbuf->port];
+		sq->head = (sq->head + 1) & MRVL_PP2_TX_SHADOWQ_MASK;
+		sq->size++;
+
+		pp2_ppio_outq_desc_reset(&descs[i]);
+		pp2_ppio_outq_desc_set_phys_addr(&descs[i],
+						 rte_pktmbuf_mtophys(mbuf));
+		pp2_ppio_outq_desc_set_pkt_offset(&descs[i], 0);
+		pp2_ppio_outq_desc_set_pkt_len(&descs[i],
+					       rte_pktmbuf_pkt_len(mbuf));
+
+		bytes_sent += rte_pktmbuf_pkt_len(mbuf);
+		/*
+		 * in case unsupported ol_flags were passed
+		 * do not update descriptor offload information
+		 */
+		ret = mrvl_prepare_proto_info(mbuf->ol_flags, mbuf->packet_type,
+					      &l3_type, &l4_type, &gen_l3_cksum,
+					      &gen_l4_cksum);
+		if (unlikely(ret))
+			continue;
+
+		pp2_ppio_outq_desc_set_proto_info(&descs[i], l3_type, l4_type,
+						  mbuf->l2_len,
+						  mbuf->l2_len + mbuf->l3_len,
+						  gen_l3_cksum, gen_l4_cksum);
+	}
+
+	num = nb_pkts;
+	pp2_ppio_send(q->priv->ppio, hif, q->queue_id, descs, &nb_pkts);
+	/* number of packets that were not sent */
+	if (unlikely(num > nb_pkts)) {
+		for (i = nb_pkts; i < num; i++) {
+			sq->head = (MRVL_PP2_TX_SHADOWQ_SIZE + sq->head - 1) &
+				MRVL_PP2_TX_SHADOWQ_MASK;
+			addr = cookie_addr_high | sq->ent[sq->head].buff.cookie;
+			bytes_sent -=
+				rte_pktmbuf_pkt_len((struct rte_mbuf *)addr);
+		}
+		sq->size -= num - nb_pkts;
+	}
+
+	q->bytes_sent += bytes_sent;
+
+	return nb_pkts;
+}
+
+/**
+ * Initialize packet processor.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_init_pp2(void)
+{
+	struct pp2_init_params init_params;
+
+	memset(&init_params, 0, sizeof(init_params));
+	init_params.hif_reserved_map = MRVL_MUSDK_HIFS_RESERVED;
+	init_params.bm_pool_reserved_map = MRVL_MUSDK_BPOOLS_RESERVED;
+	init_params.rss_tbl_reserved_map = MRVL_MUSDK_RSS_RESERVED;
+
+	return pp2_init(&init_params);
+}
+
+/**
+ * Deinitialize packet processor.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static void
+mrvl_deinit_pp2(void)
+{
+	pp2_deinit();
+}
+
+/**
+ * Create private device structure.
+ *
+ * @param dev_name
+ *   Pointer to the port name passed in the initialization parameters.
+ *
+ * @return
+ *   Pointer to the newly allocated private device structure.
+ */
+static struct mrvl_priv *
+mrvl_priv_create(const char *dev_name)
+{
+	struct pp2_bpool_params bpool_params;
+	char match[MRVL_MATCH_LEN];
+	struct mrvl_priv *priv;
+	int ret, bpool_bit;
+
+	priv = rte_zmalloc_socket(dev_name, sizeof(*priv), 0, rte_socket_id());
+	if (!priv)
+		return NULL;
+
+	ret = pp2_netdev_get_ppio_info((char *)(uintptr_t)dev_name,
+				       &priv->pp_id, &priv->ppio_id);
+	if (ret)
+		goto out_free_priv;
+
+	bpool_bit = mrvl_reserve_bit(&used_bpools[priv->pp_id],
+				     PP2_BPOOL_NUM_POOLS);
+	if (bpool_bit < 0)
+		goto out_free_priv;
+	priv->bpool_bit = bpool_bit;
+
+	snprintf(match, sizeof(match), "pool-%d:%d", priv->pp_id,
+		 priv->bpool_bit);
+	memset(&bpool_params, 0, sizeof(bpool_params));
+	bpool_params.match = match;
+	bpool_params.buff_len = MRVL_PKT_SIZE_MAX + MRVL_PKT_EFFEC_OFFS;
+	ret = pp2_bpool_init(&bpool_params, &priv->bpool);
+	if (ret)
+		goto out_clear_bpool_bit;
+
+	priv->ppio_params.type = PP2_PPIO_T_NIC;
+	rte_spinlock_init(&priv->lock);
+
+	return priv;
+out_clear_bpool_bit:
+	used_bpools[priv->pp_id] &= ~(1 << priv->bpool_bit);
+out_free_priv:
+	rte_free(priv);
+	return NULL;
+}
+
+/**
+ * Create device representing Ethernet port.
+ *
+ * @param name
+ *   Pointer to the port's name.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_eth_dev_create(struct rte_vdev_device *vdev, const char *name)
+{
+	int ret, fd = socket(AF_INET, SOCK_DGRAM, 0);
+	struct rte_eth_dev *eth_dev;
+	struct mrvl_priv *priv;
+	struct ifreq req;
+
+	eth_dev = rte_eth_dev_allocate(name);
+	if (!eth_dev)
+		return -ENOMEM;
+
+	priv = mrvl_priv_create(name);
+	if (!priv) {
+		ret = -ENOMEM;
+		goto out_free_dev;
+	}
+
+	eth_dev->data->mac_addrs =
+		rte_zmalloc("mac_addrs",
+			    ETHER_ADDR_LEN * MRVL_MAC_ADDRS_MAX, 0);
+	if (!eth_dev->data->mac_addrs) {
+		RTE_LOG(ERR, PMD, "Failed to allocate space for eth addrs\n");
+		ret = -ENOMEM;
+		goto out_free_priv;
+	}
+
+	memset(&req, 0, sizeof(req));
+	strcpy(req.ifr_name, name);
+	ret = ioctl(fd, SIOCGIFHWADDR, &req);
+	if (ret)
+		goto out_free_mac;
+
+	memcpy(eth_dev->data->mac_addrs[0].addr_bytes,
+	       req.ifr_addr.sa_data, ETHER_ADDR_LEN);
+
+	eth_dev->rx_pkt_burst = mrvl_rx_pkt_burst;
+	eth_dev->tx_pkt_burst = mrvl_tx_pkt_burst;
+	eth_dev->data->dev_private = priv;
+	eth_dev->device = &vdev->device;
+	eth_dev->dev_ops = &mrvl_ops;
+
+	return 0;
+out_free_mac:
+	rte_free(eth_dev->data->mac_addrs);
+out_free_dev:
+	rte_eth_dev_release_port(eth_dev);
+out_free_priv:
+	rte_free(priv);
+
+	return ret;
+}
+
+/**
+ * Cleanup previously created device representing Ethernet port.
+ *
+ * @param name
+ *   Pointer to the port name.
+ */
+static void
+mrvl_eth_dev_destroy(const char *name)
+{
+	struct rte_eth_dev *eth_dev;
+	struct mrvl_priv *priv;
+
+	eth_dev = rte_eth_dev_allocated(name);
+	if (!eth_dev)
+		return;
+
+	priv = eth_dev->data->dev_private;
+	pp2_bpool_deinit(priv->bpool);
+	rte_free(priv);
+	rte_free(eth_dev->data->mac_addrs);
+	rte_eth_dev_release_port(eth_dev);
+}
+
+/**
+ * Callback used by rte_kvargs_process() during argument parsing.
+ *
+ * @param key
+ *   Pointer to the parsed key (unused).
+ * @param value
+ *   Pointer to the parsed value.
+ * @param extra_args
+ *   Pointer to the extra arguments which contains address of the
+ *   table of pointers to parsed interface names.
+ *
+ * @return
+ *   Always 0.
+ */
+static int
+mrvl_get_ifnames(const char *key __rte_unused, const char *value,
+		 void *extra_args)
+{
+	const char **ifnames = extra_args;
+
+	ifnames[mrvl_ports_nb++] = value;
+
+	return 0;
+}
+
+/**
+ * Initialize per-lcore MUSDK hardware interfaces (hifs).
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_init_hifs(void)
+{
+	struct pp2_hif_params params;
+	char match[MRVL_MATCH_LEN];
+	int i, ret;
+
+	RTE_LCORE_FOREACH(i) {
+		ret = mrvl_reserve_bit(&used_hifs, MRVL_MUSDK_HIFS_MAX);
+		if (ret < 0)
+			return ret;
+
+		snprintf(match, sizeof(match), "hif-%d", ret);
+		memset(&params, 0, sizeof(params));
+		params.match = match;
+		params.out_size = MRVL_PP2_AGGR_TXQD_MAX;
+		ret = pp2_hif_init(&params, &hifs[i]);
+		if (ret) {
+			RTE_LOG(ERR, PMD, "Failed to initialize hif %d\n", i);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Deinitialize per-lcore MUSDK hardware interfaces (hifs).
+ */
+static void
+mrvl_deinit_hifs(void)
+{
+	int i;
+
+	RTE_LCORE_FOREACH(i) {
+		if (hifs[i])
+			pp2_hif_deinit(hifs[i]);
+	}
+}
+
+static void mrvl_set_first_last_cores(int core_id)
+{
+	if (core_id < mrvl_lcore_first)
+		mrvl_lcore_first = core_id;
+
+	if (core_id > mrvl_lcore_last)
+		mrvl_lcore_last = core_id;
+}
+
+/**
+ * DPDK callback to register the virtual device.
+ *
+ * @param vdev
+ *   Pointer to the virtual device.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+rte_pmd_mrvl_probe(struct rte_vdev_device *vdev)
+{
+	struct rte_kvargs *kvlist;
+	const char *ifnames[PP2_NUM_ETH_PPIO * PP2_NUM_PKT_PROC];
+	int ret = -EINVAL;
+	uint32_t i, ifnum, cfgnum, core_id;
+	const char *params;
+
+	params = rte_vdev_device_args(vdev);
+	if (!params)
+		return -EINVAL;
+
+	kvlist = rte_kvargs_parse(params, valid_args);
+	if (!kvlist)
+		return -EINVAL;
+
+	ifnum = rte_kvargs_count(kvlist, MRVL_IFACE_NAME_ARG);
+	if (ifnum > RTE_DIM(ifnames))
+		goto out_free_kvlist;
+
+	rte_kvargs_process(kvlist, MRVL_IFACE_NAME_ARG,
+			   mrvl_get_ifnames, &ifnames);
+
+	cfgnum = rte_kvargs_count(kvlist, MRVL_CFG_ARG);
+	if (cfgnum > 1) {
+		RTE_LOG(ERR, PMD, "Cannot handle more than one config file!\n");
+		goto out_free_kvlist;
+	} else if (cfgnum == 1) {
+		rte_kvargs_process(kvlist, MRVL_CFG_ARG,
+				   mrvl_get_qoscfg, &mrvl_qos_cfg);
+	}
+
+	/*
+	 * ret == -EEXIST is correct, it means DMA
+	 * has been already initialized (by another PMD).
+	 */
+	ret = mv_sys_dma_mem_init(RTE_MRVL_MUSDK_DMA_MEMSIZE);
+	if (ret < 0 && ret != -EEXIST)
+		goto out_free_kvlist;
+
+	ret = mrvl_init_pp2();
+	if (ret) {
+		RTE_LOG(ERR, PMD, "Failed to init PP!\n");
+		goto out_deinit_dma;
+	}
+
+	ret = mrvl_init_hifs();
+	if (ret)
+		goto out_deinit_hifs;
+
+	for (i = 0; i < ifnum; i++) {
+		RTE_LOG(INFO, PMD, "Creating %s\n", ifnames[i]);
+		ret = mrvl_eth_dev_create(vdev, ifnames[i]);
+		if (ret)
+			goto out_cleanup;
+	}
+
+	rte_kvargs_free(kvlist);
+
+	memset(mrvl_port_bpool_size, 0, sizeof(mrvl_port_bpool_size));
+
+	mrvl_lcore_first = RTE_MAX_LCORE;
+	mrvl_lcore_last = 0;
+
+	RTE_LCORE_FOREACH(core_id) {
+		mrvl_set_first_last_cores(core_id);
+	}
+
+	return 0;
+out_cleanup:
+	for (; i > 0; i--)
+		mrvl_eth_dev_destroy(ifnames[i]);
+out_deinit_hifs:
+	mrvl_deinit_hifs();
+	mrvl_deinit_pp2();
+out_deinit_dma:
+	mv_sys_dma_mem_destroy();
+out_free_kvlist:
+	rte_kvargs_free(kvlist);
+
+	return ret;
+}
+
+/**
+ * DPDK callback to remove virtual device.
+ *
+ * @param vdev
+ *   Pointer to the removed virtual device.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+rte_pmd_mrvl_remove(struct rte_vdev_device *vdev)
+{
+	int i;
+	const char *name;
+
+	name = rte_vdev_device_name(vdev);
+	if (!name)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Removing %s\n", name);
+
+	for (i = 0; i < rte_eth_dev_count(); i++) {
+		char ifname[RTE_ETH_NAME_MAX_LEN];
+
+		rte_eth_dev_get_name_by_port(i, ifname);
+		mrvl_eth_dev_destroy(ifname);
+	}
+
+	mrvl_deinit_hifs();
+	mrvl_deinit_pp2();
+	mv_sys_dma_mem_destroy();
+
+	return 0;
+}
+
+static struct rte_vdev_driver pmd_mrvl_drv = {
+	.probe = rte_pmd_mrvl_probe,
+	.remove = rte_pmd_mrvl_remove,
+};
+
+RTE_PMD_REGISTER_VDEV(net_mrvl, pmd_mrvl_drv);
+RTE_PMD_REGISTER_ALIAS(net_mrvl, eth_mrvl);
diff --git a/drivers/net/mrvl/mrvl_ethdev.h b/drivers/net/mrvl/mrvl_ethdev.h
new file mode 100644
index 0000000..72af4c7
--- /dev/null
+++ b/drivers/net/mrvl/mrvl_ethdev.h
@@ -0,0 +1,114 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Semihalf. 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 Semihalf 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 _MRVL_ETHDEV_H_
+#define _MRVL_ETHDEV_H_
+
+#include <rte_spinlock.h>
+#include <drivers/mv_pp2_cls.h>
+#include <drivers/mv_pp2_ppio.h>
+
+/** Maximum number of rx queues per port */
+#define MRVL_PP2_RXQ_MAX 32
+
+/** Maximum number of tx queues per port */
+#define MRVL_PP2_TXQ_MAX 8
+
+/** Minimum number of descriptors in tx queue */
+#define MRVL_PP2_TXD_MIN 16
+
+/** Maximum number of descriptors in tx queue */
+#define MRVL_PP2_TXD_MAX 2048
+
+/** Tx queue descriptors alignment */
+#define MRVL_PP2_TXD_ALIGN 16
+
+/** Minimum number of descriptors in rx queue */
+#define MRVL_PP2_RXD_MIN 16
+
+/** Maximum number of descriptors in rx queue */
+#define MRVL_PP2_RXD_MAX 2048
+
+/** Rx queue descriptors alignment */
+#define MRVL_PP2_RXD_ALIGN 16
+
+/** Maximum number of descriptors in tx aggregated queue */
+#define MRVL_PP2_AGGR_TXQD_MAX 2048
+
+/** Maximum number of Traffic Classes. */
+#define MRVL_PP2_TC_MAX 8
+
+/** Packet offset inside RX buffer. */
+#define MRVL_PKT_OFFS 64
+
+/** Maximum number of descriptors in shadow queue. Must be power of 2 */
+#define MRVL_PP2_TX_SHADOWQ_SIZE MRVL_PP2_TXD_MAX
+
+/** Shadow queue size mask (since shadow queue size is power of 2) */
+#define MRVL_PP2_TX_SHADOWQ_MASK (MRVL_PP2_TX_SHADOWQ_SIZE - 1)
+
+/** Minimum number of sent buffers to release from shadow queue to BM */
+#define MRVL_PP2_BUF_RELEASE_BURST_SIZE	64
+
+struct mrvl_priv {
+	/* Hot fields, used in fast path. */
+	struct pp2_bpool *bpool;  /**< BPool pointer */
+	struct pp2_ppio	*ppio;    /**< Port handler pointer */
+	rte_spinlock_t lock;	  /**< Spinlock for checking bpool status */
+	uint16_t bpool_max_size;  /**< BPool maximum size */
+	uint16_t bpool_min_size;  /**< BPool minimum size  */
+	uint16_t bpool_init_size; /**< Configured BPool size  */
+
+	/** Mapping for DPDK rx queue->(TC, MRVL relative inq) */
+	struct {
+		uint8_t tc;  /**< Traffic Class */
+		uint8_t inq; /**< Relative in-queue number */
+	} rxq_map[MRVL_PP2_RXQ_MAX] __rte_cache_aligned;
+
+	/* Configuration data, used sporadically. */
+	uint8_t pp_id;
+	uint8_t ppio_id;
+	uint8_t bpool_bit;
+	uint8_t rss_hf_tcp;
+	uint8_t uc_mc_flushed;
+	uint8_t vlan_flushed;
+
+	struct pp2_ppio_params ppio_params;
+	struct pp2_cls_qos_tbl_params qos_tbl_params;
+	struct pp2_cls_tbl *qos_tbl;
+	uint16_t nb_rx_queues;
+};
+
+/** Number of ports configured. */
+extern int mrvl_ports_nb;
+
+#endif /* _MRVL_ETHDEV_H_ */
diff --git a/drivers/net/mrvl/mrvl_qos.c b/drivers/net/mrvl/mrvl_qos.c
new file mode 100644
index 0000000..925f881
--- /dev/null
+++ b/drivers/net/mrvl/mrvl_qos.c
@@ -0,0 +1,628 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Semihalf. 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 Semihalf 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 <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_cfgfile.h>
+#include <rte_log.h>
+#include <rte_lcore.h>
+#include <rte_malloc.h>
+#include <rte_string_fns.h>
+
+/* Unluckily, container_of is defined by both DPDK and MUSDK,
+ * we'll declare only one version.
+ *
+ * Note that it is not used in this PMD anyway.
+ */
+#ifdef container_of
+#undef container_of
+#endif
+
+#include "mrvl_qos.h"
+
+/* Parsing tokens. Defined conveniently, so that any correction is easy. */
+#define MRVL_TOK_DEFAULT "default"
+#define MRVL_TOK_DEFAULT_TC "default_tc"
+#define MRVL_TOK_DSCP "dscp"
+#define MRVL_TOK_MAPPING_PRIORITY "mapping_priority"
+#define MRVL_TOK_IP "ip"
+#define MRVL_TOK_IP_VLAN "ip/vlan"
+#define MRVL_TOK_PCP "pcp"
+#define MRVL_TOK_PORT "port"
+#define MRVL_TOK_RXQ "rxq"
+#define MRVL_TOK_SP "SP"
+#define MRVL_TOK_TC "tc"
+#define MRVL_TOK_TXQ "txq"
+#define MRVL_TOK_VLAN "vlan"
+#define MRVL_TOK_VLAN_IP "vlan/ip"
+#define MRVL_TOK_WEIGHT "weight"
+
+/** Number of tokens in range a-b = 2. */
+#define MAX_RNG_TOKENS 2
+
+/** Maximum possible value of PCP. */
+#define MAX_PCP 7
+
+/** Maximum possible value of DSCP. */
+#define MAX_DSCP 63
+
+/** Global QoS configuration. */
+struct mrvl_qos_cfg *mrvl_qos_cfg;
+
+/**
+ * Convert string to uint32_t with extra checks for result correctness.
+ *
+ * @param string String to convert.
+ * @param val Conversion result.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+get_val_securely(const char *string, uint32_t *val)
+{
+	char *endptr;
+	size_t len = strlen(string);
+
+	if (len == 0)
+		return -1;
+
+	*val = strtoul(string, &endptr, 0);
+	if (errno != 0 || RTE_PTR_DIFF(endptr, string) != len)
+		return -2;
+
+	return 0;
+}
+
+/**
+ * Read out-queue configuration from file.
+ *
+ * @param file Path to the configuration file.
+ * @param port Port number.
+ * @param outq Out queue number.
+ * @param cfg Pointer to the Marvell QoS configuration structure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+get_outq_cfg(struct rte_cfgfile *file, int port, int outq,
+		struct mrvl_qos_cfg *cfg)
+{
+	char sec_name[32];
+	const char *entry;
+	uint32_t val;
+
+	snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
+		MRVL_TOK_PORT, port, MRVL_TOK_TXQ, outq);
+
+	/* Skip non-existing */
+	if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
+		return 0;
+
+	entry = rte_cfgfile_get_entry(file, sec_name,
+			MRVL_TOK_WEIGHT);
+	if (entry) {
+		if (get_val_securely(entry, &val) < 0)
+			return -1;
+		cfg->port[port].outq[outq].weight = (uint8_t)val;
+	}
+
+	return 0;
+}
+
+/**
+ * Gets multiple-entry values and places them in table.
+ *
+ * Entry can be anything, e.g. "1 2-3 5 6 7-9". This needs to be converted to
+ * table entries, respectively: {1, 2, 3, 5, 6, 7, 8, 9}.
+ * As all result table's elements are always 1-byte long, we
+ * won't overcomplicate the function, but we'll keep API generic,
+ * check if someone hasn't changed element size and make it simple
+ * to extend to other sizes.
+ *
+ * This function is purely utilitary, it does not print any error, only returns
+ * different error numbers.
+ *
+ * @param entry[in] Values string to parse.
+ * @param tab[out] Results table.
+ * @param elem_sz[in] Element size (in bytes).
+ * @param max_elems[in] Number of results table elements available.
+ * @param max val[in] Maximum value allowed.
+ * @returns Number of correctly parsed elements in case of success.
+ * @retval -1 Wrong element size.
+ * @retval -2 More tokens than result table allows.
+ * @retval -3 Wrong range syntax.
+ * @retval -4 Wrong range values.
+ * @retval -5 Maximum value exceeded.
+ */
+static int
+get_entry_values(const char *entry, uint8_t *tab,
+	size_t elem_sz, uint8_t max_elems, uint8_t max_val)
+{
+	/* There should not be more tokens than max elements.
+	 * Add 1 for error trap.
+	 */
+	char *tokens[max_elems + 1];
+
+	/* Begin, End + error trap = 3. */
+	char *rng_tokens[MAX_RNG_TOKENS + 1];
+	long beg, end;
+	uint32_t token_val;
+	int nb_tokens, nb_rng_tokens;
+	int i;
+	int values = 0;
+	char val;
+	char entry_cpy[CFG_VALUE_LEN];
+
+	if (elem_sz != 1)
+		return -1;
+
+	/* Copy the entry to safely use rte_strsplit(). */
+	snprintf(entry_cpy, RTE_DIM(entry_cpy), "%s", entry);
+
+	/*
+	 * If there are more tokens than array size, rte_strsplit will
+	 * not return error, just array size.
+	 */
+	nb_tokens = rte_strsplit(entry_cpy, strlen(entry_cpy),
+		tokens, max_elems + 1, ' ');
+
+	/* Quick check, will be refined later. */
+	if (nb_tokens > max_elems)
+		return -2;
+
+	for (i = 0; i < nb_tokens; ++i) {
+		if (strchr(tokens[i], '-') != NULL) {
+			/*
+			 * Split to begin and end tokens.
+			 * We want to catch error cases too, thus we leave
+			 * option for number of tokens to be more than 2.
+			 */
+			nb_rng_tokens = rte_strsplit(tokens[i],
+					strlen(tokens[i]), rng_tokens,
+					RTE_DIM(rng_tokens), '-');
+			if (nb_rng_tokens != 2)
+				return -3;
+
+			/* Range and sanity checks. */
+			if (get_val_securely(rng_tokens[0], &token_val) < 0)
+				return -4;
+			beg = (char)token_val;
+			if (get_val_securely(rng_tokens[1], &token_val) < 0)
+				return -4;
+			end = (char)token_val;
+			if (beg < 0 || beg > UCHAR_MAX ||
+				end < 0 || end > UCHAR_MAX || end < beg)
+				return -4;
+
+			for (val = beg; val <= end; ++val) {
+				if (val > max_val)
+					return -5;
+
+				*tab = val;
+				tab = RTE_PTR_ADD(tab, elem_sz);
+				++values;
+				if (values >= max_elems)
+					return -2;
+			}
+		} else {
+			/* Single values. */
+			if (get_val_securely(tokens[i], &token_val) < 0)
+				return -5;
+			val = (char)token_val;
+			if (val > max_val)
+				return -5;
+
+			*tab = val;
+			tab = RTE_PTR_ADD(tab, elem_sz);
+			++values;
+			if (values >= max_elems)
+				return -2;
+		}
+	}
+
+	return values;
+}
+
+/**
+ * Parse Traffic Class'es mapping configuration.
+ *
+ * @param file Config file handle.
+ * @param port Which port to look for.
+ * @param tc Which Traffic Class to look for.
+ * @param cfg[out] Parsing results.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
+		struct mrvl_qos_cfg *cfg)
+{
+	char sec_name[32];
+	const char *entry;
+	int n;
+
+	snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
+		MRVL_TOK_PORT, port, MRVL_TOK_TC, tc);
+
+	/* Skip non-existing */
+	if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
+		return 0;
+
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RXQ);
+	if (entry) {
+		n = get_entry_values(entry,
+			cfg->port[port].tc[tc].inq,
+			sizeof(cfg->port[port].tc[tc].inq[0]),
+			RTE_DIM(cfg->port[port].tc[tc].inq),
+			MRVL_PP2_RXQ_MAX);
+		if (n < 0) {
+			RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n",
+				n, entry);
+			return n;
+		}
+		cfg->port[port].tc[tc].inqs = n;
+	}
+
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PCP);
+	if (entry) {
+		n = get_entry_values(entry,
+			cfg->port[port].tc[tc].pcp,
+			sizeof(cfg->port[port].tc[tc].pcp[0]),
+			RTE_DIM(cfg->port[port].tc[tc].pcp),
+			MAX_PCP);
+		if (n < 0) {
+			RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n",
+				n, entry);
+			return n;
+		}
+		cfg->port[port].tc[tc].pcps = n;
+	}
+
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_DSCP);
+	if (entry) {
+		n = get_entry_values(entry,
+			cfg->port[port].tc[tc].dscp,
+			sizeof(cfg->port[port].tc[tc].dscp[0]),
+			RTE_DIM(cfg->port[port].tc[tc].dscp),
+			MAX_DSCP);
+		if (n < 0) {
+			RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n",
+				n, entry);
+			return n;
+		}
+		cfg->port[port].tc[tc].dscps = n;
+	}
+	return 0;
+}
+
+/**
+ * Parse QoS configuration - rte_kvargs_process handler.
+ *
+ * Opens configuration file and parses its content.
+ *
+ * @param key Unused.
+ * @param path Path to config file.
+ * @param extra_args Pointer to configuration structure.
+ * @returns 0 in case of success, exits otherwise.
+ */
+int
+mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
+		void *extra_args)
+{
+	struct mrvl_qos_cfg **cfg = extra_args;
+	struct rte_cfgfile *file = rte_cfgfile_load(path, 0);
+	uint32_t val;
+	int n, i, ret;
+	const char *entry;
+	char sec_name[32];
+
+	if (file == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot load configuration %s\n", path);
+
+	/* Create configuration. This is never accessed on the fast path,
+	 * so we can ignore socket.
+	 */
+	*cfg = rte_zmalloc("mrvl_qos_cfg", sizeof(struct mrvl_qos_cfg), 0);
+	if (*cfg == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot allocate configuration %s\n",
+			path);
+
+	n = rte_cfgfile_num_sections(file, MRVL_TOK_PORT,
+		sizeof(MRVL_TOK_PORT) - 1);
+
+	if (n == 0) {
+		/* This is weird, but not bad. */
+		RTE_LOG(WARNING, PMD, "Empty configuration file?\n");
+		return 0;
+	}
+
+	/* Use the number of ports given as vdev parameters. */
+	for (n = 0; n < mrvl_ports_nb; ++n) {
+		snprintf(sec_name, sizeof(sec_name), "%s %d %s",
+			MRVL_TOK_PORT, n, MRVL_TOK_DEFAULT);
+
+		/* Skip ports non-existing in configuration. */
+		if (rte_cfgfile_num_sections(file, sec_name,
+				strlen(sec_name)) <= 0) {
+			(*cfg)->port[n].use_global_defaults = 1;
+			(*cfg)->port[n].mapping_priority =
+				PP2_CLS_QOS_TBL_VLAN_IP_PRI;
+			continue;
+		}
+
+		entry = rte_cfgfile_get_entry(file, sec_name,
+				MRVL_TOK_DEFAULT_TC);
+		if (entry) {
+			if (get_val_securely(entry, &val) < 0 ||
+				val > USHRT_MAX)
+				return -1;
+			(*cfg)->port[n].default_tc = (uint8_t)val;
+		} else {
+			RTE_LOG(ERR, PMD,
+				"Default Traffic Class required in custom configuration!\n");
+			return -1;
+		}
+
+		entry = rte_cfgfile_get_entry(file, sec_name,
+				MRVL_TOK_MAPPING_PRIORITY);
+		if (entry) {
+			if (!strncmp(entry, MRVL_TOK_VLAN_IP,
+				sizeof(MRVL_TOK_VLAN_IP)))
+				(*cfg)->port[n].mapping_priority =
+					PP2_CLS_QOS_TBL_VLAN_IP_PRI;
+			else if (!strncmp(entry, MRVL_TOK_IP_VLAN,
+				sizeof(MRVL_TOK_IP_VLAN)))
+				(*cfg)->port[n].mapping_priority =
+					PP2_CLS_QOS_TBL_IP_VLAN_PRI;
+			else if (!strncmp(entry, MRVL_TOK_IP,
+				sizeof(MRVL_TOK_IP)))
+				(*cfg)->port[n].mapping_priority =
+					PP2_CLS_QOS_TBL_IP_PRI;
+			else if (!strncmp(entry, MRVL_TOK_VLAN,
+				sizeof(MRVL_TOK_VLAN)))
+				(*cfg)->port[n].mapping_priority =
+					PP2_CLS_QOS_TBL_VLAN_PRI;
+			else
+				rte_exit(EXIT_FAILURE,
+					"Error in parsing %s value (%s)!\n",
+					MRVL_TOK_MAPPING_PRIORITY, entry);
+		} else {
+			(*cfg)->port[n].mapping_priority =
+				PP2_CLS_QOS_TBL_VLAN_IP_PRI;
+		}
+
+		for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) {
+			ret = get_outq_cfg(file, n, i, *cfg);
+			if (ret < 0)
+				rte_exit(EXIT_FAILURE,
+					"Error %d parsing port %d outq %d!\n",
+					ret, n, i);
+		}
+
+		for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
+			ret = parse_tc_cfg(file, n, i, *cfg);
+			if (ret < 0)
+				rte_exit(EXIT_FAILURE,
+					"Error %d parsing port %d tc %d!\n",
+					ret, n, i);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Setup Traffic Class.
+ *
+ * Fill in TC parameters in single MUSDK TC config entry.
+ * @param param TC parameters entry.
+ * @param inqs Number of MUSDK in-queues in this TC.
+ * @param bpool Bpool for this TC.
+ * @returns 0 in case of success, exits otherwise.
+ */
+static int
+setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
+	struct pp2_bpool *bpool)
+{
+	struct pp2_ppio_inq_params *inq_params;
+
+	param->pkt_offset = MRVL_PKT_OFFS;
+	param->pools[0] = bpool;
+
+	inq_params = rte_zmalloc_socket("inq_params",
+		inqs * sizeof(*inq_params),
+		0, rte_socket_id());
+	if (!inq_params)
+		return -ENOMEM;
+
+	param->num_in_qs = inqs;
+
+	/* Release old config if necessary. */
+	if (param->inqs_params)
+		rte_free(param->inqs_params);
+
+	param->inqs_params = inq_params;
+
+	return 0;
+}
+
+/**
+ * Configure RX Queues in a given port.
+ *
+ * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
+ *
+ * @param priv Port's private data
+ * @param portid DPDK port ID
+ * @param max_queues Maximum number of queues to configure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+int
+mrvl_configure_rxqs(struct mrvl_priv *priv, uint8_t portid,
+	uint16_t max_queues)
+{
+	size_t i, tc;
+
+	if (mrvl_qos_cfg == NULL ||
+		mrvl_qos_cfg->port[portid].use_global_defaults) {
+		/* No port configuration, use default: 1 TC, no QoS. */
+		priv->ppio_params.inqs_params.num_tcs = 1;
+		setup_tc(&priv->ppio_params.inqs_params.tcs_params[0],
+			max_queues, priv->bpool);
+
+		/* Direct mapping of queues i.e. 0->0, 1->1 etc. */
+		for (i = 0; i < max_queues; ++i) {
+			priv->rxq_map[i].tc = 0;
+			priv->rxq_map[i].inq = i;
+		}
+		return 0;
+	}
+
+	/* We need only a subset of configuration. */
+	struct port_cfg *port_cfg = &mrvl_qos_cfg->port[portid];
+
+	priv->qos_tbl_params.type = port_cfg->mapping_priority;
+
+	/*
+	 * We need to reverse mapping, from tc->pcp (better from usability
+	 * point of view) to pcp->tc (configurable in MUSDK).
+	 * First, set all map elements to "default".
+	 */
+	for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
+		priv->qos_tbl_params.pcp_cos_map[i].tc = port_cfg->default_tc;
+
+	/* Then, fill in all known values. */
+	for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
+		if (port_cfg->tc[tc].pcps > RTE_DIM(port_cfg->tc[0].pcp)) {
+			/* Better safe than sorry. */
+			RTE_LOG(ERR, PMD,
+				"Too many PCPs configured in TC %zu!\n", tc);
+			return -1;
+		}
+		for (i = 0; i < port_cfg->tc[tc].pcps; ++i) {
+			priv->qos_tbl_params.pcp_cos_map[
+			  port_cfg->tc[tc].pcp[i]].tc = tc;
+		}
+	}
+
+	/*
+	 * The same logic goes with DSCP.
+	 * First, set all map elements to "default".
+	 */
+	for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
+		priv->qos_tbl_params.dscp_cos_map[i].tc =
+			port_cfg->default_tc;
+
+	/* Fill in all known values. */
+	for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
+		if (port_cfg->tc[tc].dscps > RTE_DIM(port_cfg->tc[0].dscp)) {
+			/* Better safe than sorry. */
+			RTE_LOG(ERR, PMD,
+				"Too many DSCPs configured in TC %zu!\n", tc);
+			return -1;
+		}
+		for (i = 0; i < port_cfg->tc[tc].dscps; ++i) {
+			priv->qos_tbl_params.dscp_cos_map[
+			  port_cfg->tc[tc].dscp[i]].tc = tc;
+		}
+	}
+
+	/*
+	 * Surprisingly, similar logic goes with queue mapping.
+	 * We need only to store qid->tc mapping,
+	 * to know TC when queue is read.
+	 */
+	for (i = 0; i < RTE_DIM(priv->rxq_map); ++i)
+		priv->rxq_map[i].tc = MRVL_UNKNOWN_TC;
+
+	/* Set up DPDKq->(TC,inq) mapping. */
+	for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
+		if (port_cfg->tc[tc].inqs > RTE_DIM(port_cfg->tc[0].inq)) {
+			/* Overflow. */
+			RTE_LOG(ERR, PMD,
+				"Too many RX queues configured per TC %zu!\n",
+				tc);
+			return -1;
+		}
+		for (i = 0; i < port_cfg->tc[tc].inqs; ++i) {
+			uint8_t idx = port_cfg->tc[tc].inq[i];
+
+			priv->rxq_map[idx].tc = tc;
+			priv->rxq_map[idx].inq = i;
+		}
+	}
+
+	/*
+	 * Set up TC configuration. TCs need to be sequenced: 0, 1, 2
+	 * with no gaps. Empty TC means end of processing.
+	 */
+	for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
+		if (port_cfg->tc[i].inqs == 0)
+			break;
+		setup_tc(&priv->ppio_params.inqs_params.tcs_params[i],
+				port_cfg->tc[i].inqs,
+				priv->bpool);
+	}
+
+	priv->ppio_params.inqs_params.num_tcs = i;
+
+	return 0;
+}
+
+/**
+ * Start QoS mapping.
+ *
+ * Finalize QoS table configuration and initialize it in SDK. It can be done
+ * only after port is started, so we have a valid ppio reference.
+ *
+ * @param priv Port's private (configuration) data.
+ * @returns 0 in case of success, exits otherwise.
+ */
+int
+mrvl_start_qos_mapping(struct mrvl_priv *priv)
+{
+	size_t i;
+
+	if (priv->ppio == NULL) {
+		RTE_LOG(ERR, PMD, "ppio must not be NULL here!\n");
+		return -1;
+	}
+
+	for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
+		priv->qos_tbl_params.pcp_cos_map[i].ppio = priv->ppio;
+
+	for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
+		priv->qos_tbl_params.dscp_cos_map[i].ppio = priv->ppio;
+
+	/* Initialize Classifier QoS table. */
+
+	return pp2_cls_qos_tbl_init(&priv->qos_tbl_params, &priv->qos_tbl);
+}
diff --git a/drivers/net/mrvl/mrvl_qos.h b/drivers/net/mrvl/mrvl_qos.h
new file mode 100644
index 0000000..0fcc85c
--- /dev/null
+++ b/drivers/net/mrvl/mrvl_qos.h
@@ -0,0 +1,112 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Semihalf. 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 Semihalf 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 _MRVL_QOS_H_
+#define _MRVL_QOS_H_
+
+#include <rte_common.h>
+#include <rte_config.h>
+
+#include "mrvl_ethdev.h"
+
+/** Code Points per Traffic Class. Equals max(DSCP, PCP). */
+#define MRVL_CP_PER_TC (64)
+
+/** Value used as "unknown". */
+#define MRVL_UNKNOWN_TC (0xFF)
+
+/* QoS config. */
+struct mrvl_qos_cfg {
+	struct port_cfg {
+		struct {
+			uint8_t inq[MRVL_PP2_RXQ_MAX];
+			uint8_t dscp[MRVL_CP_PER_TC];
+			uint8_t pcp[MRVL_CP_PER_TC];
+			uint8_t inqs;
+			uint8_t dscps;
+			uint8_t pcps;
+		} tc[MRVL_PP2_TC_MAX];
+		struct {
+			uint8_t weight;
+		} outq[MRVL_PP2_RXQ_MAX];
+		enum pp2_cls_qos_tbl_type mapping_priority;
+		uint16_t inqs;
+		uint16_t outqs;
+		uint8_t default_tc;
+		uint8_t use_global_defaults;
+	} port[RTE_MAX_ETHPORTS];
+};
+
+/** Global QoS configuration. */
+extern struct mrvl_qos_cfg *mrvl_qos_cfg;
+
+/**
+ * Parse QoS configuration - rte_kvargs_process handler.
+ *
+ * Opens configuration file and parses its content.
+ *
+ * @param key Unused.
+ * @param path Path to config file.
+ * @param extra_args Pointer to configuration structure.
+ * @returns 0 in case of success, exits otherwise.
+ */
+int
+mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
+		void *extra_args);
+
+/**
+ * Configure RX Queues in a given port.
+ *
+ * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
+ *
+ * @param priv Port's private data
+ * @param portid DPDK port ID
+ * @param max_queues Maximum number of queues to configure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+int
+mrvl_configure_rxqs(struct mrvl_priv *priv, uint8_t portid,
+		    uint16_t max_queues);
+
+/**
+ * Start QoS mapping.
+ *
+ * Finalize QoS table configuration and initialize it in SDK. It can be done
+ * only after port is started, so we have a valid ppio reference.
+ *
+ * @param priv Port's private (configuration) data.
+ * @returns 0 in case of success, exits otherwise.
+ */
+int
+mrvl_start_qos_mapping(struct mrvl_priv *priv);
+
+#endif /* _MRVL_QOS_H_ */
diff --git a/drivers/net/mrvl/rte_pmd_mrvl_version.map b/drivers/net/mrvl/rte_pmd_mrvl_version.map
new file mode 100644
index 0000000..a753031
--- /dev/null
+++ b/drivers/net/mrvl/rte_pmd_mrvl_version.map
@@ -0,0 +1,3 @@
+DPDK_17.11 {
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 94568a8..8df74bb 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -130,6 +130,7 @@ endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_LIO_PMD)        += -lrte_pmd_lio
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -libverbs
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD)       += -lrte_pmd_mlx5 -libverbs
+_LDLIBS-$(CONFIG_RTE_LIBRTE_MRVL_PMD)       += -lrte_pmd_mrvl -L$(LIBMUSDK_PATH)/lib -lmusdk
 _LDLIBS-$(CONFIG_RTE_LIBRTE_NFP_PMD)        += -lrte_pmd_nfp
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NULL)       += -lrte_pmd_null
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_PCAP)       += -lrte_pmd_pcap -lpcap
--
2.7.4

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

* [PATCH v3 3/4] doc: add mrvl net pmd documentation
  2017-10-03 11:51     ` [PATCH v3 0/4] add net mrvl pmd driver Tomasz Duszynski
  2017-10-03 11:51       ` [PATCH v3 1/4] app: link the whole rte_cfgfile library Tomasz Duszynski
  2017-10-03 11:51       ` [PATCH v3 2/4] net/mrvl: add mrvl net pmd driver Tomasz Duszynski
@ 2017-10-03 11:51       ` Tomasz Duszynski
  2017-10-04  0:29         ` Ferruh Yigit
  2017-10-03 11:51       ` [PATCH v3 4/4] maintainers: add maintainers for the mrvl net pmd Tomasz Duszynski
  2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
  4 siblings, 1 reply; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-03 11:51 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add documentation for the MRVL NET PMD driver.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <jck@semihalf.com>
---
 doc/guides/nics/features/mrvl.ini |  24 ++++++
 doc/guides/nics/index.rst         |   1 +
 doc/guides/nics/mrvl.rst          | 151 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 176 insertions(+)
 create mode 100644 doc/guides/nics/features/mrvl.ini
 create mode 100644 doc/guides/nics/mrvl.rst

diff --git a/doc/guides/nics/features/mrvl.ini b/doc/guides/nics/features/mrvl.ini
new file mode 100644
index 0000000..781d6dc
--- /dev/null
+++ b/doc/guides/nics/features/mrvl.ini
@@ -0,0 +1,24 @@
+;
+; Supported features of the 'mrvl' network poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Speed capabilities   = Y
+Link status          = Y
+MTU update           = Y
+Jumbo frame          = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Unicast MAC filter   = Y
+Multicast MAC filter = Y
+RSS hash             = Y
+VLAN filter          = Y
+CRC offload          = Y
+L3 checksum offload  = Y
+L4 checksum offload  = Y
+Packet type parsing  = Y
+Basic stats          = Y
+Stats per queue      = Y
+ARMv8                = Y
+Usage doc            = Y
diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index 36f4f3f..7192f63 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -55,6 +55,7 @@ Network Interface Controller Drivers
     liquidio
     mlx4
     mlx5
+    mrvl
     nfp
     qede
     sfc_efx
diff --git a/doc/guides/nics/mrvl.rst b/doc/guides/nics/mrvl.rst
new file mode 100644
index 0000000..241d89b
--- /dev/null
+++ b/doc/guides/nics/mrvl.rst
@@ -0,0 +1,151 @@
+..  BSD LICENSE
+    Copyright(c) 2017 Semihalf. All rights reserved.
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in
+        the documentation and/or other materials provided with the
+        distribution.
+      * Neither the name of Semihalf 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.
+
+MRVL Poll Mode Driver
+======================
+
+The MRVL PMD (librte_pmd_mrvl) provides poll mode driver support
+for the Marvell PPv2 (Packet Processor v2) 1/10 Gbps adapter.
+
+.. Note::
+
+   Due to external dependencies, this driver is disabled by default. It must
+   be enabled manually by setting relevant configuration option manually.
+   Please refer to `Config File Options`_ section for further details.
+
+
+Features
+--------
+
+Features of the MRVL PMD are:
+
+- Speed capabilities
+- Link status
+- Queue start/stop
+- MTU update
+- Jumbo frame
+- Promiscuous mode
+- Allmulticast mode
+- Unicast MAC filter
+- Multicast MAC filter
+- RSS hash
+- VLAN filter
+- CRC offload
+- L3 checksum offload
+- L4 checksum offload
+- Packet type parsing
+- Basic stats
+- Stats per queue
+
+
+Limitations
+-----------
+
+- Number of lcores is limited to 9 by MUSDK internal design. If more lcores
+  need to be allocated, locking will have to be considered. Number of available
+  lcores can be changed via ``MRVL_MUSDK_HIFS_RESERVED`` define in
+  ``mrvl_ethdev.c`` source file.
+
+- Flushing vlans added for filtering is not possible due to MUSDK missing
+  functionality. Current workaround is to reset board so that PPv2 has a
+  chance to start in a sane state.
+
+
+Prerequisites
+-------------
+
+- MUSDK (Marvell User-Space SDK) sources available
+  `here <https://github.com/MarvellEmbeddedProcessors/musdk-marvell/tree/musdk-armada-17.08>`_.
+
+    MUSDK is a light-weight library that provides direct access to Marvell's
+    PPv2 (Packet Processor v2). Alternatively prebuilt MUSDK library can be
+    requested from `Marvell Extranet <https://extranet.marvell.com>`_. Once
+    approval has been granted, library can be found by typing ``musdk`` in
+    search box.
+
+- DPDK environment
+
+    Follow the DPDK :ref:`Getting Started Guide for Linux <linux_gsg>` to setup
+    DPDK environment.
+
+
+Config File Options
+-------------------
+
+The following options can be modified in the ``config`` file.
+
+- ``CONFIG_RTE_LIBRTE_MRVL_PMD`` (default ``n``)
+
+    Toggle compilation of the librte_pmd_mrvl driver.
+
+- ``CONFIG_RTE_LIBRTE_MRVL_DEBUG`` (default ``n``)
+
+    Toggle display of debugging messages.
+
+- ``CONFIG_RTE_MRVL_MUSDK_DMA_MEMSIZE`` (default ``41943040``)
+
+    Size in bytes of the contiguous memory region that MUSDK will allocate
+    for run-time DMA-able data buffers.
+
+
+Building DPDK
+-------------
+
+Driver needs precompiled MUSDK library during compilation. Detailed build
+process is described in library's documentation under ``doc`` directory.
+
+Before the DPDK build process the environmental variable ``LIBMUSDK_PATH`` with
+the path to the MUSDK installation directory needs to be exported.
+
+Usage Example
+-------------
+
+MRVL PMD requires extra kernel modules to function properly:
+
+.. code-block:: console
+
+   insmod musdk_uio.ko
+   insmod mv_pp_uio.ko
+   insmod mvpp2x_sysfs.ko
+
+Additionally interfaces used by DPDK application need to be put up:
+
+.. code-block:: console
+
+   ip link set eth0 up
+   ip link set eth1 up
+
+In order to run testpmd example application following command can be used:
+
+.. code-block:: console
+
+   ./testpmd --vdev=eth_mrvl,iface=eth0,iface=eth2 -c 7 -- \
+     --burst=128 --txd=2048 --rxd=1024 --rxq=2 --txq=2  --nb-cores=2 \
+     -i -a --disable-hw-vlan-strip --rss-udp
-- 
2.7.4

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

* [PATCH v3 4/4] maintainers: add maintainers for the mrvl net pmd
  2017-10-03 11:51     ` [PATCH v3 0/4] add net mrvl pmd driver Tomasz Duszynski
                         ` (2 preceding siblings ...)
  2017-10-03 11:51       ` [PATCH v3 3/4] doc: add mrvl net pmd documentation Tomasz Duszynski
@ 2017-10-03 11:51       ` Tomasz Duszynski
  2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
  4 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-03 11:51 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 MAINTAINERS | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index a0cd75e..d4810cf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -393,6 +393,16 @@ F: drivers/net/mlx5/
 F: doc/guides/nics/mlx5.rst
 F: doc/guides/nics/features/mlx5.ini
 
+Marvell mrvl
+M: Jacek Siuda <jck@semihalf.com>
+M: Tomasz Duszynski <tdu@semihalf.com>
+M: Dmitri Epshtein <dima@marvell.com>
+M: Natalie Samsonov <nsamsono@marvell.com>
+M: Jianbo Liu <jianbo.liu@linaro.org>
+F: drivers/net/mrvl/
+F: doc/guides/nics/mrvl.rst
+F: doc/guides/nics/features/mrvl.ini
+
 Netcope szedata2
 M: Matej Vido <vido@cesnet.cz>
 F: drivers/net/szedata2/
-- 
2.7.4

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

* Re: [PATCH v3 2/4] net/mrvl: add mrvl net pmd driver
  2017-10-03 11:51       ` [PATCH v3 2/4] net/mrvl: add mrvl net pmd driver Tomasz Duszynski
@ 2017-10-04  0:24         ` Ferruh Yigit
  2017-10-04  8:59           ` Tomasz Duszynski
  2017-10-04  0:28         ` Ferruh Yigit
  1 sibling, 1 reply; 110+ messages in thread
From: Ferruh Yigit @ 2017-10-04  0:24 UTC (permalink / raw)
  To: Tomasz Duszynski, dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On 10/3/2017 12:51 PM, Tomasz Duszynski wrote:
> Add support for the Marvell PPv2 (Packet Processor v2) 1/10 Gbps adapter.
> Driver is based on external, publicly available, light-weight Marvell
> MUSDK library that provides access to network packet processor.
> 
> Driver comes with support for the following features:
> 
> * Speed capabilities
> * Link status
> * Queue start/stop
> * MTU update
> * Jumbo frame
> * Promiscuous mode
> * Allmulticast mode
> * Unicast MAC filter
> * Multicast MAC filter
> * RSS hash
> * VLAN filter
> * CRC offload
> * L3 checksum offload
> * L4 checksum offload
> * Packet type parsing
> * Basic stats
> * Stats per queue

I have more detailed comments but in high level,
what do you think splitting this patch into three patches:
- Skeleton
- Add Rx/Tx support
- Add features, like MTU update or Promiscuous etc.. support

> 
> Driver was engineered cooperatively by Semihalf and Marvell teams.
> 
> Semihalf:
> Jacek Siuda <jck@semihalf.com>
> Tomasz Duszynski <tdu@semihalf.com>
> 
> Marvell:
> Dmitri Epshtein <dima@marvell.com>
> Natalie Samsonov <nsamsono@marvell.com>
> 
> Signed-off-by: Jacek Siuda <jck@semihalf.com>
> Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>

<...>

> +static struct rte_vdev_driver pmd_mrvl_drv = {
> +	.probe = rte_pmd_mrvl_probe,
> +	.remove = rte_pmd_mrvl_remove,
> +};
> +
> +RTE_PMD_REGISTER_VDEV(net_mrvl, pmd_mrvl_drv);

Please help me understand.

This driver implemented as virtual driver, because:
With the help of custom kernel modules, musdk library already provides
userspace datapath support. This PMD is an interface to musdk library.
Is this correct?

If so, just thinking loud:
- Why not implement this PMD directly on top of kernel interface,
removing musdk layer completely?
- How big problem that this PMD depends on custom kernel code?
- How library and custom kernel code delivered? For which platforms?

<....>

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

* Re: [PATCH v3 2/4] net/mrvl: add mrvl net pmd driver
  2017-10-03 11:51       ` [PATCH v3 2/4] net/mrvl: add mrvl net pmd driver Tomasz Duszynski
  2017-10-04  0:24         ` Ferruh Yigit
@ 2017-10-04  0:28         ` Ferruh Yigit
  2017-10-04 13:19           ` Tomasz Duszynski
  1 sibling, 1 reply; 110+ messages in thread
From: Ferruh Yigit @ 2017-10-04  0:28 UTC (permalink / raw)
  To: Tomasz Duszynski, dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On 10/3/2017 12:51 PM, Tomasz Duszynski wrote:
> Add support for the Marvell PPv2 (Packet Processor v2) 1/10 Gbps adapter.
> Driver is based on external, publicly available, light-weight Marvell
> MUSDK library that provides access to network packet processor.
> 
> Driver comes with support for the following features:
> 
> * Speed capabilities
> * Link status
> * Queue start/stop
> * MTU update
> * Jumbo frame
> * Promiscuous mode
> * Allmulticast mode
> * Unicast MAC filter
> * Multicast MAC filter
> * RSS hash
> * VLAN filter
> * CRC offload
> * L3 checksum offload
> * L4 checksum offload
> * Packet type parsing
> * Basic stats
> * Stats per queue
> 
> Driver was engineered cooperatively by Semihalf and Marvell teams.
> 
> Semihalf:
> Jacek Siuda <jck@semihalf.com>
> Tomasz Duszynski <tdu@semihalf.com>
> 
> Marvell:
> Dmitri Epshtein <dima@marvell.com>
> Natalie Samsonov <nsamsono@marvell.com>
> 
> Signed-off-by: Jacek Siuda <jck@semihalf.com>
> Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>

<...>

> +++ b/config/common_base
> @@ -262,6 +262,13 @@ CONFIG_RTE_LIBRTE_NFP_PMD=n
>  CONFIG_RTE_LIBRTE_NFP_DEBUG=n
> 
>  #
> +# Compile Marvell PMD driver
> +#
> +CONFIG_RTE_LIBRTE_MRVL_PMD=n
> +CONFIG_RTE_LIBRTE_MRVL_DEBUG=n
> +CONFIG_RTE_MRVL_MUSDK_DMA_MEMSIZE=41943040

Is dma memsize needs to be a configuration option?

<...>

> +include $(RTE_SDK)/mk/rte.vars.mk
> +
> +ifneq ($(MAKECMDGOALS),clean)
> +ifneq ($(MAKECMDGOALS),config)
> +ifeq ($(LIBMUSDK_PATH),)
> +$(error "Please define LIBMUSDK_PATH environment variable")

Not sure how to resolve this dependency.
What do you think adding this as configuration option?

Or DPDK just adds the -lmusdk external dependency and while compiling
for marvel EXTRA_LDFLAGS parameter should be pass with
"-L$(LIBMUSDK_PATH)" and this can be documented in marvel doc. What do
you think?

> +endif
> +ifeq ($(CONFIG_RTE_LIBRTE_CFGFILE),n)
> +$(error "RTE_LIBRTE_CFGFILE must be enabled in configuration!")

This can be also handled in drivers/net/Makefile, it can be possible to
add check there for LIBRTE_CFGFILE dependency.

> +endif
> +endif
> +endif
> +
> +# library name
> +LIB = librte_pmd_mrvl.a
> +
> +# library version
> +LIBABIVER := 1
> +
> +# versioning export map
> +EXPORT_MAP := rte_pmd_mrvl_version.map
> +
> +# external library dependencies
> +CFLAGS += -I$(LIBMUSDK_PATH)/include
> +CFLAGS += -DMVCONF_ARCH_DMA_ADDR_T_64BIT
> +CFLAGS += -DCONF_PP2_BPOOL_COOKIE_SIZE=32
> +CFLAGS += $(WERROR_FLAGS)
> +CFLAGS += -O3
> +LDLIBS += -L$(LIBMUSDK_PATH)/lib

This can be LDFLAGS instead of LDLIBS

> +LDLIBS += -lmusdk
> +
> +# library source files
> +SRCS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl_ethdev.c
> +SRCS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl_qos.c
> +
> +# library dependencies
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += lib/librte_cfgfile

These variables no more used, you can drop this. drivers/net/Makefile
used for this, you are already updating that file, librte_cfgfile needs
to be added there.

> +
> +include $(RTE_SDK)/mk/rte.lib.mk

<...>

> +/*
> + * To use buffer harvesting based on loopback port shadow queue structure
> + * was introduced for buffers information bookkeeping.
> + *
> + * Before sending the packet, related buffer information (pp2_buff_inf) is
> + * stored in shadow queue. After packet is transmitted no longer used
> + * packet buffer is released back to it's original hardware pool,
> + * on condition it originated from interface.
> + * In case it  was generated by application itself i.e: mbuf->port field is
> + * 0xff then its released to software mempool.

You already explained here but can you please give more details why
shadow queue needed?

> + */
> +struct mrvl_shadow_txq {
> +	int head;           /* write index - used when sending buffers */
> +	int tail;           /* read index - used when releasing buffers */
> +	u16 size;           /* queue occupied size */
> +	u16 num_to_release; /* number of buffers sent, that can be released */
> +	struct buff_release_entry ent[MRVL_PP2_TX_SHADOWQ_SIZE]; /* q entries */
> +};
> +
> +struct mrvl_rxq {
> +	struct mrvl_priv *priv;
> +	struct rte_mempool *mp;
> +	int queue_id;
> +	int port_id;
> +	int cksum_enabled;
> +	uint64_t bytes_recv;
> +	uint64_t drop_mac;
> +};
> +
> +struct mrvl_txq {
> +	struct mrvl_priv *priv;
> +	int queue_id;
> +	int port_id;
> +	uint64_t bytes_sent;
> +};
> +

<...>

> +static int
> +mrvl_dev_start(struct rte_eth_dev *dev)
> +{
> +	struct mrvl_priv *priv = dev->data->dev_private;
> +	char match[MRVL_MATCH_LEN];
> +	int ret;
> +
> +	snprintf(match, sizeof(match), "ppio-%d:%d",
> +		 priv->pp_id, priv->ppio_id);
> +	priv->ppio_params.match = match;

Why this match is used, just a reminder that match is only valid for the
scope of this function, after this function it will be invalid.

<...>

> +
> +	if (rte_spinlock_trylock(&q->priv->lock) == 1) {

Why getting lock in Rx data path?

> +		num = mrvl_get_bpool_size(bpool->pp2_id, bpool->id);
> +
> +		if (unlikely(num <= q->priv->bpool_min_size ||
> +			     (!rx_done && num < q->priv->bpool_init_size))) {
> +			ret = mrvl_fill_bpool(q, MRVL_BURST_SIZE);
> +			if (ret)
> +				RTE_LOG(ERR, PMD, "Failed to fill bpool\n");
> +		} else if (unlikely(num > q->priv->bpool_max_size)) {
> +			int i;
> +			int pkt_to_remove = num - q->priv->bpool_init_size;
> +			struct rte_mbuf *mbuf;
> +			struct pp2_buff_inf buff;
> +
> +			RTE_LOG(DEBUG, PMD,
> +				"\nport-%d:%d: bpool %d oversize - remove %d buffers (pool size: %d -> %d)\n",
> +				bpool->pp2_id, q->priv->ppio->port_id,
> +				bpool->id, pkt_to_remove, num,
> +				q->priv->bpool_init_size);
> +
> +			for (i = 0; i < pkt_to_remove; i++) {
> +				pp2_bpool_get_buff(hifs[core_id], bpool, &buff);
> +				mbuf = (struct rte_mbuf *)
> +					(cookie_addr_high | buff.cookie);
> +				rte_pktmbuf_free(mbuf);
> +			}
> +			mrvl_port_bpool_size
> +				[bpool->pp2_id][bpool->id][core_id] -=
> +								pkt_to_remove;
> +		}
> +		rte_spinlock_unlock(&q->priv->lock);
> +	}
> +
> +	return rx_done;
> +}

<...>

> +	cfgnum = rte_kvargs_count(kvlist, MRVL_CFG_ARG);
> +	if (cfgnum > 1) {
> +		RTE_LOG(ERR, PMD, "Cannot handle more than one config file!\n");
> +		goto out_free_kvlist;
> +	} else if (cfgnum == 1) {
> +		rte_kvargs_process(kvlist, MRVL_CFG_ARG,
> +				   mrvl_get_qoscfg, &mrvl_qos_cfg);

Is the expected format/contect of the config file documented? How one
can know how to create a config file?

> +	}
> +
> +	/*
> +	 * ret == -EEXIST is correct, it means DMA
> +	 * has been already initialized (by another PMD).
> +	 */
> +	ret = mv_sys_dma_mem_init(RTE_MRVL_MUSDK_DMA_MEMSIZE);
> +	if (ret < 0 && ret != -EEXIST)
> +		goto out_free_kvlist;
> +
> +	ret = mrvl_init_pp2();
> +	if (ret) {
> +		RTE_LOG(ERR, PMD, "Failed to init PP!\n");
> +		goto out_deinit_dma;
> +	}
> +
> +	ret = mrvl_init_hifs();
> +	if (ret)
> +		goto out_deinit_hifs;
> +
> +	for (i = 0; i < ifnum; i++) {
> +		RTE_LOG(INFO, PMD, "Creating %s\n", ifnames[i]);
> +		ret = mrvl_eth_dev_create(vdev, ifnames[i]);

So you are supporting multiple ethdev devices created by single vdev
device, by providing multiple "iface" argument in device args.

This will cause eal create single virtual device but driver create
multiple ethdev devices. I don't see direct problem with this but lets
think about it.
This can be problem if you want to provide ethdev specific device
arguments. Perhaps that is why you need to provide a config file ?

It can be an option to define each ethdev with:
"--vdev net_mrvl0,iface=xx0,config=yy0 --vdev
net_mrlv1,iface=xx1,config=yy1 ..."

This may remove your dependecy to librte_cfgfile.

> +		if (ret)
> +			goto out_cleanup;
> +	}
> +
> +	rte_kvargs_free(kvlist);
> +
> +	memset(mrvl_port_bpool_size, 0, sizeof(mrvl_port_bpool_size));
> +
> +	mrvl_lcore_first = RTE_MAX_LCORE;
> +	mrvl_lcore_last = 0;
> +
> +	RTE_LCORE_FOREACH(core_id) {
> +		mrvl_set_first_last_cores(core_id);

This sets limits of core_id. Why you need to know this in PMD level?

<...>

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

* Re: [PATCH v3 3/4] doc: add mrvl net pmd documentation
  2017-10-03 11:51       ` [PATCH v3 3/4] doc: add mrvl net pmd documentation Tomasz Duszynski
@ 2017-10-04  0:29         ` Ferruh Yigit
  2017-10-04  7:53           ` Tomasz Duszynski
  0 siblings, 1 reply; 110+ messages in thread
From: Ferruh Yigit @ 2017-10-04  0:29 UTC (permalink / raw)
  To: Tomasz Duszynski, dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On 10/3/2017 12:51 PM, Tomasz Duszynski wrote:
> Add documentation for the MRVL NET PMD driver.
> 
> Signed-off-by: Jacek Siuda <jck@semihalf.com>
> Signed-off-by: Tomasz Duszynski <jck@semihalf.com>

<...>

> +;
> +[Features]
> +Speed capabilities   = Y

This doesn't seems correct please check doc/guides/nics/features.rst

> +Link status          = Y
> +MTU update           = Y
> +Jumbo frame          = Y
> +Promiscuous mode     = Y
> +Allmulticast mode    = Y
> +Unicast MAC filter   = Y
> +Multicast MAC filter = Y
> +RSS hash             = Y
> +VLAN filter          = Y
> +CRC offload          = Y
> +L3 checksum offload  = Y
> +L4 checksum offload  = Y
> +Packet type parsing  = Y
> +Basic stats          = Y
> +Stats per queue      = Y
> +ARMv8                = Y

Is other architecture not supported or not tested?

> +Usage doc            = Y

<...>

> +Prerequisites
> +-------------
> +
> +- MUSDK (Marvell User-Space SDK) sources available
> +  `here <https://github.com/MarvellEmbeddedProcessors/musdk-marvell/tree/musdk-armada-17.08>`_.

Is this 17.08 by change related to DPDK version, I mean is there any
relation between DPDK version and musdk library version?

> +
> +    MUSDK is a light-weight library that provides direct access to Marvell's
> +    PPv2 (Packet Processor v2). Alternatively prebuilt MUSDK library can be
> +    requested from `Marvell Extranet <https://extranet.marvell.com>`_. Once
> +    approval has been granted, library can be found by typing ``musdk`` in
> +    search box.

What is the condition of having an approval?

> +
> +- DPDK environment
> +
> +    Follow the DPDK :ref:`Getting Started Guide for Linux <linux_gsg>` to setup
> +    DPDK environment.
> +
> +

<...>

> +Building DPDK
> +-------------
> +
> +Driver needs precompiled MUSDK library during compilation. Detailed build
> +process is described in library's documentation under ``doc`` directory.
> +
> +Before the DPDK build process the environmental variable ``LIBMUSDK_PATH`` with
> +the path to the MUSDK installation directory needs to be exported.
> +
> +Usage Example
> +-------------
> +
> +MRVL PMD requires extra kernel modules to function properly:
> +
> +.. code-block:: console
> +
> +   insmod musdk_uio.ko
> +   insmod mv_pp_uio.ko
> +   insmod mvpp2x_sysfs.ko

Why these kernel modules are required and how one can obtain them?
These are out of tree kernel modules right?

<...>

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

* Re: [PATCH v3 3/4] doc: add mrvl net pmd documentation
  2017-10-04  0:29         ` Ferruh Yigit
@ 2017-10-04  7:53           ` Tomasz Duszynski
  0 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-04  7:53 UTC (permalink / raw)
  To: Ferruh Yigit
  Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jianbo.liu,
	Jacek Siuda, sgridish

On Wed, Oct 04, 2017 at 01:29:01AM +0100, Ferruh Yigit wrote:

+cc Shlomi.
> On 10/3/2017 12:51 PM, Tomasz Duszynski wrote:
> > Add documentation for the MRVL NET PMD driver.
> >
> > Signed-off-by: Jacek Siuda <jck@semihalf.com>
> > Signed-off-by: Tomasz Duszynski <jck@semihalf.com>
>
> <...>
>
> > +;
> > +[Features]
> > +Speed capabilities   = Y
>
> This doesn't seems correct please check doc/guides/nics/features.rst
Right, speed capabilities are not returned via rte_eth_dev_info. Thanks
for pointing this out. Will fix that in v4.
>
> > +Link status          = Y
> > +MTU update           = Y
> > +Jumbo frame          = Y
> > +Promiscuous mode     = Y
> > +Allmulticast mode    = Y
> > +Unicast MAC filter   = Y
> > +Multicast MAC filter = Y
> > +RSS hash             = Y
> > +VLAN filter          = Y
> > +CRC offload          = Y
> > +L3 checksum offload  = Y
> > +L4 checksum offload  = Y
> > +Packet type parsing  = Y
> > +Basic stats          = Y
> > +Stats per queue      = Y
> > +ARMv8                = Y
>
> Is other architecture not supported or not tested?
Currently that NIC comes integrated into Armada 7k/8k SoCs and they are based
on ARMv8.
>
> > +Usage doc            = Y
>
> <...>
>
> > +Prerequisites
> > +-------------
> > +
> > +- MUSDK (Marvell User-Space SDK) sources available
> > +  `here <https://github.com/MarvellEmbeddedProcessors/musdk-marvell/tree/musdk-armada-17.08>`_.
>
> Is this 17.08 by change related to DPDK version, I mean is there any
> relation between DPDK version and musdk library version?
No relation except similar versioning convention that is used. Musdk
library version needed by DPDK driver is mentioned explicitly in
documentation.
>
> > +
> > +    MUSDK is a light-weight library that provides direct access to Marvell's
> > +    PPv2 (Packet Processor v2). Alternatively prebuilt MUSDK library can be
> > +    requested from `Marvell Extranet <https://extranet.marvell.com>`_. Once
> > +    approval has been granted, library can be found by typing ``musdk`` in
> > +    search box.
>
> What is the condition of having an approval?
I think Marvell team would be more helpful here.
>
> > +
> > +- DPDK environment
> > +
> > +    Follow the DPDK :ref:`Getting Started Guide for Linux <linux_gsg>` to setup
> > +    DPDK environment.
> > +
> > +
>
> <...>
>
> > +Building DPDK
> > +-------------
> > +
> > +Driver needs precompiled MUSDK library during compilation. Detailed build
> > +process is described in library's documentation under ``doc`` directory.
> > +
> > +Before the DPDK build process the environmental variable ``LIBMUSDK_PATH`` with
> > +the path to the MUSDK installation directory needs to be exported.
> > +
> > +Usage Example
> > +-------------
> > +
> > +MRVL PMD requires extra kernel modules to function properly:
> > +
> > +.. code-block:: console
> > +
> > +   insmod musdk_uio.ko
> > +   insmod mv_pp_uio.ko
> > +   insmod mvpp2x_sysfs.ko
>
> Why these kernel modules are required and how one can obtain them?
Kernel modules are used to map device memory regions to userspace.
musdk_uio and mv_pp_uio both come with MUSDK library. As for mvpp2x_sysfs
I think Marvell team could be more helpful here.
> These are out of tree kernel modules right?
Right. You have to either build them yourself or get precompiled from
Marvell-extranet.
>
> <...>
>

--
- Tomasz Duszyński

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

* Re: [PATCH v3 2/4] net/mrvl: add mrvl net pmd driver
  2017-10-04  0:24         ` Ferruh Yigit
@ 2017-10-04  8:59           ` Tomasz Duszynski
  2017-10-04 16:59             ` Ferruh Yigit
  0 siblings, 1 reply; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-04  8:59 UTC (permalink / raw)
  To: Ferruh Yigit
  Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On Wed, Oct 04, 2017 at 01:24:27AM +0100, Ferruh Yigit wrote:
> On 10/3/2017 12:51 PM, Tomasz Duszynski wrote:
> > Add support for the Marvell PPv2 (Packet Processor v2) 1/10 Gbps adapter.
> > Driver is based on external, publicly available, light-weight Marvell
> > MUSDK library that provides access to network packet processor.
> >
> > Driver comes with support for the following features:
> >
> > * Speed capabilities
> > * Link status
> > * Queue start/stop
> > * MTU update
> > * Jumbo frame
> > * Promiscuous mode
> > * Allmulticast mode
> > * Unicast MAC filter
> > * Multicast MAC filter
> > * RSS hash
> > * VLAN filter
> > * CRC offload
> > * L3 checksum offload
> > * L4 checksum offload
> > * Packet type parsing
> > * Basic stats
> > * Stats per queue
>
> I have more detailed comments but in high level,
> what do you think splitting this patch into three patches:
> - Skeleton
> - Add Rx/Tx support
> - Add features, like MTU update or Promiscuous etc.. support
If it's how submission process works then I think you left me with no
other option than splitting driver into nice patchset :). On the other
hand driver is really a wrapper to MUSDK library and thus quite easy to
follow. What are the benefits of such 3-way split?
>
> >
> > Driver was engineered cooperatively by Semihalf and Marvell teams.
> >
> > Semihalf:
> > Jacek Siuda <jck@semihalf.com>
> > Tomasz Duszynski <tdu@semihalf.com>
> >
> > Marvell:
> > Dmitri Epshtein <dima@marvell.com>
> > Natalie Samsonov <nsamsono@marvell.com>
> >
> > Signed-off-by: Jacek Siuda <jck@semihalf.com>
> > Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
>
> <...>
>
> > +static struct rte_vdev_driver pmd_mrvl_drv = {
> > +	.probe = rte_pmd_mrvl_probe,
> > +	.remove = rte_pmd_mrvl_remove,
> > +};
> > +
> > +RTE_PMD_REGISTER_VDEV(net_mrvl, pmd_mrvl_drv);
>
> Please help me understand.
>
> This driver implemented as virtual driver, because:
> With the help of custom kernel modules, musdk library already provides
> userspace datapath support. This PMD is an interface to musdk library.
> Is this correct?
That is right. Another reason this NIC is not PCI device.
>
> If so, just thinking loud:
> - Why not implement this PMD directly on top of kernel interface,
> removing musdk layer completely?
> - How big problem that this PMD depends on custom kernel code?
I think the main reason is that MUSDK is already used in different projects.
Keeping multiple codebases offering similar functionality would be quite
demanding in terms of extra work needed.
> - How library and custom kernel code delivered? For which platforms?
Kernel and library sources are hosted on publicly available repository.
Driver was tested on Armada 7k/8k SoCs.
>
> <....>
>

--
- Tomasz Duszyński

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

* Re: [PATCH v3 2/4] net/mrvl: add mrvl net pmd driver
  2017-10-04  0:28         ` Ferruh Yigit
@ 2017-10-04 13:19           ` Tomasz Duszynski
  2017-10-05 17:37             ` Ferruh Yigit
  0 siblings, 1 reply; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-04 13:19 UTC (permalink / raw)
  To: Ferruh Yigit
  Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On Wed, Oct 04, 2017 at 01:28:47AM +0100, Ferruh Yigit wrote:
> On 10/3/2017 12:51 PM, Tomasz Duszynski wrote:
> > Add support for the Marvell PPv2 (Packet Processor v2) 1/10 Gbps adapter.
> > Driver is based on external, publicly available, light-weight Marvell
> > MUSDK library that provides access to network packet processor.
> >
> > Driver comes with support for the following features:
> >
> > * Speed capabilities
> > * Link status
> > * Queue start/stop
> > * MTU update
> > * Jumbo frame
> > * Promiscuous mode
> > * Allmulticast mode
> > * Unicast MAC filter
> > * Multicast MAC filter
> > * RSS hash
> > * VLAN filter
> > * CRC offload
> > * L3 checksum offload
> > * L4 checksum offload
> > * Packet type parsing
> > * Basic stats
> > * Stats per queue
> >
> > Driver was engineered cooperatively by Semihalf and Marvell teams.
> >
> > Semihalf:
> > Jacek Siuda <jck@semihalf.com>
> > Tomasz Duszynski <tdu@semihalf.com>
> >
> > Marvell:
> > Dmitri Epshtein <dima@marvell.com>
> > Natalie Samsonov <nsamsono@marvell.com>
> >
> > Signed-off-by: Jacek Siuda <jck@semihalf.com>
> > Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
>
> <...>
>
> > +++ b/config/common_base
> > @@ -262,6 +262,13 @@ CONFIG_RTE_LIBRTE_NFP_PMD=n
> >  CONFIG_RTE_LIBRTE_NFP_DEBUG=n
> >
> >  #
> > +# Compile Marvell PMD driver
> > +#
> > +CONFIG_RTE_LIBRTE_MRVL_PMD=n
> > +CONFIG_RTE_LIBRTE_MRVL_DEBUG=n
> > +CONFIG_RTE_MRVL_MUSDK_DMA_MEMSIZE=41943040
>
> Is dma memsize needs to be a configuration option?

That config option is used both by NET and CRYPTO drivers. In case NET
and CRYPTO are used together i.e ipsec-secgw then DMA_MEMSIZE must be
the set to the same size. Putting this configuration option in .config
makes sure DMA_MEMSIZE stays synchronized.

>
> <...>
>
> > +include $(RTE_SDK)/mk/rte.vars.mk
> > +
> > +ifneq ($(MAKECMDGOALS),clean)
> > +ifneq ($(MAKECMDGOALS),config)
> > +ifeq ($(LIBMUSDK_PATH),)
> > +$(error "Please define LIBMUSDK_PATH environment variable")
>
> Not sure how to resolve this dependency.
> What do you think adding this as configuration option?

All other drivers with external dependencies follow the same approach.

>
> Or DPDK just adds the -lmusdk external dependency and while compiling
> for marvel EXTRA_LDFLAGS parameter should be pass with
> "-L$(LIBMUSDK_PATH)" and this can be documented in marvel doc. What do
> you think?

Both solutions are reasonable. The former was chosen because that's what the
other drivers do.

>
> > +endif
> > +ifeq ($(CONFIG_RTE_LIBRTE_CFGFILE),n)
> > +$(error "RTE_LIBRTE_CFGFILE must be enabled in configuration!")
>
> This can be also handled in drivers/net/Makefile, it can be possible to
> add check there for LIBRTE_CFGFILE dependency.
>

ACK

> > +endif
> > +endif
> > +endif
> > +
> > +# library name
> > +LIB = librte_pmd_mrvl.a
> > +
> > +# library version
> > +LIBABIVER := 1
> > +
> > +# versioning export map
> > +EXPORT_MAP := rte_pmd_mrvl_version.map
> > +
> > +# external library dependencies
> > +CFLAGS += -I$(LIBMUSDK_PATH)/include
> > +CFLAGS += -DMVCONF_ARCH_DMA_ADDR_T_64BIT
> > +CFLAGS += -DCONF_PP2_BPOOL_COOKIE_SIZE=32
> > +CFLAGS += $(WERROR_FLAGS)
> > +CFLAGS += -O3
> > +LDLIBS += -L$(LIBMUSDK_PATH)/lib
>
> This can be LDFLAGS instead of LDLIBS

Moving that to LDFLAGS will break compilation in case
CONFIG_RTE_BUILD_SHARED_LIB is set as -L... does not show up on command
line thus linker does not know where to look extra library up.
I may be wrong but it looks as if specifying LDFLAGS in driver's
Makefile is no-op.

On the other hand, if we are building static libraries both
-lmusdk and -L$(LIBMUSDK_PATH)/lib are added to specific _LDLIBS which in turn
ends up in LDLIBS.

>
> > +LDLIBS += -lmusdk
> > +
> > +# library source files
> > +SRCS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl_ethdev.c
> > +SRCS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl_qos.c
> > +
> > +# library dependencies
> > +DEPDIRS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += lib/librte_cfgfile
>
> These variables no more used, you can drop this. drivers/net/Makefile
> used for this, you are already updating that file, librte_cfgfile needs
> to be added there.
>

ACK

> > +
> > +include $(RTE_SDK)/mk/rte.lib.mk
>
> <...>
>
> > +/*
> > + * To use buffer harvesting based on loopback port shadow queue structure
> > + * was introduced for buffers information bookkeeping.
> > + *
> > + * Before sending the packet, related buffer information (pp2_buff_inf) is
> > + * stored in shadow queue. After packet is transmitted no longer used
> > + * packet buffer is released back to it's original hardware pool,
> > + * on condition it originated from interface.
> > + * In case it  was generated by application itself i.e: mbuf->port field is
> > + * 0xff then its released to software mempool.
>
> You already explained here but can you please give more details why
> shadow queue needed?

It's used for mbuf harvesting in tx-path. Instead of releasing pushed
out mbuf to mempool and allocating it once again later on, mbuf is
stored in the shadow queue and returned back to hardware buffer manager
after being sent.

>
> > + */
> > +struct mrvl_shadow_txq {
> > +	int head;           /* write index - used when sending buffers */
> > +	int tail;           /* read index - used when releasing buffers */
> > +	u16 size;           /* queue occupied size */
> > +	u16 num_to_release; /* number of buffers sent, that can be released */
> > +	struct buff_release_entry ent[MRVL_PP2_TX_SHADOWQ_SIZE]; /* q entries */
> > +};
> > +
> > +struct mrvl_rxq {
> > +	struct mrvl_priv *priv;
> > +	struct rte_mempool *mp;
> > +	int queue_id;
> > +	int port_id;
> > +	int cksum_enabled;
> > +	uint64_t bytes_recv;
> > +	uint64_t drop_mac;
> > +};
> > +
> > +struct mrvl_txq {
> > +	struct mrvl_priv *priv;
> > +	int queue_id;
> > +	int port_id;
> > +	uint64_t bytes_sent;
> > +};
> > +
>
> <...>
>
> > +static int
> > +mrvl_dev_start(struct rte_eth_dev *dev)
> > +{
> > +	struct mrvl_priv *priv = dev->data->dev_private;
> > +	char match[MRVL_MATCH_LEN];
> > +	int ret;
> > +
> > +	snprintf(match, sizeof(match), "ppio-%d:%d",
> > +		 priv->pp_id, priv->ppio_id);
> > +	priv->ppio_params.match = match;
>
> Why this match is used, just a reminder that match is only valid for the
> scope of this function, after this function it will be invalid.
>

Keeping match locally is fine. That's used to tell MUSDK which physical
port to configure, i.e ppio-0:1 means to configure port 1 on packet
processor 0. Armada 8k has to such packet processor, while armada 7k
only one.

> <...>
>
> > +
> > +	if (rte_spinlock_trylock(&q->priv->lock) == 1) {
>
> Why getting lock in Rx data path?
>

In multi-core and multi-queue case some kind of protection is
necessary so that several cores cannot modify bpool at
the same time.

> > +		num = mrvl_get_bpool_size(bpool->pp2_id, bpool->id);
> > +
> > +		if (unlikely(num <= q->priv->bpool_min_size ||
> > +			     (!rx_done && num < q->priv->bpool_init_size))) {
> > +			ret = mrvl_fill_bpool(q, MRVL_BURST_SIZE);
> > +			if (ret)
> > +				RTE_LOG(ERR, PMD, "Failed to fill bpool\n");
> > +		} else if (unlikely(num > q->priv->bpool_max_size)) {
> > +			int i;
> > +			int pkt_to_remove = num - q->priv->bpool_init_size;
> > +			struct rte_mbuf *mbuf;
> > +			struct pp2_buff_inf buff;
> > +
> > +			RTE_LOG(DEBUG, PMD,
> > +				"\nport-%d:%d: bpool %d oversize - remove %d buffers (pool size: %d -> %d)\n",
> > +				bpool->pp2_id, q->priv->ppio->port_id,
> > +				bpool->id, pkt_to_remove, num,
> > +				q->priv->bpool_init_size);
> > +
> > +			for (i = 0; i < pkt_to_remove; i++) {
> > +				pp2_bpool_get_buff(hifs[core_id], bpool, &buff);
> > +				mbuf = (struct rte_mbuf *)
> > +					(cookie_addr_high | buff.cookie);
> > +				rte_pktmbuf_free(mbuf);
> > +			}
> > +			mrvl_port_bpool_size
> > +				[bpool->pp2_id][bpool->id][core_id] -=
> > +								pkt_to_remove;
> > +		}
> > +		rte_spinlock_unlock(&q->priv->lock);
> > +	}
> > +
> > +	return rx_done;
> > +}
>
> <...>
>
> > +	cfgnum = rte_kvargs_count(kvlist, MRVL_CFG_ARG);
> > +	if (cfgnum > 1) {
> > +		RTE_LOG(ERR, PMD, "Cannot handle more than one config file!\n");
> > +		goto out_free_kvlist;
> > +	} else if (cfgnum == 1) {
> > +		rte_kvargs_process(kvlist, MRVL_CFG_ARG,
> > +				   mrvl_get_qoscfg, &mrvl_qos_cfg);
>
> Is the expected format/contect of the config file documented? How one
> can know how to create a config file?
>

Right, documentation is missing for that. Will add in v4.

> > +	}
> > +
> > +	/*
> > +	 * ret == -EEXIST is correct, it means DMA
> > +	 * has been already initialized (by another PMD).
> > +	 */
> > +	ret = mv_sys_dma_mem_init(RTE_MRVL_MUSDK_DMA_MEMSIZE);
> > +	if (ret < 0 && ret != -EEXIST)
> > +		goto out_free_kvlist;
> > +
> > +	ret = mrvl_init_pp2();
> > +	if (ret) {
> > +		RTE_LOG(ERR, PMD, "Failed to init PP!\n");
> > +		goto out_deinit_dma;
> > +	}
> > +
> > +	ret = mrvl_init_hifs();
> > +	if (ret)
> > +		goto out_deinit_hifs;
> > +
> > +	for (i = 0; i < ifnum; i++) {
> > +		RTE_LOG(INFO, PMD, "Creating %s\n", ifnames[i]);
> > +		ret = mrvl_eth_dev_create(vdev, ifnames[i]);
>
> So you are supporting multiple ethdev devices created by single vdev
> device, by providing multiple "iface" argument in device args.
>
> This will cause eal create single virtual device but driver create
> multiple ethdev devices. I don't see direct problem with this but lets
> think about it.
> This can be problem if you want to provide ethdev specific device
> arguments. Perhaps that is why you need to provide a config file ?
>
> It can be an option to define each ethdev with:
> "--vdev net_mrvl0,iface=xx0,config=yy0 --vdev
> net_mrlv1,iface=xx1,config=yy1 ..."
>
> This may remove your dependecy to librte_cfgfile.
>

Currently there's not need to passing separate options to each created
device. As for configuration file it handles all devices at once.

> > +		if (ret)
> > +			goto out_cleanup;
> > +	}
> > +
> > +	rte_kvargs_free(kvlist);
> > +
> > +	memset(mrvl_port_bpool_size, 0, sizeof(mrvl_port_bpool_size));
> > +
> > +	mrvl_lcore_first = RTE_MAX_LCORE;
> > +	mrvl_lcore_last = 0;
> > +
> > +	RTE_LCORE_FOREACH(core_id) {
> > +		mrvl_set_first_last_cores(core_id);
>
> This sets limits of core_id. Why you need to know this in PMD level?

It's just to limit number of entries in mrvl_port_bpool_size we iterate
over every time we want to count the total number of buffers in the
hardware buffer pool.

>
> <...>
>

--
- Tomasz Duszyński

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

* Re: [PATCH v3 2/4] net/mrvl: add mrvl net pmd driver
  2017-10-04  8:59           ` Tomasz Duszynski
@ 2017-10-04 16:59             ` Ferruh Yigit
  2017-10-05  8:43               ` Tomasz Duszynski
  0 siblings, 1 reply; 110+ messages in thread
From: Ferruh Yigit @ 2017-10-04 16:59 UTC (permalink / raw)
  To: Tomasz Duszynski; +Cc: dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On 10/4/2017 9:59 AM, Tomasz Duszynski wrote:
> On Wed, Oct 04, 2017 at 01:24:27AM +0100, Ferruh Yigit wrote:
>> On 10/3/2017 12:51 PM, Tomasz Duszynski wrote:
>>> Add support for the Marvell PPv2 (Packet Processor v2) 1/10 Gbps adapter.
>>> Driver is based on external, publicly available, light-weight Marvell
>>> MUSDK library that provides access to network packet processor.
>>>
>>> Driver comes with support for the following features:
>>>
>>> * Speed capabilities
>>> * Link status
>>> * Queue start/stop
>>> * MTU update
>>> * Jumbo frame
>>> * Promiscuous mode
>>> * Allmulticast mode
>>> * Unicast MAC filter
>>> * Multicast MAC filter
>>> * RSS hash
>>> * VLAN filter
>>> * CRC offload
>>> * L3 checksum offload
>>> * L4 checksum offload
>>> * Packet type parsing
>>> * Basic stats
>>> * Stats per queue
>>
>> I have more detailed comments but in high level,
>> what do you think splitting this patch into three patches:
>> - Skeleton
>> - Add Rx/Tx support
>> - Add features, like MTU update or Promiscuous etc.. support
> If it's how submission process works then I think you left me with no
> other option than splitting driver into nice patchset :). 

No, there is no defined submission process.

> On the other
> hand driver is really a wrapper to MUSDK library and thus quite easy to
> follow. What are the benefits of such 3-way split?

To help others review/understand your code. Big code chunks are scary
and I believe most of details gets lost in big code chunks.

When someone from community wants to understand and update/improve/fix
your code, to help them by logically split the code that their focus can
go into more narrow part.

But this also means some effort in your side, so some kind of balance is
required.

I think splitting patch into smaller logical part is helpful for others,
what do you think, is it too much effort?

>>
>>>
>>> Driver was engineered cooperatively by Semihalf and Marvell teams.
>>>
>>> Semihalf:
>>> Jacek Siuda <jck@semihalf.com>
>>> Tomasz Duszynski <tdu@semihalf.com>
>>>
>>> Marvell:
>>> Dmitri Epshtein <dima@marvell.com>
>>> Natalie Samsonov <nsamsono@marvell.com>
>>>
>>> Signed-off-by: Jacek Siuda <jck@semihalf.com>
>>> Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
>>
>> <...>
>>
>>> +static struct rte_vdev_driver pmd_mrvl_drv = {
>>> +	.probe = rte_pmd_mrvl_probe,
>>> +	.remove = rte_pmd_mrvl_remove,
>>> +};
>>> +
>>> +RTE_PMD_REGISTER_VDEV(net_mrvl, pmd_mrvl_drv);
>>
>> Please help me understand.
>>
>> This driver implemented as virtual driver, because:
>> With the help of custom kernel modules, musdk library already provides
>> userspace datapath support. This PMD is an interface to musdk library.
>> Is this correct?
> That is right. Another reason this NIC is not PCI device.

We support more bus now :). Out of curiosity, which bus is device on?

>>
>> If so, just thinking loud:
>> - Why not implement this PMD directly on top of kernel interface,
>> removing musdk layer completely?
>> - How big problem that this PMD depends on custom kernel code?
> I think the main reason is that MUSDK is already used in different projects.
> Keeping multiple codebases offering similar functionality would be quite
> demanding in terms of extra work needed.
>> - How library and custom kernel code delivered? For which platforms?
> Kernel and library sources are hosted on publicly available repository.

I guess it would be nice to highlight custom kernel with external
patches is required. This is not mentioned in "Prerequisites" section of
the document.

> Driver was tested on Armada 7k/8k SoCs.

Can you please provide link to the HW mentioned in documentation?

>>
>> <....>
>>
> 
> --
> - Tomasz Duszyński
> 

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

* Re: [PATCH v3 2/4] net/mrvl: add mrvl net pmd driver
  2017-10-04 16:59             ` Ferruh Yigit
@ 2017-10-05  8:43               ` Tomasz Duszynski
  2017-10-05 17:29                 ` Ferruh Yigit
  2017-10-10 21:25                 ` Thomas Monjalon
  0 siblings, 2 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-05  8:43 UTC (permalink / raw)
  To: Ferruh Yigit
  Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On Wed, Oct 04, 2017 at 05:59:11PM +0100, Ferruh Yigit wrote:
> On 10/4/2017 9:59 AM, Tomasz Duszynski wrote:
> > On Wed, Oct 04, 2017 at 01:24:27AM +0100, Ferruh Yigit wrote:
> >> On 10/3/2017 12:51 PM, Tomasz Duszynski wrote:
> >>> Add support for the Marvell PPv2 (Packet Processor v2) 1/10 Gbps adapter.
> >>> Driver is based on external, publicly available, light-weight Marvell
> >>> MUSDK library that provides access to network packet processor.
> >>>
> >>> Driver comes with support for the following features:
> >>>
> >>> * Speed capabilities
> >>> * Link status
> >>> * Queue start/stop
> >>> * MTU update
> >>> * Jumbo frame
> >>> * Promiscuous mode
> >>> * Allmulticast mode
> >>> * Unicast MAC filter
> >>> * Multicast MAC filter
> >>> * RSS hash
> >>> * VLAN filter
> >>> * CRC offload
> >>> * L3 checksum offload
> >>> * L4 checksum offload
> >>> * Packet type parsing
> >>> * Basic stats
> >>> * Stats per queue
> >>
> >> I have more detailed comments but in high level,
> >> what do you think splitting this patch into three patches:
> >> - Skeleton
> >> - Add Rx/Tx support
> >> - Add features, like MTU update or Promiscuous etc.. support
> > If it's how submission process works then I think you left me with no
> > other option than splitting driver into nice patchset :).
>
> No, there is no defined submission process.
>
> > On the other
> > hand driver is really a wrapper to MUSDK library and thus quite easy to
> > follow. What are the benefits of such 3-way split?
>
> To help others review/understand your code. Big code chunks are scary
> and I believe most of details gets lost in big code chunks.
>
> When someone from community wants to understand and update/improve/fix
> your code, to help them by logically split the code that their focus can
> go into more narrow part.
>
> But this also means some effort in your side, so some kind of balance is
> required.
>
> I think splitting patch into smaller logical part is helpful for others,
> what do you think, is it too much effort?
>

Fair enough. I'll split the driver as suggested. A few specific
questions about functionality each patch should contain though.

As for skeleton, I see others just put driver probing here.

As for Rx/Tx support it seems that there's no common pattern.
Functionality like starting/stopping device, queues configuration
and all the other things related to Rx/Tx should be here as well?

What's left are features which go into features-patch.

> >>
> >>>
> >>> Driver was engineered cooperatively by Semihalf and Marvell teams.
> >>>
> >>> Semihalf:
> >>> Jacek Siuda <jck@semihalf.com>
> >>> Tomasz Duszynski <tdu@semihalf.com>
> >>>
> >>> Marvell:
> >>> Dmitri Epshtein <dima@marvell.com>
> >>> Natalie Samsonov <nsamsono@marvell.com>
> >>>
> >>> Signed-off-by: Jacek Siuda <jck@semihalf.com>
> >>> Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
> >>
> >> <...>
> >>
> >>> +static struct rte_vdev_driver pmd_mrvl_drv = {
> >>> +	.probe = rte_pmd_mrvl_probe,
> >>> +	.remove = rte_pmd_mrvl_remove,
> >>> +};
> >>> +
> >>> +RTE_PMD_REGISTER_VDEV(net_mrvl, pmd_mrvl_drv);
> >>
> >> Please help me understand.
> >>
> >> This driver implemented as virtual driver, because:
> >> With the help of custom kernel modules, musdk library already provides
> >> userspace datapath support. This PMD is an interface to musdk library.
> >> Is this correct?
> > That is right. Another reason this NIC is not PCI device.
>
> We support more bus now :). Out of curiosity, which bus is device on?

Bus is called Aurora2. That's proprietary SoC interconnect fabric.

>
> >>
> >> If so, just thinking loud:
> >> - Why not implement this PMD directly on top of kernel interface,
> >> removing musdk layer completely?
> >> - How big problem that this PMD depends on custom kernel code?
> > I think the main reason is that MUSDK is already used in different projects.
> > Keeping multiple codebases offering similar functionality would be quite
> > demanding in terms of extra work needed.
> >> - How library and custom kernel code delivered? For which platforms?
> > Kernel and library sources are hosted on publicly available repository.
>
> I guess it would be nice to highlight custom kernel with external
> patches is required. This is not mentioned in "Prerequisites" section of
> the document.
>

ACK

> > Driver was tested on Armada 7k/8k SoCs.
>
> Can you please provide link to the HW mentioned in documentation?
>

You can find some info here:

https://www.marvell.com/embedded-processors/armada-70xx/
https://www.marvell.com/embedded-processors/armada-80xx/

> >>
> >> <....>
> >>
> >
> > --
> > - Tomasz Duszyński
> >
>

--
- Tomasz Duszyński

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

* Re: [PATCH v2 2/4] doc: add mrvl crypto pmd documentation
  2017-09-28 10:23   ` [PATCH v2 2/4] doc: add mrvl crypto pmd documentation Tomasz Duszynski
@ 2017-10-05 14:45     ` De Lara Guarch, Pablo
  2017-10-06  8:06       ` Tomasz Duszynski
  0 siblings, 1 reply; 110+ messages in thread
From: De Lara Guarch, Pablo @ 2017-10-05 14:45 UTC (permalink / raw)
  To: Tomasz Duszynski, dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Jacek Siuda



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Tomasz Duszynski
> Sent: Thursday, September 28, 2017 11:24 AM
> To: dev@dpdk.org
> Cc: mw@semihalf.com; dima@marvell.com; nsamsono@marvell.com;
> Jianbo.liu@linaro.org; Tomasz Duszynski <tdu@semihalf.com>; Jacek Siuda
> <jck@semihalf.com>
> Subject: [dpdk-dev] [PATCH v2 2/4] doc: add mrvl crypto pmd
> documentation
> 
> Add documentation for the MRVL CRYPTO PMD driver.

You should add the pmd in the list of device types (devtype),
In doc/guides/tools/cryptoperf.rst.

Also, you should mention this new PMD in release notes.

> 
> Signed-off-by: Jacek Siuda <jck@semihalf.com>
> Signed-off-by: Tomasz Duszynski <jck@semihalf.com>
> ---
>  doc/guides/cryptodevs/features/mrvl.ini |  42 +++++++
>  doc/guides/cryptodevs/index.rst         |   1 +
>  doc/guides/cryptodevs/mrvl.rst          | 198

...

> +++ b/doc/guides/cryptodevs/mrvl.rst
> @@ -0,0 +1,198 @@

...

> +
> +   ./l2fwd-crypto -c 0x3 --vdev=eth_mrvl,iface=eth0
> + --vdev=cryptodev_mrvl_pmd

I will make the comment also in the first patch, but you should use "crypto_mrvl".
The cryptodev_*_pmd convention is old and we are only maintaining it for backward compatibility.
So, I would use "crypto_mrvl".

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

* Re: [PATCH v2 1/4] crypto/mrvl: add mrvl crypto pmd driver
  2017-09-28 10:23   ` [PATCH v2 1/4] crypto/mrvl: add mrvl crypto " Tomasz Duszynski
@ 2017-10-05 15:01     ` De Lara Guarch, Pablo
  2017-10-06  7:24       ` Tomasz Duszynski
  2017-10-05 15:47     ` Bruce Richardson
  1 sibling, 1 reply; 110+ messages in thread
From: De Lara Guarch, Pablo @ 2017-10-05 15:01 UTC (permalink / raw)
  To: Tomasz Duszynski, dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

Hi Tomasz,

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Tomasz Duszynski
> Sent: Thursday, September 28, 2017 11:23 AM
> To: dev@dpdk.org
> Cc: mw@semihalf.com; dima@marvell.com; nsamsono@marvell.com;
> Jianbo.liu@linaro.org; Tomasz Duszynski <tdu@semihalf.com>; Jacek Siuda
> <jck@semihalf.com>
> Subject: [dpdk-dev] [PATCH v2 1/4] crypto/mrvl: add mrvl crypto pmd
> driver
> 
> Add support for the Marvell Security Crypto Accelerator EIP197.
> Driver is based on external, publicly available, Marvell MUSDK
> library that provides access to the hardware with minimum overhead
> and high performance.
> 
> Driver comes with support for the following features:
> 
> * Symmetric crypto
> * Sym operation chaining
> * AES CBC (128)
> * AES CBC (192)
> * AES CBC (256)
> * AES CTR (128)
> * AES CTR (192)
> * AES CTR (256)
> * 3DES CBC
> * 3DES CTR
> * MD5
> * MD5 HMAC
> * SHA1
> * SHA1 HMAC
> * SHA256
> * SHA256 HMAC
> * SHA384
> * SHA384 HMAC
> * SHA512
> * SHA512 HMAC
> * AES GCM (128)
> 
> Driver was engineered cooperatively by Semihalf and Marvell teams.
> 
> Semihalf:
> Jacek Siuda <jck@semihalf.com>
> Tomasz Duszynski <tdu@semihalf.com>
> 
> Marvell:
> Dmitri Epshtein <dima@marvell.com>
> Natalie Samsonov <nsamsono@marvell.com>
> 
> Signed-off-by: Jacek Siuda <jck@semihalf.com>
> Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>

If the guys in Marvell has contributed with the code,
they should sign off too. Up to you.

There is a script to test compilation (devtools/test-build.sh).
You should also modify it to include the dependency with LIBMUSDK.

...

> diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd.c
> b/drivers/crypto/mrvl/rte_mrvl_pmd.c
> new file mode 100644
> index 0000000..63f8daa
> --- /dev/null
> +++ b/drivers/crypto/mrvl/rte_mrvl_pmd.c

...

> +
> +/* Register the driver in constructor. */
> +RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_MRVL_PMD,
> cryptodev_mrvl_pmd_drv);
> +RTE_PMD_REGISTER_ALIAS(CRYPTODEV_NAME_MRVL_PMD,
> cryptodev_mrvl_pmd);

You can remove this alias, as this is a new PMD,
we should be using the primary convention "crypto_mrvl".


> +RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_MRVL_PMD,
> +	"max_nb_queue_pairs=<int> "
> +	"max_nb_sessions=<int> "
> +	"socket_id=<int>");
> +RTE_PMD_REGISTER_CRYPTO_DRIVER(cryptodev_mrvl_pmd_drv,
> cryptodev_driver_id);
> diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
> b/drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
> new file mode 100644
> index 0000000..f7374f8
> --- /dev/null
> +++ b/drivers/crypto/mrvl/rte_mrvl_pmd_ops.c

...

> + */
> +static const struct rte_cryptodev_capabilities
> +	mrvl_crypto_pmd_capabilities[] = {
> +	{	/* MD5 HMAC */
> +		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
> +		{.sym = {
> +			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
> +			{.auth = {
> +				.algo = RTE_CRYPTO_AUTH_MD5_HMAC,
> +				.block_size = 64,
> +				.key_size = {
> +					.min = 64,
> +					.max = 64,
> +					.increment = 0
> +				},
> +				.digest_size = {
> +					.min = 16,
> +					.max = 16,
> +					.increment = 0
> +				},
> +				.aad_size = { 0 }

You can remove this aad_size, as it is only applicable to AEAD algorithms (GCM in your case).

> +			}, }
> +		}, }
> +	},

...

> +	{	/* SHA1 HMAC */
> +		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
> +			{.sym = {
> +				.xform_type =
> RTE_CRYPTO_SYM_XFORM_AUTH,
> +				{.auth = {
> +					.algo =
> RTE_CRYPTO_AUTH_SHA1_HMAC,
> +					.block_size = 64,
> +					.key_size = {
> +						.min = 16,
> +						.max = 128,
> +						.increment = 0

If min and max values are different, increment cannot be 0.

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

* Re: [PATCH v2 1/4] crypto/mrvl: add mrvl crypto pmd driver
  2017-09-28 10:23   ` [PATCH v2 1/4] crypto/mrvl: add mrvl crypto " Tomasz Duszynski
  2017-10-05 15:01     ` De Lara Guarch, Pablo
@ 2017-10-05 15:47     ` Bruce Richardson
  2017-10-06  7:05       ` Tomasz Duszynski
  1 sibling, 1 reply; 110+ messages in thread
From: Bruce Richardson @ 2017-10-05 15:47 UTC (permalink / raw)
  To: Tomasz Duszynski; +Cc: dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On Thu, Sep 28, 2017 at 12:23:29PM +0200, Tomasz Duszynski wrote:
> Add support for the Marvell Security Crypto Accelerator EIP197.
> Driver is based on external, publicly available, Marvell MUSDK
> library that provides access to the hardware with minimum overhead
> and high performance.
> 
> Driver comes with support for the following features:
> 
> * Symmetric crypto
> * Sym operation chaining
> * AES CBC (128)
> * AES CBC (192)
> * AES CBC (256)
> * AES CTR (128)
> * AES CTR (192)
> * AES CTR (256)
> * 3DES CBC
> * 3DES CTR
> * MD5
> * MD5 HMAC
> * SHA1
> * SHA1 HMAC
> * SHA256
> * SHA256 HMAC
> * SHA384
> * SHA384 HMAC
> * SHA512
> * SHA512 HMAC
> * AES GCM (128)
> 
> Driver was engineered cooperatively by Semihalf and Marvell teams.
> 
> Semihalf:
> Jacek Siuda <jck@semihalf.com>
> Tomasz Duszynski <tdu@semihalf.com>
> 
> Marvell:
> Dmitri Epshtein <dima@marvell.com>
> Natalie Samsonov <nsamsono@marvell.com>
> 
> Signed-off-by: Jacek Siuda <jck@semihalf.com>
> Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
> ---
>  config/common_base                           |   6 +
>  drivers/crypto/Makefile                      |   2 +
>  drivers/crypto/mrvl/Makefile                 |  63 ++
>  drivers/crypto/mrvl/rte_mrvl_compat.h        |  48 ++
>  drivers/crypto/mrvl/rte_mrvl_pmd.c           | 870 +++++++++++++++++++++++++++
>  drivers/crypto/mrvl/rte_mrvl_pmd_ops.c       | 787 ++++++++++++++++++++++++
>  drivers/crypto/mrvl/rte_mrvl_pmd_private.h   | 121 ++++
>  drivers/crypto/mrvl/rte_mrvl_pmd_version.map |   3 +

The standard convention for naming version files for these drivers is
"rte_pmd_<name>_version.map". Without this, the new meson build system
will have trouble finding the map file. The same convention applies to
net drivers too.

Regards,
/Bruce

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

* Re: [PATCH v3 2/4] net/mrvl: add mrvl net pmd driver
  2017-10-05  8:43               ` Tomasz Duszynski
@ 2017-10-05 17:29                 ` Ferruh Yigit
  2017-10-06  6:41                   ` Tomasz Duszynski
  2017-10-10 21:25                 ` Thomas Monjalon
  1 sibling, 1 reply; 110+ messages in thread
From: Ferruh Yigit @ 2017-10-05 17:29 UTC (permalink / raw)
  To: Tomasz Duszynski; +Cc: dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On 10/5/2017 9:43 AM, Tomasz Duszynski wrote:
> On Wed, Oct 04, 2017 at 05:59:11PM +0100, Ferruh Yigit wrote:
>> On 10/4/2017 9:59 AM, Tomasz Duszynski wrote:
>>> On Wed, Oct 04, 2017 at 01:24:27AM +0100, Ferruh Yigit wrote:
>>>> On 10/3/2017 12:51 PM, Tomasz Duszynski wrote:
>>>>> Add support for the Marvell PPv2 (Packet Processor v2) 1/10 Gbps adapter.
>>>>> Driver is based on external, publicly available, light-weight Marvell
>>>>> MUSDK library that provides access to network packet processor.
>>>>>
>>>>> Driver comes with support for the following features:
>>>>>
>>>>> * Speed capabilities
>>>>> * Link status
>>>>> * Queue start/stop
>>>>> * MTU update
>>>>> * Jumbo frame
>>>>> * Promiscuous mode
>>>>> * Allmulticast mode
>>>>> * Unicast MAC filter
>>>>> * Multicast MAC filter
>>>>> * RSS hash
>>>>> * VLAN filter
>>>>> * CRC offload
>>>>> * L3 checksum offload
>>>>> * L4 checksum offload
>>>>> * Packet type parsing
>>>>> * Basic stats
>>>>> * Stats per queue
>>>>
>>>> I have more detailed comments but in high level,
>>>> what do you think splitting this patch into three patches:
>>>> - Skeleton
>>>> - Add Rx/Tx support
>>>> - Add features, like MTU update or Promiscuous etc.. support
>>> If it's how submission process works then I think you left me with no
>>> other option than splitting driver into nice patchset :).
>>
>> No, there is no defined submission process.
>>
>>> On the other
>>> hand driver is really a wrapper to MUSDK library and thus quite easy to
>>> follow. What are the benefits of such 3-way split?
>>
>> To help others review/understand your code. Big code chunks are scary
>> and I believe most of details gets lost in big code chunks.
>>
>> When someone from community wants to understand and update/improve/fix
>> your code, to help them by logically split the code that their focus can
>> go into more narrow part.
>>
>> But this also means some effort in your side, so some kind of balance is
>> required.
>>
>> I think splitting patch into smaller logical part is helpful for others,
>> what do you think, is it too much effort?
>>
> 
> Fair enough. I'll split the driver as suggested. A few specific
> questions about functionality each patch should contain though.
> 
> As for skeleton, I see others just put driver probing here.
> 
> As for Rx/Tx support it seems that there's no common pattern.
> Functionality like starting/stopping device, queues configuration
> and all the other things related to Rx/Tx should be here as well?

As you said there is no common pattern, but I think starting/stopping
device, queues configuration can go into skeleton and mainly Rx/Tx burst
functions can go into Rx/Tx patch.
But please what you think more reasonable matters here.

> 
> What's left are features which go into features-patch.

Yes.
And the .ini file, currently part of doc patch, can be part of this
features patch, it is helps more to see the code add feature and doc
documents it in same patch.

> 
>>>>
>>>>>
>>>>> Driver was engineered cooperatively by Semihalf and Marvell teams.
>>>>>
>>>>> Semihalf:
>>>>> Jacek Siuda <jck@semihalf.com>
>>>>> Tomasz Duszynski <tdu@semihalf.com>
>>>>>
>>>>> Marvell:
>>>>> Dmitri Epshtein <dima@marvell.com>
>>>>> Natalie Samsonov <nsamsono@marvell.com>
>>>>>
>>>>> Signed-off-by: Jacek Siuda <jck@semihalf.com>
>>>>> Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
>>>>
>>>> <...>
>>>>
>>>>> +static struct rte_vdev_driver pmd_mrvl_drv = {
>>>>> +	.probe = rte_pmd_mrvl_probe,
>>>>> +	.remove = rte_pmd_mrvl_remove,
>>>>> +};
>>>>> +
>>>>> +RTE_PMD_REGISTER_VDEV(net_mrvl, pmd_mrvl_drv);
>>>>
>>>> Please help me understand.
>>>>
>>>> This driver implemented as virtual driver, because:
>>>> With the help of custom kernel modules, musdk library already provides
>>>> userspace datapath support. This PMD is an interface to musdk library.
>>>> Is this correct?
>>> That is right. Another reason this NIC is not PCI device.
>>
>> We support more bus now :). Out of curiosity, which bus is device on?
> 
> Bus is called Aurora2. That's proprietary SoC interconnect fabric.
> 
>>
>>>>
>>>> If so, just thinking loud:
>>>> - Why not implement this PMD directly on top of kernel interface,
>>>> removing musdk layer completely?
>>>> - How big problem that this PMD depends on custom kernel code?
>>> I think the main reason is that MUSDK is already used in different projects.
>>> Keeping multiple codebases offering similar functionality would be quite
>>> demanding in terms of extra work needed.
>>>> - How library and custom kernel code delivered? For which platforms?
>>> Kernel and library sources are hosted on publicly available repository.
>>
>> I guess it would be nice to highlight custom kernel with external
>> patches is required. This is not mentioned in "Prerequisites" section of
>> the document.
>>
> 
> ACK
> 
>>> Driver was tested on Armada 7k/8k SoCs.
>>
>> Can you please provide link to the HW mentioned in documentation?
>>
> 
> You can find some info here:
> 
> https://www.marvell.com/embedded-processors/armada-70xx/
> https://www.marvell.com/embedded-processors/armada-80xx/

Thanks, would you mind putting these links into driver documentation as
well?

> 
>>>>
>>>> <....>
>>>>
>>>
>>> --
>>> - Tomasz Duszyński
>>>
>>
> 
> --
> - Tomasz Duszyński
> 

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

* Re: [PATCH v3 2/4] net/mrvl: add mrvl net pmd driver
  2017-10-04 13:19           ` Tomasz Duszynski
@ 2017-10-05 17:37             ` Ferruh Yigit
  0 siblings, 0 replies; 110+ messages in thread
From: Ferruh Yigit @ 2017-10-05 17:37 UTC (permalink / raw)
  To: Tomasz Duszynski; +Cc: dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On 10/4/2017 2:19 PM, Tomasz Duszynski wrote:
> On Wed, Oct 04, 2017 at 01:28:47AM +0100, Ferruh Yigit wrote:
>> On 10/3/2017 12:51 PM, Tomasz Duszynski wrote:
>>> Add support for the Marvell PPv2 (Packet Processor v2) 1/10 Gbps adapter.
>>> Driver is based on external, publicly available, light-weight Marvell
>>> MUSDK library that provides access to network packet processor.
>>>
>>> Driver comes with support for the following features:
>>>
>>> * Speed capabilities
>>> * Link status
>>> * Queue start/stop
>>> * MTU update
>>> * Jumbo frame
>>> * Promiscuous mode
>>> * Allmulticast mode
>>> * Unicast MAC filter
>>> * Multicast MAC filter
>>> * RSS hash
>>> * VLAN filter
>>> * CRC offload
>>> * L3 checksum offload
>>> * L4 checksum offload
>>> * Packet type parsing
>>> * Basic stats
>>> * Stats per queue
>>>
>>> Driver was engineered cooperatively by Semihalf and Marvell teams.
>>>
>>> Semihalf:
>>> Jacek Siuda <jck@semihalf.com>
>>> Tomasz Duszynski <tdu@semihalf.com>
>>>
>>> Marvell:
>>> Dmitri Epshtein <dima@marvell.com>
>>> Natalie Samsonov <nsamsono@marvell.com>
>>>
>>> Signed-off-by: Jacek Siuda <jck@semihalf.com>
>>> Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
>>
>> <...>
>>
>>> +++ b/config/common_base
>>> @@ -262,6 +262,13 @@ CONFIG_RTE_LIBRTE_NFP_PMD=n
>>>  CONFIG_RTE_LIBRTE_NFP_DEBUG=n
>>>
>>>  #
>>> +# Compile Marvell PMD driver
>>> +#
>>> +CONFIG_RTE_LIBRTE_MRVL_PMD=n
>>> +CONFIG_RTE_LIBRTE_MRVL_DEBUG=n
>>> +CONFIG_RTE_MRVL_MUSDK_DMA_MEMSIZE=41943040
>>
>> Is dma memsize needs to be a configuration option?
> 
> That config option is used both by NET and CRYPTO drivers. In case NET
> and CRYPTO are used together i.e ipsec-secgw then DMA_MEMSIZE must be
> the set to the same size. Putting this configuration option in .config
> makes sure DMA_MEMSIZE stays synchronized.

OK.

> 
>>
>> <...>
>>
>>> +include $(RTE_SDK)/mk/rte.vars.mk
>>> +
>>> +ifneq ($(MAKECMDGOALS),clean)
>>> +ifneq ($(MAKECMDGOALS),config)
>>> +ifeq ($(LIBMUSDK_PATH),)
>>> +$(error "Please define LIBMUSDK_PATH environment variable")
>>
>> Not sure how to resolve this dependency.
>> What do you think adding this as configuration option?
> 
> All other drivers with external dependencies follow the same approach.
> 
>>
>> Or DPDK just adds the -lmusdk external dependency and while compiling
>> for marvel EXTRA_LDFLAGS parameter should be pass with
>> "-L$(LIBMUSDK_PATH)" and this can be documented in marvel doc. What do
>> you think?
> 
> Both solutions are reasonable. The former was chosen because that's what the
> other drivers do.

OK.

> 
>>
>>> +endif
>>> +ifeq ($(CONFIG_RTE_LIBRTE_CFGFILE),n)
>>> +$(error "RTE_LIBRTE_CFGFILE must be enabled in configuration!")
>>
>> This can be also handled in drivers/net/Makefile, it can be possible to
>> add check there for LIBRTE_CFGFILE dependency.
>>
> 
> ACK
> 
>>> +endif
>>> +endif
>>> +endif
>>> +
>>> +# library name
>>> +LIB = librte_pmd_mrvl.a
>>> +
>>> +# library version
>>> +LIBABIVER := 1
>>> +
>>> +# versioning export map
>>> +EXPORT_MAP := rte_pmd_mrvl_version.map
>>> +
>>> +# external library dependencies
>>> +CFLAGS += -I$(LIBMUSDK_PATH)/include
>>> +CFLAGS += -DMVCONF_ARCH_DMA_ADDR_T_64BIT
>>> +CFLAGS += -DCONF_PP2_BPOOL_COOKIE_SIZE=32
>>> +CFLAGS += $(WERROR_FLAGS)
>>> +CFLAGS += -O3
>>> +LDLIBS += -L$(LIBMUSDK_PATH)/lib
>>
>> This can be LDFLAGS instead of LDLIBS
> 
> Moving that to LDFLAGS will break compilation in case
> CONFIG_RTE_BUILD_SHARED_LIB is set as -L... does not show up on command
> line thus linker does not know where to look extra library up.
> I may be wrong but it looks as if specifying LDFLAGS in driver's
> Makefile is no-op.

I would expect LDFLAGS will work, but if it is breaking the build,
please keep as it is, we can check and fix this later.

> 
> On the other hand, if we are building static libraries both
> -lmusdk and -L$(LIBMUSDK_PATH)/lib are added to specific _LDLIBS which in turn
> ends up in LDLIBS.
> 
>>
>>> +LDLIBS += -lmusdk
>>> +
>>> +# library source files
>>> +SRCS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl_ethdev.c
>>> +SRCS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl_qos.c
>>> +
>>> +# library dependencies
>>> +DEPDIRS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += lib/librte_cfgfile
>>
>> These variables no more used, you can drop this. drivers/net/Makefile
>> used for this, you are already updating that file, librte_cfgfile needs
>> to be added there.
>>
> 
> ACK
> 
>>> +
>>> +include $(RTE_SDK)/mk/rte.lib.mk
>>
>> <...>
>>
>>> +/*
>>> + * To use buffer harvesting based on loopback port shadow queue structure
>>> + * was introduced for buffers information bookkeeping.
>>> + *
>>> + * Before sending the packet, related buffer information (pp2_buff_inf) is
>>> + * stored in shadow queue. After packet is transmitted no longer used
>>> + * packet buffer is released back to it's original hardware pool,
>>> + * on condition it originated from interface.
>>> + * In case it  was generated by application itself i.e: mbuf->port field is
>>> + * 0xff then its released to software mempool.
>>
>> You already explained here but can you please give more details why
>> shadow queue needed?
> 
> It's used for mbuf harvesting in tx-path. Instead of releasing pushed
> out mbuf to mempool and allocating it once again later on, mbuf is
> stored in the shadow queue and returned back to hardware buffer manager
> after being sent.
> 
>>
>>> + */
>>> +struct mrvl_shadow_txq {
>>> +	int head;           /* write index - used when sending buffers */
>>> +	int tail;           /* read index - used when releasing buffers */
>>> +	u16 size;           /* queue occupied size */
>>> +	u16 num_to_release; /* number of buffers sent, that can be released */
>>> +	struct buff_release_entry ent[MRVL_PP2_TX_SHADOWQ_SIZE]; /* q entries */
>>> +};
>>> +
>>> +struct mrvl_rxq {
>>> +	struct mrvl_priv *priv;
>>> +	struct rte_mempool *mp;
>>> +	int queue_id;
>>> +	int port_id;
>>> +	int cksum_enabled;
>>> +	uint64_t bytes_recv;
>>> +	uint64_t drop_mac;
>>> +};
>>> +
>>> +struct mrvl_txq {
>>> +	struct mrvl_priv *priv;
>>> +	int queue_id;
>>> +	int port_id;
>>> +	uint64_t bytes_sent;
>>> +};
>>> +
>>
>> <...>
>>
>>> +static int
>>> +mrvl_dev_start(struct rte_eth_dev *dev)
>>> +{
>>> +	struct mrvl_priv *priv = dev->data->dev_private;
>>> +	char match[MRVL_MATCH_LEN];
>>> +	int ret;
>>> +
>>> +	snprintf(match, sizeof(match), "ppio-%d:%d",
>>> +		 priv->pp_id, priv->ppio_id);
>>> +	priv->ppio_params.match = match;
>>
>> Why this match is used, just a reminder that match is only valid for the
>> scope of this function, after this function it will be invalid.
>>
> 
> Keeping match locally is fine. That's used to tell MUSDK which physical
> port to configure, i.e ppio-0:1 means to configure port 1 on packet
> processor 0. Armada 8k has to such packet processor, while armada 7k
> only one.

Ok, thanks for clarification.

> 
>> <...>
>>
>>> +
>>> +	if (rte_spinlock_trylock(&q->priv->lock) == 1) {
>>
>> Why getting lock in Rx data path?
>>
> 
> In multi-core and multi-queue case some kind of protection is
> necessary so that several cores cannot modify bpool at
> the same time.
> 
>>> +		num = mrvl_get_bpool_size(bpool->pp2_id, bpool->id);
>>> +
>>> +		if (unlikely(num <= q->priv->bpool_min_size ||
>>> +			     (!rx_done && num < q->priv->bpool_init_size))) {
>>> +			ret = mrvl_fill_bpool(q, MRVL_BURST_SIZE);
>>> +			if (ret)
>>> +				RTE_LOG(ERR, PMD, "Failed to fill bpool\n");
>>> +		} else if (unlikely(num > q->priv->bpool_max_size)) {
>>> +			int i;
>>> +			int pkt_to_remove = num - q->priv->bpool_init_size;
>>> +			struct rte_mbuf *mbuf;
>>> +			struct pp2_buff_inf buff;
>>> +
>>> +			RTE_LOG(DEBUG, PMD,
>>> +				"\nport-%d:%d: bpool %d oversize - remove %d buffers (pool size: %d -> %d)\n",
>>> +				bpool->pp2_id, q->priv->ppio->port_id,
>>> +				bpool->id, pkt_to_remove, num,
>>> +				q->priv->bpool_init_size);
>>> +
>>> +			for (i = 0; i < pkt_to_remove; i++) {
>>> +				pp2_bpool_get_buff(hifs[core_id], bpool, &buff);
>>> +				mbuf = (struct rte_mbuf *)
>>> +					(cookie_addr_high | buff.cookie);
>>> +				rte_pktmbuf_free(mbuf);
>>> +			}
>>> +			mrvl_port_bpool_size
>>> +				[bpool->pp2_id][bpool->id][core_id] -=
>>> +								pkt_to_remove;
>>> +		}
>>> +		rte_spinlock_unlock(&q->priv->lock);
>>> +	}
>>> +
>>> +	return rx_done;
>>> +}
>>
>> <...>
>>
>>> +	cfgnum = rte_kvargs_count(kvlist, MRVL_CFG_ARG);
>>> +	if (cfgnum > 1) {
>>> +		RTE_LOG(ERR, PMD, "Cannot handle more than one config file!\n");
>>> +		goto out_free_kvlist;
>>> +	} else if (cfgnum == 1) {
>>> +		rte_kvargs_process(kvlist, MRVL_CFG_ARG,
>>> +				   mrvl_get_qoscfg, &mrvl_qos_cfg);
>>
>> Is the expected format/contect of the config file documented? How one
>> can know how to create a config file?
>>
> 
> Right, documentation is missing for that. Will add in v4.
> 
>>> +	}
>>> +
>>> +	/*
>>> +	 * ret == -EEXIST is correct, it means DMA
>>> +	 * has been already initialized (by another PMD).
>>> +	 */
>>> +	ret = mv_sys_dma_mem_init(RTE_MRVL_MUSDK_DMA_MEMSIZE);
>>> +	if (ret < 0 && ret != -EEXIST)
>>> +		goto out_free_kvlist;
>>> +
>>> +	ret = mrvl_init_pp2();
>>> +	if (ret) {
>>> +		RTE_LOG(ERR, PMD, "Failed to init PP!\n");
>>> +		goto out_deinit_dma;
>>> +	}
>>> +
>>> +	ret = mrvl_init_hifs();
>>> +	if (ret)
>>> +		goto out_deinit_hifs;
>>> +
>>> +	for (i = 0; i < ifnum; i++) {
>>> +		RTE_LOG(INFO, PMD, "Creating %s\n", ifnames[i]);
>>> +		ret = mrvl_eth_dev_create(vdev, ifnames[i]);
>>
>> So you are supporting multiple ethdev devices created by single vdev
>> device, by providing multiple "iface" argument in device args.
>>
>> This will cause eal create single virtual device but driver create
>> multiple ethdev devices. I don't see direct problem with this but lets
>> think about it.
>> This can be problem if you want to provide ethdev specific device
>> arguments. Perhaps that is why you need to provide a config file ?
>>
>> It can be an option to define each ethdev with:
>> "--vdev net_mrvl0,iface=xx0,config=yy0 --vdev
>> net_mrlv1,iface=xx1,config=yy1 ..."
>>
>> This may remove your dependecy to librte_cfgfile.
>>
> 
> Currently there's not need to passing separate options to each created
> device. As for configuration file it handles all devices at once.

Ok, that was an option...

> 
>>> +		if (ret)
>>> +			goto out_cleanup;
>>> +	}
>>> +
>>> +	rte_kvargs_free(kvlist);
>>> +
>>> +	memset(mrvl_port_bpool_size, 0, sizeof(mrvl_port_bpool_size));
>>> +
>>> +	mrvl_lcore_first = RTE_MAX_LCORE;
>>> +	mrvl_lcore_last = 0;
>>> +
>>> +	RTE_LCORE_FOREACH(core_id) {
>>> +		mrvl_set_first_last_cores(core_id);
>>
>> This sets limits of core_id. Why you need to know this in PMD level?
> 
> It's just to limit number of entries in mrvl_port_bpool_size we iterate
> over every time we want to count the total number of buffers in the
> hardware buffer pool.
> 
>>
>> <...>
>>
> 
> --
> - Tomasz Duszyński
> 

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

* Re: [PATCH v3 2/4] net/mrvl: add mrvl net pmd driver
  2017-10-05 17:29                 ` Ferruh Yigit
@ 2017-10-06  6:41                   ` Tomasz Duszynski
  0 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-06  6:41 UTC (permalink / raw)
  To: Ferruh Yigit
  Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On Thu, Oct 05, 2017 at 06:29:12PM +0100, Ferruh Yigit wrote:
> On 10/5/2017 9:43 AM, Tomasz Duszynski wrote:
> > On Wed, Oct 04, 2017 at 05:59:11PM +0100, Ferruh Yigit wrote:
> >> On 10/4/2017 9:59 AM, Tomasz Duszynski wrote:
> >>> On Wed, Oct 04, 2017 at 01:24:27AM +0100, Ferruh Yigit wrote:
> >>>> On 10/3/2017 12:51 PM, Tomasz Duszynski wrote:
> >>>>> Add support for the Marvell PPv2 (Packet Processor v2) 1/10 Gbps adapter.
> >>>>> Driver is based on external, publicly available, light-weight Marvell
> >>>>> MUSDK library that provides access to network packet processor.
> >>>>>
> >>>>> Driver comes with support for the following features:
> >>>>>
> >>>>> * Speed capabilities
> >>>>> * Link status
> >>>>> * Queue start/stop
> >>>>> * MTU update
> >>>>> * Jumbo frame
> >>>>> * Promiscuous mode
> >>>>> * Allmulticast mode
> >>>>> * Unicast MAC filter
> >>>>> * Multicast MAC filter
> >>>>> * RSS hash
> >>>>> * VLAN filter
> >>>>> * CRC offload
> >>>>> * L3 checksum offload
> >>>>> * L4 checksum offload
> >>>>> * Packet type parsing
> >>>>> * Basic stats
> >>>>> * Stats per queue
> >>>>
> >>>> I have more detailed comments but in high level,
> >>>> what do you think splitting this patch into three patches:
> >>>> - Skeleton
> >>>> - Add Rx/Tx support
> >>>> - Add features, like MTU update or Promiscuous etc.. support
> >>> If it's how submission process works then I think you left me with no
> >>> other option than splitting driver into nice patchset :).
> >>
> >> No, there is no defined submission process.
> >>
> >>> On the other
> >>> hand driver is really a wrapper to MUSDK library and thus quite easy to
> >>> follow. What are the benefits of such 3-way split?
> >>
> >> To help others review/understand your code. Big code chunks are scary
> >> and I believe most of details gets lost in big code chunks.
> >>
> >> When someone from community wants to understand and update/improve/fix
> >> your code, to help them by logically split the code that their focus can
> >> go into more narrow part.
> >>
> >> But this also means some effort in your side, so some kind of balance is
> >> required.
> >>
> >> I think splitting patch into smaller logical part is helpful for others,
> >> what do you think, is it too much effort?
> >>
> >
> > Fair enough. I'll split the driver as suggested. A few specific
> > questions about functionality each patch should contain though.
> >
> > As for skeleton, I see others just put driver probing here.
> >
> > As for Rx/Tx support it seems that there's no common pattern.
> > Functionality like starting/stopping device, queues configuration
> > and all the other things related to Rx/Tx should be here as well?
>
> As you said there is no common pattern, but I think starting/stopping
> device, queues configuration can go into skeleton and mainly Rx/Tx burst
> functions can go into Rx/Tx patch.
> But please what you think more reasonable matters here.
>

ACK

> >
> > What's left are features which go into features-patch.
>
> Yes.
> And the .ini file, currently part of doc patch, can be part of this
> features patch, it is helps more to see the code add feature and doc
> documents it in same patch.
>

ACK

> >
> >>>>
> >>>>>
> >>>>> Driver was engineered cooperatively by Semihalf and Marvell teams.
> >>>>>
> >>>>> Semihalf:
> >>>>> Jacek Siuda <jck@semihalf.com>
> >>>>> Tomasz Duszynski <tdu@semihalf.com>
> >>>>>
> >>>>> Marvell:
> >>>>> Dmitri Epshtein <dima@marvell.com>
> >>>>> Natalie Samsonov <nsamsono@marvell.com>
> >>>>>
> >>>>> Signed-off-by: Jacek Siuda <jck@semihalf.com>
> >>>>> Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
> >>>>
> >>>> <...>
> >>>>
> >>>>> +static struct rte_vdev_driver pmd_mrvl_drv = {
> >>>>> +	.probe = rte_pmd_mrvl_probe,
> >>>>> +	.remove = rte_pmd_mrvl_remove,
> >>>>> +};
> >>>>> +
> >>>>> +RTE_PMD_REGISTER_VDEV(net_mrvl, pmd_mrvl_drv);
> >>>>
> >>>> Please help me understand.
> >>>>
> >>>> This driver implemented as virtual driver, because:
> >>>> With the help of custom kernel modules, musdk library already provides
> >>>> userspace datapath support. This PMD is an interface to musdk library.
> >>>> Is this correct?
> >>> That is right. Another reason this NIC is not PCI device.
> >>
> >> We support more bus now :). Out of curiosity, which bus is device on?
> >
> > Bus is called Aurora2. That's proprietary SoC interconnect fabric.
> >
> >>
> >>>>
> >>>> If so, just thinking loud:
> >>>> - Why not implement this PMD directly on top of kernel interface,
> >>>> removing musdk layer completely?
> >>>> - How big problem that this PMD depends on custom kernel code?
> >>> I think the main reason is that MUSDK is already used in different projects.
> >>> Keeping multiple codebases offering similar functionality would be quite
> >>> demanding in terms of extra work needed.
> >>>> - How library and custom kernel code delivered? For which platforms?
> >>> Kernel and library sources are hosted on publicly available repository.
> >>
> >> I guess it would be nice to highlight custom kernel with external
> >> patches is required. This is not mentioned in "Prerequisites" section of
> >> the document.
> >>
> >
> > ACK
> >
> >>> Driver was tested on Armada 7k/8k SoCs.
> >>
> >> Can you please provide link to the HW mentioned in documentation?
> >>
> >
> > You can find some info here:
> >
> > https://www.marvell.com/embedded-processors/armada-70xx/
> > https://www.marvell.com/embedded-processors/armada-80xx/
>
> Thanks, would you mind putting these links into driver documentation as
> well?

ACK

>
> >
> >>>>
> >>>> <....>
> >>>>
> >>>
> >>> --
> >>> - Tomasz Duszyński
> >>>
> >>
> >
> > --
> > - Tomasz Duszyński
> >
>

--
- Tomasz Duszyński

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

* Re: [PATCH v2 1/4] crypto/mrvl: add mrvl crypto pmd driver
  2017-10-05 15:47     ` Bruce Richardson
@ 2017-10-06  7:05       ` Tomasz Duszynski
  0 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-06  7:05 UTC (permalink / raw)
  To: Bruce Richardson
  Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On Thu, Oct 05, 2017 at 04:47:37PM +0100, Bruce Richardson wrote:
> On Thu, Sep 28, 2017 at 12:23:29PM +0200, Tomasz Duszynski wrote:
> > Add support for the Marvell Security Crypto Accelerator EIP197.
> > Driver is based on external, publicly available, Marvell MUSDK
> > library that provides access to the hardware with minimum overhead
> > and high performance.
> >
> > Driver comes with support for the following features:
> >
> > * Symmetric crypto
> > * Sym operation chaining
> > * AES CBC (128)
> > * AES CBC (192)
> > * AES CBC (256)
> > * AES CTR (128)
> > * AES CTR (192)
> > * AES CTR (256)
> > * 3DES CBC
> > * 3DES CTR
> > * MD5
> > * MD5 HMAC
> > * SHA1
> > * SHA1 HMAC
> > * SHA256
> > * SHA256 HMAC
> > * SHA384
> > * SHA384 HMAC
> > * SHA512
> > * SHA512 HMAC
> > * AES GCM (128)
> >
> > Driver was engineered cooperatively by Semihalf and Marvell teams.
> >
> > Semihalf:
> > Jacek Siuda <jck@semihalf.com>
> > Tomasz Duszynski <tdu@semihalf.com>
> >
> > Marvell:
> > Dmitri Epshtein <dima@marvell.com>
> > Natalie Samsonov <nsamsono@marvell.com>
> >
> > Signed-off-by: Jacek Siuda <jck@semihalf.com>
> > Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
> > ---
> >  config/common_base                           |   6 +
> >  drivers/crypto/Makefile                      |   2 +
> >  drivers/crypto/mrvl/Makefile                 |  63 ++
> >  drivers/crypto/mrvl/rte_mrvl_compat.h        |  48 ++
> >  drivers/crypto/mrvl/rte_mrvl_pmd.c           | 870 +++++++++++++++++++++++++++
> >  drivers/crypto/mrvl/rte_mrvl_pmd_ops.c       | 787 ++++++++++++++++++++++++
> >  drivers/crypto/mrvl/rte_mrvl_pmd_private.h   | 121 ++++
> >  drivers/crypto/mrvl/rte_mrvl_pmd_version.map |   3 +
>
> The standard convention for naming version files for these drivers is
> "rte_pmd_<name>_version.map". Without this, the new meson build system
> will have trouble finding the map file. The same convention applies to
> net drivers too.
>

OK. Thanks for pointing this out.

> Regards,
> /Bruce

--
- Tomasz Duszyński

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

* Re: [PATCH v2 1/4] crypto/mrvl: add mrvl crypto pmd driver
  2017-10-05 15:01     ` De Lara Guarch, Pablo
@ 2017-10-06  7:24       ` Tomasz Duszynski
  0 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-06  7:24 UTC (permalink / raw)
  To: De Lara Guarch, Pablo
  Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On Thu, Oct 05, 2017 at 03:01:33PM +0000, De Lara Guarch, Pablo wrote:
> Hi Tomasz,
>
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Tomasz Duszynski
> > Sent: Thursday, September 28, 2017 11:23 AM
> > To: dev@dpdk.org
> > Cc: mw@semihalf.com; dima@marvell.com; nsamsono@marvell.com;
> > Jianbo.liu@linaro.org; Tomasz Duszynski <tdu@semihalf.com>; Jacek Siuda
> > <jck@semihalf.com>
> > Subject: [dpdk-dev] [PATCH v2 1/4] crypto/mrvl: add mrvl crypto pmd
> > driver
> >
> > Add support for the Marvell Security Crypto Accelerator EIP197.
> > Driver is based on external, publicly available, Marvell MUSDK
> > library that provides access to the hardware with minimum overhead
> > and high performance.
> >
> > Driver comes with support for the following features:
> >
> > * Symmetric crypto
> > * Sym operation chaining
> > * AES CBC (128)
> > * AES CBC (192)
> > * AES CBC (256)
> > * AES CTR (128)
> > * AES CTR (192)
> > * AES CTR (256)
> > * 3DES CBC
> > * 3DES CTR
> > * MD5
> > * MD5 HMAC
> > * SHA1
> > * SHA1 HMAC
> > * SHA256
> > * SHA256 HMAC
> > * SHA384
> > * SHA384 HMAC
> > * SHA512
> > * SHA512 HMAC
> > * AES GCM (128)
> >
> > Driver was engineered cooperatively by Semihalf and Marvell teams.
> >
> > Semihalf:
> > Jacek Siuda <jck@semihalf.com>
> > Tomasz Duszynski <tdu@semihalf.com>
> >
> > Marvell:
> > Dmitri Epshtein <dima@marvell.com>
> > Natalie Samsonov <nsamsono@marvell.com>
> >
> > Signed-off-by: Jacek Siuda <jck@semihalf.com>
> > Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
>
> If the guys in Marvell has contributed with the code,
> they should sign off too. Up to you.
>
> There is a script to test compilation (devtools/test-build.sh).
> You should also modify it to include the dependency with LIBMUSDK.
>

ACK

> ...
>
> > diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd.c
> > b/drivers/crypto/mrvl/rte_mrvl_pmd.c
> > new file mode 100644
> > index 0000000..63f8daa
> > --- /dev/null
> > +++ b/drivers/crypto/mrvl/rte_mrvl_pmd.c
>
> ...
>
> > +
> > +/* Register the driver in constructor. */
> > +RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_MRVL_PMD,
> > cryptodev_mrvl_pmd_drv);
> > +RTE_PMD_REGISTER_ALIAS(CRYPTODEV_NAME_MRVL_PMD,
> > cryptodev_mrvl_pmd);
>
> You can remove this alias, as this is a new PMD,
> we should be using the primary convention "crypto_mrvl".
>

ACK

>
> > +RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_MRVL_PMD,
> > +	"max_nb_queue_pairs=<int> "
> > +	"max_nb_sessions=<int> "
> > +	"socket_id=<int>");
> > +RTE_PMD_REGISTER_CRYPTO_DRIVER(cryptodev_mrvl_pmd_drv,
> > cryptodev_driver_id);
> > diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
> > b/drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
> > new file mode 100644
> > index 0000000..f7374f8
> > --- /dev/null
> > +++ b/drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
>
> ...
>
> > + */
> > +static const struct rte_cryptodev_capabilities
> > +	mrvl_crypto_pmd_capabilities[] = {
> > +	{	/* MD5 HMAC */
> > +		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
> > +		{.sym = {
> > +			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
> > +			{.auth = {
> > +				.algo = RTE_CRYPTO_AUTH_MD5_HMAC,
> > +				.block_size = 64,
> > +				.key_size = {
> > +					.min = 64,
> > +					.max = 64,
> > +					.increment = 0
> > +				},
> > +				.digest_size = {
> > +					.min = 16,
> > +					.max = 16,
> > +					.increment = 0
> > +				},
> > +				.aad_size = { 0 }
>
> You can remove this aad_size, as it is only applicable to AEAD algorithms (GCM in your case).
>

ACK

> > +			}, }
> > +		}, }
> > +	},
>
> ...
>
> > +	{	/* SHA1 HMAC */
> > +		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
> > +			{.sym = {
> > +				.xform_type =
> > RTE_CRYPTO_SYM_XFORM_AUTH,
> > +				{.auth = {
> > +					.algo =
> > RTE_CRYPTO_AUTH_SHA1_HMAC,
> > +					.block_size = 64,
> > +					.key_size = {
> > +						.min = 16,
> > +						.max = 128,
> > +						.increment = 0
>
> If min and max values are different, increment cannot be 0.

ACK

Thanks for comments.

--
- Tomasz Duszyński

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

* Re: [PATCH v2 2/4] doc: add mrvl crypto pmd documentation
  2017-10-05 14:45     ` De Lara Guarch, Pablo
@ 2017-10-06  8:06       ` Tomasz Duszynski
  0 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-06  8:06 UTC (permalink / raw)
  To: De Lara Guarch, Pablo
  Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On Thu, Oct 05, 2017 at 02:45:33PM +0000, De Lara Guarch, Pablo wrote:
>
>
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Tomasz Duszynski
> > Sent: Thursday, September 28, 2017 11:24 AM
> > To: dev@dpdk.org
> > Cc: mw@semihalf.com; dima@marvell.com; nsamsono@marvell.com;
> > Jianbo.liu@linaro.org; Tomasz Duszynski <tdu@semihalf.com>; Jacek Siuda
> > <jck@semihalf.com>
> > Subject: [dpdk-dev] [PATCH v2 2/4] doc: add mrvl crypto pmd
> > documentation
> >
> > Add documentation for the MRVL CRYPTO PMD driver.
>
> You should add the pmd in the list of device types (devtype),
> In doc/guides/tools/cryptoperf.rst.

ACK

>
> Also, you should mention this new PMD in release notes.
>

ACK

> >
> > Signed-off-by: Jacek Siuda <jck@semihalf.com>
> > Signed-off-by: Tomasz Duszynski <jck@semihalf.com>
> > ---
> >  doc/guides/cryptodevs/features/mrvl.ini |  42 +++++++
> >  doc/guides/cryptodevs/index.rst         |   1 +
> >  doc/guides/cryptodevs/mrvl.rst          | 198
>
> ...
>
> > +++ b/doc/guides/cryptodevs/mrvl.rst
> > @@ -0,0 +1,198 @@
>
> ...
>
> > +
> > +   ./l2fwd-crypto -c 0x3 --vdev=eth_mrvl,iface=eth0
> > + --vdev=cryptodev_mrvl_pmd
>
> I will make the comment also in the first patch, but you should use "crypto_mrvl".
> The cryptodev_*_pmd convention is old and we are only maintaining it for backward compatibility.
> So, I would use "crypto_mrvl".

ACK

Thanks for comments.

--
- Tomasz Duszyński

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

* [PATCH v3 0/4] add crypto mrvl pmd driver
  2017-09-28 10:23 ` [PATCH v2 0/4] add crypto " Tomasz Duszynski
                     ` (3 preceding siblings ...)
  2017-09-28 10:23   ` [PATCH v2 4/4] test: add mrvl crypto pmd unit tests Tomasz Duszynski
@ 2017-10-07 20:28   ` Tomasz Duszynski
  2017-10-07 20:28     ` [PATCH v3 1/4] crypto/mrvl: add mrvl crypto " Tomasz Duszynski
                       ` (4 more replies)
  4 siblings, 5 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-07 20:28 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski

Hello,

This patch series introduces crypto driver for Marvell Armada 7k/8k
SoCs along with documentation and crypto pmd driver tests.

Below you can find the list of features which crypto pmd supports:
* Symmetric crypto
* Sym operation chaining
* AES CBC (128)
* AES CBC (192)
* AES CBC (256)
* AES CTR (128)
* AES CTR (192)
* AES CTR (256)
* 3DES CBC
* 3DES CTR
* MD5
* MD5 HMAC
* SHA1
* SHA1 HMAC
* SHA256
* SHA256 HMAC
* SHA384
* SHA384 HMAC
* SHA512
* SHA512 HMAC
* AES GCM (128)

Changes since v2:
* Added MRVL CRYPTO PMD to the test-build.sh.
* Updated release notes.
* Updated cryptoperf documentation.
* Removed cryptodev_mrvl_pmd driver alias.
* Fixed min,max key sizes used by HMACs in capabilities table.
* Renamed map file.
* Updated documentation.

Tomasz Duszynski (4):
  crypto/mrvl: add mrvl crypto pmd driver
  doc: add mrvl crypto pmd documentation
  maintainers: add maintainers for the mrvl crypto pmd
  test: add mrvl crypto pmd unit tests

 MAINTAINERS                                  |  10 +
 config/common_base                           |   6 +
 devtools/test-build.sh                       |   4 +
 doc/guides/cryptodevs/features/mrvl.ini      |  42 ++
 doc/guides/cryptodevs/index.rst              |   1 +
 doc/guides/cryptodevs/mrvl.rst               | 198 ++++++
 doc/guides/rel_notes/release_17_11.rst       |   5 +
 doc/guides/tools/cryptoperf.rst              |   1 +
 drivers/crypto/Makefile                      |   2 +
 drivers/crypto/mrvl/Makefile                 |  63 ++
 drivers/crypto/mrvl/rte_mrvl_compat.h        |  48 ++
 drivers/crypto/mrvl/rte_mrvl_pmd.c           | 869 +++++++++++++++++++++++++++
 drivers/crypto/mrvl/rte_mrvl_pmd_ops.c       | 776 ++++++++++++++++++++++++
 drivers/crypto/mrvl/rte_mrvl_pmd_private.h   | 121 ++++
 drivers/crypto/mrvl/rte_pmd_mrvl_version.map |   3 +
 mk/rte.app.mk                                |   1 +
 test/test/test_cryptodev.c                   | 168 ++++++
 test/test/test_cryptodev.h                   |   1 +
 test/test/test_cryptodev_aes_test_vectors.h  |  72 ++-
 test/test/test_cryptodev_blockcipher.c       |   9 +-
 test/test/test_cryptodev_blockcipher.h       |   1 +
 test/test/test_cryptodev_des_test_vectors.h  |  24 +-
 22 files changed, 2392 insertions(+), 33 deletions(-)
 create mode 100644 doc/guides/cryptodevs/features/mrvl.ini
 create mode 100644 doc/guides/cryptodevs/mrvl.rst
 create mode 100644 drivers/crypto/mrvl/Makefile
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_compat.h
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd.c
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_private.h
 create mode 100644 drivers/crypto/mrvl/rte_pmd_mrvl_version.map

--
2.7.4

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

* [PATCH v3 1/4] crypto/mrvl: add mrvl crypto pmd driver
  2017-10-07 20:28   ` [PATCH v3 0/4] add crypto mrvl pmd driver Tomasz Duszynski
@ 2017-10-07 20:28     ` Tomasz Duszynski
  2017-10-10 10:16       ` De Lara Guarch, Pablo
  2017-10-07 20:28     ` [PATCH v3 2/4] doc: add mrvl crypto pmd documentation Tomasz Duszynski
                       ` (3 subsequent siblings)
  4 siblings, 1 reply; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-07 20:28 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add support for the Marvell Security Crypto Accelerator EIP197.
Driver is based on external, publicly available, Marvell MUSDK
library that provides access to the hardware with minimum overhead
and high performance.

Driver comes with support for the following features:

* Symmetric crypto
* Sym operation chaining
* AES CBC (128)
* AES CBC (192)
* AES CBC (256)
* AES CTR (128)
* AES CTR (192)
* AES CTR (256)
* 3DES CBC
* 3DES CTR
* MD5
* MD5 HMAC
* SHA1
* SHA1 HMAC
* SHA256
* SHA256 HMAC
* SHA384
* SHA384 HMAC
* SHA512
* SHA512 HMAC
* AES GCM (128)

Driver was engineered cooperatively by Semihalf and Marvell teams.

Semihalf:
Jacek Siuda <jck@semihalf.com>
Tomasz Duszynski <tdu@semihalf.com>

Marvell:
Dmitri Epshtein <dima@marvell.com>
Natalie Samsonov <nsamsono@marvell.com>

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 v3:
 * Added MRVL CRYPTO PMD to the test-build.sh.
 * Updated release notes.
 * Updated cryptoperf documentation.
 * Removed cryptodev_mrvl_pmd driver alias.
 * Fixed min,max key sizes used by HMACs in capabilities table.
 * Renamed map file.

 config/common_base                           |   6 +
 devtools/test-build.sh                       |   4 +
 doc/guides/rel_notes/release_17_11.rst       |   5 +
 doc/guides/tools/cryptoperf.rst              |   1 +
 drivers/crypto/Makefile                      |   2 +
 drivers/crypto/mrvl/Makefile                 |  63 ++
 drivers/crypto/mrvl/rte_mrvl_compat.h        |  48 ++
 drivers/crypto/mrvl/rte_mrvl_pmd.c           | 869 +++++++++++++++++++++++++++
 drivers/crypto/mrvl/rte_mrvl_pmd_ops.c       | 776 ++++++++++++++++++++++++
 drivers/crypto/mrvl/rte_mrvl_pmd_private.h   | 121 ++++
 drivers/crypto/mrvl/rte_pmd_mrvl_version.map |   3 +
 mk/rte.app.mk                                |   1 +
 12 files changed, 1899 insertions(+)
 create mode 100644 drivers/crypto/mrvl/Makefile
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_compat.h
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd.c
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_private.h
 create mode 100644 drivers/crypto/mrvl/rte_pmd_mrvl_version.map

diff --git a/config/common_base b/config/common_base
index 4e4e7c1..745b239 100644
--- a/config/common_base
+++ b/config/common_base
@@ -524,6 +524,12 @@ CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER_DEBUG=n
 CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO=y

 #
+# Compile PMD for Marvell Crypto device
+#
+CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO=n
+CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO_DEBUG=n
+
+#
 # Compile generic event device library
 #
 CONFIG_RTE_LIBRTE_EVENTDEV=y
diff --git a/devtools/test-build.sh b/devtools/test-build.sh
index c6dfaf0..d82e3f4 100755
--- a/devtools/test-build.sh
+++ b/devtools/test-build.sh
@@ -50,6 +50,7 @@ default_path=$PATH
 # - LIBSSO_SNOW3G_PATH
 # - LIBSSO_KASUMI_PATH
 # - LIBSSO_ZUC_PATH
+# - LIBMUSDK_PATH
 . $(dirname $(readlink -e $0))/load-devel-config

 print_usage () {
@@ -133,6 +134,7 @@ reset_env ()
 	unset LIBSSO_KASUMI_PATH
 	unset LIBSSO_ZUC_PATH
 	unset PQOS_INSTALL_PATH
+	unset LIBMUSDK_PATH
 }

 config () # <directory> <target> <options>
@@ -193,6 +195,8 @@ config () # <directory> <target> <options>
 		test "$DPDK_DEP_SSL" != y || \
 		sed -ri            's,(PMD_QAT=)n,\1y,' $1/.config
 		sed -ri           's,(SCHED_.*=)n,\1y,' $1/.config
+		test -z "$LIBMUSDK_PATH" || \
+		sed -ri    's,(PMD_MRVL_CRYPTO=)n,\1y,' $1/.config
 		build_config_hook $1 $2 $3

 		# Explicit enabler/disabler (uppercase)
diff --git a/doc/guides/rel_notes/release_17_11.rst b/doc/guides/rel_notes/release_17_11.rst
index 4f92912..340e162 100644
--- a/doc/guides/rel_notes/release_17_11.rst
+++ b/doc/guides/rel_notes/release_17_11.rst
@@ -64,6 +64,11 @@ New Features
    * Support for Flow API
    * Support for Tx and Rx descriptor status functions

+* **Added MRVL crypto PMD.**
+
+  A new crypto PMD has been added, which provides several ciphering and hashing
+  algorithms. All cryptography operations use the MUSDK library crypto API.
+

 Resolved Issues
 ---------------
diff --git a/doc/guides/tools/cryptoperf.rst b/doc/guides/tools/cryptoperf.rst
index 457f817..5105230 100644
--- a/doc/guides/tools/cryptoperf.rst
+++ b/doc/guides/tools/cryptoperf.rst
@@ -189,6 +189,7 @@ The following are the appication command-line options:
            crypto_dpaa2_sec
            crypto_armv8
            crypto_scheduler
+           crypto_mrvl

 * ``--optype <name>``

diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 7a719b9..1d7db5b 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -51,6 +51,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_KASUMI) += kasumi
 DEPDIRS-kasumi = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_ZUC) += zuc
 DEPDIRS-zuc = $(core-libs)
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO) += mrvl
+DEPDIRS-mrvl = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO) += null
 DEPDIRS-null = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_SEC) += dpaa2_sec
diff --git a/drivers/crypto/mrvl/Makefile b/drivers/crypto/mrvl/Makefile
new file mode 100644
index 0000000..a00a19e
--- /dev/null
+++ b/drivers/crypto/mrvl/Makefile
@@ -0,0 +1,63 @@
+#   BSD LICENSE
+#
+#   Copyright (C) Semihalf 2017. 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 Semihalf 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
+
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),config)
+ifeq ($(LIBMUSDK_PATH),)
+$(error "Please define LIBMUSDK_PATH environment variable")
+endif
+endif
+endif
+
+# library name
+LIB = librte_pmd_mrvl_crypto.a
+
+# build flags
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -I$(LIBMUSDK_PATH)/include
+CFLAGS += -DMVCONF_ARCH_DMA_ADDR_T_64BIT
+
+# library version
+LIBABIVER := 1
+
+# versioning export map
+EXPORT_MAP := rte_mrvl_pmd_version.map
+
+# external library dependencies
+LDLIBS += -L$(LIBMUSDK_PATH)/lib -lmusdk
+
+# library source files
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO) += rte_mrvl_pmd.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO) += rte_mrvl_pmd_ops.c
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/crypto/mrvl/rte_mrvl_compat.h b/drivers/crypto/mrvl/rte_mrvl_compat.h
new file mode 100644
index 0000000..11d53fc
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_mrvl_compat.h
@@ -0,0 +1,48 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) Semihalf 2017. 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 Semihalf 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_MRVL_COMPAT_H_
+#define _RTE_MRVL_COMPAT_H_
+
+/* Unluckily, container_of is defined by both DPDK and MUSDK,
+ * we'll declare only one version.
+ *
+ * Note that it is not used in this PMD anyway.
+ */
+#ifdef container_of
+#undef container_of
+#endif
+#include "drivers/mv_sam.h"
+#include "drivers/mv_sam_cio.h"
+#include "drivers/mv_sam_session.h"
+
+#endif /* _RTE_MRVL_COMPAT_H_ */
diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd.c b/drivers/crypto/mrvl/rte_mrvl_pmd.c
new file mode 100644
index 0000000..a404bf4
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_mrvl_pmd.c
@@ -0,0 +1,869 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) Semihalf 2017. 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 Semihalf 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_common.h>
+#include <rte_hexdump.h>
+#include <rte_cryptodev.h>
+#include <rte_cryptodev_pmd.h>
+#include <rte_cryptodev_vdev.h>
+#include <rte_vdev.h>
+#include <rte_malloc.h>
+#include <rte_cpuflags.h>
+
+#include "rte_mrvl_pmd_private.h"
+
+#ifndef RTE_MRVL_MUSDK_DMA_MEMSIZE
+#define RTE_MRVL_MUSDK_DMA_MEMSIZE 41943040
+#endif
+
+static uint8_t cryptodev_driver_id;
+
+/**
+ * Flag if particular crypto algorithm is supported by PMD/MUSDK.
+ *
+ * The idea is to have Not Supported value as default (0).
+ * This way we need only to define proper map sizes,
+ * non-initialized entries will be by default not supported.
+ */
+enum algo_supported {
+	ALGO_NOT_SUPPORTED = 0,
+	ALGO_SUPPORTED = 1,
+};
+
+/** Map elements for cipher mapping.*/
+struct cipher_params_mapping {
+	enum algo_supported  supported;   /**< On/Off switch */
+	enum sam_cipher_alg  cipher_alg;  /**< Cipher algorithm */
+	enum sam_cipher_mode cipher_mode; /**< Cipher mode */
+	unsigned int max_key_len;         /**< Maximum key length (in bytes)*/
+}
+/* We want to squeeze in multiple maps into the cache line. */
+__rte_aligned(32);
+
+/** Map elements for auth mapping.*/
+struct auth_params_mapping {
+	enum algo_supported supported;  /**< On/off switch */
+	enum sam_auth_alg   auth_alg;   /**< Auth algorithm */
+}
+/* We want to squeeze in multiple maps into the cache line. */
+__rte_aligned(32);
+
+/**
+ * Map of supported cipher algorithms.
+ */
+static const
+struct cipher_params_mapping cipher_map[RTE_CRYPTO_CIPHER_LIST_END] = {
+	[RTE_CRYPTO_CIPHER_3DES_CBC] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_3DES,
+		.cipher_mode = SAM_CIPHER_CBC,
+		.max_key_len = BITS2BYTES(192) },
+	[RTE_CRYPTO_CIPHER_3DES_CTR] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_3DES,
+		.cipher_mode = SAM_CIPHER_CTR,
+		.max_key_len = BITS2BYTES(192) },
+	[RTE_CRYPTO_CIPHER_3DES_ECB] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_3DES,
+		.cipher_mode = SAM_CIPHER_ECB,
+		.max_key_len = BITS2BYTES(192) },
+	[RTE_CRYPTO_CIPHER_AES_CBC] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_AES,
+		.cipher_mode = SAM_CIPHER_CBC,
+		.max_key_len = BITS2BYTES(256) },
+	[RTE_CRYPTO_CIPHER_AES_CTR] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_AES,
+		.cipher_mode = SAM_CIPHER_CTR,
+		.max_key_len = BITS2BYTES(256) },
+};
+
+/**
+ * Map of supported auth algorithms.
+ */
+static const
+struct auth_params_mapping auth_map[RTE_CRYPTO_AUTH_LIST_END] = {
+	[RTE_CRYPTO_AUTH_MD5_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_MD5 },
+	[RTE_CRYPTO_AUTH_MD5] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_MD5 },
+	[RTE_CRYPTO_AUTH_SHA1_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_SHA1 },
+	[RTE_CRYPTO_AUTH_SHA1] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA1 },
+	[RTE_CRYPTO_AUTH_SHA224] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA2_224 },
+	[RTE_CRYPTO_AUTH_SHA256_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_SHA2_256 },
+	[RTE_CRYPTO_AUTH_SHA256] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA2_256 },
+	[RTE_CRYPTO_AUTH_SHA384_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_SHA2_384 },
+	[RTE_CRYPTO_AUTH_SHA384] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA2_384 },
+	[RTE_CRYPTO_AUTH_SHA512_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_SHA2_512 },
+	[RTE_CRYPTO_AUTH_SHA512] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA2_512 },
+	[RTE_CRYPTO_AUTH_AES_GMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_AES_GMAC },
+};
+
+/**
+ * Map of supported aead algorithms.
+ */
+static const
+struct cipher_params_mapping aead_map[RTE_CRYPTO_AEAD_LIST_END] = {
+	[RTE_CRYPTO_AEAD_AES_GCM] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_AES,
+		.cipher_mode = SAM_CIPHER_GCM,
+		.max_key_len = BITS2BYTES(256) },
+};
+
+/*
+ *-----------------------------------------------------------------------------
+ * Forward declarations.
+ *-----------------------------------------------------------------------------
+ */
+static int cryptodev_mrvl_crypto_uninit(struct rte_vdev_device *vdev);
+
+/*
+ *-----------------------------------------------------------------------------
+ * Session Preparation.
+ *-----------------------------------------------------------------------------
+ */
+
+/**
+ * Get xform chain order.
+ *
+ * @param xform Pointer to configuration structure chain for crypto operations.
+ * @returns Order of crypto operations.
+ */
+static enum mrvl_crypto_chain_order
+mrvl_crypto_get_chain_order(const struct rte_crypto_sym_xform *xform)
+{
+	/* Currently, Marvell supports max 2 operations in chain */
+	if (xform->next != NULL && xform->next->next != NULL)
+		return MRVL_CRYPTO_CHAIN_NOT_SUPPORTED;
+
+	if (xform->next != NULL) {
+		if ((xform->type == RTE_CRYPTO_SYM_XFORM_AUTH) &&
+			(xform->next->type == RTE_CRYPTO_SYM_XFORM_CIPHER))
+			return MRVL_CRYPTO_CHAIN_AUTH_CIPHER;
+
+		if ((xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER) &&
+			(xform->next->type == RTE_CRYPTO_SYM_XFORM_AUTH))
+			return MRVL_CRYPTO_CHAIN_CIPHER_AUTH;
+	} else {
+		if (xform->type == RTE_CRYPTO_SYM_XFORM_AUTH)
+			return MRVL_CRYPTO_CHAIN_AUTH_ONLY;
+
+		if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER)
+			return MRVL_CRYPTO_CHAIN_CIPHER_ONLY;
+
+		if (xform->type == RTE_CRYPTO_SYM_XFORM_AEAD)
+			return MRVL_CRYPTO_CHAIN_COMBINED;
+	}
+	return MRVL_CRYPTO_CHAIN_NOT_SUPPORTED;
+}
+
+/**
+ * Set session parameters for cipher part.
+ *
+ * @param sess Crypto session pointer.
+ * @param cipher_xform Pointer to configuration structure for cipher operations.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+mrvl_crypto_set_cipher_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *cipher_xform)
+{
+	/* Make sure we've got proper struct */
+	if (cipher_xform->type != RTE_CRYPTO_SYM_XFORM_CIPHER) {
+		MRVL_CRYPTO_LOG_ERR("Wrong xform struct provided!");
+		return -EINVAL;
+	}
+
+	/* See if map data is present and valid */
+	if ((cipher_xform->cipher.algo > RTE_DIM(cipher_map)) ||
+		(cipher_map[cipher_xform->cipher.algo].supported
+			!= ALGO_SUPPORTED)) {
+		MRVL_CRYPTO_LOG_ERR("Cipher algorithm not supported!");
+		return -EINVAL;
+	}
+
+	sess->cipher_iv_offset = cipher_xform->cipher.iv.offset;
+
+	sess->sam_sess_params.dir =
+		(cipher_xform->cipher.op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) ?
+		SAM_DIR_ENCRYPT : SAM_DIR_DECRYPT;
+	sess->sam_sess_params.cipher_alg =
+		cipher_map[cipher_xform->cipher.algo].cipher_alg;
+	sess->sam_sess_params.cipher_mode =
+		cipher_map[cipher_xform->cipher.algo].cipher_mode;
+
+	/* Assume IV will be passed together with data. */
+	sess->sam_sess_params.cipher_iv = NULL;
+
+	/* Get max key length. */
+	if (cipher_xform->cipher.key.length >
+		cipher_map[cipher_xform->cipher.algo].max_key_len) {
+		MRVL_CRYPTO_LOG_ERR("Wrong key length!");
+		return -EINVAL;
+	}
+
+	sess->sam_sess_params.cipher_key_len = cipher_xform->cipher.key.length;
+	sess->sam_sess_params.cipher_key = cipher_xform->cipher.key.data;
+
+	return 0;
+}
+
+/**
+ * Set session parameters for authentication part.
+ *
+ * @param sess Crypto session pointer.
+ * @param auth_xform Pointer to configuration structure for auth operations.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+mrvl_crypto_set_auth_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *auth_xform)
+{
+	/* Make sure we've got proper struct */
+	if (auth_xform->type != RTE_CRYPTO_SYM_XFORM_AUTH) {
+		MRVL_CRYPTO_LOG_ERR("Wrong xform struct provided!");
+		return -EINVAL;
+	}
+
+	/* See if map data is present and valid */
+	if ((auth_xform->auth.algo > RTE_DIM(auth_map)) ||
+		(auth_map[auth_xform->auth.algo].supported != ALGO_SUPPORTED)) {
+		MRVL_CRYPTO_LOG_ERR("Auth algorithm not supported!");
+		return -EINVAL;
+	}
+
+	sess->sam_sess_params.dir =
+		(auth_xform->auth.op == RTE_CRYPTO_AUTH_OP_GENERATE) ?
+		SAM_DIR_ENCRYPT : SAM_DIR_DECRYPT;
+	sess->sam_sess_params.auth_alg =
+		auth_map[auth_xform->auth.algo].auth_alg;
+	sess->sam_sess_params.u.basic.auth_icv_len =
+		auth_xform->auth.digest_length;
+	/* auth_key must be NULL if auth algorithm does not use HMAC */
+	sess->sam_sess_params.auth_key = auth_xform->auth.key.length ?
+					 auth_xform->auth.key.data : NULL;
+	sess->sam_sess_params.auth_key_len = auth_xform->auth.key.length;
+
+	return 0;
+}
+
+/**
+ * Set session parameters for aead part.
+ *
+ * @param sess Crypto session pointer.
+ * @param aead_xform Pointer to configuration structure for aead operations.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+mrvl_crypto_set_aead_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *aead_xform)
+{
+	/* Make sure we've got proper struct */
+	if (aead_xform->type != RTE_CRYPTO_SYM_XFORM_AEAD) {
+		MRVL_CRYPTO_LOG_ERR("Wrong xform struct provided!");
+		return -EINVAL;
+	}
+
+	/* See if map data is present and valid */
+	if ((aead_xform->aead.algo > RTE_DIM(aead_map)) ||
+		(aead_map[aead_xform->aead.algo].supported
+			!= ALGO_SUPPORTED)) {
+		MRVL_CRYPTO_LOG_ERR("AEAD algorithm not supported!");
+		return -EINVAL;
+	}
+
+	sess->sam_sess_params.dir =
+		(aead_xform->aead.op == RTE_CRYPTO_AEAD_OP_ENCRYPT) ?
+		SAM_DIR_ENCRYPT : SAM_DIR_DECRYPT;
+	sess->sam_sess_params.cipher_alg =
+		aead_map[aead_xform->aead.algo].cipher_alg;
+	sess->sam_sess_params.cipher_mode =
+		aead_map[aead_xform->aead.algo].cipher_mode;
+
+	/* Assume IV will be passed together with data. */
+	sess->sam_sess_params.cipher_iv = NULL;
+
+	/* Get max key length. */
+	if (aead_xform->aead.key.length >
+		aead_map[aead_xform->aead.algo].max_key_len) {
+		MRVL_CRYPTO_LOG_ERR("Wrong key length!");
+		return -EINVAL;
+	}
+
+	sess->sam_sess_params.cipher_key = aead_xform->aead.key.data;
+	sess->sam_sess_params.cipher_key_len = aead_xform->aead.key.length;
+
+	if (sess->sam_sess_params.cipher_mode == SAM_CIPHER_GCM)
+		sess->sam_sess_params.auth_alg = SAM_AUTH_AES_GCM;
+
+	sess->sam_sess_params.u.basic.auth_icv_len =
+		aead_xform->aead.digest_length;
+
+	sess->sam_sess_params.u.basic.auth_aad_len =
+		aead_xform->aead.aad_length;
+
+	return 0;
+}
+
+/**
+ * Parse crypto transform chain and setup session parameters.
+ *
+ * @param dev Pointer to crypto device
+ * @param sess Poiner to crypto session
+ * @param xform Pointer to configuration structure chain for crypto operations.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+int
+mrvl_crypto_set_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *xform)
+{
+	const struct rte_crypto_sym_xform *cipher_xform = NULL;
+	const struct rte_crypto_sym_xform *auth_xform = NULL;
+	const struct rte_crypto_sym_xform *aead_xform = NULL;
+
+	/* Filter out spurious/broken requests */
+	if (xform == NULL)
+		return -EINVAL;
+
+	sess->chain_order = mrvl_crypto_get_chain_order(xform);
+	switch (sess->chain_order) {
+	case MRVL_CRYPTO_CHAIN_CIPHER_AUTH:
+		cipher_xform = xform;
+		auth_xform = xform->next;
+		break;
+	case MRVL_CRYPTO_CHAIN_AUTH_CIPHER:
+		auth_xform = xform;
+		cipher_xform = xform->next;
+		break;
+	case MRVL_CRYPTO_CHAIN_CIPHER_ONLY:
+		cipher_xform = xform;
+		break;
+	case MRVL_CRYPTO_CHAIN_AUTH_ONLY:
+		auth_xform = xform;
+		break;
+	case MRVL_CRYPTO_CHAIN_COMBINED:
+		aead_xform = xform;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if ((cipher_xform != NULL) &&
+		(mrvl_crypto_set_cipher_session_parameters(
+			sess, cipher_xform) < 0)) {
+		MRVL_CRYPTO_LOG_ERR("Invalid/unsupported cipher parameters");
+		return -EINVAL;
+	}
+
+	if ((auth_xform != NULL) &&
+		(mrvl_crypto_set_auth_session_parameters(
+			sess, auth_xform) < 0)) {
+		MRVL_CRYPTO_LOG_ERR("Invalid/unsupported auth parameters");
+		return -EINVAL;
+	}
+
+	if ((aead_xform != NULL) &&
+		(mrvl_crypto_set_aead_session_parameters(
+			sess, aead_xform) < 0)) {
+		MRVL_CRYPTO_LOG_ERR("Invalid/unsupported aead parameters");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Process Operations
+ *-----------------------------------------------------------------------------
+ */
+
+/**
+ * Prepare a single request.
+ *
+ * This function basically translates DPDK crypto request into one
+ * understandable by MUDSK's SAM. If this is a first request in a session,
+ * it starts the session.
+ *
+ * @param request Pointer to pre-allocated && reset request buffer [Out].
+ * @param src_bd Pointer to pre-allocated source descriptor [Out].
+ * @param dst_bd Pointer to pre-allocated destination descriptor [Out].
+ * @param op Pointer to DPDK crypto operation struct [In].
+ */
+static inline int
+mrvl_request_prepare(struct sam_cio_op_params *request,
+		struct sam_buf_info *src_bd,
+		struct sam_buf_info *dst_bd,
+		struct rte_crypto_op *op)
+{
+	struct mrvl_crypto_session *sess;
+	struct rte_mbuf *dst_mbuf;
+	uint8_t *digest;
+
+	if (unlikely(op->sess_type == RTE_CRYPTO_OP_SESSIONLESS)) {
+		MRVL_CRYPTO_LOG_ERR("MRVL CRYPTO PMD only supports session "
+				"oriented requests, op (%p) is sessionless.",
+				op);
+		return -EINVAL;
+	}
+
+	sess = (struct mrvl_crypto_session *)get_session_private_data(
+			op->sym->session, cryptodev_driver_id);
+	if (unlikely(sess == NULL)) {
+		MRVL_CRYPTO_LOG_ERR("Session was not created for this device");
+		return -EINVAL;
+	}
+
+	/*
+	 * If application delivered us null dst buffer, it means it expects
+	 * us to deliver the result in src buffer.
+	 */
+	dst_mbuf = op->sym->m_dst ? op->sym->m_dst : op->sym->m_src;
+
+	request->sa = sess->sam_sess;
+	request->cookie = op;
+
+	/* Single buffers only, sorry. */
+	request->num_bufs = 1;
+	request->src = src_bd;
+	src_bd->vaddr = rte_pktmbuf_mtod(op->sym->m_src, void *);
+	src_bd->paddr = rte_pktmbuf_mtophys(op->sym->m_src);
+	src_bd->len = rte_pktmbuf_data_len(op->sym->m_src);
+
+	/* Empty source. */
+	if (rte_pktmbuf_data_len(op->sym->m_src) == 0) {
+		/* EIP does not support 0 length buffers. */
+		MRVL_CRYPTO_LOG_ERR("Buffer length == 0 not supported!");
+		return -1;
+	}
+
+	/* Empty destination. */
+	if (rte_pktmbuf_data_len(dst_mbuf) == 0) {
+		/* Make dst buffer fit at least source data. */
+		if (rte_pktmbuf_append(dst_mbuf,
+			rte_pktmbuf_data_len(op->sym->m_src)) == NULL) {
+			MRVL_CRYPTO_LOG_ERR("Unable to set big enough dst buffer!");
+			return -1;
+		}
+	}
+
+	request->dst = dst_bd;
+	dst_bd->vaddr = rte_pktmbuf_mtod(dst_mbuf, void *);
+	dst_bd->paddr = rte_pktmbuf_mtophys(dst_mbuf);
+
+	/*
+	 * We can use all available space in dst_mbuf,
+	 * not only what's used currently.
+	 */
+	dst_bd->len = dst_mbuf->buf_len - rte_pktmbuf_headroom(dst_mbuf);
+
+	if (sess->chain_order == MRVL_CRYPTO_CHAIN_COMBINED) {
+		request->cipher_len = op->sym->aead.data.length;
+		request->cipher_offset = op->sym->aead.data.offset;
+		request->cipher_iv = rte_crypto_op_ctod_offset(op, uint8_t *,
+			sess->cipher_iv_offset);
+
+		request->auth_aad = op->sym->aead.aad.data;
+		request->auth_offset = request->cipher_offset;
+		request->auth_len = request->cipher_len;
+	} else {
+		request->cipher_len = op->sym->cipher.data.length;
+		request->cipher_offset = op->sym->cipher.data.offset;
+		request->cipher_iv = rte_crypto_op_ctod_offset(op, uint8_t *,
+				sess->cipher_iv_offset);
+
+		request->auth_offset = op->sym->auth.data.offset;
+		request->auth_len = op->sym->auth.data.length;
+	}
+
+	digest = sess->chain_order == MRVL_CRYPTO_CHAIN_COMBINED ?
+		op->sym->aead.digest.data : op->sym->auth.digest.data;
+	if (digest == NULL) {
+		/* No auth - no worry. */
+		return 0;
+	}
+
+	request->auth_icv_offset = request->auth_offset + request->auth_len;
+
+	/*
+	 * EIP supports only scenarios where ICV(digest buffer) is placed at
+	 * auth_icv_offset. Any other placement means risking errors.
+	 */
+	if (sess->sam_sess_params.dir == SAM_DIR_ENCRYPT) {
+		/*
+		 * This should be the most common case anyway,
+		 * EIP will overwrite DST buffer at auth_icv_offset.
+		 */
+		if (rte_pktmbuf_mtod_offset(
+				dst_mbuf, uint8_t *,
+				request->auth_icv_offset) == digest) {
+			return 0;
+		}
+	} else {/* sess->sam_sess_params.dir == SAM_DIR_DECRYPT */
+		/*
+		 * EIP will look for digest at auth_icv_offset
+		 * offset in SRC buffer.
+		 */
+		if (rte_pktmbuf_mtod_offset(
+				op->sym->m_src, uint8_t *,
+				request->auth_icv_offset) == digest) {
+			return 0;
+		}
+	}
+
+	/*
+	 * If we landed here it means that digest pointer is
+	 * at different than expected place.
+	 */
+	return -1;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * PMD Framework handlers
+ *-----------------------------------------------------------------------------
+ */
+
+/**
+ * Enqueue burst.
+ *
+ * @param queue_pair Pointer to queue pair.
+ * @param ops Pointer to ops requests array.
+ * @param nb_ops Number of elements in ops requests array.
+ * @returns Number of elements consumed from ops.
+ */
+static uint16_t
+mrvl_crypto_pmd_enqueue_burst(void *queue_pair, struct rte_crypto_op **ops,
+		uint16_t nb_ops)
+{
+	uint16_t iter_ops = 0;
+	uint16_t to_enq = 0;
+	uint16_t consumed = 0;
+	int ret;
+	struct sam_cio_op_params requests[nb_ops];
+	/*
+	 * DPDK uses single fragment buffers, so we can KISS descriptors.
+	 * SAM does not store bd pointers, so on-stack scope will be enough.
+	 */
+	struct sam_buf_info src_bd[nb_ops];
+	struct sam_buf_info dst_bd[nb_ops];
+	struct mrvl_crypto_qp *qp = (struct mrvl_crypto_qp *)queue_pair;
+
+	if (nb_ops == 0)
+		return 0;
+
+	/* Prepare the burst. */
+	memset(&requests, 0, sizeof(requests));
+
+	/* Iterate through */
+	for (; iter_ops < nb_ops; ++iter_ops) {
+		if (mrvl_request_prepare(&requests[iter_ops],
+					&src_bd[iter_ops],
+					&dst_bd[iter_ops],
+					ops[iter_ops]) < 0) {
+			MRVL_CRYPTO_LOG_ERR(
+				"Error while parameters preparation!");
+			qp->stats.enqueue_err_count++;
+			ops[iter_ops]->status = RTE_CRYPTO_OP_STATUS_ERROR;
+
+			/*
+			 * Number of handled ops is increased
+			 * (even if the result of handling is error).
+			 */
+			++consumed;
+			break;
+		}
+
+		ops[iter_ops]->status =
+			RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
+
+		/* Increase the number of ops to enqueue. */
+		++to_enq;
+	} /* for (; iter_ops < nb_ops;... */
+
+	if (to_enq > 0) {
+		/* Send the burst */
+		ret = sam_cio_enq(qp->cio, requests, &to_enq);
+		consumed += to_enq;
+		if (ret < 0) {
+			/*
+			 * Trust SAM that in this case returned value will be at
+			 * some point correct (now it is returned unmodified).
+			 */
+			qp->stats.enqueue_err_count += to_enq;
+			for (iter_ops = 0; iter_ops < to_enq; ++iter_ops)
+				ops[iter_ops]->status =
+					RTE_CRYPTO_OP_STATUS_ERROR;
+		}
+	}
+
+	qp->stats.enqueued_count += to_enq;
+	return consumed;
+}
+
+/**
+ * Dequeue burst.
+ *
+ * @param queue_pair Pointer to queue pair.
+ * @param ops Pointer to ops requests array.
+ * @param nb_ops Number of elements in ops requests array.
+ * @returns Number of elements dequeued.
+ */
+static uint16_t
+mrvl_crypto_pmd_dequeue_burst(void *queue_pair,
+		struct rte_crypto_op **ops,
+		uint16_t nb_ops)
+{
+	int ret;
+	struct mrvl_crypto_qp *qp = queue_pair;
+	struct sam_cio *cio = qp->cio;
+	struct sam_cio_op_result results[nb_ops];
+	uint16_t i;
+
+	ret = sam_cio_deq(cio, results, &nb_ops);
+	if (ret < 0) {
+		/* Count all dequeued as error. */
+		qp->stats.dequeue_err_count += nb_ops;
+
+		/* But act as they were dequeued anyway*/
+		qp->stats.dequeued_count += nb_ops;
+
+		return 0;
+	}
+
+	/* Unpack and check results. */
+	for (i = 0; i < nb_ops; ++i) {
+		ops[i] = results[i].cookie;
+
+		switch (results[i].status) {
+		case SAM_CIO_OK:
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
+			break;
+		case SAM_CIO_ERR_ICV:
+			MRVL_CRYPTO_LOG_DBG("CIO returned SAM_CIO_ERR_ICV.");
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
+			break;
+		default:
+			MRVL_CRYPTO_LOG_DBG(
+				"CIO returned Error: %d", results[i].status);
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_ERROR;
+			break;
+		}
+	}
+
+	qp->stats.dequeued_count += nb_ops;
+	return nb_ops;
+}
+
+/**
+ * Create a new crypto device.
+ *
+ * @param name Driver name.
+ * @param vdev Pointer to device structure.
+ * @param init_params Pointer to initialization parameters.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+cryptodev_mrvl_crypto_create(const char *name,
+		struct rte_vdev_device *vdev,
+		struct rte_crypto_vdev_init_params *init_params)
+{
+	struct rte_cryptodev *dev;
+	struct mrvl_crypto_private *internals;
+	struct sam_init_params	sam_params;
+	int ret;
+
+	if (init_params->name[0] == '\0') {
+		ret = rte_cryptodev_pmd_create_dev_name(
+				init_params->name, name);
+
+		if (ret < 0) {
+			MRVL_CRYPTO_LOG_ERR("failed to create unique name");
+			return ret;
+		}
+	}
+
+	dev = rte_cryptodev_vdev_pmd_init(init_params->name,
+				sizeof(struct mrvl_crypto_private),
+				init_params->socket_id, vdev);
+	if (dev == NULL) {
+		MRVL_CRYPTO_LOG_ERR("failed to create cryptodev vdev");
+		goto init_error;
+	}
+
+	dev->driver_id = cryptodev_driver_id;
+	dev->dev_ops = rte_mrvl_crypto_pmd_ops;
+
+	/* Register rx/tx burst functions for data path. */
+	dev->enqueue_burst = mrvl_crypto_pmd_enqueue_burst;
+	dev->dequeue_burst = mrvl_crypto_pmd_dequeue_burst;
+
+	dev->feature_flags = RTE_CRYPTODEV_FF_SYMMETRIC_CRYPTO |
+			RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING |
+			RTE_CRYPTODEV_FF_HW_ACCELERATED;
+
+	/* Set vector instructions mode supported */
+	internals = dev->data->dev_private;
+
+	internals->max_nb_qpairs = init_params->max_nb_queue_pairs;
+	internals->max_nb_sessions = init_params->max_nb_sessions;
+
+	/*
+	 * ret == -EEXIST is correct, it means DMA
+	 * has been already initialized.
+	 */
+	ret = mv_sys_dma_mem_init(RTE_MRVL_MUSDK_DMA_MEMSIZE);
+	if ((ret < 0) && (ret != -EEXIST))
+		return ret;
+
+	sam_params.max_num_sessions = internals->max_nb_sessions;
+
+	return sam_init(&sam_params);
+
+init_error:
+	MRVL_CRYPTO_LOG_ERR(
+		"driver %s: %s failed", init_params->name, __func__);
+
+	cryptodev_mrvl_crypto_uninit(vdev);
+	return -EFAULT;
+}
+
+/**
+ * Initialize the crypto device.
+ *
+ * @param vdev Pointer to device structure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+cryptodev_mrvl_crypto_init(struct rte_vdev_device *vdev)
+{
+	struct rte_crypto_vdev_init_params init_params = { };
+	const char *name;
+	const char *input_args;
+	int ret;
+
+	name = rte_vdev_device_name(vdev);
+	if (name == NULL)
+		return -EINVAL;
+	input_args = rte_vdev_device_args(vdev);
+
+	if (!input_args)
+		return -EINVAL;
+
+	init_params.max_nb_queue_pairs = sam_get_num_inst() * SAM_HW_RING_NUM;
+	init_params.max_nb_sessions =
+		RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_SESSIONS;
+	init_params.socket_id = rte_socket_id();
+
+	ret = rte_cryptodev_vdev_parse_init_params(&init_params, input_args);
+	if (ret) {
+		RTE_LOG(ERR, PMD, "Failed to parse input arguments\n");
+		return ret;
+	}
+
+	RTE_LOG(INFO, PMD, "Initialising %s on NUMA node %d\n", name,
+			init_params.socket_id);
+	if (init_params.name[0] != '\0') {
+		RTE_LOG(INFO, PMD, "  User defined name = %s\n",
+			init_params.name);
+	}
+	RTE_LOG(INFO, PMD, "  Max number of queue pairs = %d\n",
+			init_params.max_nb_queue_pairs);
+	RTE_LOG(INFO, PMD, "  Max number of sessions = %d\n",
+			init_params.max_nb_sessions);
+
+	return cryptodev_mrvl_crypto_create(name, vdev, &init_params);
+}
+
+/**
+ * Uninitialize the crypto device
+ *
+ * @param vdev Pointer to device structure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+cryptodev_mrvl_crypto_uninit(struct rte_vdev_device *vdev)
+{
+	const char *name = rte_vdev_device_name(vdev);
+
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD,
+		"Closing Marvell crypto device %s on numa socket %u\n",
+		name, rte_socket_id());
+
+	sam_deinit();
+
+	return 0;
+}
+
+/**
+ * Basic driver handlers for use in the constructor.
+ */
+static struct rte_vdev_driver cryptodev_mrvl_pmd_drv = {
+	.probe = cryptodev_mrvl_crypto_init,
+	.remove = cryptodev_mrvl_crypto_uninit
+};
+
+/* Register the driver in constructor. */
+RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_MRVL_PMD, cryptodev_mrvl_pmd_drv);
+RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_MRVL_PMD,
+	"max_nb_queue_pairs=<int> "
+	"max_nb_sessions=<int> "
+	"socket_id=<int>");
+RTE_PMD_REGISTER_CRYPTO_DRIVER(cryptodev_mrvl_pmd_drv, cryptodev_driver_id);
diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd_ops.c b/drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
new file mode 100644
index 0000000..495fec6
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
@@ -0,0 +1,776 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) Semihalf 2017. 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 Semihalf 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 <string.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_cryptodev_pmd.h>
+
+#include "rte_mrvl_pmd_private.h"
+
+/**
+ * Capabilities list to be used in reporting to DPDK.
+ */
+static const struct rte_cryptodev_capabilities
+	mrvl_crypto_pmd_capabilities[] = {
+	{	/* MD5 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_MD5_HMAC,
+				.block_size = 64,
+				.key_size = {
+					.min = 1,
+					.max = 64,
+					.increment = 1
+				},
+				.digest_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+			}, }
+		}, }
+	},
+	{	/* MD5 */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+				{.auth = {
+					.algo = RTE_CRYPTO_AUTH_MD5,
+					.block_size = 64,
+					.key_size = {
+						.min = 0,
+						.max = 0,
+						.increment = 0
+					},
+					.digest_size = {
+						.min = 16,
+						.max = 16,
+						.increment = 0
+					},
+				}, }
+			}, }
+	},
+	{	/* SHA1 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+				{.auth = {
+					.algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+					.block_size = 64,
+					.key_size = {
+						.min = 1,
+						.max = 64,
+						.increment = 1
+					},
+					.digest_size = {
+						.min = 20,
+						.max = 20,
+						.increment = 0
+					},
+				}, }
+			}, }
+	},
+	{	/* SHA1 */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA1,
+				.block_size = 64,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 20,
+					.max = 20,
+					.increment = 0
+				},
+			}, }
+		}, }
+	},
+	{	/* SHA224 */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA224,
+				.block_size = 64,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 28,
+					.max = 28,
+					.increment = 0
+				},
+			}, }
+		}, }
+	},
+	{	/* SHA256 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+				{.auth = {
+					.algo = RTE_CRYPTO_AUTH_SHA256_HMAC,
+					.block_size = 64,
+					.key_size = {
+						.min = 1,
+						.max = 64,
+						.increment = 1
+					},
+					.digest_size = {
+						.min = 32,
+						.max = 32,
+						.increment = 0
+					},
+				}, }
+			}, }
+	},
+	{	/* SHA256 */
+			.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+				{.auth = {
+					.algo = RTE_CRYPTO_AUTH_SHA256,
+					.block_size = 64,
+					.key_size = {
+						.min = 0,
+						.max = 0,
+						.increment = 0
+					},
+					.digest_size = {
+						.min = 32,
+						.max = 32,
+						.increment = 0
+					},
+				}, }
+			}, }
+		},
+	{	/* SHA384 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA384_HMAC,
+				.block_size = 128,
+				.key_size = {
+					.min = 1,
+					.max = 128,
+					.increment = 1
+				},
+				.digest_size = {
+					.min = 48,
+					.max = 48,
+					.increment = 0
+				},
+			}, }
+		}, }
+	},
+	{	/* SHA384 */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA384,
+				.block_size = 128,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 48,
+					.max = 48,
+					.increment = 0
+				},
+			}, }
+		}, }
+	},
+	{	/* SHA512 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA512_HMAC,
+				.block_size = 128,
+				.key_size = {
+					.min = 1,
+					.max = 128,
+					.increment = 1
+				},
+				.digest_size = {
+					.min = 64,
+					.max = 64,
+					.increment = 0
+				},
+			}, }
+		}, }
+	},
+	{	/* SHA512  */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA512,
+				.block_size = 128,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 64,
+					.max = 64,
+					.increment = 0
+				},
+			}, }
+		}, }
+	},
+	{	/* AES CBC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+				{.cipher = {
+					.algo = RTE_CRYPTO_CIPHER_AES_CBC,
+					.block_size = 16,
+					.key_size = {
+						.min = 16,
+						.max = 32,
+						.increment = 8
+					},
+					.iv_size = {
+						.min = 16,
+						.max = 16,
+						.increment = 0
+					}
+				}, }
+			}, }
+	},
+	{	/* AES CTR */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_AES_CTR,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 32,
+					.increment = 8
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* AES GCM */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AEAD,
+			{.aead = {
+				.algo = RTE_CRYPTO_AEAD_AES_GCM,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 32,
+					.increment = 8
+				},
+				.digest_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.aad_size = {
+					.min = 8,
+					.max = 12,
+					.increment = 4
+				},
+				.iv_size = {
+					.min = 12,
+					.max = 16,
+					.increment = 4
+				}
+			}, }
+		}, }
+	},
+	{	/* AES GMAC (AUTH) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_AES_GMAC,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 32,
+					.increment = 8
+				},
+				.digest_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 8,
+					.max = 65532,
+					.increment = 4
+				}
+			}, }
+		}, }
+	},
+	{	/* 3DES CBC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_3DES_CBC,
+				.block_size = 8,
+				.key_size = {
+					.min = 24,
+					.max = 24,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 8,
+					.max = 8,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* 3DES CTR */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_3DES_CTR,
+				.block_size = 8,
+				.key_size = {
+					.min = 24,
+					.max = 24,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 8,
+					.max = 8,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+
+	RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
+};
+
+
+/**
+ * Configure device (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param config Pointer to configuration structure.
+ * @returns 0. Always.
+ */
+static int
+mrvl_crypto_pmd_config(__rte_unused struct rte_cryptodev *dev,
+		__rte_unused struct rte_cryptodev_config *config)
+{
+	return 0;
+}
+
+/**
+ * Start device (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @returns 0. Always.
+ */
+static int
+mrvl_crypto_pmd_start(__rte_unused struct rte_cryptodev *dev)
+{
+	return 0;
+}
+
+/**
+ * Stop device (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @returns 0. Always.
+ */
+static void
+mrvl_crypto_pmd_stop(__rte_unused struct rte_cryptodev *dev)
+{
+}
+
+/**
+ * Get device statistics (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param stats Pointer to statistics structure [out].
+ */
+static void
+mrvl_crypto_pmd_stats_get(struct rte_cryptodev *dev,
+		struct rte_cryptodev_stats *stats)
+{
+	int qp_id;
+
+	for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++) {
+		struct mrvl_crypto_qp *qp = dev->data->queue_pairs[qp_id];
+
+		stats->enqueued_count += qp->stats.enqueued_count;
+		stats->dequeued_count += qp->stats.dequeued_count;
+
+		stats->enqueue_err_count += qp->stats.enqueue_err_count;
+		stats->dequeue_err_count += qp->stats.dequeue_err_count;
+	}
+}
+
+/**
+ * Reset device statistics (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ */
+static void
+mrvl_crypto_pmd_stats_reset(struct rte_cryptodev *dev)
+{
+	int qp_id;
+
+	for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++) {
+		struct mrvl_crypto_qp *qp = dev->data->queue_pairs[qp_id];
+
+		memset(&qp->stats, 0, sizeof(qp->stats));
+	}
+}
+
+/**
+ * Get device info (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param dev_info Pointer to the device info structure [out].
+ */
+static void
+mrvl_crypto_pmd_info_get(struct rte_cryptodev *dev,
+		struct rte_cryptodev_info *dev_info)
+{
+	struct mrvl_crypto_private *internals = dev->data->dev_private;
+
+	if (dev_info != NULL) {
+		dev_info->driver_id = dev->driver_id;
+		dev_info->feature_flags = dev->feature_flags;
+		dev_info->capabilities = mrvl_crypto_pmd_capabilities;
+		dev_info->max_nb_queue_pairs = internals->max_nb_qpairs;
+		dev_info->sym.max_nb_sessions = internals->max_nb_sessions;
+	}
+}
+
+/**
+ * Release queue pair (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param qp_id ID of Queue Pair to release.
+ * @returns 0. Always.
+ */
+static int
+mrvl_crypto_pmd_qp_release(struct rte_cryptodev *dev, uint16_t qp_id)
+{
+	struct mrvl_crypto_qp *qp =
+			(struct mrvl_crypto_qp *)dev->data->queue_pairs[qp_id];
+
+	if (dev->data->queue_pairs[qp_id] != NULL) {
+		sam_cio_flush(qp->cio);
+		sam_cio_deinit(qp->cio);
+		rte_free(dev->data->queue_pairs[qp_id]);
+		dev->data->queue_pairs[qp_id] = NULL;
+	}
+
+	return 0;
+}
+
+/**
+ * Close device (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @returns 0. Always.
+ */
+static int
+mrvl_crypto_pmd_close(struct rte_cryptodev *dev)
+{
+	int qp_id;
+
+	for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++)
+		mrvl_crypto_pmd_qp_release(dev, qp_id);
+
+	return 0;
+}
+
+/**
+ * Setup a queue pair (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param qp_id ID of the Queue Pair.
+ * @param qp_conf Queue pair configuration (nb of descriptors).
+ * @param socket_id NUMA socket to allocate memory on.
+ * @returns 0 upon success, negative value otherwise.
+ */
+static int
+mrvl_crypto_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
+		const struct rte_cryptodev_qp_conf *qp_conf,
+		int socket_id, struct rte_mempool *session_pool)
+{
+	struct mrvl_crypto_qp *qp = NULL;
+	char match[RTE_CRYPTODEV_NAME_LEN];
+	unsigned int n;
+
+	/* Allocate the queue pair data structure. */
+	qp = rte_zmalloc_socket("MRVL Crypto PMD Queue Pair", sizeof(*qp),
+					RTE_CACHE_LINE_SIZE, socket_id);
+	if (qp == NULL)
+		return -ENOMEM;
+
+	/* Free old qp prior setup if needed. */
+	if (dev->data->queue_pairs[qp_id] != NULL)
+		mrvl_crypto_pmd_qp_release(dev, qp_id);
+
+	do { /* Error handling block */
+
+		/*
+		 * This extra check is necessary due to a bug in
+		 * crypto library.
+		 */
+		int num = sam_get_num_inst();
+		if (num == 0) {
+			MRVL_CRYPTO_LOG_ERR("No crypto engines detected.\n");
+			return -1;
+		}
+
+		/*
+		 * In case two crypto engines are enabled qps will
+		 * be evenly spread among them. Even and odd qps will
+		 * be handled by cio-0 and cio-1 respectively. qp-cio mapping
+		 * will look as follows:
+		 *
+		 * qp:      0        1        2        3
+		 * cio-x:y: cio-0:0, cio-1:0, cio-0:1, cio-1:1
+		 *
+		 * qp:      4        5        6        7
+		 * cio-x:y: cio-0:2, cio-1:2, cio-0:3, cio-1:3
+		 *
+		 * In case just one engine is enabled mapping will look as
+		 * follows:
+		 * qp:      0        1        2        3
+		 * cio-x:y: cio-0:0, cio-0:1, cio-0:2, cio-0:3
+		 */
+		n = snprintf(match, sizeof(match), "cio-%u:%u",
+				qp_id % num, qp_id / num);
+
+		if (n >= sizeof(match))
+			break;
+
+		qp->cio_params.match = match;
+		qp->cio_params.size = qp_conf->nb_descriptors;
+
+		if (sam_cio_init(&qp->cio_params, &qp->cio) < 0)
+			break;
+
+		qp->sess_mp = session_pool;
+
+		memset(&qp->stats, 0, sizeof(qp->stats));
+		dev->data->queue_pairs[qp_id] = qp;
+		return 0;
+	} while (0);
+
+	rte_free(qp);
+	return -1;
+}
+
+/** Start queue pair (PMD ops callback) - not supported.
+ *
+ * @param dev Pointer to the device structure.
+ * @param qp_id ID of the Queue Pair.
+ * @returns -ENOTSUP. Always.
+ */
+static int
+mrvl_crypto_pmd_qp_start(__rte_unused struct rte_cryptodev *dev,
+		__rte_unused uint16_t queue_pair_id)
+{
+	return -ENOTSUP;
+}
+
+/** Stop queue pair (PMD ops callback) - not supported.
+ *
+ * @param dev Pointer to the device structure.
+ * @param qp_id ID of the Queue Pair.
+ * @returns -ENOTSUP. Always.
+ */
+static int
+mrvl_crypto_pmd_qp_stop(__rte_unused struct rte_cryptodev *dev,
+		__rte_unused uint16_t queue_pair_id)
+{
+	return -ENOTSUP;
+}
+
+/** Return the number of allocated queue pairs (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @returns Number of allocated queue pairs.
+ */
+static uint32_t
+mrvl_crypto_pmd_qp_count(struct rte_cryptodev *dev)
+{
+	return dev->data->nb_queue_pairs;
+}
+
+/** Returns the size of the session structure (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure [Unused].
+ * @returns Size of Marvell crypto session.
+ */
+static unsigned
+mrvl_crypto_pmd_session_get_size(__rte_unused struct rte_cryptodev *dev)
+{
+	return sizeof(struct mrvl_crypto_session);
+}
+
+/** Configure the session from a crypto xform chain (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param xform Pointer to the crytpo configuration structure.
+ * @param sess Pointer to the empty session structure.
+ * @returns 0 upon success, negative value otherwise.
+ */
+static int
+mrvl_crypto_pmd_session_configure(__rte_unused struct rte_cryptodev *dev,
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mp)
+{
+	struct mrvl_crypto_session *mrvl_sess;
+	void *sess_private_data;
+	int ret;
+
+	if (sess == NULL) {
+		MRVL_CRYPTO_LOG_ERR("Invalid session struct.");
+		return -EINVAL;
+	}
+
+	if (rte_mempool_get(mp, &sess_private_data)) {
+		CDEV_LOG_ERR("Couldn't get object from session mempool.");
+		return -ENOMEM;
+	}
+
+	ret = mrvl_crypto_set_session_parameters(sess_private_data, xform);
+	if (ret != 0) {
+		MRVL_CRYPTO_LOG_ERR("Failed to configure session parameters.");
+
+		/* Return session to mempool */
+		rte_mempool_put(mp, sess_private_data);
+		return ret;
+	}
+
+	set_session_private_data(sess, dev->driver_id, sess_private_data);
+
+	mrvl_sess = (struct mrvl_crypto_session *)sess_private_data;
+	if (sam_session_create(&mrvl_sess->sam_sess_params,
+				&mrvl_sess->sam_sess) < 0) {
+		MRVL_CRYPTO_LOG_DBG("Failed to create session!");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ * Clear the memory of session so it doesn't leave key material behind.
+ *
+ * @param dev Pointer to the device structure.
+ * @returns 0. Always.
+ */
+static void
+mrvl_crypto_pmd_session_clear(struct rte_cryptodev *dev,
+		struct rte_cryptodev_sym_session *sess)
+{
+
+	uint8_t index = dev->driver_id;
+	void *sess_priv = get_session_private_data(sess, index);
+
+	/* Zero out the whole structure */
+	if (sess_priv) {
+		struct mrvl_crypto_session *mrvl_sess =
+			(struct mrvl_crypto_session *)sess_priv;
+
+		if (mrvl_sess->sam_sess &&
+		    sam_session_destroy(mrvl_sess->sam_sess) < 0) {
+			MRVL_CRYPTO_LOG_INFO("Error while destroying session!");
+		}
+
+		memset(sess, 0, sizeof(struct mrvl_crypto_session));
+		struct rte_mempool *sess_mp = rte_mempool_from_obj(sess_priv);
+		set_session_private_data(sess, index, NULL);
+		rte_mempool_put(sess_mp, sess_priv);
+	}
+}
+
+/**
+ * PMD handlers for crypto ops.
+ */
+static struct rte_cryptodev_ops mrvl_crypto_pmd_ops = {
+		.dev_configure		= mrvl_crypto_pmd_config,
+		.dev_start		= mrvl_crypto_pmd_start,
+		.dev_stop		= mrvl_crypto_pmd_stop,
+		.dev_close		= mrvl_crypto_pmd_close,
+
+		.dev_infos_get		= mrvl_crypto_pmd_info_get,
+
+		.stats_get		= mrvl_crypto_pmd_stats_get,
+		.stats_reset		= mrvl_crypto_pmd_stats_reset,
+
+		.queue_pair_setup	= mrvl_crypto_pmd_qp_setup,
+		.queue_pair_release	= mrvl_crypto_pmd_qp_release,
+		.queue_pair_start	= mrvl_crypto_pmd_qp_start,
+		.queue_pair_stop	= mrvl_crypto_pmd_qp_stop,
+		.queue_pair_count	= mrvl_crypto_pmd_qp_count,
+
+		.session_get_size	= mrvl_crypto_pmd_session_get_size,
+		.session_configure	= mrvl_crypto_pmd_session_configure,
+		.session_clear		= mrvl_crypto_pmd_session_clear
+};
+
+struct rte_cryptodev_ops *rte_mrvl_crypto_pmd_ops = &mrvl_crypto_pmd_ops;
diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd_private.h b/drivers/crypto/mrvl/rte_mrvl_pmd_private.h
new file mode 100644
index 0000000..2da14b8
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_mrvl_pmd_private.h
@@ -0,0 +1,121 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) Semihalf 2017. 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 Semihalf 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_MRVL_PMD_PRIVATE_H_
+#define _RTE_MRVL_PMD_PRIVATE_H_
+
+#include "rte_mrvl_compat.h"
+
+#define CRYPTODEV_NAME_MRVL_PMD crypto_mrvl
+/**< Marvell PMD device name */
+
+#define MRVL_CRYPTO_LOG_ERR(fmt, args...) \
+	RTE_LOG(ERR, CRYPTODEV, "[%s] %s() line %u: " fmt "\n",  \
+			RTE_STR(CRYPTODEV_NAME_MRVL_CRYPTO_PMD), \
+			__func__, __LINE__, ## args)
+
+#ifdef RTE_LIBRTE_MRVL_CRYPTO_DEBUG
+#define MRVL_CRYPTO_LOG_INFO(fmt, args...) \
+	RTE_LOG(INFO, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+			RTE_STR(CRYPTODEV_NAME_MRVL_CRYPTO_PMD), \
+			__func__, __LINE__, ## args)
+
+#define MRVL_CRYPTO_LOG_DBG(fmt, args...) \
+	RTE_LOG(DEBUG, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+			RTE_STR(CRYPTODEV_NAME_MRVL_CRYPTO_PMD), \
+			__func__, __LINE__, ## args)
+
+#else
+#define MRVL_CRYPTO_LOG_INFO(fmt, args...)
+#define MRVL_CRYPTO_LOG_DBG(fmt, args...)
+#endif
+
+/**
+ * Handy bits->bytes conversion macro.
+ */
+#define BITS2BYTES(x) ((x) >> 3)
+
+/** The operation order mode enumerator. */
+enum mrvl_crypto_chain_order {
+	MRVL_CRYPTO_CHAIN_CIPHER_ONLY,
+	MRVL_CRYPTO_CHAIN_AUTH_ONLY,
+	MRVL_CRYPTO_CHAIN_CIPHER_AUTH,
+	MRVL_CRYPTO_CHAIN_AUTH_CIPHER,
+	MRVL_CRYPTO_CHAIN_COMBINED,
+	MRVL_CRYPTO_CHAIN_NOT_SUPPORTED,
+};
+
+/** Private data structure for each crypto device. */
+struct mrvl_crypto_private {
+	unsigned int max_nb_qpairs;	/**< Max number of queue pairs */
+	unsigned int max_nb_sessions;	/**< Max number of sessions */
+};
+
+/** MRVL crypto queue pair structure. */
+struct mrvl_crypto_qp {
+	/** SAM CIO (MUSDK Queue Pair equivalent).*/
+	struct sam_cio *cio;
+
+	/** Session Mempool. */
+	struct rte_mempool *sess_mp;
+
+	/** Queue pair statistics. */
+	struct rte_cryptodev_stats stats;
+
+	/** CIO initialization parameters.*/
+	struct sam_cio_params cio_params;
+} __rte_cache_aligned;
+
+/** MRVL crypto private session structure. */
+struct mrvl_crypto_session {
+	/** Crypto operations chain order. */
+	enum mrvl_crypto_chain_order chain_order;
+
+	/** Session initialization parameters. */
+	struct sam_session_params sam_sess_params;
+
+	/** SAM session pointer. */
+	struct sam_sa *sam_sess;
+
+	/** Cipher IV offset. */
+	uint16_t cipher_iv_offset;
+} __rte_cache_aligned;
+
+/** Set and validate MRVL crypto session parameters */
+extern int
+mrvl_crypto_set_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *xform);
+
+/** device specific operations function pointer structure */
+extern struct rte_cryptodev_ops *rte_mrvl_crypto_pmd_ops;
+
+#endif /* _RTE_MRVL_PMD_PRIVATE_H_ */
diff --git a/drivers/crypto/mrvl/rte_pmd_mrvl_version.map b/drivers/crypto/mrvl/rte_pmd_mrvl_version.map
new file mode 100644
index 0000000..a753031
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_pmd_mrvl_version.map
@@ -0,0 +1,3 @@
+DPDK_17.11 {
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 009bb7c..c9eb588 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -168,6 +168,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_ZUC)         += -lrte_pmd_zuc
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_ZUC)         += -L$(LIBSSO_ZUC_PATH)/build -lsso_zuc
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO)    += -lrte_pmd_armv8
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO)    += -L$(ARMV8_CRYPTO_LIB_PATH) -larmv8_crypto
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO) += -L$(LIBMUSDK_PATH)/lib -lrte_pmd_mrvl_crypto -lmusdk
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER) += -lrte_pmd_crypto_scheduler
 ifeq ($(CONFIG_RTE_LIBRTE_FSLMC_BUS),y)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_SEC)   += -lrte_pmd_dpaa2_sec
--
2.7.4

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

* [PATCH v3 2/4] doc: add mrvl crypto pmd documentation
  2017-10-07 20:28   ` [PATCH v3 0/4] add crypto mrvl pmd driver Tomasz Duszynski
  2017-10-07 20:28     ` [PATCH v3 1/4] crypto/mrvl: add mrvl crypto " Tomasz Duszynski
@ 2017-10-07 20:28     ` Tomasz Duszynski
  2017-10-07 20:28     ` [PATCH v3 3/4] maintainers: add maintainers for the mrvl crypto pmd Tomasz Duszynski
                       ` (2 subsequent siblings)
  4 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-07 20:28 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add documentation for the MRVL CRYPTO PMD driver.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <jck@semihalf.com>
---
 v3:
 * Updated documentation.

 doc/guides/cryptodevs/features/mrvl.ini |  42 +++++++
 doc/guides/cryptodevs/index.rst         |   1 +
 doc/guides/cryptodevs/mrvl.rst          | 198 ++++++++++++++++++++++++++++++++
 3 files changed, 241 insertions(+)
 create mode 100644 doc/guides/cryptodevs/features/mrvl.ini
 create mode 100644 doc/guides/cryptodevs/mrvl.rst

diff --git a/doc/guides/cryptodevs/features/mrvl.ini b/doc/guides/cryptodevs/features/mrvl.ini
new file mode 100644
index 0000000..6d2fe6a
--- /dev/null
+++ b/doc/guides/cryptodevs/features/mrvl.ini
@@ -0,0 +1,42 @@
+; Supported features of the 'mrvl' crypto driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Symmetric crypto       = Y
+Sym operation chaining = Y
+
+;
+; Supported crypto algorithms of a default crypto driver.
+;
+[Cipher]
+AES CBC (128)  = Y
+AES CBC (192)  = Y
+AES CBC (256)  = Y
+AES CTR (128)  = Y
+AES CTR (192)  = Y
+AES CTR (256)  = Y
+3DES CBC       = Y
+3DES CTR       = Y
+
+;
+; Supported authentication algorithms of a default crypto driver.
+;
+[Auth]
+MD5          = Y
+MD5 HMAC     = Y
+SHA1         = Y
+SHA1 HMAC    = Y
+SHA256       = Y
+SHA256 HMAC  = Y
+SHA384       = Y
+SHA384 HMAC  = Y
+SHA512       = Y
+SHA512 HMAC  = Y
+AES GMAC     = Y
+
+;
+; Supported AEAD algorithms of a default crypto driver.
+;
+[AEAD]
+AES GCM (128) = Y
diff --git a/doc/guides/cryptodevs/index.rst b/doc/guides/cryptodevs/index.rst
index 361b82d..a8ee0eb 100644
--- a/doc/guides/cryptodevs/index.rst
+++ b/doc/guides/cryptodevs/index.rst
@@ -42,6 +42,7 @@ Crypto Device Drivers
     dpaa2_sec
     kasumi
     openssl
+    mrvl
     null
     scheduler
     snow3g
diff --git a/doc/guides/cryptodevs/mrvl.rst b/doc/guides/cryptodevs/mrvl.rst
new file mode 100644
index 0000000..d38bed0
--- /dev/null
+++ b/doc/guides/cryptodevs/mrvl.rst
@@ -0,0 +1,198 @@
+..  BSD LICENSE
+    Copyright(c) 2017 Semihalf. All rights reserved.
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in
+        the documentation and/or other materials provided with the
+        distribution.
+      * Neither the name of Semihalf 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.
+
+MRVL Crypto Poll Mode Driver
+============================
+
+The MRVL CRYPTO PMD (**librte_crypto_mrvl_pmd**) provides poll mode crypto driver
+support by utilizing MUSDK library, which provides cryptographic operations
+acceleration by using Security Acceleration Engine (EIP197) directly from
+user-space with minimum overhead and high performance.
+
+Features
+--------
+
+MRVL CRYPTO PMD has support for:
+
+* Symmetric crypto
+* Sym operation chaining
+* AES CBC (128)
+* AES CBC (192)
+* AES CBC (256)
+* AES CTR (128)
+* AES CTR (192)
+* AES CTR (256)
+* 3DES CBC
+* 3DES CTR
+* MD5
+* MD5 HMAC
+* SHA1
+* SHA1 HMAC
+* SHA256
+* SHA256 HMAC
+* SHA384
+* SHA384 HMAC
+* SHA512
+* SHA512 HMAC
+* AES GCM (128)
+
+Limitations
+-----------
+
+* Hardware only supports scenarios where ICV (digest buffer) is placed just
+  after the authenticated data. Other placement will result in error.
+
+Installation
+------------
+
+MRVL CRYPTO PMD driver compilation is disabled by default due to external dependencies.
+Currently there are two driver specific compilation options in
+``config/common_base`` available:
+
+- ``CONFIG_RTE_LIBRTE_MRVL_CRYPTO`` (default ``n``)
+
+    Toggle compilation of the librte_pmd_mrvl driver.
+
+- ``CONFIG_RTE_LIBRTE_MRVL_CRYPTO_DEBUG`` (default ``n``)
+
+    Toggle display of debugging messages.
+
+During compilation external MUSDK library, which provides direct access
+to Marvell's EIP197 cryptographic engine, is necessary. Library sources are
+available `here <https://github.com/MarvellEmbeddedProcessors/musdk-marvell/tree/musdk-armada-17.08>`__.
+
+Alternatively, prebuilt library can be downloaded from
+`Marvell Extranet <https://extranet.marvell.com>`_. Once approval has been
+granted, library can be found by typing ``musdk`` in the search box.
+
+For MUSDK library build instructions please refer to ``doc/musdk_get_started.txt``
+in library sources directory.
+
+MUSDK requires out of tree kernel modules to work. Kernel tree needed to build
+them is available
+`here <https://github.com/MarvellEmbeddedProcessors/linux-marvell/tree/linux-4.4.52-armada-17.08>`__.
+
+Initialization
+--------------
+
+After successfully building MRVL CRYPTO PMD, the following modules need to be
+loaded:
+
+.. code-block:: console
+
+   insmod musdk_uio.ko
+   insmod mvpp2x_sysfs.ko
+   insmod mv_pp_uio.ko
+   insmod mv_sam_uio.ko
+   insmod crypto_safexcel.ko
+
+- `musdk_uio.ko`, `mv_pp2_uio.ko` and `mv_sam_uio.ko` are distributed together with MUSDK library.
+- `crypto_safexcel.ko` is an in-kernel module.
+- `mvpp2x_sysfs.ko` can be build from sources available `here <https://github.com/MarvellEmbeddedProcessors/mvpp2x-marvell/tree/mvpp2x-armada-17.08>`__.
+
+The following parameters (all optional) are exported by the driver:
+
+* max_nb_queue_pairs: maximum number of queue pairs in the device (8 by default).
+* max_nb_sessions: maximum number of sessions that can be created (2048 by default).
+* socket_id: socket on which to allocate the device resources on.
+
+l2fwd-crypto example application can be used to verify MRVL CRYPTO PMD
+operation:
+
+.. code-block:: console
+
+   ./l2fwd-crypto --vdev=net_mrvl,iface=eth0 --vdev=crypto_mrvl -- \
+     --cipher_op ENCRYPT --cipher_algo aes-cbc \
+     --cipher_key 00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f  \
+     --auth_op GENERATE --auth_algo sha1-hmac \
+     --auth_key 10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f
+
+Example output:
+
+.. code-block:: console
+
+   [...]
+   AAD: at [0x7f253ceb80], len=
+   P ID 0 configuration ----
+   Port mode               : KR
+   MAC status              : disabled
+   Link status             : link up
+   Port speed              : 10G
+   Port duplex             : full
+   Port: Egress enable tx_port_num=16 qmap=0x1
+   PORT: Port0 - link
+   P ID 0 configuration ----
+   Port mode               : KR
+   MAC status              : disabled
+   Link status             : link down
+   Port speed              : 10G
+   Port duplex             : full
+   Port: Egress enable tx_port_num=16 qmap=0x1
+   Port 0, MAC address: 00:50:43:02:21:20
+
+
+   Checking link statusdone
+   Port 0 Link Up - speed 0 Mbps - full-duplex
+   Lcore 0: RX port 0
+   Allocated session pool on socket 0
+   eip197: 0:0 registers: paddr: 0xf2880000, vaddr: 0x0x7f56a80000
+   DMA buffer (131136 bytes) for CDR #0 allocated: paddr = 0xb0585e00, vaddr = 0x7f09384e00
+   DMA buffer (131136 bytes) for RDR #0 allocated: paddr = 0xb05a5f00, vaddr = 0x7f093a4f00
+   DMA buffers allocated for 2049 operations. Tokens - 256 bytes
+   Lcore 0: cryptodev 0
+   L2FWD: lcore 1 has nothing to do
+   L2FWD: lcore 2 has nothing to do
+   L2FWD: lcore 3 has nothing to do
+   L2FWD: entering main loop on lcore 0
+   L2FWD:  -- lcoreid=0 portid=0
+   L2FWD:  -- lcoreid=0 cryptoid=0
+   Options:-
+   nportmask: ffffffff
+   ports per lcore: 1
+   refresh period : 10000
+   single lcore mode: disabled
+   stats_printing: enabled
+   sessionless crypto: disabled
+
+   Crypto chain: Input --> Encrypt --> Auth generate --> Output
+
+   ---- Cipher information ---
+   Algorithm: aes-cbc
+   Cipher key: at [0x7f56db4e80], len=16
+   00000000: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F | ................
+   IV: at [0x7f56db4b80], len=16
+   00000000: 20 F0 63 0E 45 EB 2D 84 72 D4 13 6E 36 B5 AF FE |  .c.E.-.r..n6...
+
+   ---- Authentication information ---
+   Algorithm: sha1-hmac
+   Auth key: at [0x7f56db4d80], len=16
+   00000000: 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F | ................
+   IV: at [0x7f56db4a80], len=0
+   AAD: at [0x7f253ceb80], len=
--
2.7.4

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

* [PATCH v3 3/4] maintainers: add maintainers for the mrvl crypto pmd
  2017-10-07 20:28   ` [PATCH v3 0/4] add crypto mrvl pmd driver Tomasz Duszynski
  2017-10-07 20:28     ` [PATCH v3 1/4] crypto/mrvl: add mrvl crypto " Tomasz Duszynski
  2017-10-07 20:28     ` [PATCH v3 2/4] doc: add mrvl crypto pmd documentation Tomasz Duszynski
@ 2017-10-07 20:28     ` Tomasz Duszynski
  2017-10-07 20:28     ` [PATCH v3 4/4] test: add mrvl crypto pmd unit tests Tomasz Duszynski
  2017-10-10 12:17     ` [PATCH v4 0/4] add crypto mrvl pmd driver Tomasz Duszynski
  4 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-07 20:28 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 MAINTAINERS | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 73b0c1d..e65be03 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -574,6 +574,16 @@ F: drivers/crypto/dpaa2_sec/
 F: doc/guides/cryptodevs/dpaa2_sec.rst
 F: doc/guides/cryptodevs/features/dpaa2_sec.ini
 
+MARVELL MRVL PMD
+M: Jacek Siuda <jck@semihalf.com>
+M: Tomasz Duszynski <tdu@semihalf.com>
+M: Dmitri Epshtein <dima@marvell.com>
+M: Natalie Samsonov <nsamsono@marvell.com>
+M: Jianbo Liu <jianbo.liu@linaro.org>
+F: drivers/crypto/mrvl/
+F: doc/guides/cryptodevs/mrvl.rst
+F: doc/guides/cryptodevs/mrvl.ini
+
 SNOW 3G PMD
 M: Pablo de Lara <pablo.de.lara.guarch@intel.com>
 F: drivers/crypto/snow3g/
-- 
2.7.4

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

* [PATCH v3 4/4] test: add mrvl crypto pmd unit tests
  2017-10-07 20:28   ` [PATCH v3 0/4] add crypto mrvl pmd driver Tomasz Duszynski
                       ` (2 preceding siblings ...)
  2017-10-07 20:28     ` [PATCH v3 3/4] maintainers: add maintainers for the mrvl crypto pmd Tomasz Duszynski
@ 2017-10-07 20:28     ` Tomasz Duszynski
  2017-10-10 10:44       ` De Lara Guarch, Pablo
  2017-10-10 12:17     ` [PATCH v4 0/4] add crypto mrvl pmd driver Tomasz Duszynski
  4 siblings, 1 reply; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-07 20:28 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add unit tests for MRVL CRYPTO PMD driver.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <jck@semihalf.com>
---
 test/test/test_cryptodev.c                  | 168 ++++++++++++++++++++++++++++
 test/test/test_cryptodev.h                  |   1 +
 test/test/test_cryptodev_aes_test_vectors.h |  72 ++++++++----
 test/test/test_cryptodev_blockcipher.c      |   9 +-
 test/test/test_cryptodev_blockcipher.h      |   1 +
 test/test/test_cryptodev_des_test_vectors.h |  24 ++--
 6 files changed, 242 insertions(+), 33 deletions(-)

diff --git a/test/test/test_cryptodev.c b/test/test/test_cryptodev.c
index a4116c6..9fb6a2c 100644
--- a/test/test/test_cryptodev.c
+++ b/test/test/test_cryptodev.c
@@ -341,6 +341,28 @@ testsuite_setup(void)
 		}
 	}
 
+	/* Create a MRVL device if required */
+	if (gbl_driver_id == rte_cryptodev_driver_id_get(
+			RTE_STR(CRYPTODEV_MRVL_PMD))) {
+#ifndef RTE_LIBRTE_PMD_MRVL_CRYPTO
+		RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO must be"
+			" enabled in config file to run this testsuite.\n");
+		return TEST_FAILED;
+#endif
+		nb_devs = rte_cryptodev_device_count_by_driver(
+				rte_cryptodev_driver_id_get(
+				RTE_STR(CRYPTODEV_NAME_MRVL_PMD)));
+		if (nb_devs < 1) {
+			ret = rte_vdev_init(
+				RTE_STR(CRYPTODEV_NAME_MRVL_PMD),
+				NULL);
+
+			TEST_ASSERT(ret == 0, "Failed to create "
+				"instance of pmd : %s",
+				RTE_STR(CRYPTODEV_NAME_MRVL_PMD));
+		}
+	}
+
 #ifdef RTE_LIBRTE_PMD_CRYPTO_SCHEDULER
 	if (gbl_driver_id == rte_cryptodev_driver_id_get(
 			RTE_STR(CRYPTODEV_NAME_SCHEDULER_PMD))) {
@@ -1862,6 +1884,101 @@ test_AES_chain_armv8_all(void)
 	return TEST_SUCCESS;
 }
 
+static int
+test_AES_chain_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_AES_CHAIN_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_AES_cipheronly_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_AES_CIPHERONLY_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_authonly_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_AUTHONLY_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_3DES_chain_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_3DES_CHAIN_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_3DES_cipheronly_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_3DES_CIPHERONLY_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
 /* ***** SNOW 3G Tests ***** */
 static int
 create_wireless_algo_hash_session(uint8_t dev_id,
@@ -8939,6 +9056,40 @@ static struct unit_test_suite cryptodev_armv8_testsuite  = {
 	}
 };
 
+static struct unit_test_suite cryptodev_mrvl_testsuite  = {
+	.suite_name = "Crypto Device Marvell Component Test Suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASE_ST(ut_setup, ut_teardown, test_multi_session),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_multi_session_random_usage),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_AES_chain_mrvl_all),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_AES_cipheronly_mrvl_all),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_authonly_mrvl_all),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_3DES_chain_mrvl_all),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_3DES_cipheronly_mrvl_all),
+
+		/** Negative tests */
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			authentication_verify_HMAC_SHA1_fail_data_corrupt),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			authentication_verify_HMAC_SHA1_fail_tag_corrupt),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			auth_decryption_AES128CBC_HMAC_SHA1_fail_data_corrupt),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			auth_decryption_AES128CBC_HMAC_SHA1_fail_tag_corrupt),
+
+		TEST_CASES_END() /**< NULL terminate unit test array */
+	}
+};
+
+
 static int
 test_cryptodev_qat(void /*argv __rte_unused, int argc __rte_unused*/)
 {
@@ -9083,6 +9234,22 @@ test_cryptodev_armv8(void)
 	return unit_test_suite_runner(&cryptodev_armv8_testsuite);
 }
 
+static int
+test_cryptodev_mrvl(void)
+{
+	gbl_driver_id = rte_cryptodev_driver_id_get(
+			RTE_STR(CRYPTODEV_NAME_MRVL_PMD));
+
+	if (gbl_driver_id == -1) {
+		RTE_LOG(ERR, USER1, "MRVL PMD must be loaded. Check if "
+				"CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO is enabled "
+				"in config file to run this testsuite.\n");
+		return TEST_FAILED;
+	}
+
+	return unit_test_suite_runner(&cryptodev_mrvl_testsuite);
+}
+
 #ifdef RTE_LIBRTE_PMD_CRYPTO_SCHEDULER
 
 static int
@@ -9136,4 +9303,5 @@ REGISTER_TEST_COMMAND(cryptodev_sw_snow3g_autotest, test_cryptodev_sw_snow3g);
 REGISTER_TEST_COMMAND(cryptodev_sw_kasumi_autotest, test_cryptodev_sw_kasumi);
 REGISTER_TEST_COMMAND(cryptodev_sw_zuc_autotest, test_cryptodev_sw_zuc);
 REGISTER_TEST_COMMAND(cryptodev_sw_armv8_autotest, test_cryptodev_armv8);
+REGISTER_TEST_COMMAND(cryptodev_sw_mrvl_autotest, test_cryptodev_mrvl);
 REGISTER_TEST_COMMAND(cryptodev_dpaa2_sec_autotest, test_cryptodev_dpaa2_sec);
diff --git a/test/test/test_cryptodev.h b/test/test/test_cryptodev.h
index 4509a09..2e9eb0b 100644
--- a/test/test/test_cryptodev.h
+++ b/test/test/test_cryptodev.h
@@ -88,6 +88,7 @@
 #define CRYPTODEV_NAME_ARMV8_PMD	crypto_armv8
 #define CRYPTODEV_NAME_DPAA2_SEC_PMD	crypto_dpaa2_sec
 #define CRYPTODEV_NAME_SCHEDULER_PMD	crypto_scheduler
+#define CRYPTODEV_NAME_MRVL_PMD		crypto_mrvl
 
 /**
  * Write (spread) data from buffer to mbuf data
diff --git a/test/test/test_cryptodev_aes_test_vectors.h b/test/test/test_cryptodev_aes_test_vectors.h
index e410018..0af50fd 100644
--- a/test/test/test_cryptodev_aes_test_vectors.h
+++ b/test/test/test_cryptodev_aes_test_vectors.h
@@ -1197,7 +1197,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CTR HMAC-SHA1 Decryption Digest "
@@ -1208,7 +1209,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-192-CTR XCBC Encryption Digest",
@@ -1245,7 +1247,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-256-CTR HMAC-SHA1 Decryption Digest "
@@ -1256,7 +1259,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest",
@@ -1267,14 +1271,16 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest "
 			"(short buffers)",
 		.test_data = &aes_test_data_13,
 		.op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest "
@@ -1298,14 +1304,16 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Decryption Digest "
 			"Verify (short buffers)",
 		.test_data = &aes_test_data_13,
 		.op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA256 Encryption Digest",
@@ -1316,14 +1324,16 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA256 Encryption Digest "
 			"(short buffers)",
 		.test_data = &aes_test_data_12,
 		.op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA256 Decryption Digest "
@@ -1335,14 +1345,16 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA256 Decryption Digest "
 			"Verify (short buffers)",
 		.test_data = &aes_test_data_12,
 		.op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA512 Encryption Digest",
@@ -1352,7 +1364,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA512 Encryption Digest "
@@ -1383,7 +1396,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA512 Decryption Digest "
@@ -1462,7 +1476,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA384 Decryption Digest "
@@ -1473,7 +1488,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest "
@@ -1505,7 +1521,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC Decryption",
@@ -1515,7 +1532,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-192-CBC Encryption",
@@ -1553,7 +1571,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-256-CBC Decryption",
@@ -1563,7 +1582,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-256-CBC OOP Encryption",
@@ -1589,7 +1609,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CTR Decryption",
@@ -1599,7 +1620,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-192-CTR Encryption",
@@ -1629,7 +1651,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-256-CTR Decryption",
@@ -1639,7 +1662,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CTR Encryption (12-byte IV)",
diff --git a/test/test/test_cryptodev_blockcipher.c b/test/test/test_cryptodev_blockcipher.c
index 6089af4..01fe136 100644
--- a/test/test/test_cryptodev_blockcipher.c
+++ b/test/test/test_cryptodev_blockcipher.c
@@ -92,6 +92,8 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 			RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD));
 	int dpaa2_sec_pmd = rte_cryptodev_driver_id_get(
 			RTE_STR(CRYPTODEV_NAME_DPAA2_SEC_PMD));
+	int mrvl_pmd = rte_cryptodev_driver_id_get(
+			RTE_STR(CRYPTODEV_NAME_MRVL_PMD));
 
 	int nb_segs = 1;
 
@@ -116,7 +118,8 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 	if (driver_id == dpaa2_sec_pmd ||
 			driver_id == qat_pmd ||
 			driver_id == openssl_pmd ||
-			driver_id == armv8_pmd) { /* Fall through */
+			driver_id == armv8_pmd ||
+			driver_id == mrvl_pmd) { /* Fall through */
 		digest_len = tdata->digest.len;
 	} else if (driver_id == aesni_mb_pmd ||
 			driver_id == scheduler_pmd) {
@@ -612,6 +615,8 @@ test_blockcipher_all_tests(struct rte_mempool *mbuf_pool,
 			RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD));
 	int qat_pmd = rte_cryptodev_driver_id_get(
 			RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD));
+	int mrvl_pmd = rte_cryptodev_driver_id_get(
+			RTE_STR(CRYPTODEV_NAME_MRVL_PMD));
 
 	switch (test_type) {
 	case BLKCIPHER_AES_CHAIN_TYPE:
@@ -670,6 +675,8 @@ test_blockcipher_all_tests(struct rte_mempool *mbuf_pool,
 		target_pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER;
 	else if (driver_id == dpaa2_pmd)
 		target_pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC;
+	else if (driver_id == mrvl_pmd)
+		target_pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MRVL;
 	else
 		TEST_ASSERT(0, "Unrecognized cryptodev type");
 
diff --git a/test/test/test_cryptodev_blockcipher.h b/test/test/test_cryptodev_blockcipher.h
index 22b8d20..6919336 100644
--- a/test/test/test_cryptodev_blockcipher.h
+++ b/test/test/test_cryptodev_blockcipher.h
@@ -53,6 +53,7 @@
 #define BLOCKCIPHER_TEST_TARGET_PMD_ARMV8	0x0008 /* ARMv8 flag */
 #define BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER	0x0010 /* Scheduler */
 #define BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC	0x0020 /* DPAA2_SEC flag */
+#define BLOCKCIPHER_TEST_TARGET_PMD_MRVL	0x0040 /* Marvell flag */
 
 #define BLOCKCIPHER_TEST_OP_CIPHER	(BLOCKCIPHER_TEST_OP_ENCRYPT | \
 					BLOCKCIPHER_TEST_OP_DECRYPT)
diff --git a/test/test/test_cryptodev_des_test_vectors.h b/test/test/test_cryptodev_des_test_vectors.h
index 0b6e0b8..ffcf657 100644
--- a/test/test/test_cryptodev_des_test_vectors.h
+++ b/test/test/test_cryptodev_des_test_vectors.h
@@ -851,13 +851,15 @@ static const struct blockcipher_test_case des_cipheronly_test_cases[] = {
 		.test_descr = "DES-CBC Encryption",
 		.test_data = &des_cbc_test_vector,
 		.op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "DES-CBC Decryption",
 		.test_data = &des_cbc_test_vector,
 		.op_mask = BLOCKCIPHER_TEST_OP_DECRYPT,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 
 };
@@ -1087,7 +1089,8 @@ static const struct blockcipher_test_case triple_des_chain_test_cases[] = {
 		.op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
 		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-192-CBC HMAC-SHA1 Decryption Digest Verify",
@@ -1095,19 +1098,22 @@ static const struct blockcipher_test_case triple_des_chain_test_cases[] = {
 		.op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC,
 		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-192-CBC SHA1 Encryption Digest",
 		.test_data = &triple_des192cbc_sha1_test_vector,
 		.op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-192-CBC SHA1 Decryption Digest Verify",
 		.test_data = &triple_des192cbc_sha1_test_vector,
 		.op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-128-CTR HMAC-SHA1 Encryption Digest",
@@ -1220,7 +1226,8 @@ static const struct blockcipher_test_case triple_des_cipheronly_test_cases[] = {
 		.op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT,
 		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-192-CBC Decryption",
@@ -1228,7 +1235,8 @@ static const struct blockcipher_test_case triple_des_cipheronly_test_cases[] = {
 		.op_mask = BLOCKCIPHER_TEST_OP_DECRYPT,
 		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-128-CTR Encryption",
-- 
2.7.4

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

* [PATCH v4 00/16] add net mrvl pmd driver
  2017-10-03 11:51     ` [PATCH v3 0/4] add net mrvl pmd driver Tomasz Duszynski
                         ` (3 preceding siblings ...)
  2017-10-03 11:51       ` [PATCH v3 4/4] maintainers: add maintainers for the mrvl net pmd Tomasz Duszynski
@ 2017-10-09 15:00       ` Tomasz Duszynski
  2017-10-09 15:00         ` [PATCH v4 01/16] app: link the whole rte_cfgfile library Tomasz Duszynski
                           ` (16 more replies)
  4 siblings, 17 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-09 15:00 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski

Hello,

This patch series introduces the net driver for Marvell Armada 7k/8k
SoCs along with documentation.

Below you can find the list of features which net pmd supports:
* Speed capabilities
* Link status
* MTU update
* Jumbo frame
* Promiscuous mode
* Allmulticast mode
* Unicast MAC filter
* Multicast MAC filter
* RSS hash
* VLAN filter
* CRC offload
* L3 checksum offload
* L4 checksum offload
* Packet type parsing
* Basic stats
* QoS

Changes since v3:
* Split driver into skeleton, rx/tx, features, documentation parts
* Added speed capabilities flags.
* Added missing rx offload flags: VLAN/JUMBOFRAME
* Updated release notes.
* Updated documentation.

Changes since v2:
* Removed LINE_SPACING, MULTILINE_DEREFERENCE and SPLIT_STRING
  checkpatch warnings.
* Removed unnecessary forward declarations.
* Fixed whitespace warnings.

Changes since v1:
* Changed commit message to explain problem better.
* Removed bunch of checkpatch warnings about unnecessary parentheses.

Tomasz Duszynski (4):
  app: link the whole rte_cfgfile library
  net/mrvl: add mrvl net pmd driver skeleton
  net/mrvl: add rx/tx support
  net/mrvl: add link update
  net/mrvl: add link speed capabilities
  net/mrvl: add support for updating mtu
  net/mrvl: add jumbo frame support
  net/mrvl: add support for promiscuous and allmulticast modes
  net/mrvl: add support for mac filtering
  net/mrvl: add rss hashing support
  net/mrvl: add support for vlan filtering
  net/mrvl: add crc, l3 and l4 offloads support
  net/mrvl: add packet type parsing support.
  net/mrvl: add basic stats support
  maintainers: add maintainers for the mrvl net pmd
  doc: add mrvl net pmd documentation

 MAINTAINERS                               |   10 +
 config/common_base                        |    7 +
 doc/guides/nics/features/mrvl.ini         |   23 +
 doc/guides/nics/index.rst                 |    1 +
 doc/guides/nics/mrvl.rst                  |  256 ++++
 doc/guides/rel_notes/release_17_11.rst    |    6 +
 drivers/net/Makefile                      |    8 +
 drivers/net/mrvl/Makefile                 |   63 +
 drivers/net/mrvl/mrvl_ethdev.c            | 2279 +++++++++++++++++++++++++++++
 drivers/net/mrvl/mrvl_ethdev.h            |  114 ++
 drivers/net/mrvl/mrvl_qos.c               |  633 ++++++++
 drivers/net/mrvl/mrvl_qos.h               |  112 ++
 drivers/net/mrvl/rte_pmd_mrvl_version.map |    3 +
 mk/rte.app.mk                             |    3 +-
 14 files changed, 3517 insertions(+), 1 deletion(-)
 create mode 100644 doc/guides/nics/features/mrvl.ini
 create mode 100644 doc/guides/nics/mrvl.rst
 create mode 100644 drivers/net/mrvl/Makefile
 create mode 100644 drivers/net/mrvl/mrvl_ethdev.c
 create mode 100644 drivers/net/mrvl/mrvl_ethdev.h
 create mode 100644 drivers/net/mrvl/mrvl_qos.c
 create mode 100644 drivers/net/mrvl/mrvl_qos.h
 create mode 100644 drivers/net/mrvl/rte_pmd_mrvl_version.map

--
2.7.4

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

* [PATCH v4 01/16] app: link the whole rte_cfgfile library
  2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
@ 2017-10-09 15:00         ` Tomasz Duszynski
  2017-10-09 15:00         ` [PATCH v4 02/16] net/mrvl: add mrvl net pmd driver skeleton Tomasz Duszynski
                           ` (15 subsequent siblings)
  16 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-09 15:00 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

MRVL net pmd needs rte_cfgfile to parse QoS configuration file thus
librte_pmd_mrvl.a contains undefined symbols from librte_cfgfile.a.

As a result linking applications under app/ directory will fail
because librte_cfgfile.a comes before librte_pmd_mrvl.a during
the linking stage.

Linking the whole librte_cfgfile.a solves the issue.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 mk/rte.app.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index a788be2..4891bc2 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -81,10 +81,10 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)          += -lrte_power
 
 _LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)            += -lrte_efd
-_LDLIBS-$(CONFIG_RTE_LIBRTE_CFGFILE)        += -lrte_cfgfile
 
 _LDLIBS-y += --whole-archive
 
+_LDLIBS-$(CONFIG_RTE_LIBRTE_CFGFILE)        += -lrte_cfgfile
 _LDLIBS-$(CONFIG_RTE_LIBRTE_HASH)           += -lrte_hash
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMBER)         += -lrte_member
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VHOST)          += -lrte_vhost
-- 
2.7.4

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

* [PATCH v4 02/16] net/mrvl: add mrvl net pmd driver skeleton
  2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
  2017-10-09 15:00         ` [PATCH v4 01/16] app: link the whole rte_cfgfile library Tomasz Duszynski
@ 2017-10-09 15:00         ` Tomasz Duszynski
  2017-10-11 13:38           ` Thomas Monjalon
  2017-10-09 15:00         ` [PATCH v4 03/16] net/mrvl: add rx/tx support Tomasz Duszynski
                           ` (14 subsequent siblings)
  16 siblings, 1 reply; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-09 15:00 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add mrvl net pmd driver skeleton providing base for the further
development. Besides the basic functionality QoS configuration is
introduced as well.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 config/common_base                        |    7 +
 doc/guides/rel_notes/release_17_11.rst    |    6 +
 drivers/net/Makefile                      |    8 +
 drivers/net/mrvl/Makefile                 |   63 ++
 drivers/net/mrvl/mrvl_ethdev.c            | 1112 +++++++++++++++++++++++++++++
 drivers/net/mrvl/mrvl_ethdev.h            |  100 +++
 drivers/net/mrvl/mrvl_qos.c               |  633 ++++++++++++++++
 drivers/net/mrvl/mrvl_qos.h               |  112 +++
 drivers/net/mrvl/rte_pmd_mrvl_version.map |    3 +
 mk/rte.app.mk                             |    1 +
 10 files changed, 2045 insertions(+)
 create mode 100644 drivers/net/mrvl/Makefile
 create mode 100644 drivers/net/mrvl/mrvl_ethdev.c
 create mode 100644 drivers/net/mrvl/mrvl_ethdev.h
 create mode 100644 drivers/net/mrvl/mrvl_qos.c
 create mode 100644 drivers/net/mrvl/mrvl_qos.h
 create mode 100644 drivers/net/mrvl/rte_pmd_mrvl_version.map

diff --git a/config/common_base b/config/common_base
index 22068c5..36c7f4c 100644
--- a/config/common_base
+++ b/config/common_base
@@ -260,6 +260,13 @@ CONFIG_RTE_LIBRTE_NFP_PMD=n
 CONFIG_RTE_LIBRTE_NFP_DEBUG=n
 
 #
+# Compile Marvell PMD driver
+#
+CONFIG_RTE_LIBRTE_MRVL_PMD=n
+CONFIG_RTE_LIBRTE_MRVL_DEBUG=n
+CONFIG_RTE_MRVL_MUSDK_DMA_MEMSIZE=41943040
+
+#
 # Compile burst-oriented Broadcom BNXT PMD driver
 #
 CONFIG_RTE_LIBRTE_BNXT_PMD=y
diff --git a/doc/guides/rel_notes/release_17_11.rst b/doc/guides/rel_notes/release_17_11.rst
index 6a75ae0..d9f6b4e 100644
--- a/doc/guides/rel_notes/release_17_11.rst
+++ b/doc/guides/rel_notes/release_17_11.rst
@@ -81,6 +81,12 @@ New Features
   See the :ref:`Membership Library <Member_Library>` documentation in
   the Programmers Guide document, for more information.
 
+* **Added a new driver for Marvell Armada 7k/8k devices.**
+
+  Added the new mrvl net driver for Marvell Armada 7k/8k devices. See the
+  "Network Interface Controller Drivers" document for more details on this new
+  driver.
+
 
 Resolved Issues
 ---------------
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index b28310b..3d3e0b3 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -75,6 +75,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4
 DEPDIRS-mlx4 = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5
 DEPDIRS-mlx5 = $(core-libs)
+DIRS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl
+DEPDIRS-mrvl = $(core-libs) librte_cfgfile
 DIRS-$(CONFIG_RTE_LIBRTE_NFP_PMD) += nfp
 DEPDIRS-nfp = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += bnxt
@@ -110,4 +112,10 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_VHOST) += vhost
 endif # $(CONFIG_RTE_LIBRTE_VHOST)
 DEPDIRS-vhost = $(core-libs) librte_vhost
 
+ifeq ($(CONFIG_RTE_LIBRTE_MRVL_PMD),y)
+ifeq ($(CONFIG_RTE_LIBRTE_CFGFILE),n)
+$(error "RTE_LIBRTE_CFGFILE must be enabled in configuration!")
+endif
+endif
+
 include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/drivers/net/mrvl/Makefile b/drivers/net/mrvl/Makefile
new file mode 100644
index 0000000..26fce18
--- /dev/null
+++ b/drivers/net/mrvl/Makefile
@@ -0,0 +1,63 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2017 Semihalf. 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 Semihalf 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
+
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),config)
+ifeq ($(LIBMUSDK_PATH),)
+$(error "Please define LIBMUSDK_PATH environment variable")
+endif
+endif
+endif
+
+# library name
+LIB = librte_pmd_mrvl.a
+
+# library version
+LIBABIVER := 1
+
+# versioning export map
+EXPORT_MAP := rte_pmd_mrvl_version.map
+
+# external library dependencies
+CFLAGS += -I$(LIBMUSDK_PATH)/include
+CFLAGS += -DMVCONF_ARCH_DMA_ADDR_T_64BIT
+CFLAGS += -DCONF_PP2_BPOOL_COOKIE_SIZE=32
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -O3
+LDLIBS += -L$(LIBMUSDK_PATH)/lib
+LDLIBS += -lmusdk
+
+# library source files
+SRCS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_MRVL_PMD) += mrvl_qos.c
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/mrvl/mrvl_ethdev.c b/drivers/net/mrvl/mrvl_ethdev.c
new file mode 100644
index 0000000..1e730c6
--- /dev/null
+++ b/drivers/net/mrvl/mrvl_ethdev.c
@@ -0,0 +1,1112 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Semihalf. 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 Semihalf 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_ethdev.h>
+#include <rte_kvargs.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_vdev.h>
+
+/* Unluckily, container_of is defined by both DPDK and MUSDK,
+ * we'll declare only one version.
+ *
+ * Note that it is not used in this PMD anyway.
+ */
+#ifdef container_of
+#undef container_of
+#endif
+
+#include <drivers/mv_pp2.h>
+#include <drivers/mv_pp2_bpool.h>
+#include <drivers/mv_pp2_hif.h>
+
+#include <fcntl.h>
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "mrvl_ethdev.h"
+#include "mrvl_qos.h"
+
+/* bitmask with reserved hifs */
+#define MRVL_MUSDK_HIFS_RESERVED 0x0F
+/* bitmask with reserved bpools */
+#define MRVL_MUSDK_BPOOLS_RESERVED 0x07
+/* maximum number of available hifs */
+#define MRVL_MUSDK_HIFS_MAX 9
+
+#define MRVL_MAC_ADDRS_MAX 1
+#define MRVL_MATCH_LEN 16
+#define MRVL_PKT_EFFEC_OFFS (MRVL_PKT_OFFS + MV_MH_SIZE)
+/* Maximum allowable packet size */
+#define MRVL_PKT_SIZE_MAX (10240 - MV_MH_SIZE)
+
+#define MRVL_IFACE_NAME_ARG "iface"
+#define MRVL_CFG_ARG "cfg"
+
+#define MRVL_BURST_SIZE 64
+
+#define MRVL_ARP_LENGTH 28
+
+#define MRVL_COOKIE_ADDR_INVALID ~0ULL
+
+#define MRVL_COOKIE_HIGH_ADDR_SHIFT	(sizeof(pp2_cookie_t) * 8)
+#define MRVL_COOKIE_HIGH_ADDR_MASK	(~0ULL << MRVL_COOKIE_HIGH_ADDR_SHIFT)
+
+static const char * const valid_args[] = {
+	MRVL_IFACE_NAME_ARG,
+	MRVL_CFG_ARG,
+	NULL
+};
+
+static int used_hifs = MRVL_MUSDK_HIFS_RESERVED;
+static struct pp2_hif *hifs[RTE_MAX_LCORE];
+static int used_bpools[PP2_NUM_PKT_PROC] = {
+	MRVL_MUSDK_BPOOLS_RESERVED,
+	MRVL_MUSDK_BPOOLS_RESERVED
+};
+
+uint64_t cookie_addr_high = MRVL_COOKIE_ADDR_INVALID;
+
+struct mrvl_rxq {
+	struct mrvl_priv *priv;
+	struct rte_mempool *mp;
+	int queue_id;
+	int port_id;
+};
+
+struct mrvl_txq {
+	struct mrvl_priv *priv;
+	int queue_id;
+	int port_id;
+};
+
+/** Number of ports configured. */
+int mrvl_ports_nb;
+
+static inline int
+mrvl_reserve_bit(int *bitmap, int max)
+{
+	int n = sizeof(*bitmap) * 8 - __builtin_clz(*bitmap);
+
+	if (n >= max)
+		return -1;
+
+	*bitmap |= 1 << n;
+
+	return n;
+}
+
+/**
+ * Ethernet device configuration.
+ *
+ * Prepare the driver for a given number of TX and RX queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_dev_configure(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	if (dev->data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_NONE) {
+		RTE_LOG(INFO, PMD, "Unsupported rx multi queue mode %d\n",
+			dev->data->dev_conf.rxmode.mq_mode);
+		return -EINVAL;
+	}
+
+	if (!dev->data->dev_conf.rxmode.hw_strip_crc) {
+		RTE_LOG(INFO, PMD,
+			"L2 CRC stripping is always enabled in hw\n");
+		dev->data->dev_conf.rxmode.hw_strip_crc = 1;
+	}
+
+	if (dev->data->dev_conf.rxmode.hw_vlan_strip) {
+		RTE_LOG(INFO, PMD, "VLAN stripping not supported\n");
+		return -EINVAL;
+	}
+
+	if (dev->data->dev_conf.rxmode.split_hdr_size) {
+		RTE_LOG(INFO, PMD, "Split headers not supported\n");
+		return -EINVAL;
+	}
+
+	if (dev->data->dev_conf.rxmode.enable_scatter) {
+		RTE_LOG(INFO, PMD, "RX Scatter/Gather not supported\n");
+		return -EINVAL;
+	}
+
+	if (dev->data->dev_conf.rxmode.enable_lro) {
+		RTE_LOG(INFO, PMD, "LRO not supported\n");
+		return -EINVAL;
+	}
+
+	ret = mrvl_configure_rxqs(priv, dev->data->port_id,
+				  dev->data->nb_rx_queues);
+	if (ret < 0)
+		return ret;
+
+	priv->ppio_params.outqs_params.num_outqs = dev->data->nb_tx_queues;
+	priv->nb_rx_queues = dev->data->nb_rx_queues;
+
+	return 0;
+}
+
+/**
+ * DPDK callback to bring the link up.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_dev_set_link_up(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_enable(priv->ppio);
+	if (ret)
+		return ret;
+
+	dev->data->dev_link.link_status = ETH_LINK_UP;
+
+	return ret;
+}
+
+/**
+ * DPDK callback to bring the link down.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_dev_set_link_down(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_disable(priv->ppio);
+	if (ret)
+		return ret;
+
+	dev->data->dev_link.link_status = ETH_LINK_DOWN;
+
+	return ret;
+}
+
+/**
+ * DPDK callback to start the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, negative errno value on failure.
+ */
+static int
+mrvl_dev_start(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	char match[MRVL_MATCH_LEN];
+	int ret;
+
+	snprintf(match, sizeof(match), "ppio-%d:%d",
+		 priv->pp_id, priv->ppio_id);
+	priv->ppio_params.match = match;
+
+	/*
+	 * Calculate the maximum bpool size for refill feature to 1.5 of the
+	 * configured size. In case the bpool size will exceed this value,
+	 * superfluous buffers will be removed
+	 */
+	priv->bpool_max_size = priv->bpool_init_size +
+			      (priv->bpool_init_size >> 1);
+	/*
+	 * Calculate the minimum bpool size for refill feature as follows:
+	 * 2 default burst sizes multiply by number of rx queues.
+	 * If the bpool size will be below this value, new buffers will
+	 * be added to the pool.
+	 */
+	priv->bpool_min_size = priv->nb_rx_queues * MRVL_BURST_SIZE * 2;
+
+	ret = pp2_ppio_init(&priv->ppio_params, &priv->ppio);
+	if (ret)
+		return ret;
+
+	/* For default QoS config, don't start classifier. */
+	if (mrvl_qos_cfg) {
+		ret = mrvl_start_qos_mapping(priv);
+		if (ret) {
+			pp2_ppio_deinit(priv->ppio);
+			return ret;
+		}
+	}
+
+	ret = mrvl_dev_set_link_up(dev);
+	if (ret)
+		goto out;
+
+	return 0;
+out:
+	pp2_ppio_deinit(priv->ppio);
+	return ret;
+}
+
+/**
+ * Flush receive queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_flush_rx_queues(struct rte_eth_dev *dev)
+{
+	int i;
+
+	RTE_LOG(INFO, PMD, "Flushing rx queues\n");
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		int ret, num;
+
+		do {
+			struct mrvl_rxq *q = dev->data->rx_queues[i];
+			struct pp2_ppio_desc descs[MRVL_PP2_RXD_MAX];
+
+			num = MRVL_PP2_RXD_MAX;
+			ret = pp2_ppio_recv(q->priv->ppio,
+					    q->priv->rxq_map[q->queue_id].tc,
+					    q->priv->rxq_map[q->queue_id].inq,
+					    descs, (uint16_t *)&num);
+		} while (ret == 0 && num);
+	}
+}
+
+/**
+ * Flush hardware bpool (buffer-pool).
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_flush_bpool(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	uint32_t num;
+	int ret;
+
+	ret = pp2_bpool_get_num_buffs(priv->bpool, &num);
+	if (ret) {
+		RTE_LOG(ERR, PMD, "Failed to get bpool buffers number\n");
+		return;
+	}
+
+	while (num--) {
+		struct pp2_buff_inf inf;
+		uint64_t addr;
+
+		ret = pp2_bpool_get_buff(hifs[rte_lcore_id()], priv->bpool,
+					 &inf);
+		if (ret)
+			break;
+
+		addr = cookie_addr_high | inf.cookie;
+		rte_pktmbuf_free((struct rte_mbuf *)addr);
+	}
+}
+
+/**
+ * DPDK callback to stop the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_dev_stop(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	mrvl_dev_set_link_down(dev);
+	mrvl_flush_rx_queues(dev);
+	if (priv->qos_tbl)
+		pp2_cls_qos_tbl_deinit(priv->qos_tbl);
+	pp2_ppio_deinit(priv->ppio);
+	priv->ppio = NULL;
+}
+
+/**
+ * DPDK callback to close the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_dev_close(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	size_t i;
+
+	for (i = 0; i < priv->ppio_params.inqs_params.num_tcs; ++i) {
+		struct pp2_ppio_tc_params *tc_params =
+			&priv->ppio_params.inqs_params.tcs_params[i];
+
+		if (tc_params->inqs_params) {
+			rte_free(tc_params->inqs_params);
+			tc_params->inqs_params = NULL;
+		}
+	}
+
+	mrvl_flush_bpool(dev);
+}
+
+/**
+ * DPDK callback to set the primary MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ */
+static void
+mrvl_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	pp2_ppio_set_mac_addr(priv->ppio, mac_addr->addr_bytes);
+	/*
+	 * TODO
+	 * Port stops sending packets if pp2_ppio_set_mac_addr()
+	 * was called after pp2_ppio_enable(). As a quick fix issue
+	 * enable port once again.
+	 */
+	pp2_ppio_enable(priv->ppio);
+}
+
+/**
+ * DPDK callback to get information about the device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure (unused).
+ * @param info
+ *   Info structure output buffer.
+ */
+static void
+mrvl_dev_infos_get(struct rte_eth_dev *dev __rte_unused,
+		   struct rte_eth_dev_info *info)
+{
+	info->max_rx_queues = MRVL_PP2_RXQ_MAX;
+	info->max_tx_queues = MRVL_PP2_TXQ_MAX;
+	info->max_mac_addrs = MRVL_MAC_ADDRS_MAX;
+
+	info->rx_desc_lim.nb_max = MRVL_PP2_RXD_MAX;
+	info->rx_desc_lim.nb_min = MRVL_PP2_RXD_MIN;
+	info->rx_desc_lim.nb_align = MRVL_PP2_RXD_ALIGN;
+
+	info->tx_desc_lim.nb_max = MRVL_PP2_TXD_MAX;
+	info->tx_desc_lim.nb_min = MRVL_PP2_TXD_MIN;
+	info->tx_desc_lim.nb_align = MRVL_PP2_TXD_ALIGN;
+
+	/* By default packets are dropped if no descriptors are available */
+	info->default_rxconf.rx_drop_en = 1;
+
+	info->max_rx_pktlen = MRVL_PKT_SIZE_MAX;
+}
+
+/**
+ * DPDK callback to get information about specific receive queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param rx_queue_id
+ *   Receive queue index.
+ * @param qinfo
+ *   Receive queue information structure.
+ */
+static void mrvl_rxq_info_get(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+			      struct rte_eth_rxq_info *qinfo)
+{
+	struct mrvl_rxq *q = dev->data->rx_queues[rx_queue_id];
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int inq = priv->rxq_map[rx_queue_id].inq;
+	int tc = priv->rxq_map[rx_queue_id].tc;
+	struct pp2_ppio_tc_params *tc_params =
+		&priv->ppio_params.inqs_params.tcs_params[tc];
+
+	qinfo->mp = q->mp;
+	qinfo->nb_desc = tc_params->inqs_params[inq].size;
+}
+
+/**
+ * DPDK callback to get information about specific transmit queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param tx_queue_id
+ *   Transmit queue index.
+ * @param qinfo
+ *   Transmit queue information structure.
+ */
+static void mrvl_txq_info_get(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+			      struct rte_eth_txq_info *qinfo)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	qinfo->nb_desc =
+		priv->ppio_params.outqs_params.outqs_params[tx_queue_id].size;
+}
+
+/**
+ * Release buffers to hardware bpool (buffer-pool)
+ *
+ * @param rxq
+ *   Receive queue pointer.
+ * @param num
+ *   Number of buffers to release to bpool.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_fill_bpool(struct mrvl_rxq *rxq, int num)
+{
+	struct buff_release_entry entries[MRVL_PP2_TXD_MAX];
+	struct rte_mbuf *mbufs[MRVL_PP2_TXD_MAX];
+	int i, ret;
+	unsigned int core_id = rte_lcore_id();
+	struct pp2_hif *hif = hifs[core_id];
+	struct pp2_bpool *bpool = rxq->priv->bpool;
+
+	ret = rte_pktmbuf_alloc_bulk(rxq->mp, mbufs, num);
+	if (ret)
+		return ret;
+
+	if (cookie_addr_high == MRVL_COOKIE_ADDR_INVALID)
+		cookie_addr_high =
+			(uint64_t)mbufs[0] & MRVL_COOKIE_HIGH_ADDR_MASK;
+
+	for (i = 0; i < num; i++) {
+		if (((uint64_t)mbufs[i] & MRVL_COOKIE_HIGH_ADDR_MASK)
+			!= cookie_addr_high) {
+			RTE_LOG(ERR, PMD,
+				"mbuf virtual addr high 0x%lx out of range\n",
+				(uint64_t)mbufs[i] >> 32);
+			goto out;
+		}
+
+		entries[i].buff.addr =
+			rte_mbuf_data_dma_addr_default(mbufs[i]);
+		entries[i].buff.cookie = (pp2_cookie_t)(uint64_t)mbufs[i];
+		entries[i].bpool = bpool;
+	}
+
+	pp2_bpool_put_buffs(hif, entries, (uint16_t *)&i);
+
+	if (i != num)
+		goto out;
+
+	return 0;
+out:
+	for (; i < num; i++)
+		rte_pktmbuf_free(mbufs[i]);
+
+	return -1;
+}
+
+/**
+ * DPDK callback to configure the receive queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   RX queue index.
+ * @param desc
+ *   Number of descriptors to configure in queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param conf
+ *   Thresholds parameters (unused_).
+ * @param mp
+ *   Memory pool for buffer allocations.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
+		    unsigned int socket,
+		    const struct rte_eth_rxconf *conf __rte_unused,
+		    struct rte_mempool *mp)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_rxq *rxq;
+	uint32_t min_size,
+		 max_rx_pkt_len = dev->data->dev_conf.rxmode.max_rx_pkt_len;
+	int ret, tc, inq;
+
+	if (priv->rxq_map[idx].tc == MRVL_UNKNOWN_TC) {
+		/*
+		 * Unknown TC mapping, mapping will not have a correct queue.
+		 */
+		RTE_LOG(ERR, PMD, "Unknown TC mapping for queue %hu eth%hhu\n",
+			idx, priv->ppio_id);
+		return -EFAULT;
+	}
+
+	min_size = rte_pktmbuf_data_room_size(mp) - RTE_PKTMBUF_HEADROOM -
+		   MRVL_PKT_EFFEC_OFFS;
+	if (min_size < max_rx_pkt_len) {
+		RTE_LOG(ERR, PMD,
+			"Mbuf size must be increased to %u bytes to hold up to %u bytes of data.\n",
+			max_rx_pkt_len + RTE_PKTMBUF_HEADROOM +
+			MRVL_PKT_EFFEC_OFFS,
+			max_rx_pkt_len);
+		return -EINVAL;
+	}
+
+	if (dev->data->rx_queues[idx]) {
+		rte_free(dev->data->rx_queues[idx]);
+		dev->data->rx_queues[idx] = NULL;
+	}
+
+	rxq = rte_zmalloc_socket("rxq", sizeof(*rxq), 0, socket);
+	if (!rxq)
+		return -ENOMEM;
+
+	rxq->priv = priv;
+	rxq->mp = mp;
+	rxq->queue_id = idx;
+	rxq->port_id = dev->data->port_id;
+
+	tc = priv->rxq_map[rxq->queue_id].tc,
+	inq = priv->rxq_map[rxq->queue_id].inq;
+	priv->ppio_params.inqs_params.tcs_params[tc].inqs_params[inq].size =
+		desc;
+
+	ret = mrvl_fill_bpool(rxq, desc);
+	if (ret) {
+		rte_free(rxq);
+		return ret;
+	}
+
+	priv->bpool_init_size += desc;
+
+	dev->data->rx_queues[idx] = rxq;
+
+	return 0;
+}
+
+/**
+ * DPDK callback to release the receive queue.
+ *
+ * @param rxq
+ *   Generic receive queue pointer.
+ */
+static void
+mrvl_rx_queue_release(void *rxq)
+{
+	struct mrvl_rxq *q = rxq;
+	struct pp2_ppio_tc_params *tc_params;
+	int i, num, tc, inq;
+
+	if (!q)
+		return;
+
+	tc = q->priv->rxq_map[q->queue_id].tc;
+	inq = q->priv->rxq_map[q->queue_id].inq;
+	tc_params = &q->priv->ppio_params.inqs_params.tcs_params[tc];
+	num = tc_params->inqs_params[inq].size;
+	for (i = 0; i < num; i++) {
+		struct pp2_buff_inf inf;
+		uint64_t addr;
+
+		pp2_bpool_get_buff(hifs[rte_lcore_id()], q->priv->bpool, &inf);
+		addr = cookie_addr_high | inf.cookie;
+		rte_pktmbuf_free((struct rte_mbuf *)addr);
+	}
+
+	rte_free(q);
+}
+
+/**
+ * DPDK callback to configure the transmit queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param idx
+ *   Transmit queue index.
+ * @param desc
+ *   Number of descriptors to configure in the queue.
+ * @param socket
+ *   NUMA socket on which memory must be allocated.
+ * @param conf
+ *   Thresholds parameters (unused).
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
+		    unsigned int socket,
+		    const struct rte_eth_txconf *conf __rte_unused)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct mrvl_txq *txq;
+
+	if (dev->data->tx_queues[idx]) {
+		rte_free(dev->data->tx_queues[idx]);
+		dev->data->tx_queues[idx] = NULL;
+	}
+
+	txq = rte_zmalloc_socket("txq", sizeof(*txq), 0, socket);
+	if (!txq)
+		return -ENOMEM;
+
+	txq->priv = priv;
+	txq->queue_id = idx;
+	txq->port_id = dev->data->port_id;
+	dev->data->tx_queues[idx] = txq;
+
+	priv->ppio_params.outqs_params.outqs_params[idx].size = desc;
+	priv->ppio_params.outqs_params.outqs_params[idx].weight = 1;
+
+	return 0;
+}
+
+/**
+ * DPDK callback to release the transmit queue.
+ *
+ * @param txq
+ *   Generic transmit queue pointer.
+ */
+static void
+mrvl_tx_queue_release(void *txq)
+{
+	struct mrvl_txq *q = txq;
+
+	if (!q)
+		return;
+
+	rte_free(q);
+}
+
+static const struct eth_dev_ops mrvl_ops = {
+	.dev_configure = mrvl_dev_configure,
+	.dev_start = mrvl_dev_start,
+	.dev_stop = mrvl_dev_stop,
+	.dev_set_link_up = mrvl_dev_set_link_up,
+	.dev_set_link_down = mrvl_dev_set_link_down,
+	.dev_close = mrvl_dev_close,
+	.mac_addr_set = mrvl_mac_addr_set,
+	.dev_infos_get = mrvl_dev_infos_get,
+	.rxq_info_get = mrvl_rxq_info_get,
+	.txq_info_get = mrvl_txq_info_get,
+	.rx_queue_setup = mrvl_rx_queue_setup,
+	.rx_queue_release = mrvl_rx_queue_release,
+	.tx_queue_setup = mrvl_tx_queue_setup,
+	.tx_queue_release = mrvl_tx_queue_release,
+};
+
+/**
+ * Initialize packet processor.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_init_pp2(void)
+{
+	struct pp2_init_params init_params;
+
+	memset(&init_params, 0, sizeof(init_params));
+	init_params.hif_reserved_map = MRVL_MUSDK_HIFS_RESERVED;
+	init_params.bm_pool_reserved_map = MRVL_MUSDK_BPOOLS_RESERVED;
+
+	return pp2_init(&init_params);
+}
+
+/**
+ * Deinitialize packet processor.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static void
+mrvl_deinit_pp2(void)
+{
+	pp2_deinit();
+}
+
+/**
+ * Create private device structure.
+ *
+ * @param dev_name
+ *   Pointer to the port name passed in the initialization parameters.
+ *
+ * @return
+ *   Pointer to the newly allocated private device structure.
+ */
+static struct mrvl_priv *
+mrvl_priv_create(const char *dev_name)
+{
+	struct pp2_bpool_params bpool_params;
+	char match[MRVL_MATCH_LEN];
+	struct mrvl_priv *priv;
+	int ret, bpool_bit;
+
+	priv = rte_zmalloc_socket(dev_name, sizeof(*priv), 0, rte_socket_id());
+	if (!priv)
+		return NULL;
+
+	ret = pp2_netdev_get_ppio_info((char *)(uintptr_t)dev_name,
+				       &priv->pp_id, &priv->ppio_id);
+	if (ret)
+		goto out_free_priv;
+
+	bpool_bit = mrvl_reserve_bit(&used_bpools[priv->pp_id],
+				     PP2_BPOOL_NUM_POOLS);
+	if (bpool_bit < 0)
+		goto out_free_priv;
+	priv->bpool_bit = bpool_bit;
+
+	snprintf(match, sizeof(match), "pool-%d:%d", priv->pp_id,
+		 priv->bpool_bit);
+	memset(&bpool_params, 0, sizeof(bpool_params));
+	bpool_params.match = match;
+	bpool_params.buff_len = MRVL_PKT_SIZE_MAX + MRVL_PKT_EFFEC_OFFS;
+	ret = pp2_bpool_init(&bpool_params, &priv->bpool);
+	if (ret)
+		goto out_clear_bpool_bit;
+
+	priv->ppio_params.type = PP2_PPIO_T_NIC;
+
+	return priv;
+out_clear_bpool_bit:
+	used_bpools[priv->pp_id] &= ~(1 << priv->bpool_bit);
+out_free_priv:
+	rte_free(priv);
+	return NULL;
+}
+
+/**
+ * Create device representing Ethernet port.
+ *
+ * @param name
+ *   Pointer to the port's name.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_eth_dev_create(struct rte_vdev_device *vdev, const char *name)
+{
+	int ret, fd = socket(AF_INET, SOCK_DGRAM, 0);
+	struct rte_eth_dev *eth_dev;
+	struct mrvl_priv *priv;
+	struct ifreq req;
+
+	eth_dev = rte_eth_dev_allocate(name);
+	if (!eth_dev)
+		return -ENOMEM;
+
+	priv = mrvl_priv_create(name);
+	if (!priv) {
+		ret = -ENOMEM;
+		goto out_free_dev;
+	}
+
+	eth_dev->data->mac_addrs =
+		rte_zmalloc("mac_addrs",
+			    ETHER_ADDR_LEN * MRVL_MAC_ADDRS_MAX, 0);
+	if (!eth_dev->data->mac_addrs) {
+		RTE_LOG(ERR, PMD, "Failed to allocate space for eth addrs\n");
+		ret = -ENOMEM;
+		goto out_free_priv;
+	}
+
+	memset(&req, 0, sizeof(req));
+	strcpy(req.ifr_name, name);
+	ret = ioctl(fd, SIOCGIFHWADDR, &req);
+	if (ret)
+		goto out_free_mac;
+
+	memcpy(eth_dev->data->mac_addrs[0].addr_bytes,
+	       req.ifr_addr.sa_data, ETHER_ADDR_LEN);
+
+	eth_dev->data->dev_private = priv;
+	eth_dev->device = &vdev->device;
+	eth_dev->dev_ops = &mrvl_ops;
+
+	return 0;
+out_free_mac:
+	rte_free(eth_dev->data->mac_addrs);
+out_free_dev:
+	rte_eth_dev_release_port(eth_dev);
+out_free_priv:
+	rte_free(priv);
+
+	return ret;
+}
+
+/**
+ * Cleanup previously created device representing Ethernet port.
+ *
+ * @param name
+ *   Pointer to the port name.
+ */
+static void
+mrvl_eth_dev_destroy(const char *name)
+{
+	struct rte_eth_dev *eth_dev;
+	struct mrvl_priv *priv;
+
+	eth_dev = rte_eth_dev_allocated(name);
+	if (!eth_dev)
+		return;
+
+	priv = eth_dev->data->dev_private;
+	pp2_bpool_deinit(priv->bpool);
+	rte_free(priv);
+	rte_free(eth_dev->data->mac_addrs);
+	rte_eth_dev_release_port(eth_dev);
+}
+
+/**
+ * Callback used by rte_kvargs_process() during argument parsing.
+ *
+ * @param key
+ *   Pointer to the parsed key (unused).
+ * @param value
+ *   Pointer to the parsed value.
+ * @param extra_args
+ *   Pointer to the extra arguments which contains address of the
+ *   table of pointers to parsed interface names.
+ *
+ * @return
+ *   Always 0.
+ */
+static int
+mrvl_get_ifnames(const char *key __rte_unused, const char *value,
+		 void *extra_args)
+{
+	const char **ifnames = extra_args;
+
+	ifnames[mrvl_ports_nb++] = value;
+
+	return 0;
+}
+
+/**
+ * Initialize per-lcore MUSDK hardware interfaces (hifs).
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_init_hifs(void)
+{
+	struct pp2_hif_params params;
+	char match[MRVL_MATCH_LEN];
+	int i, ret;
+
+	RTE_LCORE_FOREACH(i) {
+		ret = mrvl_reserve_bit(&used_hifs, MRVL_MUSDK_HIFS_MAX);
+		if (ret < 0)
+			return ret;
+
+		snprintf(match, sizeof(match), "hif-%d", ret);
+		memset(&params, 0, sizeof(params));
+		params.match = match;
+		params.out_size = MRVL_PP2_AGGR_TXQD_MAX;
+		ret = pp2_hif_init(&params, &hifs[i]);
+		if (ret) {
+			RTE_LOG(ERR, PMD, "Failed to initialize hif %d\n", i);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Deinitialize per-lcore MUSDK hardware interfaces (hifs).
+ */
+static void
+mrvl_deinit_hifs(void)
+{
+	int i;
+
+	RTE_LCORE_FOREACH(i) {
+		if (hifs[i])
+			pp2_hif_deinit(hifs[i]);
+	}
+}
+
+/**
+ * DPDK callback to register the virtual device.
+ *
+ * @param vdev
+ *   Pointer to the virtual device.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+rte_pmd_mrvl_probe(struct rte_vdev_device *vdev)
+{
+	struct rte_kvargs *kvlist;
+	const char *ifnames[PP2_NUM_ETH_PPIO * PP2_NUM_PKT_PROC];
+	int ret = -EINVAL;
+	uint32_t i, ifnum, cfgnum;
+	const char *params;
+
+	params = rte_vdev_device_args(vdev);
+	if (!params)
+		return -EINVAL;
+
+	kvlist = rte_kvargs_parse(params, valid_args);
+	if (!kvlist)
+		return -EINVAL;
+
+	ifnum = rte_kvargs_count(kvlist, MRVL_IFACE_NAME_ARG);
+	if (ifnum > RTE_DIM(ifnames))
+		goto out_free_kvlist;
+
+	rte_kvargs_process(kvlist, MRVL_IFACE_NAME_ARG,
+			   mrvl_get_ifnames, &ifnames);
+
+	cfgnum = rte_kvargs_count(kvlist, MRVL_CFG_ARG);
+	if (cfgnum > 1) {
+		RTE_LOG(ERR, PMD, "Cannot handle more than one config file!\n");
+		goto out_free_kvlist;
+	} else if (cfgnum == 1) {
+		rte_kvargs_process(kvlist, MRVL_CFG_ARG,
+				   mrvl_get_qoscfg, &mrvl_qos_cfg);
+	}
+
+	/*
+	 * ret == -EEXIST is correct, it means DMA
+	 * has been already initialized (by another PMD).
+	 */
+	ret = mv_sys_dma_mem_init(RTE_MRVL_MUSDK_DMA_MEMSIZE);
+	if (ret < 0 && ret != -EEXIST)
+		goto out_free_kvlist;
+
+	ret = mrvl_init_pp2();
+	if (ret) {
+		RTE_LOG(ERR, PMD, "Failed to init PP!\n");
+		goto out_deinit_dma;
+	}
+
+	ret = mrvl_init_hifs();
+	if (ret)
+		goto out_deinit_hifs;
+
+	for (i = 0; i < ifnum; i++) {
+		RTE_LOG(INFO, PMD, "Creating %s\n", ifnames[i]);
+		ret = mrvl_eth_dev_create(vdev, ifnames[i]);
+		if (ret)
+			goto out_cleanup;
+	}
+
+	rte_kvargs_free(kvlist);
+
+	return 0;
+out_cleanup:
+	for (; i > 0; i--)
+		mrvl_eth_dev_destroy(ifnames[i]);
+out_deinit_hifs:
+	mrvl_deinit_hifs();
+	mrvl_deinit_pp2();
+out_deinit_dma:
+	mv_sys_dma_mem_destroy();
+out_free_kvlist:
+	rte_kvargs_free(kvlist);
+
+	return ret;
+}
+
+/**
+ * DPDK callback to remove virtual device.
+ *
+ * @param vdev
+ *   Pointer to the removed virtual device.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+rte_pmd_mrvl_remove(struct rte_vdev_device *vdev)
+{
+	int i;
+	const char *name;
+
+	name = rte_vdev_device_name(vdev);
+	if (!name)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Removing %s\n", name);
+
+	for (i = 0; i < rte_eth_dev_count(); i++) {
+		char ifname[RTE_ETH_NAME_MAX_LEN];
+
+		rte_eth_dev_get_name_by_port(i, ifname);
+		mrvl_eth_dev_destroy(ifname);
+	}
+
+	mrvl_deinit_hifs();
+	mrvl_deinit_pp2();
+	mv_sys_dma_mem_destroy();
+
+	return 0;
+}
+
+static struct rte_vdev_driver pmd_mrvl_drv = {
+	.probe = rte_pmd_mrvl_probe,
+	.remove = rte_pmd_mrvl_remove,
+};
+
+RTE_PMD_REGISTER_VDEV(net_mrvl, pmd_mrvl_drv);
+RTE_PMD_REGISTER_ALIAS(net_mrvl, eth_mrvl);
diff --git a/drivers/net/mrvl/mrvl_ethdev.h b/drivers/net/mrvl/mrvl_ethdev.h
new file mode 100644
index 0000000..626cfaa
--- /dev/null
+++ b/drivers/net/mrvl/mrvl_ethdev.h
@@ -0,0 +1,100 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Semihalf. 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 Semihalf 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 _MRVL_ETHDEV_H_
+#define _MRVL_ETHDEV_H_
+
+#include <drivers/mv_pp2_cls.h>
+#include <drivers/mv_pp2_ppio.h>
+
+/** Maximum number of rx queues per port */
+#define MRVL_PP2_RXQ_MAX 32
+
+/** Maximum number of tx queues per port */
+#define MRVL_PP2_TXQ_MAX 8
+
+/** Minimum number of descriptors in tx queue */
+#define MRVL_PP2_TXD_MIN 16
+
+/** Maximum number of descriptors in tx queue */
+#define MRVL_PP2_TXD_MAX 2048
+
+/** Tx queue descriptors alignment */
+#define MRVL_PP2_TXD_ALIGN 16
+
+/** Minimum number of descriptors in rx queue */
+#define MRVL_PP2_RXD_MIN 16
+
+/** Maximum number of descriptors in rx queue */
+#define MRVL_PP2_RXD_MAX 2048
+
+/** Rx queue descriptors alignment */
+#define MRVL_PP2_RXD_ALIGN 16
+
+/** Maximum number of descriptors in tx aggregated queue */
+#define MRVL_PP2_AGGR_TXQD_MAX 2048
+
+/** Maximum number of Traffic Classes. */
+#define MRVL_PP2_TC_MAX 8
+
+/** Packet offset inside RX buffer. */
+#define MRVL_PKT_OFFS 64
+
+struct mrvl_priv {
+	/* Hot fields, used in fast path. */
+	struct pp2_bpool *bpool;  /**< BPool pointer */
+	struct pp2_ppio	*ppio;    /**< Port handler pointer */
+	uint16_t bpool_max_size;  /**< BPool maximum size */
+	uint16_t bpool_min_size;  /**< BPool minimum size  */
+	uint16_t bpool_init_size; /**< Configured BPool size  */
+
+	/** Mapping for DPDK rx queue->(TC, MRVL relative inq) */
+	struct {
+		uint8_t tc;  /**< Traffic Class */
+		uint8_t inq; /**< Relative in-queue number */
+	} rxq_map[MRVL_PP2_RXQ_MAX] __rte_cache_aligned;
+
+	/* Configuration data, used sporadically. */
+	uint8_t pp_id;
+	uint8_t ppio_id;
+	uint8_t bpool_bit;
+
+	struct pp2_ppio_params ppio_params;
+	struct pp2_cls_qos_tbl_params qos_tbl_params;
+	struct pp2_cls_tbl *qos_tbl;
+	uint16_t nb_rx_queues;
+};
+
+/** Number of ports configured. */
+extern int mrvl_ports_nb;
+
+#endif /* _MRVL_ETHDEV_H_ */
diff --git a/drivers/net/mrvl/mrvl_qos.c b/drivers/net/mrvl/mrvl_qos.c
new file mode 100644
index 0000000..796509b
--- /dev/null
+++ b/drivers/net/mrvl/mrvl_qos.c
@@ -0,0 +1,633 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Semihalf. 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 Semihalf 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 <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_cfgfile.h>
+#include <rte_log.h>
+#include <rte_lcore.h>
+#include <rte_malloc.h>
+#include <rte_string_fns.h>
+
+/* Unluckily, container_of is defined by both DPDK and MUSDK,
+ * we'll declare only one version.
+ *
+ * Note that it is not used in this PMD anyway.
+ */
+#ifdef container_of
+#undef container_of
+#endif
+
+#include "mrvl_qos.h"
+
+/* Parsing tokens. Defined conveniently, so that any correction is easy. */
+#define MRVL_TOK_DEFAULT "default"
+#define MRVL_TOK_DEFAULT_TC "default_tc"
+#define MRVL_TOK_DSCP "dscp"
+#define MRVL_TOK_MAPPING_PRIORITY "mapping_priority"
+#define MRVL_TOK_IP "ip"
+#define MRVL_TOK_IP_VLAN "ip/vlan"
+#define MRVL_TOK_PCP "pcp"
+#define MRVL_TOK_PORT "port"
+#define MRVL_TOK_RXQ "rxq"
+#define MRVL_TOK_SP "SP"
+#define MRVL_TOK_TC "tc"
+#define MRVL_TOK_TXQ "txq"
+#define MRVL_TOK_VLAN "vlan"
+#define MRVL_TOK_VLAN_IP "vlan/ip"
+#define MRVL_TOK_WEIGHT "weight"
+
+/** Number of tokens in range a-b = 2. */
+#define MAX_RNG_TOKENS 2
+
+/** Maximum possible value of PCP. */
+#define MAX_PCP 7
+
+/** Maximum possible value of DSCP. */
+#define MAX_DSCP 63
+
+/** Global QoS configuration. */
+struct mrvl_qos_cfg *mrvl_qos_cfg;
+
+/**
+ * Convert string to uint32_t with extra checks for result correctness.
+ *
+ * @param string String to convert.
+ * @param val Conversion result.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+get_val_securely(const char *string, uint32_t *val)
+{
+	char *endptr;
+	size_t len = strlen(string);
+
+	if (len == 0)
+		return -1;
+
+	*val = strtoul(string, &endptr, 0);
+	if (errno != 0 || RTE_PTR_DIFF(endptr, string) != len)
+		return -2;
+
+	return 0;
+}
+
+/**
+ * Read out-queue configuration from file.
+ *
+ * @param file Path to the configuration file.
+ * @param port Port number.
+ * @param outq Out queue number.
+ * @param cfg Pointer to the Marvell QoS configuration structure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+get_outq_cfg(struct rte_cfgfile *file, int port, int outq,
+		struct mrvl_qos_cfg *cfg)
+{
+	char sec_name[32];
+	const char *entry;
+	uint32_t val;
+
+	snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
+		MRVL_TOK_PORT, port, MRVL_TOK_TXQ, outq);
+
+	/* Skip non-existing */
+	if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
+		return 0;
+
+	entry = rte_cfgfile_get_entry(file, sec_name,
+			MRVL_TOK_WEIGHT);
+	if (entry) {
+		if (get_val_securely(entry, &val) < 0)
+			return -1;
+		cfg->port[port].outq[outq].weight = (uint8_t)val;
+	}
+
+	return 0;
+}
+
+/**
+ * Gets multiple-entry values and places them in table.
+ *
+ * Entry can be anything, e.g. "1 2-3 5 6 7-9". This needs to be converted to
+ * table entries, respectively: {1, 2, 3, 5, 6, 7, 8, 9}.
+ * As all result table's elements are always 1-byte long, we
+ * won't overcomplicate the function, but we'll keep API generic,
+ * check if someone hasn't changed element size and make it simple
+ * to extend to other sizes.
+ *
+ * This function is purely utilitary, it does not print any error, only returns
+ * different error numbers.
+ *
+ * @param entry[in] Values string to parse.
+ * @param tab[out] Results table.
+ * @param elem_sz[in] Element size (in bytes).
+ * @param max_elems[in] Number of results table elements available.
+ * @param max val[in] Maximum value allowed.
+ * @returns Number of correctly parsed elements in case of success.
+ * @retval -1 Wrong element size.
+ * @retval -2 More tokens than result table allows.
+ * @retval -3 Wrong range syntax.
+ * @retval -4 Wrong range values.
+ * @retval -5 Maximum value exceeded.
+ */
+static int
+get_entry_values(const char *entry, uint8_t *tab,
+	size_t elem_sz, uint8_t max_elems, uint8_t max_val)
+{
+	/* There should not be more tokens than max elements.
+	 * Add 1 for error trap.
+	 */
+	char *tokens[max_elems + 1];
+
+	/* Begin, End + error trap = 3. */
+	char *rng_tokens[MAX_RNG_TOKENS + 1];
+	long beg, end;
+	uint32_t token_val;
+	int nb_tokens, nb_rng_tokens;
+	int i;
+	int values = 0;
+	char val;
+	char entry_cpy[CFG_VALUE_LEN];
+
+	if (elem_sz != 1)
+		return -1;
+
+	/* Copy the entry to safely use rte_strsplit(). */
+	snprintf(entry_cpy, RTE_DIM(entry_cpy), "%s", entry);
+
+	/*
+	 * If there are more tokens than array size, rte_strsplit will
+	 * not return error, just array size.
+	 */
+	nb_tokens = rte_strsplit(entry_cpy, strlen(entry_cpy),
+		tokens, max_elems + 1, ' ');
+
+	/* Quick check, will be refined later. */
+	if (nb_tokens > max_elems)
+		return -2;
+
+	for (i = 0; i < nb_tokens; ++i) {
+		if (strchr(tokens[i], '-') != NULL) {
+			/*
+			 * Split to begin and end tokens.
+			 * We want to catch error cases too, thus we leave
+			 * option for number of tokens to be more than 2.
+			 */
+			nb_rng_tokens = rte_strsplit(tokens[i],
+					strlen(tokens[i]), rng_tokens,
+					RTE_DIM(rng_tokens), '-');
+			if (nb_rng_tokens != 2)
+				return -3;
+
+			/* Range and sanity checks. */
+			if (get_val_securely(rng_tokens[0], &token_val) < 0)
+				return -4;
+			beg = (char)token_val;
+			if (get_val_securely(rng_tokens[1], &token_val) < 0)
+				return -4;
+			end = (char)token_val;
+			if (beg < 0 || beg > UCHAR_MAX ||
+				end < 0 || end > UCHAR_MAX || end < beg)
+				return -4;
+
+			for (val = beg; val <= end; ++val) {
+				if (val > max_val)
+					return -5;
+
+				*tab = val;
+				tab = RTE_PTR_ADD(tab, elem_sz);
+				++values;
+				if (values >= max_elems)
+					return -2;
+			}
+		} else {
+			/* Single values. */
+			if (get_val_securely(tokens[i], &token_val) < 0)
+				return -5;
+			val = (char)token_val;
+			if (val > max_val)
+				return -5;
+
+			*tab = val;
+			tab = RTE_PTR_ADD(tab, elem_sz);
+			++values;
+			if (values >= max_elems)
+				return -2;
+		}
+	}
+
+	return values;
+}
+
+/**
+ * Parse Traffic Class'es mapping configuration.
+ *
+ * @param file Config file handle.
+ * @param port Which port to look for.
+ * @param tc Which Traffic Class to look for.
+ * @param cfg[out] Parsing results.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
+		struct mrvl_qos_cfg *cfg)
+{
+	char sec_name[32];
+	const char *entry;
+	int n;
+
+	snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
+		MRVL_TOK_PORT, port, MRVL_TOK_TC, tc);
+
+	/* Skip non-existing */
+	if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
+		return 0;
+
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RXQ);
+	if (entry) {
+		n = get_entry_values(entry,
+			cfg->port[port].tc[tc].inq,
+			sizeof(cfg->port[port].tc[tc].inq[0]),
+			RTE_DIM(cfg->port[port].tc[tc].inq),
+			MRVL_PP2_RXQ_MAX);
+		if (n < 0) {
+			RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n",
+				n, entry);
+			return n;
+		}
+		cfg->port[port].tc[tc].inqs = n;
+	}
+
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PCP);
+	if (entry) {
+		n = get_entry_values(entry,
+			cfg->port[port].tc[tc].pcp,
+			sizeof(cfg->port[port].tc[tc].pcp[0]),
+			RTE_DIM(cfg->port[port].tc[tc].pcp),
+			MAX_PCP);
+		if (n < 0) {
+			RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n",
+				n, entry);
+			return n;
+		}
+		cfg->port[port].tc[tc].pcps = n;
+	}
+
+	entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_DSCP);
+	if (entry) {
+		n = get_entry_values(entry,
+			cfg->port[port].tc[tc].dscp,
+			sizeof(cfg->port[port].tc[tc].dscp[0]),
+			RTE_DIM(cfg->port[port].tc[tc].dscp),
+			MAX_DSCP);
+		if (n < 0) {
+			RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n",
+				n, entry);
+			return n;
+		}
+		cfg->port[port].tc[tc].dscps = n;
+	}
+	return 0;
+}
+
+/**
+ * Parse QoS configuration - rte_kvargs_process handler.
+ *
+ * Opens configuration file and parses its content.
+ *
+ * @param key Unused.
+ * @param path Path to config file.
+ * @param extra_args Pointer to configuration structure.
+ * @returns 0 in case of success, exits otherwise.
+ */
+int
+mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
+		void *extra_args)
+{
+	struct mrvl_qos_cfg **cfg = extra_args;
+	struct rte_cfgfile *file = rte_cfgfile_load(path, 0);
+	uint32_t val;
+	int n, i, ret;
+	const char *entry;
+	char sec_name[32];
+
+	if (file == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot load configuration %s\n", path);
+
+	/* Create configuration. This is never accessed on the fast path,
+	 * so we can ignore socket.
+	 */
+	*cfg = rte_zmalloc("mrvl_qos_cfg", sizeof(struct mrvl_qos_cfg), 0);
+	if (*cfg == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot allocate configuration %s\n",
+			path);
+
+	n = rte_cfgfile_num_sections(file, MRVL_TOK_PORT,
+		sizeof(MRVL_TOK_PORT) - 1);
+
+	if (n == 0) {
+		/* This is weird, but not bad. */
+		RTE_LOG(WARNING, PMD, "Empty configuration file?\n");
+		return 0;
+	}
+
+	/* Use the number of ports given as vdev parameters. */
+	for (n = 0; n < mrvl_ports_nb; ++n) {
+		snprintf(sec_name, sizeof(sec_name), "%s %d %s",
+			MRVL_TOK_PORT, n, MRVL_TOK_DEFAULT);
+
+		/* Skip ports non-existing in configuration. */
+		if (rte_cfgfile_num_sections(file, sec_name,
+				strlen(sec_name)) <= 0) {
+			(*cfg)->port[n].use_global_defaults = 1;
+			(*cfg)->port[n].mapping_priority =
+				PP2_CLS_QOS_TBL_VLAN_IP_PRI;
+			continue;
+		}
+
+		entry = rte_cfgfile_get_entry(file, sec_name,
+				MRVL_TOK_DEFAULT_TC);
+		if (entry) {
+			if (get_val_securely(entry, &val) < 0 ||
+				val > USHRT_MAX)
+				return -1;
+			(*cfg)->port[n].default_tc = (uint8_t)val;
+		} else {
+			RTE_LOG(ERR, PMD,
+				"Default Traffic Class required in custom configuration!\n");
+			return -1;
+		}
+
+		entry = rte_cfgfile_get_entry(file, sec_name,
+				MRVL_TOK_MAPPING_PRIORITY);
+		if (entry) {
+			if (!strncmp(entry, MRVL_TOK_VLAN_IP,
+				sizeof(MRVL_TOK_VLAN_IP)))
+				(*cfg)->port[n].mapping_priority =
+					PP2_CLS_QOS_TBL_VLAN_IP_PRI;
+			else if (!strncmp(entry, MRVL_TOK_IP_VLAN,
+				sizeof(MRVL_TOK_IP_VLAN)))
+				(*cfg)->port[n].mapping_priority =
+					PP2_CLS_QOS_TBL_IP_VLAN_PRI;
+			else if (!strncmp(entry, MRVL_TOK_IP,
+				sizeof(MRVL_TOK_IP)))
+				(*cfg)->port[n].mapping_priority =
+					PP2_CLS_QOS_TBL_IP_PRI;
+			else if (!strncmp(entry, MRVL_TOK_VLAN,
+				sizeof(MRVL_TOK_VLAN)))
+				(*cfg)->port[n].mapping_priority =
+					PP2_CLS_QOS_TBL_VLAN_PRI;
+			else
+				rte_exit(EXIT_FAILURE,
+					"Error in parsing %s value (%s)!\n",
+					MRVL_TOK_MAPPING_PRIORITY, entry);
+		} else {
+			(*cfg)->port[n].mapping_priority =
+				PP2_CLS_QOS_TBL_VLAN_IP_PRI;
+		}
+
+		for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) {
+			ret = get_outq_cfg(file, n, i, *cfg);
+			if (ret < 0)
+				rte_exit(EXIT_FAILURE,
+					"Error %d parsing port %d outq %d!\n",
+					ret, n, i);
+		}
+
+		for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
+			ret = parse_tc_cfg(file, n, i, *cfg);
+			if (ret < 0)
+				rte_exit(EXIT_FAILURE,
+					"Error %d parsing port %d tc %d!\n",
+					ret, n, i);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Setup Traffic Class.
+ *
+ * Fill in TC parameters in single MUSDK TC config entry.
+ * @param param TC parameters entry.
+ * @param inqs Number of MUSDK in-queues in this TC.
+ * @param bpool Bpool for this TC.
+ * @returns 0 in case of success, exits otherwise.
+ */
+static int
+setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
+	struct pp2_bpool *bpool)
+{
+	struct pp2_ppio_inq_params *inq_params;
+
+	param->pkt_offset = MRVL_PKT_OFFS;
+	param->pools[0] = bpool;
+
+	inq_params = rte_zmalloc_socket("inq_params",
+		inqs * sizeof(*inq_params),
+		0, rte_socket_id());
+	if (!inq_params)
+		return -ENOMEM;
+
+	param->num_in_qs = inqs;
+
+	/* Release old config if necessary. */
+	if (param->inqs_params)
+		rte_free(param->inqs_params);
+
+	param->inqs_params = inq_params;
+
+	return 0;
+}
+
+/**
+ * Configure RX Queues in a given port.
+ *
+ * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
+ *
+ * @param priv Port's private data
+ * @param portid DPDK port ID
+ * @param max_queues Maximum number of queues to configure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+int
+mrvl_configure_rxqs(struct mrvl_priv *priv, uint8_t portid,
+	uint16_t max_queues)
+{
+	size_t i, tc;
+
+	if (mrvl_qos_cfg == NULL ||
+		mrvl_qos_cfg->port[portid].use_global_defaults) {
+		/* No port configuration, use default: 1 TC, no QoS. */
+		priv->ppio_params.inqs_params.num_tcs = 1;
+		setup_tc(&priv->ppio_params.inqs_params.tcs_params[0],
+			max_queues, priv->bpool);
+
+		/* Direct mapping of queues i.e. 0->0, 1->1 etc. */
+		for (i = 0; i < max_queues; ++i) {
+			priv->rxq_map[i].tc = 0;
+			priv->rxq_map[i].inq = i;
+		}
+		return 0;
+	}
+
+	/* We need only a subset of configuration. */
+	struct port_cfg *port_cfg = &mrvl_qos_cfg->port[portid];
+
+	priv->qos_tbl_params.type = port_cfg->mapping_priority;
+
+	/*
+	 * We need to reverse mapping, from tc->pcp (better from usability
+	 * point of view) to pcp->tc (configurable in MUSDK).
+	 * First, set all map elements to "default".
+	 */
+	for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
+		priv->qos_tbl_params.pcp_cos_map[i].tc = port_cfg->default_tc;
+
+	/* Then, fill in all known values. */
+	for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
+		if (port_cfg->tc[tc].pcps > RTE_DIM(port_cfg->tc[0].pcp)) {
+			/* Better safe than sorry. */
+			RTE_LOG(ERR, PMD,
+				"Too many PCPs configured in TC %zu!\n", tc);
+			return -1;
+		}
+		for (i = 0; i < port_cfg->tc[tc].pcps; ++i) {
+			priv->qos_tbl_params.pcp_cos_map[
+			  port_cfg->tc[tc].pcp[i]].tc = tc;
+		}
+	}
+
+	/*
+	 * The same logic goes with DSCP.
+	 * First, set all map elements to "default".
+	 */
+	for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
+		priv->qos_tbl_params.dscp_cos_map[i].tc =
+			port_cfg->default_tc;
+
+	/* Fill in all known values. */
+	for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
+		if (port_cfg->tc[tc].dscps > RTE_DIM(port_cfg->tc[0].dscp)) {
+			/* Better safe than sorry. */
+			RTE_LOG(ERR, PMD,
+				"Too many DSCPs configured in TC %zu!\n", tc);
+			return -1;
+		}
+		for (i = 0; i < port_cfg->tc[tc].dscps; ++i) {
+			priv->qos_tbl_params.dscp_cos_map[
+			  port_cfg->tc[tc].dscp[i]].tc = tc;
+		}
+	}
+
+	/*
+	 * Surprisingly, similar logic goes with queue mapping.
+	 * We need only to store qid->tc mapping,
+	 * to know TC when queue is read.
+	 */
+	for (i = 0; i < RTE_DIM(priv->rxq_map); ++i)
+		priv->rxq_map[i].tc = MRVL_UNKNOWN_TC;
+
+	/* Set up DPDKq->(TC,inq) mapping. */
+	for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
+		if (port_cfg->tc[tc].inqs > RTE_DIM(port_cfg->tc[0].inq)) {
+			/* Overflow. */
+			RTE_LOG(ERR, PMD,
+				"Too many RX queues configured per TC %zu!\n",
+				tc);
+			return -1;
+		}
+		for (i = 0; i < port_cfg->tc[tc].inqs; ++i) {
+			uint8_t idx = port_cfg->tc[tc].inq[i];
+
+			if (idx > RTE_DIM(priv->rxq_map)) {
+				RTE_LOG(ERR, PMD, "Bad queue index %d!\n", idx);
+				return -1;
+			}
+
+			priv->rxq_map[idx].tc = tc;
+			priv->rxq_map[idx].inq = i;
+		}
+	}
+
+	/*
+	 * Set up TC configuration. TCs need to be sequenced: 0, 1, 2
+	 * with no gaps. Empty TC means end of processing.
+	 */
+	for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
+		if (port_cfg->tc[i].inqs == 0)
+			break;
+		setup_tc(&priv->ppio_params.inqs_params.tcs_params[i],
+				port_cfg->tc[i].inqs,
+				priv->bpool);
+	}
+
+	priv->ppio_params.inqs_params.num_tcs = i;
+
+	return 0;
+}
+
+/**
+ * Start QoS mapping.
+ *
+ * Finalize QoS table configuration and initialize it in SDK. It can be done
+ * only after port is started, so we have a valid ppio reference.
+ *
+ * @param priv Port's private (configuration) data.
+ * @returns 0 in case of success, exits otherwise.
+ */
+int
+mrvl_start_qos_mapping(struct mrvl_priv *priv)
+{
+	size_t i;
+
+	if (priv->ppio == NULL) {
+		RTE_LOG(ERR, PMD, "ppio must not be NULL here!\n");
+		return -1;
+	}
+
+	for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
+		priv->qos_tbl_params.pcp_cos_map[i].ppio = priv->ppio;
+
+	for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
+		priv->qos_tbl_params.dscp_cos_map[i].ppio = priv->ppio;
+
+	/* Initialize Classifier QoS table. */
+
+	return pp2_cls_qos_tbl_init(&priv->qos_tbl_params, &priv->qos_tbl);
+}
diff --git a/drivers/net/mrvl/mrvl_qos.h b/drivers/net/mrvl/mrvl_qos.h
new file mode 100644
index 0000000..0fcc85c
--- /dev/null
+++ b/drivers/net/mrvl/mrvl_qos.h
@@ -0,0 +1,112 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Semihalf. 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 Semihalf 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 _MRVL_QOS_H_
+#define _MRVL_QOS_H_
+
+#include <rte_common.h>
+#include <rte_config.h>
+
+#include "mrvl_ethdev.h"
+
+/** Code Points per Traffic Class. Equals max(DSCP, PCP). */
+#define MRVL_CP_PER_TC (64)
+
+/** Value used as "unknown". */
+#define MRVL_UNKNOWN_TC (0xFF)
+
+/* QoS config. */
+struct mrvl_qos_cfg {
+	struct port_cfg {
+		struct {
+			uint8_t inq[MRVL_PP2_RXQ_MAX];
+			uint8_t dscp[MRVL_CP_PER_TC];
+			uint8_t pcp[MRVL_CP_PER_TC];
+			uint8_t inqs;
+			uint8_t dscps;
+			uint8_t pcps;
+		} tc[MRVL_PP2_TC_MAX];
+		struct {
+			uint8_t weight;
+		} outq[MRVL_PP2_RXQ_MAX];
+		enum pp2_cls_qos_tbl_type mapping_priority;
+		uint16_t inqs;
+		uint16_t outqs;
+		uint8_t default_tc;
+		uint8_t use_global_defaults;
+	} port[RTE_MAX_ETHPORTS];
+};
+
+/** Global QoS configuration. */
+extern struct mrvl_qos_cfg *mrvl_qos_cfg;
+
+/**
+ * Parse QoS configuration - rte_kvargs_process handler.
+ *
+ * Opens configuration file and parses its content.
+ *
+ * @param key Unused.
+ * @param path Path to config file.
+ * @param extra_args Pointer to configuration structure.
+ * @returns 0 in case of success, exits otherwise.
+ */
+int
+mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
+		void *extra_args);
+
+/**
+ * Configure RX Queues in a given port.
+ *
+ * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
+ *
+ * @param priv Port's private data
+ * @param portid DPDK port ID
+ * @param max_queues Maximum number of queues to configure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+int
+mrvl_configure_rxqs(struct mrvl_priv *priv, uint8_t portid,
+		    uint16_t max_queues);
+
+/**
+ * Start QoS mapping.
+ *
+ * Finalize QoS table configuration and initialize it in SDK. It can be done
+ * only after port is started, so we have a valid ppio reference.
+ *
+ * @param priv Port's private (configuration) data.
+ * @returns 0 in case of success, exits otherwise.
+ */
+int
+mrvl_start_qos_mapping(struct mrvl_priv *priv);
+
+#endif /* _MRVL_QOS_H_ */
diff --git a/drivers/net/mrvl/rte_pmd_mrvl_version.map b/drivers/net/mrvl/rte_pmd_mrvl_version.map
new file mode 100644
index 0000000..a753031
--- /dev/null
+++ b/drivers/net/mrvl/rte_pmd_mrvl_version.map
@@ -0,0 +1,3 @@
+DPDK_17.11 {
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 4891bc2..b9197e8 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -136,6 +136,7 @@ endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_LIO_PMD)        += -lrte_pmd_lio
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -libverbs
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD)       += -lrte_pmd_mlx5 -libverbs -lmlx5
+_LDLIBS-$(CONFIG_RTE_LIBRTE_MRVL_PMD)       += -lrte_pmd_mrvl -L$(LIBMUSDK_PATH)/lib -lmusdk
 _LDLIBS-$(CONFIG_RTE_LIBRTE_NFP_PMD)        += -lrte_pmd_nfp
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NULL)       += -lrte_pmd_null
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_PCAP)       += -lrte_pmd_pcap -lpcap
-- 
2.7.4

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

* [PATCH v4 03/16] net/mrvl: add rx/tx support
  2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
  2017-10-09 15:00         ` [PATCH v4 01/16] app: link the whole rte_cfgfile library Tomasz Duszynski
  2017-10-09 15:00         ` [PATCH v4 02/16] net/mrvl: add mrvl net pmd driver skeleton Tomasz Duszynski
@ 2017-10-09 15:00         ` Tomasz Duszynski
  2017-10-09 15:00         ` [PATCH v4 04/16] net/mrvl: add link update Tomasz Duszynski
                           ` (13 subsequent siblings)
  16 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-09 15:00 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add rx/tx support.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 drivers/net/mrvl/mrvl_ethdev.c | 370 ++++++++++++++++++++++++++++++++++++++++-
 drivers/net/mrvl/mrvl_ethdev.h |  11 ++
 2 files changed, 380 insertions(+), 1 deletion(-)

diff --git a/drivers/net/mrvl/mrvl_ethdev.c b/drivers/net/mrvl/mrvl_ethdev.c
index 1e730c6..c87d48e 100644
--- a/drivers/net/mrvl/mrvl_ethdev.c
+++ b/drivers/net/mrvl/mrvl_ethdev.c
@@ -70,6 +70,9 @@
 #define MRVL_MUSDK_HIFS_MAX 9
 
 #define MRVL_MAC_ADDRS_MAX 1
+/* prefetch shift */
+#define MRVL_MUSDK_PREFETCH_SHIFT 2
+
 #define MRVL_MATCH_LEN 16
 #define MRVL_PKT_EFFEC_OFFS (MRVL_PKT_OFFS + MV_MH_SIZE)
 /* Maximum allowable packet size */
@@ -100,8 +103,29 @@ static int used_bpools[PP2_NUM_PKT_PROC] = {
 	MRVL_MUSDK_BPOOLS_RESERVED
 };
 
+struct pp2_bpool *mrvl_port_to_bpool_lookup[RTE_MAX_ETHPORTS];
+int mrvl_port_bpool_size[PP2_NUM_PKT_PROC][PP2_BPOOL_NUM_POOLS][RTE_MAX_LCORE];
 uint64_t cookie_addr_high = MRVL_COOKIE_ADDR_INVALID;
 
+/*
+ * To use buffer harvesting based on loopback port shadow queue structure
+ * was introduced for buffers information bookkeeping.
+ *
+ * Before sending the packet, related buffer information (pp2_buff_inf) is
+ * stored in shadow queue. After packet is transmitted no longer used
+ * packet buffer is released back to it's original hardware pool,
+ * on condition it originated from interface.
+ * In case it  was generated by application itself i.e: mbuf->port field is
+ * 0xff then its released to software mempool.
+ */
+struct mrvl_shadow_txq {
+	int head;           /* write index - used when sending buffers */
+	int tail;           /* read index - used when releasing buffers */
+	u16 size;           /* queue occupied size */
+	u16 num_to_release; /* number of buffers sent, that can be released */
+	struct buff_release_entry ent[MRVL_PP2_TX_SHADOWQ_SIZE]; /* q entries */
+};
+
 struct mrvl_rxq {
 	struct mrvl_priv *priv;
 	struct rte_mempool *mp;
@@ -115,8 +139,31 @@ struct mrvl_txq {
 	int port_id;
 };
 
+/*
+ * Every tx queue should have dedicated shadow tx queue.
+ *
+ * Ports assigned by DPDK might not start at zero or be continuous so
+ * as a workaround define shadow queues for each possible port so that
+ * we eventually fit somewhere.
+ */
+struct mrvl_shadow_txq shadow_txqs[RTE_MAX_ETHPORTS][RTE_MAX_LCORE];
+
 /** Number of ports configured. */
 int mrvl_ports_nb;
+static int mrvl_lcore_first;
+static int mrvl_lcore_last;
+
+static inline int
+mrvl_get_bpool_size(int pp2_id, int pool_id)
+{
+	int i;
+	int size = 0;
+
+	for (i = mrvl_lcore_first; i <= mrvl_lcore_last; i++)
+		size += mrvl_port_bpool_size[pp2_id][pool_id][i];
+
+	return size;
+}
 
 static inline int
 mrvl_reserve_bit(int *bitmap, int max)
@@ -326,6 +373,33 @@ mrvl_flush_rx_queues(struct rte_eth_dev *dev)
 }
 
 /**
+ * Flush transmit shadow queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_flush_tx_shadow_queues(struct rte_eth_dev *dev)
+{
+	int i;
+
+	RTE_LOG(INFO, PMD, "Flushing tx shadow queues\n");
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		struct mrvl_shadow_txq *sq =
+			&shadow_txqs[dev->data->port_id][i];
+
+		while (sq->tail != sq->head) {
+			uint64_t addr = cookie_addr_high |
+					sq->ent[sq->tail].buff.cookie;
+			rte_pktmbuf_free((struct rte_mbuf *)addr);
+			sq->tail = (sq->tail + 1) & MRVL_PP2_TX_SHADOWQ_MASK;
+		}
+
+		memset(sq, 0, sizeof(*sq));
+	}
+}
+
+/**
  * Flush hardware bpool (buffer-pool).
  *
  * @param dev
@@ -371,6 +445,7 @@ mrvl_dev_stop(struct rte_eth_dev *dev)
 
 	mrvl_dev_set_link_down(dev);
 	mrvl_flush_rx_queues(dev);
+	mrvl_flush_tx_shadow_queues(dev);
 	if (priv->qos_tbl)
 		pp2_cls_qos_tbl_deinit(priv->qos_tbl);
 	pp2_ppio_deinit(priv->ppio);
@@ -543,6 +618,7 @@ mrvl_fill_bpool(struct mrvl_rxq *rxq, int num)
 	}
 
 	pp2_bpool_put_buffs(hif, entries, (uint16_t *)&i);
+	mrvl_port_bpool_size[bpool->pp2_id][bpool->id][core_id] += i;
 
 	if (i != num)
 		goto out;
@@ -619,6 +695,7 @@ mrvl_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 	rxq->mp = mp;
 	rxq->queue_id = idx;
 	rxq->port_id = dev->data->port_id;
+	mrvl_port_to_bpool_lookup[rxq->port_id] = priv->bpool;
 
 	tc = priv->rxq_map[rxq->queue_id].tc,
 	inq = priv->rxq_map[rxq->queue_id].inq;
@@ -750,6 +827,276 @@ static const struct eth_dev_ops mrvl_ops = {
 };
 
 /**
+ * DPDK callback for receive.
+ *
+ * @param rxq
+ *   Generic pointer to the receive queue.
+ * @param rx_pkts
+ *   Array to store received packets.
+ * @param nb_pkts
+ *   Maximum number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully received.
+ */
+static uint16_t
+mrvl_rx_pkt_burst(void *rxq, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
+{
+	struct mrvl_rxq *q = rxq;
+	struct pp2_ppio_desc descs[nb_pkts];
+	struct pp2_bpool *bpool;
+	int i, ret, rx_done = 0;
+	int num;
+	unsigned int core_id = rte_lcore_id();
+
+	if (unlikely(!q->priv->ppio))
+		return 0;
+
+	bpool = q->priv->bpool;
+
+	ret = pp2_ppio_recv(q->priv->ppio, q->priv->rxq_map[q->queue_id].tc,
+			    q->priv->rxq_map[q->queue_id].inq, descs, &nb_pkts);
+	if (unlikely(ret < 0)) {
+		RTE_LOG(ERR, PMD, "Failed to receive packets\n");
+		return 0;
+	}
+	mrvl_port_bpool_size[bpool->pp2_id][bpool->id][core_id] -= nb_pkts;
+
+	for (i = 0; i < nb_pkts; i++) {
+		struct rte_mbuf *mbuf;
+		enum pp2_inq_desc_status status;
+		uint64_t addr;
+
+		if (likely(nb_pkts - i > MRVL_MUSDK_PREFETCH_SHIFT)) {
+			struct pp2_ppio_desc *pref_desc;
+			u64 pref_addr;
+
+			pref_desc = &descs[i + MRVL_MUSDK_PREFETCH_SHIFT];
+			pref_addr = cookie_addr_high |
+				    pp2_ppio_inq_desc_get_cookie(pref_desc);
+			rte_mbuf_prefetch_part1((struct rte_mbuf *)(pref_addr));
+			rte_mbuf_prefetch_part2((struct rte_mbuf *)(pref_addr));
+		}
+
+		addr = cookie_addr_high |
+		       pp2_ppio_inq_desc_get_cookie(&descs[i]);
+		mbuf = (struct rte_mbuf *)addr;
+		rte_pktmbuf_reset(mbuf);
+
+		/* drop packet in case of mac, overrun or resource error */
+		status = pp2_ppio_inq_desc_get_l2_pkt_error(&descs[i]);
+		if (unlikely(status != PP2_DESC_ERR_OK)) {
+			struct pp2_buff_inf binf = {
+				.addr = rte_mbuf_data_dma_addr_default(mbuf),
+				.cookie = (pp2_cookie_t)(uint64_t)mbuf,
+			};
+
+			pp2_bpool_put_buff(hifs[core_id], bpool, &binf);
+			mrvl_port_bpool_size
+				[bpool->pp2_id][bpool->id][core_id]++;
+			continue;
+		}
+
+		mbuf->data_off += MRVL_PKT_EFFEC_OFFS;
+		mbuf->pkt_len = pp2_ppio_inq_desc_get_pkt_len(&descs[i]);
+		mbuf->data_len = mbuf->pkt_len;
+		mbuf->port = q->port_id;
+
+		rx_pkts[rx_done++] = mbuf;
+	}
+
+	if (rte_spinlock_trylock(&q->priv->lock) == 1) {
+		num = mrvl_get_bpool_size(bpool->pp2_id, bpool->id);
+
+		if (unlikely(num <= q->priv->bpool_min_size ||
+			     (!rx_done && num < q->priv->bpool_init_size))) {
+			ret = mrvl_fill_bpool(q, MRVL_BURST_SIZE);
+			if (ret)
+				RTE_LOG(ERR, PMD, "Failed to fill bpool\n");
+		} else if (unlikely(num > q->priv->bpool_max_size)) {
+			int i;
+			int pkt_to_remove = num - q->priv->bpool_init_size;
+			struct rte_mbuf *mbuf;
+			struct pp2_buff_inf buff;
+
+			RTE_LOG(DEBUG, PMD,
+				"\nport-%d:%d: bpool %d oversize - remove %d buffers (pool size: %d -> %d)\n",
+				bpool->pp2_id, q->priv->ppio->port_id,
+				bpool->id, pkt_to_remove, num,
+				q->priv->bpool_init_size);
+
+			for (i = 0; i < pkt_to_remove; i++) {
+				pp2_bpool_get_buff(hifs[core_id], bpool, &buff);
+				mbuf = (struct rte_mbuf *)
+					(cookie_addr_high | buff.cookie);
+				rte_pktmbuf_free(mbuf);
+			}
+			mrvl_port_bpool_size
+				[bpool->pp2_id][bpool->id][core_id] -=
+								pkt_to_remove;
+		}
+		rte_spinlock_unlock(&q->priv->lock);
+	}
+
+	return rx_done;
+}
+
+/**
+ * Release already sent buffers to bpool (buffer-pool).
+ *
+ * @param ppio
+ *   Pointer to the port structure.
+ * @param hif
+ *   Pointer to the MUSDK hardware interface.
+ * @param sq
+ *   Pointer to the shadow queue.
+ * @param qid
+ *   Queue id number.
+ * @param force
+ *   Force releasing packets.
+ */
+static inline void
+mrvl_free_sent_buffers(struct pp2_ppio *ppio, struct pp2_hif *hif,
+		       struct mrvl_shadow_txq *sq, int qid, int force)
+{
+	struct buff_release_entry *entry;
+	uint16_t nb_done = 0, num = 0, skip_bufs = 0;
+	int i, core_id = rte_lcore_id();
+
+	pp2_ppio_get_num_outq_done(ppio, hif, qid, &nb_done);
+
+	sq->num_to_release += nb_done;
+
+	if (likely(!force &&
+		   sq->num_to_release < MRVL_PP2_BUF_RELEASE_BURST_SIZE))
+		return;
+
+	nb_done = sq->num_to_release;
+	sq->num_to_release = 0;
+
+	for (i = 0; i < nb_done; i++) {
+		entry = &sq->ent[sq->tail + num];
+		if (unlikely(!entry->buff.addr)) {
+			RTE_LOG(ERR, PMD,
+				"Shadow memory @%d: cookie(%lx), pa(%lx)!\n",
+				sq->tail, (u64)entry->buff.cookie,
+				(u64)entry->buff.addr);
+			skip_bufs = 1;
+			goto skip;
+		}
+
+		if (unlikely(!entry->bpool)) {
+			struct rte_mbuf *mbuf;
+
+			mbuf = (struct rte_mbuf *)
+			       (cookie_addr_high | entry->buff.cookie);
+			rte_pktmbuf_free(mbuf);
+			skip_bufs = 1;
+			goto skip;
+		}
+
+		mrvl_port_bpool_size
+			[entry->bpool->pp2_id][entry->bpool->id][core_id]++;
+		num++;
+		if (unlikely(sq->tail + num == MRVL_PP2_TX_SHADOWQ_SIZE))
+			goto skip;
+		continue;
+skip:
+		if (likely(num))
+			pp2_bpool_put_buffs(hif, &sq->ent[sq->tail], &num);
+		num += skip_bufs;
+		sq->tail = (sq->tail + num) & MRVL_PP2_TX_SHADOWQ_MASK;
+		sq->size -= num;
+		num = 0;
+	}
+
+	if (likely(num)) {
+		pp2_bpool_put_buffs(hif, &sq->ent[sq->tail], &num);
+		sq->tail = (sq->tail + num) & MRVL_PP2_TX_SHADOWQ_MASK;
+		sq->size -= num;
+	}
+}
+
+/**
+ * DPDK callback for transmit.
+ *
+ * @param txq
+ *   Generic pointer transmit queue.
+ * @param tx_pkts
+ *   Packets to transmit.
+ * @param nb_pkts
+ *   Number of packets in array.
+ *
+ * @return
+ *   Number of packets successfully transmitted.
+ */
+static uint16_t
+mrvl_tx_pkt_burst(void *txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+	struct mrvl_txq *q = txq;
+	struct mrvl_shadow_txq *sq = &shadow_txqs[q->port_id][rte_lcore_id()];
+	struct pp2_hif *hif = hifs[rte_lcore_id()];
+	struct pp2_ppio_desc descs[nb_pkts];
+	int i;
+	uint16_t num, sq_free_size;
+
+	if (unlikely(!q->priv->ppio))
+		return 0;
+
+	if (sq->size)
+		mrvl_free_sent_buffers(q->priv->ppio, hif, sq, q->queue_id, 0);
+
+	sq_free_size = MRVL_PP2_TX_SHADOWQ_SIZE - sq->size - 1;
+	if (unlikely(nb_pkts > sq_free_size)) {
+		RTE_LOG(DEBUG, PMD,
+			"No room in shadow queue for %d packets! %d packets will be sent.\n",
+			nb_pkts, sq_free_size);
+		nb_pkts = sq_free_size;
+	}
+
+	for (i = 0; i < nb_pkts; i++) {
+		struct rte_mbuf *mbuf = tx_pkts[i];
+
+		if (likely(nb_pkts - i > MRVL_MUSDK_PREFETCH_SHIFT)) {
+			struct rte_mbuf *pref_pkt_hdr;
+
+			pref_pkt_hdr = tx_pkts[i + MRVL_MUSDK_PREFETCH_SHIFT];
+			rte_mbuf_prefetch_part1(pref_pkt_hdr);
+			rte_mbuf_prefetch_part2(pref_pkt_hdr);
+		}
+
+		sq->ent[sq->head].buff.cookie = (pp2_cookie_t)(uint64_t)mbuf;
+		sq->ent[sq->head].buff.addr =
+			rte_mbuf_data_dma_addr_default(mbuf);
+		sq->ent[sq->head].bpool =
+			(unlikely(mbuf->port == 0xff || mbuf->refcnt > 1)) ?
+			 NULL : mrvl_port_to_bpool_lookup[mbuf->port];
+		sq->head = (sq->head + 1) & MRVL_PP2_TX_SHADOWQ_MASK;
+		sq->size++;
+
+		pp2_ppio_outq_desc_reset(&descs[i]);
+		pp2_ppio_outq_desc_set_phys_addr(&descs[i],
+						 rte_pktmbuf_mtophys(mbuf));
+		pp2_ppio_outq_desc_set_pkt_offset(&descs[i], 0);
+		pp2_ppio_outq_desc_set_pkt_len(&descs[i],
+					       rte_pktmbuf_pkt_len(mbuf));
+	}
+
+	num = nb_pkts;
+	pp2_ppio_send(q->priv->ppio, hif, q->queue_id, descs, &nb_pkts);
+	/* number of packets that were not sent */
+	if (unlikely(num > nb_pkts)) {
+		for (i = nb_pkts; i < num; i++) {
+			sq->head = (MRVL_PP2_TX_SHADOWQ_SIZE + sq->head - 1) &
+				MRVL_PP2_TX_SHADOWQ_MASK;
+		}
+		sq->size -= num - nb_pkts;
+	}
+
+	return nb_pkts;
+}
+
+/**
  * Initialize packet processor.
  *
  * @return
@@ -821,6 +1168,7 @@ mrvl_priv_create(const char *dev_name)
 		goto out_clear_bpool_bit;
 
 	priv->ppio_params.type = PP2_PPIO_T_NIC;
+	rte_spinlock_init(&priv->lock);
 
 	return priv;
 out_clear_bpool_bit:
@@ -875,6 +1223,8 @@ mrvl_eth_dev_create(struct rte_vdev_device *vdev, const char *name)
 	memcpy(eth_dev->data->mac_addrs[0].addr_bytes,
 	       req.ifr_addr.sa_data, ETHER_ADDR_LEN);
 
+	eth_dev->rx_pkt_burst = mrvl_rx_pkt_burst;
+	eth_dev->tx_pkt_burst = mrvl_tx_pkt_burst;
 	eth_dev->data->dev_private = priv;
 	eth_dev->device = &vdev->device;
 	eth_dev->dev_ops = &mrvl_ops;
@@ -984,6 +1334,15 @@ mrvl_deinit_hifs(void)
 	}
 }
 
+static void mrvl_set_first_last_cores(int core_id)
+{
+	if (core_id < mrvl_lcore_first)
+		mrvl_lcore_first = core_id;
+
+	if (core_id > mrvl_lcore_last)
+		mrvl_lcore_last = core_id;
+}
+
 /**
  * DPDK callback to register the virtual device.
  *
@@ -999,7 +1358,7 @@ rte_pmd_mrvl_probe(struct rte_vdev_device *vdev)
 	struct rte_kvargs *kvlist;
 	const char *ifnames[PP2_NUM_ETH_PPIO * PP2_NUM_PKT_PROC];
 	int ret = -EINVAL;
-	uint32_t i, ifnum, cfgnum;
+	uint32_t i, ifnum, cfgnum, core_id;
 	const char *params;
 
 	params = rte_vdev_device_args(vdev);
@@ -1053,6 +1412,15 @@ rte_pmd_mrvl_probe(struct rte_vdev_device *vdev)
 
 	rte_kvargs_free(kvlist);
 
+	memset(mrvl_port_bpool_size, 0, sizeof(mrvl_port_bpool_size));
+
+	mrvl_lcore_first = RTE_MAX_LCORE;
+	mrvl_lcore_last = 0;
+
+	RTE_LCORE_FOREACH(core_id) {
+		mrvl_set_first_last_cores(core_id);
+	}
+
 	return 0;
 out_cleanup:
 	for (; i > 0; i--)
diff --git a/drivers/net/mrvl/mrvl_ethdev.h b/drivers/net/mrvl/mrvl_ethdev.h
index 626cfaa..da33d05 100644
--- a/drivers/net/mrvl/mrvl_ethdev.h
+++ b/drivers/net/mrvl/mrvl_ethdev.h
@@ -33,6 +33,7 @@
 #ifndef _MRVL_ETHDEV_H_
 #define _MRVL_ETHDEV_H_
 
+#include <rte_spinlock.h>
 #include <drivers/mv_pp2_cls.h>
 #include <drivers/mv_pp2_ppio.h>
 
@@ -69,10 +70,20 @@
 /** Packet offset inside RX buffer. */
 #define MRVL_PKT_OFFS 64
 
+/** Maximum number of descriptors in shadow queue. Must be power of 2 */
+#define MRVL_PP2_TX_SHADOWQ_SIZE MRVL_PP2_TXD_MAX
+
+/** Shadow queue size mask (since shadow queue size is power of 2) */
+#define MRVL_PP2_TX_SHADOWQ_MASK (MRVL_PP2_TX_SHADOWQ_SIZE - 1)
+
+/** Minimum number of sent buffers to release from shadow queue to BM */
+#define MRVL_PP2_BUF_RELEASE_BURST_SIZE	64
+
 struct mrvl_priv {
 	/* Hot fields, used in fast path. */
 	struct pp2_bpool *bpool;  /**< BPool pointer */
 	struct pp2_ppio	*ppio;    /**< Port handler pointer */
+	rte_spinlock_t lock;	  /**< Spinlock for checking bpool status */
 	uint16_t bpool_max_size;  /**< BPool maximum size */
 	uint16_t bpool_min_size;  /**< BPool minimum size  */
 	uint16_t bpool_init_size; /**< Configured BPool size  */
-- 
2.7.4

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

* [PATCH v4 04/16] net/mrvl: add link update
  2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
                           ` (2 preceding siblings ...)
  2017-10-09 15:00         ` [PATCH v4 03/16] net/mrvl: add rx/tx support Tomasz Duszynski
@ 2017-10-09 15:00         ` Tomasz Duszynski
  2017-10-09 15:00         ` [PATCH v4 05/16] net/mrvl: add link speed capabilities Tomasz Duszynski
                           ` (12 subsequent siblings)
  16 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-09 15:00 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add support for retrieving physical link information i.e:
speed, duplex and link status.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 doc/guides/nics/features/mrvl.ini |  7 +++++
 drivers/net/mrvl/mrvl_ethdev.c    | 65 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 72 insertions(+)
 create mode 100644 doc/guides/nics/features/mrvl.ini

diff --git a/doc/guides/nics/features/mrvl.ini b/doc/guides/nics/features/mrvl.ini
new file mode 100644
index 0000000..72df92e
--- /dev/null
+++ b/doc/guides/nics/features/mrvl.ini
@@ -0,0 +1,7 @@
+;
+; Supported features of the 'mrvl' network poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Link status          = Y
diff --git a/drivers/net/mrvl/mrvl_ethdev.c b/drivers/net/mrvl/mrvl_ethdev.c
index c87d48e..4788784 100644
--- a/drivers/net/mrvl/mrvl_ethdev.c
+++ b/drivers/net/mrvl/mrvl_ethdev.c
@@ -478,6 +478,70 @@ mrvl_dev_close(struct rte_eth_dev *dev)
 }
 
 /**
+ * DPDK callback to retrieve physical link information.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param wait_to_complete
+ *   Wait for request completion (ignored).
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_link_update(struct rte_eth_dev *dev, int wait_to_complete __rte_unused)
+{
+	/*
+	 * TODO
+	 * once MUSDK provides necessary API use it here
+	 */
+	struct ethtool_cmd edata;
+	struct ifreq req;
+	int ret, fd;
+
+	edata.cmd = ETHTOOL_GSET;
+
+	strcpy(req.ifr_name, dev->data->name);
+	req.ifr_data = (void *)&edata;
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd == -1)
+		return -EFAULT;
+
+	ret = ioctl(fd, SIOCETHTOOL, &req);
+	if (ret == -1) {
+		close(fd);
+		return -EFAULT;
+	}
+
+	close(fd);
+
+	switch (ethtool_cmd_speed(&edata)) {
+	case SPEED_10:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_10M;
+		break;
+	case SPEED_100:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_100M;
+		break;
+	case SPEED_1000:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_1G;
+		break;
+	case SPEED_10000:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_10G;
+		break;
+	default:
+		dev->data->dev_link.link_speed = ETH_SPEED_NUM_NONE;
+	}
+
+	dev->data->dev_link.link_duplex = edata.duplex ? ETH_LINK_FULL_DUPLEX :
+							 ETH_LINK_HALF_DUPLEX;
+	dev->data->dev_link.link_autoneg = edata.autoneg ? ETH_LINK_AUTONEG :
+							   ETH_LINK_FIXED;
+
+	return 0;
+}
+
+/**
  * DPDK callback to set the primary MAC address.
  *
  * @param dev
@@ -816,6 +880,7 @@ static const struct eth_dev_ops mrvl_ops = {
 	.dev_set_link_up = mrvl_dev_set_link_up,
 	.dev_set_link_down = mrvl_dev_set_link_down,
 	.dev_close = mrvl_dev_close,
+	.link_update = mrvl_link_update,
 	.mac_addr_set = mrvl_mac_addr_set,
 	.dev_infos_get = mrvl_dev_infos_get,
 	.rxq_info_get = mrvl_rxq_info_get,
-- 
2.7.4

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

* [PATCH v4 05/16] net/mrvl: add link speed capabilities
  2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
                           ` (3 preceding siblings ...)
  2017-10-09 15:00         ` [PATCH v4 04/16] net/mrvl: add link update Tomasz Duszynski
@ 2017-10-09 15:00         ` Tomasz Duszynski
  2017-10-09 15:00         ` [PATCH v4 06/16] net/mrvl: add support for updating mtu Tomasz Duszynski
                           ` (11 subsequent siblings)
  16 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-09 15:00 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Return supported link speed capabilities via rte_dev_info_get().

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 doc/guides/nics/features/mrvl.ini | 1 +
 drivers/net/mrvl/mrvl_ethdev.c    | 5 +++++
 2 files changed, 6 insertions(+)

diff --git a/doc/guides/nics/features/mrvl.ini b/doc/guides/nics/features/mrvl.ini
index 72df92e..c3b9edf 100644
--- a/doc/guides/nics/features/mrvl.ini
+++ b/doc/guides/nics/features/mrvl.ini
@@ -4,4 +4,5 @@
 ; Refer to default.ini for the full list of available PMD features.
 ;
 [Features]
+Speed capabilities   = Y
 Link status          = Y
diff --git a/drivers/net/mrvl/mrvl_ethdev.c b/drivers/net/mrvl/mrvl_ethdev.c
index 4788784..7bd0dad 100644
--- a/drivers/net/mrvl/mrvl_ethdev.c
+++ b/drivers/net/mrvl/mrvl_ethdev.c
@@ -576,6 +576,11 @@ static void
 mrvl_dev_infos_get(struct rte_eth_dev *dev __rte_unused,
 		   struct rte_eth_dev_info *info)
 {
+	info->speed_capa = ETH_LINK_SPEED_10M |
+			   ETH_LINK_SPEED_100M |
+			   ETH_LINK_SPEED_1G |
+			   ETH_LINK_SPEED_10G;
+
 	info->max_rx_queues = MRVL_PP2_RXQ_MAX;
 	info->max_tx_queues = MRVL_PP2_TXQ_MAX;
 	info->max_mac_addrs = MRVL_MAC_ADDRS_MAX;
-- 
2.7.4

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

* [PATCH v4 06/16] net/mrvl: add support for updating mtu
  2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
                           ` (4 preceding siblings ...)
  2017-10-09 15:00         ` [PATCH v4 05/16] net/mrvl: add link speed capabilities Tomasz Duszynski
@ 2017-10-09 15:00         ` Tomasz Duszynski
  2017-10-09 15:00         ` [PATCH v4 07/16] net/mrvl: add jumbo frame support Tomasz Duszynski
                           ` (10 subsequent siblings)
  16 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-09 15:00 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add support for updating mtu.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 doc/guides/nics/features/mrvl.ini |  1 +
 drivers/net/mrvl/mrvl_ethdev.c    | 44 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/doc/guides/nics/features/mrvl.ini b/doc/guides/nics/features/mrvl.ini
index c3b9edf..13cfaab 100644
--- a/doc/guides/nics/features/mrvl.ini
+++ b/doc/guides/nics/features/mrvl.ini
@@ -6,3 +6,4 @@
 [Features]
 Speed capabilities   = Y
 Link status          = Y
+MTU update           = Y
diff --git a/drivers/net/mrvl/mrvl_ethdev.c b/drivers/net/mrvl/mrvl_ethdev.c
index 7bd0dad..628d4de 100644
--- a/drivers/net/mrvl/mrvl_ethdev.c
+++ b/drivers/net/mrvl/mrvl_ethdev.c
@@ -239,6 +239,38 @@ mrvl_dev_configure(struct rte_eth_dev *dev)
 }
 
 /**
+ * DPDK callback to change the MTU.
+ *
+ * Setting the MTU affects hardware MRU (packets larger than the MRU
+ * will be dropped).
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mtu
+ *   New MTU.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	/* extra MV_MH_SIZE bytes are required for Marvell tag */
+	uint16_t mru = mtu + MV_MH_SIZE + ETHER_HDR_LEN + ETHER_CRC_LEN;
+	int ret;
+
+	if (mtu < ETHER_MIN_MTU || mru > MRVL_PKT_SIZE_MAX)
+		return -EINVAL;
+
+	ret = pp2_ppio_set_mru(priv->ppio, mru);
+	if (ret)
+		return ret;
+
+	return pp2_ppio_set_mtu(priv->ppio, mtu);
+}
+
+/**
  * DPDK callback to bring the link up.
  *
  * @param dev
@@ -257,6 +289,17 @@ mrvl_dev_set_link_up(struct rte_eth_dev *dev)
 	if (ret)
 		return ret;
 
+	/*
+	 * mtu/mru can be updated if pp2_ppio_enable() was called at least once
+	 * as pp2_ppio_enable() changes port->t_mode from default 0 to
+	 * PP2_TRAFFIC_INGRESS_EGRESS.
+	 *
+	 * Set mtu to default DPDK value here.
+	 */
+	ret = mrvl_mtu_set(dev, dev->data->mtu);
+	if (ret)
+		pp2_ppio_disable(priv->ppio);
+
 	dev->data->dev_link.link_status = ETH_LINK_UP;
 
 	return ret;
@@ -887,6 +930,7 @@ static const struct eth_dev_ops mrvl_ops = {
 	.dev_close = mrvl_dev_close,
 	.link_update = mrvl_link_update,
 	.mac_addr_set = mrvl_mac_addr_set,
+	.mtu_set = mrvl_mtu_set,
 	.dev_infos_get = mrvl_dev_infos_get,
 	.rxq_info_get = mrvl_rxq_info_get,
 	.txq_info_get = mrvl_txq_info_get,
-- 
2.7.4

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

* [PATCH v4 07/16] net/mrvl: add jumbo frame support
  2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
                           ` (5 preceding siblings ...)
  2017-10-09 15:00         ` [PATCH v4 06/16] net/mrvl: add support for updating mtu Tomasz Duszynski
@ 2017-10-09 15:00         ` Tomasz Duszynski
  2017-10-09 15:00         ` [PATCH v4 08/16] net/mrvl: add support for promiscuous and allmulticast modes Tomasz Duszynski
                           ` (9 subsequent siblings)
  16 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-09 15:00 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add jumbo frame support.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 doc/guides/nics/features/mrvl.ini | 1 +
 drivers/net/mrvl/mrvl_ethdev.c    | 5 +++++
 2 files changed, 6 insertions(+)

diff --git a/doc/guides/nics/features/mrvl.ini b/doc/guides/nics/features/mrvl.ini
index 13cfaab..2ddabfb 100644
--- a/doc/guides/nics/features/mrvl.ini
+++ b/doc/guides/nics/features/mrvl.ini
@@ -7,3 +7,4 @@
 Speed capabilities   = Y
 Link status          = Y
 MTU update           = Y
+Jumbo frame          = Y
diff --git a/drivers/net/mrvl/mrvl_ethdev.c b/drivers/net/mrvl/mrvl_ethdev.c
index 628d4de..3a5f6a0 100644
--- a/drivers/net/mrvl/mrvl_ethdev.c
+++ b/drivers/net/mrvl/mrvl_ethdev.c
@@ -227,6 +227,10 @@ mrvl_dev_configure(struct rte_eth_dev *dev)
 		return -EINVAL;
 	}
 
+	if (dev->data->dev_conf.rxmode.jumbo_frame)
+		dev->data->mtu = dev->data->dev_conf.rxmode.max_rx_pkt_len -
+				 ETHER_HDR_LEN - ETHER_CRC_LEN;
+
 	ret = mrvl_configure_rxqs(priv, dev->data->port_id,
 				  dev->data->nb_rx_queues);
 	if (ret < 0)
@@ -636,6 +640,7 @@ mrvl_dev_infos_get(struct rte_eth_dev *dev __rte_unused,
 	info->tx_desc_lim.nb_min = MRVL_PP2_TXD_MIN;
 	info->tx_desc_lim.nb_align = MRVL_PP2_TXD_ALIGN;
 
+	info->rx_offload_capa = DEV_RX_OFFLOAD_JUMBO_FRAME;
 	/* By default packets are dropped if no descriptors are available */
 	info->default_rxconf.rx_drop_en = 1;
 
-- 
2.7.4

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

* [PATCH v4 08/16] net/mrvl: add support for promiscuous and allmulticast modes
  2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
                           ` (6 preceding siblings ...)
  2017-10-09 15:00         ` [PATCH v4 07/16] net/mrvl: add jumbo frame support Tomasz Duszynski
@ 2017-10-09 15:00         ` Tomasz Duszynski
  2017-10-09 15:00         ` [PATCH v4 09/16] net/mrvl: add support for mac filtering Tomasz Duszynski
                           ` (8 subsequent siblings)
  16 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-09 15:00 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add support for promiscuous and allmulticast modes.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 doc/guides/nics/features/mrvl.ini |  2 ++
 drivers/net/mrvl/mrvl_ethdev.c    | 72 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 74 insertions(+)

diff --git a/doc/guides/nics/features/mrvl.ini b/doc/guides/nics/features/mrvl.ini
index 2ddabfb..c2df525 100644
--- a/doc/guides/nics/features/mrvl.ini
+++ b/doc/guides/nics/features/mrvl.ini
@@ -8,3 +8,5 @@ Speed capabilities   = Y
 Link status          = Y
 MTU update           = Y
 Jumbo frame          = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
diff --git a/drivers/net/mrvl/mrvl_ethdev.c b/drivers/net/mrvl/mrvl_ethdev.c
index 3a5f6a0..519aa19 100644
--- a/drivers/net/mrvl/mrvl_ethdev.c
+++ b/drivers/net/mrvl/mrvl_ethdev.c
@@ -589,6 +589,74 @@ mrvl_link_update(struct rte_eth_dev *dev, int wait_to_complete __rte_unused)
 }
 
 /**
+ * DPDK callback to enable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_promiscuous_enable(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_set_uc_promisc(priv->ppio, 1);
+	if (ret)
+		RTE_LOG(ERR, PMD, "Failed to enable promiscuous mode\n");
+}
+
+/**
+ * DPDK callback to enable allmulti mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_allmulticast_enable(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_set_mc_promisc(priv->ppio, 1);
+	if (ret)
+		RTE_LOG(ERR, PMD, "Failed enable all-multicast mode\n");
+}
+
+/**
+ * DPDK callback to disable promiscuous mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_set_uc_promisc(priv->ppio, 0);
+	if (ret)
+		RTE_LOG(ERR, PMD, "Failed to disable promiscuous mode\n");
+}
+
+/**
+ * DPDK callback to disable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_allmulticast_disable(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int ret;
+
+	ret = pp2_ppio_set_mc_promisc(priv->ppio, 0);
+	if (ret)
+		RTE_LOG(ERR, PMD, "Failed to disable all-multicast mode\n");
+}
+
+/**
  * DPDK callback to set the primary MAC address.
  *
  * @param dev
@@ -934,6 +1002,10 @@ static const struct eth_dev_ops mrvl_ops = {
 	.dev_set_link_down = mrvl_dev_set_link_down,
 	.dev_close = mrvl_dev_close,
 	.link_update = mrvl_link_update,
+	.promiscuous_enable = mrvl_promiscuous_enable,
+	.allmulticast_enable = mrvl_allmulticast_enable,
+	.promiscuous_disable = mrvl_promiscuous_disable,
+	.allmulticast_disable = mrvl_allmulticast_disable,
 	.mac_addr_set = mrvl_mac_addr_set,
 	.mtu_set = mrvl_mtu_set,
 	.dev_infos_get = mrvl_dev_infos_get,
-- 
2.7.4

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

* [PATCH v4 09/16] net/mrvl: add support for mac filtering
  2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
                           ` (7 preceding siblings ...)
  2017-10-09 15:00         ` [PATCH v4 08/16] net/mrvl: add support for promiscuous and allmulticast modes Tomasz Duszynski
@ 2017-10-09 15:00         ` Tomasz Duszynski
  2017-10-09 15:00         ` [PATCH v4 10/16] net/mrvl: add rss hashing support Tomasz Duszynski
                           ` (7 subsequent siblings)
  16 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-09 15:00 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add support for unicast and multicast mac filters.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 doc/guides/nics/features/mrvl.ini |  2 +
 drivers/net/mrvl/mrvl_ethdev.c    | 95 ++++++++++++++++++++++++++++++++++++++-
 drivers/net/mrvl/mrvl_ethdev.h    |  1 +
 3 files changed, 97 insertions(+), 1 deletion(-)

diff --git a/doc/guides/nics/features/mrvl.ini b/doc/guides/nics/features/mrvl.ini
index c2df525..2243749 100644
--- a/doc/guides/nics/features/mrvl.ini
+++ b/doc/guides/nics/features/mrvl.ini
@@ -10,3 +10,5 @@ MTU update           = Y
 Jumbo frame          = Y
 Promiscuous mode     = Y
 Allmulticast mode    = Y
+Unicast MAC filter   = Y
+Multicast MAC filter = Y
diff --git a/drivers/net/mrvl/mrvl_ethdev.c b/drivers/net/mrvl/mrvl_ethdev.c
index 519aa19..daa2229 100644
--- a/drivers/net/mrvl/mrvl_ethdev.c
+++ b/drivers/net/mrvl/mrvl_ethdev.c
@@ -69,10 +69,11 @@
 /* maximum number of available hifs */
 #define MRVL_MUSDK_HIFS_MAX 9
 
-#define MRVL_MAC_ADDRS_MAX 1
 /* prefetch shift */
 #define MRVL_MUSDK_PREFETCH_SHIFT 2
 
+/* TCAM has 25 entries reserved for uc/mc filter entries */
+#define MRVL_MAC_ADDRS_MAX 25
 #define MRVL_MATCH_LEN 16
 #define MRVL_PKT_EFFEC_OFFS (MRVL_PKT_OFFS + MV_MH_SIZE)
 /* Maximum allowable packet size */
@@ -372,6 +373,22 @@ mrvl_dev_start(struct rte_eth_dev *dev)
 	if (ret)
 		return ret;
 
+	/*
+	 * In case there are some some stale uc/mc mac addresses flush them
+	 * here. It cannot be done during mrvl_dev_close() as port information
+	 * is already gone at that point (due to pp2_ppio_deinit() in
+	 * mrvl_dev_stop()).
+	 */
+	if (!priv->uc_mc_flushed) {
+		ret = pp2_ppio_flush_mac_addrs(priv->ppio, 1, 1);
+		if (ret) {
+			RTE_LOG(ERR, PMD,
+				"Failed to flush uc/mc filter list\n");
+			goto out;
+		}
+		priv->uc_mc_flushed = 1;
+	}
+
 	/* For default QoS config, don't start classifier. */
 	if (mrvl_qos_cfg) {
 		ret = mrvl_start_qos_mapping(priv);
@@ -657,6 +674,80 @@ mrvl_allmulticast_disable(struct rte_eth_dev *dev)
 }
 
 /**
+ * DPDK callback to remove a MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param index
+ *   MAC address index.
+ */
+static void
+mrvl_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	char buf[ETHER_ADDR_FMT_SIZE];
+	int ret;
+
+	ret = pp2_ppio_remove_mac_addr(priv->ppio,
+				       dev->data->mac_addrs[index].addr_bytes);
+	if (ret) {
+		ether_format_addr(buf, sizeof(buf),
+				  &dev->data->mac_addrs[index]);
+		RTE_LOG(ERR, PMD, "Failed to remove mac %s\n", buf);
+	}
+}
+
+/**
+ * DPDK callback to add a MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ * @param index
+ *   MAC address index.
+ * @param vmdq
+ *   VMDq pool index to associate address with (unused).
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
+		  uint32_t index, uint32_t vmdq __rte_unused)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	char buf[ETHER_ADDR_FMT_SIZE];
+	int ret;
+
+	if (index == 0)
+		/* For setting index 0, mrvl_mac_addr_set() should be used.*/
+		return -1;
+
+	/*
+	 * Maximum number of uc addresses can be tuned via kernel module mvpp2x
+	 * parameter uc_filter_max. Maximum number of mc addresses is then
+	 * MRVL_MAC_ADDRS_MAX - uc_filter_max. Currently it defaults to 4 and
+	 * 21 respectively.
+	 *
+	 * If more than uc_filter_max uc addresses were added to filter list
+	 * then NIC will switch to promiscuous mode automatically.
+	 *
+	 * If more than MRVL_MAC_ADDRS_MAX - uc_filter_max number mc addresses
+	 * were added to filter list then NIC will switch to all-multicast mode
+	 * automatically.
+	 */
+	ret = pp2_ppio_add_mac_addr(priv->ppio, mac_addr->addr_bytes);
+	if (ret) {
+		ether_format_addr(buf, sizeof(buf), mac_addr);
+		RTE_LOG(ERR, PMD, "Failed to add mac %s\n", buf);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
  * DPDK callback to set the primary MAC address.
  *
  * @param dev
@@ -1006,6 +1097,8 @@ static const struct eth_dev_ops mrvl_ops = {
 	.allmulticast_enable = mrvl_allmulticast_enable,
 	.promiscuous_disable = mrvl_promiscuous_disable,
 	.allmulticast_disable = mrvl_allmulticast_disable,
+	.mac_addr_remove = mrvl_mac_addr_remove,
+	.mac_addr_add = mrvl_mac_addr_add,
 	.mac_addr_set = mrvl_mac_addr_set,
 	.mtu_set = mrvl_mtu_set,
 	.dev_infos_get = mrvl_dev_infos_get,
diff --git a/drivers/net/mrvl/mrvl_ethdev.h b/drivers/net/mrvl/mrvl_ethdev.h
index da33d05..f43f426 100644
--- a/drivers/net/mrvl/mrvl_ethdev.h
+++ b/drivers/net/mrvl/mrvl_ethdev.h
@@ -98,6 +98,7 @@ struct mrvl_priv {
 	uint8_t pp_id;
 	uint8_t ppio_id;
 	uint8_t bpool_bit;
+	uint8_t uc_mc_flushed;
 
 	struct pp2_ppio_params ppio_params;
 	struct pp2_cls_qos_tbl_params qos_tbl_params;
-- 
2.7.4

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

* [PATCH v4 10/16] net/mrvl: add rss hashing support
  2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
                           ` (8 preceding siblings ...)
  2017-10-09 15:00         ` [PATCH v4 09/16] net/mrvl: add support for mac filtering Tomasz Duszynski
@ 2017-10-09 15:00         ` Tomasz Duszynski
  2017-10-09 15:00         ` [PATCH v4 11/16] net/mrvl: add support for vlan filtering Tomasz Duszynski
                           ` (6 subsequent siblings)
  16 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-09 15:00 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add support for rss hashing on rx.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 doc/guides/nics/features/mrvl.ini |   1 +
 drivers/net/mrvl/mrvl_ethdev.c    | 116 +++++++++++++++++++++++++++++++++++++-
 drivers/net/mrvl/mrvl_ethdev.h    |   1 +
 3 files changed, 115 insertions(+), 3 deletions(-)

diff --git a/doc/guides/nics/features/mrvl.ini b/doc/guides/nics/features/mrvl.ini
index 2243749..e65dea7 100644
--- a/doc/guides/nics/features/mrvl.ini
+++ b/doc/guides/nics/features/mrvl.ini
@@ -12,3 +12,4 @@ Promiscuous mode     = Y
 Allmulticast mode    = Y
 Unicast MAC filter   = Y
 Multicast MAC filter = Y
+RSS hash             = Y
diff --git a/drivers/net/mrvl/mrvl_ethdev.c b/drivers/net/mrvl/mrvl_ethdev.c
index daa2229..fe2603a 100644
--- a/drivers/net/mrvl/mrvl_ethdev.c
+++ b/drivers/net/mrvl/mrvl_ethdev.c
@@ -66,6 +66,8 @@
 #define MRVL_MUSDK_HIFS_RESERVED 0x0F
 /* bitmask with reserved bpools */
 #define MRVL_MUSDK_BPOOLS_RESERVED 0x07
+/* bitmask with reserved kernel RSS tables */
+#define MRVL_MUSDK_RSS_RESERVED 0x01
 /* maximum number of available hifs */
 #define MRVL_MUSDK_HIFS_MAX 9
 
@@ -180,9 +182,47 @@ mrvl_reserve_bit(int *bitmap, int max)
 }
 
 /**
+ * Configure rss based on dpdk rss configuration.
+ *
+ * @param priv
+ *   Pointer to private structure.
+ * @param rss_conf
+ *   Pointer to RSS configuration.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_configure_rss(struct mrvl_priv *priv, struct rte_eth_rss_conf *rss_conf)
+{
+	if (rss_conf->rss_key)
+		RTE_LOG(WARNING, PMD, "Changing hash key is not supported\n");
+
+	if (rss_conf->rss_hf == 0) {
+		priv->ppio_params.inqs_params.hash_type = PP2_PPIO_HASH_T_NONE;
+	} else if (rss_conf->rss_hf & ETH_RSS_IPV4) {
+		priv->ppio_params.inqs_params.hash_type =
+			PP2_PPIO_HASH_T_2_TUPLE;
+	} else if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV4_TCP) {
+		priv->ppio_params.inqs_params.hash_type =
+			PP2_PPIO_HASH_T_5_TUPLE;
+		priv->rss_hf_tcp = 1;
+	} else if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV4_UDP) {
+		priv->ppio_params.inqs_params.hash_type =
+			PP2_PPIO_HASH_T_5_TUPLE;
+		priv->rss_hf_tcp = 0;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
  * Ethernet device configuration.
  *
- * Prepare the driver for a given number of TX and RX queues.
+ * Prepare the driver for a given number of TX and RX queues and
+ * configure RSS.
  *
  * @param dev
  *   Pointer to Ethernet device structure.
@@ -196,7 +236,8 @@ mrvl_dev_configure(struct rte_eth_dev *dev)
 	struct mrvl_priv *priv = dev->data->dev_private;
 	int ret;
 
-	if (dev->data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_NONE) {
+	if (dev->data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_NONE &&
+	    dev->data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_RSS) {
 		RTE_LOG(INFO, PMD, "Unsupported rx multi queue mode %d\n",
 			dev->data->dev_conf.rxmode.mq_mode);
 		return -EINVAL;
@@ -240,7 +281,16 @@ mrvl_dev_configure(struct rte_eth_dev *dev)
 	priv->ppio_params.outqs_params.num_outqs = dev->data->nb_tx_queues;
 	priv->nb_rx_queues = dev->data->nb_rx_queues;
 
-	return 0;
+	if (dev->data->nb_rx_queues == 1 &&
+	    dev->data->dev_conf.rxmode.mq_mode == ETH_MQ_RX_RSS) {
+		RTE_LOG(WARNING, PMD, "Disabling hash for 1 rx queue\n");
+		priv->ppio_params.inqs_params.hash_type = PP2_PPIO_HASH_T_NONE;
+
+		return 0;
+	}
+
+	return mrvl_configure_rss(priv,
+				  &dev->data->dev_conf.rx_adv_conf.rss_conf);
 }
 
 /**
@@ -800,6 +850,10 @@ mrvl_dev_infos_get(struct rte_eth_dev *dev __rte_unused,
 	info->tx_desc_lim.nb_align = MRVL_PP2_TXD_ALIGN;
 
 	info->rx_offload_capa = DEV_RX_OFFLOAD_JUMBO_FRAME;
+	info->flow_type_rss_offloads = ETH_RSS_IPV4 |
+				       ETH_RSS_NONFRAG_IPV4_TCP |
+				       ETH_RSS_NONFRAG_IPV4_UDP;
+
 	/* By default packets are dropped if no descriptors are available */
 	info->default_rxconf.rx_drop_en = 1;
 
@@ -1085,6 +1139,59 @@ mrvl_tx_queue_release(void *txq)
 	rte_free(q);
 }
 
+/**
+ * Update RSS hash configuration
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param rss_conf
+ *   Pointer to RSS configuration.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_rss_hash_update(struct rte_eth_dev *dev,
+		     struct rte_eth_rss_conf *rss_conf)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	return mrvl_configure_rss(priv, rss_conf);
+}
+
+/**
+ * DPDK callback to get RSS hash configuration.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @rss_conf
+ *   Pointer to RSS configuration.
+ *
+ * @return
+ *   Always 0.
+ */
+static int
+mrvl_rss_hash_conf_get(struct rte_eth_dev *dev,
+		       struct rte_eth_rss_conf *rss_conf)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	enum pp2_ppio_hash_type hash_type =
+		priv->ppio_params.inqs_params.hash_type;
+
+	rss_conf->rss_key = NULL;
+
+	if (hash_type == PP2_PPIO_HASH_T_NONE)
+		rss_conf->rss_hf = 0;
+	else if (hash_type == PP2_PPIO_HASH_T_2_TUPLE)
+		rss_conf->rss_hf = ETH_RSS_IPV4;
+	else if (hash_type == PP2_PPIO_HASH_T_5_TUPLE && priv->rss_hf_tcp)
+		rss_conf->rss_hf = ETH_RSS_NONFRAG_IPV4_TCP;
+	else if (hash_type == PP2_PPIO_HASH_T_5_TUPLE && !priv->rss_hf_tcp)
+		rss_conf->rss_hf = ETH_RSS_NONFRAG_IPV4_UDP;
+
+	return 0;
+}
+
 static const struct eth_dev_ops mrvl_ops = {
 	.dev_configure = mrvl_dev_configure,
 	.dev_start = mrvl_dev_start,
@@ -1108,6 +1215,8 @@ static const struct eth_dev_ops mrvl_ops = {
 	.rx_queue_release = mrvl_rx_queue_release,
 	.tx_queue_setup = mrvl_tx_queue_setup,
 	.tx_queue_release = mrvl_tx_queue_release,
+	.rss_hash_update = mrvl_rss_hash_update,
+	.rss_hash_conf_get = mrvl_rss_hash_conf_get,
 };
 
 /**
@@ -1394,6 +1503,7 @@ mrvl_init_pp2(void)
 	memset(&init_params, 0, sizeof(init_params));
 	init_params.hif_reserved_map = MRVL_MUSDK_HIFS_RESERVED;
 	init_params.bm_pool_reserved_map = MRVL_MUSDK_BPOOLS_RESERVED;
+	init_params.rss_tbl_reserved_map = MRVL_MUSDK_RSS_RESERVED;
 
 	return pp2_init(&init_params);
 }
diff --git a/drivers/net/mrvl/mrvl_ethdev.h b/drivers/net/mrvl/mrvl_ethdev.h
index f43f426..136c555 100644
--- a/drivers/net/mrvl/mrvl_ethdev.h
+++ b/drivers/net/mrvl/mrvl_ethdev.h
@@ -98,6 +98,7 @@ struct mrvl_priv {
 	uint8_t pp_id;
 	uint8_t ppio_id;
 	uint8_t bpool_bit;
+	uint8_t rss_hf_tcp;
 	uint8_t uc_mc_flushed;
 
 	struct pp2_ppio_params ppio_params;
-- 
2.7.4

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

* [PATCH v4 11/16] net/mrvl: add support for vlan filtering
  2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
                           ` (9 preceding siblings ...)
  2017-10-09 15:00         ` [PATCH v4 10/16] net/mrvl: add rss hashing support Tomasz Duszynski
@ 2017-10-09 15:00         ` Tomasz Duszynski
  2017-10-09 15:00         ` [PATCH v4 12/16] net/mrvl: add crc, l3 and l4 offloads support Tomasz Duszynski
                           ` (5 subsequent siblings)
  16 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-09 15:00 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add support for vlan filtering.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 doc/guides/nics/features/mrvl.ini |  1 +
 drivers/net/mrvl/mrvl_ethdev.c    | 39 ++++++++++++++++++++++++++++++++++++++-
 drivers/net/mrvl/mrvl_ethdev.h    |  1 +
 3 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/doc/guides/nics/features/mrvl.ini b/doc/guides/nics/features/mrvl.ini
index e65dea7..5d9132e 100644
--- a/doc/guides/nics/features/mrvl.ini
+++ b/doc/guides/nics/features/mrvl.ini
@@ -13,3 +13,4 @@ Allmulticast mode    = Y
 Unicast MAC filter   = Y
 Multicast MAC filter = Y
 RSS hash             = Y
+VLAN filter          = Y
diff --git a/drivers/net/mrvl/mrvl_ethdev.c b/drivers/net/mrvl/mrvl_ethdev.c
index fe2603a..7023f5b 100644
--- a/drivers/net/mrvl/mrvl_ethdev.c
+++ b/drivers/net/mrvl/mrvl_ethdev.c
@@ -439,6 +439,19 @@ mrvl_dev_start(struct rte_eth_dev *dev)
 		priv->uc_mc_flushed = 1;
 	}
 
+	if (!priv->vlan_flushed) {
+		ret = pp2_ppio_flush_vlan(priv->ppio);
+		if (ret) {
+			RTE_LOG(ERR, PMD, "Failed to flush vlan list\n");
+			/*
+			 * TODO
+			 * once pp2_ppio_flush_vlan() is supported jump to out
+			 * goto out;
+			 */
+		}
+		priv->vlan_flushed = 1;
+	}
+
 	/* For default QoS config, don't start classifier. */
 	if (mrvl_qos_cfg) {
 		ret = mrvl_start_qos_mapping(priv);
@@ -849,7 +862,8 @@ mrvl_dev_infos_get(struct rte_eth_dev *dev __rte_unused,
 	info->tx_desc_lim.nb_min = MRVL_PP2_TXD_MIN;
 	info->tx_desc_lim.nb_align = MRVL_PP2_TXD_ALIGN;
 
-	info->rx_offload_capa = DEV_RX_OFFLOAD_JUMBO_FRAME;
+	info->rx_offload_capa = DEV_RX_OFFLOAD_JUMBO_FRAME |
+				DEV_RX_OFFLOAD_VLAN_FILTER;
 	info->flow_type_rss_offloads = ETH_RSS_IPV4 |
 				       ETH_RSS_NONFRAG_IPV4_TCP |
 				       ETH_RSS_NONFRAG_IPV4_UDP;
@@ -904,6 +918,28 @@ static void mrvl_txq_info_get(struct rte_eth_dev *dev, uint16_t tx_queue_id,
 }
 
 /**
+ * DPDK callback to Configure a VLAN filter.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param vlan_id
+ *   VLAN ID to filter.
+ * @param on
+ *   Toggle filter.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int
+mrvl_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+
+	return on ? pp2_ppio_add_vlan(priv->ppio, vlan_id) :
+		    pp2_ppio_remove_vlan(priv->ppio, vlan_id);
+}
+
+/**
  * Release buffers to hardware bpool (buffer-pool)
  *
  * @param rxq
@@ -1211,6 +1247,7 @@ static const struct eth_dev_ops mrvl_ops = {
 	.dev_infos_get = mrvl_dev_infos_get,
 	.rxq_info_get = mrvl_rxq_info_get,
 	.txq_info_get = mrvl_txq_info_get,
+	.vlan_filter_set = mrvl_vlan_filter_set,
 	.rx_queue_setup = mrvl_rx_queue_setup,
 	.rx_queue_release = mrvl_rx_queue_release,
 	.tx_queue_setup = mrvl_tx_queue_setup,
diff --git a/drivers/net/mrvl/mrvl_ethdev.h b/drivers/net/mrvl/mrvl_ethdev.h
index 136c555..72af4c7 100644
--- a/drivers/net/mrvl/mrvl_ethdev.h
+++ b/drivers/net/mrvl/mrvl_ethdev.h
@@ -100,6 +100,7 @@ struct mrvl_priv {
 	uint8_t bpool_bit;
 	uint8_t rss_hf_tcp;
 	uint8_t uc_mc_flushed;
+	uint8_t vlan_flushed;
 
 	struct pp2_ppio_params ppio_params;
 	struct pp2_cls_qos_tbl_params qos_tbl_params;
-- 
2.7.4

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

* [PATCH v4 12/16] net/mrvl: add crc, l3 and l4 offloads support
  2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
                           ` (10 preceding siblings ...)
  2017-10-09 15:00         ` [PATCH v4 11/16] net/mrvl: add support for vlan filtering Tomasz Duszynski
@ 2017-10-09 15:00         ` Tomasz Duszynski
  2017-10-09 15:00         ` [PATCH v4 13/16] net/mrvl: add packet type parsing support Tomasz Duszynski
                           ` (4 subsequent siblings)
  16 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-09 15:00 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add support for crc offload and l3/l4 checksum offloads.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 doc/guides/nics/features/mrvl.ini |   3 +
 drivers/net/mrvl/mrvl_ethdev.c    | 204 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 205 insertions(+), 2 deletions(-)

diff --git a/doc/guides/nics/features/mrvl.ini b/doc/guides/nics/features/mrvl.ini
index 5d9132e..8407b60 100644
--- a/doc/guides/nics/features/mrvl.ini
+++ b/doc/guides/nics/features/mrvl.ini
@@ -14,3 +14,6 @@ Unicast MAC filter   = Y
 Multicast MAC filter = Y
 RSS hash             = Y
 VLAN filter          = Y
+CRC offload          = Y
+L3 checksum offload  = Y
+L4 checksum offload  = Y
diff --git a/drivers/net/mrvl/mrvl_ethdev.c b/drivers/net/mrvl/mrvl_ethdev.c
index 7023f5b..f7dbdba 100644
--- a/drivers/net/mrvl/mrvl_ethdev.c
+++ b/drivers/net/mrvl/mrvl_ethdev.c
@@ -134,6 +134,7 @@ struct mrvl_rxq {
 	struct rte_mempool *mp;
 	int queue_id;
 	int port_id;
+	int cksum_enabled;
 };
 
 struct mrvl_txq {
@@ -863,7 +864,15 @@ mrvl_dev_infos_get(struct rte_eth_dev *dev __rte_unused,
 	info->tx_desc_lim.nb_align = MRVL_PP2_TXD_ALIGN;
 
 	info->rx_offload_capa = DEV_RX_OFFLOAD_JUMBO_FRAME |
-				DEV_RX_OFFLOAD_VLAN_FILTER;
+				DEV_RX_OFFLOAD_VLAN_FILTER |
+				DEV_RX_OFFLOAD_IPV4_CKSUM |
+				DEV_RX_OFFLOAD_UDP_CKSUM |
+				DEV_RX_OFFLOAD_TCP_CKSUM;
+
+	info->tx_offload_capa = DEV_TX_OFFLOAD_IPV4_CKSUM |
+				DEV_TX_OFFLOAD_UDP_CKSUM |
+				DEV_TX_OFFLOAD_TCP_CKSUM;
+
 	info->flow_type_rss_offloads = ETH_RSS_IPV4 |
 				       ETH_RSS_NONFRAG_IPV4_TCP |
 				       ETH_RSS_NONFRAG_IPV4_UDP;
@@ -1059,6 +1068,7 @@ mrvl_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
 
 	rxq->priv = priv;
 	rxq->mp = mp;
+	rxq->cksum_enabled = dev->data->dev_conf.rxmode.hw_ip_checksum;
 	rxq->queue_id = idx;
 	rxq->port_id = dev->data->port_id;
 	mrvl_port_to_bpool_lookup[rxq->port_id] = priv->bpool;
@@ -1257,6 +1267,107 @@ static const struct eth_dev_ops mrvl_ops = {
 };
 
 /**
+ * Return packet type information and l3/l4 offsets.
+ *
+ * @param desc
+ *   Pointer to the received packet descriptor.
+ * @param l3_offset
+ *   l3 packet offset.
+ * @param l4_offset
+ *   l4 packet offset.
+ *
+ * @return
+ *   Packet type information.
+ */
+static inline uint64_t
+mrvl_desc_to_packet_type_and_offset(struct pp2_ppio_desc *desc,
+				    uint8_t *l3_offset, uint8_t *l4_offset)
+{
+	enum pp2_inq_l3_type l3_type;
+	enum pp2_inq_l4_type l4_type;
+	uint64_t packet_type;
+
+	pp2_ppio_inq_desc_get_l3_info(desc, &l3_type, l3_offset);
+	pp2_ppio_inq_desc_get_l4_info(desc, &l4_type, l4_offset);
+
+	packet_type = RTE_PTYPE_L2_ETHER;
+
+	switch (l3_type) {
+	case PP2_INQ_L3_TYPE_IPV4_NO_OPTS:
+		packet_type |= RTE_PTYPE_L3_IPV4;
+		break;
+	case PP2_INQ_L3_TYPE_IPV4_OK:
+		packet_type |= RTE_PTYPE_L3_IPV4_EXT;
+		break;
+	case PP2_INQ_L3_TYPE_IPV4_TTL_ZERO:
+		packet_type |= RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
+		break;
+	case PP2_INQ_L3_TYPE_IPV6_NO_EXT:
+		packet_type |= RTE_PTYPE_L3_IPV6;
+		break;
+	case PP2_INQ_L3_TYPE_IPV6_EXT:
+		packet_type |= RTE_PTYPE_L3_IPV6_EXT;
+		break;
+	case PP2_INQ_L3_TYPE_ARP:
+		packet_type |= RTE_PTYPE_L2_ETHER_ARP;
+		/*
+		 * In case of ARP l4_offset is set to wrong value.
+		 * Set it to proper one so that later on mbuf->l3_len can be
+		 * calculated subtracting l4_offset and l3_offset.
+		 */
+		*l4_offset = *l3_offset + MRVL_ARP_LENGTH;
+		break;
+	default:
+		RTE_LOG(DEBUG, PMD, "Failed to recognise l3 packet type\n");
+		break;
+	}
+
+	switch (l4_type) {
+	case PP2_INQ_L4_TYPE_TCP:
+		packet_type |= RTE_PTYPE_L4_TCP;
+		break;
+	case PP2_INQ_L4_TYPE_UDP:
+		packet_type |= RTE_PTYPE_L4_UDP;
+		break;
+	default:
+		RTE_LOG(DEBUG, PMD, "Failed to recognise l4 packet type\n");
+		break;
+	}
+
+	return packet_type;
+}
+
+/**
+ * Get offload information from the received packet descriptor.
+ *
+ * @param desc
+ *   Pointer to the received packet descriptor.
+ *
+ * @return
+ *   Mbuf offload flags.
+ */
+static inline uint64_t
+mrvl_desc_to_ol_flags(struct pp2_ppio_desc *desc)
+{
+	uint64_t flags;
+	enum pp2_inq_desc_status status;
+
+	status = pp2_ppio_inq_desc_get_l3_pkt_error(desc);
+	if (unlikely(status != PP2_DESC_ERR_OK))
+		flags = PKT_RX_IP_CKSUM_BAD;
+	else
+		flags = PKT_RX_IP_CKSUM_GOOD;
+
+	status = pp2_ppio_inq_desc_get_l4_pkt_error(desc);
+	if (unlikely(status != PP2_DESC_ERR_OK))
+		flags |= PKT_RX_L4_CKSUM_BAD;
+	else
+		flags |= PKT_RX_L4_CKSUM_GOOD;
+
+	return flags;
+}
+
+/**
  * DPDK callback for receive.
  *
  * @param rxq
@@ -1294,6 +1405,7 @@ mrvl_rx_pkt_burst(void *rxq, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 
 	for (i = 0; i < nb_pkts; i++) {
 		struct rte_mbuf *mbuf;
+		uint8_t l3_offset, l4_offset;
 		enum pp2_inq_desc_status status;
 		uint64_t addr;
 
@@ -1331,6 +1443,15 @@ mrvl_rx_pkt_burst(void *rxq, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 		mbuf->pkt_len = pp2_ppio_inq_desc_get_pkt_len(&descs[i]);
 		mbuf->data_len = mbuf->pkt_len;
 		mbuf->port = q->port_id;
+		mbuf->packet_type =
+			mrvl_desc_to_packet_type_and_offset(&descs[i],
+							    &l3_offset,
+							    &l4_offset);
+		mbuf->l2_len = l3_offset;
+		mbuf->l3_len = l4_offset - l3_offset;
+
+		if (likely(q->cksum_enabled))
+			mbuf->ol_flags = mrvl_desc_to_ol_flags(&descs[i]);
 
 		rx_pkts[rx_done++] = mbuf;
 	}
@@ -1372,6 +1493,67 @@ mrvl_rx_pkt_burst(void *rxq, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 }
 
 /**
+ * Prepare offload information.
+ *
+ * @param ol_flags
+ *   Offload flags.
+ * @param packet_type
+ *   Packet type bitfield.
+ * @param l3_type
+ *   Pointer to the pp2_ouq_l3_type structure.
+ * @param l4_type
+ *   Pointer to the pp2_outq_l4_type structure.
+ * @param gen_l3_cksum
+ *   Will be set to 1 in case l3 checksum is computed.
+ * @param l4_cksum
+ *   Will be set to 1 in case l4 checksum is computed.
+ *
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static inline int
+mrvl_prepare_proto_info(uint64_t ol_flags, uint32_t packet_type,
+			enum pp2_outq_l3_type *l3_type,
+			enum pp2_outq_l4_type *l4_type,
+			int *gen_l3_cksum,
+			int *gen_l4_cksum)
+{
+	/*
+	 * Based on ol_flags prepare information
+	 * for pp2_ppio_outq_desc_set_proto_info() which setups descriptor
+	 * for offloading.
+	 */
+	if (ol_flags & PKT_TX_IPV4) {
+		*l3_type = PP2_OUTQ_L3_TYPE_IPV4;
+		*gen_l3_cksum = ol_flags & PKT_TX_IP_CKSUM ? 1 : 0;
+	} else if (ol_flags & PKT_TX_IPV6) {
+		*l3_type = PP2_OUTQ_L3_TYPE_IPV6;
+		/* no checksum for ipv6 header */
+		*gen_l3_cksum = 0;
+	} else {
+		/* if something different then stop processing */
+		return -1;
+	}
+
+	ol_flags &= PKT_TX_L4_MASK;
+	if ((packet_type & RTE_PTYPE_L4_TCP) &&
+	    ol_flags == PKT_TX_TCP_CKSUM) {
+		*l4_type = PP2_OUTQ_L4_TYPE_TCP;
+		*gen_l4_cksum = 1;
+	} else if ((packet_type & RTE_PTYPE_L4_UDP) &&
+		   ol_flags == PKT_TX_UDP_CKSUM) {
+		*l4_type = PP2_OUTQ_L4_TYPE_UDP;
+		*gen_l4_cksum = 1;
+	} else {
+		*l4_type = PP2_OUTQ_L4_TYPE_OTHER;
+		/* no checksum for other type */
+		*gen_l4_cksum = 0;
+	}
+
+	return 0;
+}
+
+/**
  * Release already sent buffers to bpool (buffer-pool).
  *
  * @param ppio
@@ -1467,7 +1649,7 @@ mrvl_tx_pkt_burst(void *txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 	struct mrvl_shadow_txq *sq = &shadow_txqs[q->port_id][rte_lcore_id()];
 	struct pp2_hif *hif = hifs[rte_lcore_id()];
 	struct pp2_ppio_desc descs[nb_pkts];
-	int i;
+	int i, ret;
 	uint16_t num, sq_free_size;
 
 	if (unlikely(!q->priv->ppio))
@@ -1486,6 +1668,9 @@ mrvl_tx_pkt_burst(void *txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 
 	for (i = 0; i < nb_pkts; i++) {
 		struct rte_mbuf *mbuf = tx_pkts[i];
+		int gen_l3_cksum, gen_l4_cksum;
+		enum pp2_outq_l3_type l3_type;
+		enum pp2_outq_l4_type l4_type;
 
 		if (likely(nb_pkts - i > MRVL_MUSDK_PREFETCH_SHIFT)) {
 			struct rte_mbuf *pref_pkt_hdr;
@@ -1510,6 +1695,21 @@ mrvl_tx_pkt_burst(void *txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 		pp2_ppio_outq_desc_set_pkt_offset(&descs[i], 0);
 		pp2_ppio_outq_desc_set_pkt_len(&descs[i],
 					       rte_pktmbuf_pkt_len(mbuf));
+
+		/*
+		 * in case unsupported ol_flags were passed
+		 * do not update descriptor offload information
+		 */
+		ret = mrvl_prepare_proto_info(mbuf->ol_flags, mbuf->packet_type,
+					      &l3_type, &l4_type, &gen_l3_cksum,
+					      &gen_l4_cksum);
+		if (unlikely(ret))
+			continue;
+
+		pp2_ppio_outq_desc_set_proto_info(&descs[i], l3_type, l4_type,
+						  mbuf->l2_len,
+						  mbuf->l2_len + mbuf->l3_len,
+						  gen_l3_cksum, gen_l4_cksum);
 	}
 
 	num = nb_pkts;
-- 
2.7.4

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

* [PATCH v4 13/16] net/mrvl: add packet type parsing support.
  2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
                           ` (11 preceding siblings ...)
  2017-10-09 15:00         ` [PATCH v4 12/16] net/mrvl: add crc, l3 and l4 offloads support Tomasz Duszynski
@ 2017-10-09 15:00         ` Tomasz Duszynski
  2017-10-09 15:00         ` [PATCH v4 14/16] net/mrvl: add basic stats support Tomasz Duszynski
                           ` (3 subsequent siblings)
  16 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-09 15:00 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add packet type parsing support.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 doc/guides/nics/features/mrvl.ini |  1 +
 drivers/net/mrvl/mrvl_ethdev.c    | 28 ++++++++++++++++++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/doc/guides/nics/features/mrvl.ini b/doc/guides/nics/features/mrvl.ini
index 8407b60..31b8a9c 100644
--- a/doc/guides/nics/features/mrvl.ini
+++ b/doc/guides/nics/features/mrvl.ini
@@ -17,3 +17,4 @@ VLAN filter          = Y
 CRC offload          = Y
 L3 checksum offload  = Y
 L4 checksum offload  = Y
+Packet type parsing  = Y
diff --git a/drivers/net/mrvl/mrvl_ethdev.c b/drivers/net/mrvl/mrvl_ethdev.c
index f7dbdba..d7a8527 100644
--- a/drivers/net/mrvl/mrvl_ethdev.c
+++ b/drivers/net/mrvl/mrvl_ethdev.c
@@ -884,6 +884,33 @@ mrvl_dev_infos_get(struct rte_eth_dev *dev __rte_unused,
 }
 
 /**
+ * Return supported packet types.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure (unused).
+ *
+ * @return
+ *   Const pointer to the table with supported packet types.
+ */
+static const uint32_t *
+mrvl_dev_supported_ptypes_get(struct rte_eth_dev *dev __rte_unused)
+{
+	static const uint32_t ptypes[] = {
+		RTE_PTYPE_L2_ETHER,
+		RTE_PTYPE_L3_IPV4,
+		RTE_PTYPE_L3_IPV4_EXT,
+		RTE_PTYPE_L3_IPV4_EXT_UNKNOWN,
+		RTE_PTYPE_L3_IPV6,
+		RTE_PTYPE_L3_IPV6_EXT,
+		RTE_PTYPE_L2_ETHER_ARP,
+		RTE_PTYPE_L4_TCP,
+		RTE_PTYPE_L4_UDP
+	};
+
+	return ptypes;
+}
+
+/**
  * DPDK callback to get information about specific receive queue.
  *
  * @param dev
@@ -1255,6 +1282,7 @@ static const struct eth_dev_ops mrvl_ops = {
 	.mac_addr_set = mrvl_mac_addr_set,
 	.mtu_set = mrvl_mtu_set,
 	.dev_infos_get = mrvl_dev_infos_get,
+	.dev_supported_ptypes_get = mrvl_dev_supported_ptypes_get,
 	.rxq_info_get = mrvl_rxq_info_get,
 	.txq_info_get = mrvl_txq_info_get,
 	.vlan_filter_set = mrvl_vlan_filter_set,
-- 
2.7.4

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

* [PATCH v4 14/16] net/mrvl: add basic stats support
  2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
                           ` (12 preceding siblings ...)
  2017-10-09 15:00         ` [PATCH v4 13/16] net/mrvl: add packet type parsing support Tomasz Duszynski
@ 2017-10-09 15:00         ` Tomasz Duszynski
  2017-10-09 15:00         ` [PATCH v4 15/16] maintainers: add maintainers for the mrvl net pmd Tomasz Duszynski
                           ` (2 subsequent siblings)
  16 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-09 15:00 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add support for both per queue and overall basic statistics.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 doc/guides/nics/features/mrvl.ini |   1 +
 drivers/net/mrvl/mrvl_ethdev.c    | 142 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 142 insertions(+), 1 deletion(-)

diff --git a/doc/guides/nics/features/mrvl.ini b/doc/guides/nics/features/mrvl.ini
index 31b8a9c..3643b8b 100644
--- a/doc/guides/nics/features/mrvl.ini
+++ b/doc/guides/nics/features/mrvl.ini
@@ -18,3 +18,4 @@ CRC offload          = Y
 L3 checksum offload  = Y
 L4 checksum offload  = Y
 Packet type parsing  = Y
+Basic stats          = Y
diff --git a/drivers/net/mrvl/mrvl_ethdev.c b/drivers/net/mrvl/mrvl_ethdev.c
index d7a8527..46879a4 100644
--- a/drivers/net/mrvl/mrvl_ethdev.c
+++ b/drivers/net/mrvl/mrvl_ethdev.c
@@ -135,12 +135,15 @@ struct mrvl_rxq {
 	int queue_id;
 	int port_id;
 	int cksum_enabled;
+	uint64_t bytes_recv;
+	uint64_t drop_mac;
 };
 
 struct mrvl_txq {
 	struct mrvl_priv *priv;
 	int queue_id;
 	int port_id;
+	uint64_t bytes_sent;
 };
 
 /*
@@ -280,6 +283,7 @@ mrvl_dev_configure(struct rte_eth_dev *dev)
 		return ret;
 
 	priv->ppio_params.outqs_params.num_outqs = dev->data->nb_tx_queues;
+	priv->ppio_params.maintain_stats = 1;
 	priv->nb_rx_queues = dev->data->nb_rx_queues;
 
 	if (dev->data->nb_rx_queues == 1 &&
@@ -835,6 +839,131 @@ mrvl_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
 }
 
 /**
+ * DPDK callback to get device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param stats
+ *   Stats structure output buffer.
+ */
+static void
+mrvl_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	struct pp2_ppio_statistics ppio_stats;
+	uint64_t drop_mac = 0;
+	unsigned int i, idx, ret;
+
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		struct mrvl_rxq *rxq = dev->data->rx_queues[i];
+		struct pp2_ppio_inq_statistics rx_stats;
+
+		if (!rxq)
+			continue;
+
+		idx = rxq->queue_id;
+		if (unlikely(idx >= RTE_ETHDEV_QUEUE_STAT_CNTRS)) {
+			RTE_LOG(ERR, PMD,
+				"rx queue %d stats out of range (0 - %d)\n",
+				idx, RTE_ETHDEV_QUEUE_STAT_CNTRS - 1);
+			continue;
+		}
+
+		ret = pp2_ppio_inq_get_statistics(priv->ppio,
+						  priv->rxq_map[idx].tc,
+						  priv->rxq_map[idx].inq,
+						  &rx_stats, 0);
+		if (unlikely(ret)) {
+			RTE_LOG(ERR, PMD,
+				"Failed to update rx queue %d stats\n", idx);
+			break;
+		}
+
+		stats->q_ibytes[idx] = rxq->bytes_recv;
+		stats->q_ipackets[idx] = rx_stats.enq_desc - rxq->drop_mac;
+		stats->q_errors[idx] = rx_stats.drop_early +
+				       rx_stats.drop_fullq +
+				       rx_stats.drop_bm +
+				       rxq->drop_mac;
+		stats->ibytes += rxq->bytes_recv;
+		drop_mac += rxq->drop_mac;
+	}
+
+	for (i = 0; i < dev->data->nb_tx_queues; i++) {
+		struct mrvl_txq *txq = dev->data->tx_queues[i];
+		struct pp2_ppio_outq_statistics tx_stats;
+
+		if (!txq)
+			continue;
+
+		idx = txq->queue_id;
+		if (unlikely(idx >= RTE_ETHDEV_QUEUE_STAT_CNTRS)) {
+			RTE_LOG(ERR, PMD,
+				"tx queue %d stats out of range (0 - %d)\n",
+				idx, RTE_ETHDEV_QUEUE_STAT_CNTRS - 1);
+		}
+
+		ret = pp2_ppio_outq_get_statistics(priv->ppio, idx,
+						   &tx_stats, 0);
+		if (unlikely(ret)) {
+			RTE_LOG(ERR, PMD,
+				"Failed to update tx queue %d stats\n", idx);
+			break;
+		}
+
+		stats->q_opackets[idx] = tx_stats.deq_desc;
+		stats->q_obytes[idx] = txq->bytes_sent;
+		stats->obytes += txq->bytes_sent;
+	}
+
+	ret = pp2_ppio_get_statistics(priv->ppio, &ppio_stats, 0);
+	if (unlikely(ret)) {
+		RTE_LOG(ERR, PMD, "Failed to update port statistics\n");
+		return;
+	}
+
+	stats->ipackets += ppio_stats.rx_packets - drop_mac;
+	stats->opackets += ppio_stats.tx_packets;
+	stats->imissed += ppio_stats.rx_fullq_dropped +
+			  ppio_stats.rx_bm_dropped +
+			  ppio_stats.rx_early_dropped +
+			  ppio_stats.rx_fifo_dropped +
+			  ppio_stats.rx_cls_dropped;
+	stats->ierrors = drop_mac;
+}
+
+/**
+ * DPDK callback to clear device statistics.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mrvl_stats_reset(struct rte_eth_dev *dev)
+{
+	struct mrvl_priv *priv = dev->data->dev_private;
+	int i;
+
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		struct mrvl_rxq *rxq = dev->data->rx_queues[i];
+
+		pp2_ppio_inq_get_statistics(priv->ppio, priv->rxq_map[i].tc,
+					    priv->rxq_map[i].inq, NULL, 1);
+		rxq->bytes_recv = 0;
+		rxq->drop_mac = 0;
+	}
+
+	for (i = 0; i < dev->data->nb_tx_queues; i++) {
+		struct mrvl_txq *txq = dev->data->tx_queues[i];
+
+		pp2_ppio_outq_get_statistics(priv->ppio, i, NULL, 1);
+		txq->bytes_sent = 0;
+	}
+
+	pp2_ppio_get_statistics(priv->ppio, NULL, 1);
+}
+
+/**
  * DPDK callback to get information about the device.
  *
  * @param dev
@@ -1281,6 +1410,8 @@ static const struct eth_dev_ops mrvl_ops = {
 	.mac_addr_add = mrvl_mac_addr_add,
 	.mac_addr_set = mrvl_mac_addr_set,
 	.mtu_set = mrvl_mtu_set,
+	.stats_get = mrvl_stats_get,
+	.stats_reset = mrvl_stats_reset,
 	.dev_infos_get = mrvl_dev_infos_get,
 	.dev_supported_ptypes_get = mrvl_dev_supported_ptypes_get,
 	.rxq_info_get = mrvl_rxq_info_get,
@@ -1464,6 +1595,7 @@ mrvl_rx_pkt_burst(void *rxq, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 			pp2_bpool_put_buff(hifs[core_id], bpool, &binf);
 			mrvl_port_bpool_size
 				[bpool->pp2_id][bpool->id][core_id]++;
+			q->drop_mac++;
 			continue;
 		}
 
@@ -1482,6 +1614,7 @@ mrvl_rx_pkt_burst(void *rxq, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 			mbuf->ol_flags = mrvl_desc_to_ol_flags(&descs[i]);
 
 		rx_pkts[rx_done++] = mbuf;
+		q->bytes_recv += mbuf->pkt_len;
 	}
 
 	if (rte_spinlock_trylock(&q->priv->lock) == 1) {
@@ -1677,8 +1810,9 @@ mrvl_tx_pkt_burst(void *txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 	struct mrvl_shadow_txq *sq = &shadow_txqs[q->port_id][rte_lcore_id()];
 	struct pp2_hif *hif = hifs[rte_lcore_id()];
 	struct pp2_ppio_desc descs[nb_pkts];
-	int i, ret;
+	int i, ret, bytes_sent = 0;
 	uint16_t num, sq_free_size;
+	uint64_t addr;
 
 	if (unlikely(!q->priv->ppio))
 		return 0;
@@ -1724,6 +1858,7 @@ mrvl_tx_pkt_burst(void *txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 		pp2_ppio_outq_desc_set_pkt_len(&descs[i],
 					       rte_pktmbuf_pkt_len(mbuf));
 
+		bytes_sent += rte_pktmbuf_pkt_len(mbuf);
 		/*
 		 * in case unsupported ol_flags were passed
 		 * do not update descriptor offload information
@@ -1747,10 +1882,15 @@ mrvl_tx_pkt_burst(void *txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 		for (i = nb_pkts; i < num; i++) {
 			sq->head = (MRVL_PP2_TX_SHADOWQ_SIZE + sq->head - 1) &
 				MRVL_PP2_TX_SHADOWQ_MASK;
+			addr = cookie_addr_high | sq->ent[sq->head].buff.cookie;
+			bytes_sent -=
+				rte_pktmbuf_pkt_len((struct rte_mbuf *)addr);
 		}
 		sq->size -= num - nb_pkts;
 	}
 
+	q->bytes_sent += bytes_sent;
+
 	return nb_pkts;
 }
 
-- 
2.7.4

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

* [PATCH v4 15/16] maintainers: add maintainers for the mrvl net pmd
  2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
                           ` (13 preceding siblings ...)
  2017-10-09 15:00         ` [PATCH v4 14/16] net/mrvl: add basic stats support Tomasz Duszynski
@ 2017-10-09 15:00         ` Tomasz Duszynski
  2017-10-09 19:02           ` Ferruh Yigit
  2017-10-10  3:20           ` Jianbo Liu
  2017-10-09 15:00         ` [PATCH v4 16/16] doc: add mrvl net pmd documentation Tomasz Duszynski
  2017-10-09 20:59         ` [PATCH v4 00/16] add net mrvl pmd driver Ferruh Yigit
  16 siblings, 2 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-09 15:00 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 MAINTAINERS | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 1b74f98..5c78477 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -392,6 +392,16 @@ F: drivers/net/mlx5/
 F: doc/guides/nics/mlx5.rst
 F: doc/guides/nics/features/mlx5.ini
 
+Marvell mrvl
+M: Jacek Siuda <jck@semihalf.com>
+M: Tomasz Duszynski <tdu@semihalf.com>
+M: Dmitri Epshtein <dima@marvell.com>
+M: Natalie Samsonov <nsamsono@marvell.com>
+M: Jianbo Liu <jianbo.liu@linaro.org>
+F: drivers/net/mrvl/
+F: doc/guides/nics/mrvl.rst
+F: doc/guides/nics/features/mrvl.ini
+
 Netcope szedata2
 M: Matej Vido <vido@cesnet.cz>
 F: drivers/net/szedata2/
-- 
2.7.4

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

* [PATCH v4 16/16] doc: add mrvl net pmd documentation
  2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
                           ` (14 preceding siblings ...)
  2017-10-09 15:00         ` [PATCH v4 15/16] maintainers: add maintainers for the mrvl net pmd Tomasz Duszynski
@ 2017-10-09 15:00         ` Tomasz Duszynski
  2017-10-09 20:54           ` Ferruh Yigit
  2017-10-11 14:27           ` Thomas Monjalon
  2017-10-09 20:59         ` [PATCH v4 00/16] add net mrvl pmd driver Ferruh Yigit
  16 siblings, 2 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-09 15:00 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add documentation for the MRVL NET PMD driver.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <jck@semihalf.com>
---
 doc/guides/nics/features/mrvl.ini |   2 +
 doc/guides/nics/index.rst         |   1 +
 doc/guides/nics/mrvl.rst          | 256 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 259 insertions(+)
 create mode 100644 doc/guides/nics/mrvl.rst

diff --git a/doc/guides/nics/features/mrvl.ini b/doc/guides/nics/features/mrvl.ini
index 3643b8b..00d9621 100644
--- a/doc/guides/nics/features/mrvl.ini
+++ b/doc/guides/nics/features/mrvl.ini
@@ -19,3 +19,5 @@ L3 checksum offload  = Y
 L4 checksum offload  = Y
 Packet type parsing  = Y
 Basic stats          = Y
+ARMv8                = Y
+Usage doc            = Y
diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index 4115141..df19ec7 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -56,6 +56,7 @@ Network Interface Controller Drivers
     liquidio
     mlx4
     mlx5
+    mrvl
     nfp
     qede
     sfc_efx
diff --git a/doc/guides/nics/mrvl.rst b/doc/guides/nics/mrvl.rst
new file mode 100644
index 0000000..462bc0e
--- /dev/null
+++ b/doc/guides/nics/mrvl.rst
@@ -0,0 +1,256 @@
+..  BSD LICENSE
+    Copyright(c) 2017 Semihalf. All rights reserved.
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in
+        the documentation and/or other materials provided with the
+        distribution.
+      * Neither the name of Semihalf 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.
+
+MRVL Poll Mode Driver
+======================
+
+The MRVL PMD (librte_pmd_mrvl) provides poll mode driver support
+for the Marvell PPv2 (Packet Processor v2) 1/10 Gbps adapter.
+
+Detailed information about SoCs that use PPv2 can be obtained here:
+
+* https://www.marvell.com/embedded-processors/armada-70xx/
+* https://www.marvell.com/embedded-processors/armada-80xx/
+
+.. Note::
+
+   Due to external dependencies, this driver is disabled by default. It must
+   be enabled manually by setting relevant configuration option manually.
+   Please refer to `Config File Options`_ section for further details.
+
+
+Features
+--------
+
+Features of the MRVL PMD are:
+
+- Speed capabilities
+- Link status
+- Queue start/stop
+- MTU update
+- Jumbo frame
+- Promiscuous mode
+- Allmulticast mode
+- Unicast MAC filter
+- Multicast MAC filter
+- RSS hash
+- VLAN filter
+- CRC offload
+- L3 checksum offload
+- L4 checksum offload
+- Packet type parsing
+- Basic stats
+- QoS
+
+
+Limitations
+-----------
+
+- Number of lcores is limited to 9 by MUSDK internal design. If more lcores
+  need to be allocated, locking will have to be considered. Number of available
+  lcores can be changed via ``MRVL_MUSDK_HIFS_RESERVED`` define in
+  ``mrvl_ethdev.c`` source file.
+
+- Flushing vlans added for filtering is not possible due to MUSDK missing
+  functionality. Current workaround is to reset board so that PPv2 has a
+  chance to start in a sane state.
+
+
+Prerequisites
+-------------
+
+- Custom Linux Kernel sources available
+  `here <https://github.com/MarvellEmbeddedProcessors/linux-marvell/tree/linux-4.4.52-armada-17.08>`__.
+
+- Out of tree `mvpp2x_sysfs` kernel module sources available
+  `here <https://github.com/MarvellEmbeddedProcessors/mvpp2x-marvell/tree/mvpp2x-armada-17.08>`__.
+
+- MUSDK (Marvell User-Space SDK) sources available
+  `here <https://github.com/MarvellEmbeddedProcessors/musdk-marvell/tree/musdk-armada-17.08>`__.
+
+    MUSDK is a light-weight library that provides direct access to Marvell's
+    PPv2 (Packet Processor v2). Alternatively prebuilt MUSDK library can be
+    requested from `Marvell Extranet <https://extranet.marvell.com>`_. Once
+    approval has been granted, library can be found by typing ``musdk`` in
+    the search box.
+
+    MUSDK must be configured with the following features:
+
+    .. code-block:: console
+
+       --enable-bpool-dma=64
+
+- DPDK environment
+
+    Follow the DPDK :ref:`Getting Started Guide for Linux <linux_gsg>` to setup
+    DPDK environment.
+
+
+Config File Options
+-------------------
+
+The following options can be modified in the ``config`` file.
+
+- ``CONFIG_RTE_LIBRTE_MRVL_PMD`` (default ``n``)
+
+    Toggle compilation of the librte_pmd_mrvl driver.
+
+- ``CONFIG_RTE_LIBRTE_MRVL_DEBUG`` (default ``n``)
+
+    Toggle display of debugging messages.
+
+- ``CONFIG_RTE_MRVL_MUSDK_DMA_MEMSIZE`` (default ``41943040``)
+
+    Size in bytes of the contiguous memory region that MUSDK will allocate
+    for run-time DMA-able data buffers.
+
+
+QoS Configuration
+-----------------
+
+QoS configuration is done through external configuration file. Path to the
+file must be given as `cfg` in driver's vdev parameter list.
+
+Configuration syntax
+~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: console
+
+   [port <portnum> default]
+   default_tc = <default_tc>
+   qos_mode = <qos_priority>
+
+   [port <portnum> tc <traffic_class>]
+   rxq = <rx_queue_list>
+   pcp = <pcp_list>
+   dscp = <dscp_list>
+
+   [port <portnum> tc <traffic_class>]
+   rxq = <rx_queue_list>
+   pcp = <pcp_list>
+   dscp = <dscp_list>
+
+Where:
+
+- ``<portnum>``: DPDK Port number (0..n).
+
+- ``<default_tc>``: Default traffic class (e.g. 0)
+
+- ``<qos_priority>``: QoS priority for mapping (`ip`, `vlan`, `ip/vlan` or `vlan/ip`).
+
+- ``<traffic_class>``: Traffic Class to be configured.
+
+- ``<rx_queue_list>``: List of DPDK RX queues (e.g. 0 1 3-4)
+
+- ``<pcp_list>``: List of PCP values to handle in particular TC (e.g. 0 1 3-4 7).
+
+- ``<dscp_list>``: List of DSCP values to handle in particular TC (e.g. 0-12 32-48 63).
+
+Setting PCP/DSCP values for the default TC is not required. All PCP/DSCP
+values not assigned explicitly to particular TC will be handled by the
+default TC.
+
+Configuration file example
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: console
+
+   [port 0 default]
+   default_tc = 0
+   qos_mode = ip
+
+   [port 0 tc 0]
+   rxq = 0 1
+
+   [port 0 tc 1]
+   rxq = 2
+   pcp = 5 6 7
+   dscp = 26-38
+
+   [port 1 default]
+   default_tc = 0
+   qos_mode = vlan/ip
+
+   [port 1 tc 0]
+   rxq = 0
+
+   [port 1 tc 1]
+   rxq = 1 2
+   pcp = 5 6 7
+   dscp = 26-38
+
+Usage example
+^^^^^^^^^^^^^
+
+.. code-block:: console
+
+   ./testpmd --vdev=eth_mrvl,iface=eth0,iface=eth2,cfg=/home/user/mrvl.conf \
+     -c 7 -- -i -a --disable-hw-vlan-strip --rxq=2
+
+
+Building DPDK
+-------------
+
+Driver needs precompiled MUSDK library during compilation. Please consult
+``doc/musdk_get_started.txt`` for the detailed build instructions.
+
+Before the DPDK build process the environmental variable ``LIBMUSDK_PATH`` with
+the path to the MUSDK installation directory needs to be exported.
+
+
+Usage Example
+-------------
+
+MRVL PMD requires extra out of tree kernel modules to function properly.
+`musdk_uio` and `mv_pp_uio` sources are part of the MUSDK. Please consult
+``doc/musdk_get_started.txt`` for the detailed build instructions.
+For `mvpp2x_sysfs` please consult ``Documentation/pp22_sysfs.txt`` for the
+detailed build instructions.
+
+.. code-block:: console
+
+   insmod musdk_uio.ko
+   insmod mv_pp_uio.ko
+   insmod mvpp2x_sysfs.ko
+
+Additionally interfaces used by DPDK application need to be put up:
+
+.. code-block:: console
+
+   ip link set eth0 up
+   ip link set eth1 up
+
+In order to run testpmd example application following command can be used:
+
+.. code-block:: console
+
+   ./testpmd --vdev=eth_mrvl,iface=eth0,iface=eth2 -c 7 -- \
+     --burst=128 --txd=2048 --rxd=1024 --rxq=2 --txq=2  --nb-cores=2 \
+     -i -a --disable-hw-vlan-strip --rss-udp
-- 
2.7.4

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

* Re: [PATCH v4 15/16] maintainers: add maintainers for the mrvl net pmd
  2017-10-09 15:00         ` [PATCH v4 15/16] maintainers: add maintainers for the mrvl net pmd Tomasz Duszynski
@ 2017-10-09 19:02           ` Ferruh Yigit
  2017-10-09 19:09             ` Marcin Wojtas
  2017-10-10  5:47             ` Tomasz Duszynski
  2017-10-10  3:20           ` Jianbo Liu
  1 sibling, 2 replies; 110+ messages in thread
From: Ferruh Yigit @ 2017-10-09 19:02 UTC (permalink / raw)
  To: Tomasz Duszynski, dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On 10/9/2017 4:00 PM, Tomasz Duszynski wrote:
> Signed-off-by: Jacek Siuda <jck@semihalf.com>
> Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>

Congratulations!,

this is the 30000. patch in patchwork:
http://dpdk.org/dev/patchwork/patch/30000/

20000 was here:
http://dpdk.org/ml/archives/dev/2017-January/056354.html

10K patches in less than 10 months (close to 9 months), this is lots of
patches :)

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

* Re: [PATCH v4 15/16] maintainers: add maintainers for the mrvl net pmd
  2017-10-09 19:02           ` Ferruh Yigit
@ 2017-10-09 19:09             ` Marcin Wojtas
  2017-10-09 19:12               ` Ferruh Yigit
  2017-10-10  5:47             ` Tomasz Duszynski
  1 sibling, 1 reply; 110+ messages in thread
From: Marcin Wojtas @ 2017-10-09 19:09 UTC (permalink / raw)
  To: Ferruh Yigit
  Cc: Tomasz Duszynski, dev, Dmitri Epshtein, nsamsono, Jianbo.liu,
	Jacek Siuda

2017-10-09 21:02 GMT+02:00 Ferruh Yigit <ferruh.yigit@intel.com>:
> On 10/9/2017 4:00 PM, Tomasz Duszynski wrote:
>> Signed-off-by: Jacek Siuda <jck@semihalf.com>
>> Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
>
> Congratulations!,
>
> this is the 30000. patch in patchwork:
> http://dpdk.org/dev/patchwork/patch/30000/

There's no other option now, but to merge the jubilee patchset ;)

Best regards,
Marcin

>
> 20000 was here:
> http://dpdk.org/ml/archives/dev/2017-January/056354.html
>
> 10K patches in less than 10 months (close to 9 months), this is lots of
> patches :)

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

* Re: [PATCH v4 15/16] maintainers: add maintainers for the mrvl net pmd
  2017-10-09 19:09             ` Marcin Wojtas
@ 2017-10-09 19:12               ` Ferruh Yigit
  0 siblings, 0 replies; 110+ messages in thread
From: Ferruh Yigit @ 2017-10-09 19:12 UTC (permalink / raw)
  To: Marcin Wojtas
  Cc: Tomasz Duszynski, dev, Dmitri Epshtein, nsamsono, Jianbo.liu,
	Jacek Siuda

On 10/9/2017 8:09 PM, Marcin Wojtas wrote:
> 2017-10-09 21:02 GMT+02:00 Ferruh Yigit <ferruh.yigit@intel.com>:
>> On 10/9/2017 4:00 PM, Tomasz Duszynski wrote:
>>> Signed-off-by: Jacek Siuda <jck@semihalf.com>
>>> Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
>>
>> Congratulations!,
>>
>> this is the 30000. patch in patchwork:
>> http://dpdk.org/dev/patchwork/patch/30000/
> 
> There's no other option now, but to merge the jubilee patchset ;)

nice try ;)

> 
> Best regards,
> Marcin
> 
>>
>> 20000 was here:
>> http://dpdk.org/ml/archives/dev/2017-January/056354.html
>>
>> 10K patches in less than 10 months (close to 9 months), this is lots of
>> patches :)

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

* Re: [PATCH v4 16/16] doc: add mrvl net pmd documentation
  2017-10-09 15:00         ` [PATCH v4 16/16] doc: add mrvl net pmd documentation Tomasz Duszynski
@ 2017-10-09 20:54           ` Ferruh Yigit
  2017-10-10  5:51             ` Tomasz Duszynski
  2017-10-11 14:27           ` Thomas Monjalon
  1 sibling, 1 reply; 110+ messages in thread
From: Ferruh Yigit @ 2017-10-09 20:54 UTC (permalink / raw)
  To: Tomasz Duszynski, dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On 10/9/2017 4:00 PM, Tomasz Duszynski wrote:
> Add documentation for the MRVL NET PMD driver.
> 
> Signed-off-by: Jacek Siuda <jck@semihalf.com>
> Signed-off-by: Tomasz Duszynski <jck@semihalf.com>

I guess this should be "Tomasz Duszynski <tdu@semihalf.com>" :)

Fixing accordingly while applying.

<...>

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

* Re: [PATCH v4 00/16] add net mrvl pmd driver
  2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
                           ` (15 preceding siblings ...)
  2017-10-09 15:00         ` [PATCH v4 16/16] doc: add mrvl net pmd documentation Tomasz Duszynski
@ 2017-10-09 20:59         ` Ferruh Yigit
  2017-10-10  0:25           ` Ferruh Yigit
                             ` (2 more replies)
  16 siblings, 3 replies; 110+ messages in thread
From: Ferruh Yigit @ 2017-10-09 20:59 UTC (permalink / raw)
  To: Tomasz Duszynski, dev; +Cc: mw, dima, nsamsono, Jianbo.liu

On 10/9/2017 4:00 PM, Tomasz Duszynski wrote:
> Hello,
> 
> This patch series introduces the net driver for Marvell Armada 7k/8k
> SoCs along with documentation.
> 
> Below you can find the list of features which net pmd supports:
> * Speed capabilities
> * Link status
> * MTU update
> * Jumbo frame
> * Promiscuous mode
> * Allmulticast mode
> * Unicast MAC filter
> * Multicast MAC filter
> * RSS hash
> * VLAN filter
> * CRC offload
> * L3 checksum offload
> * L4 checksum offload
> * Packet type parsing
> * Basic stats
> * QoS
> 
> Changes since v3:
> * Split driver into skeleton, rx/tx, features, documentation parts
> * Added speed capabilities flags.
> * Added missing rx offload flags: VLAN/JUMBOFRAME
> * Updated release notes.
> * Updated documentation.
> 
> Changes since v2:
> * Removed LINE_SPACING, MULTILINE_DEREFERENCE and SPLIT_STRING
>   checkpatch warnings.
> * Removed unnecessary forward declarations.
> * Fixed whitespace warnings.
> 
> Changes since v1:
> * Changed commit message to explain problem better.
> * Removed bunch of checkpatch warnings about unnecessary parentheses.
> 
> Tomasz Duszynski (4):
>   app: link the whole rte_cfgfile library
>   net/mrvl: add mrvl net pmd driver skeleton
>   net/mrvl: add rx/tx support
>   net/mrvl: add link update
>   net/mrvl: add link speed capabilities
>   net/mrvl: add support for updating mtu
>   net/mrvl: add jumbo frame support
>   net/mrvl: add support for promiscuous and allmulticast modes
>   net/mrvl: add support for mac filtering
>   net/mrvl: add rss hashing support
>   net/mrvl: add support for vlan filtering
>   net/mrvl: add crc, l3 and l4 offloads support
>   net/mrvl: add packet type parsing support.
>   net/mrvl: add basic stats support
>   maintainers: add maintainers for the mrvl net pmd
>   doc: add mrvl net pmd documentation

Series applied to dpdk-next-net/master, thanks.

(I can't compile because of missing musdk library, but since PMD is
disabled by default this is not so bad, lets get this for rc1 and for
crypto dependency, later I can have my environment set and test)

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

* Re: [PATCH v4 00/16] add net mrvl pmd driver
  2017-10-09 20:59         ` [PATCH v4 00/16] add net mrvl pmd driver Ferruh Yigit
@ 2017-10-10  0:25           ` Ferruh Yigit
  2017-10-10  7:07             ` Tomasz Duszynski
  2017-10-10  5:55           ` Tomasz Duszynski
  2017-10-12  1:51           ` Ferruh Yigit
  2 siblings, 1 reply; 110+ messages in thread
From: Ferruh Yigit @ 2017-10-10  0:25 UTC (permalink / raw)
  To: Tomasz Duszynski, dev; +Cc: mw, dima, nsamsono, Jianbo.liu

On 10/9/2017 9:59 PM, Ferruh Yigit wrote:
> On 10/9/2017 4:00 PM, Tomasz Duszynski wrote:
>> Hello,
>>
>> This patch series introduces the net driver for Marvell Armada 7k/8k
>> SoCs along with documentation.
>>
>> Below you can find the list of features which net pmd supports:
>> * Speed capabilities
>> * Link status
>> * MTU update
>> * Jumbo frame
>> * Promiscuous mode
>> * Allmulticast mode
>> * Unicast MAC filter
>> * Multicast MAC filter
>> * RSS hash
>> * VLAN filter
>> * CRC offload
>> * L3 checksum offload
>> * L4 checksum offload
>> * Packet type parsing
>> * Basic stats
>> * QoS
>>
>> Changes since v3:
>> * Split driver into skeleton, rx/tx, features, documentation parts
>> * Added speed capabilities flags.
>> * Added missing rx offload flags: VLAN/JUMBOFRAME
>> * Updated release notes.
>> * Updated documentation.
>>
>> Changes since v2:
>> * Removed LINE_SPACING, MULTILINE_DEREFERENCE and SPLIT_STRING
>>   checkpatch warnings.
>> * Removed unnecessary forward declarations.
>> * Fixed whitespace warnings.
>>
>> Changes since v1:
>> * Changed commit message to explain problem better.
>> * Removed bunch of checkpatch warnings about unnecessary parentheses.
>>
>> Tomasz Duszynski (4):
>>   app: link the whole rte_cfgfile library
>>   net/mrvl: add mrvl net pmd driver skeleton
>>   net/mrvl: add rx/tx support
>>   net/mrvl: add link update
>>   net/mrvl: add link speed capabilities
>>   net/mrvl: add support for updating mtu
>>   net/mrvl: add jumbo frame support
>>   net/mrvl: add support for promiscuous and allmulticast modes
>>   net/mrvl: add support for mac filtering
>>   net/mrvl: add rss hashing support
>>   net/mrvl: add support for vlan filtering
>>   net/mrvl: add crc, l3 and l4 offloads support
>>   net/mrvl: add packet type parsing support.
>>   net/mrvl: add basic stats support
>>   maintainers: add maintainers for the mrvl net pmd
>>   doc: add mrvl net pmd documentation
> 
> Series applied to dpdk-next-net/master, thanks.

Can you also add a web patch [1] to list NICs as supported NICs [2] ?

[1]
http://dpdk.org/browse/tools/dpdk-web/

[2]
http://dpdk.org/doc/nics


> 
> (I can't compile because of missing musdk library, but since PMD is
> disabled by default this is not so bad, lets get this for rc1 and for
> crypto dependency, later I can have my environment set and test)
> 

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

* Re: [PATCH v4 15/16] maintainers: add maintainers for the mrvl net pmd
  2017-10-09 15:00         ` [PATCH v4 15/16] maintainers: add maintainers for the mrvl net pmd Tomasz Duszynski
  2017-10-09 19:02           ` Ferruh Yigit
@ 2017-10-10  3:20           ` Jianbo Liu
  2017-10-10  4:38             ` Ferruh Yigit
  1 sibling, 1 reply; 110+ messages in thread
From: Jianbo Liu @ 2017-10-10  3:20 UTC (permalink / raw)
  To: Tomasz Duszynski; +Cc: dev, mw, dima, nsamsono, Jacek Siuda

On 9 October 2017 at 23:00, Tomasz Duszynski <tdu@semihalf.com> wrote:
> Signed-off-by: Jacek Siuda <jck@semihalf.com>
> Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
> ---
>  MAINTAINERS | 10 ++++++++++
>  1 file changed, 10 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 1b74f98..5c78477 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -392,6 +392,16 @@ F: drivers/net/mlx5/
>  F: doc/guides/nics/mlx5.rst
>  F: doc/guides/nics/features/mlx5.ini
>
> +Marvell mrvl
> +M: Jacek Siuda <jck@semihalf.com>
> +M: Tomasz Duszynski <tdu@semihalf.com>
> +M: Dmitri Epshtein <dima@marvell.com>
> +M: Natalie Samsonov <nsamsono@marvell.com>
> +M: Jianbo Liu <jianbo.liu@linaro.org>

Please change my email to jianbo.liu@arm.com, thanks.

> +F: drivers/net/mrvl/
> +F: doc/guides/nics/mrvl.rst
> +F: doc/guides/nics/features/mrvl.ini
> +
>  Netcope szedata2
>  M: Matej Vido <vido@cesnet.cz>
>  F: drivers/net/szedata2/
> --
> 2.7.4
>

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

* Re: [PATCH v4 15/16] maintainers: add maintainers for the mrvl net pmd
  2017-10-10  3:20           ` Jianbo Liu
@ 2017-10-10  4:38             ` Ferruh Yigit
  0 siblings, 0 replies; 110+ messages in thread
From: Ferruh Yigit @ 2017-10-10  4:38 UTC (permalink / raw)
  To: Jianbo Liu, Tomasz Duszynski; +Cc: dev, mw, dima, nsamsono, Jacek Siuda

On 10/10/2017 4:20 AM, Jianbo Liu wrote:
> On 9 October 2017 at 23:00, Tomasz Duszynski <tdu@semihalf.com> wrote:
>> Signed-off-by: Jacek Siuda <jck@semihalf.com>
>> Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
>> ---
>>  MAINTAINERS | 10 ++++++++++
>>  1 file changed, 10 insertions(+)
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 1b74f98..5c78477 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -392,6 +392,16 @@ F: drivers/net/mlx5/
>>  F: doc/guides/nics/mlx5.rst
>>  F: doc/guides/nics/features/mlx5.ini
>>
>> +Marvell mrvl
>> +M: Jacek Siuda <jck@semihalf.com>
>> +M: Tomasz Duszynski <tdu@semihalf.com>
>> +M: Dmitri Epshtein <dima@marvell.com>
>> +M: Natalie Samsonov <nsamsono@marvell.com>
>> +M: Jianbo Liu <jianbo.liu@linaro.org>
> 
> Please change my email to jianbo.liu@arm.com, thanks.

Done.

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

* Re: [PATCH v4 15/16] maintainers: add maintainers for the mrvl net pmd
  2017-10-09 19:02           ` Ferruh Yigit
  2017-10-09 19:09             ` Marcin Wojtas
@ 2017-10-10  5:47             ` Tomasz Duszynski
  1 sibling, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-10  5:47 UTC (permalink / raw)
  To: Ferruh Yigit
  Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On Mon, Oct 09, 2017 at 08:02:07PM +0100, Ferruh Yigit wrote:
> On 10/9/2017 4:00 PM, Tomasz Duszynski wrote:
> > Signed-off-by: Jacek Siuda <jck@semihalf.com>
> > Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
>
> Congratulations!,
>
> this is the 30000. patch in patchwork:

30k patch and series applied, double win.

> http://dpdk.org/dev/patchwork/patch/30000/
>
> 20000 was here:
> http://dpdk.org/ml/archives/dev/2017-January/056354.html
>
> 10K patches in less than 10 months (close to 9 months), this is lots of
> patches :)

Lots of reviewing as well :).

--
- Tomasz Duszyński

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

* Re: [PATCH v4 16/16] doc: add mrvl net pmd documentation
  2017-10-09 20:54           ` Ferruh Yigit
@ 2017-10-10  5:51             ` Tomasz Duszynski
  0 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-10  5:51 UTC (permalink / raw)
  To: Ferruh Yigit
  Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On Mon, Oct 09, 2017 at 09:54:20PM +0100, Ferruh Yigit wrote:
> On 10/9/2017 4:00 PM, Tomasz Duszynski wrote:
> > Add documentation for the MRVL NET PMD driver.
> >
> > Signed-off-by: Jacek Siuda <jck@semihalf.com>
> > Signed-off-by: Tomasz Duszynski <jck@semihalf.com>
>
> I guess this should be "Tomasz Duszynski <tdu@semihalf.com>" :)

Good nitpick! Thanks.

>
> Fixing accordingly while applying.
>
> <...>

--
- Tomasz Duszyński

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

* Re: [PATCH v4 00/16] add net mrvl pmd driver
  2017-10-09 20:59         ` [PATCH v4 00/16] add net mrvl pmd driver Ferruh Yigit
  2017-10-10  0:25           ` Ferruh Yigit
@ 2017-10-10  5:55           ` Tomasz Duszynski
  2017-10-12  1:51           ` Ferruh Yigit
  2 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-10  5:55 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jianbo.liu

On Mon, Oct 09, 2017 at 09:59:27PM +0100, Ferruh Yigit wrote:
> On 10/9/2017 4:00 PM, Tomasz Duszynski wrote:
> > Hello,
> >
> > This patch series introduces the net driver for Marvell Armada 7k/8k
> > SoCs along with documentation.
> >
> > Below you can find the list of features which net pmd supports:
> > * Speed capabilities
> > * Link status
> > * MTU update
> > * Jumbo frame
> > * Promiscuous mode
> > * Allmulticast mode
> > * Unicast MAC filter
> > * Multicast MAC filter
> > * RSS hash
> > * VLAN filter
> > * CRC offload
> > * L3 checksum offload
> > * L4 checksum offload
> > * Packet type parsing
> > * Basic stats
> > * QoS
> >
> > Changes since v3:
> > * Split driver into skeleton, rx/tx, features, documentation parts
> > * Added speed capabilities flags.
> > * Added missing rx offload flags: VLAN/JUMBOFRAME
> > * Updated release notes.
> > * Updated documentation.
> >
> > Changes since v2:
> > * Removed LINE_SPACING, MULTILINE_DEREFERENCE and SPLIT_STRING
> >   checkpatch warnings.
> > * Removed unnecessary forward declarations.
> > * Fixed whitespace warnings.
> >
> > Changes since v1:
> > * Changed commit message to explain problem better.
> > * Removed bunch of checkpatch warnings about unnecessary parentheses.
> >
> > Tomasz Duszynski (4):
> >   app: link the whole rte_cfgfile library
> >   net/mrvl: add mrvl net pmd driver skeleton
> >   net/mrvl: add rx/tx support
> >   net/mrvl: add link update
> >   net/mrvl: add link speed capabilities
> >   net/mrvl: add support for updating mtu
> >   net/mrvl: add jumbo frame support
> >   net/mrvl: add support for promiscuous and allmulticast modes
> >   net/mrvl: add support for mac filtering
> >   net/mrvl: add rss hashing support
> >   net/mrvl: add support for vlan filtering
> >   net/mrvl: add crc, l3 and l4 offloads support
> >   net/mrvl: add packet type parsing support.
> >   net/mrvl: add basic stats support
> >   maintainers: add maintainers for the mrvl net pmd
> >   doc: add mrvl net pmd documentation
>
> Series applied to dpdk-next-net/master, thanks.
>
> (I can't compile because of missing musdk library, but since PMD is
> disabled by default this is not so bad, lets get this for rc1 and for
> crypto dependency, later I can have my environment set and test)

Thanks!

--
- Tomasz Duszyński

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

* Re: [PATCH v4 00/16] add net mrvl pmd driver
  2017-10-10  0:25           ` Ferruh Yigit
@ 2017-10-10  7:07             ` Tomasz Duszynski
  0 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-10  7:07 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jianbo.liu

On Tue, Oct 10, 2017 at 01:25:42AM +0100, Ferruh Yigit wrote:
> On 10/9/2017 9:59 PM, Ferruh Yigit wrote:
> > On 10/9/2017 4:00 PM, Tomasz Duszynski wrote:
> >> Hello,
> >>
> >> This patch series introduces the net driver for Marvell Armada 7k/8k
> >> SoCs along with documentation.
> >>
> >> Below you can find the list of features which net pmd supports:
> >> * Speed capabilities
> >> * Link status
> >> * MTU update
> >> * Jumbo frame
> >> * Promiscuous mode
> >> * Allmulticast mode
> >> * Unicast MAC filter
> >> * Multicast MAC filter
> >> * RSS hash
> >> * VLAN filter
> >> * CRC offload
> >> * L3 checksum offload
> >> * L4 checksum offload
> >> * Packet type parsing
> >> * Basic stats
> >> * QoS
> >>
> >> Changes since v3:
> >> * Split driver into skeleton, rx/tx, features, documentation parts
> >> * Added speed capabilities flags.
> >> * Added missing rx offload flags: VLAN/JUMBOFRAME
> >> * Updated release notes.
> >> * Updated documentation.
> >>
> >> Changes since v2:
> >> * Removed LINE_SPACING, MULTILINE_DEREFERENCE and SPLIT_STRING
> >>   checkpatch warnings.
> >> * Removed unnecessary forward declarations.
> >> * Fixed whitespace warnings.
> >>
> >> Changes since v1:
> >> * Changed commit message to explain problem better.
> >> * Removed bunch of checkpatch warnings about unnecessary parentheses.
> >>
> >> Tomasz Duszynski (4):
> >>   app: link the whole rte_cfgfile library
> >>   net/mrvl: add mrvl net pmd driver skeleton
> >>   net/mrvl: add rx/tx support
> >>   net/mrvl: add link update
> >>   net/mrvl: add link speed capabilities
> >>   net/mrvl: add support for updating mtu
> >>   net/mrvl: add jumbo frame support
> >>   net/mrvl: add support for promiscuous and allmulticast modes
> >>   net/mrvl: add support for mac filtering
> >>   net/mrvl: add rss hashing support
> >>   net/mrvl: add support for vlan filtering
> >>   net/mrvl: add crc, l3 and l4 offloads support
> >>   net/mrvl: add packet type parsing support.
> >>   net/mrvl: add basic stats support
> >>   maintainers: add maintainers for the mrvl net pmd
> >>   doc: add mrvl net pmd documentation
> >
> > Series applied to dpdk-next-net/master, thanks.
>
> Can you also add a web patch [1] to list NICs as supported NICs [2] ?
>
> [1]
> http://dpdk.org/browse/tools/dpdk-web/
>
> [2]
> http://dpdk.org/doc/nics
>
>
> >
> > (I can't compile because of missing musdk library, but since PMD is
> > disabled by default this is not so bad, lets get this for rc1 and for
> > crypto dependency, later I can have my environment set and test)
> >
>

ACK

--
- Tomasz Duszyński

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

* Re: [PATCH v3 1/4] crypto/mrvl: add mrvl crypto pmd driver
  2017-10-07 20:28     ` [PATCH v3 1/4] crypto/mrvl: add mrvl crypto " Tomasz Duszynski
@ 2017-10-10 10:16       ` De Lara Guarch, Pablo
  2017-10-10 10:25         ` Tomasz Duszynski
  0 siblings, 1 reply; 110+ messages in thread
From: De Lara Guarch, Pablo @ 2017-10-10 10:16 UTC (permalink / raw)
  To: Tomasz Duszynski, dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Jacek Siuda



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Tomasz Duszynski
> Sent: Saturday, October 7, 2017 9:28 PM
> To: dev@dpdk.org
> Cc: mw@semihalf.com; dima@marvell.com; nsamsono@marvell.com;
> Jianbo.liu@linaro.org; Tomasz Duszynski <tdu@semihalf.com>; Jacek Siuda
> <jck@semihalf.com>
> Subject: [dpdk-dev] [PATCH v3 1/4] crypto/mrvl: add mrvl crypto pmd
> driver

...

> diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd.c
> b/drivers/crypto/mrvl/rte_mrvl_pmd.c
> new file mode 100644
> index 0000000..a404bf4
> --- /dev/null
> +++ b/drivers/crypto/mrvl/rte_mrvl_pmd.c

...

> +
> +/* Register the driver in constructor. */
> +RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_MRVL_PMD,
> cryptodev_mrvl_pmd_drv);
> +RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_MRVL_PMD,
> +	"max_nb_queue_pairs=<int> "
> +	"max_nb_sessions=<int> "
> +	"socket_id=<int>");
> +RTE_PMD_REGISTER_CRYPTO_DRIVER(cryptodev_mrvl_pmd_drv,
> cryptodev_driver_id);

This macro now needs 3 parameters. You probably rebased the patchset
against the main repo, and not dpdk-next-crypto.
Just a reminder that all crypto patches should target this repository.

Apart from this, the rest of the patchset looks good to me.
So send a v4 and hopefully it can be merged in RC1.

Pablo

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

* Re: [PATCH v3 1/4] crypto/mrvl: add mrvl crypto pmd driver
  2017-10-10 10:16       ` De Lara Guarch, Pablo
@ 2017-10-10 10:25         ` Tomasz Duszynski
  0 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-10 10:25 UTC (permalink / raw)
  To: De Lara Guarch, Pablo
  Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On Tue, Oct 10, 2017 at 10:16:42AM +0000, De Lara Guarch, Pablo wrote:
>
>
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Tomasz Duszynski
> > Sent: Saturday, October 7, 2017 9:28 PM
> > To: dev@dpdk.org
> > Cc: mw@semihalf.com; dima@marvell.com; nsamsono@marvell.com;
> > Jianbo.liu@linaro.org; Tomasz Duszynski <tdu@semihalf.com>; Jacek Siuda
> > <jck@semihalf.com>
> > Subject: [dpdk-dev] [PATCH v3 1/4] crypto/mrvl: add mrvl crypto pmd
> > driver
>
> ...
>
> > diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd.c
> > b/drivers/crypto/mrvl/rte_mrvl_pmd.c
> > new file mode 100644
> > index 0000000..a404bf4
> > --- /dev/null
> > +++ b/drivers/crypto/mrvl/rte_mrvl_pmd.c
>
> ...
>
> > +
> > +/* Register the driver in constructor. */
> > +RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_MRVL_PMD,
> > cryptodev_mrvl_pmd_drv);
> > +RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_MRVL_PMD,
> > +	"max_nb_queue_pairs=<int> "
> > +	"max_nb_sessions=<int> "
> > +	"socket_id=<int>");
> > +RTE_PMD_REGISTER_CRYPTO_DRIVER(cryptodev_mrvl_pmd_drv,
> > cryptodev_driver_id);
>
> This macro now needs 3 parameters. You probably rebased the patchset
> against the main repo, and not dpdk-next-crypto.

ACK

> Just a reminder that all crypto patches should target this repository.
>
> Apart from this, the rest of the patchset looks good to me.
> So send a v4 and hopefully it can be merged in RC1.
>
> Pablo
>

--
- Tomasz Duszyński

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

* Re: [PATCH v3 4/4] test: add mrvl crypto pmd unit tests
  2017-10-07 20:28     ` [PATCH v3 4/4] test: add mrvl crypto pmd unit tests Tomasz Duszynski
@ 2017-10-10 10:44       ` De Lara Guarch, Pablo
  2017-10-10 10:57         ` Tomasz Duszynski
  0 siblings, 1 reply; 110+ messages in thread
From: De Lara Guarch, Pablo @ 2017-10-10 10:44 UTC (permalink / raw)
  To: Tomasz Duszynski, dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Jacek Siuda



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Tomasz Duszynski
> Sent: Saturday, October 7, 2017 9:28 PM
> To: dev@dpdk.org
> Cc: mw@semihalf.com; dima@marvell.com; nsamsono@marvell.com;
> Jianbo.liu@linaro.org; Tomasz Duszynski <tdu@semihalf.com>; Jacek Siuda
> <jck@semihalf.com>
> Subject: [dpdk-dev] [PATCH v3 4/4] test: add mrvl crypto pmd unit tests
> 
> Add unit tests for MRVL CRYPTO PMD driver.
> 
> Signed-off-by: Jacek Siuda <jck@semihalf.com>
> Signed-off-by: Tomasz Duszynski <jck@semihalf.com>

Hi Tomasz,

Just one final comment, Patch 2 and this patch have your email wrong.

Pablo

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

* Re: [PATCH v3 4/4] test: add mrvl crypto pmd unit tests
  2017-10-10 10:44       ` De Lara Guarch, Pablo
@ 2017-10-10 10:57         ` Tomasz Duszynski
  0 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-10 10:57 UTC (permalink / raw)
  To: De Lara Guarch, Pablo
  Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On Tue, Oct 10, 2017 at 10:44:06AM +0000, De Lara Guarch, Pablo wrote:
>
>
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Tomasz Duszynski
> > Sent: Saturday, October 7, 2017 9:28 PM
> > To: dev@dpdk.org
> > Cc: mw@semihalf.com; dima@marvell.com; nsamsono@marvell.com;
> > Jianbo.liu@linaro.org; Tomasz Duszynski <tdu@semihalf.com>; Jacek Siuda
> > <jck@semihalf.com>
> > Subject: [dpdk-dev] [PATCH v3 4/4] test: add mrvl crypto pmd unit tests
> >
> > Add unit tests for MRVL CRYPTO PMD driver.
> >
> > Signed-off-by: Jacek Siuda <jck@semihalf.com>
> > Signed-off-by: Tomasz Duszynski <jck@semihalf.com>
>
> Hi Tomasz,
>
> Just one final comment, Patch 2 and this patch have your email wrong.

Fixed already. Thanks.

>
> Pablo

--
- Tomasz Duszyński

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

* [PATCH v4 0/4] add crypto mrvl pmd driver
  2017-10-07 20:28   ` [PATCH v3 0/4] add crypto mrvl pmd driver Tomasz Duszynski
                       ` (3 preceding siblings ...)
  2017-10-07 20:28     ` [PATCH v3 4/4] test: add mrvl crypto pmd unit tests Tomasz Duszynski
@ 2017-10-10 12:17     ` Tomasz Duszynski
  2017-10-10 12:17       ` [PATCH v4 1/4] crypto/mrvl: add mrvl crypto " Tomasz Duszynski
                         ` (4 more replies)
  4 siblings, 5 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-10 12:17 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski

Hello,

This patch series introduces crypto driver for Marvell Armada 7k/8k
SoCs along with documentation and crypto pmd driver tests.

Below you can find the list of features which crypto pmd supports:
* Symmetric crypto
* Sym operation chaining
* AES CBC (128)
* AES CBC (192)
* AES CBC (256)
* AES CTR (128)
* AES CTR (192)
* AES CTR (256)
* 3DES CBC
* 3DES CTR
* MD5
* MD5 HMAC
* SHA1
* SHA1 HMAC
* SHA256
* SHA256 HMAC
* SHA384
* SHA384 HMAC
* SHA512
* SHA512 HMAC
* AES GCM (128)

Changes since v3:
* Rebased on dpdk-next-crypto.
* Allocated driver structure statically.
* Fixed email addresses.
* Updated documentation.

Changes since v2:
* Added MRVL CRYPTO PMD to the test-build.sh.
* Updated release notes.
* Updated cryptoperf documentation.
* Removed cryptodev_mrvl_pmd driver alias.
* Fixed min,max key sizes used by HMACs in capabilities table.
* Renamed map file.
* Updated documentation.

Tomasz Duszynski (4):
  crypto/mrvl: add mrvl crypto pmd driver
  doc: add mrvl crypto pmd documentation
  maintainers: add maintainers for the mrvl crypto pmd
  test: add mrvl crypto pmd unit tests

 MAINTAINERS                                  |  10 +
 config/common_base                           |   6 +
 devtools/test-build.sh                       |   4 +
 doc/guides/cryptodevs/features/mrvl.ini      |  42 ++
 doc/guides/cryptodevs/index.rst              |   1 +
 doc/guides/cryptodevs/mrvl.rst               | 205 +++++++
 doc/guides/rel_notes/release_17_11.rst       |   5 +
 doc/guides/tools/cryptoperf.rst              |   1 +
 drivers/crypto/Makefile                      |   2 +
 drivers/crypto/mrvl/Makefile                 |  63 ++
 drivers/crypto/mrvl/rte_mrvl_compat.h        |  48 ++
 drivers/crypto/mrvl/rte_mrvl_pmd.c           | 872 +++++++++++++++++++++++++++
 drivers/crypto/mrvl/rte_mrvl_pmd_ops.c       | 776 ++++++++++++++++++++++++
 drivers/crypto/mrvl/rte_mrvl_pmd_private.h   | 121 ++++
 drivers/crypto/mrvl/rte_pmd_mrvl_version.map |   3 +
 mk/rte.app.mk                                |   1 +
 test/test/test_cryptodev.c                   | 168 ++++++
 test/test/test_cryptodev.h                   |   1 +
 test/test/test_cryptodev_aes_test_vectors.h  |  72 ++-
 test/test/test_cryptodev_blockcipher.c       |   9 +-
 test/test/test_cryptodev_blockcipher.h       |   1 +
 test/test/test_cryptodev_des_test_vectors.h  |  24 +-
 22 files changed, 2402 insertions(+), 33 deletions(-)
 create mode 100644 doc/guides/cryptodevs/features/mrvl.ini
 create mode 100644 doc/guides/cryptodevs/mrvl.rst
 create mode 100644 drivers/crypto/mrvl/Makefile
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_compat.h
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd.c
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_private.h
 create mode 100644 drivers/crypto/mrvl/rte_pmd_mrvl_version.map

--
2.7.4

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

* [PATCH v4 1/4] crypto/mrvl: add mrvl crypto pmd driver
  2017-10-10 12:17     ` [PATCH v4 0/4] add crypto mrvl pmd driver Tomasz Duszynski
@ 2017-10-10 12:17       ` Tomasz Duszynski
  2017-10-10 12:17       ` [PATCH v4 2/4] doc: add mrvl crypto pmd documentation Tomasz Duszynski
                         ` (3 subsequent siblings)
  4 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-10 12:17 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add support for the Marvell Security Crypto Accelerator EIP197.
Driver is based on external, publicly available, Marvell MUSDK
library that provides access to the hardware with minimum overhead
and high performance.

Driver comes with support for the following features:

* Symmetric crypto
* Sym operation chaining
* AES CBC (128)
* AES CBC (192)
* AES CBC (256)
* AES CTR (128)
* AES CTR (192)
* AES CTR (256)
* 3DES CBC
* 3DES CTR
* MD5
* MD5 HMAC
* SHA1
* SHA1 HMAC
* SHA256
* SHA256 HMAC
* SHA384
* SHA384 HMAC
* SHA512
* SHA512 HMAC
* AES GCM (128)

Driver was engineered cooperatively by Semihalf and Marvell teams.

Semihalf:
Jacek Siuda <jck@semihalf.com>
Tomasz Duszynski <tdu@semihalf.com>

Marvell:
Dmitri Epshtein <dima@marvell.com>
Natalie Samsonov <nsamsono@marvell.com>

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 v4:
 * Allocated driver structure statically.

 v3:
 * Added MRVL CRYPTO PMD to the test-build.sh.
 * Updated release notes.
 * Updated cryptoperf documentation.
 * Removed cryptodev_mrvl_pmd driver alias.
 * Fixed min,max key sizes used by HMACs in capabilities table.
 * Renamed map file.

 config/common_base                           |   6 +
 devtools/test-build.sh                       |   4 +
 doc/guides/rel_notes/release_17_11.rst       |   5 +
 doc/guides/tools/cryptoperf.rst              |   1 +
 drivers/crypto/Makefile                      |   2 +
 drivers/crypto/mrvl/Makefile                 |  63 ++
 drivers/crypto/mrvl/rte_mrvl_compat.h        |  48 ++
 drivers/crypto/mrvl/rte_mrvl_pmd.c           | 872 +++++++++++++++++++++++++++
 drivers/crypto/mrvl/rte_mrvl_pmd_ops.c       | 776 ++++++++++++++++++++++++
 drivers/crypto/mrvl/rte_mrvl_pmd_private.h   | 121 ++++
 drivers/crypto/mrvl/rte_pmd_mrvl_version.map |   3 +
 mk/rte.app.mk                                |   1 +
 12 files changed, 1902 insertions(+)
 create mode 100644 drivers/crypto/mrvl/Makefile
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_compat.h
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd.c
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
 create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_private.h
 create mode 100644 drivers/crypto/mrvl/rte_pmd_mrvl_version.map

diff --git a/config/common_base b/config/common_base
index 8adcb09..db1e20b 100644
--- a/config/common_base
+++ b/config/common_base
@@ -528,6 +528,12 @@ CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER_DEBUG=n
 CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO=y

 #
+# Compile PMD for Marvell Crypto device
+#
+CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO=n
+CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO_DEBUG=n
+
+#
 # Compile generic event device library
 #
 CONFIG_RTE_LIBRTE_EVENTDEV=y
diff --git a/devtools/test-build.sh b/devtools/test-build.sh
index c6dfaf0..d82e3f4 100755
--- a/devtools/test-build.sh
+++ b/devtools/test-build.sh
@@ -50,6 +50,7 @@ default_path=$PATH
 # - LIBSSO_SNOW3G_PATH
 # - LIBSSO_KASUMI_PATH
 # - LIBSSO_ZUC_PATH
+# - LIBMUSDK_PATH
 . $(dirname $(readlink -e $0))/load-devel-config

 print_usage () {
@@ -133,6 +134,7 @@ reset_env ()
 	unset LIBSSO_KASUMI_PATH
 	unset LIBSSO_ZUC_PATH
 	unset PQOS_INSTALL_PATH
+	unset LIBMUSDK_PATH
 }

 config () # <directory> <target> <options>
@@ -193,6 +195,8 @@ config () # <directory> <target> <options>
 		test "$DPDK_DEP_SSL" != y || \
 		sed -ri            's,(PMD_QAT=)n,\1y,' $1/.config
 		sed -ri           's,(SCHED_.*=)n,\1y,' $1/.config
+		test -z "$LIBMUSDK_PATH" || \
+		sed -ri    's,(PMD_MRVL_CRYPTO=)n,\1y,' $1/.config
 		build_config_hook $1 $2 $3

 		# Explicit enabler/disabler (uppercase)
diff --git a/doc/guides/rel_notes/release_17_11.rst b/doc/guides/rel_notes/release_17_11.rst
index f452f0b..6ff86e4 100644
--- a/doc/guides/rel_notes/release_17_11.rst
+++ b/doc/guides/rel_notes/release_17_11.rst
@@ -122,6 +122,11 @@ New Features
   added. See the "Crypto Device Drivers" document for more details on this
   driver.

+* **Added MRVL crypto PMD.**
+
+  A new crypto PMD has been added, which provides several ciphering and hashing
+  algorithms. All cryptography operations use the MUSDK library crypto API.
+

 Resolved Issues
 ---------------
diff --git a/doc/guides/tools/cryptoperf.rst b/doc/guides/tools/cryptoperf.rst
index 2b3a5b6..7e12677 100644
--- a/doc/guides/tools/cryptoperf.rst
+++ b/doc/guides/tools/cryptoperf.rst
@@ -194,6 +194,7 @@ The following are the appication command-line options:
            crypto_dpaa2_sec
            crypto_armv8
            crypto_scheduler
+           crypto_mrvl

 * ``--optype <name>``

diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 8ca5f18..d8c8740 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -51,6 +51,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_KASUMI) += kasumi
 DEPDIRS-kasumi = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_ZUC) += zuc
 DEPDIRS-zuc = $(core-libs)
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO) += mrvl
+DEPDIRS-mrvl = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO) += null
 DEPDIRS-null = $(core-libs)
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_SEC) += dpaa2_sec
diff --git a/drivers/crypto/mrvl/Makefile b/drivers/crypto/mrvl/Makefile
new file mode 100644
index 0000000..a00a19e
--- /dev/null
+++ b/drivers/crypto/mrvl/Makefile
@@ -0,0 +1,63 @@
+#   BSD LICENSE
+#
+#   Copyright (C) Semihalf 2017. 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 Semihalf 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
+
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),config)
+ifeq ($(LIBMUSDK_PATH),)
+$(error "Please define LIBMUSDK_PATH environment variable")
+endif
+endif
+endif
+
+# library name
+LIB = librte_pmd_mrvl_crypto.a
+
+# build flags
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -I$(LIBMUSDK_PATH)/include
+CFLAGS += -DMVCONF_ARCH_DMA_ADDR_T_64BIT
+
+# library version
+LIBABIVER := 1
+
+# versioning export map
+EXPORT_MAP := rte_mrvl_pmd_version.map
+
+# external library dependencies
+LDLIBS += -L$(LIBMUSDK_PATH)/lib -lmusdk
+
+# library source files
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO) += rte_mrvl_pmd.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO) += rte_mrvl_pmd_ops.c
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/crypto/mrvl/rte_mrvl_compat.h b/drivers/crypto/mrvl/rte_mrvl_compat.h
new file mode 100644
index 0000000..11d53fc
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_mrvl_compat.h
@@ -0,0 +1,48 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) Semihalf 2017. 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 Semihalf 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_MRVL_COMPAT_H_
+#define _RTE_MRVL_COMPAT_H_
+
+/* Unluckily, container_of is defined by both DPDK and MUSDK,
+ * we'll declare only one version.
+ *
+ * Note that it is not used in this PMD anyway.
+ */
+#ifdef container_of
+#undef container_of
+#endif
+#include "drivers/mv_sam.h"
+#include "drivers/mv_sam_cio.h"
+#include "drivers/mv_sam_session.h"
+
+#endif /* _RTE_MRVL_COMPAT_H_ */
diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd.c b/drivers/crypto/mrvl/rte_mrvl_pmd.c
new file mode 100644
index 0000000..0c540fa
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_mrvl_pmd.c
@@ -0,0 +1,872 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) Semihalf 2017. 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 Semihalf 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_common.h>
+#include <rte_hexdump.h>
+#include <rte_cryptodev.h>
+#include <rte_cryptodev_pmd.h>
+#include <rte_cryptodev_vdev.h>
+#include <rte_vdev.h>
+#include <rte_malloc.h>
+#include <rte_cpuflags.h>
+
+#include "rte_mrvl_pmd_private.h"
+
+#ifndef RTE_MRVL_MUSDK_DMA_MEMSIZE
+#define RTE_MRVL_MUSDK_DMA_MEMSIZE 41943040
+#endif
+
+static uint8_t cryptodev_driver_id;
+
+/**
+ * Flag if particular crypto algorithm is supported by PMD/MUSDK.
+ *
+ * The idea is to have Not Supported value as default (0).
+ * This way we need only to define proper map sizes,
+ * non-initialized entries will be by default not supported.
+ */
+enum algo_supported {
+	ALGO_NOT_SUPPORTED = 0,
+	ALGO_SUPPORTED = 1,
+};
+
+/** Map elements for cipher mapping.*/
+struct cipher_params_mapping {
+	enum algo_supported  supported;   /**< On/Off switch */
+	enum sam_cipher_alg  cipher_alg;  /**< Cipher algorithm */
+	enum sam_cipher_mode cipher_mode; /**< Cipher mode */
+	unsigned int max_key_len;         /**< Maximum key length (in bytes)*/
+}
+/* We want to squeeze in multiple maps into the cache line. */
+__rte_aligned(32);
+
+/** Map elements for auth mapping.*/
+struct auth_params_mapping {
+	enum algo_supported supported;  /**< On/off switch */
+	enum sam_auth_alg   auth_alg;   /**< Auth algorithm */
+}
+/* We want to squeeze in multiple maps into the cache line. */
+__rte_aligned(32);
+
+/**
+ * Map of supported cipher algorithms.
+ */
+static const
+struct cipher_params_mapping cipher_map[RTE_CRYPTO_CIPHER_LIST_END] = {
+	[RTE_CRYPTO_CIPHER_3DES_CBC] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_3DES,
+		.cipher_mode = SAM_CIPHER_CBC,
+		.max_key_len = BITS2BYTES(192) },
+	[RTE_CRYPTO_CIPHER_3DES_CTR] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_3DES,
+		.cipher_mode = SAM_CIPHER_CTR,
+		.max_key_len = BITS2BYTES(192) },
+	[RTE_CRYPTO_CIPHER_3DES_ECB] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_3DES,
+		.cipher_mode = SAM_CIPHER_ECB,
+		.max_key_len = BITS2BYTES(192) },
+	[RTE_CRYPTO_CIPHER_AES_CBC] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_AES,
+		.cipher_mode = SAM_CIPHER_CBC,
+		.max_key_len = BITS2BYTES(256) },
+	[RTE_CRYPTO_CIPHER_AES_CTR] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_AES,
+		.cipher_mode = SAM_CIPHER_CTR,
+		.max_key_len = BITS2BYTES(256) },
+};
+
+/**
+ * Map of supported auth algorithms.
+ */
+static const
+struct auth_params_mapping auth_map[RTE_CRYPTO_AUTH_LIST_END] = {
+	[RTE_CRYPTO_AUTH_MD5_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_MD5 },
+	[RTE_CRYPTO_AUTH_MD5] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_MD5 },
+	[RTE_CRYPTO_AUTH_SHA1_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_SHA1 },
+	[RTE_CRYPTO_AUTH_SHA1] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA1 },
+	[RTE_CRYPTO_AUTH_SHA224] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA2_224 },
+	[RTE_CRYPTO_AUTH_SHA256_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_SHA2_256 },
+	[RTE_CRYPTO_AUTH_SHA256] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA2_256 },
+	[RTE_CRYPTO_AUTH_SHA384_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_SHA2_384 },
+	[RTE_CRYPTO_AUTH_SHA384] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA2_384 },
+	[RTE_CRYPTO_AUTH_SHA512_HMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HMAC_SHA2_512 },
+	[RTE_CRYPTO_AUTH_SHA512] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_HASH_SHA2_512 },
+	[RTE_CRYPTO_AUTH_AES_GMAC] = {
+		.supported = ALGO_SUPPORTED,
+		.auth_alg = SAM_AUTH_AES_GMAC },
+};
+
+/**
+ * Map of supported aead algorithms.
+ */
+static const
+struct cipher_params_mapping aead_map[RTE_CRYPTO_AEAD_LIST_END] = {
+	[RTE_CRYPTO_AEAD_AES_GCM] = {
+		.supported = ALGO_SUPPORTED,
+		.cipher_alg = SAM_CIPHER_AES,
+		.cipher_mode = SAM_CIPHER_GCM,
+		.max_key_len = BITS2BYTES(256) },
+};
+
+/*
+ *-----------------------------------------------------------------------------
+ * Forward declarations.
+ *-----------------------------------------------------------------------------
+ */
+static int cryptodev_mrvl_crypto_uninit(struct rte_vdev_device *vdev);
+
+/*
+ *-----------------------------------------------------------------------------
+ * Session Preparation.
+ *-----------------------------------------------------------------------------
+ */
+
+/**
+ * Get xform chain order.
+ *
+ * @param xform Pointer to configuration structure chain for crypto operations.
+ * @returns Order of crypto operations.
+ */
+static enum mrvl_crypto_chain_order
+mrvl_crypto_get_chain_order(const struct rte_crypto_sym_xform *xform)
+{
+	/* Currently, Marvell supports max 2 operations in chain */
+	if (xform->next != NULL && xform->next->next != NULL)
+		return MRVL_CRYPTO_CHAIN_NOT_SUPPORTED;
+
+	if (xform->next != NULL) {
+		if ((xform->type == RTE_CRYPTO_SYM_XFORM_AUTH) &&
+			(xform->next->type == RTE_CRYPTO_SYM_XFORM_CIPHER))
+			return MRVL_CRYPTO_CHAIN_AUTH_CIPHER;
+
+		if ((xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER) &&
+			(xform->next->type == RTE_CRYPTO_SYM_XFORM_AUTH))
+			return MRVL_CRYPTO_CHAIN_CIPHER_AUTH;
+	} else {
+		if (xform->type == RTE_CRYPTO_SYM_XFORM_AUTH)
+			return MRVL_CRYPTO_CHAIN_AUTH_ONLY;
+
+		if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER)
+			return MRVL_CRYPTO_CHAIN_CIPHER_ONLY;
+
+		if (xform->type == RTE_CRYPTO_SYM_XFORM_AEAD)
+			return MRVL_CRYPTO_CHAIN_COMBINED;
+	}
+	return MRVL_CRYPTO_CHAIN_NOT_SUPPORTED;
+}
+
+/**
+ * Set session parameters for cipher part.
+ *
+ * @param sess Crypto session pointer.
+ * @param cipher_xform Pointer to configuration structure for cipher operations.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+mrvl_crypto_set_cipher_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *cipher_xform)
+{
+	/* Make sure we've got proper struct */
+	if (cipher_xform->type != RTE_CRYPTO_SYM_XFORM_CIPHER) {
+		MRVL_CRYPTO_LOG_ERR("Wrong xform struct provided!");
+		return -EINVAL;
+	}
+
+	/* See if map data is present and valid */
+	if ((cipher_xform->cipher.algo > RTE_DIM(cipher_map)) ||
+		(cipher_map[cipher_xform->cipher.algo].supported
+			!= ALGO_SUPPORTED)) {
+		MRVL_CRYPTO_LOG_ERR("Cipher algorithm not supported!");
+		return -EINVAL;
+	}
+
+	sess->cipher_iv_offset = cipher_xform->cipher.iv.offset;
+
+	sess->sam_sess_params.dir =
+		(cipher_xform->cipher.op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) ?
+		SAM_DIR_ENCRYPT : SAM_DIR_DECRYPT;
+	sess->sam_sess_params.cipher_alg =
+		cipher_map[cipher_xform->cipher.algo].cipher_alg;
+	sess->sam_sess_params.cipher_mode =
+		cipher_map[cipher_xform->cipher.algo].cipher_mode;
+
+	/* Assume IV will be passed together with data. */
+	sess->sam_sess_params.cipher_iv = NULL;
+
+	/* Get max key length. */
+	if (cipher_xform->cipher.key.length >
+		cipher_map[cipher_xform->cipher.algo].max_key_len) {
+		MRVL_CRYPTO_LOG_ERR("Wrong key length!");
+		return -EINVAL;
+	}
+
+	sess->sam_sess_params.cipher_key_len = cipher_xform->cipher.key.length;
+	sess->sam_sess_params.cipher_key = cipher_xform->cipher.key.data;
+
+	return 0;
+}
+
+/**
+ * Set session parameters for authentication part.
+ *
+ * @param sess Crypto session pointer.
+ * @param auth_xform Pointer to configuration structure for auth operations.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+mrvl_crypto_set_auth_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *auth_xform)
+{
+	/* Make sure we've got proper struct */
+	if (auth_xform->type != RTE_CRYPTO_SYM_XFORM_AUTH) {
+		MRVL_CRYPTO_LOG_ERR("Wrong xform struct provided!");
+		return -EINVAL;
+	}
+
+	/* See if map data is present and valid */
+	if ((auth_xform->auth.algo > RTE_DIM(auth_map)) ||
+		(auth_map[auth_xform->auth.algo].supported != ALGO_SUPPORTED)) {
+		MRVL_CRYPTO_LOG_ERR("Auth algorithm not supported!");
+		return -EINVAL;
+	}
+
+	sess->sam_sess_params.dir =
+		(auth_xform->auth.op == RTE_CRYPTO_AUTH_OP_GENERATE) ?
+		SAM_DIR_ENCRYPT : SAM_DIR_DECRYPT;
+	sess->sam_sess_params.auth_alg =
+		auth_map[auth_xform->auth.algo].auth_alg;
+	sess->sam_sess_params.u.basic.auth_icv_len =
+		auth_xform->auth.digest_length;
+	/* auth_key must be NULL if auth algorithm does not use HMAC */
+	sess->sam_sess_params.auth_key = auth_xform->auth.key.length ?
+					 auth_xform->auth.key.data : NULL;
+	sess->sam_sess_params.auth_key_len = auth_xform->auth.key.length;
+
+	return 0;
+}
+
+/**
+ * Set session parameters for aead part.
+ *
+ * @param sess Crypto session pointer.
+ * @param aead_xform Pointer to configuration structure for aead operations.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+mrvl_crypto_set_aead_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *aead_xform)
+{
+	/* Make sure we've got proper struct */
+	if (aead_xform->type != RTE_CRYPTO_SYM_XFORM_AEAD) {
+		MRVL_CRYPTO_LOG_ERR("Wrong xform struct provided!");
+		return -EINVAL;
+	}
+
+	/* See if map data is present and valid */
+	if ((aead_xform->aead.algo > RTE_DIM(aead_map)) ||
+		(aead_map[aead_xform->aead.algo].supported
+			!= ALGO_SUPPORTED)) {
+		MRVL_CRYPTO_LOG_ERR("AEAD algorithm not supported!");
+		return -EINVAL;
+	}
+
+	sess->sam_sess_params.dir =
+		(aead_xform->aead.op == RTE_CRYPTO_AEAD_OP_ENCRYPT) ?
+		SAM_DIR_ENCRYPT : SAM_DIR_DECRYPT;
+	sess->sam_sess_params.cipher_alg =
+		aead_map[aead_xform->aead.algo].cipher_alg;
+	sess->sam_sess_params.cipher_mode =
+		aead_map[aead_xform->aead.algo].cipher_mode;
+
+	/* Assume IV will be passed together with data. */
+	sess->sam_sess_params.cipher_iv = NULL;
+
+	/* Get max key length. */
+	if (aead_xform->aead.key.length >
+		aead_map[aead_xform->aead.algo].max_key_len) {
+		MRVL_CRYPTO_LOG_ERR("Wrong key length!");
+		return -EINVAL;
+	}
+
+	sess->sam_sess_params.cipher_key = aead_xform->aead.key.data;
+	sess->sam_sess_params.cipher_key_len = aead_xform->aead.key.length;
+
+	if (sess->sam_sess_params.cipher_mode == SAM_CIPHER_GCM)
+		sess->sam_sess_params.auth_alg = SAM_AUTH_AES_GCM;
+
+	sess->sam_sess_params.u.basic.auth_icv_len =
+		aead_xform->aead.digest_length;
+
+	sess->sam_sess_params.u.basic.auth_aad_len =
+		aead_xform->aead.aad_length;
+
+	return 0;
+}
+
+/**
+ * Parse crypto transform chain and setup session parameters.
+ *
+ * @param dev Pointer to crypto device
+ * @param sess Poiner to crypto session
+ * @param xform Pointer to configuration structure chain for crypto operations.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+int
+mrvl_crypto_set_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *xform)
+{
+	const struct rte_crypto_sym_xform *cipher_xform = NULL;
+	const struct rte_crypto_sym_xform *auth_xform = NULL;
+	const struct rte_crypto_sym_xform *aead_xform = NULL;
+
+	/* Filter out spurious/broken requests */
+	if (xform == NULL)
+		return -EINVAL;
+
+	sess->chain_order = mrvl_crypto_get_chain_order(xform);
+	switch (sess->chain_order) {
+	case MRVL_CRYPTO_CHAIN_CIPHER_AUTH:
+		cipher_xform = xform;
+		auth_xform = xform->next;
+		break;
+	case MRVL_CRYPTO_CHAIN_AUTH_CIPHER:
+		auth_xform = xform;
+		cipher_xform = xform->next;
+		break;
+	case MRVL_CRYPTO_CHAIN_CIPHER_ONLY:
+		cipher_xform = xform;
+		break;
+	case MRVL_CRYPTO_CHAIN_AUTH_ONLY:
+		auth_xform = xform;
+		break;
+	case MRVL_CRYPTO_CHAIN_COMBINED:
+		aead_xform = xform;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if ((cipher_xform != NULL) &&
+		(mrvl_crypto_set_cipher_session_parameters(
+			sess, cipher_xform) < 0)) {
+		MRVL_CRYPTO_LOG_ERR("Invalid/unsupported cipher parameters");
+		return -EINVAL;
+	}
+
+	if ((auth_xform != NULL) &&
+		(mrvl_crypto_set_auth_session_parameters(
+			sess, auth_xform) < 0)) {
+		MRVL_CRYPTO_LOG_ERR("Invalid/unsupported auth parameters");
+		return -EINVAL;
+	}
+
+	if ((aead_xform != NULL) &&
+		(mrvl_crypto_set_aead_session_parameters(
+			sess, aead_xform) < 0)) {
+		MRVL_CRYPTO_LOG_ERR("Invalid/unsupported aead parameters");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Process Operations
+ *-----------------------------------------------------------------------------
+ */
+
+/**
+ * Prepare a single request.
+ *
+ * This function basically translates DPDK crypto request into one
+ * understandable by MUDSK's SAM. If this is a first request in a session,
+ * it starts the session.
+ *
+ * @param request Pointer to pre-allocated && reset request buffer [Out].
+ * @param src_bd Pointer to pre-allocated source descriptor [Out].
+ * @param dst_bd Pointer to pre-allocated destination descriptor [Out].
+ * @param op Pointer to DPDK crypto operation struct [In].
+ */
+static inline int
+mrvl_request_prepare(struct sam_cio_op_params *request,
+		struct sam_buf_info *src_bd,
+		struct sam_buf_info *dst_bd,
+		struct rte_crypto_op *op)
+{
+	struct mrvl_crypto_session *sess;
+	struct rte_mbuf *dst_mbuf;
+	uint8_t *digest;
+
+	if (unlikely(op->sess_type == RTE_CRYPTO_OP_SESSIONLESS)) {
+		MRVL_CRYPTO_LOG_ERR("MRVL CRYPTO PMD only supports session "
+				"oriented requests, op (%p) is sessionless.",
+				op);
+		return -EINVAL;
+	}
+
+	sess = (struct mrvl_crypto_session *)get_session_private_data(
+			op->sym->session, cryptodev_driver_id);
+	if (unlikely(sess == NULL)) {
+		MRVL_CRYPTO_LOG_ERR("Session was not created for this device");
+		return -EINVAL;
+	}
+
+	/*
+	 * If application delivered us null dst buffer, it means it expects
+	 * us to deliver the result in src buffer.
+	 */
+	dst_mbuf = op->sym->m_dst ? op->sym->m_dst : op->sym->m_src;
+
+	request->sa = sess->sam_sess;
+	request->cookie = op;
+
+	/* Single buffers only, sorry. */
+	request->num_bufs = 1;
+	request->src = src_bd;
+	src_bd->vaddr = rte_pktmbuf_mtod(op->sym->m_src, void *);
+	src_bd->paddr = rte_pktmbuf_mtophys(op->sym->m_src);
+	src_bd->len = rte_pktmbuf_data_len(op->sym->m_src);
+
+	/* Empty source. */
+	if (rte_pktmbuf_data_len(op->sym->m_src) == 0) {
+		/* EIP does not support 0 length buffers. */
+		MRVL_CRYPTO_LOG_ERR("Buffer length == 0 not supported!");
+		return -1;
+	}
+
+	/* Empty destination. */
+	if (rte_pktmbuf_data_len(dst_mbuf) == 0) {
+		/* Make dst buffer fit at least source data. */
+		if (rte_pktmbuf_append(dst_mbuf,
+			rte_pktmbuf_data_len(op->sym->m_src)) == NULL) {
+			MRVL_CRYPTO_LOG_ERR("Unable to set big enough dst buffer!");
+			return -1;
+		}
+	}
+
+	request->dst = dst_bd;
+	dst_bd->vaddr = rte_pktmbuf_mtod(dst_mbuf, void *);
+	dst_bd->paddr = rte_pktmbuf_mtophys(dst_mbuf);
+
+	/*
+	 * We can use all available space in dst_mbuf,
+	 * not only what's used currently.
+	 */
+	dst_bd->len = dst_mbuf->buf_len - rte_pktmbuf_headroom(dst_mbuf);
+
+	if (sess->chain_order == MRVL_CRYPTO_CHAIN_COMBINED) {
+		request->cipher_len = op->sym->aead.data.length;
+		request->cipher_offset = op->sym->aead.data.offset;
+		request->cipher_iv = rte_crypto_op_ctod_offset(op, uint8_t *,
+			sess->cipher_iv_offset);
+
+		request->auth_aad = op->sym->aead.aad.data;
+		request->auth_offset = request->cipher_offset;
+		request->auth_len = request->cipher_len;
+	} else {
+		request->cipher_len = op->sym->cipher.data.length;
+		request->cipher_offset = op->sym->cipher.data.offset;
+		request->cipher_iv = rte_crypto_op_ctod_offset(op, uint8_t *,
+				sess->cipher_iv_offset);
+
+		request->auth_offset = op->sym->auth.data.offset;
+		request->auth_len = op->sym->auth.data.length;
+	}
+
+	digest = sess->chain_order == MRVL_CRYPTO_CHAIN_COMBINED ?
+		op->sym->aead.digest.data : op->sym->auth.digest.data;
+	if (digest == NULL) {
+		/* No auth - no worry. */
+		return 0;
+	}
+
+	request->auth_icv_offset = request->auth_offset + request->auth_len;
+
+	/*
+	 * EIP supports only scenarios where ICV(digest buffer) is placed at
+	 * auth_icv_offset. Any other placement means risking errors.
+	 */
+	if (sess->sam_sess_params.dir == SAM_DIR_ENCRYPT) {
+		/*
+		 * This should be the most common case anyway,
+		 * EIP will overwrite DST buffer at auth_icv_offset.
+		 */
+		if (rte_pktmbuf_mtod_offset(
+				dst_mbuf, uint8_t *,
+				request->auth_icv_offset) == digest) {
+			return 0;
+		}
+	} else {/* sess->sam_sess_params.dir == SAM_DIR_DECRYPT */
+		/*
+		 * EIP will look for digest at auth_icv_offset
+		 * offset in SRC buffer.
+		 */
+		if (rte_pktmbuf_mtod_offset(
+				op->sym->m_src, uint8_t *,
+				request->auth_icv_offset) == digest) {
+			return 0;
+		}
+	}
+
+	/*
+	 * If we landed here it means that digest pointer is
+	 * at different than expected place.
+	 */
+	return -1;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * PMD Framework handlers
+ *-----------------------------------------------------------------------------
+ */
+
+/**
+ * Enqueue burst.
+ *
+ * @param queue_pair Pointer to queue pair.
+ * @param ops Pointer to ops requests array.
+ * @param nb_ops Number of elements in ops requests array.
+ * @returns Number of elements consumed from ops.
+ */
+static uint16_t
+mrvl_crypto_pmd_enqueue_burst(void *queue_pair, struct rte_crypto_op **ops,
+		uint16_t nb_ops)
+{
+	uint16_t iter_ops = 0;
+	uint16_t to_enq = 0;
+	uint16_t consumed = 0;
+	int ret;
+	struct sam_cio_op_params requests[nb_ops];
+	/*
+	 * DPDK uses single fragment buffers, so we can KISS descriptors.
+	 * SAM does not store bd pointers, so on-stack scope will be enough.
+	 */
+	struct sam_buf_info src_bd[nb_ops];
+	struct sam_buf_info dst_bd[nb_ops];
+	struct mrvl_crypto_qp *qp = (struct mrvl_crypto_qp *)queue_pair;
+
+	if (nb_ops == 0)
+		return 0;
+
+	/* Prepare the burst. */
+	memset(&requests, 0, sizeof(requests));
+
+	/* Iterate through */
+	for (; iter_ops < nb_ops; ++iter_ops) {
+		if (mrvl_request_prepare(&requests[iter_ops],
+					&src_bd[iter_ops],
+					&dst_bd[iter_ops],
+					ops[iter_ops]) < 0) {
+			MRVL_CRYPTO_LOG_ERR(
+				"Error while parameters preparation!");
+			qp->stats.enqueue_err_count++;
+			ops[iter_ops]->status = RTE_CRYPTO_OP_STATUS_ERROR;
+
+			/*
+			 * Number of handled ops is increased
+			 * (even if the result of handling is error).
+			 */
+			++consumed;
+			break;
+		}
+
+		ops[iter_ops]->status =
+			RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
+
+		/* Increase the number of ops to enqueue. */
+		++to_enq;
+	} /* for (; iter_ops < nb_ops;... */
+
+	if (to_enq > 0) {
+		/* Send the burst */
+		ret = sam_cio_enq(qp->cio, requests, &to_enq);
+		consumed += to_enq;
+		if (ret < 0) {
+			/*
+			 * Trust SAM that in this case returned value will be at
+			 * some point correct (now it is returned unmodified).
+			 */
+			qp->stats.enqueue_err_count += to_enq;
+			for (iter_ops = 0; iter_ops < to_enq; ++iter_ops)
+				ops[iter_ops]->status =
+					RTE_CRYPTO_OP_STATUS_ERROR;
+		}
+	}
+
+	qp->stats.enqueued_count += to_enq;
+	return consumed;
+}
+
+/**
+ * Dequeue burst.
+ *
+ * @param queue_pair Pointer to queue pair.
+ * @param ops Pointer to ops requests array.
+ * @param nb_ops Number of elements in ops requests array.
+ * @returns Number of elements dequeued.
+ */
+static uint16_t
+mrvl_crypto_pmd_dequeue_burst(void *queue_pair,
+		struct rte_crypto_op **ops,
+		uint16_t nb_ops)
+{
+	int ret;
+	struct mrvl_crypto_qp *qp = queue_pair;
+	struct sam_cio *cio = qp->cio;
+	struct sam_cio_op_result results[nb_ops];
+	uint16_t i;
+
+	ret = sam_cio_deq(cio, results, &nb_ops);
+	if (ret < 0) {
+		/* Count all dequeued as error. */
+		qp->stats.dequeue_err_count += nb_ops;
+
+		/* But act as they were dequeued anyway*/
+		qp->stats.dequeued_count += nb_ops;
+
+		return 0;
+	}
+
+	/* Unpack and check results. */
+	for (i = 0; i < nb_ops; ++i) {
+		ops[i] = results[i].cookie;
+
+		switch (results[i].status) {
+		case SAM_CIO_OK:
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
+			break;
+		case SAM_CIO_ERR_ICV:
+			MRVL_CRYPTO_LOG_DBG("CIO returned SAM_CIO_ERR_ICV.");
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
+			break;
+		default:
+			MRVL_CRYPTO_LOG_DBG(
+				"CIO returned Error: %d", results[i].status);
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_ERROR;
+			break;
+		}
+	}
+
+	qp->stats.dequeued_count += nb_ops;
+	return nb_ops;
+}
+
+/**
+ * Create a new crypto device.
+ *
+ * @param name Driver name.
+ * @param vdev Pointer to device structure.
+ * @param init_params Pointer to initialization parameters.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+cryptodev_mrvl_crypto_create(const char *name,
+		struct rte_vdev_device *vdev,
+		struct rte_crypto_vdev_init_params *init_params)
+{
+	struct rte_cryptodev *dev;
+	struct mrvl_crypto_private *internals;
+	struct sam_init_params	sam_params;
+	int ret;
+
+	if (init_params->name[0] == '\0') {
+		ret = rte_cryptodev_pmd_create_dev_name(
+				init_params->name, name);
+
+		if (ret < 0) {
+			MRVL_CRYPTO_LOG_ERR("failed to create unique name");
+			return ret;
+		}
+	}
+
+	dev = rte_cryptodev_vdev_pmd_init(init_params->name,
+				sizeof(struct mrvl_crypto_private),
+				init_params->socket_id, vdev);
+	if (dev == NULL) {
+		MRVL_CRYPTO_LOG_ERR("failed to create cryptodev vdev");
+		goto init_error;
+	}
+
+	dev->driver_id = cryptodev_driver_id;
+	dev->dev_ops = rte_mrvl_crypto_pmd_ops;
+
+	/* Register rx/tx burst functions for data path. */
+	dev->enqueue_burst = mrvl_crypto_pmd_enqueue_burst;
+	dev->dequeue_burst = mrvl_crypto_pmd_dequeue_burst;
+
+	dev->feature_flags = RTE_CRYPTODEV_FF_SYMMETRIC_CRYPTO |
+			RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING |
+			RTE_CRYPTODEV_FF_HW_ACCELERATED;
+
+	/* Set vector instructions mode supported */
+	internals = dev->data->dev_private;
+
+	internals->max_nb_qpairs = init_params->max_nb_queue_pairs;
+	internals->max_nb_sessions = init_params->max_nb_sessions;
+
+	/*
+	 * ret == -EEXIST is correct, it means DMA
+	 * has been already initialized.
+	 */
+	ret = mv_sys_dma_mem_init(RTE_MRVL_MUSDK_DMA_MEMSIZE);
+	if ((ret < 0) && (ret != -EEXIST))
+		return ret;
+
+	sam_params.max_num_sessions = internals->max_nb_sessions;
+
+	return sam_init(&sam_params);
+
+init_error:
+	MRVL_CRYPTO_LOG_ERR(
+		"driver %s: %s failed", init_params->name, __func__);
+
+	cryptodev_mrvl_crypto_uninit(vdev);
+	return -EFAULT;
+}
+
+/**
+ * Initialize the crypto device.
+ *
+ * @param vdev Pointer to device structure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+cryptodev_mrvl_crypto_init(struct rte_vdev_device *vdev)
+{
+	struct rte_crypto_vdev_init_params init_params = { };
+	const char *name;
+	const char *input_args;
+	int ret;
+
+	name = rte_vdev_device_name(vdev);
+	if (name == NULL)
+		return -EINVAL;
+	input_args = rte_vdev_device_args(vdev);
+
+	if (!input_args)
+		return -EINVAL;
+
+	init_params.max_nb_queue_pairs = sam_get_num_inst() * SAM_HW_RING_NUM;
+	init_params.max_nb_sessions =
+		RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_SESSIONS;
+	init_params.socket_id = rte_socket_id();
+
+	ret = rte_cryptodev_vdev_parse_init_params(&init_params, input_args);
+	if (ret) {
+		RTE_LOG(ERR, PMD, "Failed to parse input arguments\n");
+		return ret;
+	}
+
+	RTE_LOG(INFO, PMD, "Initialising %s on NUMA node %d\n", name,
+			init_params.socket_id);
+	if (init_params.name[0] != '\0') {
+		RTE_LOG(INFO, PMD, "  User defined name = %s\n",
+			init_params.name);
+	}
+	RTE_LOG(INFO, PMD, "  Max number of queue pairs = %d\n",
+			init_params.max_nb_queue_pairs);
+	RTE_LOG(INFO, PMD, "  Max number of sessions = %d\n",
+			init_params.max_nb_sessions);
+
+	return cryptodev_mrvl_crypto_create(name, vdev, &init_params);
+}
+
+/**
+ * Uninitialize the crypto device
+ *
+ * @param vdev Pointer to device structure.
+ * @returns 0 in case of success, negative value otherwise.
+ */
+static int
+cryptodev_mrvl_crypto_uninit(struct rte_vdev_device *vdev)
+{
+	const char *name = rte_vdev_device_name(vdev);
+
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD,
+		"Closing Marvell crypto device %s on numa socket %u\n",
+		name, rte_socket_id());
+
+	sam_deinit();
+
+	return 0;
+}
+
+/**
+ * Basic driver handlers for use in the constructor.
+ */
+static struct rte_vdev_driver cryptodev_mrvl_pmd_drv = {
+	.probe = cryptodev_mrvl_crypto_init,
+	.remove = cryptodev_mrvl_crypto_uninit
+};
+
+static struct cryptodev_driver mrvl_crypto_drv;
+
+/* Register the driver in constructor. */
+RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_MRVL_PMD, cryptodev_mrvl_pmd_drv);
+RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_MRVL_PMD,
+	"max_nb_queue_pairs=<int> "
+	"max_nb_sessions=<int> "
+	"socket_id=<int>");
+RTE_PMD_REGISTER_CRYPTO_DRIVER(mrvl_crypto_drv, cryptodev_mrvl_pmd_drv,
+		cryptodev_driver_id);
diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd_ops.c b/drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
new file mode 100644
index 0000000..495fec6
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
@@ -0,0 +1,776 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) Semihalf 2017. 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 Semihalf 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 <string.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_cryptodev_pmd.h>
+
+#include "rte_mrvl_pmd_private.h"
+
+/**
+ * Capabilities list to be used in reporting to DPDK.
+ */
+static const struct rte_cryptodev_capabilities
+	mrvl_crypto_pmd_capabilities[] = {
+	{	/* MD5 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_MD5_HMAC,
+				.block_size = 64,
+				.key_size = {
+					.min = 1,
+					.max = 64,
+					.increment = 1
+				},
+				.digest_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+			}, }
+		}, }
+	},
+	{	/* MD5 */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+				{.auth = {
+					.algo = RTE_CRYPTO_AUTH_MD5,
+					.block_size = 64,
+					.key_size = {
+						.min = 0,
+						.max = 0,
+						.increment = 0
+					},
+					.digest_size = {
+						.min = 16,
+						.max = 16,
+						.increment = 0
+					},
+				}, }
+			}, }
+	},
+	{	/* SHA1 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+				{.auth = {
+					.algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+					.block_size = 64,
+					.key_size = {
+						.min = 1,
+						.max = 64,
+						.increment = 1
+					},
+					.digest_size = {
+						.min = 20,
+						.max = 20,
+						.increment = 0
+					},
+				}, }
+			}, }
+	},
+	{	/* SHA1 */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA1,
+				.block_size = 64,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 20,
+					.max = 20,
+					.increment = 0
+				},
+			}, }
+		}, }
+	},
+	{	/* SHA224 */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA224,
+				.block_size = 64,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 28,
+					.max = 28,
+					.increment = 0
+				},
+			}, }
+		}, }
+	},
+	{	/* SHA256 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+				{.auth = {
+					.algo = RTE_CRYPTO_AUTH_SHA256_HMAC,
+					.block_size = 64,
+					.key_size = {
+						.min = 1,
+						.max = 64,
+						.increment = 1
+					},
+					.digest_size = {
+						.min = 32,
+						.max = 32,
+						.increment = 0
+					},
+				}, }
+			}, }
+	},
+	{	/* SHA256 */
+			.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+				{.auth = {
+					.algo = RTE_CRYPTO_AUTH_SHA256,
+					.block_size = 64,
+					.key_size = {
+						.min = 0,
+						.max = 0,
+						.increment = 0
+					},
+					.digest_size = {
+						.min = 32,
+						.max = 32,
+						.increment = 0
+					},
+				}, }
+			}, }
+		},
+	{	/* SHA384 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA384_HMAC,
+				.block_size = 128,
+				.key_size = {
+					.min = 1,
+					.max = 128,
+					.increment = 1
+				},
+				.digest_size = {
+					.min = 48,
+					.max = 48,
+					.increment = 0
+				},
+			}, }
+		}, }
+	},
+	{	/* SHA384 */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA384,
+				.block_size = 128,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 48,
+					.max = 48,
+					.increment = 0
+				},
+			}, }
+		}, }
+	},
+	{	/* SHA512 HMAC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA512_HMAC,
+				.block_size = 128,
+				.key_size = {
+					.min = 1,
+					.max = 128,
+					.increment = 1
+				},
+				.digest_size = {
+					.min = 64,
+					.max = 64,
+					.increment = 0
+				},
+			}, }
+		}, }
+	},
+	{	/* SHA512  */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SHA512,
+				.block_size = 128,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 64,
+					.max = 64,
+					.increment = 0
+				},
+			}, }
+		}, }
+	},
+	{	/* AES CBC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			{.sym = {
+				.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+				{.cipher = {
+					.algo = RTE_CRYPTO_CIPHER_AES_CBC,
+					.block_size = 16,
+					.key_size = {
+						.min = 16,
+						.max = 32,
+						.increment = 8
+					},
+					.iv_size = {
+						.min = 16,
+						.max = 16,
+						.increment = 0
+					}
+				}, }
+			}, }
+	},
+	{	/* AES CTR */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_AES_CTR,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 32,
+					.increment = 8
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* AES GCM */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AEAD,
+			{.aead = {
+				.algo = RTE_CRYPTO_AEAD_AES_GCM,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 32,
+					.increment = 8
+				},
+				.digest_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.aad_size = {
+					.min = 8,
+					.max = 12,
+					.increment = 4
+				},
+				.iv_size = {
+					.min = 12,
+					.max = 16,
+					.increment = 4
+				}
+			}, }
+		}, }
+	},
+	{	/* AES GMAC (AUTH) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_AES_GMAC,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 32,
+					.increment = 8
+				},
+				.digest_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 8,
+					.max = 65532,
+					.increment = 4
+				}
+			}, }
+		}, }
+	},
+	{	/* 3DES CBC */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_3DES_CBC,
+				.block_size = 8,
+				.key_size = {
+					.min = 24,
+					.max = 24,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 8,
+					.max = 8,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* 3DES CTR */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_3DES_CTR,
+				.block_size = 8,
+				.key_size = {
+					.min = 24,
+					.max = 24,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 8,
+					.max = 8,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+
+	RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
+};
+
+
+/**
+ * Configure device (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param config Pointer to configuration structure.
+ * @returns 0. Always.
+ */
+static int
+mrvl_crypto_pmd_config(__rte_unused struct rte_cryptodev *dev,
+		__rte_unused struct rte_cryptodev_config *config)
+{
+	return 0;
+}
+
+/**
+ * Start device (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @returns 0. Always.
+ */
+static int
+mrvl_crypto_pmd_start(__rte_unused struct rte_cryptodev *dev)
+{
+	return 0;
+}
+
+/**
+ * Stop device (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @returns 0. Always.
+ */
+static void
+mrvl_crypto_pmd_stop(__rte_unused struct rte_cryptodev *dev)
+{
+}
+
+/**
+ * Get device statistics (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param stats Pointer to statistics structure [out].
+ */
+static void
+mrvl_crypto_pmd_stats_get(struct rte_cryptodev *dev,
+		struct rte_cryptodev_stats *stats)
+{
+	int qp_id;
+
+	for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++) {
+		struct mrvl_crypto_qp *qp = dev->data->queue_pairs[qp_id];
+
+		stats->enqueued_count += qp->stats.enqueued_count;
+		stats->dequeued_count += qp->stats.dequeued_count;
+
+		stats->enqueue_err_count += qp->stats.enqueue_err_count;
+		stats->dequeue_err_count += qp->stats.dequeue_err_count;
+	}
+}
+
+/**
+ * Reset device statistics (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ */
+static void
+mrvl_crypto_pmd_stats_reset(struct rte_cryptodev *dev)
+{
+	int qp_id;
+
+	for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++) {
+		struct mrvl_crypto_qp *qp = dev->data->queue_pairs[qp_id];
+
+		memset(&qp->stats, 0, sizeof(qp->stats));
+	}
+}
+
+/**
+ * Get device info (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param dev_info Pointer to the device info structure [out].
+ */
+static void
+mrvl_crypto_pmd_info_get(struct rte_cryptodev *dev,
+		struct rte_cryptodev_info *dev_info)
+{
+	struct mrvl_crypto_private *internals = dev->data->dev_private;
+
+	if (dev_info != NULL) {
+		dev_info->driver_id = dev->driver_id;
+		dev_info->feature_flags = dev->feature_flags;
+		dev_info->capabilities = mrvl_crypto_pmd_capabilities;
+		dev_info->max_nb_queue_pairs = internals->max_nb_qpairs;
+		dev_info->sym.max_nb_sessions = internals->max_nb_sessions;
+	}
+}
+
+/**
+ * Release queue pair (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param qp_id ID of Queue Pair to release.
+ * @returns 0. Always.
+ */
+static int
+mrvl_crypto_pmd_qp_release(struct rte_cryptodev *dev, uint16_t qp_id)
+{
+	struct mrvl_crypto_qp *qp =
+			(struct mrvl_crypto_qp *)dev->data->queue_pairs[qp_id];
+
+	if (dev->data->queue_pairs[qp_id] != NULL) {
+		sam_cio_flush(qp->cio);
+		sam_cio_deinit(qp->cio);
+		rte_free(dev->data->queue_pairs[qp_id]);
+		dev->data->queue_pairs[qp_id] = NULL;
+	}
+
+	return 0;
+}
+
+/**
+ * Close device (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @returns 0. Always.
+ */
+static int
+mrvl_crypto_pmd_close(struct rte_cryptodev *dev)
+{
+	int qp_id;
+
+	for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++)
+		mrvl_crypto_pmd_qp_release(dev, qp_id);
+
+	return 0;
+}
+
+/**
+ * Setup a queue pair (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param qp_id ID of the Queue Pair.
+ * @param qp_conf Queue pair configuration (nb of descriptors).
+ * @param socket_id NUMA socket to allocate memory on.
+ * @returns 0 upon success, negative value otherwise.
+ */
+static int
+mrvl_crypto_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
+		const struct rte_cryptodev_qp_conf *qp_conf,
+		int socket_id, struct rte_mempool *session_pool)
+{
+	struct mrvl_crypto_qp *qp = NULL;
+	char match[RTE_CRYPTODEV_NAME_LEN];
+	unsigned int n;
+
+	/* Allocate the queue pair data structure. */
+	qp = rte_zmalloc_socket("MRVL Crypto PMD Queue Pair", sizeof(*qp),
+					RTE_CACHE_LINE_SIZE, socket_id);
+	if (qp == NULL)
+		return -ENOMEM;
+
+	/* Free old qp prior setup if needed. */
+	if (dev->data->queue_pairs[qp_id] != NULL)
+		mrvl_crypto_pmd_qp_release(dev, qp_id);
+
+	do { /* Error handling block */
+
+		/*
+		 * This extra check is necessary due to a bug in
+		 * crypto library.
+		 */
+		int num = sam_get_num_inst();
+		if (num == 0) {
+			MRVL_CRYPTO_LOG_ERR("No crypto engines detected.\n");
+			return -1;
+		}
+
+		/*
+		 * In case two crypto engines are enabled qps will
+		 * be evenly spread among them. Even and odd qps will
+		 * be handled by cio-0 and cio-1 respectively. qp-cio mapping
+		 * will look as follows:
+		 *
+		 * qp:      0        1        2        3
+		 * cio-x:y: cio-0:0, cio-1:0, cio-0:1, cio-1:1
+		 *
+		 * qp:      4        5        6        7
+		 * cio-x:y: cio-0:2, cio-1:2, cio-0:3, cio-1:3
+		 *
+		 * In case just one engine is enabled mapping will look as
+		 * follows:
+		 * qp:      0        1        2        3
+		 * cio-x:y: cio-0:0, cio-0:1, cio-0:2, cio-0:3
+		 */
+		n = snprintf(match, sizeof(match), "cio-%u:%u",
+				qp_id % num, qp_id / num);
+
+		if (n >= sizeof(match))
+			break;
+
+		qp->cio_params.match = match;
+		qp->cio_params.size = qp_conf->nb_descriptors;
+
+		if (sam_cio_init(&qp->cio_params, &qp->cio) < 0)
+			break;
+
+		qp->sess_mp = session_pool;
+
+		memset(&qp->stats, 0, sizeof(qp->stats));
+		dev->data->queue_pairs[qp_id] = qp;
+		return 0;
+	} while (0);
+
+	rte_free(qp);
+	return -1;
+}
+
+/** Start queue pair (PMD ops callback) - not supported.
+ *
+ * @param dev Pointer to the device structure.
+ * @param qp_id ID of the Queue Pair.
+ * @returns -ENOTSUP. Always.
+ */
+static int
+mrvl_crypto_pmd_qp_start(__rte_unused struct rte_cryptodev *dev,
+		__rte_unused uint16_t queue_pair_id)
+{
+	return -ENOTSUP;
+}
+
+/** Stop queue pair (PMD ops callback) - not supported.
+ *
+ * @param dev Pointer to the device structure.
+ * @param qp_id ID of the Queue Pair.
+ * @returns -ENOTSUP. Always.
+ */
+static int
+mrvl_crypto_pmd_qp_stop(__rte_unused struct rte_cryptodev *dev,
+		__rte_unused uint16_t queue_pair_id)
+{
+	return -ENOTSUP;
+}
+
+/** Return the number of allocated queue pairs (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @returns Number of allocated queue pairs.
+ */
+static uint32_t
+mrvl_crypto_pmd_qp_count(struct rte_cryptodev *dev)
+{
+	return dev->data->nb_queue_pairs;
+}
+
+/** Returns the size of the session structure (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure [Unused].
+ * @returns Size of Marvell crypto session.
+ */
+static unsigned
+mrvl_crypto_pmd_session_get_size(__rte_unused struct rte_cryptodev *dev)
+{
+	return sizeof(struct mrvl_crypto_session);
+}
+
+/** Configure the session from a crypto xform chain (PMD ops callback).
+ *
+ * @param dev Pointer to the device structure.
+ * @param xform Pointer to the crytpo configuration structure.
+ * @param sess Pointer to the empty session structure.
+ * @returns 0 upon success, negative value otherwise.
+ */
+static int
+mrvl_crypto_pmd_session_configure(__rte_unused struct rte_cryptodev *dev,
+		struct rte_crypto_sym_xform *xform,
+		struct rte_cryptodev_sym_session *sess,
+		struct rte_mempool *mp)
+{
+	struct mrvl_crypto_session *mrvl_sess;
+	void *sess_private_data;
+	int ret;
+
+	if (sess == NULL) {
+		MRVL_CRYPTO_LOG_ERR("Invalid session struct.");
+		return -EINVAL;
+	}
+
+	if (rte_mempool_get(mp, &sess_private_data)) {
+		CDEV_LOG_ERR("Couldn't get object from session mempool.");
+		return -ENOMEM;
+	}
+
+	ret = mrvl_crypto_set_session_parameters(sess_private_data, xform);
+	if (ret != 0) {
+		MRVL_CRYPTO_LOG_ERR("Failed to configure session parameters.");
+
+		/* Return session to mempool */
+		rte_mempool_put(mp, sess_private_data);
+		return ret;
+	}
+
+	set_session_private_data(sess, dev->driver_id, sess_private_data);
+
+	mrvl_sess = (struct mrvl_crypto_session *)sess_private_data;
+	if (sam_session_create(&mrvl_sess->sam_sess_params,
+				&mrvl_sess->sam_sess) < 0) {
+		MRVL_CRYPTO_LOG_DBG("Failed to create session!");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ * Clear the memory of session so it doesn't leave key material behind.
+ *
+ * @param dev Pointer to the device structure.
+ * @returns 0. Always.
+ */
+static void
+mrvl_crypto_pmd_session_clear(struct rte_cryptodev *dev,
+		struct rte_cryptodev_sym_session *sess)
+{
+
+	uint8_t index = dev->driver_id;
+	void *sess_priv = get_session_private_data(sess, index);
+
+	/* Zero out the whole structure */
+	if (sess_priv) {
+		struct mrvl_crypto_session *mrvl_sess =
+			(struct mrvl_crypto_session *)sess_priv;
+
+		if (mrvl_sess->sam_sess &&
+		    sam_session_destroy(mrvl_sess->sam_sess) < 0) {
+			MRVL_CRYPTO_LOG_INFO("Error while destroying session!");
+		}
+
+		memset(sess, 0, sizeof(struct mrvl_crypto_session));
+		struct rte_mempool *sess_mp = rte_mempool_from_obj(sess_priv);
+		set_session_private_data(sess, index, NULL);
+		rte_mempool_put(sess_mp, sess_priv);
+	}
+}
+
+/**
+ * PMD handlers for crypto ops.
+ */
+static struct rte_cryptodev_ops mrvl_crypto_pmd_ops = {
+		.dev_configure		= mrvl_crypto_pmd_config,
+		.dev_start		= mrvl_crypto_pmd_start,
+		.dev_stop		= mrvl_crypto_pmd_stop,
+		.dev_close		= mrvl_crypto_pmd_close,
+
+		.dev_infos_get		= mrvl_crypto_pmd_info_get,
+
+		.stats_get		= mrvl_crypto_pmd_stats_get,
+		.stats_reset		= mrvl_crypto_pmd_stats_reset,
+
+		.queue_pair_setup	= mrvl_crypto_pmd_qp_setup,
+		.queue_pair_release	= mrvl_crypto_pmd_qp_release,
+		.queue_pair_start	= mrvl_crypto_pmd_qp_start,
+		.queue_pair_stop	= mrvl_crypto_pmd_qp_stop,
+		.queue_pair_count	= mrvl_crypto_pmd_qp_count,
+
+		.session_get_size	= mrvl_crypto_pmd_session_get_size,
+		.session_configure	= mrvl_crypto_pmd_session_configure,
+		.session_clear		= mrvl_crypto_pmd_session_clear
+};
+
+struct rte_cryptodev_ops *rte_mrvl_crypto_pmd_ops = &mrvl_crypto_pmd_ops;
diff --git a/drivers/crypto/mrvl/rte_mrvl_pmd_private.h b/drivers/crypto/mrvl/rte_mrvl_pmd_private.h
new file mode 100644
index 0000000..2da14b8
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_mrvl_pmd_private.h
@@ -0,0 +1,121 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright (C) Semihalf 2017. 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 Semihalf 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_MRVL_PMD_PRIVATE_H_
+#define _RTE_MRVL_PMD_PRIVATE_H_
+
+#include "rte_mrvl_compat.h"
+
+#define CRYPTODEV_NAME_MRVL_PMD crypto_mrvl
+/**< Marvell PMD device name */
+
+#define MRVL_CRYPTO_LOG_ERR(fmt, args...) \
+	RTE_LOG(ERR, CRYPTODEV, "[%s] %s() line %u: " fmt "\n",  \
+			RTE_STR(CRYPTODEV_NAME_MRVL_CRYPTO_PMD), \
+			__func__, __LINE__, ## args)
+
+#ifdef RTE_LIBRTE_MRVL_CRYPTO_DEBUG
+#define MRVL_CRYPTO_LOG_INFO(fmt, args...) \
+	RTE_LOG(INFO, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+			RTE_STR(CRYPTODEV_NAME_MRVL_CRYPTO_PMD), \
+			__func__, __LINE__, ## args)
+
+#define MRVL_CRYPTO_LOG_DBG(fmt, args...) \
+	RTE_LOG(DEBUG, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+			RTE_STR(CRYPTODEV_NAME_MRVL_CRYPTO_PMD), \
+			__func__, __LINE__, ## args)
+
+#else
+#define MRVL_CRYPTO_LOG_INFO(fmt, args...)
+#define MRVL_CRYPTO_LOG_DBG(fmt, args...)
+#endif
+
+/**
+ * Handy bits->bytes conversion macro.
+ */
+#define BITS2BYTES(x) ((x) >> 3)
+
+/** The operation order mode enumerator. */
+enum mrvl_crypto_chain_order {
+	MRVL_CRYPTO_CHAIN_CIPHER_ONLY,
+	MRVL_CRYPTO_CHAIN_AUTH_ONLY,
+	MRVL_CRYPTO_CHAIN_CIPHER_AUTH,
+	MRVL_CRYPTO_CHAIN_AUTH_CIPHER,
+	MRVL_CRYPTO_CHAIN_COMBINED,
+	MRVL_CRYPTO_CHAIN_NOT_SUPPORTED,
+};
+
+/** Private data structure for each crypto device. */
+struct mrvl_crypto_private {
+	unsigned int max_nb_qpairs;	/**< Max number of queue pairs */
+	unsigned int max_nb_sessions;	/**< Max number of sessions */
+};
+
+/** MRVL crypto queue pair structure. */
+struct mrvl_crypto_qp {
+	/** SAM CIO (MUSDK Queue Pair equivalent).*/
+	struct sam_cio *cio;
+
+	/** Session Mempool. */
+	struct rte_mempool *sess_mp;
+
+	/** Queue pair statistics. */
+	struct rte_cryptodev_stats stats;
+
+	/** CIO initialization parameters.*/
+	struct sam_cio_params cio_params;
+} __rte_cache_aligned;
+
+/** MRVL crypto private session structure. */
+struct mrvl_crypto_session {
+	/** Crypto operations chain order. */
+	enum mrvl_crypto_chain_order chain_order;
+
+	/** Session initialization parameters. */
+	struct sam_session_params sam_sess_params;
+
+	/** SAM session pointer. */
+	struct sam_sa *sam_sess;
+
+	/** Cipher IV offset. */
+	uint16_t cipher_iv_offset;
+} __rte_cache_aligned;
+
+/** Set and validate MRVL crypto session parameters */
+extern int
+mrvl_crypto_set_session_parameters(struct mrvl_crypto_session *sess,
+		const struct rte_crypto_sym_xform *xform);
+
+/** device specific operations function pointer structure */
+extern struct rte_cryptodev_ops *rte_mrvl_crypto_pmd_ops;
+
+#endif /* _RTE_MRVL_PMD_PRIVATE_H_ */
diff --git a/drivers/crypto/mrvl/rte_pmd_mrvl_version.map b/drivers/crypto/mrvl/rte_pmd_mrvl_version.map
new file mode 100644
index 0000000..a753031
--- /dev/null
+++ b/drivers/crypto/mrvl/rte_pmd_mrvl_version.map
@@ -0,0 +1,3 @@
+DPDK_17.11 {
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 51b97e3..c6d21df 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -172,6 +172,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_ZUC)         += -lrte_pmd_zuc
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_ZUC)         += -L$(LIBSSO_ZUC_PATH)/build -lsso_zuc
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO)    += -lrte_pmd_armv8
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO)    += -L$(ARMV8_CRYPTO_LIB_PATH) -larmv8_crypto
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO) += -L$(LIBMUSDK_PATH)/lib -lrte_pmd_mrvl_crypto -lmusdk
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER) += -lrte_pmd_crypto_scheduler
 ifeq ($(CONFIG_RTE_LIBRTE_FSLMC_BUS),y)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_SEC)   += -lrte_pmd_dpaa2_sec
--
2.7.4

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

* [PATCH v4 2/4] doc: add mrvl crypto pmd documentation
  2017-10-10 12:17     ` [PATCH v4 0/4] add crypto mrvl pmd driver Tomasz Duszynski
  2017-10-10 12:17       ` [PATCH v4 1/4] crypto/mrvl: add mrvl crypto " Tomasz Duszynski
@ 2017-10-10 12:17       ` Tomasz Duszynski
  2017-10-10 12:17       ` [PATCH v4 3/4] maintainers: add maintainers for the mrvl crypto pmd Tomasz Duszynski
                         ` (2 subsequent siblings)
  4 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-10 12:17 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add documentation for the MRVL CRYPTO PMD driver.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 v4:
 * Updated documentation.

 v3:
 * Updated documentation.

 doc/guides/cryptodevs/features/mrvl.ini |  42 +++++++
 doc/guides/cryptodevs/index.rst         |   1 +
 doc/guides/cryptodevs/mrvl.rst          | 205 ++++++++++++++++++++++++++++++++
 3 files changed, 248 insertions(+)
 create mode 100644 doc/guides/cryptodevs/features/mrvl.ini
 create mode 100644 doc/guides/cryptodevs/mrvl.rst

diff --git a/doc/guides/cryptodevs/features/mrvl.ini b/doc/guides/cryptodevs/features/mrvl.ini
new file mode 100644
index 0000000..6d2fe6a
--- /dev/null
+++ b/doc/guides/cryptodevs/features/mrvl.ini
@@ -0,0 +1,42 @@
+; Supported features of the 'mrvl' crypto driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Symmetric crypto       = Y
+Sym operation chaining = Y
+
+;
+; Supported crypto algorithms of a default crypto driver.
+;
+[Cipher]
+AES CBC (128)  = Y
+AES CBC (192)  = Y
+AES CBC (256)  = Y
+AES CTR (128)  = Y
+AES CTR (192)  = Y
+AES CTR (256)  = Y
+3DES CBC       = Y
+3DES CTR       = Y
+
+;
+; Supported authentication algorithms of a default crypto driver.
+;
+[Auth]
+MD5          = Y
+MD5 HMAC     = Y
+SHA1         = Y
+SHA1 HMAC    = Y
+SHA256       = Y
+SHA256 HMAC  = Y
+SHA384       = Y
+SHA384 HMAC  = Y
+SHA512       = Y
+SHA512 HMAC  = Y
+AES GMAC     = Y
+
+;
+; Supported AEAD algorithms of a default crypto driver.
+;
+[AEAD]
+AES GCM (128) = Y
diff --git a/doc/guides/cryptodevs/index.rst b/doc/guides/cryptodevs/index.rst
index 3a39a2d..6d4e15b 100644
--- a/doc/guides/cryptodevs/index.rst
+++ b/doc/guides/cryptodevs/index.rst
@@ -43,6 +43,7 @@ Crypto Device Drivers
     dpaa_sec
     kasumi
     openssl
+    mrvl
     null
     scheduler
     snow3g
diff --git a/doc/guides/cryptodevs/mrvl.rst b/doc/guides/cryptodevs/mrvl.rst
new file mode 100644
index 0000000..8c941f9
--- /dev/null
+++ b/doc/guides/cryptodevs/mrvl.rst
@@ -0,0 +1,205 @@
+..  BSD LICENSE
+    Copyright(c) 2017 Semihalf. All rights reserved.
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in
+        the documentation and/or other materials provided with the
+        distribution.
+      * Neither the name of Semihalf 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.
+
+MRVL Crypto Poll Mode Driver
+============================
+
+The MRVL CRYPTO PMD (**librte_crypto_mrvl_pmd**) provides poll mode crypto driver
+support by utilizing MUSDK library, which provides cryptographic operations
+acceleration by using Security Acceleration Engine (EIP197) directly from
+user-space with minimum overhead and high performance.
+
+Features
+--------
+
+MRVL CRYPTO PMD has support for:
+
+* Symmetric crypto
+* Sym operation chaining
+* AES CBC (128)
+* AES CBC (192)
+* AES CBC (256)
+* AES CTR (128)
+* AES CTR (192)
+* AES CTR (256)
+* 3DES CBC
+* 3DES CTR
+* MD5
+* MD5 HMAC
+* SHA1
+* SHA1 HMAC
+* SHA256
+* SHA256 HMAC
+* SHA384
+* SHA384 HMAC
+* SHA512
+* SHA512 HMAC
+* AES GCM (128)
+
+Limitations
+-----------
+
+* Hardware only supports scenarios where ICV (digest buffer) is placed just
+  after the authenticated data. Other placement will result in error.
+
+* Before running crypto test suite it is advised to increase limit of
+  opened files:
+
+  .. code-block:: console
+
+     ulimit -n 20000
+
+Installation
+------------
+
+MRVL CRYPTO PMD driver compilation is disabled by default due to external dependencies.
+Currently there are two driver specific compilation options in
+``config/common_base`` available:
+
+- ``CONFIG_RTE_LIBRTE_MRVL_CRYPTO`` (default ``n``)
+
+    Toggle compilation of the librte_pmd_mrvl driver.
+
+- ``CONFIG_RTE_LIBRTE_MRVL_CRYPTO_DEBUG`` (default ``n``)
+
+    Toggle display of debugging messages.
+
+During compilation external MUSDK library, which provides direct access
+to Marvell's EIP197 cryptographic engine, is necessary. Library sources are
+available `here <https://github.com/MarvellEmbeddedProcessors/musdk-marvell/tree/musdk-armada-17.08>`__.
+
+Alternatively, prebuilt library can be downloaded from
+`Marvell Extranet <https://extranet.marvell.com>`_. Once approval has been
+granted, library can be found by typing ``musdk`` in the search box.
+
+For MUSDK library build instructions please refer to ``doc/musdk_get_started.txt``
+in library sources directory.
+
+MUSDK requires out of tree kernel modules to work. Kernel tree needed to build
+them is available
+`here <https://github.com/MarvellEmbeddedProcessors/linux-marvell/tree/linux-4.4.52-armada-17.08>`__.
+
+Initialization
+--------------
+
+After successfully building MRVL CRYPTO PMD, the following modules need to be
+loaded:
+
+.. code-block:: console
+
+   insmod musdk_uio.ko
+   insmod mvpp2x_sysfs.ko
+   insmod mv_pp_uio.ko
+   insmod mv_sam_uio.ko
+   insmod crypto_safexcel.ko
+
+- `musdk_uio.ko`, `mv_pp2_uio.ko` and `mv_sam_uio.ko` are distributed together with MUSDK library.
+- `crypto_safexcel.ko` is an in-kernel module.
+- `mvpp2x_sysfs.ko` can be build from sources available `here <https://github.com/MarvellEmbeddedProcessors/mvpp2x-marvell/tree/mvpp2x-armada-17.08>`__.
+
+The following parameters (all optional) are exported by the driver:
+
+* max_nb_queue_pairs: maximum number of queue pairs in the device (8 by default).
+* max_nb_sessions: maximum number of sessions that can be created (2048 by default).
+* socket_id: socket on which to allocate the device resources on.
+
+l2fwd-crypto example application can be used to verify MRVL CRYPTO PMD
+operation:
+
+.. code-block:: console
+
+   ./l2fwd-crypto --vdev=net_mrvl,iface=eth0 --vdev=crypto_mrvl -- \
+     --cipher_op ENCRYPT --cipher_algo aes-cbc \
+     --cipher_key 00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f  \
+     --auth_op GENERATE --auth_algo sha1-hmac \
+     --auth_key 10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f
+
+Example output:
+
+.. code-block:: console
+
+   [...]
+   AAD: at [0x7f253ceb80], len=
+   P ID 0 configuration ----
+   Port mode               : KR
+   MAC status              : disabled
+   Link status             : link up
+   Port speed              : 10G
+   Port duplex             : full
+   Port: Egress enable tx_port_num=16 qmap=0x1
+   PORT: Port0 - link
+   P ID 0 configuration ----
+   Port mode               : KR
+   MAC status              : disabled
+   Link status             : link down
+   Port speed              : 10G
+   Port duplex             : full
+   Port: Egress enable tx_port_num=16 qmap=0x1
+   Port 0, MAC address: 00:50:43:02:21:20
+
+
+   Checking link statusdone
+   Port 0 Link Up - speed 0 Mbps - full-duplex
+   Lcore 0: RX port 0
+   Allocated session pool on socket 0
+   eip197: 0:0 registers: paddr: 0xf2880000, vaddr: 0x0x7f56a80000
+   DMA buffer (131136 bytes) for CDR #0 allocated: paddr = 0xb0585e00, vaddr = 0x7f09384e00
+   DMA buffer (131136 bytes) for RDR #0 allocated: paddr = 0xb05a5f00, vaddr = 0x7f093a4f00
+   DMA buffers allocated for 2049 operations. Tokens - 256 bytes
+   Lcore 0: cryptodev 0
+   L2FWD: lcore 1 has nothing to do
+   L2FWD: lcore 2 has nothing to do
+   L2FWD: lcore 3 has nothing to do
+   L2FWD: entering main loop on lcore 0
+   L2FWD:  -- lcoreid=0 portid=0
+   L2FWD:  -- lcoreid=0 cryptoid=0
+   Options:-
+   nportmask: ffffffff
+   ports per lcore: 1
+   refresh period : 10000
+   single lcore mode: disabled
+   stats_printing: enabled
+   sessionless crypto: disabled
+
+   Crypto chain: Input --> Encrypt --> Auth generate --> Output
+
+   ---- Cipher information ---
+   Algorithm: aes-cbc
+   Cipher key: at [0x7f56db4e80], len=16
+   00000000: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F | ................
+   IV: at [0x7f56db4b80], len=16
+   00000000: 20 F0 63 0E 45 EB 2D 84 72 D4 13 6E 36 B5 AF FE |  .c.E.-.r..n6...
+
+   ---- Authentication information ---
+   Algorithm: sha1-hmac
+   Auth key: at [0x7f56db4d80], len=16
+   00000000: 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F | ................
+   IV: at [0x7f56db4a80], len=0
+   AAD: at [0x7f253ceb80], len=
--
2.7.4

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

* [PATCH v4 3/4] maintainers: add maintainers for the mrvl crypto pmd
  2017-10-10 12:17     ` [PATCH v4 0/4] add crypto mrvl pmd driver Tomasz Duszynski
  2017-10-10 12:17       ` [PATCH v4 1/4] crypto/mrvl: add mrvl crypto " Tomasz Duszynski
  2017-10-10 12:17       ` [PATCH v4 2/4] doc: add mrvl crypto pmd documentation Tomasz Duszynski
@ 2017-10-10 12:17       ` Tomasz Duszynski
  2017-10-10 12:17       ` [PATCH v4 4/4] test: add mrvl crypto pmd unit tests Tomasz Duszynski
  2017-10-12 12:11       ` [PATCH v4 0/4] add crypto mrvl pmd driver De Lara Guarch, Pablo
  4 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-10 12:17 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 v4:
 * Changed Jianbo Liu mail address.

 MAINTAINERS | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index fd565ae..eb453a9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -576,6 +576,16 @@ F: drivers/crypto/dpaa2_sec/
 F: doc/guides/cryptodevs/dpaa2_sec.rst
 F: doc/guides/cryptodevs/features/dpaa2_sec.ini

+MARVELL MRVL PMD
+M: Jacek Siuda <jck@semihalf.com>
+M: Tomasz Duszynski <tdu@semihalf.com>
+M: Dmitri Epshtein <dima@marvell.com>
+M: Natalie Samsonov <nsamsono@marvell.com>
+M: Jianbo Liu <jianbo.liu@arm.org>
+F: drivers/crypto/mrvl/
+F: doc/guides/cryptodevs/mrvl.rst
+F: doc/guides/cryptodevs/mrvl.ini
+
 SNOW 3G PMD
 M: Pablo de Lara <pablo.de.lara.guarch@intel.com>
 F: drivers/crypto/snow3g/
--
2.7.4

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

* [PATCH v4 4/4] test: add mrvl crypto pmd unit tests
  2017-10-10 12:17     ` [PATCH v4 0/4] add crypto mrvl pmd driver Tomasz Duszynski
                         ` (2 preceding siblings ...)
  2017-10-10 12:17       ` [PATCH v4 3/4] maintainers: add maintainers for the mrvl crypto pmd Tomasz Duszynski
@ 2017-10-10 12:17       ` Tomasz Duszynski
  2017-10-12 12:11       ` [PATCH v4 0/4] add crypto mrvl pmd driver De Lara Guarch, Pablo
  4 siblings, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-10 12:17 UTC (permalink / raw)
  To: dev; +Cc: mw, dima, nsamsono, Jianbo.liu, Tomasz Duszynski, Jacek Siuda

Add unit tests for MRVL CRYPTO PMD driver.

Signed-off-by: Jacek Siuda <jck@semihalf.com>
Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
---
 test/test/test_cryptodev.c                  | 168 ++++++++++++++++++++++++++++
 test/test/test_cryptodev.h                  |   1 +
 test/test/test_cryptodev_aes_test_vectors.h |  72 ++++++++----
 test/test/test_cryptodev_blockcipher.c      |   9 +-
 test/test/test_cryptodev_blockcipher.h      |   1 +
 test/test/test_cryptodev_des_test_vectors.h |  24 ++--
 6 files changed, 242 insertions(+), 33 deletions(-)

diff --git a/test/test/test_cryptodev.c b/test/test/test_cryptodev.c
index df84430..a926779 100644
--- a/test/test/test_cryptodev.c
+++ b/test/test/test_cryptodev.c
@@ -341,6 +341,28 @@ testsuite_setup(void)
 		}
 	}
 
+	/* Create a MRVL device if required */
+	if (gbl_driver_id == rte_cryptodev_driver_id_get(
+			RTE_STR(CRYPTODEV_MRVL_PMD))) {
+#ifndef RTE_LIBRTE_PMD_MRVL_CRYPTO
+		RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO must be"
+			" enabled in config file to run this testsuite.\n");
+		return TEST_FAILED;
+#endif
+		nb_devs = rte_cryptodev_device_count_by_driver(
+				rte_cryptodev_driver_id_get(
+				RTE_STR(CRYPTODEV_NAME_MRVL_PMD)));
+		if (nb_devs < 1) {
+			ret = rte_vdev_init(
+				RTE_STR(CRYPTODEV_NAME_MRVL_PMD),
+				NULL);
+
+			TEST_ASSERT(ret == 0, "Failed to create "
+				"instance of pmd : %s",
+				RTE_STR(CRYPTODEV_NAME_MRVL_PMD));
+		}
+	}
+
 #ifdef RTE_LIBRTE_PMD_CRYPTO_SCHEDULER
 	if (gbl_driver_id == rte_cryptodev_driver_id_get(
 			RTE_STR(CRYPTODEV_NAME_SCHEDULER_PMD))) {
@@ -1919,6 +1941,101 @@ test_AES_chain_armv8_all(void)
 	return TEST_SUCCESS;
 }
 
+static int
+test_AES_chain_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_AES_CHAIN_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_AES_cipheronly_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_AES_CIPHERONLY_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_authonly_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_AUTHONLY_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_3DES_chain_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_3DES_CHAIN_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_3DES_cipheronly_mrvl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool,
+		ts_params->session_mpool,
+		ts_params->valid_devs[0],
+		rte_cryptodev_driver_id_get(
+		RTE_STR(CRYPTODEV_NAME_MRVL_PMD)),
+		BLKCIPHER_3DES_CIPHERONLY_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
 /* ***** SNOW 3G Tests ***** */
 static int
 create_wireless_algo_hash_session(uint8_t dev_id,
@@ -9417,6 +9534,40 @@ static struct unit_test_suite cryptodev_armv8_testsuite  = {
 	}
 };
 
+static struct unit_test_suite cryptodev_mrvl_testsuite  = {
+	.suite_name = "Crypto Device Marvell Component Test Suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASE_ST(ut_setup, ut_teardown, test_multi_session),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_multi_session_random_usage),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_AES_chain_mrvl_all),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_AES_cipheronly_mrvl_all),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_authonly_mrvl_all),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_3DES_chain_mrvl_all),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_3DES_cipheronly_mrvl_all),
+
+		/** Negative tests */
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			authentication_verify_HMAC_SHA1_fail_data_corrupt),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			authentication_verify_HMAC_SHA1_fail_tag_corrupt),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			auth_decryption_AES128CBC_HMAC_SHA1_fail_data_corrupt),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			auth_decryption_AES128CBC_HMAC_SHA1_fail_tag_corrupt),
+
+		TEST_CASES_END() /**< NULL terminate unit test array */
+	}
+};
+
+
 static int
 test_cryptodev_qat(void /*argv __rte_unused, int argc __rte_unused*/)
 {
@@ -9561,6 +9712,22 @@ test_cryptodev_armv8(void)
 	return unit_test_suite_runner(&cryptodev_armv8_testsuite);
 }
 
+static int
+test_cryptodev_mrvl(void)
+{
+	gbl_driver_id = rte_cryptodev_driver_id_get(
+			RTE_STR(CRYPTODEV_NAME_MRVL_PMD));
+
+	if (gbl_driver_id == -1) {
+		RTE_LOG(ERR, USER1, "MRVL PMD must be loaded. Check if "
+				"CONFIG_RTE_LIBRTE_PMD_MRVL_CRYPTO is enabled "
+				"in config file to run this testsuite.\n");
+		return TEST_FAILED;
+	}
+
+	return unit_test_suite_runner(&cryptodev_mrvl_testsuite);
+}
+
 #ifdef RTE_LIBRTE_PMD_CRYPTO_SCHEDULER
 
 static int
@@ -9630,5 +9797,6 @@ REGISTER_TEST_COMMAND(cryptodev_sw_snow3g_autotest, test_cryptodev_sw_snow3g);
 REGISTER_TEST_COMMAND(cryptodev_sw_kasumi_autotest, test_cryptodev_sw_kasumi);
 REGISTER_TEST_COMMAND(cryptodev_sw_zuc_autotest, test_cryptodev_sw_zuc);
 REGISTER_TEST_COMMAND(cryptodev_sw_armv8_autotest, test_cryptodev_armv8);
+REGISTER_TEST_COMMAND(cryptodev_sw_mrvl_autotest, test_cryptodev_mrvl);
 REGISTER_TEST_COMMAND(cryptodev_dpaa2_sec_autotest, test_cryptodev_dpaa2_sec);
 REGISTER_TEST_COMMAND(cryptodev_dpaa_sec_autotest, test_cryptodev_dpaa_sec);
diff --git a/test/test/test_cryptodev.h b/test/test/test_cryptodev.h
index 4509a09..2e9eb0b 100644
--- a/test/test/test_cryptodev.h
+++ b/test/test/test_cryptodev.h
@@ -88,6 +88,7 @@
 #define CRYPTODEV_NAME_ARMV8_PMD	crypto_armv8
 #define CRYPTODEV_NAME_DPAA2_SEC_PMD	crypto_dpaa2_sec
 #define CRYPTODEV_NAME_SCHEDULER_PMD	crypto_scheduler
+#define CRYPTODEV_NAME_MRVL_PMD		crypto_mrvl
 
 /**
  * Write (spread) data from buffer to mbuf data
diff --git a/test/test/test_cryptodev_aes_test_vectors.h b/test/test/test_cryptodev_aes_test_vectors.h
index 0c7e48f..e9773b5 100644
--- a/test/test/test_cryptodev_aes_test_vectors.h
+++ b/test/test/test_cryptodev_aes_test_vectors.h
@@ -1198,7 +1198,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CTR HMAC-SHA1 Decryption Digest "
@@ -1210,7 +1211,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-192-CTR XCBC Encryption Digest",
@@ -1248,7 +1250,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-256-CTR HMAC-SHA1 Decryption Digest "
@@ -1260,7 +1263,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest",
@@ -1272,14 +1276,16 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest "
 			"(short buffers)",
 		.test_data = &aes_test_data_13,
 		.op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest "
@@ -1304,14 +1310,16 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Decryption Digest "
 			"Verify (short buffers)",
 		.test_data = &aes_test_data_13,
 		.op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA256 Encryption Digest",
@@ -1323,14 +1331,16 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA256 Encryption Digest "
 			"(short buffers)",
 		.test_data = &aes_test_data_12,
 		.op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA256 Decryption Digest "
@@ -1343,14 +1353,16 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA256 Decryption Digest "
 			"Verify (short buffers)",
 		.test_data = &aes_test_data_12,
 		.op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA512 Encryption Digest",
@@ -1361,7 +1373,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA512 Encryption Digest "
@@ -1393,7 +1406,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA512 Decryption Digest "
@@ -1475,7 +1489,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA384 Decryption Digest "
@@ -1487,7 +1502,8 @@ static const struct blockcipher_test_case aes_chain_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest "
@@ -1520,7 +1536,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CBC Decryption",
@@ -1531,7 +1548,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-192-CBC Encryption",
@@ -1572,7 +1590,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-256-CBC Decryption",
@@ -1583,7 +1602,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-256-CBC OOP Encryption",
@@ -1610,7 +1630,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CTR Decryption",
@@ -1621,7 +1642,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-192-CTR Encryption",
@@ -1654,7 +1676,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-256-CTR Decryption",
@@ -1665,7 +1688,8 @@ static const struct blockcipher_test_case aes_cipheronly_test_cases[] = {
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
 			BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "AES-128-CTR Encryption (12-byte IV)",
diff --git a/test/test/test_cryptodev_blockcipher.c b/test/test/test_cryptodev_blockcipher.c
index 167d196..9a9fd8b 100644
--- a/test/test/test_cryptodev_blockcipher.c
+++ b/test/test/test_cryptodev_blockcipher.c
@@ -94,6 +94,8 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 			RTE_STR(CRYPTODEV_NAME_DPAA2_SEC_PMD));
 	int dpaa_sec_pmd = rte_cryptodev_driver_id_get(
 			RTE_STR(CRYPTODEV_NAME_DPAA_SEC_PMD));
+	int mrvl_pmd = rte_cryptodev_driver_id_get(
+			RTE_STR(CRYPTODEV_NAME_MRVL_PMD));
 
 	int nb_segs = 1;
 
@@ -119,7 +121,8 @@ test_blockcipher_one_case(const struct blockcipher_test_case *t,
 			driver_id == dpaa_sec_pmd ||
 			driver_id == qat_pmd ||
 			driver_id == openssl_pmd ||
-			driver_id == armv8_pmd) { /* Fall through */
+			driver_id == armv8_pmd ||
+			driver_id == mrvl_pmd) { /* Fall through */
 		digest_len = tdata->digest.len;
 	} else if (driver_id == aesni_mb_pmd ||
 			driver_id == scheduler_pmd) {
@@ -592,6 +595,8 @@ test_blockcipher_all_tests(struct rte_mempool *mbuf_pool,
 			RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD));
 	int qat_pmd = rte_cryptodev_driver_id_get(
 			RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD));
+	int mrvl_pmd = rte_cryptodev_driver_id_get(
+			RTE_STR(CRYPTODEV_NAME_MRVL_PMD));
 
 	switch (test_type) {
 	case BLKCIPHER_AES_CHAIN_TYPE:
@@ -652,6 +657,8 @@ test_blockcipher_all_tests(struct rte_mempool *mbuf_pool,
 		target_pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC;
 	else if (driver_id == dpaa_sec_pmd)
 		target_pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC;
+	else if (driver_id == mrvl_pmd)
+		target_pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MRVL;
 	else
 		TEST_ASSERT(0, "Unrecognized cryptodev type");
 
diff --git a/test/test/test_cryptodev_blockcipher.h b/test/test/test_cryptodev_blockcipher.h
index b81e559..67c78d4 100644
--- a/test/test/test_cryptodev_blockcipher.h
+++ b/test/test/test_cryptodev_blockcipher.h
@@ -54,6 +54,7 @@
 #define BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER	0x0010 /* Scheduler */
 #define BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC	0x0020 /* DPAA2_SEC flag */
 #define BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC	0x0040 /* DPAA_SEC flag */
+#define BLOCKCIPHER_TEST_TARGET_PMD_MRVL	0x0080 /* Marvell flag */
 
 #define BLOCKCIPHER_TEST_OP_CIPHER	(BLOCKCIPHER_TEST_OP_ENCRYPT | \
 					BLOCKCIPHER_TEST_OP_DECRYPT)
diff --git a/test/test/test_cryptodev_des_test_vectors.h b/test/test/test_cryptodev_des_test_vectors.h
index ebf8869..05265ae 100644
--- a/test/test/test_cryptodev_des_test_vectors.h
+++ b/test/test/test_cryptodev_des_test_vectors.h
@@ -853,7 +853,8 @@ static const struct blockcipher_test_case des_cipheronly_test_cases[] = {
 		.op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT,
 		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
-			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "DES-CBC Decryption",
@@ -861,7 +862,8 @@ static const struct blockcipher_test_case des_cipheronly_test_cases[] = {
 		.op_mask = BLOCKCIPHER_TEST_OP_DECRYPT,
 		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_MB |
-			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 
 };
@@ -1100,7 +1102,8 @@ static const struct blockcipher_test_case triple_des_chain_test_cases[] = {
 		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-192-CBC HMAC-SHA1 Decryption Digest Verify",
@@ -1109,19 +1112,22 @@ static const struct blockcipher_test_case triple_des_chain_test_cases[] = {
 		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-192-CBC SHA1 Encryption Digest",
 		.test_data = &triple_des192cbc_sha1_test_vector,
 		.op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-192-CBC SHA1 Decryption Digest Verify",
 		.test_data = &triple_des192cbc_sha1_test_vector,
 		.op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC,
-		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-128-CTR HMAC-SHA1 Encryption Digest",
@@ -1237,7 +1243,8 @@ static const struct blockcipher_test_case triple_des_cipheronly_test_cases[] = {
 		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-192-CBC Decryption",
@@ -1246,7 +1253,8 @@ static const struct blockcipher_test_case triple_des_cipheronly_test_cases[] = {
 		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT |
 			BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC |
-			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC
+			BLOCKCIPHER_TEST_TARGET_PMD_DPAA_SEC |
+			BLOCKCIPHER_TEST_TARGET_PMD_MRVL
 	},
 	{
 		.test_descr = "3DES-128-CTR Encryption",
-- 
2.7.4

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

* Re: [PATCH v3 2/4] net/mrvl: add mrvl net pmd driver
  2017-10-05  8:43               ` Tomasz Duszynski
  2017-10-05 17:29                 ` Ferruh Yigit
@ 2017-10-10 21:25                 ` Thomas Monjalon
  1 sibling, 0 replies; 110+ messages in thread
From: Thomas Monjalon @ 2017-10-10 21:25 UTC (permalink / raw)
  To: Tomasz Duszynski
  Cc: dev, Ferruh Yigit, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

05/10/2017 10:43, Tomasz Duszynski:
> On Wed, Oct 04, 2017 at 05:59:11PM +0100, Ferruh Yigit wrote:
> > On 10/4/2017 9:59 AM, Tomasz Duszynski wrote:
> > > On Wed, Oct 04, 2017 at 01:24:27AM +0100, Ferruh Yigit wrote:
> > >> On 10/3/2017 12:51 PM, Tomasz Duszynski wrote:
> > >>> Add support for the Marvell PPv2 (Packet Processor v2) 1/10 Gbps adapter.
> > >>> Driver is based on external, publicly available, light-weight Marvell
> > >>> MUSDK library that provides access to network packet processor.
[...]
> > >>> +static struct rte_vdev_driver pmd_mrvl_drv = {
> > >>> +	.probe = rte_pmd_mrvl_probe,
> > >>> +	.remove = rte_pmd_mrvl_remove,
> > >>> +};
> > >>> +
> > >>> +RTE_PMD_REGISTER_VDEV(net_mrvl, pmd_mrvl_drv);
> > >>
> > >> Please help me understand.
> > >>
> > >> This driver implemented as virtual driver, because:
> > >> With the help of custom kernel modules, musdk library already provides
> > >> userspace datapath support. This PMD is an interface to musdk library.
> > >> Is this correct?
> > > That is right. Another reason this NIC is not PCI device.
> >
> > We support more bus now :). Out of curiosity, which bus is device on?
> 
> Bus is called Aurora2. That's proprietary SoC interconnect fabric.

So you should provide drivers/bus/aurora2/.
It would do a software scan of devices (probably looking in sysfs).
Then the probe function is nearly the same as with vdev init.
It could provide a better user experience by removing the need of
explicit declaration of devices. It will allow to be integrated in
a more generic whitelist/blacklist mechanism.
And having such well defined bus code and objects will probably help
in your future developments.

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

* Re: [PATCH v4 02/16] net/mrvl: add mrvl net pmd driver skeleton
  2017-10-09 15:00         ` [PATCH v4 02/16] net/mrvl: add mrvl net pmd driver skeleton Tomasz Duszynski
@ 2017-10-11 13:38           ` Thomas Monjalon
  2017-10-12  6:51             ` Tomasz Duszynski
  0 siblings, 1 reply; 110+ messages in thread
From: Thomas Monjalon @ 2017-10-11 13:38 UTC (permalink / raw)
  To: Tomasz Duszynski; +Cc: dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

Hi,

09/10/2017 17:00, Tomasz Duszynski:
>  #
> +# Compile Marvell PMD driver
> +#
> +CONFIG_RTE_LIBRTE_MRVL_PMD=n
> +CONFIG_RTE_LIBRTE_MRVL_DEBUG=n
> +CONFIG_RTE_MRVL_MUSDK_DMA_MEMSIZE=41943040

We are trying to remove build-time configurations and behave like
a true library.

The DEBUG config options are now prohibited.
Where is it used in your code?
If it is used for logs, you should switch to the dynamic log config.

What is MUSDK_DMA_MEMSIZE?
If the value cannot change, it must be a constant in the code.
If it can change, it should be a run-time driver option.

Thank you and welcome!

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

* Re: [PATCH v4 16/16] doc: add mrvl net pmd documentation
  2017-10-09 15:00         ` [PATCH v4 16/16] doc: add mrvl net pmd documentation Tomasz Duszynski
  2017-10-09 20:54           ` Ferruh Yigit
@ 2017-10-11 14:27           ` Thomas Monjalon
  2017-10-12  2:01             ` Thomas Monjalon
  1 sibling, 1 reply; 110+ messages in thread
From: Thomas Monjalon @ 2017-10-11 14:27 UTC (permalink / raw)
  To: Tomasz Duszynski; +Cc: dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

09/10/2017 17:00, Tomasz Duszynski:
> +- MUSDK (Marvell User-Space SDK) sources available
> +  `here <https://github.com/MarvellEmbeddedProcessors/musdk-marvell/tree/musdk-armada-17.08>`__.
> +
> +    MUSDK is a light-weight library that provides direct access to Marvell's
> +    PPv2 (Packet Processor v2). Alternatively prebuilt MUSDK library can be
> +    requested from `Marvell Extranet <https://extranet.marvell.com>`_. Once
> +    approval has been granted, library can be found by typing ``musdk`` in
> +    the search box.
> +
> +    MUSDK must be configured with the following features:
> +
> +    .. code-block:: console
> +
> +       --enable-bpool-dma=64

It is really too short.
This is what I did:

export CROSS_COMPILE=<toolchain>/bin/aarch64-linux-gnu-
export CROSS_COMPILE=<toolchain>/bin/arm-linux-gnueabi-
export ARCH=arm64
./bootstrap
./configure --host=aarch64-linux-gnu --enable-bpool-dma=64
make install

But if fails at link step:

  CCLD     libmusdk.la
gcc-linaro-7.1.1-2017.08-x86_64_aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/7.1.1/../../../../aarch64-linux-gnu/bin/ld: lib/.libs/libmusdk_la-list.o: Relocations in generic ELF (EM: 62)
lib/.libs/libmusdk_la-list.o: error adding symbols: File in wrong format

Please help

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

* Re: [PATCH v4 00/16] add net mrvl pmd driver
  2017-10-09 20:59         ` [PATCH v4 00/16] add net mrvl pmd driver Ferruh Yigit
  2017-10-10  0:25           ` Ferruh Yigit
  2017-10-10  5:55           ` Tomasz Duszynski
@ 2017-10-12  1:51           ` Ferruh Yigit
  2017-10-12  2:37             ` [PATCH] doc: add build steps to mrvl NIC guide Thomas Monjalon
  2017-10-12  6:07             ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
  2 siblings, 2 replies; 110+ messages in thread
From: Ferruh Yigit @ 2017-10-12  1:51 UTC (permalink / raw)
  To: Tomasz Duszynski, dev; +Cc: mw, dima, nsamsono, Jianbo.liu

On 10/9/2017 9:59 PM, Ferruh Yigit wrote:
> On 10/9/2017 4:00 PM, Tomasz Duszynski wrote:
>> Hello,
>>
>> This patch series introduces the net driver for Marvell Armada 7k/8k
>> SoCs along with documentation.
>>
>> Below you can find the list of features which net pmd supports:
>> * Speed capabilities
>> * Link status
>> * MTU update
>> * Jumbo frame
>> * Promiscuous mode
>> * Allmulticast mode
>> * Unicast MAC filter
>> * Multicast MAC filter
>> * RSS hash
>> * VLAN filter
>> * CRC offload
>> * L3 checksum offload
>> * L4 checksum offload
>> * Packet type parsing
>> * Basic stats
>> * QoS
>>
>> Changes since v3:
>> * Split driver into skeleton, rx/tx, features, documentation parts
>> * Added speed capabilities flags.
>> * Added missing rx offload flags: VLAN/JUMBOFRAME
>> * Updated release notes.
>> * Updated documentation.
>>
>> Changes since v2:
>> * Removed LINE_SPACING, MULTILINE_DEREFERENCE and SPLIT_STRING
>>   checkpatch warnings.
>> * Removed unnecessary forward declarations.
>> * Fixed whitespace warnings.
>>
>> Changes since v1:
>> * Changed commit message to explain problem better.
>> * Removed bunch of checkpatch warnings about unnecessary parentheses.
>>
>> Tomasz Duszynski (4):
>>   app: link the whole rte_cfgfile library
>>   net/mrvl: add mrvl net pmd driver skeleton
>>   net/mrvl: add rx/tx support
>>   net/mrvl: add link update
>>   net/mrvl: add link speed capabilities
>>   net/mrvl: add support for updating mtu
>>   net/mrvl: add jumbo frame support
>>   net/mrvl: add support for promiscuous and allmulticast modes
>>   net/mrvl: add support for mac filtering
>>   net/mrvl: add rss hashing support
>>   net/mrvl: add support for vlan filtering
>>   net/mrvl: add crc, l3 and l4 offloads support
>>   net/mrvl: add packet type parsing support.
>>   net/mrvl: add basic stats support
>>   maintainers: add maintainers for the mrvl net pmd
>>   doc: add mrvl net pmd documentation
> 
> Series applied to dpdk-next-net/master, thanks.
> 
> (I can't compile because of missing musdk library, but since PMD is
> disabled by default this is not so bad, lets get this for rc1 and for
> crypto dependency, later I can have my environment set and test)

Did able to compile but I have questions :)

1- Used the "arm64-armv8a-linuxapp-gcc" config, can you please confirm.
Does it make sense to document this?

2- I used different toolchain than documented in musdk, which uses a
marvel one. Can you please confirm any aarch64-linux-gnu-gcc is OK?

3- Used following command:
CROSS=<toolchain>/aarch64-linux-gnu- make
EXTRA_CFLAGS="-I.../musdk-marvell/src/include
-L.../musdk-marvell/src/.libs/"

Do you also need to use EXTRA_CFLAGS? Otherwise I can't compile. If you
also use it please document it, if not please share with us how to do?

4- musk generated a static library, can you please confirm there is a
way to generate a shared musdk library as well?

5- Still not tested building kernel modules, and building musdk with
./configure options, I will do later.

Thanks,
ferruh

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

* Re: [PATCH v4 16/16] doc: add mrvl net pmd documentation
  2017-10-11 14:27           ` Thomas Monjalon
@ 2017-10-12  2:01             ` Thomas Monjalon
  0 siblings, 0 replies; 110+ messages in thread
From: Thomas Monjalon @ 2017-10-12  2:01 UTC (permalink / raw)
  To: Tomasz Duszynski; +Cc: dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

11/10/2017 16:27, Thomas Monjalon:
> 09/10/2017 17:00, Tomasz Duszynski:
> > +- MUSDK (Marvell User-Space SDK) sources available
> > +  `here <https://github.com/MarvellEmbeddedProcessors/musdk-marvell/tree/musdk-armada-17.08>`__.
> > +
> > +    MUSDK is a light-weight library that provides direct access to Marvell's
> > +    PPv2 (Packet Processor v2). Alternatively prebuilt MUSDK library can be
> > +    requested from `Marvell Extranet <https://extranet.marvell.com>`_. Once
> > +    approval has been granted, library can be found by typing ``musdk`` in
> > +    the search box.
> > +
> > +    MUSDK must be configured with the following features:
> > +
> > +    .. code-block:: console
> > +
> > +       --enable-bpool-dma=64
> 
> It is really too short.
> This is what I did:
> 
> export CROSS_COMPILE=<toolchain>/bin/aarch64-linux-gnu-
> export CROSS_COMPILE=<toolchain>/bin/arm-linux-gnueabi-
> export ARCH=arm64
> ./bootstrap
> ./configure --host=aarch64-linux-gnu --enable-bpool-dma=64
> make install
> 
> But if fails at link step:
> 
>   CCLD     libmusdk.la
> gcc-linaro-7.1.1-2017.08-x86_64_aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/7.1.1/../../../../aarch64-linux-gnu/bin/ld: lib/.libs/libmusdk_la-list.o: Relocations in generic ELF (EM: 62)
> lib/.libs/libmusdk_la-list.o: error adding symbols: File in wrong format
> 
> Please help

This failure was probably due to a previous wrong configuration.
After "make clean", it works.

When looking at your wiki, there are more options used:
https://github.com/MarvellEmbeddedProcessors/dpdk-marvell/wiki/Building-and-Running
   --enable-bpool-cookie=64 \
   --enable-bpool-dma=64 \
   --enable-dma-addr=64 \
   --enable-sam

Are they needed?

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

* [PATCH] doc: add build steps to mrvl NIC guide
  2017-10-12  1:51           ` Ferruh Yigit
@ 2017-10-12  2:37             ` Thomas Monjalon
  2017-10-12  6:28               ` Tomasz Duszynski
  2017-10-12  6:07             ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
  1 sibling, 1 reply; 110+ messages in thread
From: Thomas Monjalon @ 2017-10-12  2:37 UTC (permalink / raw)
  To: tdu; +Cc: ferruh.yigit, dev

Show how to compile MUSDK and enable compilation of the mrvl PMD.

The build test tool is also updated to support this new PMD.

Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
---
 devtools/test-build.sh   |  4 ++++
 doc/guides/nics/mrvl.rst | 15 +++++++++++++++
 2 files changed, 19 insertions(+)

diff --git a/devtools/test-build.sh b/devtools/test-build.sh
index c6dfaf0a8..4d7eaa499 100755
--- a/devtools/test-build.sh
+++ b/devtools/test-build.sh
@@ -47,6 +47,7 @@ default_path=$PATH
 # - DPDK_DEP_ZLIB (y/[n])
 # - DPDK_MAKE_JOBS (int)
 # - DPDK_NOTIFY (notify-send)
+# - LIBMUSDK_PATH
 # - LIBSSO_SNOW3G_PATH
 # - LIBSSO_KASUMI_PATH
 # - LIBSSO_ZUC_PATH
@@ -129,6 +130,7 @@ reset_env ()
 	unset DPDK_DEP_ZLIB
 	unset AESNI_MULTI_BUFFER_LIB_PATH
 	unset ARMV8_CRYPTO_LIB_PATH
+	unset LIBMUSDK_PATH
 	unset LIBSSO_SNOW3G_PATH
 	unset LIBSSO_KASUMI_PATH
 	unset LIBSSO_ZUC_PATH
@@ -169,6 +171,8 @@ config () # <directory> <target> <options>
 		sed -ri       's,(RESOURCE_TAR=)n,\1y,' $1/.config
 		test "$DPDK_DEP_MOFED" != y || \
 		sed -ri           's,(MLX._PMD=)n,\1y,' $1/.config
+		test -z "$LIBMUSDK_PATH" || \
+		sed -ri           's,(MRVL_PMD=)n,\1y,' $1/.config
 		test "$DPDK_DEP_SZE" != y || \
 		sed -ri       's,(PMD_SZEDATA2=)n,\1y,' $1/.config
 		test "$DPDK_DEP_ZLIB" != y || \
diff --git a/doc/guides/nics/mrvl.rst b/doc/guides/nics/mrvl.rst
index 462bc0e9d..df0032bda 100644
--- a/doc/guides/nics/mrvl.rst
+++ b/doc/guides/nics/mrvl.rst
@@ -221,9 +221,24 @@ Building DPDK
 Driver needs precompiled MUSDK library during compilation. Please consult
 ``doc/musdk_get_started.txt`` for the detailed build instructions.
 
+.. code-block:: console
+
+   export CROSS_COMPILE=<toolchain>/bin/aarch64-linux-gnu-
+   ./bootstrap
+   ./configure --enable-bpool-dma=64
+   make install
+
 Before the DPDK build process the environmental variable ``LIBMUSDK_PATH`` with
 the path to the MUSDK installation directory needs to be exported.
 
+.. code-block:: console
+
+   export LIBMUSDK_PATH=<musdk>/usr/local
+   export CROSS=aarch64-linux-gnu-
+   make config T=arm64-armv8a-linuxapp-gcc
+   sed -ri 's,(MRVL_PMD=)n,\1y,' build/.config
+   make
+
 
 Usage Example
 -------------
-- 
2.14.1

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

* Re: [PATCH v4 00/16] add net mrvl pmd driver
  2017-10-12  1:51           ` Ferruh Yigit
  2017-10-12  2:37             ` [PATCH] doc: add build steps to mrvl NIC guide Thomas Monjalon
@ 2017-10-12  6:07             ` Tomasz Duszynski
  1 sibling, 0 replies; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-12  6:07 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jianbo.liu

On Thu, Oct 12, 2017 at 02:51:19AM +0100, Ferruh Yigit wrote:
> On 10/9/2017 9:59 PM, Ferruh Yigit wrote:
> > On 10/9/2017 4:00 PM, Tomasz Duszynski wrote:
> >> Hello,
> >>
> >> This patch series introduces the net driver for Marvell Armada 7k/8k
> >> SoCs along with documentation.
> >>
> >> Below you can find the list of features which net pmd supports:
> >> * Speed capabilities
> >> * Link status
> >> * MTU update
> >> * Jumbo frame
> >> * Promiscuous mode
> >> * Allmulticast mode
> >> * Unicast MAC filter
> >> * Multicast MAC filter
> >> * RSS hash
> >> * VLAN filter
> >> * CRC offload
> >> * L3 checksum offload
> >> * L4 checksum offload
> >> * Packet type parsing
> >> * Basic stats
> >> * QoS
> >>
> >> Changes since v3:
> >> * Split driver into skeleton, rx/tx, features, documentation parts
> >> * Added speed capabilities flags.
> >> * Added missing rx offload flags: VLAN/JUMBOFRAME
> >> * Updated release notes.
> >> * Updated documentation.
> >>
> >> Changes since v2:
> >> * Removed LINE_SPACING, MULTILINE_DEREFERENCE and SPLIT_STRING
> >>   checkpatch warnings.
> >> * Removed unnecessary forward declarations.
> >> * Fixed whitespace warnings.
> >>
> >> Changes since v1:
> >> * Changed commit message to explain problem better.
> >> * Removed bunch of checkpatch warnings about unnecessary parentheses.
> >>
> >> Tomasz Duszynski (4):
> >>   app: link the whole rte_cfgfile library
> >>   net/mrvl: add mrvl net pmd driver skeleton
> >>   net/mrvl: add rx/tx support
> >>   net/mrvl: add link update
> >>   net/mrvl: add link speed capabilities
> >>   net/mrvl: add support for updating mtu
> >>   net/mrvl: add jumbo frame support
> >>   net/mrvl: add support for promiscuous and allmulticast modes
> >>   net/mrvl: add support for mac filtering
> >>   net/mrvl: add rss hashing support
> >>   net/mrvl: add support for vlan filtering
> >>   net/mrvl: add crc, l3 and l4 offloads support
> >>   net/mrvl: add packet type parsing support.
> >>   net/mrvl: add basic stats support
> >>   maintainers: add maintainers for the mrvl net pmd
> >>   doc: add mrvl net pmd documentation
> >
> > Series applied to dpdk-next-net/master, thanks.
> >
> > (I can't compile because of missing musdk library, but since PMD is
> > disabled by default this is not so bad, lets get this for rc1 and for
> > crypto dependency, later I can have my environment set and test)
>
> Did able to compile but I have questions :)
>
> 1- Used the "arm64-armv8a-linuxapp-gcc" config, can you please confirm.
> Does it make sense to document this?

Right, that makes sense.

>
> 2- I used different toolchain than documented in musdk, which uses a
> marvel one. Can you please confirm any aarch64-linux-gnu-gcc is OK?
>

I am not sure that every toolchain out there will work but those
available here
https://releases.linaro.org/components/toolchain/binaries/*/aarch64-linux-gnu/
should work fine.

> 3- Used following command:
> CROSS=<toolchain>/aarch64-linux-gnu- make
> EXTRA_CFLAGS="-I.../musdk-marvell/src/include
> -L.../musdk-marvell/src/.libs/"
>
> Do you also need to use EXTRA_CFLAGS? Otherwise I can't compile. If you
> also use it please document it, if not please share with us how to do?

As for MUSDK I build it as follows:

export CROSS_COMPILE=/home/tdu/workspace/gcc-linaro-5.4.1-2017.01-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-

# in case of the first build
./bootstrap

# later on that will do
make clean
./configure \
	--host=aarch64-linux-gnu \
	--prefix=$(pwd)/musdk-install-dir \
	--enable-sam \
	--enable-bpool-dma=64 \
	--disable-shared

make -j8
make install

As for building DPDK that works for me:

export RTE_KERNELDIR=/home/tdu/workspace/tmp2/linux-marvell
export LIBMUSDK_PATH=/home/tdu/workspace/tmp2/musdk-marvell/musdk-install-dir
export CROSS=/home/tdu/workspace/tmp2/gcc-linaro-5.4.1-2017.01-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-

make -j8

>
> 4- musk generated a static library, can you please confirm there is a
> way to generate a shared musdk library as well?
>

To generate shared just remove `--disable-shared` from ./configure
command line. Then you will have both *.so and *.a generated.

> 5- Still not tested building kernel modules, and building musdk with
> ./configure options, I will do later.

Let me know in case you have any sort of difficulties or something is
unclear.

>
> Thanks,
> ferruh

--
- Tomasz Duszyński

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

* Re: [PATCH] doc: add build steps to mrvl NIC guide
  2017-10-12  2:37             ` [PATCH] doc: add build steps to mrvl NIC guide Thomas Monjalon
@ 2017-10-12  6:28               ` Tomasz Duszynski
  2017-10-12  8:02                 ` Thomas Monjalon
  0 siblings, 1 reply; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-12  6:28 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: tdu, ferruh.yigit, dev

On Thu, Oct 12, 2017 at 04:37:45AM +0200, Thomas Monjalon wrote:
> Show how to compile MUSDK and enable compilation of the mrvl PMD.
>
> The build test tool is also updated to support this new PMD.
>
> Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
> ---
>  devtools/test-build.sh   |  4 ++++
>  doc/guides/nics/mrvl.rst | 15 +++++++++++++++
>  2 files changed, 19 insertions(+)
>
> diff --git a/devtools/test-build.sh b/devtools/test-build.sh
> index c6dfaf0a8..4d7eaa499 100755
> --- a/devtools/test-build.sh
> +++ b/devtools/test-build.sh
> @@ -47,6 +47,7 @@ default_path=$PATH
>  # - DPDK_DEP_ZLIB (y/[n])
>  # - DPDK_MAKE_JOBS (int)
>  # - DPDK_NOTIFY (notify-send)
> +# - LIBMUSDK_PATH
>  # - LIBSSO_SNOW3G_PATH
>  # - LIBSSO_KASUMI_PATH
>  # - LIBSSO_ZUC_PATH
> @@ -129,6 +130,7 @@ reset_env ()
>  	unset DPDK_DEP_ZLIB
>  	unset AESNI_MULTI_BUFFER_LIB_PATH
>  	unset ARMV8_CRYPTO_LIB_PATH
> +	unset LIBMUSDK_PATH
>  	unset LIBSSO_SNOW3G_PATH
>  	unset LIBSSO_KASUMI_PATH
>  	unset LIBSSO_ZUC_PATH
> @@ -169,6 +171,8 @@ config () # <directory> <target> <options>
>  		sed -ri       's,(RESOURCE_TAR=)n,\1y,' $1/.config
>  		test "$DPDK_DEP_MOFED" != y || \
>  		sed -ri           's,(MLX._PMD=)n,\1y,' $1/.config
> +		test -z "$LIBMUSDK_PATH" || \
> +		sed -ri           's,(MRVL_PMD=)n,\1y,' $1/.config

test-build.sh modifications come with crypto-mrvl patches. The only
difference is that PMD_MRVL_CRYPTO is enabled instead of MRVL_PMD. Thus
I don't think it will apply after applying crypto patches.

>  		test "$DPDK_DEP_SZE" != y || \
>  		sed -ri       's,(PMD_SZEDATA2=)n,\1y,' $1/.config
>  		test "$DPDK_DEP_ZLIB" != y || \
> diff --git a/doc/guides/nics/mrvl.rst b/doc/guides/nics/mrvl.rst
> index 462bc0e9d..df0032bda 100644
> --- a/doc/guides/nics/mrvl.rst
> +++ b/doc/guides/nics/mrvl.rst
> @@ -221,9 +221,24 @@ Building DPDK
>  Driver needs precompiled MUSDK library during compilation. Please consult
>  ``doc/musdk_get_started.txt`` for the detailed build instructions.
>
> +.. code-block:: console
> +
> +   export CROSS_COMPILE=<toolchain>/bin/aarch64-linux-gnu-
> +   ./bootstrap
> +   ./configure --enable-bpool-dma=64
> +   make install

I personally build MUSDK as follows:

export CROSS_COMPILE=/home/tdu/workspace/gcc-linaro-5.4.1-2017.01-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-

make clean
./configure \
	--prefix=$(pwd)/musdk-install-dir \
	--enable-bpool-dma=64 \
	--enable-sam \
	--disable-shared

make install

'--enable-sam' is of course optional if you're not going to use crypto
engine.

MUSDK ends up in musdk-install-dir then. Otherwise you'll need extra
permissions to install to /usr/local. Of course its up to you where
would you like to have it installed.

The reason I tend to add '--disable-shared' is that during build
DPDK will suck in static libraries and then later on I don't have to
install MUSDK library on the development board.

> +
>  Before the DPDK build process the environmental variable ``LIBMUSDK_PATH`` with
>  the path to the MUSDK installation directory needs to be exported.
>
> +.. code-block:: console
> +
> +   export LIBMUSDK_PATH=<musdk>/usr/local
> +   export CROSS=aarch64-linux-gnu-
> +   make config T=arm64-armv8a-linuxapp-gcc
> +   sed -ri 's,(MRVL_PMD=)n,\1y,' build/.config
> +   make
> +
>
>  Usage Example
>  -------------
> --
> 2.14.1
>

Anyway patch looks good. Thanks.
Acked-by: Tomasz Duszynski <tdu@semihalf.com>

--
- Tomasz Duszyński

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

* Re: [PATCH v4 02/16] net/mrvl: add mrvl net pmd driver skeleton
  2017-10-11 13:38           ` Thomas Monjalon
@ 2017-10-12  6:51             ` Tomasz Duszynski
  2017-10-12  7:59               ` Vincent JARDIN
  0 siblings, 1 reply; 110+ messages in thread
From: Tomasz Duszynski @ 2017-10-12  6:51 UTC (permalink / raw)
  To: Thomas Monjalon
  Cc: Tomasz Duszynski, dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

On Wed, Oct 11, 2017 at 03:38:36PM +0200, Thomas Monjalon wrote:
> Hi,
>
> 09/10/2017 17:00, Tomasz Duszynski:
> >  #
> > +# Compile Marvell PMD driver
> > +#
> > +CONFIG_RTE_LIBRTE_MRVL_PMD=n
> > +CONFIG_RTE_LIBRTE_MRVL_DEBUG=n
> > +CONFIG_RTE_MRVL_MUSDK_DMA_MEMSIZE=41943040
>
> We are trying to remove build-time configurations and behave like
> a true library.
>
> The DEBUG config options are now prohibited.
> Where is it used in your code?
> If it is used for logs, you should switch to the dynamic log config.
>
> What is MUSDK_DMA_MEMSIZE?
> If the value cannot change, it must be a constant in the code.
> If it can change, it should be a run-time driver option.

It's up to the user what MUSDK_DMA_MEMSIZE is going to be. Currently it's
set to value that should work it all cases.

Except that, MUSDK_DMA_MEMSIZE is used as synchronization point for net
and crypto (on condition they are used together i.e ipsec-secgw).

Suppose we have two different MUSDK_DMA_MEMSIZE defined for net/crypto then
dma memsize allocated will depend on driver probing sequence which might
confuse user.

If you have any better idea please share it with us. Thanks.

>
> Thank you and welcome

--
- Tomasz Duszyński

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

* Re: [PATCH v4 02/16] net/mrvl: add mrvl net pmd driver skeleton
  2017-10-12  6:51             ` Tomasz Duszynski
@ 2017-10-12  7:59               ` Vincent JARDIN
  2017-10-12 12:14                 ` Jacek Siuda
  0 siblings, 1 reply; 110+ messages in thread
From: Vincent JARDIN @ 2017-10-12  7:59 UTC (permalink / raw)
  To: Tomasz Duszynski, Thomas Monjalon
  Cc: dev, mw, dima, nsamsono, Jianbo.liu, Jacek Siuda

+1 with Thomas, see below,

Le 12/10/2017 à 08:51, Tomasz Duszynski a écrit :
>> What is MUSDK_DMA_MEMSIZE?
>> If the value cannot change, it must be a constant in the code.
>> If it can change, it should be a run-time driver option.
> It's up to the user what MUSDK_DMA_MEMSIZE is going to be. Currently it's
> set to value that should work it all cases.
> 
> Except that, MUSDK_DMA_MEMSIZE is used as synchronization point for net
> and crypto (on condition they are used together i.e ipsec-secgw).
> 
> Suppose we have two different MUSDK_DMA_MEMSIZE defined for net/crypto then
> dma memsize allocated will depend on driver probing sequence which might
> confuse user.
It does not make sense,
+	/*
+	 * ret == -EEXIST is correct, it means DMA
+	 * has been already initialized (by another PMD).
+	 */
+	ret = mv_sys_dma_mem_init(RTE_MRVL_MUSDK_DMA_MEMSIZE

int mv_sys_dma_mem_init(u64 size)
{
         struct sys_dma  *i_sys_dma;
         int err;

         if (sys_dma) {
                 pr_err("Dma object already exits.\n");
                 return -EEXIST;
         }

So, I do not understand why you cannot add some checks into the drivers 
to assert that users must have set the same value for both when calling:
   ret = mv_sys_dma_mem_init(my_best_size);
maybe, you need to fix and improve musdk first to avoid DPDK from 
getting such compilation issues.

best regards,
   Vincent

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

* Re: [PATCH] doc: add build steps to mrvl NIC guide
  2017-10-12  6:28               ` Tomasz Duszynski
@ 2017-10-12  8:02                 ` Thomas Monjalon
  0 siblings, 0 replies; 110+ messages in thread
From: Thomas Monjalon @ 2017-10-12  8:02 UTC (permalink / raw)
  To: Tomasz Duszynski; +Cc: ferruh.yigit, dev

12/10/2017 08:28, Tomasz Duszynski:
> On Thu, Oct 12, 2017 at 04:37:45AM +0200, Thomas Monjalon wrote:
> > Show how to compile MUSDK and enable compilation of the mrvl PMD.
> >
> > The build test tool is also updated to support this new PMD.
> >
> > Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
> > ---
> >  devtools/test-build.sh   |  4 ++++
> >  doc/guides/nics/mrvl.rst | 15 +++++++++++++++
> >  2 files changed, 19 insertions(+)
> >
> > diff --git a/devtools/test-build.sh b/devtools/test-build.sh
> > index c6dfaf0a8..4d7eaa499 100755
> > --- a/devtools/test-build.sh
> > +++ b/devtools/test-build.sh
> > @@ -47,6 +47,7 @@ default_path=$PATH
> >  # - DPDK_DEP_ZLIB (y/[n])
> >  # - DPDK_MAKE_JOBS (int)
> >  # - DPDK_NOTIFY (notify-send)
> > +# - LIBMUSDK_PATH
> >  # - LIBSSO_SNOW3G_PATH
> >  # - LIBSSO_KASUMI_PATH
> >  # - LIBSSO_ZUC_PATH
> > @@ -129,6 +130,7 @@ reset_env ()
> >  	unset DPDK_DEP_ZLIB
> >  	unset AESNI_MULTI_BUFFER_LIB_PATH
> >  	unset ARMV8_CRYPTO_LIB_PATH
> > +	unset LIBMUSDK_PATH
> >  	unset LIBSSO_SNOW3G_PATH
> >  	unset LIBSSO_KASUMI_PATH
> >  	unset LIBSSO_ZUC_PATH
> > @@ -169,6 +171,8 @@ config () # <directory> <target> <options>
> >  		sed -ri       's,(RESOURCE_TAR=)n,\1y,' $1/.config
> >  		test "$DPDK_DEP_MOFED" != y || \
> >  		sed -ri           's,(MLX._PMD=)n,\1y,' $1/.config
> > +		test -z "$LIBMUSDK_PATH" || \
> > +		sed -ri           's,(MRVL_PMD=)n,\1y,' $1/.config
> 
> test-build.sh modifications come with crypto-mrvl patches. The only
> difference is that PMD_MRVL_CRYPTO is enabled instead of MRVL_PMD. Thus
> I don't think it will apply after applying crypto patches.

OK I will adapt with crypto patches.

> > --- a/doc/guides/nics/mrvl.rst
> > +++ b/doc/guides/nics/mrvl.rst
> > @@ -221,9 +221,24 @@ Building DPDK
> >  Driver needs precompiled MUSDK library during compilation. Please consult
> >  ``doc/musdk_get_started.txt`` for the detailed build instructions.
> >
> > +.. code-block:: console
> > +
> > +   export CROSS_COMPILE=<toolchain>/bin/aarch64-linux-gnu-
> > +   ./bootstrap
> > +   ./configure --enable-bpool-dma=64
> > +   make install
> 
> I personally build MUSDK as follows:
> 
> export CROSS_COMPILE=/home/tdu/workspace/gcc-linaro-5.4.1-2017.01-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
> 
> make clean
> ./configure \
> 	--prefix=$(pwd)/musdk-install-dir \
> 	--enable-bpool-dma=64 \
> 	--enable-sam \
> 	--disable-shared
> 
> make install
> 
> '--enable-sam' is of course optional if you're not going to use crypto
> engine.
> 
> MUSDK ends up in musdk-install-dir then. Otherwise you'll need extra
> permissions to install to /usr/local. Of course its up to you where
> would you like to have it installed.

No, the default is to install in usr/local inside musdk directory.

> The reason I tend to add '--disable-shared' is that during build
> DPDK will suck in static libraries and then later on I don't have to
> install MUSDK library on the development board.
> 
> > +
> >  Before the DPDK build process the environmental variable ``LIBMUSDK_PATH`` with
> >  the path to the MUSDK installation directory needs to be exported.
> >
> > +.. code-block:: console
> > +
> > +   export LIBMUSDK_PATH=<musdk>/usr/local
> > +   export CROSS=aarch64-linux-gnu-
> > +   make config T=arm64-armv8a-linuxapp-gcc
> > +   sed -ri 's,(MRVL_PMD=)n,\1y,' build/.config
> > +   make
> > +
[...]
> 
> Anyway patch looks good. Thanks.
> Acked-by: Tomasz Duszynski <tdu@semihalf.com>
> 
> --
> - Tomasz Duszyński

Thanks

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

* Re: [PATCH v4 0/4] add crypto mrvl pmd driver
  2017-10-10 12:17     ` [PATCH v4 0/4] add crypto mrvl pmd driver Tomasz Duszynski
                         ` (3 preceding siblings ...)
  2017-10-10 12:17       ` [PATCH v4 4/4] test: add mrvl crypto pmd unit tests Tomasz Duszynski
@ 2017-10-12 12:11       ` De Lara Guarch, Pablo
  4 siblings, 0 replies; 110+ messages in thread
From: De Lara Guarch, Pablo @ 2017-10-12 12:11 UTC (permalink / raw)
  To: Tomasz Duszynski, dev; +Cc: mw, dima, nsamsono, Jianbo.liu



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Tomasz Duszynski
> Sent: Tuesday, October 10, 2017 1:17 PM
> To: dev@dpdk.org
> Cc: mw@semihalf.com; dima@marvell.com; nsamsono@marvell.com;
> Jianbo.liu@arm.org; Tomasz Duszynski <tdu@semihalf.com>
> Subject: [dpdk-dev] [PATCH v4 0/4] add crypto mrvl pmd driver
> 
> Hello,
> 
> This patch series introduces crypto driver for Marvell Armada 7k/8k SoCs
> along with documentation and crypto pmd driver tests.
> 
> Below you can find the list of features which crypto pmd supports:
> * Symmetric crypto
> * Sym operation chaining
> * AES CBC (128)
> * AES CBC (192)
> * AES CBC (256)
> * AES CTR (128)
> * AES CTR (192)
> * AES CTR (256)
> * 3DES CBC
> * 3DES CTR
> * MD5
> * MD5 HMAC
> * SHA1
> * SHA1 HMAC
> * SHA256
> * SHA256 HMAC
> * SHA384
> * SHA384 HMAC
> * SHA512
> * SHA512 HMAC
> * AES GCM (128)
> 
> Changes since v3:
> * Rebased on dpdk-next-crypto.
> * Allocated driver structure statically.
> * Fixed email addresses.
> * Updated documentation.
> 
> Changes since v2:
> * Added MRVL CRYPTO PMD to the test-build.sh.
> * Updated release notes.
> * Updated cryptoperf documentation.
> * Removed cryptodev_mrvl_pmd driver alias.
> * Fixed min,max key sizes used by HMACs in capabilities table.
> * Renamed map file.
> * Updated documentation.
> 
> Tomasz Duszynski (4):
>   crypto/mrvl: add mrvl crypto pmd driver
>   doc: add mrvl crypto pmd documentation
>   maintainers: add maintainers for the mrvl crypto pmd
>   test: add mrvl crypto pmd unit tests
> 
>  MAINTAINERS                                  |  10 +
>  config/common_base                           |   6 +
>  devtools/test-build.sh                       |   4 +
>  doc/guides/cryptodevs/features/mrvl.ini      |  42 ++
>  doc/guides/cryptodevs/index.rst              |   1 +
>  doc/guides/cryptodevs/mrvl.rst               | 205 +++++++
>  doc/guides/rel_notes/release_17_11.rst       |   5 +
>  doc/guides/tools/cryptoperf.rst              |   1 +
>  drivers/crypto/Makefile                      |   2 +
>  drivers/crypto/mrvl/Makefile                 |  63 ++
>  drivers/crypto/mrvl/rte_mrvl_compat.h        |  48 ++
>  drivers/crypto/mrvl/rte_mrvl_pmd.c           | 872
> +++++++++++++++++++++++++++
>  drivers/crypto/mrvl/rte_mrvl_pmd_ops.c       | 776
> ++++++++++++++++++++++++
>  drivers/crypto/mrvl/rte_mrvl_pmd_private.h   | 121 ++++
>  drivers/crypto/mrvl/rte_pmd_mrvl_version.map |   3 +
>  mk/rte.app.mk                                |   1 +
>  test/test/test_cryptodev.c                   | 168 ++++++
>  test/test/test_cryptodev.h                   |   1 +
>  test/test/test_cryptodev_aes_test_vectors.h  |  72 ++-
>  test/test/test_cryptodev_blockcipher.c       |   9 +-
>  test/test/test_cryptodev_blockcipher.h       |   1 +
>  test/test/test_cryptodev_des_test_vectors.h  |  24 +-
>  22 files changed, 2402 insertions(+), 33 deletions(-)  create mode 100644
> doc/guides/cryptodevs/features/mrvl.ini
>  create mode 100644 doc/guides/cryptodevs/mrvl.rst  create mode 100644
> drivers/crypto/mrvl/Makefile  create mode 100644
> drivers/crypto/mrvl/rte_mrvl_compat.h
>  create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd.c
>  create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_ops.c
>  create mode 100644 drivers/crypto/mrvl/rte_mrvl_pmd_private.h
>  create mode 100644 drivers/crypto/mrvl/rte_pmd_mrvl_version.map
> 
> --
> 2.7.4

Applied to dpdk-next-crypto, squashing patch 1 and 3.
Thanks,

Pablo

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

* Re: [PATCH v4 02/16] net/mrvl: add mrvl net pmd driver skeleton
  2017-10-12  7:59               ` Vincent JARDIN
@ 2017-10-12 12:14                 ` Jacek Siuda
  2017-10-12 13:57                   ` Vincent JARDIN
  0 siblings, 1 reply; 110+ messages in thread
From: Jacek Siuda @ 2017-10-12 12:14 UTC (permalink / raw)
  To: Vincent JARDIN
  Cc: Tomasz Duszynski, Thomas Monjalon, dev, Marcin Wojtas,
	Dmitri Epshtein, Natalie Samsonov, Jianbo.liu

Hi,

The problem is, that both drivers are totally separate entities, linked
into separate libs, but we need to use only one setting in both of them.
So, in order to provide any runtime (or even compile-time) verification, we
would need to create a third entity just to handle a simple assertion - a
bit overkill. At the time the code was written, common configuration option
seemed the most logical. If your long-term goal is to get rid of build-time
configurations, then it puts everything in a different perspective.

What we can do, is to add a run-time driver option and oblige user (in
documentation) to set the option only for the first mrvl vdev. If the
driver doesn't see the option set, it  won't initialize DMA. This, plus
meaningful error handling/logs should take care of any potential
mishandling by user that we were afraid of. I hope that would be more
acceptable.

Best Regards,
Jacek Siuda.




2017-10-12 9:59 GMT+02:00 Vincent JARDIN <vincent.jardin@6wind.com>:

> +1 with Thomas, see below,
>
> Le 12/10/2017 à 08:51, Tomasz Duszynski a écrit :
>
>> What is MUSDK_DMA_MEMSIZE?
>>> If the value cannot change, it must be a constant in the code.
>>> If it can change, it should be a run-time driver option.
>>>
>> It's up to the user what MUSDK_DMA_MEMSIZE is going to be. Currently it's
>> set to value that should work it all cases.
>>
>> Except that, MUSDK_DMA_MEMSIZE is used as synchronization point for net
>> and crypto (on condition they are used together i.e ipsec-secgw).
>>
>> Suppose we have two different MUSDK_DMA_MEMSIZE defined for net/crypto
>> then
>> dma memsize allocated will depend on driver probing sequence which might
>> confuse user.
>>
> It does not make sense,
> +       /*
> +        * ret == -EEXIST is correct, it means DMA
> +        * has been already initialized (by another PMD).
> +        */
> +       ret = mv_sys_dma_mem_init(RTE_MRVL_MUSDK_DMA_MEMSIZE
>
> int mv_sys_dma_mem_init(u64 size)
> {
>         struct sys_dma  *i_sys_dma;
>         int err;
>
>         if (sys_dma) {
>                 pr_err("Dma object already exits.\n");
>                 return -EEXIST;
>         }
>
> So, I do not understand why you cannot add some checks into the drivers to
> assert that users must have set the same value for both when calling:
>   ret = mv_sys_dma_mem_init(my_best_size);
> maybe, you need to fix and improve musdk first to avoid DPDK from getting
> such compilation issues.
>
> best regards,
>   Vincent
>

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

* Re: [PATCH v4 02/16] net/mrvl: add mrvl net pmd driver skeleton
  2017-10-12 12:14                 ` Jacek Siuda
@ 2017-10-12 13:57                   ` Vincent JARDIN
  0 siblings, 0 replies; 110+ messages in thread
From: Vincent JARDIN @ 2017-10-12 13:57 UTC (permalink / raw)
  To: Jacek Siuda
  Cc: Tomasz Duszynski, Thomas Monjalon, dev, Marcin Wojtas,
	Dmitri Epshtein, Natalie Samsonov, Jianbo.liu

Le 12/10/2017 à 14:14, Jacek Siuda a écrit :
> 
> What we can do, is to add a run-time driver option and oblige user (in 
> documentation) to set the option only for the first mrvl vdev. If the 
> driver doesn't see the option set, it  won't initialize DMA. This, plus 
> meaningful error handling/logs should take care of any potential 
> mishandling by user that we were afraid of. I hope that would be more 
> acceptable.

Yes, it does. And it already matches the current design in fact since 
the return error can be EEXIST and it is ignored.

thank you,
   Vincent

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

end of thread, other threads:[~2017-10-12 13:57 UTC | newest]

Thread overview: 110+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-26  9:39 [PATCH 0/8] add net/crypto mrvl pmd drivers Tomasz Duszynski
2017-09-26  9:39 ` [PATCH 1/8] app: link the whole rte_cfgfile library Tomasz Duszynski
2017-09-26 14:31   ` Bruce Richardson
2017-09-27  7:36     ` Tomasz Duszynski
2017-09-27 12:01       ` Bruce Richardson
2017-09-26  9:39 ` [PATCH 2/8] net/mrvl: add mrvl net pmd driver Tomasz Duszynski
2017-09-26  9:40 ` [PATCH 3/8] doc: add mrvl net pmd documentation Tomasz Duszynski
2017-09-26  9:40 ` [PATCH 4/8] maintainers: add maintainers for the mrvl net pmd Tomasz Duszynski
2017-09-26  9:40 ` [PATCH 5/8] crypto/mrvl: add mrvl crypto pmd driver Tomasz Duszynski
2017-09-26  9:40 ` [PATCH 6/8] doc: add mrvl crypto pmd documentation Tomasz Duszynski
2017-09-26  9:40 ` [PATCH 7/8] maintainers: add maintainers for the mrvl crypto pmd Tomasz Duszynski
2017-09-26  9:40 ` [PATCH 8/8] test: add mrvl crypto pmd unit tests Tomasz Duszynski
2017-09-27  9:40 ` [PATCH 0/8] add net/crypto mrvl pmd drivers De Lara Guarch, Pablo
2017-09-27 10:59   ` Tomasz Duszynski
2017-09-28 10:22 ` [PATCH v2 0/4] add net mrvl pmd driver Tomasz Duszynski
2017-09-28 10:22   ` [PATCH v2 1/4] app: link the whole rte_cfgfile library Tomasz Duszynski
2017-10-03 11:51     ` [PATCH v3 0/4] add net mrvl pmd driver Tomasz Duszynski
2017-10-03 11:51       ` [PATCH v3 1/4] app: link the whole rte_cfgfile library Tomasz Duszynski
2017-10-03 11:51       ` [PATCH v3 2/4] net/mrvl: add mrvl net pmd driver Tomasz Duszynski
2017-10-04  0:24         ` Ferruh Yigit
2017-10-04  8:59           ` Tomasz Duszynski
2017-10-04 16:59             ` Ferruh Yigit
2017-10-05  8:43               ` Tomasz Duszynski
2017-10-05 17:29                 ` Ferruh Yigit
2017-10-06  6:41                   ` Tomasz Duszynski
2017-10-10 21:25                 ` Thomas Monjalon
2017-10-04  0:28         ` Ferruh Yigit
2017-10-04 13:19           ` Tomasz Duszynski
2017-10-05 17:37             ` Ferruh Yigit
2017-10-03 11:51       ` [PATCH v3 3/4] doc: add mrvl net pmd documentation Tomasz Duszynski
2017-10-04  0:29         ` Ferruh Yigit
2017-10-04  7:53           ` Tomasz Duszynski
2017-10-03 11:51       ` [PATCH v3 4/4] maintainers: add maintainers for the mrvl net pmd Tomasz Duszynski
2017-10-09 15:00       ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
2017-10-09 15:00         ` [PATCH v4 01/16] app: link the whole rte_cfgfile library Tomasz Duszynski
2017-10-09 15:00         ` [PATCH v4 02/16] net/mrvl: add mrvl net pmd driver skeleton Tomasz Duszynski
2017-10-11 13:38           ` Thomas Monjalon
2017-10-12  6:51             ` Tomasz Duszynski
2017-10-12  7:59               ` Vincent JARDIN
2017-10-12 12:14                 ` Jacek Siuda
2017-10-12 13:57                   ` Vincent JARDIN
2017-10-09 15:00         ` [PATCH v4 03/16] net/mrvl: add rx/tx support Tomasz Duszynski
2017-10-09 15:00         ` [PATCH v4 04/16] net/mrvl: add link update Tomasz Duszynski
2017-10-09 15:00         ` [PATCH v4 05/16] net/mrvl: add link speed capabilities Tomasz Duszynski
2017-10-09 15:00         ` [PATCH v4 06/16] net/mrvl: add support for updating mtu Tomasz Duszynski
2017-10-09 15:00         ` [PATCH v4 07/16] net/mrvl: add jumbo frame support Tomasz Duszynski
2017-10-09 15:00         ` [PATCH v4 08/16] net/mrvl: add support for promiscuous and allmulticast modes Tomasz Duszynski
2017-10-09 15:00         ` [PATCH v4 09/16] net/mrvl: add support for mac filtering Tomasz Duszynski
2017-10-09 15:00         ` [PATCH v4 10/16] net/mrvl: add rss hashing support Tomasz Duszynski
2017-10-09 15:00         ` [PATCH v4 11/16] net/mrvl: add support for vlan filtering Tomasz Duszynski
2017-10-09 15:00         ` [PATCH v4 12/16] net/mrvl: add crc, l3 and l4 offloads support Tomasz Duszynski
2017-10-09 15:00         ` [PATCH v4 13/16] net/mrvl: add packet type parsing support Tomasz Duszynski
2017-10-09 15:00         ` [PATCH v4 14/16] net/mrvl: add basic stats support Tomasz Duszynski
2017-10-09 15:00         ` [PATCH v4 15/16] maintainers: add maintainers for the mrvl net pmd Tomasz Duszynski
2017-10-09 19:02           ` Ferruh Yigit
2017-10-09 19:09             ` Marcin Wojtas
2017-10-09 19:12               ` Ferruh Yigit
2017-10-10  5:47             ` Tomasz Duszynski
2017-10-10  3:20           ` Jianbo Liu
2017-10-10  4:38             ` Ferruh Yigit
2017-10-09 15:00         ` [PATCH v4 16/16] doc: add mrvl net pmd documentation Tomasz Duszynski
2017-10-09 20:54           ` Ferruh Yigit
2017-10-10  5:51             ` Tomasz Duszynski
2017-10-11 14:27           ` Thomas Monjalon
2017-10-12  2:01             ` Thomas Monjalon
2017-10-09 20:59         ` [PATCH v4 00/16] add net mrvl pmd driver Ferruh Yigit
2017-10-10  0:25           ` Ferruh Yigit
2017-10-10  7:07             ` Tomasz Duszynski
2017-10-10  5:55           ` Tomasz Duszynski
2017-10-12  1:51           ` Ferruh Yigit
2017-10-12  2:37             ` [PATCH] doc: add build steps to mrvl NIC guide Thomas Monjalon
2017-10-12  6:28               ` Tomasz Duszynski
2017-10-12  8:02                 ` Thomas Monjalon
2017-10-12  6:07             ` [PATCH v4 00/16] add net mrvl pmd driver Tomasz Duszynski
2017-09-28 10:22   ` [PATCH v2 2/4] net/mrvl: add mrvl net " Tomasz Duszynski
2017-09-29 15:38     ` Stephen Hemminger
2017-10-02 11:08       ` Bruce Richardson
2017-10-03  6:33         ` Tomasz Duszynski
2017-10-03  6:23       ` Tomasz Duszynski
2017-09-28 10:22   ` [PATCH v2 3/4] doc: add mrvl net pmd documentation Tomasz Duszynski
2017-09-28 10:22   ` [PATCH v2 4/4] maintainers: add maintainers for the mrvl net pmd Tomasz Duszynski
2017-09-28 11:06   ` [PATCH v2 0/4] add net mrvl pmd driver Ferruh Yigit
2017-09-28 11:40     ` Amit Tomer
2017-09-28 12:01       ` Marcin Wojtas
2017-09-28 10:23 ` [PATCH v2 0/4] add crypto " Tomasz Duszynski
2017-09-28 10:23   ` [PATCH v2 1/4] crypto/mrvl: add mrvl crypto " Tomasz Duszynski
2017-10-05 15:01     ` De Lara Guarch, Pablo
2017-10-06  7:24       ` Tomasz Duszynski
2017-10-05 15:47     ` Bruce Richardson
2017-10-06  7:05       ` Tomasz Duszynski
2017-09-28 10:23   ` [PATCH v2 2/4] doc: add mrvl crypto pmd documentation Tomasz Duszynski
2017-10-05 14:45     ` De Lara Guarch, Pablo
2017-10-06  8:06       ` Tomasz Duszynski
2017-09-28 10:23   ` [PATCH v2 3/4] maintainers: add maintainers for the mrvl crypto pmd Tomasz Duszynski
2017-09-28 10:23   ` [PATCH v2 4/4] test: add mrvl crypto pmd unit tests Tomasz Duszynski
2017-10-07 20:28   ` [PATCH v3 0/4] add crypto mrvl pmd driver Tomasz Duszynski
2017-10-07 20:28     ` [PATCH v3 1/4] crypto/mrvl: add mrvl crypto " Tomasz Duszynski
2017-10-10 10:16       ` De Lara Guarch, Pablo
2017-10-10 10:25         ` Tomasz Duszynski
2017-10-07 20:28     ` [PATCH v3 2/4] doc: add mrvl crypto pmd documentation Tomasz Duszynski
2017-10-07 20:28     ` [PATCH v3 3/4] maintainers: add maintainers for the mrvl crypto pmd Tomasz Duszynski
2017-10-07 20:28     ` [PATCH v3 4/4] test: add mrvl crypto pmd unit tests Tomasz Duszynski
2017-10-10 10:44       ` De Lara Guarch, Pablo
2017-10-10 10:57         ` Tomasz Duszynski
2017-10-10 12:17     ` [PATCH v4 0/4] add crypto mrvl pmd driver Tomasz Duszynski
2017-10-10 12:17       ` [PATCH v4 1/4] crypto/mrvl: add mrvl crypto " Tomasz Duszynski
2017-10-10 12:17       ` [PATCH v4 2/4] doc: add mrvl crypto pmd documentation Tomasz Duszynski
2017-10-10 12:17       ` [PATCH v4 3/4] maintainers: add maintainers for the mrvl crypto pmd Tomasz Duszynski
2017-10-10 12:17       ` [PATCH v4 4/4] test: add mrvl crypto pmd unit tests Tomasz Duszynski
2017-10-12 12:11       ` [PATCH v4 0/4] add crypto mrvl pmd driver De Lara Guarch, Pablo

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.