static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr,
uint32_t val, int len);
static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled);
-static int vfio_populate_device(VFIODevice *vbasedev);
/*
* Disabling BAR mmaping can be slow, but toggling it around INTx can
abort();
}
- trace_vfio_msi_interrupt(vbasedev->name, nr, msg.address, msg.data);
+ trace_vfio_msi_interrupt(vdev->vbasedev.name, nr, msg.address, msg.data);
#endif
if (vdev->interrupt == VFIO_INT_MSIX) {
}
static void vfio_vga_quirk_teardown(VFIOPCIDevice *vdev)
+{
+ VFIOQuirk *quirk;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vdev->vga.region); i++) {
+ QLIST_FOREACH(quirk, &vdev->vga.region[i].quirks, next) {
+ memory_region_del_subregion(&vdev->vga.region[i].mem, &quirk->mem);
+ }
+ }
+}
+
+static void vfio_vga_quirk_free(VFIOPCIDevice *vdev)
{
int i;
for (i = 0; i < ARRAY_SIZE(vdev->vga.region); i++) {
while (!QLIST_EMPTY(&vdev->vga.region[i].quirks)) {
VFIOQuirk *quirk = QLIST_FIRST(&vdev->vga.region[i].quirks);
- memory_region_del_subregion(&vdev->vga.region[i].mem, &quirk->mem);
object_unparent(OBJECT(&quirk->mem));
QLIST_REMOVE(quirk, next);
g_free(quirk);
}
static void vfio_bar_quirk_teardown(VFIOPCIDevice *vdev, int nr)
+{
+ VFIOBAR *bar = &vdev->bars[nr];
+ VFIOQuirk *quirk;
+
+ QLIST_FOREACH(quirk, &bar->quirks, next) {
+ memory_region_del_subregion(&bar->region.mem, &quirk->mem);
+ }
+}
+
+static void vfio_bar_quirk_free(VFIOPCIDevice *vdev, int nr)
{
VFIOBAR *bar = &vdev->bars[nr];
while (!QLIST_EMPTY(&bar->quirks)) {
VFIOQuirk *quirk = QLIST_FIRST(&bar->quirks);
- memory_region_del_subregion(&bar->region.mem, &quirk->mem);
object_unparent(OBJECT(&quirk->mem));
QLIST_REMOVE(quirk, next);
g_free(quirk);
}
}
-static void vfio_unmap_bar(VFIOPCIDevice *vdev, int nr)
+static void vfio_unregister_bar(VFIOPCIDevice *vdev, int nr)
{
VFIOBAR *bar = &vdev->bars[nr];
vfio_bar_quirk_teardown(vdev, nr);
memory_region_del_subregion(&bar->region.mem, &bar->region.mmap_mem);
- munmap(bar->region.mmap, memory_region_size(&bar->region.mmap_mem));
if (vdev->msix && vdev->msix->table_bar == nr) {
memory_region_del_subregion(&bar->region.mem, &vdev->msix->mmap_mem);
+ }
+}
+
+static void vfio_unmap_bar(VFIOPCIDevice *vdev, int nr)
+{
+ VFIOBAR *bar = &vdev->bars[nr];
+
+ if (!bar->region.size) {
+ return;
+ }
+
+ vfio_bar_quirk_free(vdev, nr);
+
+ munmap(bar->region.mmap, memory_region_size(&bar->region.mmap_mem));
+
+ if (vdev->msix && vdev->msix->table_bar == nr) {
munmap(vdev->msix->mmap, memory_region_size(&vdev->msix->mmap_mem));
}
}
}
}
-static void vfio_unmap_bars(VFIOPCIDevice *vdev)
+static void vfio_unregister_bars(VFIOPCIDevice *vdev)
{
int i;
for (i = 0; i < PCI_ROM_SLOT; i++) {
- vfio_unmap_bar(vdev, i);
+ vfio_unregister_bar(vdev, i);
}
if (vdev->has_vga) {
}
}
+static void vfio_unmap_bars(VFIOPCIDevice *vdev)
+{
+ int i;
+
+ for (i = 0; i < PCI_ROM_SLOT; i++) {
+ vfio_unmap_bar(vdev, i);
+ }
+
+ if (vdev->has_vga) {
+ vfio_vga_quirk_free(vdev);
+ }
+}
+
/*
* General setup
*/
.vfio_compute_needs_reset = vfio_pci_compute_needs_reset,
.vfio_hot_reset_multi = vfio_pci_hot_reset_multi,
.vfio_eoi = vfio_eoi,
- .vfio_populate_device = vfio_populate_device,
};
-static int vfio_populate_device(VFIODevice *vbasedev)
+static int vfio_populate_device(VFIOPCIDevice *vdev)
{
- VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev);
+ VFIODevice *vbasedev = &vdev->vbasedev;
struct vfio_region_info reg_info = { .argsz = sizeof(reg_info) };
struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info) };
int i, ret = -1;
{
g_free(vdev->vbasedev.name);
if (vdev->msix) {
+ object_unparent(OBJECT(&vdev->msix->mmap_mem));
g_free(vdev->msix);
vdev->msix = NULL;
}
return ret;
}
+ ret = vfio_populate_device(vdev);
+ if (ret) {
+ return ret;
+ }
+
/* Get a copy of config space */
ret = pread(vdev->vbasedev.fd, vdev->pdev.config,
MIN(pci_config_size(&vdev->pdev), vdev->config_size),
if (ret < (int)MIN(pci_config_size(&vdev->pdev), vdev->config_size)) {
ret = ret < 0 ? -errno : -EFAULT;
error_report("vfio: Failed to read device config space");
- goto out_put;
+ return ret;
}
/* vfio emulates a lot for us, but some bits need extra love */
ret = vfio_early_setup_msix(vdev);
if (ret) {
- goto out_put;
+ return ret;
}
vfio_map_bars(vdev);
out_teardown:
pci_device_set_intx_routing_notifier(&vdev->pdev, NULL);
vfio_teardown_msi(vdev);
+ vfio_unregister_bars(vdev);
+ return ret;
+}
+
+static void vfio_instance_finalize(Object *obj)
+{
+ PCIDevice *pci_dev = PCI_DEVICE(obj);
+ VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pci_dev);
+ VFIOGroup *group = vdev->vbasedev.group;
+
vfio_unmap_bars(vdev);
-out_put:
g_free(vdev->emulated_config_bits);
+ g_free(vdev->rom);
vfio_put_device(vdev);
vfio_put_group(group);
- return ret;
}
static void vfio_exitfn(PCIDevice *pdev)
{
VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
- VFIOGroup *group = vdev->vbasedev.group;
vfio_unregister_err_notifier(vdev);
pci_device_set_intx_routing_notifier(&vdev->pdev, NULL);
timer_free(vdev->intx.mmap_timer);
}
vfio_teardown_msi(vdev);
- vfio_unmap_bars(vdev);
- g_free(vdev->emulated_config_bits);
- g_free(vdev->rom);
- vfio_put_device(vdev);
- vfio_put_group(group);
+ vfio_unregister_bars(vdev);
}
static void vfio_pci_reset(DeviceState *dev)
DEFINE_PROP_BIT("x-vga", VFIOPCIDevice, features,
VFIO_FEATURE_ENABLE_VGA_BIT, false),
DEFINE_PROP_INT32("bootindex", VFIOPCIDevice, bootindex, -1),
+ DEFINE_PROP_BOOL("x-mmap", VFIOPCIDevice, vbasedev.allow_mmap, true),
/*
* TODO - support passed fds... is this necessary?
* DEFINE_PROP_STRING("vfiofd", VFIOPCIDevice, vfiofd_name),
.instance_size = sizeof(VFIOPCIDevice),
.class_init = vfio_pci_dev_class_init,
.instance_init = vfio_instance_init,
+ .instance_finalize = vfio_instance_finalize,
};
static void register_vfio_pci_dev_type(void)