diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2018-03-16 09:51:47 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2018-03-16 09:51:47 +0000 |
commit | a57946ff2acb9c0d95c9f127914540586b0b8c21 (patch) | |
tree | bc790f23ea3802e0a5241c4b6a0d4f6b441cec60 /hw | |
parent | 58888f8cdd198affa454f9bf664a076f5f63a6a6 (diff) | |
parent | fcad0d2121976df4b422b4007a5eb7fcaac01134 (diff) |
Merge remote-tracking branch 'remotes/awilliam/tags/vfio-update-20180313.0' into staging
VFIO updates 2018-03-13
- Display support for vGPUs (Gerd Hoffmann)
- Enable new kernel support for mmaps overlapping MSI-X vector table,
disable MSI-X emulation on POWER (Alexey Kardashevskiy)
# gpg: Signature made Tue 13 Mar 2018 19:48:49 GMT
# gpg: using RSA key 239B9B6E3BB08B22
# gpg: Good signature from "Alex Williamson <alex.williamson@redhat.com>"
# gpg: aka "Alex Williamson <alex@shazbot.org>"
# gpg: aka "Alex Williamson <alwillia@redhat.com>"
# gpg: aka "Alex Williamson <alex.l.williamson@gmail.com>"
# Primary key fingerprint: 42F6 C04E 540B D1A9 9E7B 8A90 239B 9B6E 3BB0 8B22
* remotes/awilliam/tags/vfio-update-20180313.0:
ppc/spapr, vfio: Turn off MSIX emulation for VFIO devices
vfio-pci: Allow mmap of MSIX BAR
vfio/pci: Relax DMA map errors for MMIO regions
vfio/display: adding dmabuf support
vfio/display: adding region support
vfio/display: core & wireup
vfio/common: cleanup in vfio_region_finalize
secondary-vga: properly close QemuConsole on unplug
console: minimal hotplug suport
ui/pixman: add qemu_drm_format_to_pixman()
standard-headers: add drm/drm_fourcc.h
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/display/vga-pci.c | 9 | ||||
-rw-r--r-- | hw/ppc/spapr.c | 7 | ||||
-rw-r--r-- | hw/vfio/Makefile.objs | 2 | ||||
-rw-r--r-- | hw/vfio/common.c | 77 | ||||
-rw-r--r-- | hw/vfio/display.c | 347 | ||||
-rw-r--r-- | hw/vfio/pci.c | 32 | ||||
-rw-r--r-- | hw/vfio/pci.h | 5 |
7 files changed, 472 insertions, 7 deletions
diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c index 1674bd3581..f312930664 100644 --- a/hw/display/vga-pci.c +++ b/hw/display/vga-pci.c @@ -292,6 +292,14 @@ static void pci_secondary_vga_realize(PCIDevice *dev, Error **errp) pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio); } +static void pci_secondary_vga_exit(PCIDevice *dev) +{ + PCIVGAState *d = PCI_VGA(dev); + VGACommonState *s = &d->vga; + + graphic_console_close(s->con); +} + static void pci_secondary_vga_init(Object *obj) { /* Expose framebuffer byteorder via QOM */ @@ -361,6 +369,7 @@ static void secondary_class_init(ObjectClass *klass, void *data) PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); k->realize = pci_secondary_vga_realize; + k->exit = pci_secondary_vga_exit; k->class_id = PCI_CLASS_DISPLAY_OTHER; dc->props = secondary_pci_properties; dc->reset = pci_secondary_vga_reset; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 7e1c858566..032d03423f 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2855,6 +2855,11 @@ static void spapr_set_modern_hotplug_events(Object *obj, bool value, spapr->use_hotplug_event_source = value; } +static bool spapr_get_msix_emulation(Object *obj, Error **errp) +{ + return true; +} + static char *spapr_get_resize_hpt(Object *obj, Error **errp) { sPAPRMachineState *spapr = SPAPR_MACHINE(obj); @@ -2936,6 +2941,8 @@ static void spapr_instance_init(Object *obj) object_property_set_description(obj, "vsmt", "Virtual SMT: KVM behaves as if this were" " the host's SMT mode", &error_abort); + object_property_add_bool(obj, "vfio-no-msix-emulation", + spapr_get_msix_emulation, NULL, NULL); } static void spapr_machine_finalizefn(Object *obj) diff --git a/hw/vfio/Makefile.objs b/hw/vfio/Makefile.objs index c3ab9097f1..a2e7a0a7cf 100644 --- a/hw/vfio/Makefile.objs +++ b/hw/vfio/Makefile.objs @@ -1,6 +1,6 @@ ifeq ($(CONFIG_LINUX), y) obj-$(CONFIG_SOFTMMU) += common.o -obj-$(CONFIG_PCI) += pci.o pci-quirks.o +obj-$(CONFIG_PCI) += pci.o pci-quirks.o display.o obj-$(CONFIG_VFIO_CCW) += ccw.o obj-$(CONFIG_SOFTMMU) += platform.o obj-$(CONFIG_VFIO_XGMAC) += calxeda-xgmac.o diff --git a/hw/vfio/common.c b/hw/vfio/common.c index f895e3c335..5e84716218 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -544,18 +544,40 @@ static void vfio_listener_region_add(MemoryListener *listener, llsize = int128_sub(llend, int128_make64(iova)); + if (memory_region_is_ram_device(section->mr)) { + hwaddr pgmask = (1ULL << ctz64(hostwin->iova_pgsizes)) - 1; + + if ((iova & pgmask) || (int128_get64(llsize) & pgmask)) { + error_report("Region 0x%"HWADDR_PRIx"..0x%"HWADDR_PRIx + " is not aligned to 0x%"HWADDR_PRIx + " and cannot be mapped for DMA", + section->offset_within_region, + int128_getlo(section->size), + pgmask + 1); + return; + } + } + ret = vfio_dma_map(container, iova, int128_get64(llsize), vaddr, section->readonly); if (ret) { error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", " "0x%"HWADDR_PRIx", %p) = %d (%m)", container, iova, int128_get64(llsize), vaddr, ret); + if (memory_region_is_ram_device(section->mr)) { + /* Allow unexpected mappings not to be fatal for RAM devices */ + return; + } goto fail; } return; fail: + if (memory_region_is_ram_device(section->mr)) { + error_report("failed to vfio_dma_map. pci p2p may not work"); + return; + } /* * On the initfn path, store the first error in the container so we * can gracefully fail. Runtime, there's not much we can do other @@ -577,6 +599,7 @@ static void vfio_listener_region_del(MemoryListener *listener, hwaddr iova, end; Int128 llend, llsize; int ret; + bool try_unmap = true; if (vfio_listener_skipped_section(section)) { trace_vfio_listener_region_del_skip( @@ -629,14 +652,34 @@ static void vfio_listener_region_del(MemoryListener *listener, trace_vfio_listener_region_del(iova, end); - ret = vfio_dma_unmap(container, iova, int128_get64(llsize)); - memory_region_unref(section->mr); - if (ret) { - error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", " - "0x%"HWADDR_PRIx") = %d (%m)", - container, iova, int128_get64(llsize), ret); + if (memory_region_is_ram_device(section->mr)) { + hwaddr pgmask; + VFIOHostDMAWindow *hostwin; + bool hostwin_found = false; + + QLIST_FOREACH(hostwin, &container->hostwin_list, hostwin_next) { + if (hostwin->min_iova <= iova && end <= hostwin->max_iova) { + hostwin_found = true; + break; + } + } + assert(hostwin_found); /* or region_add() would have failed */ + + pgmask = (1ULL << ctz64(hostwin->iova_pgsizes)) - 1; + try_unmap = !((iova & pgmask) || (int128_get64(llsize) & pgmask)); } + if (try_unmap) { + ret = vfio_dma_unmap(container, iova, int128_get64(llsize)); + if (ret) { + error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", " + "0x%"HWADDR_PRIx") = %d (%m)", + container, iova, int128_get64(llsize), ret); + } + } + + memory_region_unref(section->mr); + if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) { vfio_spapr_remove_window(container, section->offset_within_address_space); @@ -858,6 +901,13 @@ void vfio_region_finalize(VFIORegion *region) g_free(region->mmaps); trace_vfio_region_finalize(region->vbasedev->name, region->nr); + + region->mem = NULL; + region->mmaps = NULL; + region->nr_mmaps = 0; + region->size = 0; + region->flags = 0; + region->nr = 0; } void vfio_region_mmaps_set_enabled(VFIORegion *region, bool enabled) @@ -1421,6 +1471,21 @@ int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, return -ENODEV; } +bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type) +{ + struct vfio_region_info *info = NULL; + bool ret = false; + + if (!vfio_get_region_info(vbasedev, region, &info)) { + if (vfio_get_region_info_cap(info, cap_type)) { + ret = true; + } + g_free(info); + } + + return ret; +} + /* * Interfaces for IBM EEH (Enhanced Error Handling) */ diff --git a/hw/vfio/display.c b/hw/vfio/display.c new file mode 100644 index 0000000000..7d727ce910 --- /dev/null +++ b/hw/vfio/display.c @@ -0,0 +1,347 @@ +/* + * display support for mdev based vgpu devices + * + * Copyright Red Hat, Inc. 2017 + * + * Authors: + * Gerd Hoffmann + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include <linux/vfio.h> +#include <sys/ioctl.h> + +#include "sysemu/sysemu.h" +#include "ui/console.h" +#include "qapi/error.h" +#include "pci.h" + +#ifndef DRM_PLANE_TYPE_PRIMARY +# define DRM_PLANE_TYPE_PRIMARY 1 +# define DRM_PLANE_TYPE_CURSOR 2 +#endif + +static void vfio_display_update_cursor(VFIODMABuf *dmabuf, + struct vfio_device_gfx_plane_info *plane) +{ + if (dmabuf->pos_x != plane->x_pos || dmabuf->pos_y != plane->y_pos) { + dmabuf->pos_x = plane->x_pos; + dmabuf->pos_y = plane->y_pos; + dmabuf->pos_updates++; + } + if (dmabuf->hot_x != plane->x_hot || dmabuf->hot_y != plane->y_hot) { + dmabuf->hot_x = plane->x_hot; + dmabuf->hot_y = plane->y_hot; + dmabuf->hot_updates++; + } +} + +static VFIODMABuf *vfio_display_get_dmabuf(VFIOPCIDevice *vdev, + uint32_t plane_type) +{ + VFIODisplay *dpy = vdev->dpy; + struct vfio_device_gfx_plane_info plane; + VFIODMABuf *dmabuf; + int fd, ret; + + memset(&plane, 0, sizeof(plane)); + plane.argsz = sizeof(plane); + plane.flags = VFIO_GFX_PLANE_TYPE_DMABUF; + plane.drm_plane_type = plane_type; + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_QUERY_GFX_PLANE, &plane); + if (ret < 0) { + return NULL; + } + if (!plane.drm_format || !plane.size) { + return NULL; + } + + QTAILQ_FOREACH(dmabuf, &dpy->dmabuf.bufs, next) { + if (dmabuf->dmabuf_id == plane.dmabuf_id) { + /* found in list, move to head, return it */ + QTAILQ_REMOVE(&dpy->dmabuf.bufs, dmabuf, next); + QTAILQ_INSERT_HEAD(&dpy->dmabuf.bufs, dmabuf, next); + if (plane_type == DRM_PLANE_TYPE_CURSOR) { + vfio_display_update_cursor(dmabuf, &plane); + } + return dmabuf; + } + } + + fd = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_GFX_DMABUF, &plane.dmabuf_id); + if (fd < 0) { + return NULL; + } + + dmabuf = g_new0(VFIODMABuf, 1); + dmabuf->dmabuf_id = plane.dmabuf_id; + dmabuf->buf.width = plane.width; + dmabuf->buf.height = plane.height; + dmabuf->buf.stride = plane.stride; + dmabuf->buf.fourcc = plane.drm_format; + dmabuf->buf.fd = fd; + if (plane_type == DRM_PLANE_TYPE_CURSOR) { + vfio_display_update_cursor(dmabuf, &plane); + } + + QTAILQ_INSERT_HEAD(&dpy->dmabuf.bufs, dmabuf, next); + return dmabuf; +} + +static void vfio_display_free_one_dmabuf(VFIODisplay *dpy, VFIODMABuf *dmabuf) +{ + QTAILQ_REMOVE(&dpy->dmabuf.bufs, dmabuf, next); + dpy_gl_release_dmabuf(dpy->con, &dmabuf->buf); + close(dmabuf->buf.fd); + g_free(dmabuf); +} + +static void vfio_display_free_dmabufs(VFIOPCIDevice *vdev) +{ + VFIODisplay *dpy = vdev->dpy; + VFIODMABuf *dmabuf, *tmp; + uint32_t keep = 5; + + QTAILQ_FOREACH_SAFE(dmabuf, &dpy->dmabuf.bufs, next, tmp) { + if (keep > 0) { + keep--; + continue; + } + assert(dmabuf != dpy->dmabuf.primary); + vfio_display_free_one_dmabuf(dpy, dmabuf); + } +} + +static void vfio_display_dmabuf_update(void *opaque) +{ + VFIOPCIDevice *vdev = opaque; + VFIODisplay *dpy = vdev->dpy; + VFIODMABuf *primary, *cursor; + bool free_bufs = false, new_cursor = false;; + + primary = vfio_display_get_dmabuf(vdev, DRM_PLANE_TYPE_PRIMARY); + if (primary == NULL) { + return; + } + + if (dpy->dmabuf.primary != primary) { + dpy->dmabuf.primary = primary; + qemu_console_resize(dpy->con, + primary->buf.width, primary->buf.height); + dpy_gl_scanout_dmabuf(dpy->con, &primary->buf); + free_bufs = true; + } + + cursor = vfio_display_get_dmabuf(vdev, DRM_PLANE_TYPE_CURSOR); + if (dpy->dmabuf.cursor != cursor) { + dpy->dmabuf.cursor = cursor; + new_cursor = true; + free_bufs = true; + } + + if (cursor && (new_cursor || cursor->hot_updates)) { + bool have_hot = (cursor->hot_x != 0xffffffff && + cursor->hot_y != 0xffffffff); + dpy_gl_cursor_dmabuf(dpy->con, &cursor->buf, have_hot, + cursor->hot_x, cursor->hot_y); + cursor->hot_updates = 0; + } else if (!cursor && new_cursor) { + dpy_gl_cursor_dmabuf(dpy->con, NULL, false, 0, 0); + } + + if (cursor && cursor->pos_updates) { + dpy_gl_cursor_position(dpy->con, + cursor->pos_x, + cursor->pos_y); + cursor->pos_updates = 0; + } + + dpy_gl_update(dpy->con, 0, 0, primary->buf.width, primary->buf.height); + + if (free_bufs) { + vfio_display_free_dmabufs(vdev); + } +} + +static const GraphicHwOps vfio_display_dmabuf_ops = { + .gfx_update = vfio_display_dmabuf_update, +}; + +static int vfio_display_dmabuf_init(VFIOPCIDevice *vdev, Error **errp) +{ + if (!display_opengl) { + error_setg(errp, "vfio-display-dmabuf: opengl not available"); + return -1; + } + + vdev->dpy = g_new0(VFIODisplay, 1); + vdev->dpy->con = graphic_console_init(DEVICE(vdev), 0, + &vfio_display_dmabuf_ops, + vdev); + return 0; +} + +static void vfio_display_dmabuf_exit(VFIODisplay *dpy) +{ + VFIODMABuf *dmabuf; + + if (QTAILQ_EMPTY(&dpy->dmabuf.bufs)) { + return; + } + + while ((dmabuf = QTAILQ_FIRST(&dpy->dmabuf.bufs)) != NULL) { + vfio_display_free_one_dmabuf(dpy, dmabuf); + } +} + +/* ---------------------------------------------------------------------- */ + +static void vfio_display_region_update(void *opaque) +{ + VFIOPCIDevice *vdev = opaque; + VFIODisplay *dpy = vdev->dpy; + struct vfio_device_gfx_plane_info plane = { + .argsz = sizeof(plane), + .flags = VFIO_GFX_PLANE_TYPE_REGION + }; + pixman_format_code_t format; + int ret; + + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_QUERY_GFX_PLANE, &plane); + if (ret < 0) { + error_report("ioctl VFIO_DEVICE_QUERY_GFX_PLANE: %s", + strerror(errno)); + return; + } + if (!plane.drm_format || !plane.size) { + return; + } + format = qemu_drm_format_to_pixman(plane.drm_format); + if (!format) { + return; + } + + if (dpy->region.buffer.size && + dpy->region.buffer.nr != plane.region_index) { + /* region changed */ + vfio_region_exit(&dpy->region.buffer); + vfio_region_finalize(&dpy->region.buffer); + dpy->region.surface = NULL; + } + + if (dpy->region.surface && + (surface_width(dpy->region.surface) != plane.width || + surface_height(dpy->region.surface) != plane.height || + surface_format(dpy->region.surface) != format)) { + /* size changed */ + dpy->region.surface = NULL; + } + + if (!dpy->region.buffer.size) { + /* mmap region */ + ret = vfio_region_setup(OBJECT(vdev), &vdev->vbasedev, + &dpy->region.buffer, + plane.region_index, + "display"); + if (ret != 0) { + error_report("%s: vfio_region_setup(%d): %s", + __func__, plane.region_index, strerror(-ret)); + goto err; + } + ret = vfio_region_mmap(&dpy->region.buffer); + if (ret != 0) { + error_report("%s: vfio_region_mmap(%d): %s", __func__, + plane.region_index, strerror(-ret)); + goto err; + } + assert(dpy->region.buffer.mmaps[0].mmap != NULL); + } + + if (dpy->region.surface == NULL) { + /* create surface */ + dpy->region.surface = qemu_create_displaysurface_from + (plane.width, plane.height, format, + plane.stride, dpy->region.buffer.mmaps[0].mmap); + dpy_gfx_replace_surface(dpy->con, dpy->region.surface); + } + + /* full screen update */ + dpy_gfx_update(dpy->con, 0, 0, + surface_width(dpy->region.surface), + surface_height(dpy->region.surface)); + return; + +err: + vfio_region_exit(&dpy->region.buffer); + vfio_region_finalize(&dpy->region.buffer); +} + +static const GraphicHwOps vfio_display_region_ops = { + .gfx_update = vfio_display_region_update, +}; + +static int vfio_display_region_init(VFIOPCIDevice *vdev, Error **errp) +{ + vdev->dpy = g_new0(VFIODisplay, 1); + vdev->dpy->con = graphic_console_init(DEVICE(vdev), 0, + &vfio_display_region_ops, + vdev); + return 0; +} + +static void vfio_display_region_exit(VFIODisplay *dpy) +{ + if (!dpy->region.buffer.size) { + return; + } + + vfio_region_exit(&dpy->region.buffer); + vfio_region_finalize(&dpy->region.buffer); +} + +/* ---------------------------------------------------------------------- */ + +int vfio_display_probe(VFIOPCIDevice *vdev, Error **errp) +{ + struct vfio_device_gfx_plane_info probe; + int ret; + + memset(&probe, 0, sizeof(probe)); + probe.argsz = sizeof(probe); + probe.flags = VFIO_GFX_PLANE_TYPE_PROBE | VFIO_GFX_PLANE_TYPE_DMABUF; + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_QUERY_GFX_PLANE, &probe); + if (ret == 0) { + return vfio_display_dmabuf_init(vdev, errp); + } + + memset(&probe, 0, sizeof(probe)); + probe.argsz = sizeof(probe); + probe.flags = VFIO_GFX_PLANE_TYPE_PROBE | VFIO_GFX_PLANE_TYPE_REGION; + ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_QUERY_GFX_PLANE, &probe); + if (ret == 0) { + return vfio_display_region_init(vdev, errp); + } + + if (vdev->display == ON_OFF_AUTO_AUTO) { + /* not an error in automatic mode */ + return 0; + } + + error_setg(errp, "vfio: device doesn't support any (known) display method"); + return -1; +} + +void vfio_display_finalize(VFIOPCIDevice *vdev) +{ + if (!vdev->dpy) { + return; + } + + graphic_console_close(vdev->dpy->con); + vfio_display_dmabuf_exit(vdev->dpy); + vfio_display_region_exit(vdev->dpy); + g_free(vdev->dpy); +} diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 3ba3cbc146..b9bc6cd310 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -1295,6 +1295,15 @@ static void vfio_pci_fixup_msix_region(VFIOPCIDevice *vdev) VFIORegion *region = &vdev->bars[vdev->msix->table_bar].region; /* + * If the host driver allows mapping of a MSIX data, we are going to + * do map the entire BAR and emulate MSIX table on top of that. + */ + if (vfio_has_region_cap(&vdev->vbasedev, region->nr, + VFIO_REGION_INFO_CAP_MSIX_MAPPABLE)) { + return; + } + + /* * We expect to find a single mmap covering the whole BAR, anything else * means it's either unsupported or already setup. */ @@ -1572,6 +1581,19 @@ static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos, Error **errp) */ memory_region_set_enabled(&vdev->pdev.msix_pba_mmio, false); + /* + * The emulated machine may provide a paravirt interface for MSIX setup + * so it is not strictly necessary to emulate MSIX here. This becomes + * helpful when frequently accessed MMIO registers are located in + * subpages adjacent to the MSIX table but the MSIX data containing page + * cannot be mapped because of a host page size bigger than the MSIX table + * alignment. + */ + if (object_property_get_bool(OBJECT(qdev_get_machine()), + "vfio-no-msix-emulation", NULL)) { + memory_region_set_enabled(&vdev->pdev.msix_table_mmio, false); + } + return 0; } @@ -3015,6 +3037,13 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) } } + if (vdev->display != ON_OFF_AUTO_OFF) { + ret = vfio_display_probe(vdev, errp); + if (ret) { + goto out_teardown; + } + } + vfio_register_err_notifier(vdev); vfio_register_req_notifier(vdev); vfio_setup_resetfn_quirk(vdev); @@ -3035,6 +3064,7 @@ static void vfio_instance_finalize(Object *obj) VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pci_dev); VFIOGroup *group = vdev->vbasedev.group; + vfio_display_finalize(vdev); vfio_bars_finalize(vdev); g_free(vdev->emulated_config_bits); g_free(vdev->rom); @@ -3123,6 +3153,8 @@ static void vfio_instance_init(Object *obj) static Property vfio_pci_dev_properties[] = { DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIOPCIDevice, host), DEFINE_PROP_STRING("sysfsdev", VFIOPCIDevice, vbasedev.sysfsdev), + DEFINE_PROP_ON_OFF_AUTO("display", VFIOPCIDevice, + display, ON_OFF_AUTO_AUTO), DEFINE_PROP_UINT32("x-intx-mmap-timeout-ms", VFIOPCIDevice, intx.mmap_timeout, 1100), DEFINE_PROP_BIT("x-vga", VFIOPCIDevice, features, diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h index f4aa13e021..629c875701 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -133,6 +133,7 @@ typedef struct VFIOPCIDevice { #define VFIO_FEATURE_ENABLE_IGD_OPREGION_BIT 2 #define VFIO_FEATURE_ENABLE_IGD_OPREGION \ (1 << VFIO_FEATURE_ENABLE_IGD_OPREGION_BIT) + OnOffAuto display; int32_t bootindex; uint32_t igd_gms; OffAutoPCIBAR msix_relo; @@ -147,6 +148,7 @@ typedef struct VFIOPCIDevice { bool no_kvm_msi; bool no_kvm_msix; bool no_geforce_quirks; + VFIODisplay *dpy; } VFIOPCIDevice; uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len); @@ -174,4 +176,7 @@ int vfio_pci_igd_opregion_init(VFIOPCIDevice *vdev, struct vfio_region_info *info, Error **errp); +int vfio_display_probe(VFIOPCIDevice *vdev, Error **errp); +void vfio_display_finalize(VFIOPCIDevice *vdev); + #endif /* HW_VFIO_VFIO_PCI_H */ |