This patch extracts the virtqueue initialization out of
the Virtio ethdev queue initialization, as preliminary
work to provide a way for Virtio-user to allocate its
shadow control virtqueue.

Signed-off-by: Maxime Coquelin <maxime.coque...@redhat.com>
Reviewed-by: Chenbo Xia <chenbo....@intel.com>
---
 drivers/net/virtio/virtio_ethdev.c | 261 ++--------------------------
 drivers/net/virtio/virtqueue.c     | 266 +++++++++++++++++++++++++++++
 drivers/net/virtio/virtqueue.h     |   5 +
 3 files changed, 282 insertions(+), 250 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c 
b/drivers/net/virtio/virtio_ethdev.c
index 14c5dc9059..0103d95920 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -221,173 +221,18 @@ virtio_get_nr_vq(struct virtio_hw *hw)
        return nr_vq;
 }
 
-static void
-virtio_init_vring(struct virtqueue *vq)
-{
-       int size = vq->vq_nentries;
-       uint8_t *ring_mem = vq->vq_ring_virt_mem;
-
-       PMD_INIT_FUNC_TRACE();
-
-       memset(ring_mem, 0, vq->vq_ring_size);
-
-       vq->vq_used_cons_idx = 0;
-       vq->vq_desc_head_idx = 0;
-       vq->vq_avail_idx = 0;
-       vq->vq_desc_tail_idx = (uint16_t)(vq->vq_nentries - 1);
-       vq->vq_free_cnt = vq->vq_nentries;
-       memset(vq->vq_descx, 0, sizeof(struct vq_desc_extra) * vq->vq_nentries);
-       if (virtio_with_packed_queue(vq->hw)) {
-               vring_init_packed(&vq->vq_packed.ring, ring_mem,
-                                 VIRTIO_VRING_ALIGN, size);
-               vring_desc_init_packed(vq, size);
-       } else {
-               struct vring *vr = &vq->vq_split.ring;
-
-               vring_init_split(vr, ring_mem, VIRTIO_VRING_ALIGN, size);
-               vring_desc_init_split(vr->desc, size);
-       }
-       /*
-        * Disable device(host) interrupting guest
-        */
-       virtqueue_disable_intr(vq);
-}
-
 static void
 virtio_control_queue_notify(struct virtqueue *vq, __rte_unused void *cookie)
 {
        virtqueue_notify(vq);
 }
 
