Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

vfio: selftests: Keep track of DMA regions mapped into the device

Keep track of the list of DMA regions that are mapped into the device
using a linked list and a new struct vfio_dma_region and use that to add
{__,}to_iova() for converting host virtual addresses into IOVAs.

This will be used in a subsequent commit to map multiple DMA regions
into a device that are then used by drivers.

Acked-by: Shuah Khan <skhan@linuxfoundation.org>
Signed-off-by: David Matlack <dmatlack@google.com>
Link: https://lore.kernel.org/r/20250822212518.4156428-10-dmatlack@google.com
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>

authored by

David Matlack and committed by
Alex Williamson
346cd58f 47f86104

+79 -24
+20 -3
tools/testing/selftests/vfio/lib/include/vfio_util.h
··· 51 51 void *vaddr; 52 52 }; 53 53 54 + typedef u64 iova_t; 55 + 56 + #define INVALID_IOVA UINT64_MAX 57 + 58 + struct vfio_dma_region { 59 + struct list_head link; 60 + void *vaddr; 61 + iova_t iova; 62 + u64 size; 63 + }; 64 + 54 65 struct vfio_pci_device { 55 66 int fd; 56 67 int group_fd; ··· 73 62 74 63 struct vfio_irq_info msi_info; 75 64 struct vfio_irq_info msix_info; 65 + 66 + struct list_head dma_regions; 76 67 77 68 /* eventfds for MSI and MSI-x interrupts */ 78 69 int msi_eventfds[PCI_MSIX_FLAGS_QSIZE + 1]; ··· 98 85 void vfio_pci_device_cleanup(struct vfio_pci_device *device); 99 86 void vfio_pci_device_reset(struct vfio_pci_device *device); 100 87 101 - void vfio_pci_dma_map(struct vfio_pci_device *device, u64 iova, u64 size, 102 - void *vaddr); 103 - void vfio_pci_dma_unmap(struct vfio_pci_device *device, u64 iova, u64 size); 88 + void vfio_pci_dma_map(struct vfio_pci_device *device, 89 + struct vfio_dma_region *region); 90 + void vfio_pci_dma_unmap(struct vfio_pci_device *device, 91 + struct vfio_dma_region *region); 104 92 105 93 void vfio_pci_config_access(struct vfio_pci_device *device, bool write, 106 94 size_t config, size_t size, void *data); ··· 151 137 { 152 138 vfio_pci_irq_disable(device, VFIO_PCI_MSIX_IRQ_INDEX); 153 139 } 140 + 141 + iova_t __to_iova(struct vfio_pci_device *device, void *vaddr); 142 + iova_t to_iova(struct vfio_pci_device *device, void *vaddr); 154 143 155 144 #endif /* SELFTESTS_VFIO_LIB_INCLUDE_VFIO_UTIL_H */
+42 -7
tools/testing/selftests/vfio/lib/vfio_pci_device.c
··· 26 26 VFIO_ASSERT_EQ(__ret, 0, "ioctl(%s, %s, %s) returned %d\n", #_fd, #_op, #_arg, __ret); \ 27 27 } while (0) 28 28 29 + iova_t __to_iova(struct vfio_pci_device *device, void *vaddr) 30 + { 31 + struct vfio_dma_region *region; 32 + 33 + list_for_each_entry(region, &device->dma_regions, link) { 34 + if (vaddr < region->vaddr) 35 + continue; 36 + 37 + if (vaddr >= region->vaddr + region->size) 38 + continue; 39 + 40 + return region->iova + (vaddr - region->vaddr); 41 + } 42 + 43 + return INVALID_IOVA; 44 + } 45 + 46 + iova_t to_iova(struct vfio_pci_device *device, void *vaddr) 47 + { 48 + iova_t iova; 49 + 50 + iova = __to_iova(device, vaddr); 51 + VFIO_ASSERT_NE(iova, INVALID_IOVA, "%p is not mapped into device.\n", vaddr); 52 + 53 + return iova; 54 + } 55 + 29 56 static void vfio_pci_irq_set(struct vfio_pci_device *device, 30 57 u32 index, u32 vector, u32 count, int *fds) 31 58 { ··· 139 112 ioctl_assert(device->fd, VFIO_DEVICE_GET_IRQ_INFO, irq_info); 140 113 } 141 114 142 - void vfio_pci_dma_map(struct vfio_pci_device *device, u64 iova, u64 size, void *vaddr) 115 + void vfio_pci_dma_map(struct vfio_pci_device *device, 116 + struct vfio_dma_region *region) 143 117 { 144 118 struct vfio_iommu_type1_dma_map map = { 145 119 .argsz = sizeof(map), 146 120 .flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE, 147 - .vaddr = (u64)vaddr, 148 - .iova = iova, 149 - .size = size, 121 + .vaddr = (u64)region->vaddr, 122 + .iova = region->iova, 123 + .size = region->size, 150 124 }; 151 125 152 126 ioctl_assert(device->container_fd, VFIO_IOMMU_MAP_DMA, &map); 127 + 128 + list_add(&region->link, &device->dma_regions); 153 129 } 154 130 155 - void vfio_pci_dma_unmap(struct vfio_pci_device *device, u64 iova, u64 size) 131 + void vfio_pci_dma_unmap(struct vfio_pci_device *device, 132 + struct vfio_dma_region *region) 156 133 { 157 134 struct vfio_iommu_type1_dma_unmap unmap = { 158 135 .argsz = sizeof(unmap), 159 - .iova = iova, 160 - .size = size, 136 + .iova = region->iova, 137 + .size = region->size, 161 138 }; 162 139 163 140 ioctl_assert(device->container_fd, VFIO_IOMMU_UNMAP_DMA, &unmap); 141 + 142 + list_del(&region->link); 164 143 } 165 144 166 145 static void vfio_pci_region_get(struct vfio_pci_device *device, int index, ··· 292 259 static void vfio_pci_iommu_setup(struct vfio_pci_device *device, unsigned long iommu_type) 293 260 { 294 261 int ret; 262 + 263 + INIT_LIST_HEAD(&device->dma_regions); 295 264 296 265 ret = ioctl(device->container_fd, VFIO_CHECK_EXTENSION, iommu_type); 297 266 VFIO_ASSERT_GT(ret, 0, "VFIO IOMMU type %lu not supported\n", iommu_type);
+17 -14
tools/testing/selftests/vfio/vfio_dma_mapping_test.c
··· 128 128 { 129 129 const u64 size = variant->size ?: getpagesize(); 130 130 const int flags = variant->mmap_flags; 131 + struct vfio_dma_region region; 131 132 struct iommu_mapping mapping; 132 - void *mem; 133 - u64 iova; 134 133 int rc; 135 134 136 - mem = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); 135 + region.vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); 137 136 138 137 /* Skip the test if there aren't enough HugeTLB pages available. */ 139 - if (flags & MAP_HUGETLB && mem == MAP_FAILED) 138 + if (flags & MAP_HUGETLB && region.vaddr == MAP_FAILED) 140 139 SKIP(return, "mmap() failed: %s (%d)\n", strerror(errno), errno); 141 140 else 142 - ASSERT_NE(mem, MAP_FAILED); 141 + ASSERT_NE(region.vaddr, MAP_FAILED); 143 142 144 - iova = (u64)mem; 143 + region.iova = (u64)region.vaddr; 144 + region.size = size; 145 145 146 - vfio_pci_dma_map(self->device, iova, size, mem); 147 - printf("Mapped HVA %p (size 0x%lx) at IOVA 0x%lx\n", mem, size, iova); 146 + vfio_pci_dma_map(self->device, &region); 147 + printf("Mapped HVA %p (size 0x%lx) at IOVA 0x%lx\n", region.vaddr, size, region.iova); 148 148 149 - rc = iommu_mapping_get(device_bdf, iova, &mapping); 149 + ASSERT_EQ(region.iova, to_iova(self->device, region.vaddr)); 150 + 151 + rc = iommu_mapping_get(device_bdf, region.iova, &mapping); 150 152 if (rc == -EOPNOTSUPP) 151 153 goto unmap; 152 154 153 155 ASSERT_EQ(0, rc); 154 - printf("Found IOMMU mappings for IOVA 0x%lx:\n", iova); 156 + printf("Found IOMMU mappings for IOVA 0x%lx:\n", region.iova); 155 157 printf("PGD: 0x%016lx\n", mapping.pgd); 156 158 printf("P4D: 0x%016lx\n", mapping.p4d); 157 159 printf("PUD: 0x%016lx\n", mapping.pud); ··· 178 176 } 179 177 180 178 unmap: 181 - vfio_pci_dma_unmap(self->device, iova, size); 182 - printf("Unmapped IOVA 0x%lx\n", iova); 183 - ASSERT_NE(0, iommu_mapping_get(device_bdf, iova, &mapping)); 179 + vfio_pci_dma_unmap(self->device, &region); 180 + printf("Unmapped IOVA 0x%lx\n", region.iova); 181 + ASSERT_EQ(INVALID_IOVA, __to_iova(self->device, region.vaddr)); 182 + ASSERT_NE(0, iommu_mapping_get(device_bdf, region.iova, &mapping)); 184 183 185 - ASSERT_TRUE(!munmap(mem, size)); 184 + ASSERT_TRUE(!munmap(region.vaddr, size)); 186 185 } 187 186 188 187 int main(int argc, char *argv[])