Hi Eric, On Fri, 2014-10-31 at 14:05 +0000, Eric Auger wrote: > Introduce the VFIODevice struct that is going to be shared by > VFIOPCIDevice and VFIOPlatformDevice. > > Additional fields will be added there later on for review > convenience. > > the group's device_list becomes a list of VFIODevice > > This obliges to rework the reset_handler which becomes generic and > calls VFIODevice ops that are specialized in each parent object. > Also functions that iterate on this list must take care that the > devices can be something else than VFIOPCIDevice. The type is used > to discriminate them. > > we profit from this step to change the prototype of > vfio_unmask_intx, vfio_mask_intx, vfio_disable_irqindex which now > apply to VFIODevice. They are renamed as *_irqindex. > The index is passed as parameter to anticipate their usage for > platform IRQs
I cringe when reviewers tell me this, so I apologize in advance, but there are logically at least 4 separate things happening in this patch: 1) VFIODevice 2) VFIODeviceOps 3) irqindex conversions 4) strcmp(name) vs comparing ssss:bb:dd.f I don't really see any dependencies between them, and I think they'd also be easier to review as 4 separate patches. More below... > > Signed-off-by: Eric Auger <eric.au...@linaro.org> > > --- > > v4->v5: > - fix style issues > - in vfio_initfn, rework allocation of vdev->vbasedev.name and > replace snprintf by g_strdup_printf > --- > hw/vfio/pci.c | 241 > +++++++++++++++++++++++++++++++++++----------------------- > 1 file changed, 147 insertions(+), 94 deletions(-) > > diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c > index 93181bf..0531744 100644 > --- a/hw/vfio/pci.c > +++ b/hw/vfio/pci.c > @@ -48,6 +48,11 @@ > #define VFIO_ALLOW_KVM_MSI 1 > #define VFIO_ALLOW_KVM_MSIX 1 > > +enum { > + VFIO_DEVICE_TYPE_PCI = 0, > + VFIO_DEVICE_TYPE_PLATFORM = 1, VFIO_DEVICE_TYPE_PLATFORM gets dropped in patch 8 and re-added in patch 9. Let's remove it here and let it's first appearance be in patch 9. > +}; > + > struct VFIOPCIDevice; > > typedef struct VFIOQuirk { > @@ -185,9 +190,27 @@ typedef struct VFIOMSIXInfo { > void *mmap; > } VFIOMSIXInfo; > > +typedef struct VFIODeviceOps VFIODeviceOps; > + > +typedef struct VFIODevice { > + QLIST_ENTRY(VFIODevice) next; > + struct VFIOGroup *group; > + char *name; > + int fd; > + int type; > + bool reset_works; > + bool needs_reset; > + VFIODeviceOps *ops; > +} VFIODevice; > + > +struct VFIODeviceOps { > + bool (*vfio_compute_needs_reset)(VFIODevice *vdev); > + int (*vfio_hot_reset_multi)(VFIODevice *vdev); > +}; > + > typedef struct VFIOPCIDevice { > PCIDevice pdev; > - int fd; > + VFIODevice vbasedev; > VFIOINTx intx; > unsigned int config_size; > uint8_t *emulated_config_bits; /* QEMU emulated bits, little-endian */ > @@ -203,20 +226,16 @@ typedef struct VFIOPCIDevice { > VFIOBAR bars[PCI_NUM_REGIONS - 1]; /* No ROM */ > VFIOVGA vga; /* 0xa0000, 0x3b0, 0x3c0 */ > PCIHostDeviceAddress host; > - QLIST_ENTRY(VFIOPCIDevice) next; > - struct VFIOGroup *group; > EventNotifier err_notifier; > uint32_t features; > #define VFIO_FEATURE_ENABLE_VGA_BIT 0 > #define VFIO_FEATURE_ENABLE_VGA (1 << VFIO_FEATURE_ENABLE_VGA_BIT) > int32_t bootindex; > uint8_t pm_cap; > - bool reset_works; > bool has_vga; > bool pci_aer; > bool has_flr; > bool has_pm_reset; > - bool needs_reset; > bool rom_read_failed; > } VFIOPCIDevice; > > @@ -224,7 +243,7 @@ typedef struct VFIOGroup { > int fd; > int groupid; > VFIOContainer *container; > - QLIST_HEAD(, VFIOPCIDevice) device_list; > + QLIST_HEAD(, VFIODevice) device_list; > QLIST_ENTRY(VFIOGroup) next; > QLIST_ENTRY(VFIOGroup) container_next; > } VFIOGroup; > @@ -277,7 +296,7 @@ static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, > bool enabled); > /* > * Common VFIO interrupt disable > */ > -static void vfio_disable_irqindex(VFIOPCIDevice *vdev, int index) > +static void vfio_disable_irqindex(VFIODevice *vbasedev, int index) > { > struct vfio_irq_set irq_set = { > .argsz = sizeof(irq_set), > @@ -287,37 +306,37 @@ static void vfio_disable_irqindex(VFIOPCIDevice *vdev, > int index) > .count = 0, > }; > > - ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); > + ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); > } > > /* > * INTx > */ > -static void vfio_unmask_intx(VFIOPCIDevice *vdev) > +static void vfio_unmask_irqindex(VFIODevice *vbasedev, int index) > { > struct vfio_irq_set irq_set = { > .argsz = sizeof(irq_set), > .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK, > - .index = VFIO_PCI_INTX_IRQ_INDEX, > + .index = index, > .start = 0, > .count = 1, > }; We're turning these into a generic function, but the function assumes a single start/count. Do we want to reflect that in the name or args? For instance, maybe it should be vfio_unmask_simple_irqindex() to reflect the common use case of a single interrupt per index and we can create another function later for a more complete specification should we ever need it. Thanks, Alex > > - ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); > + ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); > } > > #ifdef CONFIG_KVM /* Unused outside of CONFIG_KVM code */ > -static void vfio_mask_intx(VFIOPCIDevice *vdev) > +static void vfio_mask_irqindex(VFIODevice *vbasedev, int index) > { > struct vfio_irq_set irq_set = { > .argsz = sizeof(irq_set), > .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK, > - .index = VFIO_PCI_INTX_IRQ_INDEX, > + .index = index, > .start = 0, > .count = 1, > }; > > - ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); > + ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); > } > #endif > > @@ -381,7 +400,7 @@ static void vfio_eoi(VFIOPCIDevice *vdev) > > vdev->intx.pending = false; > pci_irq_deassert(&vdev->pdev); > - vfio_unmask_intx(vdev); > + vfio_unmask_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); > } > > static void vfio_enable_intx_kvm(VFIOPCIDevice *vdev) > @@ -404,7 +423,7 @@ static void vfio_enable_intx_kvm(VFIOPCIDevice *vdev) > > /* Get to a known interrupt state */ > qemu_set_fd_handler(irqfd.fd, NULL, NULL, vdev); > - vfio_mask_intx(vdev); > + vfio_mask_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); > vdev->intx.pending = false; > pci_irq_deassert(&vdev->pdev); > > @@ -434,7 +453,7 @@ static void vfio_enable_intx_kvm(VFIOPCIDevice *vdev) > > *pfd = irqfd.resamplefd; > > - ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); > + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); > g_free(irq_set); > if (ret) { > error_report("vfio: Error: Failed to setup INTx unmask fd: %m"); > @@ -442,7 +461,7 @@ static void vfio_enable_intx_kvm(VFIOPCIDevice *vdev) > } > > /* Let'em rip */ > - vfio_unmask_intx(vdev); > + vfio_unmask_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); > > vdev->intx.kvm_accel = true; > > @@ -458,7 +477,7 @@ fail_irqfd: > event_notifier_cleanup(&vdev->intx.unmask); > fail: > qemu_set_fd_handler(irqfd.fd, vfio_intx_interrupt, NULL, vdev); > - vfio_unmask_intx(vdev); > + vfio_unmask_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); > #endif > } > > @@ -479,7 +498,7 @@ static void vfio_disable_intx_kvm(VFIOPCIDevice *vdev) > * Get to a known state, hardware masked, QEMU ready to accept new > * interrupts, QEMU IRQ de-asserted. > */ > - vfio_mask_intx(vdev); > + vfio_mask_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); > vdev->intx.pending = false; > pci_irq_deassert(&vdev->pdev); > > @@ -497,7 +516,7 @@ static void vfio_disable_intx_kvm(VFIOPCIDevice *vdev) > vdev->intx.kvm_accel = false; > > /* If we've missed an event, let it re-fire through QEMU */ > - vfio_unmask_intx(vdev); > + vfio_unmask_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); > > trace_vfio_disable_intx_kvm(vdev->host.domain, vdev->host.bus, > vdev->host.slot, vdev->host.function); > @@ -583,7 +602,7 @@ static int vfio_enable_intx(VFIOPCIDevice *vdev) > *pfd = event_notifier_get_fd(&vdev->intx.interrupt); > qemu_set_fd_handler(*pfd, vfio_intx_interrupt, NULL, vdev); > > - ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); > + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); > g_free(irq_set); > if (ret) { > error_report("vfio: Error: Failed to setup INTx fd: %m"); > @@ -608,7 +627,7 @@ static void vfio_disable_intx(VFIOPCIDevice *vdev) > > timer_del(vdev->intx.mmap_timer); > vfio_disable_intx_kvm(vdev); > - vfio_disable_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX); > + vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); > vdev->intx.pending = false; > pci_irq_deassert(&vdev->pdev); > vfio_mmap_set_enabled(vdev, true); > @@ -698,7 +717,7 @@ static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool > msix) > fds[i] = fd; > } > > - ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); > + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); > > g_free(irq_set); > > @@ -795,7 +814,7 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, > unsigned int nr, > * increase them as needed. > */ > if (vdev->nr_vectors < nr + 1) { > - vfio_disable_irqindex(vdev, VFIO_PCI_MSIX_IRQ_INDEX); > + vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX); > vdev->nr_vectors = nr + 1; > ret = vfio_enable_vectors(vdev, true); > if (ret) { > @@ -823,7 +842,7 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, > unsigned int nr, > *pfd = event_notifier_get_fd(&vector->interrupt); > } > > - ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); > + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); > g_free(irq_set); > if (ret) { > error_report("vfio: failed to modify vector, %d", ret); > @@ -874,7 +893,7 @@ static void vfio_msix_vector_release(PCIDevice *pdev, > unsigned int nr) > > *pfd = event_notifier_get_fd(&vector->interrupt); > > - ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); > + ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); > > g_free(irq_set); > } > @@ -1033,7 +1052,7 @@ static void vfio_disable_msix(VFIOPCIDevice *vdev) > } > > if (vdev->nr_vectors) { > - vfio_disable_irqindex(vdev, VFIO_PCI_MSIX_IRQ_INDEX); > + vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX); > } > > vfio_disable_msi_common(vdev); > @@ -1044,7 +1063,7 @@ static void vfio_disable_msix(VFIOPCIDevice *vdev) > > static void vfio_disable_msi(VFIOPCIDevice *vdev) > { > - vfio_disable_irqindex(vdev, VFIO_PCI_MSI_IRQ_INDEX); > + vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSI_IRQ_INDEX); > vfio_disable_msi_common(vdev); > > trace_vfio_disable_msi(vdev->host.domain, vdev->host.bus, > @@ -1188,7 +1207,7 @@ static void vfio_pci_load_rom(VFIOPCIDevice *vdev) > off_t off = 0; > size_t bytes; > > - if (ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, ®_info)) { > + if (ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_REGION_INFO, ®_info)) { > error_report("vfio: Error getting ROM info: %m"); > return; > } > @@ -1218,7 +1237,8 @@ static void vfio_pci_load_rom(VFIOPCIDevice *vdev) > memset(vdev->rom, 0xff, size); > > while (size) { > - bytes = pread(vdev->fd, vdev->rom + off, size, vdev->rom_offset + > off); > + bytes = pread(vdev->vbasedev.fd, vdev->rom + off, > + size, vdev->rom_offset + off); > if (bytes == 0) { > break; > } else if (bytes > 0) { > @@ -1312,6 +1332,7 @@ static void vfio_pci_size_rom(VFIOPCIDevice *vdev) > off_t offset = vdev->config_offset + PCI_ROM_ADDRESS; > DeviceState *dev = DEVICE(vdev); > char name[32]; > + int fd = vdev->vbasedev.fd; > > if (vdev->pdev.romfile || !vdev->pdev.rom_bar) { > /* Since pci handles romfile, just print a message and return */ > @@ -1330,10 +1351,10 @@ static void vfio_pci_size_rom(VFIOPCIDevice *vdev) > * Use the same size ROM BAR as the physical device. The contents > * will get filled in later when the guest tries to read it. > */ > - if (pread(vdev->fd, &orig, 4, offset) != 4 || > - pwrite(vdev->fd, &size, 4, offset) != 4 || > - pread(vdev->fd, &size, 4, offset) != 4 || > - pwrite(vdev->fd, &orig, 4, offset) != 4) { > + if (pread(fd, &orig, 4, offset) != 4 || > + pwrite(fd, &size, 4, offset) != 4 || > + pread(fd, &size, 4, offset) != 4 || > + pwrite(fd, &orig, 4, offset) != 4) { > error_report("%s(%04x:%02x:%02x.%x) failed: %m", > __func__, vdev->host.domain, vdev->host.bus, > vdev->host.slot, vdev->host.function); > @@ -2345,7 +2366,8 @@ static uint32_t vfio_pci_read_config(PCIDevice *pdev, > uint32_t addr, int len) > if (~emu_bits & (0xffffffffU >> (32 - len * 8))) { > ssize_t ret; > > - ret = pread(vdev->fd, &phys_val, len, vdev->config_offset + addr); > + ret = pread(vdev->vbasedev.fd, &phys_val, len, > + vdev->config_offset + addr); > if (ret != len) { > error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x) failed: %m", > __func__, vdev->host.domain, vdev->host.bus, > @@ -2375,7 +2397,8 @@ static void vfio_pci_write_config(PCIDevice *pdev, > uint32_t addr, > addr, val, len); > > /* Write everything to VFIO, let it filter out what we can't write */ > - if (pwrite(vdev->fd, &val_le, len, vdev->config_offset + addr) != len) { > + if (pwrite(vdev->vbasedev.fd, &val_le, len, vdev->config_offset + addr) > + != len) { > error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x, 0x%x) failed: %m", > __func__, vdev->host.domain, vdev->host.bus, > vdev->host.slot, vdev->host.function, addr, val, len); > @@ -2743,7 +2766,7 @@ static int vfio_setup_msi(VFIOPCIDevice *vdev, int pos) > bool msi_64bit, msi_maskbit; > int ret, entries; > > - if (pread(vdev->fd, &ctrl, sizeof(ctrl), > + if (pread(vdev->vbasedev.fd, &ctrl, sizeof(ctrl), > vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) { > return -errno; > } > @@ -2782,23 +2805,24 @@ static int vfio_early_setup_msix(VFIOPCIDevice *vdev) > uint8_t pos; > uint16_t ctrl; > uint32_t table, pba; > + int fd = vdev->vbasedev.fd; > > pos = pci_find_capability(&vdev->pdev, PCI_CAP_ID_MSIX); > if (!pos) { > return 0; > } > > - if (pread(vdev->fd, &ctrl, sizeof(ctrl), > + if (pread(fd, &ctrl, sizeof(ctrl), > vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) { > return -errno; > } > > - if (pread(vdev->fd, &table, sizeof(table), > + if (pread(fd, &table, sizeof(table), > vdev->config_offset + pos + PCI_MSIX_TABLE) != sizeof(table)) { > return -errno; > } > > - if (pread(vdev->fd, &pba, sizeof(pba), > + if (pread(fd, &pba, sizeof(pba), > vdev->config_offset + pos + PCI_MSIX_PBA) != sizeof(pba)) { > return -errno; > } > @@ -2950,7 +2974,7 @@ static void vfio_map_bar(VFIOPCIDevice *vdev, int nr) > vdev->host.function, nr); > > /* Determine what type of BAR this is for registration */ > - ret = pread(vdev->fd, &pci_bar, sizeof(pci_bar), > + ret = pread(vdev->vbasedev.fd, &pci_bar, sizeof(pci_bar), > vdev->config_offset + PCI_BASE_ADDRESS_0 + (4 * nr)); > if (ret != sizeof(pci_bar)) { > error_report("vfio: Failed to read BAR %d (%m)", nr); > @@ -3365,12 +3389,12 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, > bool single) > single ? "one" : "multi"); > > vfio_pci_pre_reset(vdev); > - vdev->needs_reset = false; > + vdev->vbasedev.needs_reset = false; > > info = g_malloc0(sizeof(*info)); > info->argsz = sizeof(*info); > > - ret = ioctl(vdev->fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, info); > + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, info); > if (ret && errno != ENOSPC) { > ret = -errno; > if (!vdev->has_pm_reset) { > @@ -3386,7 +3410,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool > single) > info->argsz = sizeof(*info) + (count * sizeof(*devices)); > devices = &info->devices[0]; > > - ret = ioctl(vdev->fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, info); > + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, info); > if (ret) { > ret = -errno; > error_report("vfio: hot reset info failed: %m"); > @@ -3402,6 +3426,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool > single) > for (i = 0; i < info->count; i++) { > PCIHostDeviceAddress host; > VFIOPCIDevice *tmp; > + VFIODevice *vbasedev_iter; > > host.domain = devices[i].segment; > host.bus = devices[i].bus; > @@ -3433,7 +3458,11 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, > bool single) > } > > /* Prep dependent devices for reset and clear our marker. */ > - QLIST_FOREACH(tmp, &group->device_list, next) { > + QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { > + if (vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI) { > + continue; > + } > + tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev); > if (vfio_pci_host_match(&host, &tmp->host)) { > if (single) { > error_report("vfio: found another in-use device " > @@ -3443,7 +3472,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool > single) > goto out_single; > } > vfio_pci_pre_reset(tmp); > - tmp->needs_reset = false; > + tmp->vbasedev.needs_reset = false; > multi = true; > break; > } > @@ -3482,7 +3511,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool > single) > } > > /* Bus reset! */ > - ret = ioctl(vdev->fd, VFIO_DEVICE_PCI_HOT_RESET, reset); > + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_PCI_HOT_RESET, reset); > g_free(reset); > > trace_vfio_pci_hot_reset_result(vdev->host.domain, > @@ -3496,6 +3525,7 @@ out: > for (i = 0; i < info->count; i++) { > PCIHostDeviceAddress host; > VFIOPCIDevice *tmp; > + VFIODevice *vbasedev_iter; > > host.domain = devices[i].segment; > host.bus = devices[i].bus; > @@ -3516,7 +3546,11 @@ out: > break; > } > > - QLIST_FOREACH(tmp, &group->device_list, next) { > + QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { > + if (vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI) { > + continue; > + } > + tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev); > if (vfio_pci_host_match(&host, &tmp->host)) { > vfio_pci_post_reset(tmp); > break; > @@ -3550,28 +3584,41 @@ static int vfio_pci_hot_reset_one(VFIOPCIDevice *vdev) > return vfio_pci_hot_reset(vdev, true); > } > > -static int vfio_pci_hot_reset_multi(VFIOPCIDevice *vdev) > +static int vfio_pci_hot_reset_multi(VFIODevice *vbasedev) > { > + VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev); > return vfio_pci_hot_reset(vdev, false); > } > > -static void vfio_pci_reset_handler(void *opaque) > +static bool vfio_pci_compute_needs_reset(VFIODevice *vbasedev) > +{ > + VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev); > + if (!vbasedev->reset_works || (!vdev->has_flr && vdev->has_pm_reset)) { > + vbasedev->needs_reset = true; > + } > + return vbasedev->needs_reset; > +} > + > +static VFIODeviceOps vfio_pci_ops = { > + .vfio_compute_needs_reset = vfio_pci_compute_needs_reset, > + .vfio_hot_reset_multi = vfio_pci_hot_reset_multi, > +}; > + > +static void vfio_reset_handler(void *opaque) > { > VFIOGroup *group; > - VFIOPCIDevice *vdev; > + VFIODevice *vbasedev; > > QLIST_FOREACH(group, &group_list, next) { > - QLIST_FOREACH(vdev, &group->device_list, next) { > - if (!vdev->reset_works || (!vdev->has_flr && > vdev->has_pm_reset)) { > - vdev->needs_reset = true; > - } > + QLIST_FOREACH(vbasedev, &group->device_list, next) { > + vbasedev->ops->vfio_compute_needs_reset(vbasedev); > } > } > > QLIST_FOREACH(group, &group_list, next) { > - QLIST_FOREACH(vdev, &group->device_list, next) { > - if (vdev->needs_reset) { > - vfio_pci_hot_reset_multi(vdev); > + QLIST_FOREACH(vbasedev, &group->device_list, next) { > + if (vbasedev->needs_reset) { > + vbasedev->ops->vfio_hot_reset_multi(vbasedev); > } > } > } > @@ -3860,7 +3907,7 @@ static VFIOGroup *vfio_get_group(int groupid, > AddressSpace *as) > } > > if (QLIST_EMPTY(&group_list)) { > - qemu_register_reset(vfio_pci_reset_handler, NULL); > + qemu_register_reset(vfio_reset_handler, NULL); > } > > QLIST_INSERT_HEAD(&group_list, group, next); > @@ -3892,7 +3939,7 @@ static void vfio_put_group(VFIOGroup *group) > g_free(group); > > if (QLIST_EMPTY(&group_list)) { > - qemu_unregister_reset(vfio_pci_reset_handler, NULL); > + qemu_unregister_reset(vfio_reset_handler, NULL); > } > } > > @@ -3913,12 +3960,12 @@ static int vfio_get_device(VFIOGroup *group, const > char *name, > return ret; > } > > - vdev->fd = ret; > - vdev->group = group; > - QLIST_INSERT_HEAD(&group->device_list, vdev, next); > + vdev->vbasedev.fd = ret; > + vdev->vbasedev.group = group; > + QLIST_INSERT_HEAD(&group->device_list, &vdev->vbasedev, next); > > /* Sanity check device */ > - ret = ioctl(vdev->fd, VFIO_DEVICE_GET_INFO, &dev_info); > + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_INFO, &dev_info); > if (ret) { > error_report("vfio: error getting device info: %m"); > goto error; > @@ -3932,7 +3979,7 @@ static int vfio_get_device(VFIOGroup *group, const char > *name, > goto error; > } > > - vdev->reset_works = !!(dev_info.flags & VFIO_DEVICE_FLAGS_RESET); > + vdev->vbasedev.reset_works = !!(dev_info.flags & > VFIO_DEVICE_FLAGS_RESET); > > if (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) { > error_report("vfio: unexpected number of io regions %u", > @@ -3948,7 +3995,7 @@ static int vfio_get_device(VFIOGroup *group, const char > *name, > for (i = VFIO_PCI_BAR0_REGION_INDEX; i < VFIO_PCI_ROM_REGION_INDEX; i++) > { > reg_info.index = i; > > - ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, ®_info); > + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_REGION_INFO, > ®_info); > if (ret) { > error_report("vfio: Error getting region %d info: %m", i); > goto error; > @@ -3962,14 +4009,14 @@ static int vfio_get_device(VFIOGroup *group, const > char *name, > vdev->bars[i].flags = reg_info.flags; > vdev->bars[i].size = reg_info.size; > vdev->bars[i].fd_offset = reg_info.offset; > - vdev->bars[i].fd = vdev->fd; > + vdev->bars[i].fd = vdev->vbasedev.fd; > vdev->bars[i].nr = i; > QLIST_INIT(&vdev->bars[i].quirks); > } > > reg_info.index = VFIO_PCI_CONFIG_REGION_INDEX; > > - ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, ®_info); > + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_REGION_INFO, ®_info); > if (ret) { > error_report("vfio: Error getting config info: %m"); > goto error; > @@ -3992,7 +4039,7 @@ static int vfio_get_device(VFIOGroup *group, const char > *name, > .index = VFIO_PCI_VGA_REGION_INDEX, > }; > > - ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, &vga_info); > + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_REGION_INFO, > &vga_info); > if (ret) { > error_report( > "vfio: Device does not support requested feature x-vga"); > @@ -4009,7 +4056,7 @@ static int vfio_get_device(VFIOGroup *group, const char > *name, > } > > vdev->vga.fd_offset = vga_info.offset; > - vdev->vga.fd = vdev->fd; > + vdev->vga.fd = vdev->vbasedev.fd; > > vdev->vga.region[QEMU_PCI_VGA_MEM].offset = QEMU_PCI_VGA_MEM_BASE; > vdev->vga.region[QEMU_PCI_VGA_MEM].nr = QEMU_PCI_VGA_MEM; > @@ -4027,7 +4074,7 @@ static int vfio_get_device(VFIOGroup *group, const char > *name, > } > irq_info.index = VFIO_PCI_ERR_IRQ_INDEX; > > - ret = ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info); > + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info); > if (ret) { > /* This can fail for an old kernel or legacy PCI dev */ > trace_vfio_get_device_get_irq_info_failure(); > @@ -4043,19 +4090,20 @@ static int vfio_get_device(VFIOGroup *group, const > char *name, > > error: > if (ret) { > - QLIST_REMOVE(vdev, next); > - vdev->group = NULL; > - close(vdev->fd); > + QLIST_REMOVE(&vdev->vbasedev, next); > + vdev->vbasedev.group = NULL; > + close(vdev->vbasedev.fd); > } > return ret; > } > > static void vfio_put_device(VFIOPCIDevice *vdev) > { > - QLIST_REMOVE(vdev, next); > - vdev->group = NULL; > - trace_vfio_put_device(vdev->fd); > - close(vdev->fd); > + QLIST_REMOVE(&vdev->vbasedev, next); > + vdev->vbasedev.group = NULL; > + trace_vfio_put_device(vdev->vbasedev.fd); > + close(vdev->vbasedev.fd); > + g_free(vdev->vbasedev.name); > if (vdev->msix) { > g_free(vdev->msix); > vdev->msix = NULL; > @@ -4124,7 +4172,7 @@ static void vfio_register_err_notifier(VFIOPCIDevice > *vdev) > *pfd = event_notifier_get_fd(&vdev->err_notifier); > qemu_set_fd_handler(*pfd, vfio_err_notifier_handler, NULL, vdev); > > - ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); > + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); > if (ret) { > error_report("vfio: Failed to set up error notification"); > qemu_set_fd_handler(*pfd, NULL, NULL, vdev); > @@ -4157,7 +4205,7 @@ static void vfio_unregister_err_notifier(VFIOPCIDevice > *vdev) > pfd = (int32_t *)&irq_set->data; > *pfd = -1; > > - ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); > + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); > if (ret) { > error_report("vfio: Failed to de-assign error fd: %m"); > } > @@ -4169,7 +4217,8 @@ static void vfio_unregister_err_notifier(VFIOPCIDevice > *vdev) > > static int vfio_initfn(PCIDevice *pdev) > { > - VFIOPCIDevice *pvdev, *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); > + VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); > + VFIODevice *vbasedev_iter; > VFIOGroup *group; > char path[PATH_MAX], iommu_group_path[PATH_MAX], *group_name; > ssize_t len; > @@ -4187,6 +4236,13 @@ static int vfio_initfn(PCIDevice *pdev) > return -errno; > } > > + vdev->vbasedev.ops = &vfio_pci_ops; > + > + vdev->vbasedev.type = VFIO_DEVICE_TYPE_PCI; > + g_strdup_printf(vdev->vbasedev.name, "%04x:%02x:%02x.%01x", > + vdev->host.domain, vdev->host.bus, vdev->host.slot, > + vdev->host.function); > + > strncat(path, "iommu_group", sizeof(path) - strlen(path) - 1); > > len = readlink(path, iommu_group_path, sizeof(path)); > @@ -4216,12 +4272,8 @@ static int vfio_initfn(PCIDevice *pdev) > vdev->host.domain, vdev->host.bus, vdev->host.slot, > vdev->host.function); > > - QLIST_FOREACH(pvdev, &group->device_list, next) { > - if (pvdev->host.domain == vdev->host.domain && > - pvdev->host.bus == vdev->host.bus && > - pvdev->host.slot == vdev->host.slot && > - pvdev->host.function == vdev->host.function) { > - > + QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { > + if (strcmp(vbasedev_iter->name, vdev->vbasedev.name) == 0) { > error_report("vfio: error: device %s is already attached", path); > vfio_put_group(group); > return -EBUSY; > @@ -4236,7 +4288,7 @@ static int vfio_initfn(PCIDevice *pdev) > } > > /* Get a copy of config space */ > - ret = pread(vdev->fd, vdev->pdev.config, > + ret = pread(vdev->vbasedev.fd, vdev->pdev.config, > MIN(pci_config_size(&vdev->pdev), vdev->config_size), > vdev->config_offset); > if (ret < (int)MIN(pci_config_size(&vdev->pdev), vdev->config_size)) { > @@ -4323,7 +4375,7 @@ out_put: > static void vfio_exitfn(PCIDevice *pdev) > { > VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); > - VFIOGroup *group = vdev->group; > + VFIOGroup *group = vdev->vbasedev.group; > > vfio_unregister_err_notifier(vdev); > pci_device_set_intx_routing_notifier(&vdev->pdev, NULL); > @@ -4349,8 +4401,9 @@ static void vfio_pci_reset(DeviceState *dev) > > vfio_pci_pre_reset(vdev); > > - if (vdev->reset_works && (vdev->has_flr || !vdev->has_pm_reset) && > - !ioctl(vdev->fd, VFIO_DEVICE_RESET)) { > + if (vdev->vbasedev.reset_works && > + (vdev->has_flr || !vdev->has_pm_reset) && > + !ioctl(vdev->vbasedev.fd, VFIO_DEVICE_RESET)) { > trace_vfio_pci_reset_flr(vdev->host.domain, vdev->host.bus, > vdev->host.slot, vdev->host.function); > goto post_reset; > @@ -4362,8 +4415,8 @@ static void vfio_pci_reset(DeviceState *dev) > } > > /* If nothing else works and the device supports PM reset, use it */ > - if (vdev->reset_works && vdev->has_pm_reset && > - !ioctl(vdev->fd, VFIO_DEVICE_RESET)) { > + if (vdev->vbasedev.reset_works && vdev->has_pm_reset && > + !ioctl(vdev->vbasedev.fd, VFIO_DEVICE_RESET)) { > trace_vfio_pci_reset_pm(vdev->host.domain, vdev->host.bus, > vdev->host.slot, vdev->host.function); > goto post_reset;