1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <fcntl.h> 3 #include <stdlib.h> 4 5 #include <sys/ioctl.h> 6 #include <sys/mman.h> 7 8 #include <linux/limits.h> 9 #include <linux/pci_regs.h> 10 #include <linux/sizes.h> 11 #include <linux/vfio.h> 12 13 #include <libvfio.h> 14 15 #include "kselftest_harness.h" 16 17 static const char *device_bdf; 18 19 /* 20 * Limit the number of MSIs enabled/disabled by the test regardless of the 21 * number of MSIs the device itself supports, e.g. to avoid hitting IRTE limits. 22 */ 23 #define MAX_TEST_MSI 16U 24 25 FIXTURE(vfio_pci_device_test) { 26 struct iommu *iommu; 27 struct vfio_pci_device *device; 28 }; 29 30 FIXTURE_SETUP(vfio_pci_device_test) 31 { 32 self->iommu = iommu_init(default_iommu_mode); 33 self->device = vfio_pci_device_init(device_bdf, self->iommu); 34 } 35 36 FIXTURE_TEARDOWN(vfio_pci_device_test) 37 { 38 vfio_pci_device_cleanup(self->device); 39 iommu_cleanup(self->iommu); 40 } 41 42 #define read_pci_id_from_sysfs(_file) ({ \ 43 char __sysfs_path[PATH_MAX]; \ 44 char __buf[32]; \ 45 int __fd; \ 46 \ 47 snprintf(__sysfs_path, PATH_MAX, "/sys/bus/pci/devices/%s/%s", device_bdf, _file); \ 48 ASSERT_GT((__fd = open(__sysfs_path, O_RDONLY)), 0); \ 49 ASSERT_GT(read(__fd, __buf, ARRAY_SIZE(__buf)), 0); \ 50 ASSERT_EQ(0, close(__fd)); \ 51 (u16)strtoul(__buf, NULL, 0); \ 52 }) 53 54 TEST_F(vfio_pci_device_test, config_space_read_write) 55 { 56 u16 vendor, device; 57 u16 command; 58 59 /* Check that Vendor and Device match what the kernel reports. */ 60 vendor = read_pci_id_from_sysfs("vendor"); 61 device = read_pci_id_from_sysfs("device"); 62 ASSERT_TRUE(vfio_pci_device_match(self->device, vendor, device)); 63 64 printf("Vendor: %04x, Device: %04x\n", vendor, device); 65 66 command = vfio_pci_config_readw(self->device, PCI_COMMAND); 67 ASSERT_FALSE(command & PCI_COMMAND_MASTER); 68 69 vfio_pci_config_writew(self->device, PCI_COMMAND, command | PCI_COMMAND_MASTER); 70 command = vfio_pci_config_readw(self->device, PCI_COMMAND); 71 ASSERT_TRUE(command & PCI_COMMAND_MASTER); 72 printf("Enabled Bus Mastering (command: %04x)\n", command); 73 74 vfio_pci_config_writew(self->device, PCI_COMMAND, command & ~PCI_COMMAND_MASTER); 75 command = vfio_pci_config_readw(self->device, PCI_COMMAND); 76 ASSERT_FALSE(command & PCI_COMMAND_MASTER); 77 printf("Disabled Bus Mastering (command: %04x)\n", command); 78 } 79 80 TEST_F(vfio_pci_device_test, validate_bars) 81 { 82 struct vfio_pci_bar *bar; 83 int i; 84 85 for (i = 0; i < PCI_STD_NUM_BARS; i++) { 86 bar = &self->device->bars[i]; 87 88 if (!(bar->info.flags & VFIO_REGION_INFO_FLAG_MMAP)) { 89 printf("BAR %d does not support mmap()\n", i); 90 ASSERT_EQ(NULL, bar->vaddr); 91 continue; 92 } 93 94 /* 95 * BARs that support mmap() should be automatically mapped by 96 * vfio_pci_device_init(). 97 */ 98 ASSERT_NE(NULL, bar->vaddr); 99 ASSERT_NE(0, bar->info.size); 100 printf("BAR %d mapped at %p (size 0x%llx)\n", i, bar->vaddr, bar->info.size); 101 } 102 } 103 104 FIXTURE(vfio_pci_irq_test) { 105 struct iommu *iommu; 106 struct vfio_pci_device *device; 107 }; 108 109 FIXTURE_VARIANT(vfio_pci_irq_test) { 110 int irq_index; 111 }; 112 113 FIXTURE_VARIANT_ADD(vfio_pci_irq_test, msi) { 114 .irq_index = VFIO_PCI_MSI_IRQ_INDEX, 115 }; 116 117 FIXTURE_VARIANT_ADD(vfio_pci_irq_test, msix) { 118 .irq_index = VFIO_PCI_MSIX_IRQ_INDEX, 119 }; 120 121 FIXTURE_SETUP(vfio_pci_irq_test) 122 { 123 self->iommu = iommu_init(default_iommu_mode); 124 self->device = vfio_pci_device_init(device_bdf, self->iommu); 125 } 126 127 FIXTURE_TEARDOWN(vfio_pci_irq_test) 128 { 129 vfio_pci_device_cleanup(self->device); 130 iommu_cleanup(self->iommu); 131 } 132 133 TEST_F(vfio_pci_irq_test, enable_trigger_disable) 134 { 135 bool msix = variant->irq_index == VFIO_PCI_MSIX_IRQ_INDEX; 136 int msi_eventfd; 137 u32 count; 138 u64 value; 139 int i; 140 141 if (msix) 142 count = self->device->msix_info.count; 143 else 144 count = self->device->msi_info.count; 145 146 count = min(count, MAX_TEST_MSI); 147 148 if (!count) 149 SKIP(return, "MSI%s: not supported\n", msix ? "-x" : ""); 150 151 vfio_pci_irq_enable(self->device, variant->irq_index, 0, count); 152 printf("MSI%s: enabled %d interrupts\n", msix ? "-x" : "", count); 153 154 for (i = 0; i < count; i++) { 155 msi_eventfd = self->device->msi_eventfds[i]; 156 157 fcntl_set_nonblock(msi_eventfd); 158 ASSERT_EQ(-1, read(msi_eventfd, &value, 8)); 159 ASSERT_EQ(EAGAIN, errno); 160 161 vfio_pci_irq_trigger(self->device, variant->irq_index, i); 162 163 ASSERT_EQ(8, read(msi_eventfd, &value, 8)); 164 ASSERT_EQ(1, value); 165 } 166 167 vfio_pci_irq_disable(self->device, variant->irq_index); 168 } 169 170 TEST_F(vfio_pci_device_test, reset) 171 { 172 if (!(self->device->info.flags & VFIO_DEVICE_FLAGS_RESET)) 173 SKIP(return, "Device does not support reset\n"); 174 175 vfio_pci_device_reset(self->device); 176 } 177 178 int main(int argc, char *argv[]) 179 { 180 device_bdf = vfio_selftests_get_bdf(&argc, argv); 181 return test_harness_run(argc, argv); 182 } 183