diff options
author | Ilias Apalodimas <ilias.apalodimas@linaro.org> | 2017-10-06 13:09:39 +0300 |
---|---|---|
committer | Ilias Apalodimas <ilias.apalodimas@linaro.org> | 2017-10-06 13:09:39 +0300 |
commit | 5798d785e263d18d62c1e698551a7bc932addca8 (patch) | |
tree | e4ccef0488d42b80131167d726ce775c8fc89bc6 | |
parent | b53f7b98be89a8c908ce4d87018329b3bb15ab04 (diff) |
Managed to map/pin DMA memory
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | README | 7 | ||||
-rwxr-xr-x | build.sh | 4 | ||||
-rw-r--r-- | ether-test.c (renamed from test.c) | 1 | ||||
-rw-r--r-- | vfio-iommu-map-unmap.c | 161 | ||||
-rw-r--r-- | vfio-netem.c | 26 |
6 files changed, 185 insertions, 18 deletions
@@ -3,7 +3,9 @@ *.cmd Module.symvers modules.order -test_dma vfio-netem.mod.c .tmp_versions/ tags +ether_test +map_unmap + @@ -20,3 +20,10 @@ sudo ./pcimem /sys/devices/pci0000:00/0000:00:1c.3/0000:04:00.0/resource2 0 w sudo ./pcimem /sys/devices/pci0000:00/0000:00:1c.3/0000:04:00.0/resource4 16368 w run ./test_dma + +# Enable kernel debug +echo file drivers/iommu/iommu.c line 1533-1600 +p > /sys/kernel/debug/dynamic_debug/control +or +echo file drivers/iommu/iommu.c func iommu_map +p > /sys/kernel/debug/dynamic_debug/control +or +echo file drivers/iommu/iommu.c +p > /sys/kernel/debug/dynamic_debug/control @@ -2,7 +2,9 @@ what=$1 if [ -n "$1" -a "$1" = 'clean' ]; then make -C /lib/modules/`uname -r`/build M=`pwd` modules clean + rm map_unmap ether_test -f else make -C /lib/modules/`uname -r`/build M=`pwd` modules - gcc test.c -o test_dma -Werror -Wall -Wunused -O2 + gcc ether-test.c -o ether_test -Werror -Wall -Wunused -O2 + gcc vfio-iommu-map-unmap.c -o map_unmap -Werror -Wall -Wunused -O2 fi @@ -13,6 +13,7 @@ #include "reg_api.h" const char glob_uuid[] = "d0b24768-9c51-11e7-8de5-c7b0c2769e69"; +/* iommu alignment */ #define TEST_SIZE 1024 * 1024 #define EOR (1 << 30) #define OWN (1 << 31) 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; +} diff --git a/vfio-netem.c b/vfio-netem.c index 2083007..97ff951 100644 --- a/vfio-netem.c +++ b/vfio-netem.c @@ -138,19 +138,16 @@ static const struct attribute_group *vfio_attr_groups[] = { static int vfio_net_create(struct kobject *kobj, struct mdev_device *mdev) { - struct device *dev = mdev_parent_dev(mdev); - //struct iommu_domain *domain; - - dev_info(dev, "MDEV-NETEM: Create on parent\n"); - //domain = iommu_get_domain_for_dev(dev); - //if (domain) - //iommu_detach_device(domain, dev); - if (dev && dev->driver && dev->driver->name) - printk("AA %s\n", dev->driver->name); + struct device *dev = mdev_parent_dev(mdev); + struct iommu_domain *domain; - if (dev->parent && dev->parent->driver && dev->parent->driver->name) - printk("BB %s\n", dev->parent->driver->name); + dev_info(dev, "MDEV-NETEM: Create mdev for %s\n", dev_name(dev)); + domain = iommu_get_domain_for_dev(dev->parent->parent->parent); + if (domain) { + printk("AA Detach domain\n"); + iommu_detach_device(domain, dev->parent->parent->parent); + } /* Inherit parent's iommu_ops */ if (dev && dev->parent && dev->parent->bus && @@ -158,7 +155,8 @@ static int vfio_net_create(struct kobject *kobj, struct mdev_device *mdev) mdev->dev.bus->iommu_ops = dev->parent->bus->iommu_ops; //XXX dont do that //mdev->dev.iommu_group = dev->parent->iommu_group; - dev_info(dev, "MDEV-NETEM: Set mdev iommu_ops\n"); + dev_info(dev, "MDEV-NETEM: Inherit %s iommu_ops\n", + dev_name(dev->parent)); } return 0; @@ -338,9 +336,6 @@ int vfio_vring_init(struct device *dev) } err = mdev_register_device(dev, &vfio_net_ops); - if (!err) - dev_info(dev, "MDEV-NETEM: Register for driver %s", - pdev->driver->name); return err; @@ -351,7 +346,6 @@ out_inv_dev: void vfio_vring_destroy(struct device *dev) { - dev_info(dev, "MDEV-NETEM: Unregistering\n"); mdev_unregister_device(dev); } |