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.

at master 182 lines 4.6 kB view raw
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 17static 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 25FIXTURE(vfio_pci_device_test) { 26 struct iommu *iommu; 27 struct vfio_pci_device *device; 28}; 29 30FIXTURE_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 36FIXTURE_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 54TEST_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 80TEST_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 104FIXTURE(vfio_pci_irq_test) { 105 struct iommu *iommu; 106 struct vfio_pci_device *device; 107}; 108 109FIXTURE_VARIANT(vfio_pci_irq_test) { 110 int irq_index; 111}; 112 113FIXTURE_VARIANT_ADD(vfio_pci_irq_test, msi) { 114 .irq_index = VFIO_PCI_MSI_IRQ_INDEX, 115}; 116 117FIXTURE_VARIANT_ADD(vfio_pci_irq_test, msix) { 118 .irq_index = VFIO_PCI_MSIX_IRQ_INDEX, 119}; 120 121FIXTURE_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 127FIXTURE_TEARDOWN(vfio_pci_irq_test) 128{ 129 vfio_pci_device_cleanup(self->device); 130 iommu_cleanup(self->iommu); 131} 132 133TEST_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 170TEST_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 178int main(int argc, char *argv[]) 179{ 180 device_bdf = vfio_selftests_get_bdf(&argc, argv); 181 return test_harness_run(argc, argv); 182}