File Index
Files and directories
Sign in
FILE

vfio_pci_device_test.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/vfio/vfio_pci_device_test.c C
  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}
~/ Read-only file preview.