-static int
-virtio_alloc_queue_headers(struct virtqueue *vq, int numa_node, const char 
*name)
-{
-       char hdr_name[VIRTQUEUE_MAX_NAME_SZ];
-       const struct rte_memzone **hdr_mz;
-       rte_iova_t *hdr_mem;
-       ssize_t size;
-       int queue_type;
-
-       queue_type = virtio_get_queue_type(vq->hw, vq->vq_queue_index);
-       switch (queue_type) {
-       case VTNET_TQ:
-               /*
-                * For each xmit packet, allocate a virtio_net_hdr
-                * and indirect ring elements
-                */
-               size = vq->vq_nentries * sizeof(struct virtio_tx_region);
-               hdr_mz = &vq->txq.hdr_mz;
-               hdr_mem = &vq->txq.hdr_mem;
-               break;
-       case VTNET_CQ:
-               /* Allocate a page for control vq command, data and status */
-               size = rte_mem_page_size();
-               hdr_mz = &vq->cq.hdr_mz;
-               hdr_mem = &vq->cq.hdr_mem;
-               break;
-       case VTNET_RQ:
-               /* fallthrough */
-       default:
-               return 0;
-       }
-
-       snprintf(hdr_name, sizeof(hdr_name), "%s_hdr", name);
-       *hdr_mz = rte_memzone_reserve_aligned(hdr_name, size, numa_node,
-                       RTE_MEMZONE_IOVA_CONTIG, RTE_CACHE_LINE_SIZE);
-       if (*hdr_mz == NULL) {
-               if (rte_errno == EEXIST)
-                       *hdr_mz = rte_memzone_lookup(hdr_name);
-               if (*hdr_mz == NULL)
-                       return -ENOMEM;
-       }
-
-       memset((*hdr_mz)->addr, 0, size);
-
-       if (vq->hw->use_va)
-               *hdr_mem = (uintptr_t)(*hdr_mz)->addr;
-       else
-               *hdr_mem = (uintptr_t)(*hdr_mz)->iova;
-
-       return 0;
-}
-
-static void
-virtio_free_queue_headers(struct virtqueue *vq)
-{
-       const struct rte_memzone **hdr_mz;
-       rte_iova_t *hdr_mem;
-       int queue_type;
-
-       queue_type = virtio_get_queue_type(vq->hw, vq->vq_queue_index);
-       switch (queue_type) {
-       case VTNET_TQ:
-               hdr_mz = &vq->txq.hdr_mz;
-               hdr_mem = &vq->txq.hdr_mem;
-               break;
-       case VTNET_CQ:
-               hdr_mz = &vq->cq.hdr_mz;
-               hdr_mem = &vq->cq.hdr_mem;
-               break;
-       case VTNET_RQ:
-               /* fallthrough */
-       default:
-               return;
-       }
-
-       rte_memzone_free(*hdr_mz);
-       *hdr_mz = NULL;
-       *hdr_mem = 0;
-}
-
-static int
-virtio_rxq_sw_ring_alloc(struct virtqueue *vq, int numa_node)
-{
-       void *sw_ring;
-       struct rte_mbuf *mbuf;
-       size_t size;
-
-       /* SW ring is only used with vectorized datapath */
-       if (!vq->hw->use_vec_rx)
-               return 0;
-
-       size = (RTE_PMD_VIRTIO_RX_MAX_BURST + vq->vq_nentries) * 
sizeof(vq->rxq.sw_ring[0]);
-
-       sw_ring = rte_zmalloc_socket("sw_ring", size, RTE_CACHE_LINE_SIZE, 
numa_node);
-       if (!sw_ring) {
-               PMD_INIT_LOG(ERR, "can not allocate RX soft ring");
-               return -ENOMEM;
-       }
-
-       mbuf = rte_zmalloc_socket("sw_ring", sizeof(*mbuf), 
RTE_CACHE_LINE_SIZE, numa_node);
-       if (!mbuf) {
-               PMD_INIT_LOG(ERR, "can not allocate fake mbuf");
-               rte_free(sw_ring);
-               return -ENOMEM;
-       }
-
-       vq->rxq.sw_ring = sw_ring;
-       vq->rxq.fake_mbuf = mbuf;
-
-       return 0;
-}
-
-static void
-virtio_rxq_sw_ring_free(struct virtqueue *vq)
-{
-       rte_free(vq->rxq.fake_mbuf);
-       vq->rxq.fake_mbuf = NULL;
-       rte_free(vq->rxq.sw_ring);
-       vq->rxq.sw_ring = NULL;
-}
-
 static int
 virtio_init_queue(struct rte_eth_dev *dev, uint16_t queue_idx)
 {
        char vq_name[VIRTQUEUE_MAX_NAME_SZ];
-       const struct rte_memzone *mz = NULL;
-       unsigned int vq_size, size;
+       unsigned int vq_size;
        struct virtio_hw *hw = dev->data->dev_private;
-       struct virtnet_ctl *cvq = NULL;
        struct virtqueue *vq;
        int queue_type = virtio_get_queue_type(hw, queue_idx);
        int ret;
@@ -414,87 +259,19 @@ virtio_init_queue(struct rte_eth_dev *dev, uint16_t 
queue_idx)
 
        snprintf(vq_name, sizeof(vq_name), "port%d_vq%d", dev->data->port_id, 
queue_idx);
 
-       size = RTE_ALIGN_CEIL(sizeof(*vq) +
-                               vq_size * sizeof(struct vq_desc_extra),
-                               RTE_CACHE_LINE_SIZE);
-
-
-       vq = rte_zmalloc_socket(vq_name, size, RTE_CACHE_LINE_SIZE,
-                               numa_node);
-       if (vq == NULL) {
-               PMD_INIT_LOG(ERR, "can not allocate vq");
+       vq = virtqueue_alloc(hw, queue_idx, vq_size, queue_type, numa_node, 
vq_name);
+       if (!vq) {
+               PMD_INIT_LOG(ERR, "virtqueue init failed");
                return -ENOMEM;
        }
-       hw->vqs[queue_idx] = vq;
 
-       vq->hw = hw;
-       vq->vq_queue_index = queue_idx;
-       vq->vq_nentries = vq_size;
-       if (virtio_with_packed_queue(hw)) {
-               vq->vq_packed.used_wrap_counter = 1;
-               vq->vq_packed.cached_flags = VRING_PACKED_DESC_F_AVAIL;
-               vq->vq_packed.event_flags_shadow = 0;
-               if (queue_type == VTNET_RQ)
-                       vq->vq_packed.cached_flags |= VRING_DESC_F_WRITE;
-       }
-
-       /*
-        * Reserve a memzone for vring elements
-        */
-       size = vring_size(hw, vq_size, VIRTIO_VRING_ALIGN);
-       vq->vq_ring_size = RTE_ALIGN_CEIL(size, VIRTIO_VRING_ALIGN);
-       PMD_INIT_LOG(DEBUG, "vring_size: %d, rounded_vring_size: %d",
-                    size, vq->vq_ring_size);
-
-       mz = rte_memzone_reserve_aligned(vq_name, vq->vq_ring_size,
-                       numa_node, RTE_MEMZONE_IOVA_CONTIG,
-                       VIRTIO_VRING_ALIGN);
-       if (mz == NULL) {
-               if (rte_errno == EEXIST)
-                       mz = rte_memzone_lookup(vq_name);
-               if (mz == NULL) {
-                       ret = -ENOMEM;
-                       goto free_vq;
-               }
-       }
-
-       memset(mz->addr, 0, mz->len);
-
-       vq->mz = mz;
-       if (hw->use_va)
-               vq->vq_ring_mem = (uintptr_t)mz->addr;
-       else
-               vq->vq_ring_mem = mz->iova;
-
-       vq->vq_ring_virt_mem = mz->addr;
-       PMD_INIT_LOG(DEBUG, "vq->vq_ring_mem: 0x%" PRIx64, vq->vq_ring_mem);
-       PMD_INIT_LOG(DEBUG, "vq->vq_ring_virt_mem: %p", vq->vq_ring_virt_mem);
-
-       virtio_init_vring(vq);
+       hw->vqs[queue_idx] = vq;
 
-       ret = virtio_alloc_queue_headers(vq, numa_node, vq_name);
-       if (ret) {
-               PMD_INIT_LOG(ERR, "Failed to alloc queue headers");
-               goto free_mz;
-       }
-
-       if (queue_type == VTNET_RQ) {
-               ret = virtio_rxq_sw_ring_alloc(vq, numa_node);
-               if (ret)
-                       goto free_hdr_mz;
-       } else if (queue_type == VTNET_TQ) {
-               virtqueue_txq_indirect_headers_init(vq);
-       } else if (queue_type == VTNET_CQ) {
-               cvq = &vq->cq;
-               hw->cvq = cvq;
+       if (queue_type == VTNET_CQ) {
+               hw->cvq = &vq->cq;
                vq->cq.notify_queue = &virtio_control_queue_notify;
        }
 
-       if (hw->use_va)
-               vq->mbuf_addr_offset = offsetof(struct rte_mbuf, buf_addr);
-       else
-               vq->mbuf_addr_offset = offsetof(struct rte_mbuf, buf_iova);
-
        if (VIRTIO_OPS(hw)->setup_queue(hw, vq) < 0) {
                PMD_INIT_LOG(ERR, "setup_queue failed");
                ret = -EINVAL;
@@ -504,15 +281,9 @@ virtio_init_queue(struct rte_eth_dev *dev, uint16_t 
queue_idx)
        return 0;
 
 clean_vq:
-       hw->cvq = NULL;
-       if (queue_type == VTNET_RQ)
-               virtio_rxq_sw_ring_free(vq);
-free_hdr_mz:
-       virtio_free_queue_headers(vq);
-free_mz:
-       rte_memzone_free(mz);
-free_vq:
-       rte_free(vq);
+       if (queue_type == VTNET_CQ)
+               hw->cvq = NULL;
+       virtqueue_free(vq);
        hw->vqs[queue_idx] = NULL;
 
        return ret;
@@ -523,7 +294,6 @@ virtio_free_queues(struct virtio_hw *hw)
 {
        uint16_t nr_vq = virtio_get_nr_vq(hw);
        struct virtqueue *vq;
-       int queue_type;
        uint16_t i;
 
        if (hw->vqs == NULL)
@@ -533,16 +303,7 @@ virtio_free_queues(struct virtio_hw *hw)
                vq = hw->vqs[i];
                if (!vq)
                        continue;
-
-               queue_type = virtio_get_queue_type(hw, i);
-               if (queue_type == VTNET_RQ) {
-                       rte_free(vq->rxq.fake_mbuf);
-                       rte_free(vq->rxq.sw_ring);
-               }
-
-               virtio_free_queue_headers(vq);
-               rte_memzone_free(vq->mz);
-               rte_free(vq);
+               virtqueue_free(vq);
                hw->vqs[i] = NULL;
        }
 
diff --git a/drivers/net/virtio/virtqueue.c b/drivers/net/virtio/virtqueue.c
index 7a84796513..1d836f2530 100644
--- a/drivers/net/virtio/virtqueue.c
+++ b/drivers/net/virtio/virtqueue.c
@@ -2,8 +2,12 @@
  * Copyright(c) 2010-2015 Intel Corporation
  */
 #include <stdint.h>
+#include <unistd.h>
 
+#include <rte_eal_paging.h>
+#include <rte_malloc.h>
 #include <rte_mbuf.h>
+#include <rte_memzone.h>
 
 #include "virtqueue.h"
 #include "virtio_logs.h"
@@ -259,3 +263,265 @@ virtqueue_txvq_reset_packed(struct virtqueue *vq)
 
        return 0;
 }
+
+
+static void
+virtio_init_vring(struct virtqueue *vq)
+{
+       int size = vq->vq_nentries;
+       uint8_t *ring_mem = vq->vq_ring_virt_mem;
+
+       PMD_INIT_FUNC_TRACE();
+
+       memset(ring_mem, 0, vq->vq_ring_size);
+
+       vq->vq_used_cons_idx = 0;
+       vq->vq_desc_head_idx = 0;
+       vq->vq_avail_idx = 0;
+       vq->vq_desc_tail_idx = (uint16_t)(vq->vq_nentries - 1);
+       vq->vq_free_cnt = vq->vq_nentries;
+       memset(vq->vq_descx, 0, sizeof(struct vq_desc_extra) * vq->vq_nentries);
+       if (virtio_with_packed_queue(vq->hw)) {
+               vring_init_packed(&vq->vq_packed.ring, ring_mem,
+                                 VIRTIO_VRING_ALIGN, size);
+               vring_desc_init_packed(vq, size);
+       } else {
+               struct vring *vr = &vq->vq_split.ring;
+
+               vring_init_split(vr, ring_mem, VIRTIO_VRING_ALIGN, size);
+               vring_desc_init_split(vr->desc, size);
+       }
+       /*
+        * Disable device(host) interrupting guest
+        */
+       virtqueue_disable_intr(vq);
+}
+
+static int
+virtio_alloc_queue_headers(struct virtqueue *vq, int numa_node, const char 
*name)
+{
+       char hdr_name[VIRTQUEUE_MAX_NAME_SZ];
+       const struct rte_memzone **hdr_mz;
+       rte_iova_t *hdr_mem;
+       ssize_t size;
+       int queue_type;
+
+       queue_type = virtio_get_queue_type(vq->hw, vq->vq_queue_index);
+       switch (queue_type) {
+       case VTNET_TQ:
+               /*
+                * For each xmit packet, allocate a virtio_net_hdr
+                * and indirect ring elements
+                */
+               size = vq->vq_nentries * sizeof(struct virtio_tx_region);
+               hdr_mz = &vq->txq.hdr_mz;
+               hdr_mem = &vq->txq.hdr_mem;
+               break;
+       case VTNET_CQ:
+               /* Allocate a page for control vq command, data and status */
+               size = rte_mem_page_size();
+               hdr_mz = &vq->cq.hdr_mz;
+               hdr_mem = &vq->cq.hdr_mem;
+               break;
+       case VTNET_RQ:
+               /* fallthrough */
+       default:
+               return 0;
+       }
+
+       snprintf(hdr_name, sizeof(hdr_name), "%s_hdr", name);
+       *hdr_mz = rte_memzone_reserve_aligned(hdr_name, size, numa_node,
+                       RTE_MEMZONE_IOVA_CONTIG, RTE_CACHE_LINE_SIZE);
+       if (*hdr_mz == NULL) {
+               if (rte_errno == EEXIST)
+                       *hdr_mz = rte_memzone_lookup(hdr_name);
+               if (*hdr_mz == NULL)
+                       return -ENOMEM;
+       }
+
+       memset((*hdr_mz)->addr, 0, size);
+
+       if (vq->hw->use_va)
+               *hdr_mem = (uintptr_t)(*hdr_mz)->addr;
+       else
+               *hdr_mem = (uintptr_t)(*hdr_mz)->iova;
+
+       return 0;
+}
+
+static void
+virtio_free_queue_headers(struct virtqueue *vq)
+{
+       const struct rte_memzone **hdr_mz;
+       rte_iova_t *hdr_mem;
+       int queue_type;
+
+       queue_type = virtio_get_queue_type(vq->hw, vq->vq_queue_index);
+       switch (queue_type) {
+       case VTNET_TQ:
+               hdr_mz = &vq->txq.hdr_mz;
+               hdr_mem = &vq->txq.hdr_mem;
+               break;
+       case VTNET_CQ:
+               hdr_mz = &vq->cq.hdr_mz;
+               hdr_mem = &vq->cq.hdr_mem;
+               break;
+       case VTNET_RQ:
+               /* fallthrough */
+       default:
+               return;
+       }
+
+       rte_memzone_free(*hdr_mz);
+       *hdr_mz = NULL;
+       *hdr_mem = 0;
+}
+
+static int
+virtio_rxq_sw_ring_alloc(struct virtqueue *vq, int numa_node)
+{
+       void *sw_ring;
+       struct rte_mbuf *mbuf;
+       size_t size;
+
+       /* SW ring is only used with vectorized datapath */
+       if (!vq->hw->use_vec_rx)
+               return 0;
+
+       size = (RTE_PMD_VIRTIO_RX_MAX_BURST + vq->vq_nentries) * 
sizeof(vq->rxq.sw_ring[0]);
+
+       sw_ring = rte_zmalloc_socket("sw_ring", size, RTE_CACHE_LINE_SIZE, 
numa_node);
+       if (!sw_ring) {
+               PMD_INIT_LOG(ERR, "can not allocate RX soft ring");
+               return -ENOMEM;
+       }
+
+       mbuf = rte_zmalloc_socket("sw_ring", sizeof(*mbuf), 
RTE_CACHE_LINE_SIZE, numa_node);
+       if (!mbuf) {
+               PMD_INIT_LOG(ERR, "can not allocate fake mbuf");
+               rte_free(sw_ring);
+               return -ENOMEM;
+       }
+
+       vq->rxq.sw_ring = sw_ring;
+       vq->rxq.fake_mbuf = mbuf;
+
+       return 0;
+}
+
+static void
+virtio_rxq_sw_ring_free(struct virtqueue *vq)
+{
+       rte_free(vq->rxq.fake_mbuf);
+       vq->rxq.fake_mbuf = NULL;
+       rte_free(vq->rxq.sw_ring);
+       vq->rxq.sw_ring = NULL;
+}
+
+struct virtqueue *
+virtqueue_alloc(struct virtio_hw *hw, uint16_t index, uint16_t num, int type,
+               int node, const char *name)
+{
+       struct virtqueue *vq;
+       const struct rte_memzone *mz;
+       unsigned int size;
+
+       size = sizeof(*vq) + num * sizeof(struct vq_desc_extra);
+       size = RTE_ALIGN_CEIL(size, RTE_CACHE_LINE_SIZE);
+
+       vq = rte_zmalloc_socket(name, size, RTE_CACHE_LINE_SIZE, node);
+       if (vq == NULL) {
+               PMD_INIT_LOG(ERR, "can not allocate vq");
+               return NULL;
+       }
+
+       vq->hw = hw;
+       vq->vq_queue_index = index;
+       vq->vq_nentries = num;
+       if (virtio_with_packed_queue(hw)) {
+               vq->vq_packed.used_wrap_counter = 1;
+               vq->vq_packed.cached_flags = VRING_PACKED_DESC_F_AVAIL;
+               vq->vq_packed.event_flags_shadow = 0;
+               if (type == VTNET_RQ)
+                       vq->vq_packed.cached_flags |= VRING_DESC_F_WRITE;
+       }
+
+       /*
+        * Reserve a memzone for vring elements
+        */
+       size = vring_size(hw, num, VIRTIO_VRING_ALIGN);
+       vq->vq_ring_size = RTE_ALIGN_CEIL(size, VIRTIO_VRING_ALIGN);
+       PMD_INIT_LOG(DEBUG, "vring_size: %d, rounded_vring_size: %d", size, 
vq->vq_ring_size);
+
+       mz = rte_memzone_reserve_aligned(name, vq->vq_ring_size, node,
+                       RTE_MEMZONE_IOVA_CONTIG, VIRTIO_VRING_ALIGN);
+       if (mz == NULL) {
+               if (rte_errno == EEXIST)
+                       mz = rte_memzone_lookup(name);
+               if (mz == NULL)
+                       goto free_vq;
+       }
+
+       memset(mz->addr, 0, mz->len);
+       vq->mz = mz;
+       vq->vq_ring_virt_mem = mz->addr;
+
+       if (hw->use_va) {
+               vq->vq_ring_mem = (uintptr_t)mz->addr;
+               vq->mbuf_addr_offset = offsetof(struct rte_mbuf, buf_addr);
+       } else {
+               vq->vq_ring_mem = mz->iova;
+               vq->mbuf_addr_offset = offsetof(struct rte_mbuf, buf_iova);
+       }
+
+       PMD_INIT_LOG(DEBUG, "vq->vq_ring_mem: 0x%" PRIx64, vq->vq_ring_mem);
+       PMD_INIT_LOG(DEBUG, "vq->vq_ring_virt_mem: %p", vq->vq_ring_virt_mem);
+
+       virtio_init_vring(vq);
+
+       if (virtio_alloc_queue_headers(vq, node, name)) {
+               PMD_INIT_LOG(ERR, "Failed to alloc queue headers");
+               goto free_mz;
+       }
+
+       switch (type) {
+       case VTNET_RQ:
+               if (virtio_rxq_sw_ring_alloc(vq, node))
+                       goto free_hdr_mz;
+               break;
+       case VTNET_TQ:
+               virtqueue_txq_indirect_headers_init(vq);
+               break;
+       }
+
+       return vq;
+
+free_hdr_mz:
+       virtio_free_queue_headers(vq);
+free_mz:
+       rte_memzone_free(mz);
+free_vq:
+       rte_free(vq);
+
+       return NULL;
+}
+
+void
+virtqueue_free(struct virtqueue *vq)
+{
+       int type;
+
+       type = virtio_get_queue_type(vq->hw, vq->vq_queue_index);
+       switch (type) {
+       case VTNET_RQ:
+               virtio_rxq_sw_ring_free(vq);
+               break;
+       case VTNET_TQ:
+       case VTNET_CQ:
+               virtio_free_queue_headers(vq);
+               break;
+       }
+
+       rte_memzone_free(vq->mz);
+       rte_free(vq);
+}
diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h
index d7f8ee79bb..9d4aba11a3 100644
--- a/drivers/net/virtio/virtqueue.h
+++ b/drivers/net/virtio/virtqueue.h
@@ -385,6 +385,11 @@ int virtqueue_txvq_reset_packed(struct virtqueue *vq);
 
 void virtqueue_txq_indirect_headers_init(struct virtqueue *vq);
 
+struct virtqueue *virtqueue_alloc(struct virtio_hw *hw, uint16_t index,
+               uint16_t num, int type, int node, const char *name);
+
+void virtqueue_free(struct virtqueue *vq);
+
 static inline int
 virtqueue_full(const struct virtqueue *vq)
 {
-- 
2.39.1

Reply via email to