net/virtio: fix crash on querying xstats
[dpdk.git] / drivers / net / virtio / virtio_ethdev.c
index 4cb27b6..12fa640 100644 (file)
@@ -59,7 +59,6 @@
 #include "virtqueue.h"
 #include "virtio_rxtx.h"
 
-static int eth_virtio_dev_init(struct rte_eth_dev *eth_dev);
 static int eth_virtio_dev_uninit(struct rte_eth_dev *eth_dev);
 static int  virtio_dev_configure(struct rte_eth_dev *dev);
 static int  virtio_dev_start(struct rte_eth_dev *dev);
@@ -191,14 +190,14 @@ virtio_send_command(struct virtnet_ctl *cvq, struct virtio_pmd_ctrl *ctrl,
         * One RX packet for ACK.
         */
        vq->vq_ring.desc[head].flags = VRING_DESC_F_NEXT;
-       vq->vq_ring.desc[head].addr = cvq->virtio_net_hdr_mz->phys_addr;
+       vq->vq_ring.desc[head].addr = cvq->virtio_net_hdr_mem;
        vq->vq_ring.desc[head].len = sizeof(struct virtio_net_ctrl_hdr);
        vq->vq_free_cnt--;
        i = vq->vq_ring.desc[head].next;
 
        for (k = 0; k < pkt_num; k++) {
                vq->vq_ring.desc[i].flags = VRING_DESC_F_NEXT;
-               vq->vq_ring.desc[i].addr = cvq->virtio_net_hdr_mz->phys_addr
+               vq->vq_ring.desc[i].addr = cvq->virtio_net_hdr_mem
                        + sizeof(struct virtio_net_ctrl_hdr)
                        + sizeof(ctrl->status) + sizeof(uint8_t)*sum;
                vq->vq_ring.desc[i].len = dlen[k];
@@ -208,7 +207,7 @@ virtio_send_command(struct virtnet_ctl *cvq, struct virtio_pmd_ctrl *ctrl,
        }
 
        vq->vq_ring.desc[i].flags = VRING_DESC_F_WRITE;
-       vq->vq_ring.desc[i].addr = cvq->virtio_net_hdr_mz->phys_addr
+       vq->vq_ring.desc[i].addr = cvq->virtio_net_hdr_mem
                        + sizeof(struct virtio_net_ctrl_hdr);
        vq->vq_ring.desc[i].len = sizeof(ctrl->status);
        vq->vq_free_cnt--;
@@ -311,9 +310,9 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
        const struct rte_memzone *mz = NULL, *hdr_mz = NULL;
        unsigned int vq_size, size;
        struct virtio_hw *hw = dev->data->dev_private;
-       struct virtnet_rx *rxvq;
-       struct virtnet_tx *txvq;
-       struct virtnet_ctl *cvq;
+       struct virtnet_rx *rxvq = NULL;
+       struct virtnet_tx *txvq = NULL;
+       struct virtnet_ctl *cvq = NULL;
        struct virtqueue *vq;
        const char *queue_names[] = {"rvq", "txq", "cvq"};
        size_t sz_vq, sz_q = 0, sz_hdr_mz = 0;
@@ -391,16 +390,6 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
                }
        }
 
-       /*
-        * Virtio PCI device VIRTIO_PCI_QUEUE_PF register is 32bit,
-        * and only accepts 32 bit page frame number.
-        * Check if the allocated physical memory exceeds 16TB.
-        */
-       if ((mz->phys_addr + vq->vq_ring_size - 1) >> (VIRTIO_PCI_QUEUE_ADDR_SHIFT + 32)) {
-               PMD_INIT_LOG(ERR, "vring address shouldn't be above 16TB!");
-               ret = -ENOMEM;
-               goto fail_q_alloc;
-       }
        memset(mz->addr, 0, sizeof(mz->len));
 
        vq->vq_ring_mem = mz->phys_addr;
