diff options
author | Gerd Hoffmann <kraxel@redhat.com> | 2018-03-13 11:17:30 -0600 |
---|---|---|
committer | Alex Williamson <alex.williamson@redhat.com> | 2018-03-13 11:17:30 -0600 |
commit | 00195ba710a004af02a711239324d7137f0b189a (patch) | |
tree | 65c32ae696f621d8eaa0c20a8309eb53b13d0d65 /hw/vfio | |
parent | a9994687cb9b5f72399398a0985419f4d2b95dc5 (diff) |
vfio/display: adding region support
Wire up region-based display.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed By: Kirti Wankhede <kwankhede@nvidia.com>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Diffstat (limited to 'hw/vfio')
-rw-r--r-- | hw/vfio/display.c | 117 | ||||
-rw-r--r-- | hw/vfio/pci.h | 1 |
2 files changed, 116 insertions, 2 deletions
diff --git a/hw/vfio/display.c b/hw/vfio/display.c index 3e997f8a44..0add223039 100644 --- a/hw/vfio/display.c +++ b/hw/vfio/display.c @@ -19,6 +19,113 @@ #include "qapi/error.h" #include "pci.h" +/* ---------------------------------------------------------------------- */ + +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; @@ -38,8 +145,7 @@ int vfio_display_probe(VFIOPCIDevice *vdev, Error **errp) 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) { - error_setg(errp, "vfio-display: region support not implemented yet"); - return -1; + return vfio_display_region_init(vdev, errp); } if (vdev->display == ON_OFF_AUTO_AUTO) { @@ -53,4 +159,11 @@ int vfio_display_probe(VFIOPCIDevice *vdev, Error **errp) void vfio_display_finalize(VFIOPCIDevice *vdev) { + if (!vdev->dpy) { + return; + } + + graphic_console_close(vdev->dpy->con); + vfio_display_region_exit(vdev->dpy); + g_free(vdev->dpy); } diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h index a846cf6237..629c875701 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -148,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); |