In order to implement VFIO_DEVICE_FEATURE_DMA_BUF, we first need to identify the PCI region the buffer (represented by iovec) belongs to and then translate its addresses to offsets within that region.
The qemu_ram_block_from_host() API gives us both the region and the offset info we need to populate the dma ranges in order to invoke this feature. Cc: Alex Williamson <[email protected]> Cc: Cédric Le Goater <[email protected]> Signed-off-by: Vivek Kasireddy <[email protected]> --- hw/vfio/region.c | 49 +++++++++++++++++++++++++++++++++++ include/hw/vfio/vfio-device.h | 3 +++ 2 files changed, 52 insertions(+) diff --git a/hw/vfio/region.c b/hw/vfio/region.c index d04c57db63..b58188147c 100644 --- a/hw/vfio/region.c +++ b/hw/vfio/region.c @@ -28,6 +28,7 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/units.h" +#include "system/ramblock.h" #include "monitor/monitor.h" #include "vfio-helpers.h" @@ -401,3 +402,51 @@ void vfio_region_mmaps_set_enabled(VFIORegion *region, bool enabled) trace_vfio_region_mmaps_set_enabled(memory_region_name(region->mem), enabled); } + +int vfio_device_create_dmabuf(VFIODevice *vdev, + struct iovec *iov, unsigned int iov_cnt) +{ + g_autofree struct vfio_device_feature *feature; + struct vfio_device_feature_dma_buf *dma_buf; + VFIORegion *region; + ram_addr_t offset; + MemoryRegion *mr; + RAMBlock *rb; + size_t argsz; + int i; + + argsz = sizeof(*feature) + sizeof (*dma_buf) + + sizeof(struct vfio_region_dma_range) * iov_cnt; + feature = g_malloc0(argsz); + dma_buf = (struct vfio_device_feature_dma_buf *)feature->data; + + for (i = 0; i < iov_cnt; i++) { + rcu_read_lock(); + rb = qemu_ram_block_from_host(iov[i].iov_base, false, &offset); + rcu_read_unlock(); + + if (!rb) { + return -1; + } + + mr = rb->mr; + if (mr->ops != &vfio_region_ops) { + mr = mr->container; + if (mr->ops != &vfio_region_ops) { + return -1; + } + } + + region = mr->opaque; + dma_buf->region_index = region->nr; + dma_buf->dma_ranges[i].offset = offset; + dma_buf->dma_ranges[i].length = iov[i].iov_len; + } + + dma_buf->nr_ranges = iov_cnt; + dma_buf->open_flags = O_RDONLY | O_CLOEXEC; + feature->argsz = argsz; + feature->flags = VFIO_DEVICE_FEATURE_GET | VFIO_DEVICE_FEATURE_DMA_BUF; + + return ioctl(vdev->fd, VFIO_DEVICE_FEATURE, feature); +} diff --git a/include/hw/vfio/vfio-device.h b/include/hw/vfio/vfio-device.h index 6e4d5ccdac..e127abd5f0 100644 --- a/include/hw/vfio/vfio-device.h +++ b/include/hw/vfio/vfio-device.h @@ -277,6 +277,9 @@ bool vfio_device_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_t int vfio_device_get_irq_info(VFIODevice *vbasedev, int index, struct vfio_irq_info *info); + +int vfio_device_create_dmabuf(VFIODevice *vbasedev, + struct iovec *iov, unsigned int iov_cnt); #endif /* Returns 0 on success, or a negative errno. */ -- 2.50.1
