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