summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Lo <loj@cisco.com>2016-07-04 23:23:32 -0400
committerDamjan Marion <dmarion.lists@gmail.com>2016-07-05 16:21:35 +0000
commit55bf5c938585f0cc91b848ec37a5abfaf01f9515 (patch)
treedb08c0efcf55a9d13905616af27a8f819c2dc1c2
parentf727db9e6fb50b2930aedf18bcdda55fe0b96889 (diff)
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>
-rw-r--r--[-rwxr-xr-x]dpdk/dpdk-16.04_patches/0013-Revert-ixgbe-fix-packet-type-from-vector-Rx.patch0
-rw-r--r--[-rwxr-xr-x]dpdk/dpdk-16.04_patches/0014-enic-Set-PKT_RX_VLAN_PKT-iff-returned-packet-has-VLA.patch0
-rw-r--r--dpdk/dpdk-16.04_patches/0018-enic-fix-segfault-on-Tx-path-after-restarting-a-devi.patch46
-rw-r--r--dpdk/dpdk-16.04_patches/0019-enic-fix-Rx-queue-initialization-after-restarting-a-.patch37
-rw-r--r--dpdk/dpdk-16.04_patches/0020-net-enic-fix-releasing-mbufs-when-tearing-down-Rx-qu.patch43
-rw-r--r--dpdk/dpdk-16.04_patches/0021-net-enic-fix-crash-when-releasing-queues.patch61
-rw-r--r--dpdk/dpdk-16.04_patches/0022-net-enic-improve-out-of-resources-error-handling.patch67
-rw-r--r--dpdk/dpdk-16.04_patches/0023-net-enic-fix-memory-freeing.patch238
-rw-r--r--dpdk/dpdk-16.04_patches/0024-net-enic-fix-Rx-scatter-with-multiple-queues.patch80
-rw-r--r--dpdk/dpdk-16.04_patches/0025-enic-fixup-of-Rx-Scatter-patch.patch169
10 files changed, 741 insertions, 0 deletions
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
index e64ed590c5b..e64ed590c5b 100755..100644
--- 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
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
index e510446bc5c..e510446bc5c 100755..100644
--- 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
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 00000000000..10b66375b44
--- /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 00000000000..3e1074862c9
--- /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 00000000000..47bcda23431
--- /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 00000000000..56d2c677e1b
--- /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 00000000000..bf6df8113fa
--- /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 00000000000..0cc423acb54
--- /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 00000000000..d581702d47a
--- /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 00000000000..e4e9f4305d8
--- /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
+