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, VFIO_TYPE1_IOMMU); 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 60 ASSERT_EQ(vendor, vfio_pci_config_readw(self->device, PCI_VENDOR_ID)); 61 ASSERT_EQ(device, vfio_pci_config_readw(self->device, PCI_DEVICE_ID)); 62 63 printf("Vendor: %04x, Device: %04x\n", vendor, device); 64 65 command = vfio_pci_config_readw(self->device, PCI_COMMAND); 66 ASSERT_FALSE(command & PCI_COMMAND_MASTER); 67 68 vfio_pci_config_writew(self->device, PCI_COMMAND, command | PCI_COMMAND_MASTER); 69 command = vfio_pci_config_readw(self->device, PCI_COMMAND); 70 ASSERT_TRUE(command & PCI_COMMAND_MASTER); 71 printf("Enabled Bus Mastering (command: %04x)\n", command); 72 73 vfio_pci_config_writew(self->device, PCI_COMMAND, command & ~PCI_COMMAND_MASTER); 74 command = vfio_pci_config_readw(self->device, PCI_COMMAND); 75 ASSERT_FALSE(command & PCI_COMMAND_MASTER); 76 printf("Disabled Bus Mastering (command: %04x)\n", command); 77 } 78 79 TEST_F(vfio_pci_device_test, validate_bars) 80 { 81 struct vfio_pci_bar *bar; 82 int i; 83 84 for (i = 0; i < PCI_STD_NUM_BARS; i++) { 85 bar = &self->device->bars[i]; 86 87 if (!(bar->info.flags & VFIO_REGION_INFO_FLAG_MMAP)) { 88 printf("BAR %d does not support mmap()\n", i); 89 ASSERT_EQ(NULL, bar->vaddr); 90 continue; 91 } 92 93 /* 94 * BARs that support mmap() should be automatically mapped by 95 * vfio_pci_device_init(). 96 */ 97 ASSERT_NE(NULL, bar->vaddr); 98 ASSERT_NE(0, bar->info.size); 99 printf("BAR %d mapped at %p (size 0x%llx)\n", i, bar->vaddr, bar->info.size); 100 } 101 } 102 103 FIXTURE(vfio_pci_irq_test) { 104 struct vfio_pci_device *device; 105 }; 106 107 FIXTURE_VARIANT(vfio_pci_irq_test) { 108 int irq_index; 109 }; 110 111 FIXTURE_VARIANT_ADD(vfio_pci_irq_test, msi) { 112 .irq_index = VFIO_PCI_MSI_IRQ_INDEX, 113 }; 114 115 FIXTURE_VARIANT_ADD(vfio_pci_irq_test, msix) { 116 .irq_index = VFIO_PCI_MSIX_IRQ_INDEX, 117 }; 118 119 FIXTURE_SETUP(vfio_pci_irq_test) 120 { 121 self->device = vfio_pci_device_init(device_bdf, VFIO_TYPE1_IOMMU); 122 } 123 124 FIXTURE_TEARDOWN(vfio_pci_irq_test) 125 { 126 vfio_pci_device_cleanup(self->device); 127 } 128 129 TEST_F(vfio_pci_irq_test, enable_trigger_disable) 130 { 131 bool msix = variant->irq_index == VFIO_PCI_MSIX_IRQ_INDEX; 132 u32 count; 133 u64 value; 134 int i; 135 136 if (msix) 137 count = self->device->msix_info.count; 138 else 139 count = self->device->msi_info.count; 140 141 count = min(count, MAX_TEST_MSI); 142 143 if (!count) 144 SKIP(return, "MSI%s: not supported\n", msix ? "-x" : ""); 145 146 vfio_pci_irq_enable(self->device, variant->irq_index, 0, count); 147 printf("MSI%s: enabled %d interrupts\n", msix ? "-x" : "", count); 148 149 for (i = 0; i < count; i++) { 150 vfio_pci_irq_trigger(self->device, variant->irq_index, i); 151 ASSERT_EQ(8, read(self->device->msi_eventfds[i], &value, 8)); 152 ASSERT_EQ(1, value); 153 } 154 155 vfio_pci_irq_disable(self->device, variant->irq_index); 156 } 157 158 int main(int argc, char *argv[]) 159 { 160 device_bdf = vfio_selftests_get_bdf(&argc, argv); 161 return test_harness_run(argc, argv); 162 } 163