xref: /qemu/hw/vfio/display.c (revision b290659fc3dd8fc51ea35511ea44d7656a3c9396)
1a9994687SGerd Hoffmann /*
2a9994687SGerd Hoffmann  * display support for mdev based vgpu devices
3a9994687SGerd Hoffmann  *
4a9994687SGerd Hoffmann  * Copyright Red Hat, Inc. 2017
5a9994687SGerd Hoffmann  *
6a9994687SGerd Hoffmann  * Authors:
7a9994687SGerd Hoffmann  *    Gerd Hoffmann
8a9994687SGerd Hoffmann  *
9a9994687SGerd Hoffmann  * This work is licensed under the terms of the GNU GPL, version 2.  See
10a9994687SGerd Hoffmann  * the COPYING file in the top-level directory.
11a9994687SGerd Hoffmann  */
12a9994687SGerd Hoffmann 
13a9994687SGerd Hoffmann #include "qemu/osdep.h"
14a9994687SGerd Hoffmann #include <linux/vfio.h>
15a9994687SGerd Hoffmann #include <sys/ioctl.h>
16a9994687SGerd Hoffmann 
17a9994687SGerd Hoffmann #include "sysemu/sysemu.h"
18a9994687SGerd Hoffmann #include "ui/console.h"
19a9994687SGerd Hoffmann #include "qapi/error.h"
20a9994687SGerd Hoffmann #include "pci.h"
21a9994687SGerd Hoffmann 
228b818e05SGerd Hoffmann #ifndef DRM_PLANE_TYPE_PRIMARY
238b818e05SGerd Hoffmann # define DRM_PLANE_TYPE_PRIMARY 1
248b818e05SGerd Hoffmann # define DRM_PLANE_TYPE_CURSOR  2
258b818e05SGerd Hoffmann #endif
268b818e05SGerd Hoffmann 
278b818e05SGerd Hoffmann static void vfio_display_update_cursor(VFIODMABuf *dmabuf,
288b818e05SGerd Hoffmann                                        struct vfio_device_gfx_plane_info *plane)
298b818e05SGerd Hoffmann {
308b818e05SGerd Hoffmann     if (dmabuf->pos_x != plane->x_pos || dmabuf->pos_y != plane->y_pos) {
318b818e05SGerd Hoffmann         dmabuf->pos_x      = plane->x_pos;
328b818e05SGerd Hoffmann         dmabuf->pos_y      = plane->y_pos;
338b818e05SGerd Hoffmann         dmabuf->pos_updates++;
348b818e05SGerd Hoffmann     }
358b818e05SGerd Hoffmann     if (dmabuf->hot_x != plane->x_hot || dmabuf->hot_y != plane->y_hot) {
368b818e05SGerd Hoffmann         dmabuf->hot_x      = plane->x_hot;
378b818e05SGerd Hoffmann         dmabuf->hot_y      = plane->y_hot;
388b818e05SGerd Hoffmann         dmabuf->hot_updates++;
398b818e05SGerd Hoffmann     }
408b818e05SGerd Hoffmann }
418b818e05SGerd Hoffmann 
428b818e05SGerd Hoffmann static VFIODMABuf *vfio_display_get_dmabuf(VFIOPCIDevice *vdev,
438b818e05SGerd Hoffmann                                            uint32_t plane_type)
448b818e05SGerd Hoffmann {
458b818e05SGerd Hoffmann     VFIODisplay *dpy = vdev->dpy;
468b818e05SGerd Hoffmann     struct vfio_device_gfx_plane_info plane;
478b818e05SGerd Hoffmann     VFIODMABuf *dmabuf;
488b818e05SGerd Hoffmann     int fd, ret;
498b818e05SGerd Hoffmann 
508b818e05SGerd Hoffmann     memset(&plane, 0, sizeof(plane));
518b818e05SGerd Hoffmann     plane.argsz = sizeof(plane);
528b818e05SGerd Hoffmann     plane.flags = VFIO_GFX_PLANE_TYPE_DMABUF;
538b818e05SGerd Hoffmann     plane.drm_plane_type = plane_type;
548b818e05SGerd Hoffmann     ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_QUERY_GFX_PLANE, &plane);
558b818e05SGerd Hoffmann     if (ret < 0) {
568b818e05SGerd Hoffmann         return NULL;
578b818e05SGerd Hoffmann     }
588b818e05SGerd Hoffmann     if (!plane.drm_format || !plane.size) {
598b818e05SGerd Hoffmann         return NULL;
608b818e05SGerd Hoffmann     }
618b818e05SGerd Hoffmann 
628b818e05SGerd Hoffmann     QTAILQ_FOREACH(dmabuf, &dpy->dmabuf.bufs, next) {
638b818e05SGerd Hoffmann         if (dmabuf->dmabuf_id == plane.dmabuf_id) {
648b818e05SGerd Hoffmann             /* found in list, move to head, return it */
658b818e05SGerd Hoffmann             QTAILQ_REMOVE(&dpy->dmabuf.bufs, dmabuf, next);
668b818e05SGerd Hoffmann             QTAILQ_INSERT_HEAD(&dpy->dmabuf.bufs, dmabuf, next);
678b818e05SGerd Hoffmann             if (plane_type == DRM_PLANE_TYPE_CURSOR) {
688b818e05SGerd Hoffmann                 vfio_display_update_cursor(dmabuf, &plane);
698b818e05SGerd Hoffmann             }
708b818e05SGerd Hoffmann             return dmabuf;
718b818e05SGerd Hoffmann         }
728b818e05SGerd Hoffmann     }
738b818e05SGerd Hoffmann 
748b818e05SGerd Hoffmann     fd = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_GFX_DMABUF, &plane.dmabuf_id);
758b818e05SGerd Hoffmann     if (fd < 0) {
768b818e05SGerd Hoffmann         return NULL;
778b818e05SGerd Hoffmann     }
788b818e05SGerd Hoffmann 
798b818e05SGerd Hoffmann     dmabuf = g_new0(VFIODMABuf, 1);
808b818e05SGerd Hoffmann     dmabuf->dmabuf_id  = plane.dmabuf_id;
818b818e05SGerd Hoffmann     dmabuf->buf.width  = plane.width;
828b818e05SGerd Hoffmann     dmabuf->buf.height = plane.height;
838b818e05SGerd Hoffmann     dmabuf->buf.stride = plane.stride;
848b818e05SGerd Hoffmann     dmabuf->buf.fourcc = plane.drm_format;
858b818e05SGerd Hoffmann     dmabuf->buf.fd     = fd;
868b818e05SGerd Hoffmann     if (plane_type == DRM_PLANE_TYPE_CURSOR) {
878b818e05SGerd Hoffmann         vfio_display_update_cursor(dmabuf, &plane);
888b818e05SGerd Hoffmann     }
898b818e05SGerd Hoffmann 
908b818e05SGerd Hoffmann     QTAILQ_INSERT_HEAD(&dpy->dmabuf.bufs, dmabuf, next);
918b818e05SGerd Hoffmann     return dmabuf;
928b818e05SGerd Hoffmann }
938b818e05SGerd Hoffmann 
948b818e05SGerd Hoffmann static void vfio_display_free_one_dmabuf(VFIODisplay *dpy, VFIODMABuf *dmabuf)
958b818e05SGerd Hoffmann {
968b818e05SGerd Hoffmann     QTAILQ_REMOVE(&dpy->dmabuf.bufs, dmabuf, next);
978b818e05SGerd Hoffmann     dpy_gl_release_dmabuf(dpy->con, &dmabuf->buf);
988b818e05SGerd Hoffmann     close(dmabuf->buf.fd);
998b818e05SGerd Hoffmann     g_free(dmabuf);
1008b818e05SGerd Hoffmann }
1018b818e05SGerd Hoffmann 
1028b818e05SGerd Hoffmann static void vfio_display_free_dmabufs(VFIOPCIDevice *vdev)
1038b818e05SGerd Hoffmann {
1048b818e05SGerd Hoffmann     VFIODisplay *dpy = vdev->dpy;
1058b818e05SGerd Hoffmann     VFIODMABuf *dmabuf, *tmp;
1068b818e05SGerd Hoffmann     uint32_t keep = 5;
1078b818e05SGerd Hoffmann 
1088b818e05SGerd Hoffmann     QTAILQ_FOREACH_SAFE(dmabuf, &dpy->dmabuf.bufs, next, tmp) {
1098b818e05SGerd Hoffmann         if (keep > 0) {
1108b818e05SGerd Hoffmann             keep--;
1118b818e05SGerd Hoffmann             continue;
1128b818e05SGerd Hoffmann         }
1138b818e05SGerd Hoffmann         assert(dmabuf != dpy->dmabuf.primary);
1148b818e05SGerd Hoffmann         vfio_display_free_one_dmabuf(dpy, dmabuf);
1158b818e05SGerd Hoffmann     }
1168b818e05SGerd Hoffmann }
1178b818e05SGerd Hoffmann 
1188b818e05SGerd Hoffmann static void vfio_display_dmabuf_update(void *opaque)
1198b818e05SGerd Hoffmann {
1208b818e05SGerd Hoffmann     VFIOPCIDevice *vdev = opaque;
1218b818e05SGerd Hoffmann     VFIODisplay *dpy = vdev->dpy;
1228b818e05SGerd Hoffmann     VFIODMABuf *primary, *cursor;
1238b818e05SGerd Hoffmann     bool free_bufs = false, new_cursor = false;;
1248b818e05SGerd Hoffmann 
1258b818e05SGerd Hoffmann     primary = vfio_display_get_dmabuf(vdev, DRM_PLANE_TYPE_PRIMARY);
1268b818e05SGerd Hoffmann     if (primary == NULL) {
127*b290659fSGerd Hoffmann         if (dpy->ramfb) {
128*b290659fSGerd Hoffmann             ramfb_display_update(dpy->con, dpy->ramfb);
129*b290659fSGerd Hoffmann         }
1308b818e05SGerd Hoffmann         return;
1318b818e05SGerd Hoffmann     }
1328b818e05SGerd Hoffmann 
1338b818e05SGerd Hoffmann     if (dpy->dmabuf.primary != primary) {
1348b818e05SGerd Hoffmann         dpy->dmabuf.primary = primary;
1358b818e05SGerd Hoffmann         qemu_console_resize(dpy->con,
1368b818e05SGerd Hoffmann                             primary->buf.width, primary->buf.height);
1378b818e05SGerd Hoffmann         dpy_gl_scanout_dmabuf(dpy->con, &primary->buf);
1388b818e05SGerd Hoffmann         free_bufs = true;
1398b818e05SGerd Hoffmann     }
1408b818e05SGerd Hoffmann 
1418b818e05SGerd Hoffmann     cursor = vfio_display_get_dmabuf(vdev, DRM_PLANE_TYPE_CURSOR);
1428b818e05SGerd Hoffmann     if (dpy->dmabuf.cursor != cursor) {
1438b818e05SGerd Hoffmann         dpy->dmabuf.cursor = cursor;
1448b818e05SGerd Hoffmann         new_cursor = true;
1458b818e05SGerd Hoffmann         free_bufs = true;
1468b818e05SGerd Hoffmann     }
1478b818e05SGerd Hoffmann 
1488b818e05SGerd Hoffmann     if (cursor && (new_cursor || cursor->hot_updates)) {
1498b818e05SGerd Hoffmann         bool have_hot = (cursor->hot_x != 0xffffffff &&
1508b818e05SGerd Hoffmann                          cursor->hot_y != 0xffffffff);
1518b818e05SGerd Hoffmann         dpy_gl_cursor_dmabuf(dpy->con, &cursor->buf, have_hot,
1528b818e05SGerd Hoffmann                              cursor->hot_x, cursor->hot_y);
1538b818e05SGerd Hoffmann         cursor->hot_updates = 0;
1548b818e05SGerd Hoffmann     } else if (!cursor && new_cursor) {
1558b818e05SGerd Hoffmann         dpy_gl_cursor_dmabuf(dpy->con, NULL, false, 0, 0);
1568b818e05SGerd Hoffmann     }
1578b818e05SGerd Hoffmann 
1588b818e05SGerd Hoffmann     if (cursor && cursor->pos_updates) {
1598b818e05SGerd Hoffmann         dpy_gl_cursor_position(dpy->con,
1608b818e05SGerd Hoffmann                                cursor->pos_x,
1618b818e05SGerd Hoffmann                                cursor->pos_y);
1628b818e05SGerd Hoffmann         cursor->pos_updates = 0;
1638b818e05SGerd Hoffmann     }
1648b818e05SGerd Hoffmann 
1658b818e05SGerd Hoffmann     dpy_gl_update(dpy->con, 0, 0, primary->buf.width, primary->buf.height);
1668b818e05SGerd Hoffmann 
1678b818e05SGerd Hoffmann     if (free_bufs) {
1688b818e05SGerd Hoffmann         vfio_display_free_dmabufs(vdev);
1698b818e05SGerd Hoffmann     }
1708b818e05SGerd Hoffmann }
1718b818e05SGerd Hoffmann 
1728b818e05SGerd Hoffmann static const GraphicHwOps vfio_display_dmabuf_ops = {
1738b818e05SGerd Hoffmann     .gfx_update = vfio_display_dmabuf_update,
1748b818e05SGerd Hoffmann };
1758b818e05SGerd Hoffmann 
1768b818e05SGerd Hoffmann static int vfio_display_dmabuf_init(VFIOPCIDevice *vdev, Error **errp)
1778b818e05SGerd Hoffmann {
1788b818e05SGerd Hoffmann     if (!display_opengl) {
1798b818e05SGerd Hoffmann         error_setg(errp, "vfio-display-dmabuf: opengl not available");
1808b818e05SGerd Hoffmann         return -1;
1818b818e05SGerd Hoffmann     }
1828b818e05SGerd Hoffmann 
1838b818e05SGerd Hoffmann     vdev->dpy = g_new0(VFIODisplay, 1);
1848b818e05SGerd Hoffmann     vdev->dpy->con = graphic_console_init(DEVICE(vdev), 0,
1858b818e05SGerd Hoffmann                                           &vfio_display_dmabuf_ops,
1868b818e05SGerd Hoffmann                                           vdev);
187*b290659fSGerd Hoffmann     if (vdev->enable_ramfb) {
188*b290659fSGerd Hoffmann         vdev->dpy->ramfb = ramfb_setup(errp);
189*b290659fSGerd Hoffmann     }
1908b818e05SGerd Hoffmann     return 0;
1918b818e05SGerd Hoffmann }
1928b818e05SGerd Hoffmann 
1938b818e05SGerd Hoffmann static void vfio_display_dmabuf_exit(VFIODisplay *dpy)
1948b818e05SGerd Hoffmann {
1958b818e05SGerd Hoffmann     VFIODMABuf *dmabuf;
1968b818e05SGerd Hoffmann 
1978b818e05SGerd Hoffmann     if (QTAILQ_EMPTY(&dpy->dmabuf.bufs)) {
1988b818e05SGerd Hoffmann         return;
1998b818e05SGerd Hoffmann     }
2008b818e05SGerd Hoffmann 
2018b818e05SGerd Hoffmann     while ((dmabuf = QTAILQ_FIRST(&dpy->dmabuf.bufs)) != NULL) {
2028b818e05SGerd Hoffmann         vfio_display_free_one_dmabuf(dpy, dmabuf);
2038b818e05SGerd Hoffmann     }
2048b818e05SGerd Hoffmann }
2058b818e05SGerd Hoffmann 
20600195ba7SGerd Hoffmann /* ---------------------------------------------------------------------- */
2078983e3e3STina Zhang void vfio_display_reset(VFIOPCIDevice *vdev)
2088983e3e3STina Zhang {
2098983e3e3STina Zhang     if (!vdev || !vdev->dpy || !vdev->dpy->con ||
2108983e3e3STina Zhang         !vdev->dpy->dmabuf.primary) {
2118983e3e3STina Zhang         return;
2128983e3e3STina Zhang     }
2138983e3e3STina Zhang 
2148983e3e3STina Zhang     dpy_gl_scanout_disable(vdev->dpy->con);
2158983e3e3STina Zhang     vfio_display_dmabuf_exit(vdev->dpy);
2168983e3e3STina Zhang     dpy_gfx_update_full(vdev->dpy->con);
2178983e3e3STina Zhang }
21800195ba7SGerd Hoffmann 
21900195ba7SGerd Hoffmann static void vfio_display_region_update(void *opaque)
22000195ba7SGerd Hoffmann {
22100195ba7SGerd Hoffmann     VFIOPCIDevice *vdev = opaque;
22200195ba7SGerd Hoffmann     VFIODisplay *dpy = vdev->dpy;
22300195ba7SGerd Hoffmann     struct vfio_device_gfx_plane_info plane = {
22400195ba7SGerd Hoffmann         .argsz = sizeof(plane),
22500195ba7SGerd Hoffmann         .flags = VFIO_GFX_PLANE_TYPE_REGION
22600195ba7SGerd Hoffmann     };
22700195ba7SGerd Hoffmann     pixman_format_code_t format;
22800195ba7SGerd Hoffmann     int ret;
22900195ba7SGerd Hoffmann 
23000195ba7SGerd Hoffmann     ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_QUERY_GFX_PLANE, &plane);
23100195ba7SGerd Hoffmann     if (ret < 0) {
23200195ba7SGerd Hoffmann         error_report("ioctl VFIO_DEVICE_QUERY_GFX_PLANE: %s",
23300195ba7SGerd Hoffmann                      strerror(errno));
23400195ba7SGerd Hoffmann         return;
23500195ba7SGerd Hoffmann     }
23600195ba7SGerd Hoffmann     if (!plane.drm_format || !plane.size) {
237*b290659fSGerd Hoffmann         if (dpy->ramfb) {
238*b290659fSGerd Hoffmann             ramfb_display_update(dpy->con, dpy->ramfb);
239*b290659fSGerd Hoffmann         }
24000195ba7SGerd Hoffmann         return;
24100195ba7SGerd Hoffmann     }
24200195ba7SGerd Hoffmann     format = qemu_drm_format_to_pixman(plane.drm_format);
24300195ba7SGerd Hoffmann     if (!format) {
24400195ba7SGerd Hoffmann         return;
24500195ba7SGerd Hoffmann     }
24600195ba7SGerd Hoffmann 
24700195ba7SGerd Hoffmann     if (dpy->region.buffer.size &&
24800195ba7SGerd Hoffmann         dpy->region.buffer.nr != plane.region_index) {
24900195ba7SGerd Hoffmann         /* region changed */
25000195ba7SGerd Hoffmann         vfio_region_exit(&dpy->region.buffer);
25100195ba7SGerd Hoffmann         vfio_region_finalize(&dpy->region.buffer);
25200195ba7SGerd Hoffmann         dpy->region.surface = NULL;
25300195ba7SGerd Hoffmann     }
25400195ba7SGerd Hoffmann 
25500195ba7SGerd Hoffmann     if (dpy->region.surface &&
25600195ba7SGerd Hoffmann         (surface_width(dpy->region.surface) != plane.width ||
25700195ba7SGerd Hoffmann          surface_height(dpy->region.surface) != plane.height ||
25800195ba7SGerd Hoffmann          surface_format(dpy->region.surface) != format)) {
25900195ba7SGerd Hoffmann         /* size changed */
26000195ba7SGerd Hoffmann         dpy->region.surface = NULL;
26100195ba7SGerd Hoffmann     }
26200195ba7SGerd Hoffmann 
26300195ba7SGerd Hoffmann     if (!dpy->region.buffer.size) {
26400195ba7SGerd Hoffmann         /* mmap region */
26500195ba7SGerd Hoffmann         ret = vfio_region_setup(OBJECT(vdev), &vdev->vbasedev,
26600195ba7SGerd Hoffmann                                 &dpy->region.buffer,
26700195ba7SGerd Hoffmann                                 plane.region_index,
26800195ba7SGerd Hoffmann                                 "display");
26900195ba7SGerd Hoffmann         if (ret != 0) {
27000195ba7SGerd Hoffmann             error_report("%s: vfio_region_setup(%d): %s",
27100195ba7SGerd Hoffmann                          __func__, plane.region_index, strerror(-ret));
27200195ba7SGerd Hoffmann             goto err;
27300195ba7SGerd Hoffmann         }
27400195ba7SGerd Hoffmann         ret = vfio_region_mmap(&dpy->region.buffer);
27500195ba7SGerd Hoffmann         if (ret != 0) {
27600195ba7SGerd Hoffmann             error_report("%s: vfio_region_mmap(%d): %s", __func__,
27700195ba7SGerd Hoffmann                          plane.region_index, strerror(-ret));
27800195ba7SGerd Hoffmann             goto err;
27900195ba7SGerd Hoffmann         }
28000195ba7SGerd Hoffmann         assert(dpy->region.buffer.mmaps[0].mmap != NULL);
28100195ba7SGerd Hoffmann     }
28200195ba7SGerd Hoffmann 
28300195ba7SGerd Hoffmann     if (dpy->region.surface == NULL) {
28400195ba7SGerd Hoffmann         /* create surface */
28500195ba7SGerd Hoffmann         dpy->region.surface = qemu_create_displaysurface_from
28600195ba7SGerd Hoffmann             (plane.width, plane.height, format,
28700195ba7SGerd Hoffmann              plane.stride, dpy->region.buffer.mmaps[0].mmap);
28800195ba7SGerd Hoffmann         dpy_gfx_replace_surface(dpy->con, dpy->region.surface);
28900195ba7SGerd Hoffmann     }
29000195ba7SGerd Hoffmann 
29100195ba7SGerd Hoffmann     /* full screen update */
29200195ba7SGerd Hoffmann     dpy_gfx_update(dpy->con, 0, 0,
29300195ba7SGerd Hoffmann                    surface_width(dpy->region.surface),
29400195ba7SGerd Hoffmann                    surface_height(dpy->region.surface));
29500195ba7SGerd Hoffmann     return;
29600195ba7SGerd Hoffmann 
29700195ba7SGerd Hoffmann err:
29800195ba7SGerd Hoffmann     vfio_region_exit(&dpy->region.buffer);
29900195ba7SGerd Hoffmann     vfio_region_finalize(&dpy->region.buffer);
30000195ba7SGerd Hoffmann }
30100195ba7SGerd Hoffmann 
30200195ba7SGerd Hoffmann static const GraphicHwOps vfio_display_region_ops = {
30300195ba7SGerd Hoffmann     .gfx_update = vfio_display_region_update,
30400195ba7SGerd Hoffmann };
30500195ba7SGerd Hoffmann 
30600195ba7SGerd Hoffmann static int vfio_display_region_init(VFIOPCIDevice *vdev, Error **errp)
30700195ba7SGerd Hoffmann {
30800195ba7SGerd Hoffmann     vdev->dpy = g_new0(VFIODisplay, 1);
30900195ba7SGerd Hoffmann     vdev->dpy->con = graphic_console_init(DEVICE(vdev), 0,
31000195ba7SGerd Hoffmann                                           &vfio_display_region_ops,
31100195ba7SGerd Hoffmann                                           vdev);
312*b290659fSGerd Hoffmann     if (vdev->enable_ramfb) {
313*b290659fSGerd Hoffmann         vdev->dpy->ramfb = ramfb_setup(errp);
314*b290659fSGerd Hoffmann     }
31500195ba7SGerd Hoffmann     return 0;
31600195ba7SGerd Hoffmann }
31700195ba7SGerd Hoffmann 
31800195ba7SGerd Hoffmann static void vfio_display_region_exit(VFIODisplay *dpy)
31900195ba7SGerd Hoffmann {
32000195ba7SGerd Hoffmann     if (!dpy->region.buffer.size) {
32100195ba7SGerd Hoffmann         return;
32200195ba7SGerd Hoffmann     }
32300195ba7SGerd Hoffmann 
32400195ba7SGerd Hoffmann     vfio_region_exit(&dpy->region.buffer);
32500195ba7SGerd Hoffmann     vfio_region_finalize(&dpy->region.buffer);
32600195ba7SGerd Hoffmann }
32700195ba7SGerd Hoffmann 
32800195ba7SGerd Hoffmann /* ---------------------------------------------------------------------- */
32900195ba7SGerd Hoffmann 
330a9994687SGerd Hoffmann int vfio_display_probe(VFIOPCIDevice *vdev, Error **errp)
331a9994687SGerd Hoffmann {
332a9994687SGerd Hoffmann     struct vfio_device_gfx_plane_info probe;
333a9994687SGerd Hoffmann     int ret;
334a9994687SGerd Hoffmann 
335a9994687SGerd Hoffmann     memset(&probe, 0, sizeof(probe));
336a9994687SGerd Hoffmann     probe.argsz = sizeof(probe);
337a9994687SGerd Hoffmann     probe.flags = VFIO_GFX_PLANE_TYPE_PROBE | VFIO_GFX_PLANE_TYPE_DMABUF;
338a9994687SGerd Hoffmann     ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_QUERY_GFX_PLANE, &probe);
339a9994687SGerd Hoffmann     if (ret == 0) {
3408b818e05SGerd Hoffmann         return vfio_display_dmabuf_init(vdev, errp);
341a9994687SGerd Hoffmann     }
342a9994687SGerd Hoffmann 
343a9994687SGerd Hoffmann     memset(&probe, 0, sizeof(probe));
344a9994687SGerd Hoffmann     probe.argsz = sizeof(probe);
345a9994687SGerd Hoffmann     probe.flags = VFIO_GFX_PLANE_TYPE_PROBE | VFIO_GFX_PLANE_TYPE_REGION;
346a9994687SGerd Hoffmann     ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_QUERY_GFX_PLANE, &probe);
347a9994687SGerd Hoffmann     if (ret == 0) {
34800195ba7SGerd Hoffmann         return vfio_display_region_init(vdev, errp);
349a9994687SGerd Hoffmann     }
350a9994687SGerd Hoffmann 
351a9994687SGerd Hoffmann     if (vdev->display == ON_OFF_AUTO_AUTO) {
352a9994687SGerd Hoffmann         /* not an error in automatic mode */
353a9994687SGerd Hoffmann         return 0;
354a9994687SGerd Hoffmann     }
355a9994687SGerd Hoffmann 
356a9994687SGerd Hoffmann     error_setg(errp, "vfio: device doesn't support any (known) display method");
357a9994687SGerd Hoffmann     return -1;
358a9994687SGerd Hoffmann }
359a9994687SGerd Hoffmann 
360a9994687SGerd Hoffmann void vfio_display_finalize(VFIOPCIDevice *vdev)
361a9994687SGerd Hoffmann {
36200195ba7SGerd Hoffmann     if (!vdev->dpy) {
36300195ba7SGerd Hoffmann         return;
36400195ba7SGerd Hoffmann     }
36500195ba7SGerd Hoffmann 
36600195ba7SGerd Hoffmann     graphic_console_close(vdev->dpy->con);
3678b818e05SGerd Hoffmann     vfio_display_dmabuf_exit(vdev->dpy);
36800195ba7SGerd Hoffmann     vfio_display_region_exit(vdev->dpy);
36900195ba7SGerd Hoffmann     g_free(vdev->dpy);
370a9994687SGerd Hoffmann }
371