On Tue, 18 Jun 2019 16:47:58 +0100 James Courtier-Dutton <james.dut...@gmail.com> wrote:
> On Tue, 18 Jun 2019 at 16:18, Alex Williamson <alex.william...@redhat.com> > wrote: > > > [cc +vfio-users] > > > > You need a version of the hot reset unit test that accepts multiple > > devices since each is in a separate group. The grouping on the Asus > > system you provided is preferred, it's not a problem. Thanks, > > > > > Do you have such a version, or shall I craft one ? I think the attached one works, pass: <group #> <device ssss:bb:dd.f> [<group #> <device ssss:bb:dd.f>]... Thanks, Alex
#include <errno.h> #include <libgen.h> #include <fcntl.h> #include <libgen.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <sys/param.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/vfs.h> #include <linux/ioctl.h> #include <linux/vfio.h> void usage(char *name) { printf("usage: %s <iommu group id> <ssss:bb:dd.f>\n", name); } #define false 0 #define true 1 int main(int argc, char **argv) { int i, j, ret, container, *pfd; char path[PATH_MAX]; struct vfio_group_status group_status = { .argsz = sizeof(group_status) }; struct vfio_pci_hot_reset_info *reset_info; struct vfio_pci_dependent_device *devices; struct vfio_pci_hot_reset *reset; struct reset_dev { int groupid; int seg; int bus; int dev; int func; int fd; int group; } *reset_devs; if (argc < 3) { usage(argv[0]); return -1; } printf("Expect %d group/device pairs\n", (argc - 1)/2); reset_devs = calloc((argc - 1)/2, sizeof(struct reset_dev)); if (!reset_devs) return -1; for (i = 0; i < (argc - 1)/2; i++) { ret = sscanf(argv[i*2 + 1], "%d", &reset_devs[i].groupid); if (ret != 1) { usage(argv[0]); return -1; } ret = sscanf(argv[i*2 + 2], "%04x:%02x:%02x.%d", &reset_devs[i].seg, &reset_devs[i].bus, &reset_devs[i].dev, &reset_devs[i].func); if (ret != 4) { usage(argv[0]); return -1; } printf("Using PCI device %04x:%02x:%02x.%d in group %d " "for hot reset test\n", reset_devs[i].seg, reset_devs[i].bus, reset_devs[i].dev, reset_devs[i].func, reset_devs[i].groupid); } container = open("/dev/vfio/vfio", O_RDWR); if (container < 0) { printf("Failed to open /dev/vfio/vfio, %d (%s)\n", container, strerror(errno)); return container; } for (i = 0; i < (argc - 1)/2; i++) { snprintf(path, sizeof(path), "/dev/vfio/%d", reset_devs[i].groupid); reset_devs[i].group = open(path, O_RDWR); if (reset_devs[i].group < 0) { printf("Failed to open %s, %d (%s)\n", path, reset_devs[i].group, strerror(errno)); return reset_devs[i].group; } ret = ioctl(reset_devs[i].group, VFIO_GROUP_GET_STATUS, &group_status); if (ret) { printf("ioctl(VFIO_GROUP_GET_STATUS) failed\n"); return ret; } if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE)) { printf("Group not viable, are all devices attached to vfio?\n"); return -1; } ret = ioctl(reset_devs[i].group, VFIO_GROUP_SET_CONTAINER, &container); if (ret) { printf("Failed to set group container\n"); return ret; } if (i == 0) { ret = ioctl(container, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU); if (ret) { printf("Failed to set IOMMU\n"); return ret; } } snprintf(path, sizeof(path), "%04x:%02x:%02x.%d", reset_devs[i].seg, reset_devs[i].bus, reset_devs[i].dev, reset_devs[i].func); reset_devs[i].fd = ioctl(reset_devs[i].group, VFIO_GROUP_GET_DEVICE_FD, path); if (reset_devs[i].fd < 0) { printf("Failed to get device %s\n", path); return -1; } } reset_info = malloc(sizeof(*reset_info)); if (!reset_info) { printf("Failed to alloc info struct\n"); return -ENOMEM; } reset_info->argsz = sizeof(*reset_info); ret = ioctl(reset_devs[0].fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, reset_info); if (ret && errno == ENODEV) { printf("Device does not support hot reset\n"); return 0; } if (!ret || errno != ENOSPC) { printf("Expected fail/-ENOSPC, got %d/%d\n", ret, -errno); return -1; } printf("Dependent device count: %d\n", reset_info->count); reset_info = realloc(reset_info, sizeof(*reset_info) + (reset_info->count * sizeof(*devices))); if (!reset_info) { printf("Failed to re-alloc info struct\n"); return -ENOMEM; } reset_info->argsz = sizeof(*reset_info) + (reset_info->count * sizeof(*devices)); ret = ioctl(reset_devs[0].fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, reset_info); if (ret) { printf("Reset Info error\n"); return ret; } devices = &reset_info->devices[0]; for (i = 0; i < reset_info->count; i++) printf("%d: %04x:%02x:%02x.%d group %d\n", i, devices[i].segment, devices[i].bus, devices[i].devfn >> 3, devices[i].devfn & 7, devices[i].group_id); printf("Attempting reset: "); fflush(stdout); reset = malloc(sizeof(*reset) + (sizeof(*pfd) * reset_info->count)); pfd = &reset->group_fds[0]; for (i = 0; i < reset_info->count; i++) { for (j = 0; j < (argc - 1)/2; j++) { if (devices[i].group_id == reset_devs[j].groupid) { *pfd++ = reset_devs[j].group; break; } } if (j == (argc - 1)/2) { printf("Group %d not found\n", devices[i].group_id); return -1; } } reset->argsz = sizeof(*reset) + (sizeof(*pfd) * reset_info->count); reset->count = reset_info->count; reset->flags = 0; ret = ioctl(reset_devs[0].fd, VFIO_DEVICE_PCI_HOT_RESET, reset); printf("%s\n", ret ? "Failed" : "Pass"); return ret; }
_______________________________________________ vfio-users mailing list vfio-users@redhat.com https://www.redhat.com/mailman/listinfo/vfio-users