vfio_pci_device_test.c 4.5 KB

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