diff options
Diffstat (limited to 'vfio-iommu-map-unmap.c')
-rw-r--r-- | vfio-iommu-map-unmap.c | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/vfio-iommu-map-unmap.c b/vfio-iommu-map-unmap.c new file mode 100644 index 0000000..a5d5c46 --- /dev/null +++ b/vfio-iommu-map-unmap.c @@ -0,0 +1,161 @@ +#include <errno.h> +#include <libgen.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <linux/ioctl.h> +#include <linux/vfio.h> + +#define MAP_SIZE (1UL * 1024 * 1024 * 1024) +#define MAP_CHUNK (4 * 1024) +#define REALLOC_INTERVAL 30 + +void usage(char *name) +{ + printf("usage: %s <group id> <allocs> \n", name); +} + +int main(int argc, char **argv) +{ + int ret, container, group; + char path[64]; + unsigned long i, count, max; + void **maps; + struct vfio_group_status group_status = { + .argsz = sizeof(group_status) + }; + struct vfio_iommu_type1_dma_map dma_map = { + .argsz = sizeof(dma_map) + }; + struct vfio_iommu_type1_dma_unmap dma_unmap = { + .argsz = sizeof(dma_unmap) + }; + + if (argc != 3) { + usage(argv[0]); + return -1; + } + + container = open("/dev/vfio/vfio", O_RDWR); + if (container < 0) { + printf("Failed to open /dev/vfio/vfio, %d (%s)\n", + container, strerror(errno)); + return container; + } + + snprintf(path, sizeof(path), "/dev/vfio/%d", atoi(argv[1])); + group = open(path, O_RDWR); + if (group < 0) { + printf("Failed to open %s, %d (%s)\n", + path, group, strerror(errno)); + return group; + } + max = atoi(argv[2]); + + ret = ioctl(group, VFIO_GROUP_GET_STATUS, &group_status); + if (ret) { + printf("ioctl(VFIO_GROUP_GET_STATUS) failed\n"); + return ret; + } + + if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE)) { + printf("Group not viable, are all devices attached to vfio?\n"); + return -1; + } + + ret = ioctl(group, VFIO_GROUP_SET_CONTAINER, &container); + if (ret) { + printf("Failed to set group container\n"); + return ret; + } + + ret = ioctl(container, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU); + if (ret) { + printf("Failed to set IOMMU\n"); + return ret; + } + + /* Test code */ + dma_map.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE; + dma_map.size = MAP_CHUNK; + dma_unmap.size = MAP_SIZE; + dma_unmap.iova = 0; + + /* Track our mmaps for re-use */ + maps = malloc(sizeof(void *) * (MAP_SIZE/dma_map.size)); + if (!maps) { + printf("Failed to allocate map (%s)\n", strerror(errno)); + return -1; + } + + memset(maps, 0, sizeof(void *) * (MAP_SIZE/dma_map.size)); + + for (count = 0; count < max; count++) { + + /* Every REALLOC_INTERVAL, dump our mappings to give THP something to collapse */ + if (count % REALLOC_INTERVAL == 0) { + for (i = 0; i < MAP_SIZE/dma_map.size; i++) { + if (maps[i]) { + munmap(maps[i], dma_map.size); + maps[i] = NULL; + } + } + if (count) { + printf("\t%ld\n", count); + //return 0; + } + printf("|"); + fflush(stdout); + } + + /* Map MAP_CHUNK at a time, each chunk is pinned on map, so THP can't do anything until unmap */ + for (i = dma_map.iova = 0; i < MAP_SIZE/dma_map.size; i++, dma_map.iova += dma_map.size) { + if (!maps[i]) { + maps[i] = mmap(NULL, dma_map.size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (maps[i] == MAP_FAILED) { + printf("Failed to mmap memory (%s)\n", strerror(errno)); + return -1; + } + } + + ret = madvise(maps[i], dma_map.size, MADV_HUGEPAGE); + if (ret) { + printf("Madvise failed (%s)\n", strerror(errno)); + } + + dma_map.vaddr = (unsigned long)maps[i]; + + ret = ioctl(container, VFIO_IOMMU_MAP_DMA, &dma_map); + if (ret) { + printf("Failed to map memory (%s)\n", + strerror(errno)); + return ret; + } + } + + printf("+"); + fflush(stdout); + + /* Unmap everything at once */ + ret = ioctl(container, VFIO_IOMMU_UNMAP_DMA, &dma_unmap); + if (ret) { + printf("Failed to unmap memory (%s)\n", strerror(errno)); + return ret; + } + + printf("-"); + fflush(stdout); + } + printf("\n"); + + return 0; +} |