@@ -447,9 +436,6 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
                rxvq->mz = mz;
                *pvq = rxvq;
        } else if (queue_type == VTNET_TQ) {
-               struct virtio_tx_region *txr;
-               unsigned int i;
-
                txvq = (struct virtnet_tx *)RTE_PTR_ADD(vq, sz_vq);
                txvq->vq = vq;
                txvq->port_id = dev->data->port_id;
@@ -458,6 +444,36 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
                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 = (struct virtnet_ctl *)RTE_PTR_ADD(vq, sz_vq);
+               cvq->vq = vq;
+               cvq->mz = mz;
+               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;
+       }
+
+       /* For virtio-user case (that is when dev->pci_dev is NULL), we use
+        * virtual address. And we need properly set _offset_, please see
+        * MBUF_DATA_DMA_ADDR in virtqueue.h for more information.
+        */
+       if (dev->pci_dev)
+               vq->offset = offsetof(struct rte_mbuf, buf_physaddr);
+       else {
+               vq->vq_ring_mem = (uintptr_t)mz->addr;
+               vq->offset = offsetof(struct rte_mbuf, buf_addr);
+               if (queue_type == VTNET_TQ)
+                       txvq->virtio_net_hdr_mem = (uintptr_t)hdr_mz->addr;
+               else if (queue_type == VTNET_CQ)
+                       cvq->virtio_net_hdr_mem = (uintptr_t)hdr_mz->addr;
+       }
+
+       if (queue_type == VTNET_TQ) {
+               struct virtio_tx_region *txr;
+               unsigned int i;
+
                txr = hdr_mz->addr;
                memset(txr, 0, vq_size * sizeof(*txr));
                for (i = 0; i < vq_size; i++) {
@@ -473,19 +489,14 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
                        start_dp->len = hw->vtnet_hdr_size;
                        start_dp->flags = VRING_DESC_F_NEXT;
                }
+       }
 
-               *pvq = txvq;
-       } else if (queue_type == VTNET_CQ) {
-               cvq = (struct virtnet_ctl *)RTE_PTR_ADD(vq, sz_vq);
-               cvq->vq = vq;
-               cvq->mz = mz;
-               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;
+       if (hw->vtpci_ops->setup_queue(hw, vq) < 0) {
+               PMD_INIT_LOG(ERR, "setup_queue failed");
+               virtio_dev_queue_release(vq);
+               return -EINVAL;
        }
 
-       hw->vtpci_ops->setup_queue(hw, vq);
        vq->configured = 1;
        return 0;
 
@@ -765,7 +776,7 @@ static int virtio_dev_xstats_get_names(struct rte_eth_dev *dev,
        unsigned nstats = dev->data->nb_tx_queues * VIRTIO_NB_TXQ_XSTATS +
                dev->data->nb_rx_queues * VIRTIO_NB_RXQ_XSTATS;
 
-       if (xstats_names == NULL) {
+       if (xstats_names != NULL) {
                /* Note: limit checked in rte_eth_xstats_names() */
 
                for (i = 0; i < dev->data->nb_rx_queues; i++) {
@@ -1118,7 +1129,7 @@ rx_func_get(struct rte_eth_dev *eth_dev)
  * This function is based on probe() function in virtio_pci.c
  * It returns 0 on success.
  */
-static int
+int
 eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 {
        struct virtio_hw *hw = eth_dev->data->dev_private;
@@ -1149,9 +1160,11 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
        pci_dev = eth_dev->pci_dev;
 
-       ret = vtpci_init(pci_dev, hw, &dev_flags);
-       if (ret)
-               return ret;
+       if (pci_dev) {
+               ret = vtpci_init(pci_dev, hw, &dev_flags);
+               if (ret)
+                       return ret;
+       }
 
        /* Reset the device although not necessary at startup */
        vtpci_reset(hw);
@@ -1243,7 +1256,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
        PMD_INIT_LOG(DEBUG, "hw->max_rx_queues=%d   hw->max_tx_queues=%d",
                        hw->max_rx_queues, hw->max_tx_queues);
-       PMD_INIT_LOG(DEBUG, "port %d vendorID=0x%x deviceID=0x%x",
+       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,
                        pci_dev->id.device_id);
 
@@ -1531,7 +1545,10 @@ virtio_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 {
        struct virtio_hw *hw = dev->data->dev_private;
 
-       dev_info->driver_name = dev->driver->pci_drv.name;
+       if (dev->pci_dev)
+               dev_info->driver_name = dev->driver->pci_drv.name;
+       else
+               dev_info->driver_name = "virtio-user PMD";
        dev_info->max_rx_queues = (uint16_t)hw->max_rx_queues;
        dev_info->max_tx_queues = (uint16_t)hw->max_tx_queues;
        dev_info->min_rx_bufsize = VIRTIO_MIN_RX_BUFSIZE;