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: Add driver framework

Add a driver framework to VFIO selftests, so that devices can generate
DMA and interrupts in a common way that can be then utilized by tests.
This will enable VFIO selftests to exercise real hardware DMA and
interrupt paths, without needing any device-specific code in the test
itself.

Subsequent commits will introduce drivers for specific devices.

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

authored by

David Matlack and committed by
Alex Williamson
1b197032 50d8fe80

+214
+92
tools/testing/selftests/vfio/lib/include/vfio_util.h
··· 63 63 u64 size; 64 64 }; 65 65 66 + struct vfio_pci_device; 67 + 68 + struct vfio_pci_driver_ops { 69 + const char *name; 70 + 71 + /** 72 + * @probe() - Check if the driver supports the given device. 73 + * 74 + * Return: 0 on success, non-0 on failure. 75 + */ 76 + int (*probe)(struct vfio_pci_device *device); 77 + 78 + /** 79 + * @init() - Initialize the driver for @device. 80 + * 81 + * Must be called after device->driver.region has been initialized. 82 + */ 83 + void (*init)(struct vfio_pci_device *device); 84 + 85 + /** 86 + * remove() - Deinitialize the driver for @device. 87 + */ 88 + void (*remove)(struct vfio_pci_device *device); 89 + 90 + /** 91 + * memcpy_start() - Kick off @count repeated memcpy operations from 92 + * [@src, @src + @size) to [@dst, @dst + @size). 93 + * 94 + * Guarantees: 95 + * - The device will attempt DMA reads on [src, src + size). 96 + * - The device will attempt DMA writes on [dst, dst + size). 97 + * - The device will not generate any interrupts. 98 + * 99 + * memcpy_start() returns immediately, it does not wait for the 100 + * copies to complete. 101 + */ 102 + void (*memcpy_start)(struct vfio_pci_device *device, 103 + iova_t src, iova_t dst, u64 size, u64 count); 104 + 105 + /** 106 + * memcpy_wait() - Wait until the memcpy operations started by 107 + * memcpy_start() have finished. 108 + * 109 + * Guarantees: 110 + * - All in-flight DMAs initiated by memcpy_start() are fully complete 111 + * before memcpy_wait() returns. 112 + * 113 + * Returns non-0 if the driver detects that an error occurred during the 114 + * memcpy, 0 otherwise. 115 + */ 116 + int (*memcpy_wait)(struct vfio_pci_device *device); 117 + 118 + /** 119 + * send_msi() - Make the device send the MSI device->driver.msi. 120 + * 121 + * Guarantees: 122 + * - The device will send the MSI once. 123 + */ 124 + void (*send_msi)(struct vfio_pci_device *device); 125 + }; 126 + 127 + struct vfio_pci_driver { 128 + const struct vfio_pci_driver_ops *ops; 129 + bool initialized; 130 + bool memcpy_in_progress; 131 + 132 + /* Region to be used by the driver (e.g. for in-memory descriptors) */ 133 + struct vfio_dma_region region; 134 + 135 + /* The maximum size that can be passed to memcpy_start(). */ 136 + u64 max_memcpy_size; 137 + 138 + /* The maximum count that can be passed to memcpy_start(). */ 139 + u64 max_memcpy_count; 140 + 141 + /* The MSI vector the device will signal in ops->send_msi(). */ 142 + int msi; 143 + }; 144 + 66 145 struct vfio_pci_device { 67 146 int fd; 68 147 int group_fd; ··· 158 79 159 80 /* eventfds for MSI and MSI-x interrupts */ 160 81 int msi_eventfds[PCI_MSIX_FLAGS_QSIZE + 1]; 82 + 83 + struct vfio_pci_driver driver; 161 84 }; 162 85 163 86 /* ··· 254 173 return (vendor_id == vfio_pci_config_readw(device, PCI_VENDOR_ID)) && 255 174 (device_id == vfio_pci_config_readw(device, PCI_DEVICE_ID)); 256 175 } 176 + 177 + void vfio_pci_driver_probe(struct vfio_pci_device *device); 178 + void vfio_pci_driver_init(struct vfio_pci_device *device); 179 + void vfio_pci_driver_remove(struct vfio_pci_device *device); 180 + int vfio_pci_driver_memcpy(struct vfio_pci_device *device, 181 + iova_t src, iova_t dst, u64 size); 182 + void vfio_pci_driver_memcpy_start(struct vfio_pci_device *device, 183 + iova_t src, iova_t dst, u64 size, 184 + u64 count); 185 + int vfio_pci_driver_memcpy_wait(struct vfio_pci_device *device); 186 + void vfio_pci_driver_send_msi(struct vfio_pci_device *device); 257 187 258 188 #endif /* SELFTESTS_VFIO_LIB_INCLUDE_VFIO_UTIL_H */
+1
tools/testing/selftests/vfio/lib/libvfio.mk
··· 1 1 VFIO_DIR := $(selfdir)/vfio 2 2 3 3 LIBVFIO_C := lib/vfio_pci_device.c 4 + LIBVFIO_C += lib/vfio_pci_driver.c 4 5 5 6 LIBVFIO_O := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBVFIO_C)) 6 7
+5
tools/testing/selftests/vfio/lib/vfio_pci_device.c
··· 344 344 vfio_pci_iommu_setup(device, iommu_type); 345 345 vfio_pci_device_setup(device, bdf); 346 346 347 + vfio_pci_driver_probe(device); 348 + 347 349 return device; 348 350 } 349 351 350 352 void vfio_pci_device_cleanup(struct vfio_pci_device *device) 351 353 { 352 354 int i; 355 + 356 + if (device->driver.initialized) 357 + vfio_pci_driver_remove(device); 353 358 354 359 vfio_pci_bar_unmap_all(device); 355 360
+116
tools/testing/selftests/vfio/lib/vfio_pci_driver.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + #include <stdio.h> 3 + 4 + #include "../../../kselftest.h" 5 + #include <vfio_util.h> 6 + 7 + static struct vfio_pci_driver_ops *driver_ops[] = {}; 8 + 9 + void vfio_pci_driver_probe(struct vfio_pci_device *device) 10 + { 11 + struct vfio_pci_driver_ops *ops; 12 + int i; 13 + 14 + VFIO_ASSERT_NULL(device->driver.ops); 15 + 16 + for (i = 0; i < ARRAY_SIZE(driver_ops); i++) { 17 + ops = driver_ops[i]; 18 + 19 + if (ops->probe(device)) 20 + continue; 21 + 22 + printf("Driver found: %s\n", ops->name); 23 + device->driver.ops = ops; 24 + } 25 + } 26 + 27 + static void vfio_check_driver_op(struct vfio_pci_driver *driver, void *op, 28 + const char *op_name) 29 + { 30 + VFIO_ASSERT_NOT_NULL(driver->ops); 31 + VFIO_ASSERT_NOT_NULL(op, "Driver has no %s()\n", op_name); 32 + VFIO_ASSERT_EQ(driver->initialized, op != driver->ops->init); 33 + VFIO_ASSERT_EQ(driver->memcpy_in_progress, op == driver->ops->memcpy_wait); 34 + } 35 + 36 + #define VFIO_CHECK_DRIVER_OP(_driver, _op) do { \ 37 + struct vfio_pci_driver *__driver = (_driver); \ 38 + vfio_check_driver_op(__driver, __driver->ops->_op, #_op); \ 39 + } while (0) 40 + 41 + void vfio_pci_driver_init(struct vfio_pci_device *device) 42 + { 43 + struct vfio_pci_driver *driver = &device->driver; 44 + 45 + VFIO_ASSERT_NOT_NULL(driver->region.vaddr); 46 + VFIO_CHECK_DRIVER_OP(driver, init); 47 + 48 + driver->ops->init(device); 49 + 50 + driver->initialized = true; 51 + 52 + printf("%s: region: vaddr %p, iova 0x%lx, size 0x%lx\n", 53 + driver->ops->name, 54 + driver->region.vaddr, 55 + driver->region.iova, 56 + driver->region.size); 57 + 58 + printf("%s: max_memcpy_size 0x%lx, max_memcpy_count 0x%lx\n", 59 + driver->ops->name, 60 + driver->max_memcpy_size, 61 + driver->max_memcpy_count); 62 + } 63 + 64 + void vfio_pci_driver_remove(struct vfio_pci_device *device) 65 + { 66 + struct vfio_pci_driver *driver = &device->driver; 67 + 68 + VFIO_CHECK_DRIVER_OP(driver, remove); 69 + 70 + driver->ops->remove(device); 71 + driver->initialized = false; 72 + } 73 + 74 + void vfio_pci_driver_send_msi(struct vfio_pci_device *device) 75 + { 76 + struct vfio_pci_driver *driver = &device->driver; 77 + 78 + VFIO_CHECK_DRIVER_OP(driver, send_msi); 79 + 80 + driver->ops->send_msi(device); 81 + } 82 + 83 + void vfio_pci_driver_memcpy_start(struct vfio_pci_device *device, 84 + iova_t src, iova_t dst, u64 size, 85 + u64 count) 86 + { 87 + struct vfio_pci_driver *driver = &device->driver; 88 + 89 + VFIO_ASSERT_LE(size, driver->max_memcpy_size); 90 + VFIO_ASSERT_LE(count, driver->max_memcpy_count); 91 + VFIO_CHECK_DRIVER_OP(driver, memcpy_start); 92 + 93 + driver->ops->memcpy_start(device, src, dst, size, count); 94 + driver->memcpy_in_progress = true; 95 + } 96 + 97 + int vfio_pci_driver_memcpy_wait(struct vfio_pci_device *device) 98 + { 99 + struct vfio_pci_driver *driver = &device->driver; 100 + int r; 101 + 102 + VFIO_CHECK_DRIVER_OP(driver, memcpy_wait); 103 + 104 + r = driver->ops->memcpy_wait(device); 105 + driver->memcpy_in_progress = false; 106 + 107 + return r; 108 + } 109 + 110 + int vfio_pci_driver_memcpy(struct vfio_pci_device *device, 111 + iova_t src, iova_t dst, u64 size) 112 + { 113 + vfio_pci_driver_memcpy_start(device, src, dst, size, 1); 114 + 115 + return vfio_pci_driver_memcpy_wait(device); 116 + }