virtio: fix crash when releasing null queue
[dpdk.git] / drivers / net / virtio / virtio_ethdev.c
index 4d5412a..147aca1 100644 (file)
@@ -239,9 +239,10 @@ virtio_set_multiple_queues(struct rte_eth_dev *dev, uint16_t nb_queues)
 
 void
 virtio_dev_queue_release(struct virtqueue *vq) {
-       struct virtio_hw *hw = vq->hw;
+       struct virtio_hw *hw;
 
        if (vq) {
+               hw = vq->hw;
                /* Select and deactivate the queue */
                VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->queue_id);
                VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
@@ -254,7 +255,7 @@ 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 vtpci_queue_idx,
                        uint16_t nb_desc,
                        unsigned int socket_id,
                        struct virtqueue **pvq)
@@ -264,7 +265,7 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
        uint16_t vq_size;
        int size;
        struct virtio_hw *hw = dev->data->dev_private;
-       struct virtqueue  *vq = NULL;
+       struct virtqueue *vq = NULL;
 
        /* Write the virtqueue index to the Queue Select Field */
        VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vtpci_queue_idx);
@@ -276,8 +277,6 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
         */
        vq_size = VIRTIO_READ_REG_2(hw, VIRTIO_PCI_QUEUE_NUM);
        PMD_INIT_LOG(DEBUG, "vq_size: %d nb_desc:%d", vq_size, nb_desc);
-       if (nb_desc == 0)
-               nb_desc = vq_size;
        if (vq_size == 0) {
                PMD_INIT_LOG(ERR, "%s: virtqueue does not exist", __func__);
                return -EINVAL;
@@ -288,16 +287,6 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
                return -EINVAL;
        }
 
-       if (nb_desc < vq_size) {
-               if (!rte_is_power_of_2(nb_desc)) {
-                       PMD_INIT_LOG(ERR,
-                                    "nb_desc(%u) size is not powerof 2",
-                                    nb_desc);
-                       return -EINVAL;
-               }
-               vq_size = nb_desc;
-       }
-
        if (queue_type == VTNET_RQ) {
                snprintf(vq_name, sizeof(vq_name), "port%d_rvq%d",
                        dev->data->port_id, queue_idx);
@@ -325,7 +314,10 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
        vq->queue_id = queue_idx;
        vq->vq_queue_index = vtpci_queue_idx;
        vq->vq_nentries = vq_size;
-       vq->vq_free_cnt = vq_size;
+
+       if (nb_desc == 0 || nb_desc > vq_size)
+               nb_desc = vq_size;
+       vq->vq_free_cnt = nb_desc;
 
        /*
         * Reserve a memzone for vring elements
@@ -422,13 +414,12 @@ virtio_dev_cq_queue_setup(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx,
                uint32_t socket_id)
 {
        struct virtqueue *vq;
-       uint16_t nb_desc = 0;
        int ret;
        struct virtio_hw *hw = dev->data->dev_private;
 
        PMD_INIT_FUNC_TRACE();
        ret = virtio_dev_queue_setup(dev, VTNET_CQ, VTNET_SQ_CQ_QUEUE_IDX,
-                       vtpci_queue_idx, nb_desc, socket_id, &vq);
+                       vtpci_queue_idx, 0, socket_id, &vq);
        if (ret < 0) {
                PMD_INIT_LOG(ERR, "control vq initialization failed");
                return ret;
@@ -438,6 +429,22 @@ virtio_dev_cq_queue_setup(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx,
        return 0;
 }
 
+static void
+virtio_free_queues(struct rte_eth_dev *dev)
+{
+       unsigned int i;
+
+       for (i = 0; i < dev->data->nb_rx_queues; i++)
+               virtio_dev_rx_queue_release(dev->data->rx_queues[i]);
+
+       dev->data->nb_rx_queues = 0;
+
+       for (i = 0; i < dev->data->nb_tx_queues; i++)
+               virtio_dev_tx_queue_release(dev->data->tx_queues[i]);
+
+       dev->data->nb_tx_queues = 0;
+}
+
 static void
 virtio_dev_close(struct rte_eth_dev *dev)
 {
@@ -452,6 +459,7 @@ virtio_dev_close(struct rte_eth_dev *dev)
        vtpci_reset(hw);
        hw->started = 0;
        virtio_dev_free_mbufs(dev);
+       virtio_free_queues(dev);
 }
 
 static void