qemu/vdpa-iommufd-Implement-DMA-mapping-through-the-iommu.patch
Jiabo Feng b60d6a584c QEMU update to version 8.2.0-32:
- target/i386: csv: Release CSV3 shared pages after unmapping DMA
- target/i386: Add new CPU model ClearwaterForest
- target/i386: add sha512, sm3, sm4 feature bits
- docs: Add GNR, SRF and CWF CPU models
- target/i386: Export BHI_NO bit to guests
- target/i386: Introduce SierraForest-v2 model
- vdpa/iommufd:Implement DMA mapping through the iommufd interface
- vdpa/iommufd:Introduce vdpa-iommufd module
- vdpa/iommufd:support associating iommufd backend for vDPA devices
- Kconfig/iommufd/VDPA: Update IOMMUFD module configuration dependencies The vDPA module can also use IOMMUFD like the VFIO module.
- backends/iommufd: Get rid of qemu_open_old()
- backends/iommufd: Make iommufd_backend_*() return bool
- backends/iommufd: Fix missing ERRP_GUARD() for error_prepend()
- backends/iommufd: Remove mutex
- backends/iommufd: Remove check on number of backend users
- hw/intc: Add extioi ability of 256 vcpu interrupt routing
- hw/rtc: Fixed loongson rtc emulation errors
- hw/loongarch/boot: Adjust the loading position of the initrd
- target/loongarch: Fix the cpu unplug resource leak
- target/loongarch: fix vcpu reset command word issue
- vdpa:Fix dirty page bitmap synchronization not done after suspend for vdpa devices

Signed-off-by: Jiabo Feng <fengjiabo1@huawei.com>
(cherry picked from commit a5212066e7516ff2a316e1b2feaa75dd5ee4d17a)
2025-05-15 17:01:38 +08:00

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