289 lines
10 KiB
Diff
289 lines
10 KiB
Diff
|
|
From b88b03c84aa695b96a91329e2d01fffad551c34d Mon Sep 17 00:00:00 2001
|
||
|
|
From: libai <libai12@huawei.com>
|
||
|
|
Date: Thu, 27 Mar 2025 19:24:53 +0800
|
||
|
|
Subject: [PATCH] vdpa/iommufd:Implement DMA mapping through the iommufd
|
||
|
|
interface
|
||
|
|
|
||
|
|
Change the owner of memorylistener from the independent vDPA device to VDPAIOMMUFDContainer
|
||
|
|
|
||
|
|
Signed-off-by: libai <libai12@huawei.com>
|
||
|
|
---
|
||
|
|
hw/virtio/vdpa-dev-iommufd.c | 137 +++++++++++++++++++++++++++
|
||
|
|
hw/virtio/vdpa-dev.c | 4 +-
|
||
|
|
hw/virtio/vhost-vdpa.c | 13 +--
|
||
|
|
include/hw/virtio/vdpa-dev-iommufd.h | 1 +
|
||
|
|
include/hw/virtio/vhost-vdpa.h | 7 ++
|
||
|
|
5 files changed, 154 insertions(+), 8 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/hw/virtio/vdpa-dev-iommufd.c b/hw/virtio/vdpa-dev-iommufd.c
|
||
|
|
index d72f56d52f..668c6a1cb1 100644
|
||
|
|
--- a/hw/virtio/vdpa-dev-iommufd.c
|
||
|
|
+++ b/hw/virtio/vdpa-dev-iommufd.c
|
||
|
|
@@ -9,11 +9,124 @@
|
||
|
|
#include <sys/ioctl.h>
|
||
|
|
#include <linux/vhost.h>
|
||
|
|
#include "qapi/error.h"
|
||
|
|
+#include "exec/target_page.h"
|
||
|
|
+#include "exec/address-spaces.h"
|
||
|
|
#include "hw/virtio/vdpa-dev-iommufd.h"
|
||
|
|
|
||
|
|
static QLIST_HEAD(, VDPAIOMMUFDContainer) vdpa_container_list =
|
||
|
|
QLIST_HEAD_INITIALIZER(vdpa_container_list);
|
||
|
|
|
||
|
|
+static int vhost_vdpa_iommufd_container_dma_map(VDPAIOMMUFDContainer *container, hwaddr iova,
|
||
|
|
+ hwaddr size, void *vaddr, bool readonly)
|
||
|
|
+{
|
||
|
|
+ return iommufd_backend_map_dma(container->iommufd, container->ioas_id, iova, size, vaddr, readonly);
|
||
|
|
+
|
||
|
|
+}
|
||
|
|
+static int vhost_vdpa_iommufd_container_dma_unmap(VDPAIOMMUFDContainer *container,
|
||
|
|
+ hwaddr iova, hwaddr size)
|
||
|
|
+{
|
||
|
|
+ return iommufd_backend_unmap_dma(container->iommufd, container->ioas_id, iova, size);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static void vhost_vdpa_iommufd_container_region_add(MemoryListener *listener,
|
||
|
|
+ MemoryRegionSection *section)
|
||
|
|
+{
|
||
|
|
+ VDPAIOMMUFDContainer *container = container_of(listener, VDPAIOMMUFDContainer, listener);
|
||
|
|
+ hwaddr iova;
|
||
|
|
+ Int128 llend, llsize;
|
||
|
|
+ void *vaddr;
|
||
|
|
+ int page_size = qemu_target_page_size();
|
||
|
|
+ int page_mask = -page_size;
|
||
|
|
+ int ret;
|
||
|
|
+
|
||
|
|
+ if (vhost_vdpa_listener_skipped_section(section, 0, ULLONG_MAX, page_mask)) {
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (unlikely((section->offset_within_address_space & ~page_mask) !=
|
||
|
|
+ (section->offset_within_region & ~page_mask))) {
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ iova = ROUND_UP(section->offset_within_address_space, page_size);
|
||
|
|
+ llend = vhost_vdpa_section_end(section, page_mask);
|
||
|
|
+ if (int128_ge(int128_make64(iova), llend)) {
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ memory_region_ref(section->mr);
|
||
|
|
+ vaddr = memory_region_get_ram_ptr(section->mr) +
|
||
|
|
+ section->offset_within_region +
|
||
|
|
+ (iova - section->offset_within_address_space);
|
||
|
|
+
|
||
|
|
+ llsize = int128_sub(llend, int128_make64(iova));
|
||
|
|
+
|
||
|
|
+ ret = vhost_vdpa_iommufd_container_dma_map(container, iova, int128_get64(llsize),
|
||
|
|
+ vaddr, section->readonly);
|
||
|
|
+ if (ret) {
|
||
|
|
+ qemu_log("vhost vdpa iommufd container dma map failed: %d\n", ret);
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static void vhost_vdpa_iommufd_container_region_del(MemoryListener *listener,
|
||
|
|
+ MemoryRegionSection *section)
|
||
|
|
+{
|
||
|
|
+ VDPAIOMMUFDContainer *container = container_of(listener, VDPAIOMMUFDContainer, listener);
|
||
|
|
+ hwaddr iova;
|
||
|
|
+ Int128 llend, llsize;
|
||
|
|
+ int page_size = qemu_target_page_size();
|
||
|
|
+ int page_mask = -page_size;
|
||
|
|
+ int ret;
|
||
|
|
+
|
||
|
|
+ if (vhost_vdpa_listener_skipped_section(section, 0, ULLONG_MAX, page_mask)) {
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (unlikely((section->offset_within_address_space & ~page_mask) !=
|
||
|
|
+ (section->offset_within_region & ~page_mask))) {
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ iova = ROUND_UP(section->offset_within_address_space, page_size);
|
||
|
|
+ llend = vhost_vdpa_section_end(section, page_mask);
|
||
|
|
+
|
||
|
|
+ if (int128_ge(int128_make64(iova), llend)) {
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ llsize = int128_sub(llend, int128_make64(iova));
|
||
|
|
+ /*
|
||
|
|
+ * The unmap ioctl doesn't accept a full 64-bit. need to check it
|
||
|
|
+ */
|
||
|
|
+ if (int128_eq(llsize, int128_2_64())) {
|
||
|
|
+ llsize = int128_rshift(llsize, 1);
|
||
|
|
+ ret = vhost_vdpa_iommufd_container_dma_unmap(container, iova, int128_get64(llsize));
|
||
|
|
+
|
||
|
|
+ if (ret) {
|
||
|
|
+ qemu_log("vhost vdpa iommufd container unmap failed(0x%" HWADDR_PRIx ", "
|
||
|
|
+ "0x%" HWADDR_PRIx ") = %d (%m)", iova, int128_get64(llsize), ret);
|
||
|
|
+ }
|
||
|
|
+ iova += int128_get64(llsize);
|
||
|
|
+ }
|
||
|
|
+ ret = vhost_vdpa_iommufd_container_dma_unmap(container, iova, int128_get64(llsize));
|
||
|
|
+
|
||
|
|
+ if (ret) {
|
||
|
|
+ qemu_log("vhost vdpa iommufd container unmap failed(0x%" HWADDR_PRIx ", "
|
||
|
|
+ "0x%" HWADDR_PRIx ") = %d (%m)", iova, int128_get64(llsize), ret);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ memory_region_unref(section->mr);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * IOTLB API used by vhost vdpa iommufd container
|
||
|
|
+ */
|
||
|
|
+const MemoryListener vhost_vdpa_iommufd_container_listener = {
|
||
|
|
+ .name = "vhost-vdpa-iommufd-container",
|
||
|
|
+ .region_add = vhost_vdpa_iommufd_container_region_add,
|
||
|
|
+ .region_del = vhost_vdpa_iommufd_container_region_del,
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
static int vhost_vdpa_container_connect_iommufd(VDPAIOMMUFDContainer *container)
|
||
|
|
{
|
||
|
|
IOMMUFDBackend *iommufd = container->iommufd;
|
||
|
|
@@ -87,6 +200,7 @@ static VDPAIOMMUFDContainer *vhost_vdpa_create_container(VhostVdpaDevice *vdev)
|
||
|
|
|
||
|
|
container = g_new0(VDPAIOMMUFDContainer, 1);
|
||
|
|
container->iommufd = vdev->iommufd;
|
||
|
|
+ container->listener = vhost_vdpa_iommufd_container_listener;
|
||
|
|
QLIST_INIT(&container->hwpt_list);
|
||
|
|
|
||
|
|
QLIST_INSERT_HEAD(&vdpa_container_list, container, next);
|
||
|
|
@@ -213,11 +327,27 @@ static void vhost_vdpa_container_detach_device(VDPAIOMMUFDContainer *container,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
+static int vhost_vdpa_container_get_dev_count(VDPAIOMMUFDContainer *container)
|
||
|
|
+{
|
||
|
|
+ IOMMUFDHWPT *hwpt;
|
||
|
|
+ VhostVdpaDevice *dev;
|
||
|
|
+ int dev_count = 0;
|
||
|
|
+
|
||
|
|
+ QLIST_FOREACH(hwpt, &container->hwpt_list, next) {
|
||
|
|
+ QLIST_FOREACH(dev, &hwpt->device_list, next) {
|
||
|
|
+ dev_count++;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return dev_count;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
int vhost_vdpa_attach_container(VhostVdpaDevice *vdev)
|
||
|
|
{
|
||
|
|
VDPAIOMMUFDContainer *container = NULL;
|
||
|
|
IOMMUFDBackend *iommufd = vdev->iommufd;
|
||
|
|
bool new_container = false;
|
||
|
|
+ int dev_count = 0;
|
||
|
|
int ret = 0;
|
||
|
|
|
||
|
|
if (!iommufd) {
|
||
|
|
@@ -251,6 +381,12 @@ int vhost_vdpa_attach_container(VhostVdpaDevice *vdev)
|
||
|
|
goto unbind;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ /* register the container memory listener when attaching the first device */
|
||
|
|
+ dev_count = vhost_vdpa_container_get_dev_count(container);
|
||
|
|
+ if (dev_count == 1) {
|
||
|
|
+ memory_listener_register(&container->listener, &address_space_memory);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
unbind:
|
||
|
|
@@ -288,6 +424,7 @@ void vhost_vdpa_detach_container(VhostVdpaDevice *vdev)
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
/* No HWPT in this container, destroy it */
|
||
|
|
+ memory_listener_unregister(&container->listener);
|
||
|
|
vhost_vdpa_container_disconnect_iommufd(container);
|
||
|
|
|
||
|
|
vhost_vdpa_destroy_container(container);
|
||
|
|
diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c
|
||
|
|
index a6bd695724..b256ad540c 100644
|
||
|
|
--- a/hw/virtio/vdpa-dev.c
|
||
|
|
+++ b/hw/virtio/vdpa-dev.c
|
||
|
|
@@ -136,9 +136,9 @@ static void vhost_vdpa_device_realize(DeviceState *dev, Error **errp)
|
||
|
|
strerror(-ret));
|
||
|
|
goto free_vqs;
|
||
|
|
}
|
||
|
|
+ } else {
|
||
|
|
+ memory_listener_register(&v->vdpa.listener, &address_space_memory);
|
||
|
|
}
|
||
|
|
-
|
||
|
|
- memory_listener_register(&v->vdpa.listener, &address_space_memory);
|
||
|
|
v->config_size = vhost_vdpa_device_get_u32(v->vhostfd,
|
||
|
|
VHOST_VDPA_GET_CONFIG_SIZE,
|
||
|
|
errp);
|
||
|
|
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
|
||
|
|
index 4a8fc37851..b5fb89b98e 100644
|
||
|
|
--- a/hw/virtio/vhost-vdpa.c
|
||
|
|
+++ b/hw/virtio/vhost-vdpa.c
|
||
|
|
@@ -26,13 +26,14 @@
|
||
|
|
#include "qemu/main-loop.h"
|
||
|
|
#include "trace.h"
|
||
|
|
#include "qapi/error.h"
|
||
|
|
+#include "hw/virtio/vdpa-dev-iommufd.h"
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Return one past the end of the end of section. Be careful with uint64_t
|
||
|
|
* conversions!
|
||
|
|
*/
|
||
|
|
-static Int128 vhost_vdpa_section_end(const MemoryRegionSection *section,
|
||
|
|
- int page_mask)
|
||
|
|
+Int128 vhost_vdpa_section_end(const MemoryRegionSection *section,
|
||
|
|
+ int page_mask)
|
||
|
|
{
|
||
|
|
Int128 llend = int128_make64(section->offset_within_address_space);
|
||
|
|
llend = int128_add(llend, section->size);
|
||
|
|
@@ -41,10 +42,10 @@ static Int128 vhost_vdpa_section_end(const MemoryRegionSection *section,
|
||
|
|
return llend;
|
||
|
|
}
|
||
|
|
|
||
|
|
-static bool vhost_vdpa_listener_skipped_section(MemoryRegionSection *section,
|
||
|
|
- uint64_t iova_min,
|
||
|
|
- uint64_t iova_max,
|
||
|
|
- int page_mask)
|
||
|
|
+bool vhost_vdpa_listener_skipped_section(MemoryRegionSection *section,
|
||
|
|
+ uint64_t iova_min,
|
||
|
|
+ uint64_t iova_max,
|
||
|
|
+ int page_mask)
|
||
|
|
{
|
||
|
|
Int128 llend;
|
||
|
|
|
||
|
|
diff --git a/include/hw/virtio/vdpa-dev-iommufd.h b/include/hw/virtio/vdpa-dev-iommufd.h
|
||
|
|
index dc14d9dd15..8e56647690 100644
|
||
|
|
--- a/include/hw/virtio/vdpa-dev-iommufd.h
|
||
|
|
+++ b/include/hw/virtio/vdpa-dev-iommufd.h
|
||
|
|
@@ -23,6 +23,7 @@ typedef struct IOMMUFDHWPT {
|
||
|
|
} IOMMUFDHWPT;
|
||
|
|
|
||
|
|
typedef struct VDPAIOMMUFDContainer {
|
||
|
|
+ MemoryListener listener;
|
||
|
|
struct IOMMUFDBackend *iommufd;
|
||
|
|
uint32_t ioas_id;
|
||
|
|
QLIST_HEAD(, IOMMUFDHWPT) hwpt_list;
|
||
|
|
diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h
|
||
|
|
index ee255bc1bd..e32effc6e1 100644
|
||
|
|
--- a/include/hw/virtio/vhost-vdpa.h
|
||
|
|
+++ b/include/hw/virtio/vhost-vdpa.h
|
||
|
|
@@ -57,6 +57,13 @@ typedef struct vhost_vdpa {
|
||
|
|
int vhost_vdpa_get_iova_range(int fd, struct vhost_vdpa_iova_range *iova_range);
|
||
|
|
int vhost_vdpa_set_vring_ready(struct vhost_vdpa *v, unsigned idx);
|
||
|
|
|
||
|
|
+Int128 vhost_vdpa_section_end(const MemoryRegionSection *section,
|
||
|
|
+ int page_mask);
|
||
|
|
+bool vhost_vdpa_listener_skipped_section(MemoryRegionSection *section,
|
||
|
|
+ uint64_t iova_min,
|
||
|
|
+ uint64_t iova_max,
|
||
|
|
+ int page_mask);
|
||
|
|
+
|
||
|
|
int vhost_vdpa_dma_map(struct vhost_vdpa *v, uint32_t asid, hwaddr iova,
|
||
|
|
hwaddr size, void *vaddr, bool readonly);
|
||
|
|
int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, uint32_t asid, hwaddr iova,
|
||
|
|
--
|
||
|
|
2.41.0.windows.1
|
||
|
|
|