* [PATCH v7 0/7] vhost: optimize mergeable Rx path
From: Yuanhan Liu @ 2016-10-14 9:34 UTC (permalink / raw)
To: dev; +Cc: Maxime Coquelin, Yuanhan Liu, Jianbo Liu
In-Reply-To: <1474336817-22683-1-git-send-email-zhihong.wang@intel.com>
This is a new set of patches to optimize the mergeable Rx code path.
No refactoring (rewrite) was made this time. It just applies some
findings from Zhihong (kudos to him!) that could improve the mergeable
Rx path on the old code.
The two major factors that could improve the performance greatly are:
- copy virtio header together with packet data. This could remove
the buubbles between the two copy to optimize the cache access.
This is implemented in patch 2 "vhost: optimize cache access"
- shadow used ring update and update them at once
The basic idea is to update used ring in a local buffer and flush
them to the virtio used ring at once in the end. Again, this is
for optimizing the cache access.
This is implemented in patch 5 "vhost: shadow used ring update"
The two optimizations could yield 40+% performance in micro testing
and 20+% in PVP case testing with 64B packet size.
Besides that, there are some tiny optimizations, such as prefetch
avail ring (patch 6) and retrieve avail head once (patch 7).
Note: the shadow used ring tech could also be applied to the non-mrg
Rx path (and even the dequeu) path. I didn't do that for two reasons:
- we already update used ring in batch in both path: it's not shadowed
first though.
- it's a bit too late too make many changes at this stage: RC1 is out.
Please help testing.
Thanks.
--yliu
Cc: Jianbo Liu <jianbo.liu@linaro.org>
---
Yuanhan Liu (4):
vhost: simplify mergeable Rx vring reservation
vhost: use last avail idx for avail ring reservation
vhost: prefetch avail ring
vhost: retrieve avail head once
Zhihong Wang (3):
vhost: remove useless volatile
vhost: optimize cache access
vhost: shadow used ring update
lib/librte_vhost/vhost.c | 13 ++-
lib/librte_vhost/vhost.h | 5 +-
lib/librte_vhost/vhost_user.c | 23 +++--
lib/librte_vhost/virtio_net.c | 193 +++++++++++++++++++++++++-----------------
4 files changed, 149 insertions(+), 85 deletions(-)
--
1.9.0
^ permalink raw reply
* [PATCH v7 1/7] vhost: remove useless volatile
From: Yuanhan Liu @ 2016-10-14 9:34 UTC (permalink / raw)
To: dev; +Cc: Maxime Coquelin, Zhihong Wang
In-Reply-To: <1476437678-7102-1-git-send-email-yuanhan.liu@linux.intel.com>
From: Zhihong Wang <zhihong.wang@intel.com>
last_used_idx is a local var, there is no need to decorate it
by "volatile".
Signed-off-by: Zhihong Wang <zhihong.wang@intel.com>
---
lib/librte_vhost/vhost.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/librte_vhost/vhost.h b/lib/librte_vhost/vhost.h
index 53dbf33..17c557f 100644
--- a/lib/librte_vhost/vhost.h
+++ b/lib/librte_vhost/vhost.h
@@ -85,7 +85,7 @@ struct vhost_virtqueue {
uint32_t size;
uint16_t last_avail_idx;
- volatile uint16_t last_used_idx;
+ uint16_t last_used_idx;
#define VIRTIO_INVALID_EVENTFD (-1)
#define VIRTIO_UNINITIALIZED_EVENTFD (-2)
--
1.9.0
^ permalink raw reply related
* [PATCH v7 2/7] vhost: optimize cache access
From: Yuanhan Liu @ 2016-10-14 9:34 UTC (permalink / raw)
To: dev; +Cc: Maxime Coquelin, Zhihong Wang, Yuanhan Liu
In-Reply-To: <1476437678-7102-1-git-send-email-yuanhan.liu@linux.intel.com>
From: Zhihong Wang <zhihong.wang@intel.com>
This patch reorders the code to delay virtio header write to improve
cache access efficiency for cases where the mrg_rxbuf feature is turned
on. CPU pipeline stall cycles can be significantly reduced.
Virtio header write and mbuf data copy are all remote store operations
which takes a long time to finish. It's a good idea to put them together
to remove bubbles in between, to let as many remote store instructions
as possible go into store buffer at the same time to hide latency, and
to let the H/W prefetcher goes to work as early as possible.
On a Haswell machine, about 100 cycles can be saved per packet by this
patch alone. Taking 64B packets traffic for example, this means about 60%
efficiency improvement for the enqueue operation.
Signed-off-by: Zhihong Wang <zhihong.wang@intel.com>
Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
lib/librte_vhost/virtio_net.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/lib/librte_vhost/virtio_net.c b/lib/librte_vhost/virtio_net.c
index 812e5d3..d4fc62a 100644
--- a/lib/librte_vhost/virtio_net.c
+++ b/lib/librte_vhost/virtio_net.c
@@ -390,6 +390,8 @@ copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct vhost_virtqueue *vq,
uint32_t desc_offset, desc_avail;
uint32_t cpy_len;
uint16_t desc_idx, used_idx;
+ uint64_t hdr_addr, hdr_phys_addr;
+ struct rte_mbuf *hdr_mbuf;
if (unlikely(m == NULL))
return 0;
@@ -401,17 +403,15 @@ copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct vhost_virtqueue *vq,
if (buf_vec[vec_idx].buf_len < dev->vhost_hlen || !desc_addr)
return 0;
- rte_prefetch0((void *)(uintptr_t)desc_addr);
+ hdr_mbuf = m;
+ hdr_addr = desc_addr;
+ hdr_phys_addr = buf_vec[vec_idx].buf_addr;
+ rte_prefetch0((void *)(uintptr_t)hdr_addr);
virtio_hdr.num_buffers = end_idx - start_idx;
LOG_DEBUG(VHOST_DATA, "(%d) RX: num merge buffers %d\n",
dev->vid, virtio_hdr.num_buffers);
- virtio_enqueue_offload(m, &virtio_hdr.hdr);
- copy_virtio_net_hdr(dev, desc_addr, virtio_hdr);
- vhost_log_write(dev, buf_vec[vec_idx].buf_addr, dev->vhost_hlen);
- PRINT_PACKET(dev, (uintptr_t)desc_addr, dev->vhost_hlen, 0);
-
desc_avail = buf_vec[vec_idx].buf_len - dev->vhost_hlen;
desc_offset = dev->vhost_hlen;
desc_chain_head = buf_vec[vec_idx].desc_idx;
@@ -456,6 +456,16 @@ copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct vhost_virtqueue *vq,
mbuf_avail = rte_pktmbuf_data_len(m);
}
+ if (hdr_addr) {
+ virtio_enqueue_offload(hdr_mbuf, &virtio_hdr.hdr);
+ copy_virtio_net_hdr(dev, hdr_addr, virtio_hdr);
+ vhost_log_write(dev, hdr_phys_addr, dev->vhost_hlen);
+ PRINT_PACKET(dev, (uintptr_t)hdr_addr,
+ dev->vhost_hlen, 0);
+
+ hdr_addr = 0;
+ }
+
cpy_len = RTE_MIN(desc_avail, mbuf_avail);
rte_memcpy((void *)((uintptr_t)(desc_addr + desc_offset)),
rte_pktmbuf_mtod_offset(m, void *, mbuf_offset),
--
1.9.0
^ permalink raw reply related
* [PATCH v7 3/7] vhost: simplify mergeable Rx vring reservation
From: Yuanhan Liu @ 2016-10-14 9:34 UTC (permalink / raw)
To: dev; +Cc: Maxime Coquelin, Yuanhan Liu, Zhihong Wang
In-Reply-To: <1476437678-7102-1-git-send-email-yuanhan.liu@linux.intel.com>
Let it return "num_buffers" we reserved, so that we could re-use it
with copy_mbuf_to_desc_mergeable() directly, instead of calculating
it again there.
Meanwhile, the return type of copy_mbuf_to_desc_mergeable is changed
to "int". -1 will be return on error.
Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Signed-off-by: Zhihong Wang <zhihong.wang@intel.com>
---
lib/librte_vhost/virtio_net.c | 41 +++++++++++++++++++++--------------------
1 file changed, 21 insertions(+), 20 deletions(-)
diff --git a/lib/librte_vhost/virtio_net.c b/lib/librte_vhost/virtio_net.c
index d4fc62a..1a40c91 100644
--- a/lib/librte_vhost/virtio_net.c
+++ b/lib/librte_vhost/virtio_net.c
@@ -336,7 +336,7 @@ fill_vec_buf(struct vhost_virtqueue *vq, uint32_t avail_idx,
*/
static inline int
reserve_avail_buf_mergeable(struct vhost_virtqueue *vq, uint32_t size,
- uint16_t *end, struct buf_vector *buf_vec)
+ struct buf_vector *buf_vec, uint16_t *num_buffers)
{
uint16_t cur_idx;
uint16_t avail_idx;
@@ -370,19 +370,18 @@ reserve_avail_buf_mergeable(struct vhost_virtqueue *vq, uint32_t size,
return -1;
}
- *end = cur_idx;
+ *num_buffers = cur_idx - vq->last_used_idx;
return 0;
}
-static inline uint32_t __attribute__((always_inline))
+static inline int __attribute__((always_inline))
copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct vhost_virtqueue *vq,
- uint16_t end_idx, struct rte_mbuf *m,
- struct buf_vector *buf_vec)
+ struct rte_mbuf *m, struct buf_vector *buf_vec,
+ uint16_t num_buffers)
{
struct virtio_net_hdr_mrg_rxbuf virtio_hdr = {{0, 0, 0, 0, 0, 0}, 0};
uint32_t vec_idx = 0;
- uint16_t start_idx = vq->last_used_idx;
- uint16_t cur_idx = start_idx;
+ uint16_t cur_idx = vq->last_used_idx;
uint64_t desc_addr;
uint32_t desc_chain_head;
uint32_t desc_chain_len;
@@ -394,21 +393,21 @@ copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct vhost_virtqueue *vq,
struct rte_mbuf *hdr_mbuf;
if (unlikely(m == NULL))
- return 0;
+ return -1;
LOG_DEBUG(VHOST_DATA, "(%d) current index %d | end index %d\n",
dev->vid, cur_idx, end_idx);
desc_addr = gpa_to_vva(dev, buf_vec[vec_idx].buf_addr);
if (buf_vec[vec_idx].buf_len < dev->vhost_hlen || !desc_addr)
- return 0;
+ return -1;
hdr_mbuf = m;
hdr_addr = desc_addr;
hdr_phys_addr = buf_vec[vec_idx].buf_addr;
rte_prefetch0((void *)(uintptr_t)hdr_addr);
- virtio_hdr.num_buffers = end_idx - start_idx;
+ virtio_hdr.num_buffers = num_buffers;
LOG_DEBUG(VHOST_DATA, "(%d) RX: num merge buffers %d\n",
dev->vid, virtio_hdr.num_buffers);
@@ -440,7 +439,7 @@ copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct vhost_virtqueue *vq,
desc_addr = gpa_to_vva(dev, buf_vec[vec_idx].buf_addr);
if (unlikely(!desc_addr))
- return 0;
+ return -1;
/* Prefetch buffer address. */
rte_prefetch0((void *)(uintptr_t)desc_addr);
@@ -489,7 +488,7 @@ copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct vhost_virtqueue *vq,
offsetof(struct vring_used, ring[used_idx]),
sizeof(vq->used->ring[used_idx]));
- return end_idx - start_idx;
+ return 0;
}
static inline uint32_t __attribute__((always_inline))
@@ -497,8 +496,8 @@ virtio_dev_merge_rx(struct virtio_net *dev, uint16_t queue_id,
struct rte_mbuf **pkts, uint32_t count)
{
struct vhost_virtqueue *vq;
- uint32_t pkt_idx = 0, nr_used = 0;
- uint16_t end;
+ uint32_t pkt_idx = 0;
+ uint16_t num_buffers;
struct buf_vector buf_vec[BUF_VECTOR_MAX];
LOG_DEBUG(VHOST_DATA, "(%d) %s\n", dev->vid, __func__);
@@ -519,22 +518,24 @@ virtio_dev_merge_rx(struct virtio_net *dev, uint16_t queue_id,
for (pkt_idx = 0; pkt_idx < count; pkt_idx++) {
uint32_t pkt_len = pkts[pkt_idx]->pkt_len + dev->vhost_hlen;
- if (unlikely(reserve_avail_buf_mergeable(vq, pkt_len,
- &end, buf_vec) < 0)) {
+ if (unlikely(reserve_avail_buf_mergeable(vq, pkt_len, buf_vec,
+ &num_buffers) < 0)) {
LOG_DEBUG(VHOST_DATA,
"(%d) failed to get enough desc from vring\n",
dev->vid);
break;
}
- nr_used = copy_mbuf_to_desc_mergeable(dev, vq, end,
- pkts[pkt_idx], buf_vec);
+ if (copy_mbuf_to_desc_mergeable(dev, vq, pkts[pkt_idx],
+ buf_vec, num_buffers) < 0)
+ break;
+
rte_smp_wmb();
- *(volatile uint16_t *)&vq->used->idx += nr_used;
+ *(volatile uint16_t *)&vq->used->idx += num_buffers;
vhost_log_used_vring(dev, vq, offsetof(struct vring_used, idx),
sizeof(vq->used->idx));
- vq->last_used_idx += nr_used;
+ vq->last_used_idx += num_buffers;
}
if (likely(pkt_idx)) {
--
1.9.0
^ permalink raw reply related
* [PATCH v7 4/7] vhost: use last avail idx for avail ring reservation
From: Yuanhan Liu @ 2016-10-14 9:34 UTC (permalink / raw)
To: dev; +Cc: Maxime Coquelin, Yuanhan Liu, Zhihong Wang
In-Reply-To: <1476437678-7102-1-git-send-email-yuanhan.liu@linux.intel.com>
shadow_used_ring will be introduced later. Since then last avail
idx will not be updated together with last used idx.
So, here we use last_avail_idx for avail ring reservation.
Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Signed-off-by: Zhihong Wang <zhihong.wang@intel.com>
---
lib/librte_vhost/virtio_net.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/librte_vhost/virtio_net.c b/lib/librte_vhost/virtio_net.c
index 1a40c91..b5ba633 100644
--- a/lib/librte_vhost/virtio_net.c
+++ b/lib/librte_vhost/virtio_net.c
@@ -344,7 +344,7 @@ reserve_avail_buf_mergeable(struct vhost_virtqueue *vq, uint32_t size,
uint32_t vec_idx = 0;
uint16_t tries = 0;
- cur_idx = vq->last_used_idx;
+ cur_idx = vq->last_avail_idx;
while (1) {
avail_idx = *((volatile uint16_t *)&vq->avail->idx);
@@ -370,7 +370,7 @@ reserve_avail_buf_mergeable(struct vhost_virtqueue *vq, uint32_t size,
return -1;
}
- *num_buffers = cur_idx - vq->last_used_idx;
+ *num_buffers = cur_idx - vq->last_avail_idx;
return 0;
}
@@ -536,6 +536,7 @@ virtio_dev_merge_rx(struct virtio_net *dev, uint16_t queue_id,
vhost_log_used_vring(dev, vq, offsetof(struct vring_used, idx),
sizeof(vq->used->idx));
vq->last_used_idx += num_buffers;
+ vq->last_avail_idx += num_buffers;
}
if (likely(pkt_idx)) {
--
1.9.0
^ permalink raw reply related
* [PATCH v7 5/7] vhost: shadow used ring update
From: Yuanhan Liu @ 2016-10-14 9:34 UTC (permalink / raw)
To: dev; +Cc: Maxime Coquelin, Zhihong Wang, Yuanhan Liu
In-Reply-To: <1476437678-7102-1-git-send-email-yuanhan.liu@linux.intel.com>
From: Zhihong Wang <zhihong.wang@intel.com>
The basic idea is to shadow the used ring update: update them into a
local buffer first, and then flush them all to the virtio used vring
at once in the end.
And since we do avail ring reservation before enqueuing data, we would
know which and how many descs will be used. Which means we could update
the shadow used ring at the reservation time. It also introduce another
slight advantage: we don't need access the desc->flag any more inside
copy_mbuf_to_desc_mergeable().
Signed-off-by: Zhihong Wang <zhihong.wang@intel.com>
Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
lib/librte_vhost/vhost.c | 13 +++-
lib/librte_vhost/vhost.h | 3 +
lib/librte_vhost/vhost_user.c | 23 +++++--
lib/librte_vhost/virtio_net.c | 138 +++++++++++++++++++++++++-----------------
4 files changed, 113 insertions(+), 64 deletions(-)
diff --git a/lib/librte_vhost/vhost.c b/lib/librte_vhost/vhost.c
index 469117a..d8116ff 100644
--- a/lib/librte_vhost/vhost.c
+++ b/lib/librte_vhost/vhost.c
@@ -121,9 +121,18 @@ static void
free_device(struct virtio_net *dev)
{
uint32_t i;
+ struct vhost_virtqueue *rxq, *txq;
- for (i = 0; i < dev->virt_qp_nb; i++)
- rte_free(dev->virtqueue[i * VIRTIO_QNUM]);
+ for (i = 0; i < dev->virt_qp_nb; i++) {
+ rxq = dev->virtqueue[i * VIRTIO_QNUM + VIRTIO_RXQ];
+ txq = dev->virtqueue[i * VIRTIO_QNUM + VIRTIO_TXQ];
+
+ rte_free(rxq->shadow_used_ring);
+ rte_free(txq->shadow_used_ring);
+
+ /* rxq and txq are allocated together as queue-pair */
+ rte_free(rxq);
+ }
rte_free(dev);
}
diff --git a/lib/librte_vhost/vhost.h b/lib/librte_vhost/vhost.h
index 17c557f..acec772 100644
--- a/lib/librte_vhost/vhost.h
+++ b/lib/librte_vhost/vhost.h
@@ -105,6 +105,9 @@ struct vhost_virtqueue {
uint16_t last_zmbuf_idx;
struct zcopy_mbuf *zmbufs;
struct zcopy_mbuf_list zmbuf_list;
+
+ struct vring_used_elem *shadow_used_ring;
+ uint16_t shadow_used_idx;
} __rte_cache_aligned;
/* Old kernels have no such macro defined */
diff --git a/lib/librte_vhost/vhost_user.c b/lib/librte_vhost/vhost_user.c
index 3074227..6b83c15 100644
--- a/lib/librte_vhost/vhost_user.c
+++ b/lib/librte_vhost/vhost_user.c
@@ -198,6 +198,15 @@ vhost_user_set_vring_num(struct virtio_net *dev,
}
}
+ vq->shadow_used_ring = rte_malloc(NULL,
+ vq->size * sizeof(struct vring_used_elem),
+ RTE_CACHE_LINE_SIZE);
+ if (!vq->shadow_used_ring) {
+ RTE_LOG(ERR, VHOST_CONFIG,
+ "failed to allocate memory for shadow used ring.\n");
+ return -1;
+ }
+
return 0;
}
@@ -711,6 +720,8 @@ static int
vhost_user_get_vring_base(struct virtio_net *dev,
struct vhost_vring_state *state)
{
+ struct vhost_virtqueue *vq = dev->virtqueue[state->index];
+
/* We have to stop the queue (virtio) if it is running. */
if (dev->flags & VIRTIO_DEV_RUNNING) {
dev->flags &= ~VIRTIO_DEV_RUNNING;
@@ -718,7 +729,7 @@ vhost_user_get_vring_base(struct virtio_net *dev,
}
/* Here we are safe to get the last used index */
- state->num = dev->virtqueue[state->index]->last_used_idx;
+ state->num = vq->last_used_idx;
RTE_LOG(INFO, VHOST_CONFIG,
"vring base idx:%d file:%d\n", state->index, state->num);
@@ -727,13 +738,15 @@ vhost_user_get_vring_base(struct virtio_net *dev,
* sent and only sent in vhost_vring_stop.
* TODO: cleanup the vring, it isn't usable since here.
*/
- if (dev->virtqueue[state->index]->kickfd >= 0)
- close(dev->virtqueue[state->index]->kickfd);
+ if (vq->kickfd >= 0)
+ close(vq->kickfd);
- dev->virtqueue[state->index]->kickfd = VIRTIO_UNINITIALIZED_EVENTFD;
+ vq->kickfd = VIRTIO_UNINITIALIZED_EVENTFD;
if (dev->dequeue_zero_copy)
- free_zmbufs(dev->virtqueue[state->index]);
+ free_zmbufs(vq);
+ rte_free(vq->shadow_used_ring);
+ vq->shadow_used_ring = NULL;
return 0;
}
diff --git a/lib/librte_vhost/virtio_net.c b/lib/librte_vhost/virtio_net.c
index b5ba633..2bdc2fe 100644
--- a/lib/librte_vhost/virtio_net.c
+++ b/lib/librte_vhost/virtio_net.c
@@ -91,6 +91,56 @@ is_valid_virt_queue_idx(uint32_t idx, int is_tx, uint32_t qp_nb)
return (is_tx ^ (idx & 1)) == 0 && idx < qp_nb * VIRTIO_QNUM;
}
+static inline void __attribute__((always_inline))
+do_flush_shadow_used_ring(struct virtio_net *dev, struct vhost_virtqueue *vq,
+ uint16_t to, uint16_t from, uint16_t size)
+{
+ rte_memcpy(&vq->used->ring[to],
+ &vq->shadow_used_ring[from],
+ size * sizeof(struct vring_used_elem));
+ vhost_log_used_vring(dev, vq,
+ offsetof(struct vring_used, ring[to]),
+ size * sizeof(struct vring_used_elem));
+}
+
+static inline void __attribute__((always_inline))
+flush_shadow_used_ring(struct virtio_net *dev, struct vhost_virtqueue *vq)
+{
+ uint16_t used_idx = vq->last_used_idx & (vq->size - 1);
+
+ if (used_idx + vq->shadow_used_idx <= vq->size) {
+ do_flush_shadow_used_ring(dev, vq, used_idx, 0,
+ vq->shadow_used_idx);
+ } else {
+ uint16_t size;
+
+ /* update used ring interval [used_idx, vq->size] */
+ size = vq->size - used_idx;
+ do_flush_shadow_used_ring(dev, vq, used_idx, 0, size);
+
+ /* update the left half used ring interval [0, left_size] */
+ do_flush_shadow_used_ring(dev, vq, 0, size,
+ vq->shadow_used_idx - size);
+ }
+ vq->last_used_idx += vq->shadow_used_idx;
+
+ rte_smp_wmb();
+
+ *(volatile uint16_t *)&vq->used->idx += vq->shadow_used_idx;
+ vhost_log_used_vring(dev, vq, offsetof(struct vring_used, idx),
+ sizeof(vq->used->idx));
+}
+
+static inline void __attribute__((always_inline))
+update_shadow_used_ring(struct vhost_virtqueue *vq,
+ uint16_t desc_idx, uint16_t len)
+{
+ uint16_t i = vq->shadow_used_idx++;
+
+ vq->shadow_used_ring[i].id = desc_idx;
+ vq->shadow_used_ring[i].len = len;
+}
+
static void
virtio_enqueue_offload(struct rte_mbuf *m_buf, struct virtio_net_hdr *net_hdr)
{
@@ -300,15 +350,16 @@ virtio_dev_rx(struct virtio_net *dev, uint16_t queue_id,
return count;
}
-static inline int
+static inline int __attribute__((always_inline))
fill_vec_buf(struct vhost_virtqueue *vq, uint32_t avail_idx,
- uint32_t *allocated, uint32_t *vec_idx,
- struct buf_vector *buf_vec)
+ uint32_t *vec_idx, struct buf_vector *buf_vec,
+ uint16_t *desc_chain_head, uint16_t *desc_chain_len)
{
uint16_t idx = vq->avail->ring[avail_idx & (vq->size - 1)];
uint32_t vec_id = *vec_idx;
- uint32_t len = *allocated;
+ uint32_t len = 0;
+ *desc_chain_head = idx;
while (1) {
if (unlikely(vec_id >= BUF_VECTOR_MAX || idx >= vq->size))
return -1;
@@ -325,8 +376,8 @@ fill_vec_buf(struct vhost_virtqueue *vq, uint32_t avail_idx,
idx = vq->desc[idx].next;
}
- *allocated = len;
- *vec_idx = vec_id;
+ *desc_chain_len = len;
+ *vec_idx = vec_id;
return 0;
}
@@ -340,26 +391,30 @@ reserve_avail_buf_mergeable(struct vhost_virtqueue *vq, uint32_t size,
{
uint16_t cur_idx;
uint16_t avail_idx;
- uint32_t allocated = 0;
uint32_t vec_idx = 0;
uint16_t tries = 0;
- cur_idx = vq->last_avail_idx;
+ uint16_t head_idx = 0;
+ uint16_t len = 0;
- while (1) {
+ *num_buffers = 0;
+ cur_idx = vq->last_avail_idx;
+
+ while (size > 0) {
avail_idx = *((volatile uint16_t *)&vq->avail->idx);
if (unlikely(cur_idx == avail_idx))
return -1;
- if (unlikely(fill_vec_buf(vq, cur_idx, &allocated,
- &vec_idx, buf_vec) < 0))
+ if (unlikely(fill_vec_buf(vq, cur_idx, &vec_idx, buf_vec,
+ &head_idx, &len) < 0))
return -1;
+ len = RTE_MIN(len, size);
+ update_shadow_used_ring(vq, head_idx, len);
+ size -= len;
cur_idx++;
tries++;
-
- if (allocated >= size)
- break;
+ *num_buffers += 1;
/*
* if we tried all available ring items, and still
@@ -370,25 +425,19 @@ reserve_avail_buf_mergeable(struct vhost_virtqueue *vq, uint32_t size,
return -1;
}
- *num_buffers = cur_idx - vq->last_avail_idx;
return 0;
}
static inline int __attribute__((always_inline))
-copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct vhost_virtqueue *vq,
- struct rte_mbuf *m, struct buf_vector *buf_vec,
- uint16_t num_buffers)
+copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct rte_mbuf *m,
+ struct buf_vector *buf_vec, uint16_t num_buffers)
{
struct virtio_net_hdr_mrg_rxbuf virtio_hdr = {{0, 0, 0, 0, 0, 0}, 0};
uint32_t vec_idx = 0;
- uint16_t cur_idx = vq->last_used_idx;
uint64_t desc_addr;
- uint32_t desc_chain_head;
- uint32_t desc_chain_len;
uint32_t mbuf_offset, mbuf_avail;
uint32_t desc_offset, desc_avail;
uint32_t cpy_len;
- uint16_t desc_idx, used_idx;
uint64_t hdr_addr, hdr_phys_addr;
struct rte_mbuf *hdr_mbuf;
@@ -409,34 +458,17 @@ copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct vhost_virtqueue *vq,
virtio_hdr.num_buffers = num_buffers;
LOG_DEBUG(VHOST_DATA, "(%d) RX: num merge buffers %d\n",
- dev->vid, virtio_hdr.num_buffers);
+ dev->vid, num_buffers);
desc_avail = buf_vec[vec_idx].buf_len - dev->vhost_hlen;
desc_offset = dev->vhost_hlen;
- desc_chain_head = buf_vec[vec_idx].desc_idx;
- desc_chain_len = desc_offset;
mbuf_avail = rte_pktmbuf_data_len(m);
mbuf_offset = 0;
while (mbuf_avail != 0 || m->next != NULL) {
/* done with current desc buf, get the next one */
if (desc_avail == 0) {
- desc_idx = buf_vec[vec_idx].desc_idx;
vec_idx++;
-
- if (!(vq->desc[desc_idx].flags & VRING_DESC_F_NEXT)) {
- /* Update used ring with desc information */
- used_idx = cur_idx++ & (vq->size - 1);
- vq->used->ring[used_idx].id = desc_chain_head;
- vq->used->ring[used_idx].len = desc_chain_len;
- vhost_log_used_vring(dev, vq,
- offsetof(struct vring_used,
- ring[used_idx]),
- sizeof(vq->used->ring[used_idx]));
- desc_chain_head = buf_vec[vec_idx].desc_idx;
- desc_chain_len = 0;
- }
-
desc_addr = gpa_to_vva(dev, buf_vec[vec_idx].buf_addr);
if (unlikely(!desc_addr))
return -1;
@@ -478,16 +510,8 @@ copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct vhost_virtqueue *vq,
mbuf_offset += cpy_len;
desc_avail -= cpy_len;
desc_offset += cpy_len;
- desc_chain_len += cpy_len;
}
- used_idx = cur_idx & (vq->size - 1);
- vq->used->ring[used_idx].id = desc_chain_head;
- vq->used->ring[used_idx].len = desc_chain_len;
- vhost_log_used_vring(dev, vq,
- offsetof(struct vring_used, ring[used_idx]),
- sizeof(vq->used->ring[used_idx]));
-
return 0;
}
@@ -515,6 +539,7 @@ virtio_dev_merge_rx(struct virtio_net *dev, uint16_t queue_id,
if (count == 0)
return 0;
+ vq->shadow_used_idx = 0;
for (pkt_idx = 0; pkt_idx < count; pkt_idx++) {
uint32_t pkt_len = pkts[pkt_idx]->pkt_len + dev->vhost_hlen;
@@ -523,23 +548,22 @@ virtio_dev_merge_rx(struct virtio_net *dev, uint16_t queue_id,
LOG_DEBUG(VHOST_DATA,
"(%d) failed to get enough desc from vring\n",
dev->vid);
+ vq->shadow_used_idx -= num_buffers;
break;
}
- if (copy_mbuf_to_desc_mergeable(dev, vq, pkts[pkt_idx],
- buf_vec, num_buffers) < 0)
+ if (copy_mbuf_to_desc_mergeable(dev, pkts[pkt_idx],
+ buf_vec, num_buffers) < 0) {
+ vq->shadow_used_idx -= num_buffers;
break;
+ }
- rte_smp_wmb();
-
- *(volatile uint16_t *)&vq->used->idx += num_buffers;
- vhost_log_used_vring(dev, vq, offsetof(struct vring_used, idx),
- sizeof(vq->used->idx));
- vq->last_used_idx += num_buffers;
vq->last_avail_idx += num_buffers;
}
- if (likely(pkt_idx)) {
+ if (likely(vq->shadow_used_idx)) {
+ flush_shadow_used_ring(dev, vq);
+
/* flush used->idx update before we read avail->flags. */
rte_mb();
--
1.9.0
^ permalink raw reply related
* [PATCH v7 7/7] vhost: retrieve avail head once
From: Yuanhan Liu @ 2016-10-14 9:34 UTC (permalink / raw)
To: dev; +Cc: Maxime Coquelin, Yuanhan Liu, Zhihong Wang
In-Reply-To: <1476437678-7102-1-git-send-email-yuanhan.liu@linux.intel.com>
There is no need to retrieve the latest avail head every time we enqueue
a packet in the mereable Rx path by
avail_idx = *((volatile uint16_t *)&vq->avail->idx);
Instead, we could just retrieve it once at the beginning of the enqueue
path. This could diminish the cache penalty slightly, because the virtio
driver could be updating it while vhost is reading it (for each packet).
Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Signed-off-by: Zhihong Wang <zhihong.wang@intel.com>
---
lib/librte_vhost/virtio_net.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/lib/librte_vhost/virtio_net.c b/lib/librte_vhost/virtio_net.c
index 12a037b..b784dba 100644
--- a/lib/librte_vhost/virtio_net.c
+++ b/lib/librte_vhost/virtio_net.c
@@ -387,10 +387,10 @@ fill_vec_buf(struct vhost_virtqueue *vq, uint32_t avail_idx,
*/
static inline int
reserve_avail_buf_mergeable(struct vhost_virtqueue *vq, uint32_t size,
- struct buf_vector *buf_vec, uint16_t *num_buffers)
+ struct buf_vector *buf_vec, uint16_t *num_buffers,
+ uint16_t avail_head)
{
uint16_t cur_idx;
- uint16_t avail_idx;
uint32_t vec_idx = 0;
uint16_t tries = 0;
@@ -401,8 +401,7 @@ reserve_avail_buf_mergeable(struct vhost_virtqueue *vq, uint32_t size,
cur_idx = vq->last_avail_idx;
while (size > 0) {
- avail_idx = *((volatile uint16_t *)&vq->avail->idx);
- if (unlikely(cur_idx == avail_idx))
+ if (unlikely(cur_idx == avail_head))
return -1;
if (unlikely(fill_vec_buf(vq, cur_idx, &vec_idx, buf_vec,
@@ -523,6 +522,7 @@ virtio_dev_merge_rx(struct virtio_net *dev, uint16_t queue_id,
uint32_t pkt_idx = 0;
uint16_t num_buffers;
struct buf_vector buf_vec[BUF_VECTOR_MAX];
+ uint16_t avail_head;
LOG_DEBUG(VHOST_DATA, "(%d) %s\n", dev->vid, __func__);
if (unlikely(!is_valid_virt_queue_idx(queue_id, 0, dev->virt_qp_nb))) {
@@ -542,11 +542,12 @@ virtio_dev_merge_rx(struct virtio_net *dev, uint16_t queue_id,
rte_prefetch0(&vq->avail->ring[vq->last_avail_idx & (vq->size - 1)]);
vq->shadow_used_idx = 0;
+ avail_head = *((volatile uint16_t *)&vq->avail->idx);
for (pkt_idx = 0; pkt_idx < count; pkt_idx++) {
uint32_t pkt_len = pkts[pkt_idx]->pkt_len + dev->vhost_hlen;
if (unlikely(reserve_avail_buf_mergeable(vq, pkt_len, buf_vec,
- &num_buffers) < 0)) {
+ &num_buffers, avail_head) < 0)) {
LOG_DEBUG(VHOST_DATA,
"(%d) failed to get enough desc from vring\n",
dev->vid);
--
1.9.0
^ permalink raw reply related
* [PATCH v7 6/7] vhost: prefetch avail ring
From: Yuanhan Liu @ 2016-10-14 9:34 UTC (permalink / raw)
To: dev; +Cc: Maxime Coquelin, Yuanhan Liu, Zhihong Wang
In-Reply-To: <1476437678-7102-1-git-send-email-yuanhan.liu@linux.intel.com>
Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Signed-off-by: Zhihong Wang <zhihong.wang@intel.com>
---
lib/librte_vhost/virtio_net.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lib/librte_vhost/virtio_net.c b/lib/librte_vhost/virtio_net.c
index 2bdc2fe..12a037b 100644
--- a/lib/librte_vhost/virtio_net.c
+++ b/lib/librte_vhost/virtio_net.c
@@ -539,6 +539,8 @@ virtio_dev_merge_rx(struct virtio_net *dev, uint16_t queue_id,
if (count == 0)
return 0;
+ rte_prefetch0(&vq->avail->ring[vq->last_avail_idx & (vq->size - 1)]);
+
vq->shadow_used_idx = 0;
for (pkt_idx = 0; pkt_idx < count; pkt_idx++) {
uint32_t pkt_len = pkts[pkt_idx]->pkt_len + dev->vhost_hlen;
--
1.9.0
^ permalink raw reply related
* Re: [PATCH v9] drivers/net:new PMD using tun/tap host interface
From: Ferruh Yigit @ 2016-10-14 9:39 UTC (permalink / raw)
To: Keith Wiles, dev; +Cc: pmatilai, yuanhan.liu
In-Reply-To: <1476396234-44694-1-git-send-email-keith.wiles@intel.com>
On 10/13/2016 11:03 PM, Keith Wiles wrote:
> The rte_eth_tap.c PMD creates a device using TUN/TAP interfaces
> on the local host. The PMD allows for DPDK and the host to
> communicate using a raw device interface on the host and in
> the DPDK application. The device created is a Tap device with
> a L2 packet header.
>
> v9 - Fix up the docs to use correct syntax
> v8 - Fix issue with tap_tx_queue_setup() not return zero on success.
> v7 - Reword the comment in common_base and fix the data->name issue
> v6 - fixed the checkpatch issues
> v5 - merge in changes from list review see related emails
> fixed many minor edits
> v4 - merge with latest driver changes
> v3 - fix includes by removing ifdef for other type besides Linux
> Fix the copyright notice in the Makefile
> v2 - merge all of the patches into one patch
> Fix a typo on naming the tap device
> Update the maintainers list
>
> Signed-off-by: Keith Wiles <keith.wiles@intel.com>
> ---
Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
^ permalink raw reply
* Re: [PATCH v3 0/5] vhost: optimize enqueue
From: Yuanhan Liu @ 2016-10-14 10:11 UTC (permalink / raw)
To: Maxime Coquelin; +Cc: Wang, Zhihong, Jianbo Liu, Thomas Monjalon, dev@dpdk.org
In-Reply-To: <570cc934-590e-8770-9853-f03a1380d181@redhat.com>
On Thu, Oct 13, 2016 at 11:23:44AM +0200, Maxime Coquelin wrote:
> I was going to re-run some PVP benchmark with 0% pkt loss, as I had
> some strange results last week.
>
> Problem is that your series no more apply cleanly due to
> next-virtio's master branch history rewrite.
> Any chance you send me a rebased version so that I can apply the series?
I think it's pointless to do that now: it won't be merged after all.
We have refactored out the new series, please help review if you
got time :)
BTW, apologize that I forgot to include your Reviewed-by for the
first patch. I intended to do that ...
--yliu
^ permalink raw reply
* Re: [RFC] [PATCH v2] libeventdev: event driven programming model framework for DPDK
From: Hemant Agrawal @ 2016-10-14 10:30 UTC (permalink / raw)
To: Jerin Jacob, Bill Fischofer
Cc: dev@dpdk.org, thomas.monjalon@6wind.com,
bruce.richardson@intel.com, narender.vangati@intel.com,
gage.eads@intel.com
In-Reply-To: <20161014092607.GA16828@localhost.localdomain>
Hi Bill/Jerin,
>
> Thanks for the review.
>
> [snip]
> > > + * If the device init operation is successful, the correspondence
> > > + between
> > > + * the device identifier assigned to the new device and its
> > > + associated
> > > + * *rte_event_dev* structure is effectively registered.
> > > + * Otherwise, both the *rte_event_dev* structure and the device
> > > identifier are
> > > + * freed.
> > > + *
> > > + * The functions exported by the application Event API to setup a
> > > + device
> > > + * designated by its device identifier must be invoked in the
> > > + following
> > > order:
> > > + * - rte_event_dev_configure()
> > > + * - rte_event_queue_setup()
> > > + * - rte_event_port_setup()
> > > + * - rte_event_port_link()
> > > + * - rte_event_dev_start()
> > > + *
> > > + * Then, the application can invoke, in any order, the functions
> > > + * exported by the Event API to schedule events, dequeue events,
> > > + enqueue
> > > events,
> > > + * change event queue(s) to event port [un]link establishment and so on.
> > > + *
> > > + * Application may use rte_event_[queue/port]_default_conf_get() to
> > > + get
> > > the
> > > + * default configuration to set up an event queue or event port by
> > > + * overriding few default values.
> > > + *
> > > + * If the application wants to change the configuration (i.e. call
> > > + * rte_event_dev_configure(), rte_event_queue_setup(), or
> > > + * rte_event_port_setup()), it must call rte_event_dev_stop() first
> > > + to
> > > stop the
> > > + * device and then do the reconfiguration before calling
> > > rte_event_dev_start()
> > > + * again. The schedule, enqueue and dequeue functions should not be
> > > invoked
> > > + * when the device is stopped.
> > >
> >
> > Given this requirement, the question is what happens to events that
> > are "in flight" at the time rte_event_dev_stop() is called? Is stop an
> > asynchronous operation that quiesces the event _dev and allows
> > in-flight events to drain from queues/ports prior to fully stopping,
> > or is some sort of separate explicit quiesce mechanism required? If
> > stop is synchronous and simply halts the event_dev, then how is an
> > application to know if subsequent configure/setup calls would leave
> > these pending events with no place to stand?
> >
>
> From an application API perspective rte_event_dev_stop() is a synchronous
> function.
> If the stop has been called for re-configuring the number of queues, ports etc of
> the device, then "in flight" entry preservation will be implementation defined.
> else "in flight" entries will be preserved.
>
> [snip]
>
> > > +extern int
> > > +rte_event_dev_socket_id(uint8_t dev_id);
> > > +
> > > +/* Event device capability bitmap flags */
> > > +#define RTE_EVENT_DEV_CAP_QUEUE_QOS (1 << 0)
> > > +/**< Event scheduling prioritization is based on the priority
> > > +associated
> > > with
> > > + * each event queue.
> > > + *
> > > + * \see rte_event_queue_setup(), RTE_EVENT_QUEUE_PRIORITY_NORMAL
> > > +*/
> > > +#define RTE_EVENT_DEV_CAP_EVENT_QOS (1 << 1)
> > > +/**< Event scheduling prioritization is based on the priority
> > > +associated
> > > with
> > > + * each event. Priority of each event is supplied in *rte_event*
> > > structure
> > > + * on each enqueue operation.
> > > + *
> > > + * \see rte_event_enqueue()
> > > + */
> > > +
> > > +/**
> > > + * Event device information
> > > + */
> > > +struct rte_event_dev_info {
> > > + const char *driver_name; /**< Event driver name */
> > > + struct rte_pci_device *pci_dev; /**< PCI information */
> > > + uint32_t min_dequeue_wait_ns;
> > > + /**< Minimum supported global dequeue wait delay(ns) by this
> > > device */
> > > + uint32_t max_dequeue_wait_ns;
> > > + /**< Maximum supported global dequeue wait delay(ns) by this
> > > device */
> > > + uint32_t dequeue_wait_ns;
> > >
> >
> > Am I reading this correctly that there is no way to support an
> > indefinite waiting capability? Or is this just saying that if a timed
> > wait is performed there are min/max limits for the wait duration?
>
> Application can wait indefinite if required. see
> RTE_EVENT_DEV_CFG_PER_DEQUEUE_WAIT configuration option.
>
> Trivial application may not need different wait values on each dequeue.This is a
> performance optimization opportunity for implementation.
Jerin, It is irrespective of wait configuration, whether you are using per device wait or per dequeuer wait.
Can the value of MAX_U32 or MAX_U64 be treated as infinite weight?
>
> >
> >
> > > + /**< Configured global dequeue wait delay(ns) for this device */
> > > + uint8_t max_event_queues;
> > > + /**< Maximum event_queues supported by this device */
> > > + uint32_t max_event_queue_flows;
> > > + /**< Maximum supported flows in an event queue by this device*/
> > > + uint8_t max_event_queue_priority_levels;
> > > + /**< Maximum number of event queue priority levels by this device.
> > > + * Valid when the device has RTE_EVENT_DEV_CAP_QUEUE_QOS
> capability
> > > + */
> > > + uint8_t nb_event_queues;
> > > + /**< Configured number of event queues for this device */
> > >
> >
> > Is 256 a sufficient number of queues? While various SoCs may have
> > limits, why impose such a small limit architecturally?
>
> Each event queue potentially can support millions of flows.That way, 256 may
> not be a small limit.The reason to choose queue_id as 8bit to hold all the
> attribute of "struct rte_event" in 128bit. So that SIMD optimization is possible in
> the implementation.
>
[Hemant] 256 is not an small number of event queue. Please consider event queue as logically equivalent of a scheduler group in ODP.
> > > + /**< The maximum number of active flows this queue can track at any
> > > + * given time. The value must be in the range of
> > > + * [1 - max_event_queue_flows)] which previously supplied
> > > + * to rte_event_dev_configure().
> > > + */
> > > + uint32_t nb_atomic_order_sequences;
> > > + /**< The maximum number of outstanding events waiting to be
> > > (egress-)
> > > + * reordered by this queue. In other words, the number of
> > > + entries
> > > in
> > > + * this queue’s reorder buffer.The value must be in the range of
> > > + * [1 - max_event_queue_flows)] which previously supplied
> > > + * to rte_event_dev_configure().
> > >
> >
> > What happens if this limit is exceeded? While atomic limits are
> > bounded by the number of lcores, the same cannot be said for ordered
> queues.
> > Presumably the queue would refuse further dequeues once this limit is
> > reached until pending reorders are resolved to permit continued processing?
> > If so that should be stated explicitly.
>
> OK. I will update details.
>
> >
> >
> > > + *
> > > + *
> > > + * The device start step is the last one and consists of setting
> > > +the event
> > > + * queues to start accepting the events and schedules to event ports.
> > > + *
> > > + * On success, all basic functions exported by the API (event
> > > +enqueue,
> > > + * event dequeue and so on) can be invoked.
> > > + *
> > > + * @param dev_id
> > > + * Event device identifier
> > > + * @return
> > > + * - 0: Success, device started.
> > > + * - <0: Error code of the driver device start function.
> > > + */
> > > +extern int
> > > +rte_event_dev_start(uint8_t dev_id);
> > > +
> > > +/**
> > > + * Stop an event device. The device can be restarted with a call to
> > > + * rte_event_dev_start()
> > > + *
> > > + * @param dev_id
> > > + * Event device identifier.
> > > + */
> > > +extern void
> > > +rte_event_dev_stop(uint8_t dev_id);
> > >
> >
> > Having this be a void function implies this function cannot fail. Is
> > that assumption always correct?
>
> Yes. Subsequent rte_event_dev_start() can return error if the implementation
> really have some critical issues on starting the device.
>
> >
> >
> > > +
> > > +/**
> > > + * Close an event device. The device cannot be restarted!
> > > + *
> > > + * @param dev_id
> > > + * Event device identifier
> > > + *
> > > + * @return
> > > + * - 0 on successfully closing device
> > > + * - <0 on failure to close device */ extern int
^ permalink raw reply
* [PATCH v2 0/4] Generalize PCI specific EAL function/structures
From: Shreyansh Jain @ 2016-10-14 10:55 UTC (permalink / raw)
To: dev; +Cc: viktorin, thomas.monjalon, david.marchand, Shreyansh Jain
In-Reply-To: <1474985551-14219-1-git-send-email-shreyansh.jain@nxp.com>
(Rebased these over HEAD fed622dfd)
These patches were initially part of Jan's original series on SoC
Framework ([1],[2]). An update to that series, without these patches,
was posted here [3].
Main motivation for these is aim of introducing a non-PCI centric
subsystem in EAL. As of now the first usecase is SoC, but not limited to
it.
4 patches in this series are independent of each other, as well as SoC
framework. All these focus on generalizing some structure or functions
present with the PCI specific code to EAL Common area (or splitting a
function to be more userful).
- 0001: move the rte_kernel_driver enum from rte_pci to rte_dev. As of
now this structure is embedded in rte_pci_device, but, going ahead it
can be part of other rte_xxx_device structures. Either way, it has no
impact on PCI.
- 0002: Functions pci_map_resource/pci_unmap_resource are moved to EAL
common as rte_eal_map_resource/rte_eal_unmap_resource, respectively.
- 0003: Split the pci_unbind_kernel_driver into two, still working on
the PCI BDF sysfs layout, first handles the file path (and validations)
and second does the actual unbind. The second part might be useful in
case of non-PCI layouts.
-- This is useful for other subsystem, parallel to PCI, which require
| MMAP support.
`- an equivalent NOTSUP function for BSD has been added in v1
- 0004: Move pci_get_kernel_driver_by_path to
rte_eal_get_kernel_driver_by_path in EAL common. This function is
generic for any sysfs compliant driver and can be re-used by other
non-PCI subsystem.
`- an equivalent NOTSUP function for BSD has been added in v1
Changes since v1
- Rebased over master (fed622dfd)
- Added dummy functions for BSD for unbind and kernel driver fetch
functions (patches 003, 004)
Changes since v0 [4]:
- Fix for checkpatch and check-git-log
- Fix missing include in patch 0001
- Drop patch 2 for splitting sysfs into a sub-function taking file
handle. This patch doesn't really fit into the model of PCI->EAL
movement of generic functions which other patches relate to.
Also, taking cue from review comment [5], it might not have a
viable use-case as of now.
[1] http://dpdk.org/ml/archives/dev/2016-January/030915.html
[2] http://www.dpdk.org/ml/archives/dev/2016-May/038486.html
[3] http://dpdk.org/ml/archives/dev/2016-August/045993.html
[4] http://dpdk.org/ml/archives/dev/2016-September/046035.html
[5] http://dpdk.org/ml/archives/dev/2016-September/046041.html
Jan Viktorin (4):
eal: generalize PCI kernel driver enum to EAL
eal: generalize PCI map/unmap resource to EAL
eal/linux: generalize PCI kernel unbinding driver to EAL
eal/linux: generalize PCI kernel driver extraction to EAL
lib/librte_eal/bsdapp/eal/eal.c | 14 ++++++
lib/librte_eal/bsdapp/eal/eal_pci.c | 6 +--
lib/librte_eal/bsdapp/eal/rte_eal_version.map | 2 +
lib/librte_eal/common/eal_common_dev.c | 39 ++++++++++++++++
lib/librte_eal/common/eal_common_pci.c | 39 ----------------
lib/librte_eal/common/eal_common_pci_uio.c | 16 ++++---
lib/librte_eal/common/eal_private.h | 27 +++++++++++
lib/librte_eal/common/include/rte_dev.h | 44 ++++++++++++++++++
lib/librte_eal/common/include/rte_pci.h | 41 ----------------
lib/librte_eal/linuxapp/eal/eal.c | 55 ++++++++++++++++++++++
lib/librte_eal/linuxapp/eal/eal_pci.c | 62 ++++---------------------
lib/librte_eal/linuxapp/eal/eal_pci_uio.c | 2 +-
lib/librte_eal/linuxapp/eal/eal_pci_vfio.c | 5 +-
lib/librte_eal/linuxapp/eal/rte_eal_version.map | 2 +
14 files changed, 208 insertions(+), 146 deletions(-)
--
2.7.4
^ permalink raw reply
* [PATCH v2 1/4] eal: generalize PCI kernel driver enum to EAL
From: Shreyansh Jain @ 2016-10-14 10:55 UTC (permalink / raw)
To: dev; +Cc: viktorin, thomas.monjalon, david.marchand, Shreyansh Jain
In-Reply-To: <1476442527-30726-1-git-send-email-shreyansh.jain@nxp.com>
From: Jan Viktorin <viktorin@rehivetech.com>
Signed-off-by: Jan Viktorin <viktorin@rehivetech.com>
Signed-off-by: Shreyansh Jain <shreyansh.jain@nxp.com>
--
Changes since v0:
- fix compilation error due to missing include
---
lib/librte_eal/common/include/rte_dev.h | 12 ++++++++++++
lib/librte_eal/common/include/rte_pci.h | 9 ---------
2 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index b3873bd..e73b0fa 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -109,6 +109,18 @@ struct rte_mem_resource {
void *addr; /**< Virtual address, NULL when not mapped. */
};
+/**
+ * Kernel driver passthrough type
+ */
+enum rte_kernel_driver {
+ RTE_KDRV_UNKNOWN = 0,
+ RTE_KDRV_IGB_UIO,
+ RTE_KDRV_VFIO,
+ RTE_KDRV_UIO_GENERIC,
+ RTE_KDRV_NIC_UIO,
+ RTE_KDRV_NONE,
+};
+
/** Double linked list of device drivers. */
TAILQ_HEAD(rte_driver_list, rte_driver);
/** Double linked list of devices. */
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 9ce8847..2c7046f 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -135,15 +135,6 @@ struct rte_pci_addr {
struct rte_devargs;
-enum rte_kernel_driver {
- RTE_KDRV_UNKNOWN = 0,
- RTE_KDRV_IGB_UIO,
- RTE_KDRV_VFIO,
- RTE_KDRV_UIO_GENERIC,
- RTE_KDRV_NIC_UIO,
- RTE_KDRV_NONE,
-};
-
/**
* A structure describing a PCI device.
*/
--
2.7.4
^ permalink raw reply related
* [PATCH v2 2/4] eal: generalize PCI map/unmap resource to EAL
From: Shreyansh Jain @ 2016-10-14 10:55 UTC (permalink / raw)
To: dev; +Cc: viktorin, thomas.monjalon, david.marchand, Shreyansh Jain
In-Reply-To: <1476442527-30726-1-git-send-email-shreyansh.jain@nxp.com>
From: Jan Viktorin <viktorin@rehivetech.com>
The functions pci_map_resource, pci_unmap_resource are generic so the
pci_* prefix can be omitted. The functions are moved to the
eal_common_dev.c so they can be reused by other infrastructure.
Signed-off-by: Jan Viktorin <viktorin@rehivetech.com>
Signed-off-by: Shreyansh Jain <shreyansh.jain@nxp.com>
---
lib/librte_eal/bsdapp/eal/eal_pci.c | 2 +-
lib/librte_eal/bsdapp/eal/rte_eal_version.map | 2 ++
lib/librte_eal/common/eal_common_dev.c | 39 +++++++++++++++++++++++++
lib/librte_eal/common/eal_common_pci.c | 39 -------------------------
lib/librte_eal/common/eal_common_pci_uio.c | 16 +++++-----
lib/librte_eal/common/include/rte_dev.h | 32 ++++++++++++++++++++
lib/librte_eal/common/include/rte_pci.h | 32 --------------------
lib/librte_eal/linuxapp/eal/eal_pci_uio.c | 2 +-
lib/librte_eal/linuxapp/eal/eal_pci_vfio.c | 5 ++--
lib/librte_eal/linuxapp/eal/rte_eal_version.map | 2 ++
10 files changed, 89 insertions(+), 82 deletions(-)
diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 8b3ed88..7ed0115 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -228,7 +228,7 @@ pci_uio_map_resource_by_index(struct rte_pci_device *dev, int res_idx,
/* if matching map is found, then use it */
offset = res_idx * pagesz;
- mapaddr = pci_map_resource(NULL, fd, (off_t)offset,
+ mapaddr = rte_eal_map_resource(NULL, fd, (off_t)offset,
(size_t)dev->mem_resource[res_idx].len, 0);
close(fd);
if (mapaddr == MAP_FAILED)
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index 2f81f7c..11d9f59 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -170,6 +170,8 @@ DPDK_16.11 {
rte_delay_us_callback_register;
rte_eal_dev_attach;
rte_eal_dev_detach;
+ rte_eal_map_resource;
+ rte_eal_unmap_resource;
rte_eal_vdrv_register;
rte_eal_vdrv_unregister;
diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 4f3b493..457d227 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -36,6 +36,7 @@
#include <string.h>
#include <inttypes.h>
#include <sys/queue.h>
+#include <sys/mman.h>
#include <rte_dev.h>
#include <rte_devargs.h>
@@ -151,3 +152,41 @@ err:
RTE_LOG(ERR, EAL, "Driver cannot detach the device (%s)\n", name);
return -EINVAL;
}
+
+/* map a particular resource from a file */
+void *
+rte_eal_map_resource(void *requested_addr, int fd, off_t offset, size_t size,
+ int additional_flags)
+{
+ void *mapaddr;
+
+ /* Map the Memory resource of device */
+ mapaddr = mmap(requested_addr, size, PROT_READ | PROT_WRITE,
+ MAP_SHARED | additional_flags, fd, offset);
+ if (mapaddr == MAP_FAILED) {
+ RTE_LOG(ERR, EAL, "%s(): cannot mmap(%d, %p, 0x%lx, 0x%lx): %s"
+ " (%p)\n", __func__, fd, requested_addr,
+ (unsigned long)size, (unsigned long)offset,
+ strerror(errno), mapaddr);
+ } else
+ RTE_LOG(DEBUG, EAL, " Device memory mapped at %p\n", mapaddr);
+
+ return mapaddr;
+}
+
+/* unmap a particular resource */
+void
+rte_eal_unmap_resource(void *requested_addr, size_t size)
+{
+ if (requested_addr == NULL)
+ return;
+
+ /* Unmap the Memory resource of device */
+ if (munmap(requested_addr, size)) {
+ RTE_LOG(ERR, EAL, "%s(): cannot munmap(%p, 0x%lx): %s\n",
+ __func__, requested_addr, (unsigned long)size,
+ strerror(errno));
+ } else
+ RTE_LOG(DEBUG, EAL, " Device memory unmapped at %p\n",
+ requested_addr);
+}
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index 638cd86..464acc1 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -67,7 +67,6 @@
#include <stdlib.h>
#include <stdio.h>
#include <sys/queue.h>
-#include <sys/mman.h>
#include <rte_interrupts.h>
#include <rte_log.h>
@@ -114,44 +113,6 @@ static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
return NULL;
}
-/* map a particular resource from a file */
-void *
-pci_map_resource(void *requested_addr, int fd, off_t offset, size_t size,
- int additional_flags)
-{
- void *mapaddr;
-
- /* Map the PCI memory resource of device */
- mapaddr = mmap(requested_addr, size, PROT_READ | PROT_WRITE,
- MAP_SHARED | additional_flags, fd, offset);
- if (mapaddr == MAP_FAILED) {
- RTE_LOG(ERR, EAL, "%s(): cannot mmap(%d, %p, 0x%lx, 0x%lx): %s (%p)\n",
- __func__, fd, requested_addr,
- (unsigned long)size, (unsigned long)offset,
- strerror(errno), mapaddr);
- } else
- RTE_LOG(DEBUG, EAL, " PCI memory mapped at %p\n", mapaddr);
-
- return mapaddr;
-}
-
-/* unmap a particular resource */
-void
-pci_unmap_resource(void *requested_addr, size_t size)
-{
- if (requested_addr == NULL)
- return;
-
- /* Unmap the PCI memory resource of device */
- if (munmap(requested_addr, size)) {
- RTE_LOG(ERR, EAL, "%s(): cannot munmap(%p, 0x%lx): %s\n",
- __func__, requested_addr, (unsigned long)size,
- strerror(errno));
- } else
- RTE_LOG(DEBUG, EAL, " PCI memory unmapped at %p\n",
- requested_addr);
-}
-
/*
* If vendor/device ID match, call the probe() function of the
* driver.
diff --git a/lib/librte_eal/common/eal_common_pci_uio.c b/lib/librte_eal/common/eal_common_pci_uio.c
index 367a681..3402518 100644
--- a/lib/librte_eal/common/eal_common_pci_uio.c
+++ b/lib/librte_eal/common/eal_common_pci_uio.c
@@ -75,9 +75,11 @@ pci_uio_map_secondary(struct rte_pci_device *dev)
return -1;
}
- void *mapaddr = pci_map_resource(uio_res->maps[i].addr,
- fd, (off_t)uio_res->maps[i].offset,
- (size_t)uio_res->maps[i].size, 0);
+ void *mapaddr = rte_eal_map_resource(
+ uio_res->maps[i].addr, fd,
+ (off_t)uio_res->maps[i].offset,
+ (size_t)uio_res->maps[i].size,
+ 0);
/* fd is not needed in slave process, close it */
close(fd);
if (mapaddr != uio_res->maps[i].addr) {
@@ -88,11 +90,11 @@ pci_uio_map_secondary(struct rte_pci_device *dev)
if (mapaddr != MAP_FAILED) {
/* unmap addrs correctly mapped */
for (j = 0; j < i; j++)
- pci_unmap_resource(
+ rte_eal_unmap_resource(
uio_res->maps[j].addr,
(size_t)uio_res->maps[j].size);
/* unmap addr wrongly mapped */
- pci_unmap_resource(mapaddr,
+ rte_eal_unmap_resource(mapaddr,
(size_t)uio_res->maps[i].size);
}
return -1;
@@ -150,7 +152,7 @@ pci_uio_map_resource(struct rte_pci_device *dev)
return 0;
error:
for (i = 0; i < map_idx; i++) {
- pci_unmap_resource(uio_res->maps[i].addr,
+ rte_eal_unmap_resource(uio_res->maps[i].addr,
(size_t)uio_res->maps[i].size);
rte_free(uio_res->maps[i].path);
}
@@ -167,7 +169,7 @@ pci_uio_unmap(struct mapped_pci_resource *uio_res)
return;
for (i = 0; i != uio_res->nb_maps; i++) {
- pci_unmap_resource(uio_res->maps[i].addr,
+ rte_eal_unmap_resource(uio_res->maps[i].addr,
(size_t)uio_res->maps[i].size);
if (rte_eal_process_type() == RTE_PROC_PRIMARY)
rte_free(uio_res->maps[i].path);
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index e73b0fa..277c07b 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -234,6 +234,38 @@ int rte_eal_dev_attach(const char *name, const char *devargs);
*/
int rte_eal_dev_detach(const char *name);
+/*
+ * @internal
+ * Map a particular resource from a file.
+ *
+ * @param requested_addr
+ * The starting address for the new mapping range.
+ * @param fd
+ * The file descriptor.
+ * @param offset
+ * The offset for the mapping range.
+ * @param size
+ * The size for the mapping range.
+ * @param additional_flags
+ * The additional flags for the mapping range.
+ * @return
+ * - On success, the function returns a pointer to the mapped area.
+ * - On error, the value MAP_FAILED is returned.
+ */
+void *rte_eal_map_resource(void *requested_addr, int fd, off_t offset,
+ size_t size, int additional_flags);
+
+/**
+ * @internal
+ * Unmap a particular resource.
+ *
+ * @param requested_addr
+ * The address for the unmapping range.
+ * @param size
+ * The size for the unmapping range.
+ */
+void rte_eal_unmap_resource(void *requested_addr, size_t size);
+
#define RTE_PMD_EXPORT_NAME_ARRAY(n, idx) n##idx[]
#define RTE_PMD_EXPORT_NAME(name, idx) \
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 2c7046f..7d6eef5 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -399,38 +399,6 @@ int rte_eal_pci_map_device(struct rte_pci_device *dev);
void rte_eal_pci_unmap_device(struct rte_pci_device *dev);
/**
- * @internal
- * Map a particular resource from a file.
- *
- * @param requested_addr
- * The starting address for the new mapping range.
- * @param fd
- * The file descriptor.
- * @param offset
- * The offset for the mapping range.
- * @param size
- * The size for the mapping range.
- * @param additional_flags
- * The additional flags for the mapping range.
- * @return
- * - On success, the function returns a pointer to the mapped area.
- * - On error, the value MAP_FAILED is returned.
- */
-void *pci_map_resource(void *requested_addr, int fd, off_t offset,
- size_t size, int additional_flags);
-
-/**
- * @internal
- * Unmap a particular resource.
- *
- * @param requested_addr
- * The address for the unmapping range.
- * @param size
- * The size for the unmapping range.
- */
-void pci_unmap_resource(void *requested_addr, size_t size);
-
-/**
* Probe the single PCI device.
*
* Scan the content of the PCI bus, and find the pci device specified by pci
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
index 1786b75..5c34421 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
@@ -347,7 +347,7 @@ pci_uio_map_resource_by_index(struct rte_pci_device *dev, int res_idx,
if (pci_map_addr == NULL)
pci_map_addr = pci_find_max_end_va();
- mapaddr = pci_map_resource(pci_map_addr, fd, 0,
+ mapaddr = rte_eal_map_resource(pci_map_addr, fd, 0,
(size_t)dev->mem_resource[res_idx].len, 0);
close(fd);
if (mapaddr == MAP_FAILED)
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c b/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c
index 5f478c5..5ad8cbe 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c
@@ -465,7 +465,8 @@ pci_vfio_map_resource(struct rte_pci_device *dev)
void *map_addr = NULL;
if (memreg[0].size) {
/* actual map of first part */
- map_addr = pci_map_resource(bar_addr, vfio_dev_fd,
+ map_addr = rte_eal_map_resource(bar_addr,
+ vfio_dev_fd,
memreg[0].offset,
memreg[0].size,
MAP_FIXED);
@@ -477,7 +478,7 @@ pci_vfio_map_resource(struct rte_pci_device *dev)
void *second_addr = RTE_PTR_ADD(bar_addr,
memreg[1].offset -
(uintptr_t)reg.offset);
- map_addr = pci_map_resource(second_addr,
+ map_addr = rte_eal_map_resource(second_addr,
vfio_dev_fd, memreg[1].offset,
memreg[1].size,
MAP_FIXED);
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index 83721ba..22b5b59 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -174,6 +174,8 @@ DPDK_16.11 {
rte_delay_us_callback_register;
rte_eal_dev_attach;
rte_eal_dev_detach;
+ rte_eal_map_resource;
+ rte_eal_unmap_resource;
rte_eal_vdrv_register;
rte_eal_vdrv_unregister;
--
2.7.4
^ permalink raw reply related
* [PATCH v2 3/4] eal/linux: generalize PCI kernel unbinding driver to EAL
From: Shreyansh Jain @ 2016-10-14 10:55 UTC (permalink / raw)
To: dev; +Cc: viktorin, thomas.monjalon, david.marchand, Shreyansh Jain
In-Reply-To: <1476442527-30726-1-git-send-email-shreyansh.jain@nxp.com>
From: Jan Viktorin <viktorin@rehivetech.com>
Generalize the PCI-specific pci_unbind_kernel_driver. It is now divided
into two parts. First, determination of the path and string identification
of the device to be unbound. Second, the actual unbind operation which is
generic.
BSD implementation updated as ENOTSUP
Signed-off-by: Jan Viktorin <viktorin@rehivetech.com>
Signed-off-by: Shreyansh Jain <shreyansh.jain@nxp.com>
--
Changes since v1:
- update BSD support for unbind kernel driver
---
lib/librte_eal/bsdapp/eal/eal.c | 7 +++++++
lib/librte_eal/bsdapp/eal/eal_pci.c | 4 ++--
lib/librte_eal/common/eal_private.h | 13 +++++++++++++
lib/librte_eal/linuxapp/eal/eal.c | 26 ++++++++++++++++++++++++++
lib/librte_eal/linuxapp/eal/eal_pci.c | 33 +++++++++------------------------
5 files changed, 57 insertions(+), 26 deletions(-)
diff --git a/lib/librte_eal/bsdapp/eal/eal.c b/lib/librte_eal/bsdapp/eal/eal.c
index 35e3117..5271fc2 100644
--- a/lib/librte_eal/bsdapp/eal/eal.c
+++ b/lib/librte_eal/bsdapp/eal/eal.c
@@ -633,3 +633,10 @@ rte_eal_process_type(void)
{
return rte_config.process_type;
}
+
+int
+rte_eal_unbind_kernel_driver(const char *devpath __rte_unused,
+ const char *devid __rte_unused)
+{
+ return -ENOTSUP;
+}
diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 7ed0115..703f034 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -89,11 +89,11 @@
/* unbind kernel driver for this device */
int
-pci_unbind_kernel_driver(struct rte_pci_device *dev __rte_unused)
+pci_unbind_kernel_driver(struct rte_pci_device *dev)
{
RTE_LOG(ERR, EAL, "RTE_PCI_DRV_FORCE_UNBIND flag is not implemented "
"for BSD\n");
- return -ENOTSUP;
+ return rte_eal_unbind_kernel_driver(dev);
}
/* Map pci device */
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index 9e7d8f6..b0c208a 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -256,6 +256,19 @@ int rte_eal_alarm_init(void);
int rte_eal_check_module(const char *module_name);
/**
+ * Unbind kernel driver bound to the device specified by the given devpath,
+ * and its string identification.
+ *
+ * @param devpath path to the device directory ("/sys/.../devices/<name>")
+ * @param devid identification of the device (<name>)
+ *
+ * @return
+ * -1 unbind has failed
+ * 0 module has been unbound
+ */
+int rte_eal_unbind_kernel_driver(const char *devpath, const char *devid);
+
+/**
* Get cpu core_id.
*
* This function is private to the EAL.
diff --git a/lib/librte_eal/linuxapp/eal/eal.c b/lib/librte_eal/linuxapp/eal/eal.c
index 2075282..5f6676d 100644
--- a/lib/librte_eal/linuxapp/eal/eal.c
+++ b/lib/librte_eal/linuxapp/eal/eal.c
@@ -943,3 +943,29 @@ rte_eal_check_module(const char *module_name)
/* Module has been found */
return 1;
}
+
+int
+rte_eal_unbind_kernel_driver(const char *devpath, const char *devid)
+{
+ char filename[PATH_MAX];
+ FILE *f;
+
+ snprintf(filename, sizeof(filename),
+ "%s/driver/unbind", devpath);
+
+ f = fopen(filename, "w");
+ if (f == NULL) /* device was not bound */
+ return 0;
+
+ if (fwrite(devid, strlen(devid), 1, f) == 0) {
+ RTE_LOG(ERR, EAL, "%s(): could not write to %s\n", __func__,
+ filename);
+ goto error;
+ }
+
+ fclose(f);
+ return 0;
+error:
+ fclose(f);
+ return -1;
+}
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 876ba38..a03553f 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -59,38 +59,23 @@ int
pci_unbind_kernel_driver(struct rte_pci_device *dev)
{
int n;
- FILE *f;
- char filename[PATH_MAX];
- char buf[BUFSIZ];
+ char devpath[PATH_MAX];
+ char devid[BUFSIZ];
struct rte_pci_addr *loc = &dev->addr;
- /* open /sys/bus/pci/devices/AAAA:BB:CC.D/driver */
- snprintf(filename, sizeof(filename),
- "%s/" PCI_PRI_FMT "/driver/unbind", pci_get_sysfs_path(),
+ /* devpath /sys/bus/pci/devices/AAAA:BB:CC.D */
+ snprintf(devpath, sizeof(devpath),
+ "%s/" PCI_PRI_FMT, pci_get_sysfs_path(),
loc->domain, loc->bus, loc->devid, loc->function);
- f = fopen(filename, "w");
- if (f == NULL) /* device was not bound */
- return 0;
-
- n = snprintf(buf, sizeof(buf), PCI_PRI_FMT "\n",
+ n = snprintf(devid, sizeof(devid), PCI_PRI_FMT "\n",
loc->domain, loc->bus, loc->devid, loc->function);
- if ((n < 0) || (n >= (int)sizeof(buf))) {
+ if ((n < 0) || (n >= (int)sizeof(devid))) {
RTE_LOG(ERR, EAL, "%s(): snprintf failed\n", __func__);
- goto error;
- }
- if (fwrite(buf, n, 1, f) == 0) {
- RTE_LOG(ERR, EAL, "%s(): could not write to %s\n", __func__,
- filename);
- goto error;
+ return -1;
}
- fclose(f);
- return 0;
-
-error:
- fclose(f);
- return -1;
+ return rte_eal_unbind_kernel_driver(devpath, devid);
}
static int
--
2.7.4
^ permalink raw reply related
* [PATCH v2 4/4] eal/linux: generalize PCI kernel driver extraction to EAL
From: Shreyansh Jain @ 2016-10-14 10:55 UTC (permalink / raw)
To: dev; +Cc: viktorin, thomas.monjalon, david.marchand, Shreyansh Jain
In-Reply-To: <1476442527-30726-1-git-send-email-shreyansh.jain@nxp.com>
From: Jan Viktorin <viktorin@rehivetech.com>
Generalize the PCI-specific pci_get_kernel_driver_by_path. The function
is general enough, we have just moved it to eal.c, changed the prefix to
rte_eal and provided it privately to other parts of EAL.
Signed-off-by: Jan Viktorin <viktorin@rehivetech.com>
Signed-off-by: Shreyansh Jain <shreyansh.jain@nxp.com>
--
Changes since v1:
- update BSD support for unbind kernel driver
---
lib/librte_eal/bsdapp/eal/eal.c | 7 +++++++
lib/librte_eal/common/eal_private.h | 14 ++++++++++++++
lib/librte_eal/linuxapp/eal/eal.c | 29 +++++++++++++++++++++++++++++
lib/librte_eal/linuxapp/eal/eal_pci.c | 31 +------------------------------
4 files changed, 51 insertions(+), 30 deletions(-)
diff --git a/lib/librte_eal/bsdapp/eal/eal.c b/lib/librte_eal/bsdapp/eal/eal.c
index 5271fc2..9b93da3 100644
--- a/lib/librte_eal/bsdapp/eal/eal.c
+++ b/lib/librte_eal/bsdapp/eal/eal.c
@@ -640,3 +640,10 @@ rte_eal_unbind_kernel_driver(const char *devpath __rte_unused,
{
return -ENOTSUP;
}
+
+int
+rte_eal_get_kernel_driver_by_path(const char *filename __rte_unused,
+ char *dri_name __rte_unused)
+{
+ return -ENOTSUP;
+}
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index b0c208a..c8c2131 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -269,6 +269,20 @@ int rte_eal_check_module(const char *module_name);
int rte_eal_unbind_kernel_driver(const char *devpath, const char *devid);
/**
+ * Extract the kernel driver name from the absolute path to the driver.
+ *
+ * @param filename path to the driver ("<path-to-device>/driver")
+ * @path dri_name target buffer where to place the driver name
+ * (should be at least PATH_MAX long)
+ *
+ * @return
+ * -1 on failure
+ * 0 when successful
+ * 1 when there is no such driver
+ */
+int rte_eal_get_kernel_driver_by_path(const char *filename, char *dri_name);
+
+/**
* Get cpu core_id.
*
* This function is private to the EAL.
diff --git a/lib/librte_eal/linuxapp/eal/eal.c b/lib/librte_eal/linuxapp/eal/eal.c
index 5f6676d..00af21c 100644
--- a/lib/librte_eal/linuxapp/eal/eal.c
+++ b/lib/librte_eal/linuxapp/eal/eal.c
@@ -969,3 +969,32 @@ error:
fclose(f);
return -1;
}
+
+int
+rte_eal_get_kernel_driver_by_path(const char *filename, char *dri_name)
+{
+ int count;
+ char path[PATH_MAX];
+ char *name;
+
+ if (!filename || !dri_name)
+ return -1;
+
+ count = readlink(filename, path, PATH_MAX);
+ if (count >= PATH_MAX)
+ return -1;
+
+ /* For device does not have a driver */
+ if (count < 0)
+ return 1;
+
+ path[count] = '\0';
+
+ name = strrchr(path, '/');
+ if (name) {
+ strncpy(dri_name, name + 1, strlen(name + 1) + 1);
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index a03553f..e1cf9e8 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -78,35 +78,6 @@ pci_unbind_kernel_driver(struct rte_pci_device *dev)
return rte_eal_unbind_kernel_driver(devpath, devid);
}
-static int
-pci_get_kernel_driver_by_path(const char *filename, char *dri_name)
-{
- int count;
- char path[PATH_MAX];
- char *name;
-
- if (!filename || !dri_name)
- return -1;
-
- count = readlink(filename, path, PATH_MAX);
- if (count >= PATH_MAX)
- return -1;
-
- /* For device does not have a driver */
- if (count < 0)
- return 1;
-
- path[count] = '\0';
-
- name = strrchr(path, '/');
- if (name) {
- strncpy(dri_name, name + 1, strlen(name + 1) + 1);
- return 0;
- }
-
- return -1;
-}
-
/* Map pci device */
int
rte_eal_pci_map_device(struct rte_pci_device *dev)
@@ -354,7 +325,7 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
/* parse driver */
snprintf(filename, sizeof(filename), "%s/driver", dirname);
- ret = pci_get_kernel_driver_by_path(filename, driver);
+ ret = rte_eal_get_kernel_driver_by_path(filename, driver);
if (ret < 0) {
RTE_LOG(ERR, EAL, "Fail to get kernel driver\n");
free(dev);
--
2.7.4
^ permalink raw reply related
* [PATCH] kni: fix unused variable compile error
From: Ferruh Yigit @ 2016-10-14 11:24 UTC (permalink / raw)
To: dev; +Cc: Ferruh Yigit
compile error:
CC [M] .../lib/librte_eal/linuxapp/kni/kni_misc.o
cc1: warnings being treated as errors
.../lib/librte_eal/linuxapp/kni/kni_misc.c: In function ‘kni_exit_net’:
.../lib/librte_eal/linuxapp/kni/kni_misc.c:113:18:
error: unused variable ‘knet’
For some kernel versions mutex_destroy() is macro and does nothing,
this cause an unused variable warning for knet which used in mutex_destroy
Added unused attribute to the knet variable.
Fixes: 93a298b34e1b ("kni: support core id parameter in single threaded mode")
Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
---
lib/librte_eal/linuxapp/kni/kni_misc.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/lib/librte_eal/linuxapp/kni/kni_misc.c b/lib/librte_eal/linuxapp/kni/kni_misc.c
index 3303d9b..497db9b 100644
--- a/lib/librte_eal/linuxapp/kni/kni_misc.c
+++ b/lib/librte_eal/linuxapp/kni/kni_misc.c
@@ -110,9 +110,11 @@ kni_init_net(struct net *net)
static void __net_exit
kni_exit_net(struct net *net)
{
- struct kni_net *knet = net_generic(net, kni_net_id);
+ struct kni_net *knet __maybe_unused;
+ knet = net_generic(net, kni_net_id);
mutex_destroy(&knet->kni_kthread_lock);
+
#ifndef HAVE_SIMPLIFIED_PERNET_OPERATIONS
kfree(knet);
#endif
--
2.7.4
^ permalink raw reply related
* Re: [PATCH v3 2/2] mempool: pktmbuf pool default fallback for mempool ops error
From: Olivier Matz @ 2016-10-14 12:10 UTC (permalink / raw)
To: Hemant Agrawal; +Cc: dev, jerin.jacob, david.hunt
In-Reply-To: <7e26965e-173b-1cf6-0beb-c94712ad615a@nxp.com>
Hi Hemant,
Sorry for the late answer. Please see some comments inline.
On 10/13/2016 03:15 PM, Hemant Agrawal wrote:
> Hi Olivier,
> Any updates w.r.t this patch set?
>
> Regards
> Hemant
> On 9/22/2016 6:42 PM, Hemant Agrawal wrote:
>> Hi Olivier
>>
>> On 9/19/2016 7:27 PM, Olivier Matz wrote:
>>> Hi Hemant,
>>>
>>> On 09/16/2016 06:46 PM, Hemant Agrawal wrote:
>>>> In the rte_pktmbuf_pool_create, if the default external mempool is
>>>> not available, the implementation can default to "ring_mp_mc", which
>>>> is an software implementation.
>>>>
>>>> Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
>>>> ---
>>>> Changes in V3:
>>>> * adding warning message to say that falling back to default sw pool
>>>> ---
>>>> lib/librte_mbuf/rte_mbuf.c | 8 ++++++++
>>>> 1 file changed, 8 insertions(+)
>>>>
>>>> diff --git a/lib/librte_mbuf/rte_mbuf.c b/lib/librte_mbuf/rte_mbuf.c
>>>> index 4846b89..8ab0eb1 100644
>>>> --- a/lib/librte_mbuf/rte_mbuf.c
>>>> +++ b/lib/librte_mbuf/rte_mbuf.c
>>>> @@ -176,6 +176,14 @@ rte_pktmbuf_pool_create(const char *name,
>>>> unsigned n,
>>>>
>>>> rte_errno = rte_mempool_set_ops_byname(mp,
>>>> RTE_MBUF_DEFAULT_MEMPOOL_OPS, NULL);
>>>> +
>>>> + /* on error, try falling back to the software based default
>>>> pool */
>>>> + if (rte_errno == -EOPNOTSUPP) {
>>>> + RTE_LOG(WARNING, MBUF, "Default HW Mempool not supported. "
>>>> + "falling back to sw mempool \"ring_mp_mc\"");
>>>> + rte_errno = rte_mempool_set_ops_byname(mp, "ring_mp_mc",
>>>> NULL);
>>>> + }
>>>> +
>>>> if (rte_errno != 0) {
>>>> RTE_LOG(ERR, MBUF, "error setting mempool handler\n");
>>>> return NULL;
>>>>
>>>
>>> Without adding a new method ".supported()", the first call to
>>> rte_mempool_populate() could return the same error ENOTSUP. In this
>>> case, it is still possible to fallback.
>>>
>> It will be bit late.
>>
>> On failure, than we have to set the default ops and do a goto before
>> rte_pktmbuf_pool_init(mp, &mbp_priv);
I still think we can do the job without adding the .supported() method.
The following code is just an (untested) example:
struct rte_mempool *
rte_pktmbuf_pool_create(const char *name, unsigned n,
unsigned cache_size, uint16_t priv_size, uint16_t data_room_size,
int socket_id)
{
struct rte_mempool *mp;
struct rte_pktmbuf_pool_private mbp_priv;
unsigned elt_size;
int ret;
const char *ops[] = {
RTE_MBUF_DEFAULT_MEMPOOL_OPS, "ring_mp_mc", NULL,
};
const char **op;
if (RTE_ALIGN(priv_size, RTE_MBUF_PRIV_ALIGN) != priv_size) {
RTE_LOG(ERR, MBUF, "mbuf priv_size=%u is not aligned\n",
priv_size);
rte_errno = EINVAL;
return NULL;
}
elt_size = sizeof(struct rte_mbuf) + (unsigned)priv_size +
(unsigned)data_room_size;
mbp_priv.mbuf_data_room_size = data_room_size;
mbp_priv.mbuf_priv_size = priv_size;
for (op = &ops[0]; *op != NULL; op++) {
mp = rte_mempool_create_empty(name, n, elt_size, cache_size,
sizeof(struct rte_pktmbuf_pool_private), socket_id, 0);
if (mp == NULL)
return NULL;
ret = rte_mempool_set_ops_byname(mp, *op, NULL);
if (ret != 0) {
RTE_LOG(ERR, MBUF, "error setting mempool handler\n");
rte_mempool_free(mp);
if (ret == -ENOTSUP)
continue;
rte_errno = -ret;
return NULL;
}
rte_pktmbuf_pool_init(mp, &mbp_priv);
ret = rte_mempool_populate_default(mp);
if (ret < 0) {
rte_mempool_free(mp);
if (ret == -ENOTSUP)
continue;
rte_errno = -ret;
return NULL;
}
}
rte_mempool_obj_iter(mp, rte_pktmbuf_init, NULL);
return mp;
}
>>> I've just submitted an RFC, which I think is quite linked:
>>> http://dpdk.org/ml/archives/dev/2016-September/046974.html
>>> Assuming a new parameter "mempool_ops" is added to
>>> rte_pktmbuf_pool_create(), would it make sense to fallback to
>>> "ring_mp_mc"? What about just returning ENOTSUP? The application could
>>> do the job and decide which sw fallback to use.
>>
>> We ran into this issue when trying to run the standard DPDK examples
>> (l3fwd) in VM. Do you think, is it practical to add fallback handling in
>> each of the DPDK examples?
OK. What is still unclear for me, is how the software is aware of the
different hardware-assisted handlers. Moreover, we could imagine more
software handlers, which could be used depending on the use case.
I think this choice has to be made by the user or the application:
- the application may want to use a specific (sw or hw) handler: in
this case, it want to be notified if it fails, instead of having
a quiet fallback to ring_mp_mc
- if several handlers are available, the application may want to
try them in a specific order
- maybe some handlers will have some limitations with some
configurations or driver? The application could decide to use
a different handler according the configuration.
So that's why I think this is an application decision.
>> Typically when someone is writing a application on host, he need not
>> worry non-availability of the hw offloaded mempool. He may also want to
>> run the same binary in virtual machine. In VM, it is not guaranteed that
>> hw offloaded mempools will be available.
Running the same binary is of course a need. But if your VM does not
provide the same virtualized hardware than the host, I think the command
line option makes sense.
AFAIU, on the host, you can use a hw mempool handler or a sw one, and
on the guest, only a sw one. So you need an option to select the
behavior you want on the host, without recompiling.
I understand that modifying all the applications is not a good option
either. I'm thinking a a EAL parameter that would allow to configure a
library (mbuf in this case). Something like kernel boot options.
Example: testpmd -l 2,4 --opt mbuf.handler="ring_mp_mc" -- [app args]
I don't know if this is feasible, this has to be discussed first, but
what do you think on the principle? The value could also be an
ordered list if we want a fallback, and this option could be overriden
by the application before creating the mbuf pool. There was some
discussions about a kind of dpdk global configuration some time ago.
Regards,
Olivier
^ permalink raw reply
* Re: [PATCH] kni: fix unused variable compile error
From: Thomas Monjalon @ 2016-10-14 12:30 UTC (permalink / raw)
To: Ferruh Yigit; +Cc: dev
In-Reply-To: <20161014112440.12966-1-ferruh.yigit@intel.com>
2016-10-14 12:24, Ferruh Yigit:
> compile error:
> CC [M] .../lib/librte_eal/linuxapp/kni/kni_misc.o
> cc1: warnings being treated as errors
> .../lib/librte_eal/linuxapp/kni/kni_misc.c: In function ‘kni_exit_net’:
> .../lib/librte_eal/linuxapp/kni/kni_misc.c:113:18:
> error: unused variable ‘knet’
>
> For some kernel versions mutex_destroy() is macro and does nothing,
> this cause an unused variable warning for knet which used in mutex_destroy
>
> Added unused attribute to the knet variable.
>
> Fixes: 93a298b34e1b ("kni: support core id parameter in single threaded mode")
>
> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
That's why supporting an out-of-tree kernel module is a nightmare.
Compilation breaks everytime with various kernels :(
Please could you tell which Linux versions are affected?
^ permalink raw reply
* Re: [RFC] [PATCH v2] libeventdev: event driven programming model framework for DPDK
From: Jerin Jacob @ 2016-10-14 12:52 UTC (permalink / raw)
To: Hemant Agrawal
Cc: Bill Fischofer, dev@dpdk.org, thomas.monjalon@6wind.com,
bruce.richardson@intel.com, narender.vangati@intel.com,
gage.eads@intel.com
In-Reply-To: <DB5PR04MB1605D0F7FAAEB2484BEFF76689DF0@DB5PR04MB1605.eurprd04.prod.outlook.com>
On Fri, Oct 14, 2016 at 10:30:33AM +0000, Hemant Agrawal wrote:
> > > Am I reading this correctly that there is no way to support an
> > > indefinite waiting capability? Or is this just saying that if a timed
> > > wait is performed there are min/max limits for the wait duration?
> >
> > Application can wait indefinite if required. see
> > RTE_EVENT_DEV_CFG_PER_DEQUEUE_WAIT configuration option.
> >
> > Trivial application may not need different wait values on each dequeue.This is a
> > performance optimization opportunity for implementation.
>
> Jerin, It is irrespective of wait configuration, whether you are using per device wait or per dequeuer wait.
> Can the value of MAX_U32 or MAX_U64 be treated as infinite weight?
That will be yet another check in the fast path in the implementation, I
think, for more fine-grained wait scheme. Let application configure the device
with RTE_EVENT_DEV_CFG_PER_DEQUEUE_WAIT so that the application can have
two different function pointer-based implementation for dequeue function
if required.
With RTE_EVENT_DEV_CFG_PER_DEQUEUE_WAIT configuration, implicitly
MAX_U64 becomes infinite weight as the wait is uint64_t.
I can add this info in v3 if required.
Jerin
>
> >
^ permalink raw reply
* Re: [PATCH v2 2/5] i40e: implement vector PMD for ARM architecture
From: Jerin Jacob @ 2016-10-14 13:26 UTC (permalink / raw)
To: Jianbo Liu; +Cc: helin.zhang, jingjing.wu, dev, qi.z.zhang
In-Reply-To: <1476417604-22400-3-git-send-email-jianbo.liu@linaro.org>
On Fri, Oct 14, 2016 at 09:30:01AM +0530, Jianbo Liu wrote:
> Use ARM NEON intrinsic to implement i40e vPMD
>
> Signed-off-by: Jianbo Liu <jianbo.liu@linaro.org>
I'm not entirely familiar with i40e internals.The patch looks OK interms
of using NEON instructions.
Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> ---
> drivers/net/i40e/Makefile | 4 +
> drivers/net/i40e/i40e_rxtx_vec_neon.c | 614 ++++++++++++++++++++++++++++++++++
> 2 files changed, 618 insertions(+)
> create mode 100644 drivers/net/i40e/i40e_rxtx_vec_neon.c
>
^ permalink raw reply
* Re: [PATCH v2 3/5] i40e: enable i40e vector PMD on ARMv8a platform
From: Jerin Jacob @ 2016-10-14 13:28 UTC (permalink / raw)
To: Jianbo Liu; +Cc: helin.zhang, jingjing.wu, dev, qi.z.zhang
In-Reply-To: <1476417604-22400-4-git-send-email-jianbo.liu@linaro.org>
On Fri, Oct 14, 2016 at 09:30:02AM +0530, Jianbo Liu wrote:
> Signed-off-by: Jianbo Liu <jianbo.liu@linaro.org>
Reviewed-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> ---
> config/defconfig_arm64-armv8a-linuxapp-gcc | 1 -
> doc/guides/nics/features/i40e_vec.ini | 1 +
> doc/guides/nics/features/i40e_vf_vec.ini | 1 +
> 3 files changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/config/defconfig_arm64-armv8a-linuxapp-gcc b/config/defconfig_arm64-armv8a-linuxapp-gcc
> index a0f4473..6321884 100644
> --- a/config/defconfig_arm64-armv8a-linuxapp-gcc
> +++ b/config/defconfig_arm64-armv8a-linuxapp-gcc
> @@ -45,6 +45,5 @@ CONFIG_RTE_TOOLCHAIN_GCC=y
> CONFIG_RTE_EAL_IGB_UIO=n
>
> CONFIG_RTE_LIBRTE_FM10K_PMD=n
> -CONFIG_RTE_LIBRTE_I40E_INC_VECTOR=n
>
> CONFIG_RTE_SCHED_VECTOR=n
> diff --git a/doc/guides/nics/features/i40e_vec.ini b/doc/guides/nics/features/i40e_vec.ini
> index 0953d84..edd6b71 100644
> --- a/doc/guides/nics/features/i40e_vec.ini
> +++ b/doc/guides/nics/features/i40e_vec.ini
> @@ -37,3 +37,4 @@ Linux UIO = Y
> Linux VFIO = Y
> x86-32 = Y
> x86-64 = Y
> +ARMv8 = Y
> diff --git a/doc/guides/nics/features/i40e_vf_vec.ini b/doc/guides/nics/features/i40e_vf_vec.ini
> index 2a44bf6..d6674f7 100644
> --- a/doc/guides/nics/features/i40e_vf_vec.ini
> +++ b/doc/guides/nics/features/i40e_vf_vec.ini
> @@ -26,3 +26,4 @@ Linux UIO = Y
> Linux VFIO = Y
> x86-32 = Y
> x86-64 = Y
> +ARMv8 = Y
> --
> 2.4.11
>
^ permalink raw reply
* [PATCH v2] net/ixgbe: support multiqueue mode VMDq DCB with SRIOV
From: Bernard Iremonger @ 2016-10-14 13:29 UTC (permalink / raw)
To: dev, rahul.r.shah, wenzhuo.lu; +Cc: Bernard Iremonger
In-Reply-To: <1472202487-20119-1-git-send-email-bernard.iremonger@intel.com>
modify ixgbe_dcb_tx_hw_config function.
modify ixgbe_dev_mq_rx_configure function.
modify ixgbe_configure_dcb function.
Changes in v2:
Rebased to DPDK v16.11-rc1
Signed-off-by: Rahul R Shah <rahul.r.shah@intel.com>
Signed-off-by: Bernard Iremonger <bernard.iremonger@intel.com>
---
drivers/net/ixgbe/ixgbe_ethdev.c | 9 ++++-----
drivers/net/ixgbe/ixgbe_rxtx.c | 37 +++++++++++++++++++++----------------
2 files changed, 25 insertions(+), 21 deletions(-)
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 4ca5747..114698d 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -1977,6 +1977,8 @@ ixgbe_check_mq_mode(struct rte_eth_dev *dev)
/* check multi-queue mode */
switch (dev_conf->rxmode.mq_mode) {
case ETH_MQ_RX_VMDQ_DCB:
+ PMD_INIT_LOG(INFO, "ETH_MQ_RX_VMDQ_DCB mode supported in SRIOV");
+ break;
case ETH_MQ_RX_VMDQ_DCB_RSS:
/* DCB/RSS VMDQ in SRIOV mode, not implement yet */
PMD_INIT_LOG(ERR, "SRIOV active,"
@@ -2012,11 +2014,8 @@ ixgbe_check_mq_mode(struct rte_eth_dev *dev)
switch (dev_conf->txmode.mq_mode) {
case ETH_MQ_TX_VMDQ_DCB:
- /* DCB VMDQ in SRIOV mode, not implement yet */
- PMD_INIT_LOG(ERR, "SRIOV is active,"
- " unsupported VMDQ mq_mode tx %d.",
- dev_conf->txmode.mq_mode);
- return -EINVAL;
+ PMD_INIT_LOG(INFO, "ETH_MQ_TX_VMDQ_DCB mode supported in SRIOV");
+ break;
default: /* ETH_MQ_TX_VMDQ_ONLY or ETH_MQ_TX_NONE */
dev->data->dev_conf.txmode.mq_mode = ETH_MQ_TX_VMDQ_ONLY;
break;
diff --git a/drivers/net/ixgbe/ixgbe_rxtx.c b/drivers/net/ixgbe/ixgbe_rxtx.c
index 2ce8234..bb13889 100644
--- a/drivers/net/ixgbe/ixgbe_rxtx.c
+++ b/drivers/net/ixgbe/ixgbe_rxtx.c
@@ -1,7 +1,7 @@
/*-
* BSD LICENSE
*
- * Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
* Copyright 2014 6WIND S.A.
* All rights reserved.
*
@@ -3313,15 +3313,16 @@ ixgbe_vmdq_dcb_configure(struct rte_eth_dev *dev)
/**
* ixgbe_dcb_config_tx_hw_config - Configure general DCB TX parameters
- * @hw: pointer to hardware structure
+ * @dev: pointer to eth_dev structure
* @dcb_config: pointer to ixgbe_dcb_config structure
*/
static void
-ixgbe_dcb_tx_hw_config(struct ixgbe_hw *hw,
+ixgbe_dcb_tx_hw_config(struct rte_eth_dev *dev,
struct ixgbe_dcb_config *dcb_config)
{
uint32_t reg;
uint32_t q;
+ struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
PMD_INIT_FUNC_TRACE();
if (hw->mac.type != ixgbe_mac_82598EB) {
@@ -3339,11 +3340,17 @@ ixgbe_dcb_tx_hw_config(struct ixgbe_hw *hw,
if (dcb_config->vt_mode)
reg |= IXGBE_MTQC_VT_ENA;
IXGBE_WRITE_REG(hw, IXGBE_MTQC, reg);
-
- /* Disable drop for all queues */
- for (q = 0; q < 128; q++)
- IXGBE_WRITE_REG(hw, IXGBE_QDE,
- (IXGBE_QDE_WRITE | (q << IXGBE_QDE_IDX_SHIFT)));
+ if (RTE_ETH_DEV_SRIOV(dev).active == 0) {
+ /* Disable drop for all queues in VMDQ mode*/
+ for (q = 0; q < 128; q++)
+ IXGBE_WRITE_REG(hw, IXGBE_QDE,
+ (IXGBE_QDE_WRITE | (q << IXGBE_QDE_IDX_SHIFT) | IXGBE_QDE_ENABLE));
+ } else {
+ /* Enable drop for all queues in SRIOV mode */
+ for (q = 0; q < 128; q++)
+ IXGBE_WRITE_REG(hw, IXGBE_QDE,
+ (IXGBE_QDE_WRITE | (q << IXGBE_QDE_IDX_SHIFT)));
+ }
/* Enable the Tx desc arbiter */
reg = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
@@ -3378,7 +3385,7 @@ ixgbe_vmdq_dcb_hw_tx_config(struct rte_eth_dev *dev,
vmdq_tx_conf->nb_queue_pools == ETH_16_POOLS ? 0xFFFF : 0xFFFFFFFF);
/*Configure general DCB TX parameters*/
- ixgbe_dcb_tx_hw_config(hw, dcb_config);
+ ixgbe_dcb_tx_hw_config(dev, dcb_config);
}
static void
@@ -3661,7 +3668,7 @@ ixgbe_dcb_hw_configure(struct rte_eth_dev *dev,
/*get DCB TX configuration parameters from rte_eth_conf*/
ixgbe_dcb_tx_config(dev, dcb_config);
/*Configure general DCB TX parameters*/
- ixgbe_dcb_tx_hw_config(hw, dcb_config);
+ ixgbe_dcb_tx_hw_config(dev, dcb_config);
break;
default:
PMD_INIT_LOG(ERR, "Incorrect DCB TX mode configuration");
@@ -3810,9 +3817,6 @@ void ixgbe_configure_dcb(struct rte_eth_dev *dev)
(dev_conf->rxmode.mq_mode != ETH_MQ_RX_DCB_RSS))
return;
- if (dev->data->nb_rx_queues != ETH_DCB_NUM_QUEUES)
- return;
-
/** Configure DCB hardware **/
ixgbe_dcb_hw_configure(dev, dcb_cfg);
}
@@ -4082,12 +4086,13 @@ ixgbe_dev_mq_rx_configure(struct rte_eth_dev *dev)
case ETH_MQ_RX_VMDQ_RSS:
ixgbe_config_vf_rss(dev);
break;
-
- /* FIXME if support DCB/RSS together with VMDq & SRIOV */
case ETH_MQ_RX_VMDQ_DCB:
+ ixgbe_vmdq_dcb_configure(dev);
+ break;
+ /* FIXME if support DCB/RSS together with VMDq & SRIOV */
case ETH_MQ_RX_VMDQ_DCB_RSS:
PMD_INIT_LOG(ERR,
- "Could not support DCB with VMDq & SRIOV");
+ "Could not support DCB/RSS with VMDq & SRIOV");
return -1;
default:
ixgbe_config_vf_default(dev);
--
2.10.1
^ permalink raw reply related
* Re: [PATCH v5 1/6] ethdev: add Tx preparation
From: Kulasek, TomaszX @ 2016-10-14 14:02 UTC (permalink / raw)
To: Thomas Monjalon; +Cc: dev@dpdk.org, Ananyev, Konstantin
In-Reply-To: <8024593.WaNfoiub2G@xps13>
Hi Thomas,
> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Thursday, October 13, 2016 21:21
> To: Kulasek, TomaszX <tomaszx.kulasek@intel.com>
> Cc: dev@dpdk.org; Ananyev, Konstantin <konstantin.ananyev@intel.com>
> Subject: Re: [PATCH v5 1/6] ethdev: add Tx preparation
>
> Hi,
>
> 2016-10-13 19:36, Tomasz Kulasek:
> > Added API for `rte_eth_tx_prep`
> >
> > uint16_t rte_eth_tx_prep(uint8_t port_id, uint16_t queue_id,
> > struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
> >
> > Added fields to the `struct rte_eth_desc_lim`:
> >
> > uint16_t nb_seg_max;
> > /**< Max number of segments per whole packet. */
> >
> > uint16_t nb_mtu_seg_max;
> > /**< Max number of segments per one MTU */
> >
> > Created `rte_pkt.h` header with common used functions:
>
> Same comment as in previous revision:
> this description lacks the usability and performance considerations.
>
> > +static inline uint16_t
> > +rte_eth_tx_prep(uint8_t port_id __rte_unused, uint16_t queue_id
> __rte_unused,
> > + struct rte_mbuf **tx_pkts __rte_unused, uint16_t nb_pkts)
>
> Doxygen still do not parse it well (same issue as previous revision).
>
> > +/**
> > + * Fix pseudo header checksum for TSO and non-TSO tcp/udp packets
> before
> > + * hardware tx checksum.
> > + * For non-TSO tcp/udp packets full pseudo-header checksum is counted
> and set.
> > + * For TSO the IP payload length is not included.
> > + */
> > +static inline int
> > +rte_phdr_cksum_fix(struct rte_mbuf *m)
>
> You probably don't need this function since the recent improvements from
> Olivier.
Do you mean this improvement: "net: add function to calculate a checksum in a mbuf"
http://dpdk.org/dev/patchwork/patch/16542/
I see only full raw checksum computation on mbuf in Olivier patches, while this function counts only pseudo-header checksum to be used with tx offload.
Tomasz
^ permalink raw reply
* Re: [PATCH v5 1/6] ethdev: add Tx preparation
From: Thomas Monjalon @ 2016-10-14 14:20 UTC (permalink / raw)
To: Kulasek, TomaszX; +Cc: dev, Ananyev, Konstantin, olivier.matz
In-Reply-To: <3042915272161B4EB253DA4D77EB373A14F35FFC@IRSMSX102.ger.corp.intel.com>
2016-10-14 14:02, Kulasek, TomaszX:
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > 2016-10-13 19:36, Tomasz Kulasek:
> > > +/**
> > > + * Fix pseudo header checksum for TSO and non-TSO tcp/udp packets
> > before
> > > + * hardware tx checksum.
> > > + * For non-TSO tcp/udp packets full pseudo-header checksum is counted
> > and set.
> > > + * For TSO the IP payload length is not included.
> > > + */
> > > +static inline int
> > > +rte_phdr_cksum_fix(struct rte_mbuf *m)
> >
> > You probably don't need this function since the recent improvements from
> > Olivier.
>
> Do you mean this improvement: "net: add function to calculate a checksum in a mbuf"
> http://dpdk.org/dev/patchwork/patch/16542/
>
> I see only full raw checksum computation on mbuf in Olivier patches, while this function counts only pseudo-header checksum to be used with tx offload.
OK. Please check what exists already in librte_net (especially rte_ip.h)
and try to re-use code if possible. Thanks
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox