[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC PATCH v5 25/26] vhost: Use a tree to store memory mappings
From: |
Eugenio Pérez |
Subject: |
[RFC PATCH v5 25/26] vhost: Use a tree to store memory mappings |
Date: |
Fri, 29 Oct 2021 20:35:24 +0200 |
Track memory translations of devices with IOMMU (all vhost-vdpa
devices at the moment). It does not work if device has restrictions in
its iova range at the moment.
Updates to tree are protected by BQL, each one always run from main
event loop context.
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
---
include/hw/virtio/vhost-vdpa.h | 3 ++
hw/virtio/vhost-vdpa.c | 50 +++++++++++++++++++++++++++++++++-
2 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h
index 2f57b17208..365b102c14 100644
--- a/include/hw/virtio/vhost-vdpa.h
+++ b/include/hw/virtio/vhost-vdpa.h
@@ -14,6 +14,7 @@
#include <gmodule.h>
+#include "hw/virtio/vhost-iova-tree.h"
#include "hw/virtio/virtio.h"
#include "standard-headers/linux/vhost_types.h"
@@ -30,6 +31,8 @@ typedef struct vhost_vdpa {
MemoryListener listener;
struct vhost_vdpa_iova_range iova_range;
bool shadow_vqs_enabled;
+ /* IOVA mapping used by Shadow Virtqueue */
+ VhostIOVATree *iova_map;
GPtrArray *shadow_vqs;
struct vhost_dev *dev;
int kick_fd[VIRTIO_QUEUE_MAX];
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
index e1c55e43e7..a827ecbe4f 100644
--- a/hw/virtio/vhost-vdpa.c
+++ b/hw/virtio/vhost-vdpa.c
@@ -466,6 +466,7 @@ static void vhost_vdpa_svq_cleanup(struct vhost_dev *dev)
vhost_svq_stop(dev, idx, g_ptr_array_index(v->shadow_vqs, idx));
}
g_ptr_array_free(v->shadow_vqs, true);
+ g_clear_pointer(&v->iova_map, vhost_iova_tree_unref);
}
static int vhost_vdpa_cleanup(struct vhost_dev *dev)
@@ -822,6 +823,22 @@ static bool vhost_vdpa_force_iommu(struct vhost_dev *dev)
return true;
}
+/**
+ * Maps QEMU vaddr memory to device in a suitable way for shadow virtqueue:
+ * - It always reference qemu memory address, not guest's memory.
+ * - TODO It's always in range of device.
+ *
+ * It returns the translated address
+ */
+static int vhost_vdpa_svq_map(struct vhost_vdpa *v, DMAMap *map)
+{
+ int r = vhost_iova_tree_map_alloc(v->iova_map, map);
+ assert(r == IOVA_OK);
+
+ return vhost_vdpa_dma_map(v, map->iova, map->size,
+ (void *)map->translated_addr, false);
+}
+
static int vhost_vdpa_vring_pause(struct vhost_dev *dev)
{
int r;
@@ -872,8 +889,36 @@ static bool vhost_vdpa_svq_start_vq(struct vhost_dev *dev,
unsigned idx,
if (svq_mode) {
const EventNotifier *vhost_kick = vhost_svq_get_dev_kick_notifier(svq);
const EventNotifier *vhost_call = vhost_svq_get_svq_call_notifier(svq);
+ DMAMap device_region, driver_region;
vhost_svq_get_vring_addr(svq, &addr);
+ driver_region = (DMAMap) {
+ .translated_addr = (hwaddr)addr.desc_user_addr,
+
+ /*
+ * DMAMAp.size include the last byte included in the range, while
+ * sizeof marks one past it. Substract one byte to make them match.
+ */
+ .size = vhost_svq_driver_area_size(svq) - 1,
+ .perm = VHOST_ACCESS_RO,
+ };
+ device_region = (DMAMap) {
+ .translated_addr = (hwaddr)addr.used_user_addr,
+ .size = vhost_svq_device_area_size(svq) - 1,
+ .perm = VHOST_ACCESS_RW,
+ };
+
+ r = vhost_vdpa_svq_map(v, &driver_region);
+ assert(r == 0);
+ r = vhost_vdpa_svq_map(v, &device_region);
+ assert(r == 0);
+
+ /* Expose IOVA addresses to vDPA device */
+ addr.avail_user_addr = driver_region.iova + addr.avail_user_addr
+ - addr.desc_user_addr;
+ addr.desc_user_addr = driver_region.iova;
+ addr.used_user_addr = device_region.iova;
+
if (n->addr) {
r = virtio_queue_set_host_notifier_mr(dev->vdev, idx, &n->mr,
false);
@@ -885,7 +930,6 @@ static bool vhost_vdpa_svq_start_vq(struct vhost_dev *dev,
unsigned idx,
assert(r == 0);
vhost_svq_set_host_mr_notifier(svq, n->addr);
}
-
vhost_svq_set_guest_call_notifier(svq, v->call_fd[idx]);
vhost_svq_start(dev, idx, svq, v->kick_fd[idx]);
@@ -1001,6 +1045,7 @@ static bool vhost_vdpa_valid_features(struct vhost_dev
*hdev,
void vhost_vdpa_enable_svq(struct vhost_vdpa *v, bool enable, Error **errp)
{
struct vhost_dev *hdev = v->dev;
+ hwaddr iova_first = v->iova_range.first, iova_last = v->iova_range.last;
unsigned n;
int r;
uint64_t svq_features = hdev->features | BIT_ULL(VIRTIO_F_IOMMU_PLATFORM) |
@@ -1017,6 +1062,8 @@ void vhost_vdpa_enable_svq(struct vhost_vdpa *v, bool
enable, Error **errp)
return;
}
+ v->iova_map = vhost_iova_tree_new(iova_first, iova_last);
+
/* Allocate resources */
assert(v->shadow_vqs->len == 0);
for (n = 0; n < hdev->nvqs; ++n) {
@@ -1093,6 +1140,7 @@ err_svq_new:
if (!enable) {
/* Resources cleanup */
g_ptr_array_set_size(v->shadow_vqs, 0);
+ g_clear_pointer(&v->iova_map, vhost_iova_tree_unref);
}
}
--
2.27.0
- [RFC PATCH v5 15/26] vdpa: Save call_fd in vhost-vdpa, (continued)
- [RFC PATCH v5 15/26] vdpa: Save call_fd in vhost-vdpa, Eugenio Pérez, 2021/10/29
- [RFC PATCH v5 16/26] vhost-vdpa: Take into account SVQ in vhost_vdpa_set_vring_call, Eugenio Pérez, 2021/10/29
- [RFC PATCH v5 17/26] vhost: Route host->guest notification through shadow virtqueue, Eugenio Pérez, 2021/10/29
- [RFC PATCH v5 18/26] virtio: Add vhost_shadow_vq_get_vring_addr, Eugenio Pérez, 2021/10/29
- [RFC PATCH v5 19/26] vdpa: ack VIRTIO_F_QUEUE_STATE if device supports it, Eugenio Pérez, 2021/10/29
- [RFC PATCH v5 20/26] vhost: Add vhost_svq_valid_device_features to shadow vq, Eugenio Pérez, 2021/10/29
- [RFC PATCH v5 21/26] vhost: Add vhost_svq_valid_guest_features to shadow vq, Eugenio Pérez, 2021/10/29
- [RFC PATCH v5 22/26] vhost: Shadow virtqueue buffers forwarding, Eugenio Pérez, 2021/10/29
- [RFC PATCH v5 23/26] util: Add iova_tree_alloc, Eugenio Pérez, 2021/10/29
- [RFC PATCH v5 24/26] vhost: Add VhostIOVATree, Eugenio Pérez, 2021/10/29
- [RFC PATCH v5 25/26] vhost: Use a tree to store memory mappings,
Eugenio Pérez <=
- [RFC PATCH v5 26/26] vdpa: Add custom IOTLB translations to SVQ, Eugenio Pérez, 2021/10/29