summaryrefslogtreecommitdiffstats
path: root/vhost_loopback.c
diff options
context:
space:
mode:
Diffstat (limited to 'vhost_loopback.c')
-rw-r--r--vhost_loopback.c94
1 files changed, 80 insertions, 14 deletions
diff --git a/vhost_loopback.c b/vhost_loopback.c
index 0dc5c52..3e137eb 100644
--- a/vhost_loopback.c
+++ b/vhost_loopback.c
@@ -148,9 +148,14 @@ static int vhost_virtqueue_set_addr(struct vhost_dev *dev,
memset(&addr, 0, sizeof(struct vhost_vring_addr));
- addr.desc_user_addr = (uint64_t)(unsigned long)vq->desc;
- addr.avail_user_addr = (uint64_t)(unsigned long)vq->avail;
- addr.used_user_addr = (uint64_t)(unsigned long)vq->used;
+ addr.desc_user_addr = (uint64_t)(unsigned long)vq->desc_phys;
+ addr.avail_user_addr = (uint64_t)(unsigned long)vq->avail_phys;
+ addr.used_user_addr = (uint64_t)(unsigned long)vq->used_phys;
+
+ DBG("Print physical addresses of vrings:\n");
+ DBG("\tvq->desc_phys: 0x%llx\n", vq->desc_phys);
+ DBG("\tvq->avail_phys: 0x%llx\n", vq->avail_phys);
+ DBG("\tvq->used_phys: 0x%llx\n", vq->used_phys);
addr.index = idx;
addr.log_guest_addr = vq->used_phys;
@@ -163,6 +168,34 @@ static int vhost_virtqueue_set_addr(struct vhost_dev *dev,
return r;
}
+uint64_t vhost_get_features(struct vhost_dev *hdev, const int *feature_bits,
+ uint64_t features)
+{
+ const int *bit = feature_bits;
+ while (*bit != VHOST_INVALID_FEATURE_BIT) {
+ uint64_t bit_mask = (1ULL << *bit);
+ if (!(hdev->features & bit_mask)) {
+ features &= ~bit_mask;
+ }
+ bit++;
+ }
+ return features;
+}
+
+void vhost_ack_features(struct vhost_dev *hdev, const int *feature_bits,
+ uint64_t features)
+{
+ const int *bit = feature_bits;
+ while (*bit != VHOST_INVALID_FEATURE_BIT) {
+ uint64_t bit_mask = (1ULL << *bit);
+ if (features & bit_mask) {
+ hdev->acked_features |= bit_mask;
+ }
+ bit++;
+ }
+}
+
+
/* Mask/unmask events from this vq. */
void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
@@ -207,6 +240,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
a = virtio_queue_get_desc_addr(vdev, idx);
if (a == 0) {
/* Queue might not be ready for start */
+ DBG("Error: Queue might not be ready for start\n");
return 0;
}
@@ -226,8 +260,8 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
}
vq->desc_size = s = l = virtio_queue_get_desc_size(vdev, idx);
- vq->desc_phys = a;
- vq->desc = (void *)a;
+ vq->desc_phys = vring_phys_addrs[idx] << 12;
+ vq->desc = (void *)virtio_queue_get_desc_addr(vdev, idx);
if (!vq->desc || l != s) {
DBG("Error : vq->desc = a\n");
r = -ENOMEM;
@@ -235,8 +269,9 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
}
vq->avail_size = s = l = virtio_queue_get_avail_size(vdev, idx);
- vq->avail_phys = a = virtio_queue_get_avail_addr(vdev, idx);
- vq->avail = (void *)a;
+ vq->avail_phys = vq->desc_phys + virtio_queue_get_avail_addr(vdev, idx)
+ - virtio_queue_get_desc_addr(vdev, idx);
+ vq->avail = (void *)virtio_queue_get_avail_addr(vdev, idx);
if (!vq->avail || l != s) {
DBG("Error : vq->avail = a\n");
r = -ENOMEM;
@@ -244,8 +279,9 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
}
vq->used_size = s = l = virtio_queue_get_used_size(vdev, idx);
- vq->used_phys = a = virtio_queue_get_used_addr(vdev, idx);
- vq->used = (void *)a;
+ vq->used_phys = a = vq->avail_phys + virtio_queue_get_used_addr(vdev, idx)
+ - virtio_queue_get_avail_addr(vdev, idx);
+ vq->used = (void *)virtio_queue_get_used_addr(vdev, idx);
if (!vq->used || l != s) {
DBG("Error : vq->used = a\n");
r = -ENOMEM;
@@ -277,12 +313,10 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
* will do it later.
*/
if (!vdev->use_guest_notifier_mask) {
- DBG("!vdev->use_guest_notifier_mask\n");
/* TODO: check and handle errors. */
vhost_virtqueue_mask(dev, vdev, idx, false);
}
- DBG("vhost_virtqueue_start return successfully\n");
return 0;
}
@@ -294,8 +328,27 @@ void update_mem_table(VirtIODevice *vdev)
(void)vhost_user_set_mem_table(vdev->vhdev);
}
+static int vhost_dev_set_vring_enable(struct vhost_dev *hdev, int enable)
+{
+ DBG("vhost_dev_set_vring_enable not yet implemented\n");
+
+ /*
+ * For vhost-user devices, if VHOST_USER_F_PROTOCOL_FEATURES has not
+ * been negotiated, the rings start directly in the enabled state, and
+ * .vhost_set_vring_enable callback will fail since
+ * VHOST_USER_SET_VRING_ENABLE is not supported.
+ */
+ if (!virtio_has_feature(hdev->backend_features,
+ VHOST_USER_F_PROTOCOL_FEATURES)) {
+ DBG("Does not have VHOST_USER_F_PROTOCOL_FEATURES\n");
+ return 0;
+ }
+
+ return vhost_user_set_vring_enable(hdev, enable);
+}
+
/* Host notifiers must be enabled at this point. */
-int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
+int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings)
{
int i, r;
@@ -312,8 +365,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
DBG("memory_listener_register?\n");
}
- /* This is used to exhange the loopback_fd to the vhost-user-device */
- vhost_user_share_fd();
+ vhost_commit_mem_regions(hdev);
for (i = 0; i < hdev->nvqs; ++i) {
r = vhost_virtqueue_start(hdev,
@@ -326,6 +378,20 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
}
}
+ if (vrings) {
+ r = vhost_dev_set_vring_enable(hdev, true);
+ if (r) {
+ DBG("Fail vhost_dev_set_vring_enable\n");
+ return r;
+ }
+ }
+
+ r = vhost_user_dev_start(hdev, true);
+ if (r) {
+ DBG("Fail vhost_dev_set_vring_enable\n");
+ return r;
+ }
+
return 0;
}