[dpdk-dev] [PATCH 4/8] net/virtio: allocate queue at init stage
Maxime Coquelin
maxime.coquelin at redhat.com
Thu Nov 3 22:11:43 CET 2016
On 11/03/2016 05:09 PM, Yuanhan Liu wrote:
> Queue allocation should be done once, since the queue related info (such
> as vring addreess) will only be informed to the vhost-user backend once
> without virtio device reset.
>
> That means, if you allocate queues again after the vhost-user negotiation,
> the vhost-user backend will not be informed any more. Leading to a state
> that the vring info mismatches between virtio PMD driver and vhost-backend:
> the driver switches to the new address has just been allocated, while the
> vhost-backend still sticks to the old address has been assigned in the init
> stage.
>
> Unfortunately, that is exactly how the virtio driver is coded so far: queue
> allocation is done at queue_setup stage (when rte_eth_tx/rx_queue_setup is
> invoked). This is wrong, because queue_setup can be invoked several times.
> For example,
>
> $ start_testpmd.sh ... --txq=1 --rxq=1 ...
> > port stop 0
> > port config all txq 1 # just trigger the queue_setup callback again
> > port config all rxq 1
> > port start 0
>
> The right way to do is allocate the queues in the init stage, so that the
> vring info could be persistent with the vhost-user backend.
>
> Besides that, we should allocate max_queue pairs the device supports, but
> not nr queue pairs firstly configured, to make following case work.
I understand, but how much memory overhead does that represent?
Have you considered performing a device reset when queue number is
changed?
>
> $ start_testpmd.sh ... --txq=1 --rxq=1 ...
> > port stop 0
> > port config all txq 2
> > port config all rxq 2
> > port start 0
>
> Signed-off-by: Yuanhan Liu <yuanhan.liu at linux.intel.com>
> ---
> drivers/net/virtio/virtio_ethdev.c | 105 +++++++++++++++++++++++--------------
> drivers/net/virtio/virtio_ethdev.h | 8 ---
> drivers/net/virtio/virtio_pci.h | 2 +
> drivers/net/virtio/virtio_rxtx.c | 38 +++++++-------
> 4 files changed, 85 insertions(+), 68 deletions(-)
>
> diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
> index 5a2c14b..253bcb5 100644
> --- a/drivers/net/virtio/virtio_ethdev.c
> +++ b/drivers/net/virtio/virtio_ethdev.c
> @@ -295,13 +295,19 @@ virtio_dev_queue_release(struct virtqueue *vq)
> }
> }
>
> -int virtio_dev_queue_setup(struct rte_eth_dev *dev,
> - int queue_type,
> - uint16_t queue_idx,
> - uint16_t vtpci_queue_idx,
> - uint16_t nb_desc,
> - unsigned int socket_id,
> - void **pvq)
> +static int
> +virtio_get_queue_type(struct virtio_hw *hw, uint16_t vtpci_queue_idx)
> +{
> + if (vtpci_queue_idx == hw->max_queue_pairs * 2)
> + return VTNET_CQ;
> + else if (vtpci_queue_idx % 2 == 0)
> + return VTNET_RQ;
> + else
> + return VTNET_TQ;
> +}
> +
> +static int
> +virtio_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx)
> {
> char vq_name[VIRTQUEUE_MAX_NAME_SZ];
> char vq_hdr_name[VIRTQUEUE_MAX_NAME_SZ];
> @@ -314,6 +320,7 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
> struct virtqueue *vq;
> size_t sz_hdr_mz = 0;
> void *sw_ring = NULL;
> + int queue_type = virtio_get_queue_type(hw, vtpci_queue_idx);
> int ret;
>
> PMD_INIT_LOG(DEBUG, "setting up queue: %u", vtpci_queue_idx);
> @@ -351,18 +358,18 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
> sz_hdr_mz = PAGE_SIZE;
> }
>
> - vq = rte_zmalloc_socket(vq_name, size, RTE_CACHE_LINE_SIZE, socket_id);
> + vq = rte_zmalloc_socket(vq_name, size, RTE_CACHE_LINE_SIZE,
> + SOCKET_ID_ANY);
> if (vq == NULL) {
> PMD_INIT_LOG(ERR, "can not allocate vq");
> return -ENOMEM;
> }
> + hw->vqs[vtpci_queue_idx] = vq;
> +
> vq->hw = hw;
> vq->vq_queue_index = vtpci_queue_idx;
> vq->vq_nentries = vq_size;
> -
> - if (nb_desc == 0 || nb_desc > vq_size)
> - nb_desc = vq_size;
> - vq->vq_free_cnt = nb_desc;
> + vq->vq_free_cnt = vq_size;
>
> /*
> * Reserve a memzone for vring elements
> @@ -372,7 +379,8 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
> 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, socket_id,
> + mz = rte_memzone_reserve_aligned(vq_name, vq->vq_ring_size,
> + SOCKET_ID_ANY,
> 0, VIRTIO_PCI_VRING_ALIGN);
> if (mz == NULL) {
> if (rte_errno == EEXIST)
> @@ -396,7 +404,7 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
> snprintf(vq_hdr_name, sizeof(vq_hdr_name), "port%d_vq%d_hdr",
> dev->data->port_id, vtpci_queue_idx);
> hdr_mz = rte_memzone_reserve_aligned(vq_hdr_name, sz_hdr_mz,
> - socket_id, 0,
> + SOCKET_ID_ANY, 0,
> RTE_CACHE_LINE_SIZE);
> if (hdr_mz == NULL) {
> if (rte_errno == EEXIST)
> @@ -413,7 +421,7 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
> sizeof(vq->sw_ring[0]);
>
> sw_ring = rte_zmalloc_socket("sw_ring", sz_sw,
> - RTE_CACHE_LINE_SIZE, socket_id);
> + RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
> if (!sw_ring) {
> PMD_INIT_LOG(ERR, "can not allocate RX soft ring");
> ret = -ENOMEM;
> @@ -424,19 +432,14 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
> rxvq = &vq->rxq;
> rxvq->vq = vq;
> rxvq->port_id = dev->data->port_id;
> - rxvq->queue_id = queue_idx;
> rxvq->mz = mz;
> - *pvq = rxvq;
> } else if (queue_type == VTNET_TQ) {
> txvq = &vq->txq;
> txvq->vq = vq;
> txvq->port_id = dev->data->port_id;
> - txvq->queue_id = queue_idx;
> txvq->mz = mz;
> txvq->virtio_net_hdr_mz = hdr_mz;
> txvq->virtio_net_hdr_mem = hdr_mz->phys_addr;
> -
> - *pvq = txvq;
> } else if (queue_type == VTNET_CQ) {
> cvq = &vq->cq;
> cvq->vq = vq;
> @@ -444,7 +447,8 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
> cvq->virtio_net_hdr_mz = hdr_mz;
> cvq->virtio_net_hdr_mem = hdr_mz->phys_addr;
> memset(cvq->virtio_net_hdr_mz->addr, 0, PAGE_SIZE);
> - *pvq = cvq;
> +
> + hw->cvq = cvq;
> }
>
> /* For virtio_user case (that is when dev->pci_dev is NULL), we use
> @@ -502,23 +506,45 @@ fail_q_alloc:
> }
>
> static int
> -virtio_dev_cq_queue_setup(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx,
> - uint32_t socket_id)
> +virtio_alloc_queues(struct rte_eth_dev *dev)
> {
> - struct virtnet_ctl *cvq;
> - int ret;
> struct virtio_hw *hw = dev->data->dev_private;
> + uint16_t nr_vq = hw->max_queue_pairs * 2;
> + uint16_t i;
> + int ret;
>
> - PMD_INIT_FUNC_TRACE();
> - ret = virtio_dev_queue_setup(dev, VTNET_CQ, VTNET_SQ_CQ_QUEUE_IDX,
> - vtpci_queue_idx, 0, socket_id, (void **)&cvq);
> - if (ret < 0) {
> - PMD_INIT_LOG(ERR, "control vq initialization failed");
> - return ret;
> + if (vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_VQ))
> + nr_vq += 1;
> +
> + hw->vqs = rte_zmalloc(NULL, sizeof(struct virtqueue *) * nr_vq, 0);
> + if (!hw->vqs) {
> + PMD_INIT_LOG(ERR, "failed to allocate vqs");
> + return -ENOMEM;
> + }
> +
> + for (i = 0; i < nr_vq; i++) {
> + ret = virtio_init_queue(dev, i);
> + if (ret < 0)
> + goto cleanup;
> }
>
> - hw->cvq = cvq;
> return 0;
> +
> +cleanup:
> + /*
> + * ctrl queue is the last queue; if we go here, it means the ctrl
> + * queue is not allocated, that we can do no cleanup for it here.
> + */
> + while (i > 0) {
> + i--;
> + if (i % 2 == 0)
> + virtio_dev_rx_queue_release(&hw->vqs[i]->rxq);
> + else
> + virtio_dev_tx_queue_release(&hw->vqs[i]->txq);
> + }
> + rte_free(hw->vqs);
> +
> + return ret;
> }
>
> static void
> @@ -1141,6 +1167,7 @@ virtio_init_device(struct rte_eth_dev *eth_dev, uint64_t req_features)
> struct virtio_net_config *config;
> struct virtio_net_config local_config;
> struct rte_pci_device *pci_dev = eth_dev->pci_dev;
> + int ret;
>
> /* Reset the device although not necessary at startup */
> vtpci_reset(hw);
> @@ -1222,6 +1249,10 @@ virtio_init_device(struct rte_eth_dev *eth_dev, uint64_t req_features)
> hw->max_queue_pairs = 1;
> }
>
> + ret = virtio_alloc_queues(eth_dev);
> + if (ret < 0)
> + return ret;
> +
> if (pci_dev)
> PMD_INIT_LOG(DEBUG, "port %d vendorID=0x%x deviceID=0x%x",
> eth_dev->data->port_id, pci_dev->id.vendor_id,
> @@ -1390,15 +1421,9 @@ virtio_dev_configure(struct rte_eth_dev *dev)
> return -ENOTSUP;
> }
>
> - /* Setup and start control queue */
> - if (vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_VQ)) {
> - ret = virtio_dev_cq_queue_setup(dev,
> - hw->max_queue_pairs * 2,
> - SOCKET_ID_ANY);
> - if (ret < 0)
> - return ret;
> + /* start control queue */
> + if (vtpci_with_feature(hw, VIRTIO_NET_F_CTRL_VQ))
> virtio_dev_cq_start(dev);
> - }
>
> hw->vlan_strip = rxmode->hw_vlan_strip;
>
> diff --git a/drivers/net/virtio/virtio_ethdev.h b/drivers/net/virtio/virtio_ethdev.h
> index de33b32..5db8632 100644
> --- a/drivers/net/virtio/virtio_ethdev.h
> +++ b/drivers/net/virtio/virtio_ethdev.h
> @@ -80,14 +80,6 @@ void virtio_dev_cq_start(struct rte_eth_dev *dev);
> */
> void virtio_dev_rxtx_start(struct rte_eth_dev *dev);
>
> -int virtio_dev_queue_setup(struct rte_eth_dev *dev,
> - int queue_type,
> - uint16_t queue_idx,
> - uint16_t vtpci_queue_idx,
> - uint16_t nb_desc,
> - unsigned int socket_id,
> - void **pvq);
> -
> void virtio_dev_queue_release(struct virtqueue *vq);
>
> int virtio_dev_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
> diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
> index 0c5ed31..f63f76c 100644
> --- a/drivers/net/virtio/virtio_pci.h
> +++ b/drivers/net/virtio/virtio_pci.h
> @@ -264,6 +264,8 @@ struct virtio_hw {
> struct virtio_net_config *dev_cfg;
> const struct virtio_pci_ops *vtpci_ops;
> void *virtio_user_dev;
> +
> + struct virtqueue **vqs;
> };
>
> /*
> diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
> index b4c4aa4..fb703d2 100644
> --- a/drivers/net/virtio/virtio_rxtx.c
> +++ b/drivers/net/virtio/virtio_rxtx.c
> @@ -530,24 +530,24 @@ int
> virtio_dev_rx_queue_setup(struct rte_eth_dev *dev,
> uint16_t queue_idx,
> uint16_t nb_desc,
> - unsigned int socket_id,
> + unsigned int socket_id __rte_unused,
> __rte_unused const struct rte_eth_rxconf *rx_conf,
> struct rte_mempool *mp)
> {
> uint16_t vtpci_queue_idx = 2 * queue_idx + VTNET_SQ_RQ_QUEUE_IDX;
> + struct virtio_hw *hw = dev->data->dev_private;
> + struct virtqueue *vq = hw->vqs[vtpci_queue_idx];
> struct virtnet_rx *rxvq;
> - int ret;
>
> PMD_INIT_FUNC_TRACE();
> - ret = virtio_dev_queue_setup(dev, VTNET_RQ, queue_idx, vtpci_queue_idx,
> - nb_desc, socket_id, (void **)&rxvq);
> - if (ret < 0) {
> - PMD_INIT_LOG(ERR, "rvq initialization failed");
> - return ret;
> - }
>
> - /* Create mempool for rx mbuf allocation */
> + if (nb_desc == 0 || nb_desc > vq->vq_nentries)
> + nb_desc = vq->vq_nentries;
> + vq->vq_free_cnt = RTE_MIN(vq->vq_free_cnt, nb_desc);
> +
> + rxvq = &vq->rxq;
> rxvq->mpool = mp;
> + rxvq->queue_id = queue_idx;
>
> dev->data->rx_queues[queue_idx] = rxvq;
>
> @@ -613,27 +613,25 @@ int
> virtio_dev_tx_queue_setup(struct rte_eth_dev *dev,
> uint16_t queue_idx,
> uint16_t nb_desc,
> - unsigned int socket_id,
> + unsigned int socket_id __rte_unused,
> const struct rte_eth_txconf *tx_conf)
> {
> uint8_t vtpci_queue_idx = 2 * queue_idx + VTNET_SQ_TQ_QUEUE_IDX;
> + struct virtio_hw *hw = dev->data->dev_private;
> + struct virtqueue *vq = hw->vqs[vtpci_queue_idx];
> struct virtnet_tx *txvq;
> - struct virtqueue *vq;
> uint16_t tx_free_thresh;
> - int ret;
>
> PMD_INIT_FUNC_TRACE();
>
> -
> virtio_update_rxtx_handler(dev, tx_conf);
>
> - ret = virtio_dev_queue_setup(dev, VTNET_TQ, queue_idx, vtpci_queue_idx,
> - nb_desc, socket_id, (void **)&txvq);
> - if (ret < 0) {
> - PMD_INIT_LOG(ERR, "tvq initialization failed");
> - return ret;
> - }
> - vq = txvq->vq;
> + if (nb_desc == 0 || nb_desc > vq->vq_nentries)
> + nb_desc = vq->vq_nentries;
> + vq->vq_free_cnt = RTE_MIN(vq->vq_free_cnt, nb_desc);
> +
> + txvq = &vq->txq;
> + txvq->queue_id = queue_idx;
>
> tx_free_thresh = tx_conf->tx_free_thresh;
> if (tx_free_thresh == 0)
>
More information about the dev
mailing list