]> Git Repo - qemu.git/blob - hw/vfio/display.c
vfio/display: adding region support
[qemu.git] / hw / vfio / display.c
1 /*
2  * display support for mdev based vgpu devices
3  *
4  * Copyright Red Hat, Inc. 2017
5  *
6  * Authors:
7  *    Gerd Hoffmann
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2.  See
10  * the COPYING file in the top-level directory.
11  */
12
13 #include "qemu/osdep.h"
14 #include <linux/vfio.h>
15 #include <sys/ioctl.h>
16
17 #include "sysemu/sysemu.h"
18 #include "ui/console.h"
19 #include "qapi/error.h"
20 #include "pci.h"
21
22 /* ---------------------------------------------------------------------- */
23
24 static void vfio_display_region_update(void *opaque)
25 {
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
31     };
32     pixman_format_code_t format;
33     int ret;
34
35     ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_QUERY_GFX_PLANE, &plane);
36     if (ret < 0) {
37         error_report("ioctl VFIO_DEVICE_QUERY_GFX_PLANE: %s",
38                      strerror(errno));
39         return;
40     }
41     if (!plane.drm_format || !plane.size) {
42         return;
43     }
44     format = qemu_drm_format_to_pixman(plane.drm_format);
45     if (!format) {
46         return;
47     }
48
49     if (dpy->region.buffer.size &&
50         dpy->region.buffer.nr != plane.region_index) {
51         /* region changed */
52         vfio_region_exit(&dpy->region.buffer);
53         vfio_region_finalize(&dpy->region.buffer);
54         dpy->region.surface = NULL;
55     }
56
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)) {
61         /* size changed */
62         dpy->region.surface = NULL;
63     }
64
65     if (!dpy->region.buffer.size) {
66         /* mmap region */
67         ret = vfio_region_setup(OBJECT(vdev), &vdev->vbasedev,
68                                 &dpy->region.buffer,
69                                 plane.region_index,
70                                 "display");
71         if (ret != 0) {
72             error_report("%s: vfio_region_setup(%d): %s",
73                          __func__, plane.region_index, strerror(-ret));
74             goto err;
75         }
76         ret = vfio_region_mmap(&dpy->region.buffer);
77         if (ret != 0) {
78             error_report("%s: vfio_region_mmap(%d): %s", __func__,
79                          plane.region_index, strerror(-ret));
80             goto err;
81         }
82         assert(dpy->region.buffer.mmaps[0].mmap != NULL);
83     }
84
85     if (dpy->region.surface == NULL) {
86         /* create surface */
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);
91     }
92
93     /* full screen update */
94     dpy_gfx_update(dpy->con, 0, 0,
95                    surface_width(dpy->region.surface),
96                    surface_height(dpy->region.surface));
97     return;
98
99 err:
100     vfio_region_exit(&dpy->region.buffer);
101     vfio_region_finalize(&dpy->region.buffer);
102 }
103
104 static const GraphicHwOps vfio_display_region_ops = {
105     .gfx_update = vfio_display_region_update,
106 };
107
108 static int vfio_display_region_init(VFIOPCIDevice *vdev, Error **errp)
109 {
110     vdev->dpy = g_new0(VFIODisplay, 1);
111     vdev->dpy->con = graphic_console_init(DEVICE(vdev), 0,
112                                           &vfio_display_region_ops,
113                                           vdev);
114     return 0;
115 }
116
117 static void vfio_display_region_exit(VFIODisplay *dpy)
118 {
119     if (!dpy->region.buffer.size) {
120         return;
121     }
122
123     vfio_region_exit(&dpy->region.buffer);
124     vfio_region_finalize(&dpy->region.buffer);
125 }
126
127 /* ---------------------------------------------------------------------- */
128
129 int vfio_display_probe(VFIOPCIDevice *vdev, Error **errp)
130 {
131     struct vfio_device_gfx_plane_info probe;
132     int ret;
133
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);
138     if (ret == 0) {
139         error_setg(errp, "vfio-display: dmabuf support not implemented yet");
140         return -1;
141     }
142
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);
147     if (ret == 0) {
148         return vfio_display_region_init(vdev, errp);
149     }
150
151     if (vdev->display == ON_OFF_AUTO_AUTO) {
152         /* not an error in automatic mode */
153         return 0;
154     }
155
156     error_setg(errp, "vfio: device doesn't support any (known) display method");
157     return -1;
158 }
159
160 void vfio_display_finalize(VFIOPCIDevice *vdev)
161 {
162     if (!vdev->dpy) {
163         return;
164     }
165
166     graphic_console_close(vdev->dpy->con);
167     vfio_display_region_exit(vdev->dpy);
168     g_free(vdev->dpy);
169 }
This page took 0.031551 seconds and 4 git commands to generate.