ENIC driver patches to address various issues

Also clear x-bit for old patch files 0013-xxx and 0014-xxx.

Change-Id: I217fdbfb32cef1ae575c668270d3baf593e688c6
Signed-off-by: John Lo <loj@cisco.com>
diff --git a/dpdk/dpdk-16.04_patches/0013-Revert-ixgbe-fix-packet-type-from-vector-Rx.patch b/dpdk/dpdk-16.04_patches/0013-Revert-ixgbe-fix-packet-type-from-vector-Rx.patch
old mode 100755
new mode 100644
diff --git a/dpdk/dpdk-16.04_patches/0014-enic-Set-PKT_RX_VLAN_PKT-iff-returned-packet-has-VLA.patch b/dpdk/dpdk-16.04_patches/0014-enic-Set-PKT_RX_VLAN_PKT-iff-returned-packet-has-VLA.patch
old mode 100755
new mode 100644
diff --git a/dpdk/dpdk-16.04_patches/0018-enic-fix-segfault-on-Tx-path-after-restarting-a-devi.patch b/dpdk/dpdk-16.04_patches/0018-enic-fix-segfault-on-Tx-path-after-restarting-a-devi.patch
new file mode 100644
index 0000000..10b6637
--- /dev/null
+++ b/dpdk/dpdk-16.04_patches/0018-enic-fix-segfault-on-Tx-path-after-restarting-a-devi.patch
@@ -0,0 +1,46 @@
+From 60971e62dcbb50a7ef1c3839e8b33b5aef6a48fe Mon Sep 17 00:00:00 2001
+From: John Daley <johndale@cisco.com>
+Date: Fri, 1 Jul 2016 12:24:45 -0700
+Subject: [PATCH 18/25] enic: fix segfault on Tx path after restarting a device
+
+If you stop then start a port that had already sent some packets,
+there was a segfault due to not resetting the number of completed
+sends to zero.
+
+Fixes: d5d882fe1a11 ("Tx path rewrite to reduce Host CPU overhead")
+
+Signed-off-by: Nelson Escobar <neescoba@cisco.com>
+Reviewed-by: John Daley <johndale@cisco.com>
+---
+ drivers/net/enic/base/vnic_wq.c | 2 ++
+ drivers/net/enic/base/vnic_wq.h | 1 +
+ 2 files changed, 3 insertions(+)
+
+diff --git a/drivers/net/enic/base/vnic_wq.c b/drivers/net/enic/base/vnic_wq.c
+index ccbbd61..7026bfe 100644
+--- a/drivers/net/enic/base/vnic_wq.c
++++ b/drivers/net/enic/base/vnic_wq.c
+@@ -206,6 +206,8 @@ void vnic_wq_clean(struct vnic_wq *wq,
+ 
+ 	wq->head_idx = 0;
+ 	wq->tail_idx = 0;
++	wq->last_completed_index = 0;
++	*((uint32_t *)wq->cqmsg_rz->addr) = 0;
+ 
+ 	iowrite32(0, &wq->ctrl->fetch_index);
+ 	iowrite32(0, &wq->ctrl->posted_index);
+diff --git a/drivers/net/enic/base/vnic_wq.h b/drivers/net/enic/base/vnic_wq.h
+index 37c3ff9..faf3bfa 100644
+--- a/drivers/net/enic/base/vnic_wq.h
++++ b/drivers/net/enic/base/vnic_wq.h
+@@ -38,6 +38,7 @@
+ 
+ #include "vnic_dev.h"
+ #include "vnic_cq.h"
++#include <rte_memzone.h>
+ 
+ /* Work queue control */
+ struct vnic_wq_ctrl {
+-- 
+2.7.0
+
diff --git a/dpdk/dpdk-16.04_patches/0019-enic-fix-Rx-queue-initialization-after-restarting-a-.patch b/dpdk/dpdk-16.04_patches/0019-enic-fix-Rx-queue-initialization-after-restarting-a-.patch
new file mode 100644
index 0000000..3e10748
--- /dev/null
+++ b/dpdk/dpdk-16.04_patches/0019-enic-fix-Rx-queue-initialization-after-restarting-a-.patch
@@ -0,0 +1,37 @@
+From 8d336ba9cbcb4832b992201497afe07afcd4f2e1 Mon Sep 17 00:00:00 2001
+From: John Daley <johndale@cisco.com>
+Date: Fri, 1 Jul 2016 12:32:45 -0700
+Subject: [PATCH 19/25] enic: fix Rx queue initialization after restarting a
+ device
+
+If you stop then start a port that had already received some packets,
+the NIC could fetch discriptors from the wrong location. This could
+effectivly reduce the size of the Rx queue by a random amount and
+cause packet drop or reduced performance.
+
+Reset the NIC fetch index to 0 when allocating and posting mbuf
+addresses to the NIC.
+
+Fixes: 947d860c821f ("enic: improve Rx performance")
+
+Signed-off-by: John Daley <johndale@cisco.com>
+Reviewed-by: Nelson Escobar <neescoba@cisco.com>
+---
+ drivers/net/enic/enic_main.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
+index be17707..68532d3 100644
+--- a/drivers/net/enic/enic_main.c
++++ b/drivers/net/enic/enic_main.c
+@@ -346,6 +346,7 @@ enic_alloc_rx_queue_mbufs(struct enic *enic, struct vnic_rq *rq)
+ 	dev_debug(enic, "port=%u, qidx=%u, Write %u posted idx, %u sw held\n",
+ 		enic->port_id, rq->index, rq->posted_index, rq->rx_nb_hold);
+ 	iowrite32(rq->posted_index, &rq->ctrl->posted_index);
++	iowrite32(0, &rq->ctrl->fetch_index);
+ 	rte_rmb();
+ 
+ //	printf("posted %d buffers to %s rq\n", rq->ring.desc_count,
+-- 
+2.7.0
+
diff --git a/dpdk/dpdk-16.04_patches/0020-net-enic-fix-releasing-mbufs-when-tearing-down-Rx-qu.patch b/dpdk/dpdk-16.04_patches/0020-net-enic-fix-releasing-mbufs-when-tearing-down-Rx-qu.patch
new file mode 100644
index 0000000..47bcda2
--- /dev/null
+++ b/dpdk/dpdk-16.04_patches/0020-net-enic-fix-releasing-mbufs-when-tearing-down-Rx-qu.patch
@@ -0,0 +1,43 @@
+From 3f276178609472585a85fe440b549013a64d9327 Mon Sep 17 00:00:00 2001
+From: Nelson Escobar <neescoba@cisco.com>
+Date: Tue, 14 Jun 2016 16:55:34 -0700
+Subject: [PATCH 20/25] net/enic: fix releasing mbufs when tearing down Rx
+ queue
+
+When trying to release the mbufs, the function was incorrectly
+iterating over the max size configured instead of the actual size
+of the ring.
+
+Fixes: 947d860c821f ("enic: improve Rx performance")
+
+Signed-off-by: Nelson Escobar <neescoba@cisco.com>
+Reviewed-by: John Daley <johndale@cisco.com>
+---
+ drivers/net/enic/enic_main.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
+index 68532d3..56ec96e 100644
+--- a/drivers/net/enic/enic_main.c
++++ b/drivers/net/enic/enic_main.c
+@@ -91,7 +91,7 @@ static int is_eth_addr_valid(uint8_t *addr)
+ }
+ 
+ static void
+-enic_rxmbuf_queue_release(struct enic *enic, struct vnic_rq *rq)
++enic_rxmbuf_queue_release(__rte_unused struct enic *enic, struct vnic_rq *rq)
+ {
+ 	uint16_t i;
+ 
+@@ -100,7 +100,7 @@ enic_rxmbuf_queue_release(struct enic *enic, struct vnic_rq *rq)
+ 		return;
+ 	}
+ 
+-	for (i = 0; i < enic->config.rq_desc_count; i++) {
++	for (i = 0; i < rq->ring.desc_count; i++) {
+ 		if (rq->mbuf_ring[i]) {
+ 			rte_pktmbuf_free_seg(rq->mbuf_ring[i]);
+ 			rq->mbuf_ring[i] = NULL;
+-- 
+2.7.0
+
diff --git a/dpdk/dpdk-16.04_patches/0021-net-enic-fix-crash-when-releasing-queues.patch b/dpdk/dpdk-16.04_patches/0021-net-enic-fix-crash-when-releasing-queues.patch
new file mode 100644
index 0000000..56d2c67
--- /dev/null
+++ b/dpdk/dpdk-16.04_patches/0021-net-enic-fix-crash-when-releasing-queues.patch
@@ -0,0 +1,61 @@
+From 38e154305ee5fd2ee454c19218ca144ffd1535f1 Mon Sep 17 00:00:00 2001
+From: John Daley <johndale@cisco.com>
+Date: Sat, 11 Jun 2016 10:27:04 -0700
+Subject: [PATCH 21/25] net/enic: fix crash when releasing queues
+
+If device configuration failed due to a lack of resources, such as
+if more queues are requested than are available, the queue release
+functions are called with NULL pointers which were being dereferenced.
+
+Skip releasing queues if they are NULL pointers.
+
+Fixes: fefed3d1e62c ("enic: new driver")
+
+Signed-off-by: John Daley <johndale@cisco.com>
+---
+ drivers/net/enic/enic_main.c | 21 ++++++++++++++++-----
+ 1 file changed, 16 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
+index 56ec96e..4e5594f 100644
+--- a/drivers/net/enic/enic_main.c
++++ b/drivers/net/enic/enic_main.c
+@@ -462,9 +462,15 @@ int enic_alloc_intr_resources(struct enic *enic)
+ 
+ void enic_free_rq(void *rxq)
+ {
+-	struct vnic_rq *rq_sop = (struct vnic_rq *)rxq;
+-	struct enic *enic = vnic_dev_priv(rq_sop->vdev);
+-	struct vnic_rq *rq_data = &enic->rq[rq_sop->data_queue_idx];
++	struct vnic_rq *rq_sop, *rq_data;
++	struct enic *enic;
++
++	if (rxq == NULL)
++		return;
++
++	rq_sop = (struct vnic_rq *)rxq;
++	enic = vnic_dev_priv(rq_sop->vdev);
++	rq_data = &enic->rq[rq_sop->data_queue_idx];
+ 
+ 	enic_rxmbuf_queue_release(enic, rq_sop);
+ 	if (rq_data->in_use)
+@@ -657,9 +663,14 @@ err_exit:
+ 
+ void enic_free_wq(void *txq)
+ {
+-	struct vnic_wq *wq = (struct vnic_wq *)txq;
+-	struct enic *enic = vnic_dev_priv(wq->vdev);
++	struct vnic_wq *wq;
++	struct enic *enic;
++
++	if (txq == NULL)
++		return;
+ 
++	wq = (struct vnic_wq *)txq;
++	enic = vnic_dev_priv(wq->vdev);
+ 	rte_memzone_free(wq->cqmsg_rz);
+ 	vnic_wq_free(wq);
+ 	vnic_cq_free(&enic->cq[enic->rq_count + wq->index]);
+-- 
+2.7.0
+
diff --git a/dpdk/dpdk-16.04_patches/0022-net-enic-improve-out-of-resources-error-handling.patch b/dpdk/dpdk-16.04_patches/0022-net-enic-improve-out-of-resources-error-handling.patch
new file mode 100644
index 0000000..bf6df81
--- /dev/null
+++ b/dpdk/dpdk-16.04_patches/0022-net-enic-improve-out-of-resources-error-handling.patch
@@ -0,0 +1,67 @@
+From db0a30a2e61a3bf2f6cb8e74203dab84280b0419 Mon Sep 17 00:00:00 2001
+From: John Daley <johndale@cisco.com>
+Date: Sat, 11 Jun 2016 10:27:05 -0700
+Subject: [PATCH 22/25] net/enic: improve out of resources error handling
+
+If configuration fails due to lack of resources, be more specific
+about which resources are lacking - work queues, read queues or
+completion queues. Return -EINVAL instead of -1 if more queeues
+are requested than are available.
+
+Fixes: fefed3d1e62c ("enic: new driver")
+
+Signed-off-by: John Daley <johndale@cisco.com>
+---
+ drivers/net/enic/enic_main.c | 30 ++++++++++++++++++++----------
+ 1 file changed, 20 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
+index 4e5594f..43e4af1 100644
+--- a/drivers/net/enic/enic_main.c
++++ b/drivers/net/enic/enic_main.c
+@@ -970,22 +970,32 @@ static void enic_dev_deinit(struct enic *enic)
+ int enic_set_vnic_res(struct enic *enic)
+ {
+ 	struct rte_eth_dev *eth_dev = enic->rte_dev;
++	int rc = 0;
+ 
+-	if ((enic->rq_count < eth_dev->data->nb_rx_queues) ||
+-		(enic->wq_count < eth_dev->data->nb_tx_queues)) {
+-		dev_err(dev, "Not enough resources configured, aborting\n");
+-		return -1;
++	if (enic->rq_count < eth_dev->data->nb_rx_queues) {
++		dev_err(dev, "Not enough Receive queues. Requested:%u, Configured:%u\n",
++			eth_dev->data->nb_rx_queues, enic->rq_count);
++		rc = -EINVAL;
++	}
++	if (enic->wq_count < eth_dev->data->nb_tx_queues) {
++		dev_err(dev, "Not enough Transmit queues. Requested:%u, Configured:%u\n",
++			eth_dev->data->nb_tx_queues, enic->wq_count);
++		rc = -EINVAL;
+ 	}
+ 
+-	enic->rq_count = eth_dev->data->nb_rx_queues;
+-	enic->wq_count = eth_dev->data->nb_tx_queues;
+ 	if (enic->cq_count < (enic->rq_count + enic->wq_count)) {
+-		dev_err(dev, "Not enough resources configured, aborting\n");
+-		return -1;
++		dev_err(dev, "Not enough Completion queues. Required:%u, Configured:%u\n",
++			enic->rq_count + enic->wq_count, enic->cq_count);
++		rc = -EINVAL;
+ 	}
+ 
+-	enic->cq_count = enic->rq_count + enic->wq_count;
+-	return 0;
++	if (rc == 0) {
++		enic->rq_count = eth_dev->data->nb_rx_queues;
++		enic->wq_count = eth_dev->data->nb_tx_queues;
++		enic->cq_count = enic->rq_count + enic->wq_count;
++	}
++
++	return rc;
+ }
+ 
+ static int enic_dev_init(struct enic *enic)
+-- 
+2.7.0
+
diff --git a/dpdk/dpdk-16.04_patches/0023-net-enic-fix-memory-freeing.patch b/dpdk/dpdk-16.04_patches/0023-net-enic-fix-memory-freeing.patch
new file mode 100644
index 0000000..0cc423a
--- /dev/null
+++ b/dpdk/dpdk-16.04_patches/0023-net-enic-fix-memory-freeing.patch
@@ -0,0 +1,238 @@
+From 2040a8f4e47d3bc4b7f0f11faa863a4bd8d8891d Mon Sep 17 00:00:00 2001
+From: Nelson Escobar <neescoba@cisco.com>
+Date: Thu, 23 Jun 2016 16:14:58 -0700
+Subject: [PATCH 23/25] net/enic: fix memory freeing
+
+enic_alloc_consistent() allocated memory, but enic_free_consistent()
+was an empty function, so allocated memory was never freed.
+
+This commit adds a list and lock to the enic structure to keep track
+of the memzones allocated in enic_alloc_consistent(), and
+enic_free_consistent() uses that information to properly free memory.
+
+Fixes: fefed3d1e62c ("enic: new driver")
+
+Signed-off-by: Nelson Escobar <neescoba@cisco.com>
+Reviewed-by: John Daley <johndale@cisco.com>
+---
+ drivers/net/enic/base/vnic_dev.c | 14 +++++------
+ drivers/net/enic/base/vnic_dev.h |  2 +-
+ drivers/net/enic/enic.h          | 11 ++++++++
+ drivers/net/enic/enic_main.c     | 54 ++++++++++++++++++++++++++++++++++------
+ 4 files changed, 65 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/net/enic/base/vnic_dev.c b/drivers/net/enic/base/vnic_dev.c
+index e8a5028..fc2e4cc 100644
+--- a/drivers/net/enic/base/vnic_dev.c
++++ b/drivers/net/enic/base/vnic_dev.c
+@@ -83,7 +83,7 @@ struct vnic_dev {
+ 	struct vnic_intr_coal_timer_info intr_coal_timer_info;
+ 	void *(*alloc_consistent)(void *priv, size_t size,
+ 		dma_addr_t *dma_handle, u8 *name);
+-	void (*free_consistent)(struct rte_pci_device *hwdev,
++	void (*free_consistent)(void *priv,
+ 		size_t size, void *vaddr,
+ 		dma_addr_t dma_handle);
+ };
+@@ -101,7 +101,7 @@ void *vnic_dev_priv(struct vnic_dev *vdev)
+ void vnic_register_cbacks(struct vnic_dev *vdev,
+ 	void *(*alloc_consistent)(void *priv, size_t size,
+ 	    dma_addr_t *dma_handle, u8 *name),
+-	void (*free_consistent)(struct rte_pci_device *hwdev,
++	void (*free_consistent)(void *priv,
+ 	    size_t size, void *vaddr,
+ 	    dma_addr_t dma_handle))
+ {
+@@ -807,7 +807,7 @@ int vnic_dev_notify_unsetcmd(struct vnic_dev *vdev)
+ int vnic_dev_notify_unset(struct vnic_dev *vdev)
+ {
+ 	if (vdev->notify && !vnic_dev_in_reset(vdev)) {
+-		vdev->free_consistent(vdev->pdev,
++		vdev->free_consistent(vdev->priv,
+ 			sizeof(struct vnic_devcmd_notify),
+ 			vdev->notify,
+ 			vdev->notify_pa);
+@@ -924,16 +924,16 @@ void vnic_dev_unregister(struct vnic_dev *vdev)
+ {
+ 	if (vdev) {
+ 		if (vdev->notify)
+-			vdev->free_consistent(vdev->pdev,
++			vdev->free_consistent(vdev->priv,
+ 				sizeof(struct vnic_devcmd_notify),
+ 				vdev->notify,
+ 				vdev->notify_pa);
+ 		if (vdev->stats)
+-			vdev->free_consistent(vdev->pdev,
++			vdev->free_consistent(vdev->priv,
+ 				sizeof(struct vnic_stats),
+ 				vdev->stats, vdev->stats_pa);
+ 		if (vdev->fw_info)
+-			vdev->free_consistent(vdev->pdev,
++			vdev->free_consistent(vdev->priv,
+ 				sizeof(struct vnic_devcmd_fw_info),
+ 				vdev->fw_info, vdev->fw_info_pa);
+ 		kfree(vdev);
+@@ -1041,7 +1041,7 @@ int vnic_dev_classifier(struct vnic_dev *vdev, u8 cmd, u16 *entry,
+ 
+ 		ret = vnic_dev_cmd(vdev, CMD_ADD_FILTER, &a0, &a1, wait);
+ 		*entry = (u16)a0;
+-		vdev->free_consistent(vdev->pdev, tlv_size, tlv_va, tlv_pa);
++		vdev->free_consistent(vdev->priv, tlv_size, tlv_va, tlv_pa);
+ 	} else if (cmd == CLSF_DEL) {
+ 		a0 = *entry;
+ 		ret = vnic_dev_cmd(vdev, CMD_DEL_FILTER, &a0, &a1, wait);
+diff --git a/drivers/net/enic/base/vnic_dev.h b/drivers/net/enic/base/vnic_dev.h
+index 113d6ac..689442f 100644
+--- a/drivers/net/enic/base/vnic_dev.h
++++ b/drivers/net/enic/base/vnic_dev.h
+@@ -102,7 +102,7 @@ unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev,
+ void vnic_register_cbacks(struct vnic_dev *vdev,
+ 	void *(*alloc_consistent)(void *priv, size_t size,
+ 		dma_addr_t *dma_handle, u8 *name),
+-	void (*free_consistent)(struct rte_pci_device *hwdev,
++	void (*free_consistent)(void *priv,
+ 		size_t size, void *vaddr,
+ 		dma_addr_t dma_handle));
+ void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type,
+diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
+index d2de6ee..175adb8 100644
+--- a/drivers/net/enic/enic.h
++++ b/drivers/net/enic/enic.h
+@@ -46,6 +46,8 @@
+ #include "vnic_rss.h"
+ #include "enic_res.h"
+ #include "cq_enet_desc.h"
++#include <sys/queue.h>
++#include <rte_spinlock.h>
+ 
+ #define DRV_NAME		"enic_pmd"
+ #define DRV_DESCRIPTION		"Cisco VIC Ethernet NIC Poll-mode Driver"
+@@ -96,6 +98,11 @@ struct enic_soft_stats {
+ 	rte_atomic64_t rx_packet_errors;
+ };
+ 
++struct enic_memzone_entry {
++	const struct rte_memzone *rz;
++	LIST_ENTRY(enic_memzone_entry) entries;
++};
++
+ /* Per-instance private data structure */
+ struct enic {
+ 	struct enic *next;
+@@ -140,6 +147,10 @@ struct enic {
+ 	unsigned int intr_count;
+ 
+ 	struct enic_soft_stats soft_stats;
++
++	/* linked list storing memory allocations */
++	LIST_HEAD(enic_memzone_list, enic_memzone_entry) memzone_list;
++	rte_spinlock_t memzone_list_lock;
+ };
+ 
+ static inline unsigned int enic_sop_rq(__rte_unused struct enic *enic, unsigned int rq)
+diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
+index 43e4af1..0547f3b 100644
+--- a/drivers/net/enic/enic_main.c
++++ b/drivers/net/enic/enic_main.c
+@@ -356,12 +356,14 @@ enic_alloc_rx_queue_mbufs(struct enic *enic, struct vnic_rq *rq)
+ }
+ 
+ static void *
+-enic_alloc_consistent(__rte_unused void *priv, size_t size,
++enic_alloc_consistent(void *priv, size_t size,
+ 	dma_addr_t *dma_handle, u8 *name)
+ {
+ 	void *vaddr;
+ 	const struct rte_memzone *rz;
+ 	*dma_handle = 0;
++	struct enic *enic = (struct enic *)priv;
++	struct enic_memzone_entry *mze;
+ 
+ 	rz = rte_memzone_reserve_aligned((const char *)name,
+ 					 size, SOCKET_ID_ANY, 0, ENIC_ALIGN);
+@@ -374,16 +376,49 @@ enic_alloc_consistent(__rte_unused void *priv, size_t size,
+ 	vaddr = rz->addr;
+ 	*dma_handle = (dma_addr_t)rz->phys_addr;
+ 
++	mze = rte_malloc("enic memzone entry",
++			 sizeof(struct enic_memzone_entry), 0);
++
++	if (!mze) {
++		pr_err("%s : Failed to allocate memory for memzone list\n",
++		       __func__);
++		rte_memzone_free(rz);
++	}
++
++	mze->rz = rz;
++
++	rte_spinlock_lock(&enic->memzone_list_lock);
++	LIST_INSERT_HEAD(&enic->memzone_list, mze, entries);
++	rte_spinlock_unlock(&enic->memzone_list_lock);
++
+ 	return vaddr;
+ }
+ 
+ static void
+-enic_free_consistent(__rte_unused struct rte_pci_device *hwdev,
+-	__rte_unused size_t size,
+-	__rte_unused void *vaddr,
+-	__rte_unused dma_addr_t dma_handle)
++enic_free_consistent(void *priv,
++		     __rte_unused size_t size,
++		     void *vaddr,
++		     dma_addr_t dma_handle)
+ {
+-	/* Nothing to be done */
++	struct enic_memzone_entry *mze;
++	struct enic *enic = (struct enic *)priv;
++
++	rte_spinlock_lock(&enic->memzone_list_lock);
++	LIST_FOREACH(mze, &enic->memzone_list, entries) {
++		if (mze->rz->addr == vaddr &&
++		    mze->rz->phys_addr == dma_handle)
++			break;
++	}
++	if (mze == NULL) {
++		rte_spinlock_unlock(&enic->memzone_list_lock);
++		dev_warning(enic,
++			    "Tried to free memory, but couldn't find it in the memzone list\n");
++		return;
++	}
++	LIST_REMOVE(mze, entries);
++	rte_spinlock_unlock(&enic->memzone_list_lock);
++	rte_memzone_free(mze->rz);
++	rte_free(mze);
+ }
+ 
+ static void
+@@ -840,7 +875,7 @@ static int enic_set_rsskey(struct enic *enic)
+ 		rss_key_buf_pa,
+ 		sizeof(union vnic_rss_key));
+ 
+-	enic_free_consistent(enic->pdev, sizeof(union vnic_rss_key),
++	enic_free_consistent(enic, sizeof(union vnic_rss_key),
+ 		rss_key_buf_va, rss_key_buf_pa);
+ 
+ 	return err;
+@@ -867,7 +902,7 @@ static int enic_set_rsscpu(struct enic *enic, u8 rss_hash_bits)
+ 		rss_cpu_buf_pa,
+ 		sizeof(union vnic_rss_cpu));
+ 
+-	enic_free_consistent(enic->pdev, sizeof(union vnic_rss_cpu),
++	enic_free_consistent(enic, sizeof(union vnic_rss_cpu),
+ 		rss_cpu_buf_va, rss_cpu_buf_pa);
+ 
+ 	return err;
+@@ -1049,6 +1084,9 @@ int enic_probe(struct enic *enic)
+ 		goto err_out;
+ 	}
+ 
++	LIST_INIT(&enic->memzone_list);
++	rte_spinlock_init(&enic->memzone_list_lock);
++
+ 	vnic_register_cbacks(enic->vdev,
+ 		enic_alloc_consistent,
+ 		enic_free_consistent);
+-- 
+2.7.0
+
diff --git a/dpdk/dpdk-16.04_patches/0024-net-enic-fix-Rx-scatter-with-multiple-queues.patch b/dpdk/dpdk-16.04_patches/0024-net-enic-fix-Rx-scatter-with-multiple-queues.patch
new file mode 100644
index 0000000..d581702
--- /dev/null
+++ b/dpdk/dpdk-16.04_patches/0024-net-enic-fix-Rx-scatter-with-multiple-queues.patch
@@ -0,0 +1,80 @@
+From 658069b0c5994e260cd7d0a7dfc7f03d78dd4f5a Mon Sep 17 00:00:00 2001
+From: Nelson Escobar <neescoba@cisco.com>
+Date: Tue, 28 Jun 2016 11:49:11 -0700
+Subject: [PATCH 24/25] net/enic: fix Rx scatter with multiple queues
+
+The Rx scatter patch failed to make a few changes and resulted in
+problems when using multiple receive queues (RQs) in DPDK (ie RSS)
+since the wrong adapter resources were being used.
+
+- get and use the correct completion queue index associated with a
+  receive queue.
+- set the correct receive queue index when using RSS
+
+Fixes: 856d7ba7ed22 ("net/enic: support scattered Rx")
+
+Signed-off-by: Nelson Escobar <neescoba@cisco.com>
+Reviewed-by: John Daley <johndale@cisco.com>
+---
+ drivers/net/enic/enic.h      |  6 +++++-
+ drivers/net/enic/enic_main.c | 10 ++++++----
+ 2 files changed, 11 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
+index 175adb8..8b0fa05 100644
+--- a/drivers/net/enic/enic.h
++++ b/drivers/net/enic/enic.h
+@@ -165,7 +165,11 @@ static inline unsigned int enic_data_rq(__rte_unused struct enic *enic, unsigned
+ 
+ static inline unsigned int enic_cq_rq(__rte_unused struct enic *enic, unsigned int rq)
+ {
+-	return rq;
++	/* Scatter rx uses two receive queues together with one
++	 * completion queue, so the completion queue number is no
++	 * longer the same as the rq number.
++	 */
++	return rq / 2;
+ }
+ 
+ static inline unsigned int enic_cq_wq(struct enic *enic, unsigned int wq)
+diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
+index 0547f3b..976c9da 100644
+--- a/drivers/net/enic/enic_main.c
++++ b/drivers/net/enic/enic_main.c
+@@ -252,19 +252,20 @@ void enic_init_vnic_resources(struct enic *enic)
+ 	vnic_dev_stats_clear(enic->vdev);
+ 
+ 	for (index = 0; index < enic->rq_count; index++) {
++		cq_idx = enic_cq_rq(enic, enic_sop_rq(enic, index));
++
+ 		vnic_rq_init(&enic->rq[enic_sop_rq(enic, index)],
+-			enic_cq_rq(enic, index),
++			cq_idx,
+ 			error_interrupt_enable,
+ 			error_interrupt_offset);
+ 
+ 		data_rq = &enic->rq[enic_data_rq(enic, index)];
+ 		if (data_rq->in_use) 
+ 			vnic_rq_init(data_rq,
+-				     enic_cq_rq(enic, index),
++				     cq_idx,
+ 				     error_interrupt_enable,
+ 				     error_interrupt_offset);
+ 
+-		cq_idx = enic_cq_rq(enic, index);
+ 		vnic_cq_init(&enic->cq[cq_idx],
+ 			0 /* flow_control_enable */,
+ 			1 /* color_enable */,
+@@ -896,7 +897,8 @@ static int enic_set_rsscpu(struct enic *enic, u8 rss_hash_bits)
+ 		return -ENOMEM;
+ 
+ 	for (i = 0; i < (1 << rss_hash_bits); i++)
+-		(*rss_cpu_buf_va).cpu[i/4].b[i%4] = i % enic->rq_count;
++		(*rss_cpu_buf_va).cpu[i / 4].b[i % 4] =
++			enic_sop_rq(enic, i % enic->rq_count);
+ 
+ 	err = enic_set_rss_cpu(enic,
+ 		rss_cpu_buf_pa,
+-- 
+2.7.0
+
diff --git a/dpdk/dpdk-16.04_patches/0025-enic-fixup-of-Rx-Scatter-patch.patch b/dpdk/dpdk-16.04_patches/0025-enic-fixup-of-Rx-Scatter-patch.patch
new file mode 100644
index 0000000..e4e9f43
--- /dev/null
+++ b/dpdk/dpdk-16.04_patches/0025-enic-fixup-of-Rx-Scatter-patch.patch
@@ -0,0 +1,169 @@
+From 3131adb7f4195771bf54b294b2ee496055c3e65d Mon Sep 17 00:00:00 2001
+From: Nelson Escobar <neescoba@cisco.com>
+Date: Tue, 14 Jun 2016 11:54:01 -0700
+Subject: [PATCH 25/25] enic: fixup of Rx Scatter patch
+
+A version of the Rx Scatter patch was used by VPP before the
+patch was accepted in dpdk.org. This patch contains the change
+made to the patch before it was accepted.
+
+Composed of internal dpdk devel patches:
+enic: fixup rq count usage in wake of rx scatter
+enic: update checks since RX scatter uses 2 VIC RQs per app RQ.
+enic: fix packet type and flags when doing scatter Rx
+
+fixes: ENIC scatter RX
+
+Signed-off-by: Nelson Escobar <neescoba@cisco.com>
+---
+ drivers/net/enic/enic.h        | 12 ++++++++++--
+ drivers/net/enic/enic_ethdev.c |  7 +++++--
+ drivers/net/enic/enic_main.c   | 19 +++++++++++--------
+ drivers/net/enic/enic_res.c    |  5 +++--
+ drivers/net/enic/enic_rxtx.c   |  7 +++++--
+ 5 files changed, 34 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
+index 8b0fa05..9cc9f0b 100644
+--- a/drivers/net/enic/enic.h
++++ b/drivers/net/enic/enic.h
+@@ -55,8 +55,11 @@
+ #define DRV_COPYRIGHT		"Copyright 2008-2015 Cisco Systems, Inc"
+ 
+ #define ENIC_WQ_MAX		8
+-#define ENIC_RQ_MAX		8
+-#define ENIC_CQ_MAX		(ENIC_WQ_MAX + ENIC_RQ_MAX)
++/* With Rx scatter support, we use two RQs on VIC per RQ used by app. Both
++ * RQs use the same CQ.
++ */
++#define ENIC_RQ_MAX		16
++#define ENIC_CQ_MAX		(ENIC_WQ_MAX + (ENIC_RQ_MAX / 2))
+ #define ENIC_INTR_MAX		(ENIC_CQ_MAX + 2)
+ 
+ #define VLAN_ETH_HLEN           18
+@@ -163,6 +166,11 @@ static inline unsigned int enic_data_rq(__rte_unused struct enic *enic, unsigned
+ 	return rq * 2 + 1;
+ }
+ 
++static inline unsigned int enic_vnic_rq_count(struct enic *enic)
++{
++	return (enic->rq_count * 2);
++}
++
+ static inline unsigned int enic_cq_rq(__rte_unused struct enic *enic, unsigned int rq)
+ {
+ 	/* Scatter rx uses two receive queues together with one
+diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
+index 697ff82..e5b84e1 100644
+--- a/drivers/net/enic/enic_ethdev.c
++++ b/drivers/net/enic/enic_ethdev.c
+@@ -269,9 +269,12 @@ static int enicpmd_dev_rx_queue_setup(struct rte_eth_dev *eth_dev,
+ 	struct enic *enic = pmd_priv(eth_dev);
+ 
+ 	ENICPMD_FUNC_TRACE();
+-	if (queue_idx >= ENIC_RQ_MAX) {
++	/* With Rx scatter support, two RQs are now used on VIC per RQ used
++	 * by the application.
++	 */
++	if (queue_idx * 2 >= ENIC_RQ_MAX) {
+ 		dev_err(enic,
+-			"Max number of RX queues exceeded.  Max is %d\n",
++			"Max number of RX queues exceeded.  Max is %d. This PMD uses 2 RQs on VIC per RQ used by DPDK.\n",
+ 			ENIC_RQ_MAX);
+ 		return -EINVAL;
+ 	}
+diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
+index 976c9da..ff94ee2 100644
+--- a/drivers/net/enic/enic_main.c
++++ b/drivers/net/enic/enic_main.c
+@@ -133,7 +133,7 @@ static void enic_log_q_error(struct enic *enic)
+ 				error_status);
+ 	}
+ 
+-	for (i = 0; i < enic->rq_count; i++) {
++	for (i = 0; i < enic_vnic_rq_count(enic); i++) {
+ 		error_status = vnic_rq_error_status(&enic->rq[i]);
+ 		if (error_status)
+ 			dev_err(enic, "RQ[%d] error_status %d\n", i,
+@@ -486,7 +486,7 @@ int enic_alloc_intr_resources(struct enic *enic)
+ 
+ 	dev_info(enic, "vNIC resources used:  "\
+ 		"wq %d rq %d cq %d intr %d\n",
+-		enic->wq_count, enic->rq_count,
++		enic->wq_count, enic_vnic_rq_count(enic),
+ 		enic->cq_count, enic->intr_count);
+ 
+ 	err = vnic_intr_alloc(enic->vdev, &enic->intr, 0);
+@@ -790,10 +790,12 @@ int enic_disable(struct enic *enic)
+ 		if (err)
+ 			return err;
+ 	}
+-	for (i = 0; i < enic->rq_count; i++) {
+-		err = vnic_rq_disable(&enic->rq[i]);
+-		if (err)
+-			return err;
++	for (i = 0; i < enic_vnic_rq_count(enic); i++) {
++		if (enic->rq[i].in_use) {
++			err = vnic_rq_disable(&enic->rq[i]);
++			if (err)
++				return err;
++		}
+ 	}
+ 
+ 	vnic_dev_set_reset_flag(enic->vdev, 1);
+@@ -802,8 +804,9 @@ int enic_disable(struct enic *enic)
+ 	for (i = 0; i < enic->wq_count; i++)
+ 		vnic_wq_clean(&enic->wq[i], enic_free_wq_buf);
+ 
+-	for (i = 0; i < enic->rq_count; i++)
+-		vnic_rq_clean(&enic->rq[i], enic_free_rq_buf);
++	for (i = 0; i < enic_vnic_rq_count(enic); i++)
++		if (enic->rq[i].in_use)
++			vnic_rq_clean(&enic->rq[i], enic_free_rq_buf);
+ 	for (i = 0; i < enic->cq_count; i++)
+ 		vnic_cq_clean(&enic->cq[i]);
+ 	vnic_intr_clean(&enic->intr);
+diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c
+index ebe379d..42edd84 100644
+--- a/drivers/net/enic/enic_res.c
++++ b/drivers/net/enic/enic_res.c
+@@ -196,8 +196,9 @@ void enic_free_vnic_resources(struct enic *enic)
+ 
+ 	for (i = 0; i < enic->wq_count; i++)
+ 		vnic_wq_free(&enic->wq[i]);
+-	for (i = 0; i < enic->rq_count; i++)
+-		vnic_rq_free(&enic->rq[i]);
++	for (i = 0; i < enic_vnic_rq_count(enic); i++)
++		if (enic->rq[i].in_use)
++			vnic_rq_free(&enic->rq[i]);
+ 	for (i = 0; i < enic->cq_count; i++)
+ 		vnic_cq_free(&enic->cq[i]);
+ 	vnic_intr_free(&enic->intr);
+diff --git a/drivers/net/enic/enic_rxtx.c b/drivers/net/enic/enic_rxtx.c
+index 463b954..c68bbfb 100644
+--- a/drivers/net/enic/enic_rxtx.c
++++ b/drivers/net/enic/enic_rxtx.c
+@@ -326,8 +326,7 @@ enic_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
+ 
+ 		/* Fill in the rest of the mbuf */
+ 		seg_length = enic_cq_rx_desc_n_bytes(&cqd);
+-		rxmb->packet_type = enic_cq_rx_flags_to_pkt_type(&cqd);
+-		enic_cq_rx_to_pkt_flags(&cqd, rxmb);
++
+ 		if (rq->is_sop) {
+ 			first_seg = rxmb;
+ 			first_seg->nb_segs = 1;
+@@ -350,6 +349,10 @@ enic_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
+ 			continue;
+ 		}
+ 
++		/* cq rx flags are only valid if eop bit is set */
++		first_seg->packet_type = enic_cq_rx_flags_to_pkt_type(&cqd);
++		enic_cq_rx_to_pkt_flags(&cqd, first_seg);
++
+ 		if (unlikely(packet_error)) {
+ 			rte_pktmbuf_free(first_seg);
+ 			rte_atomic64_inc(&enic->soft_stats.rx_packet_errors);
+-- 
+2.7.0
+