2 * display support for mdev based vgpu devices
4 * Copyright Red Hat, Inc. 2017
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
13 #include "qemu/osdep.h"
14 #include <linux/vfio.h>
15 #include <sys/ioctl.h>
17 #include "sysemu/sysemu.h"
18 #include "ui/console.h"
19 #include "qapi/error.h"
22 /* ---------------------------------------------------------------------- */
24 static void vfio_display_region_update(void *opaque)
26 VFIOPCIDevice *vdev = opaque;
27 VFIODisplay *dpy = vdev->dpy;
28 struct vfio_device_gfx_plane_info plane = {
29 .argsz = sizeof(plane),
30 .flags = VFIO_GFX_PLANE_TYPE_REGION
32 pixman_format_code_t format;
35 ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_QUERY_GFX_PLANE, &plane);
37 error_report("ioctl VFIO_DEVICE_QUERY_GFX_PLANE: %s",
41 if (!plane.drm_format || !plane.size) {
44 format = qemu_drm_format_to_pixman(plane.drm_format);
49 if (dpy->region.buffer.size &&
50 dpy->region.buffer.nr != plane.region_index) {
52 vfio_region_exit(&dpy->region.buffer);
53 vfio_region_finalize(&dpy->region.buffer);
54 dpy->region.surface = NULL;
57 if (dpy->region.surface &&
58 (surface_width(dpy->region.surface) != plane.width ||
59 surface_height(dpy->region.surface) != plane.height ||
60 surface_format(dpy->region.surface) != format)) {
62 dpy->region.surface = NULL;
65 if (!dpy->region.buffer.size) {
67 ret = vfio_region_setup(OBJECT(vdev), &vdev->vbasedev,
72 error_report("%s: vfio_region_setup(%d): %s",
73 __func__, plane.region_index, strerror(-ret));
76 ret = vfio_region_mmap(&dpy->region.buffer);
78 error_report("%s: vfio_region_mmap(%d): %s", __func__,
79 plane.region_index, strerror(-ret));
82 assert(dpy->region.buffer.mmaps[0].mmap != NULL);
85 if (dpy->region.surface == NULL) {
87 dpy->region.surface = qemu_create_displaysurface_from
88 (plane.width, plane.height, format,
89 plane.stride, dpy->region.buffer.mmaps[0].mmap);
90 dpy_gfx_replace_surface(dpy->con, dpy->region.surface);
93 /* full screen update */
94 dpy_gfx_update(dpy->con, 0, 0,
95 surface_width(dpy->region.surface),
96 surface_height(dpy->region.surface));
100 vfio_region_exit(&dpy->region.buffer);
101 vfio_region_finalize(&dpy->region.buffer);
104 static const GraphicHwOps vfio_display_region_ops = {
105 .gfx_update = vfio_display_region_update,
108 static int vfio_display_region_init(VFIOPCIDevice *vdev, Error **errp)
110 vdev->dpy = g_new0(VFIODisplay, 1);
111 vdev->dpy->con = graphic_console_init(DEVICE(vdev), 0,
112 &vfio_display_region_ops,
117 static void vfio_display_region_exit(VFIODisplay *dpy)
119 if (!dpy->region.buffer.size) {
123 vfio_region_exit(&dpy->region.buffer);
124 vfio_region_finalize(&dpy->region.buffer);
127 /* ---------------------------------------------------------------------- */
129 int vfio_display_probe(VFIOPCIDevice *vdev, Error **errp)
131 struct vfio_device_gfx_plane_info probe;
134 memset(&probe, 0, sizeof(probe));
135 probe.argsz = sizeof(probe);
136 probe.flags = VFIO_GFX_PLANE_TYPE_PROBE | VFIO_GFX_PLANE_TYPE_DMABUF;
137 ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_QUERY_GFX_PLANE, &probe);
139 error_setg(errp, "vfio-display: dmabuf support not implemented yet");
143 memset(&probe, 0, sizeof(probe));
144 probe.argsz = sizeof(probe);
145 probe.flags = VFIO_GFX_PLANE_TYPE_PROBE | VFIO_GFX_PLANE_TYPE_REGION;
146 ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_QUERY_GFX_PLANE, &probe);
148 return vfio_display_region_init(vdev, errp);
151 if (vdev->display == ON_OFF_AUTO_AUTO) {
152 /* not an error in automatic mode */
156 error_setg(errp, "vfio: device doesn't support any (known) display method");
160 void vfio_display_finalize(VFIOPCIDevice *vdev)
166 graphic_console_close(vdev->dpy->con);
167 vfio_display_region_exit(vdev->dpy);