ethdev: fix missing imissed counter in xstats
[dpdk.git] / lib / librte_vhost / vhost.c
index 6e55116..4f8b73a 100644 (file)
@@ -55,6 +55,7 @@
 
 struct virtio_net *vhost_devices[MAX_VHOST_DEVICE];
 
+/* Called with iotlb_lock read-locked */
 uint64_t
 __vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq,
                    uint64_t iova, uint64_t size, uint8_t perm)
@@ -71,8 +72,19 @@ __vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq,
                return vva;
 
        if (!vhost_user_iotlb_pending_miss(vq, iova + tmp_size, perm)) {
+               /*
+                * iotlb_lock is read-locked for a full burst,
+                * but it only protects the iotlb cache.
+                * In case of IOTLB miss, we might block on the socket,
+                * which could cause a deadlock with QEMU if an IOTLB update
+                * is being handled. We can safely unlock here to avoid it.
+                */
+               vhost_user_iotlb_rd_unlock(vq);
+
                vhost_user_iotlb_pending_insert(vq, iova + tmp_size, perm);
                vhost_user_iotlb_miss(dev, iova + tmp_size, perm);
+
+               vhost_user_iotlb_rd_lock(vq);
        }
 
        return 0;
@@ -136,6 +148,58 @@ free_device(struct virtio_net *dev)
        rte_free(dev);
 }
 
+int
+vring_translate(struct virtio_net *dev, struct vhost_virtqueue *vq)
+{
+       uint64_t size;
+
+       if (!(dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM)))
+               goto out;
+
+       size = sizeof(struct vring_desc) * vq->size;
+       vq->desc = (struct vring_desc *)(uintptr_t)vhost_iova_to_vva(dev, vq,
+                                               vq->ring_addrs.desc_user_addr,
+                                               size, VHOST_ACCESS_RW);
+       if (!vq->desc)
+               return -1;
+
+       size = sizeof(struct vring_avail);
+       size += sizeof(uint16_t) * vq->size;
+       vq->avail = (struct vring_avail *)(uintptr_t)vhost_iova_to_vva(dev, vq,
+                                               vq->ring_addrs.avail_user_addr,
+                                               size, VHOST_ACCESS_RW);
+       if (!vq->avail)
+               return -1;
+
+       size = sizeof(struct vring_used);
+       size += sizeof(struct vring_used_elem) * vq->size;
+       vq->used = (struct vring_used *)(uintptr_t)vhost_iova_to_vva(dev, vq,
+                                               vq->ring_addrs.used_user_addr,
+                                               size, VHOST_ACCESS_RW);
+       if (!vq->used)
+               return -1;
+
+out:
+       vq->access_ok = 1;
+
+       return 0;
+}
+
+void
+vring_invalidate(struct virtio_net *dev, struct vhost_virtqueue *vq)
+{
+       if (dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM))
+               vhost_user_iotlb_wr_lock(vq);
+
+       vq->access_ok = 0;
+       vq->desc = NULL;
+       vq->avail = NULL;
+       vq->used = NULL;
+
+       if (dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM))
+               vhost_user_iotlb_wr_unlock(vq);
+}
+
 static void
 init_vring_queue(struct virtio_net *dev, uint32_t vring_idx)
 {
@@ -159,12 +223,6 @@ init_vring_queue(struct virtio_net *dev, uint32_t vring_idx)
        /* Backends are set to -1 indicating an inactive device. */
        vq->backend = -1;
 
-       /*
-        * always set the vq to enabled; this is to keep compatibility
-        * with the old QEMU, whereas there is no SET_VRING_ENABLE message.
-        */
-       vq->enabled = 1;
-
        TAILQ_INIT(&vq->zmbuf_list);
 }