1267f6646SMarc-André Lureau /*
2267f6646SMarc-André Lureau * vhost-user GPU Device
3267f6646SMarc-André Lureau *
4267f6646SMarc-André Lureau * Copyright Red Hat, Inc. 2018
5267f6646SMarc-André Lureau *
6267f6646SMarc-André Lureau * Authors:
7267f6646SMarc-André Lureau * Marc-André Lureau <marcandre.lureau@redhat.com>
8267f6646SMarc-André Lureau *
9267f6646SMarc-André Lureau * This work is licensed under the terms of the GNU GPL, version 2 or later.
10267f6646SMarc-André Lureau * See the COPYING file in the top-level directory.
11267f6646SMarc-André Lureau */
12267f6646SMarc-André Lureau
13267f6646SMarc-André Lureau #include "qemu/osdep.h"
145feed38cSThomas Huth #include "qemu/error-report.h"
159cbda7b3SGuoyi Tu #include "qemu/sockets.h"
16a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
17267f6646SMarc-André Lureau #include "hw/virtio/virtio-gpu.h"
18267f6646SMarc-André Lureau #include "chardev/char-fe.h"
19267f6646SMarc-André Lureau #include "qapi/error.h"
20267f6646SMarc-André Lureau #include "migration/blocker.h"
21ac705689SQiang Yu #include "standard-headers/drm/drm_fourcc.h"
22267f6646SMarc-André Lureau
23267f6646SMarc-André Lureau typedef enum VhostUserGpuRequest {
24267f6646SMarc-André Lureau VHOST_USER_GPU_NONE = 0,
25267f6646SMarc-André Lureau VHOST_USER_GPU_GET_PROTOCOL_FEATURES,
26267f6646SMarc-André Lureau VHOST_USER_GPU_SET_PROTOCOL_FEATURES,
27267f6646SMarc-André Lureau VHOST_USER_GPU_GET_DISPLAY_INFO,
28267f6646SMarc-André Lureau VHOST_USER_GPU_CURSOR_POS,
29267f6646SMarc-André Lureau VHOST_USER_GPU_CURSOR_POS_HIDE,
30267f6646SMarc-André Lureau VHOST_USER_GPU_CURSOR_UPDATE,
31267f6646SMarc-André Lureau VHOST_USER_GPU_SCANOUT,
32267f6646SMarc-André Lureau VHOST_USER_GPU_UPDATE,
33267f6646SMarc-André Lureau VHOST_USER_GPU_DMABUF_SCANOUT,
34267f6646SMarc-André Lureau VHOST_USER_GPU_DMABUF_UPDATE,
3531f137e3SErico Nunes VHOST_USER_GPU_GET_EDID,
36d824da9dSErico Nunes VHOST_USER_GPU_DMABUF_SCANOUT2,
37267f6646SMarc-André Lureau } VhostUserGpuRequest;
38267f6646SMarc-André Lureau
39267f6646SMarc-André Lureau typedef struct VhostUserGpuDisplayInfoReply {
40267f6646SMarc-André Lureau struct virtio_gpu_resp_display_info info;
41267f6646SMarc-André Lureau } VhostUserGpuDisplayInfoReply;
42267f6646SMarc-André Lureau
43267f6646SMarc-André Lureau typedef struct VhostUserGpuCursorPos {
44267f6646SMarc-André Lureau uint32_t scanout_id;
45267f6646SMarc-André Lureau uint32_t x;
46267f6646SMarc-André Lureau uint32_t y;
47267f6646SMarc-André Lureau } QEMU_PACKED VhostUserGpuCursorPos;
48267f6646SMarc-André Lureau
49267f6646SMarc-André Lureau typedef struct VhostUserGpuCursorUpdate {
50267f6646SMarc-André Lureau VhostUserGpuCursorPos pos;
51267f6646SMarc-André Lureau uint32_t hot_x;
52267f6646SMarc-André Lureau uint32_t hot_y;
53267f6646SMarc-André Lureau uint32_t data[64 * 64];
54267f6646SMarc-André Lureau } QEMU_PACKED VhostUserGpuCursorUpdate;
55267f6646SMarc-André Lureau
56267f6646SMarc-André Lureau typedef struct VhostUserGpuScanout {
57267f6646SMarc-André Lureau uint32_t scanout_id;
58267f6646SMarc-André Lureau uint32_t width;
59267f6646SMarc-André Lureau uint32_t height;
60267f6646SMarc-André Lureau } QEMU_PACKED VhostUserGpuScanout;
61267f6646SMarc-André Lureau
62267f6646SMarc-André Lureau typedef struct VhostUserGpuUpdate {
63267f6646SMarc-André Lureau uint32_t scanout_id;
64267f6646SMarc-André Lureau uint32_t x;
65267f6646SMarc-André Lureau uint32_t y;
66267f6646SMarc-André Lureau uint32_t width;
67267f6646SMarc-André Lureau uint32_t height;
68267f6646SMarc-André Lureau uint8_t data[];
69267f6646SMarc-André Lureau } QEMU_PACKED VhostUserGpuUpdate;
70267f6646SMarc-André Lureau
71267f6646SMarc-André Lureau typedef struct VhostUserGpuDMABUFScanout {
72267f6646SMarc-André Lureau uint32_t scanout_id;
73267f6646SMarc-André Lureau uint32_t x;
74267f6646SMarc-André Lureau uint32_t y;
75267f6646SMarc-André Lureau uint32_t width;
76267f6646SMarc-André Lureau uint32_t height;
77267f6646SMarc-André Lureau uint32_t fd_width;
78267f6646SMarc-André Lureau uint32_t fd_height;
79267f6646SMarc-André Lureau uint32_t fd_stride;
80267f6646SMarc-André Lureau uint32_t fd_flags;
81267f6646SMarc-André Lureau int fd_drm_fourcc;
82267f6646SMarc-André Lureau } QEMU_PACKED VhostUserGpuDMABUFScanout;
83267f6646SMarc-André Lureau
84d824da9dSErico Nunes typedef struct VhostUserGpuDMABUFScanout2 {
85d824da9dSErico Nunes struct VhostUserGpuDMABUFScanout dmabuf_scanout;
86d824da9dSErico Nunes uint64_t modifier;
87d824da9dSErico Nunes } QEMU_PACKED VhostUserGpuDMABUFScanout2;
88d824da9dSErico Nunes
8931f137e3SErico Nunes typedef struct VhostUserGpuEdidRequest {
9031f137e3SErico Nunes uint32_t scanout_id;
9131f137e3SErico Nunes } QEMU_PACKED VhostUserGpuEdidRequest;
9231f137e3SErico Nunes
93267f6646SMarc-André Lureau typedef struct VhostUserGpuMsg {
94267f6646SMarc-André Lureau uint32_t request; /* VhostUserGpuRequest */
95267f6646SMarc-André Lureau uint32_t flags;
96267f6646SMarc-André Lureau uint32_t size; /* the following payload size */
97267f6646SMarc-André Lureau union {
98267f6646SMarc-André Lureau VhostUserGpuCursorPos cursor_pos;
99267f6646SMarc-André Lureau VhostUserGpuCursorUpdate cursor_update;
100267f6646SMarc-André Lureau VhostUserGpuScanout scanout;
101267f6646SMarc-André Lureau VhostUserGpuUpdate update;
102267f6646SMarc-André Lureau VhostUserGpuDMABUFScanout dmabuf_scanout;
103d824da9dSErico Nunes VhostUserGpuDMABUFScanout2 dmabuf_scanout2;
10431f137e3SErico Nunes VhostUserGpuEdidRequest edid_req;
10531f137e3SErico Nunes struct virtio_gpu_resp_edid resp_edid;
106267f6646SMarc-André Lureau struct virtio_gpu_resp_display_info display_info;
107267f6646SMarc-André Lureau uint64_t u64;
108267f6646SMarc-André Lureau } payload;
109267f6646SMarc-André Lureau } QEMU_PACKED VhostUserGpuMsg;
110267f6646SMarc-André Lureau
111267f6646SMarc-André Lureau static VhostUserGpuMsg m __attribute__ ((unused));
112267f6646SMarc-André Lureau #define VHOST_USER_GPU_HDR_SIZE \
113267f6646SMarc-André Lureau (sizeof(m.request) + sizeof(m.size) + sizeof(m.flags))
114267f6646SMarc-André Lureau
115267f6646SMarc-André Lureau #define VHOST_USER_GPU_MSG_FLAG_REPLY 0x4
116267f6646SMarc-André Lureau
11731f137e3SErico Nunes #define VHOST_USER_GPU_PROTOCOL_F_EDID 0
118d824da9dSErico Nunes #define VHOST_USER_GPU_PROTOCOL_F_DMABUF2 1
11931f137e3SErico Nunes
120267f6646SMarc-André Lureau static void vhost_user_gpu_update_blocked(VhostUserGPU *g, bool blocked);
121267f6646SMarc-André Lureau
122267f6646SMarc-André Lureau static void
vhost_user_gpu_handle_cursor(VhostUserGPU * g,VhostUserGpuMsg * msg)123267f6646SMarc-André Lureau vhost_user_gpu_handle_cursor(VhostUserGPU *g, VhostUserGpuMsg *msg)
124267f6646SMarc-André Lureau {
125267f6646SMarc-André Lureau VhostUserGpuCursorPos *pos = &msg->payload.cursor_pos;
126267f6646SMarc-André Lureau struct virtio_gpu_scanout *s;
127267f6646SMarc-André Lureau
128267f6646SMarc-André Lureau if (pos->scanout_id >= g->parent_obj.conf.max_outputs) {
129267f6646SMarc-André Lureau return;
130267f6646SMarc-André Lureau }
131267f6646SMarc-André Lureau s = &g->parent_obj.scanout[pos->scanout_id];
132267f6646SMarc-André Lureau
133267f6646SMarc-André Lureau if (msg->request == VHOST_USER_GPU_CURSOR_UPDATE) {
134267f6646SMarc-André Lureau VhostUserGpuCursorUpdate *up = &msg->payload.cursor_update;
135267f6646SMarc-André Lureau if (!s->current_cursor) {
136267f6646SMarc-André Lureau s->current_cursor = cursor_alloc(64, 64);
137267f6646SMarc-André Lureau }
138267f6646SMarc-André Lureau
139267f6646SMarc-André Lureau s->current_cursor->hot_x = up->hot_x;
140267f6646SMarc-André Lureau s->current_cursor->hot_y = up->hot_y;
141267f6646SMarc-André Lureau
142267f6646SMarc-André Lureau memcpy(s->current_cursor->data, up->data,
143267f6646SMarc-André Lureau 64 * 64 * sizeof(uint32_t));
144267f6646SMarc-André Lureau
145267f6646SMarc-André Lureau dpy_cursor_define(s->con, s->current_cursor);
146267f6646SMarc-André Lureau }
147267f6646SMarc-André Lureau
148267f6646SMarc-André Lureau dpy_mouse_set(s->con, pos->x, pos->y,
149267f6646SMarc-André Lureau msg->request != VHOST_USER_GPU_CURSOR_POS_HIDE);
150267f6646SMarc-André Lureau }
151267f6646SMarc-André Lureau
152267f6646SMarc-André Lureau static void
vhost_user_gpu_send_msg(VhostUserGPU * g,const VhostUserGpuMsg * msg)153267f6646SMarc-André Lureau vhost_user_gpu_send_msg(VhostUserGPU *g, const VhostUserGpuMsg *msg)
154267f6646SMarc-André Lureau {
155267f6646SMarc-André Lureau qemu_chr_fe_write(&g->vhost_chr, (uint8_t *)msg,
156267f6646SMarc-André Lureau VHOST_USER_GPU_HDR_SIZE + msg->size);
157267f6646SMarc-André Lureau }
158267f6646SMarc-André Lureau
159267f6646SMarc-André Lureau static void
vhost_user_gpu_unblock(VhostUserGPU * g)160267f6646SMarc-André Lureau vhost_user_gpu_unblock(VhostUserGPU *g)
161267f6646SMarc-André Lureau {
162267f6646SMarc-André Lureau VhostUserGpuMsg msg = {
163267f6646SMarc-André Lureau .request = VHOST_USER_GPU_DMABUF_UPDATE,
164267f6646SMarc-André Lureau .flags = VHOST_USER_GPU_MSG_FLAG_REPLY,
165267f6646SMarc-André Lureau };
166267f6646SMarc-André Lureau
167267f6646SMarc-André Lureau vhost_user_gpu_send_msg(g, &msg);
168267f6646SMarc-André Lureau }
169267f6646SMarc-André Lureau
170267f6646SMarc-André Lureau static void
vhost_user_gpu_handle_display(VhostUserGPU * g,VhostUserGpuMsg * msg)171267f6646SMarc-André Lureau vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg)
172267f6646SMarc-André Lureau {
173267f6646SMarc-André Lureau QemuConsole *con = NULL;
174267f6646SMarc-André Lureau struct virtio_gpu_scanout *s;
175267f6646SMarc-André Lureau
176267f6646SMarc-André Lureau switch (msg->request) {
177267f6646SMarc-André Lureau case VHOST_USER_GPU_GET_PROTOCOL_FEATURES: {
178267f6646SMarc-André Lureau VhostUserGpuMsg reply = {
179267f6646SMarc-André Lureau .request = msg->request,
180267f6646SMarc-André Lureau .flags = VHOST_USER_GPU_MSG_FLAG_REPLY,
181267f6646SMarc-André Lureau .size = sizeof(uint64_t),
18231f137e3SErico Nunes .payload = {
183d824da9dSErico Nunes .u64 = (1 << VHOST_USER_GPU_PROTOCOL_F_EDID) |
184d824da9dSErico Nunes (1 << VHOST_USER_GPU_PROTOCOL_F_DMABUF2)
18531f137e3SErico Nunes }
186267f6646SMarc-André Lureau };
187267f6646SMarc-André Lureau
188267f6646SMarc-André Lureau vhost_user_gpu_send_msg(g, &reply);
189267f6646SMarc-André Lureau break;
190267f6646SMarc-André Lureau }
191267f6646SMarc-André Lureau case VHOST_USER_GPU_SET_PROTOCOL_FEATURES: {
192267f6646SMarc-André Lureau break;
193267f6646SMarc-André Lureau }
194267f6646SMarc-André Lureau case VHOST_USER_GPU_GET_DISPLAY_INFO: {
195267f6646SMarc-André Lureau struct virtio_gpu_resp_display_info display_info = { {} };
196267f6646SMarc-André Lureau VhostUserGpuMsg reply = {
197267f6646SMarc-André Lureau .request = msg->request,
198267f6646SMarc-André Lureau .flags = VHOST_USER_GPU_MSG_FLAG_REPLY,
199267f6646SMarc-André Lureau .size = sizeof(struct virtio_gpu_resp_display_info),
200267f6646SMarc-André Lureau };
201267f6646SMarc-André Lureau
202267f6646SMarc-André Lureau display_info.hdr.type = VIRTIO_GPU_RESP_OK_DISPLAY_INFO;
203267f6646SMarc-André Lureau virtio_gpu_base_fill_display_info(VIRTIO_GPU_BASE(g), &display_info);
204267f6646SMarc-André Lureau memcpy(&reply.payload.display_info, &display_info,
205267f6646SMarc-André Lureau sizeof(display_info));
206267f6646SMarc-André Lureau vhost_user_gpu_send_msg(g, &reply);
207267f6646SMarc-André Lureau break;
208267f6646SMarc-André Lureau }
20931f137e3SErico Nunes case VHOST_USER_GPU_GET_EDID: {
21031f137e3SErico Nunes VhostUserGpuEdidRequest *m = &msg->payload.edid_req;
21131f137e3SErico Nunes struct virtio_gpu_resp_edid resp = { {} };
21231f137e3SErico Nunes VhostUserGpuMsg reply = {
21331f137e3SErico Nunes .request = msg->request,
21431f137e3SErico Nunes .flags = VHOST_USER_GPU_MSG_FLAG_REPLY,
21531f137e3SErico Nunes .size = sizeof(reply.payload.resp_edid),
21631f137e3SErico Nunes };
21731f137e3SErico Nunes
21831f137e3SErico Nunes if (m->scanout_id >= g->parent_obj.conf.max_outputs) {
21931f137e3SErico Nunes error_report("invalid scanout: %d", m->scanout_id);
22031f137e3SErico Nunes break;
22131f137e3SErico Nunes }
22231f137e3SErico Nunes
22331f137e3SErico Nunes resp.hdr.type = VIRTIO_GPU_RESP_OK_EDID;
22431f137e3SErico Nunes virtio_gpu_base_generate_edid(VIRTIO_GPU_BASE(g), m->scanout_id, &resp);
22531f137e3SErico Nunes memcpy(&reply.payload.resp_edid, &resp, sizeof(resp));
22631f137e3SErico Nunes vhost_user_gpu_send_msg(g, &reply);
22731f137e3SErico Nunes break;
22831f137e3SErico Nunes }
229267f6646SMarc-André Lureau case VHOST_USER_GPU_SCANOUT: {
230267f6646SMarc-André Lureau VhostUserGpuScanout *m = &msg->payload.scanout;
231267f6646SMarc-André Lureau
232267f6646SMarc-André Lureau if (m->scanout_id >= g->parent_obj.conf.max_outputs) {
233267f6646SMarc-André Lureau return;
234267f6646SMarc-André Lureau }
235267f6646SMarc-André Lureau
236267f6646SMarc-André Lureau g->parent_obj.enable = 1;
237267f6646SMarc-André Lureau s = &g->parent_obj.scanout[m->scanout_id];
238267f6646SMarc-André Lureau con = s->con;
239267f6646SMarc-André Lureau
240ed8f3fe6SAkihiko Odaki if (m->width == 0) {
241ed8f3fe6SAkihiko Odaki dpy_gfx_replace_surface(con, NULL);
242267f6646SMarc-André Lureau } else {
243267f6646SMarc-André Lureau s->ds = qemu_create_displaysurface(m->width, m->height);
244267f6646SMarc-André Lureau /* replace surface on next update */
245267f6646SMarc-André Lureau }
246267f6646SMarc-André Lureau
247267f6646SMarc-André Lureau break;
248267f6646SMarc-André Lureau }
249d824da9dSErico Nunes case VHOST_USER_GPU_DMABUF_SCANOUT2:
250267f6646SMarc-André Lureau case VHOST_USER_GPU_DMABUF_SCANOUT: {
251267f6646SMarc-André Lureau VhostUserGpuDMABUFScanout *m = &msg->payload.dmabuf_scanout;
252267f6646SMarc-André Lureau int fd = qemu_chr_fe_get_msgfd(&g->vhost_chr);
253bb5101aaSQiang Yu uint32_t offset = 0;
254bb5101aaSQiang Yu uint32_t stride = m->fd_stride;
255ac705689SQiang Yu uint64_t modifier = DRM_FORMAT_MOD_INVALID;
256267f6646SMarc-André Lureau QemuDmaBuf *dmabuf;
257267f6646SMarc-André Lureau
258267f6646SMarc-André Lureau if (m->scanout_id >= g->parent_obj.conf.max_outputs) {
259267f6646SMarc-André Lureau error_report("invalid scanout: %d", m->scanout_id);
260267f6646SMarc-André Lureau if (fd >= 0) {
261267f6646SMarc-André Lureau close(fd);
262267f6646SMarc-André Lureau }
263267f6646SMarc-André Lureau break;
264267f6646SMarc-André Lureau }
265267f6646SMarc-André Lureau
266267f6646SMarc-André Lureau g->parent_obj.enable = 1;
267267f6646SMarc-André Lureau con = g->parent_obj.scanout[m->scanout_id].con;
268c0fcd633SDongwon Kim dmabuf = g->dmabuf[m->scanout_id];
269c0fcd633SDongwon Kim
270c0fcd633SDongwon Kim if (dmabuf) {
2716779a307SDongwon Kim qemu_dmabuf_close(dmabuf);
272267f6646SMarc-André Lureau dpy_gl_release_dmabuf(con, dmabuf);
273c0fcd633SDongwon Kim g_clear_pointer(&dmabuf, qemu_dmabuf_free);
274d824da9dSErico Nunes }
275d824da9dSErico Nunes
276c0fcd633SDongwon Kim if (fd == -1) {
277c0fcd633SDongwon Kim dpy_gl_scanout_disable(con);
278c0fcd633SDongwon Kim g->dmabuf[m->scanout_id] = NULL;
279c0fcd633SDongwon Kim break;
280c0fcd633SDongwon Kim }
281c0fcd633SDongwon Kim
282c0fcd633SDongwon Kim if (msg->request == VHOST_USER_GPU_DMABUF_SCANOUT2) {
283c0fcd633SDongwon Kim VhostUserGpuDMABUFScanout2 *m2 = &msg->payload.dmabuf_scanout2;
284c0fcd633SDongwon Kim modifier = m2->modifier;
285c0fcd633SDongwon Kim }
286c0fcd633SDongwon Kim
28780c8a26dSMarc-André Lureau dmabuf = qemu_dmabuf_new(m->width, m->height,
288bb5101aaSQiang Yu &offset, &stride, 0, 0,
28980c8a26dSMarc-André Lureau m->fd_width, m->fd_height,
290c0fcd633SDongwon Kim m->fd_drm_fourcc, modifier,
291bb5101aaSQiang Yu &fd, 1, false, m->fd_flags &
292c0fcd633SDongwon Kim VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP);
293c0fcd633SDongwon Kim
294267f6646SMarc-André Lureau dpy_gl_scanout_dmabuf(con, dmabuf);
295c0fcd633SDongwon Kim g->dmabuf[m->scanout_id] = dmabuf;
296267f6646SMarc-André Lureau break;
297267f6646SMarc-André Lureau }
298267f6646SMarc-André Lureau case VHOST_USER_GPU_DMABUF_UPDATE: {
299267f6646SMarc-André Lureau VhostUserGpuUpdate *m = &msg->payload.update;
300267f6646SMarc-André Lureau
301267f6646SMarc-André Lureau if (m->scanout_id >= g->parent_obj.conf.max_outputs ||
302267f6646SMarc-André Lureau !g->parent_obj.scanout[m->scanout_id].con) {
303267f6646SMarc-André Lureau error_report("invalid scanout update: %d", m->scanout_id);
304267f6646SMarc-André Lureau vhost_user_gpu_unblock(g);
305267f6646SMarc-André Lureau break;
306267f6646SMarc-André Lureau }
307267f6646SMarc-André Lureau
308267f6646SMarc-André Lureau con = g->parent_obj.scanout[m->scanout_id].con;
309267f6646SMarc-André Lureau if (!console_has_gl(con)) {
310267f6646SMarc-André Lureau error_report("console doesn't support GL!");
311267f6646SMarc-André Lureau vhost_user_gpu_unblock(g);
312267f6646SMarc-André Lureau break;
313267f6646SMarc-André Lureau }
314267f6646SMarc-André Lureau g->backend_blocked = true;
315f6413cbfSMarc-André Lureau dpy_gl_update(con, m->x, m->y, m->width, m->height);
316267f6646SMarc-André Lureau break;
317267f6646SMarc-André Lureau }
31868fd1670SMarc-André Lureau #ifdef CONFIG_PIXMAN
319267f6646SMarc-André Lureau case VHOST_USER_GPU_UPDATE: {
320267f6646SMarc-André Lureau VhostUserGpuUpdate *m = &msg->payload.update;
321267f6646SMarc-André Lureau
322267f6646SMarc-André Lureau if (m->scanout_id >= g->parent_obj.conf.max_outputs) {
323267f6646SMarc-André Lureau break;
324267f6646SMarc-André Lureau }
325267f6646SMarc-André Lureau s = &g->parent_obj.scanout[m->scanout_id];
326267f6646SMarc-André Lureau con = s->con;
327267f6646SMarc-André Lureau pixman_image_t *image =
328267f6646SMarc-André Lureau pixman_image_create_bits(PIXMAN_x8r8g8b8,
329267f6646SMarc-André Lureau m->width,
330267f6646SMarc-André Lureau m->height,
331267f6646SMarc-André Lureau (uint32_t *)m->data,
332267f6646SMarc-André Lureau m->width * 4);
333267f6646SMarc-André Lureau
334267f6646SMarc-André Lureau pixman_image_composite(PIXMAN_OP_SRC,
335267f6646SMarc-André Lureau image, NULL, s->ds->image,
336267f6646SMarc-André Lureau 0, 0, 0, 0, m->x, m->y, m->width, m->height);
337267f6646SMarc-André Lureau
338267f6646SMarc-André Lureau pixman_image_unref(image);
339267f6646SMarc-André Lureau if (qemu_console_surface(con) != s->ds) {
340267f6646SMarc-André Lureau dpy_gfx_replace_surface(con, s->ds);
341267f6646SMarc-André Lureau } else {
342267f6646SMarc-André Lureau dpy_gfx_update(con, m->x, m->y, m->width, m->height);
343267f6646SMarc-André Lureau }
344267f6646SMarc-André Lureau break;
345267f6646SMarc-André Lureau }
34668fd1670SMarc-André Lureau #endif
347267f6646SMarc-André Lureau default:
348267f6646SMarc-André Lureau g_warning("unhandled message %d %d", msg->request, msg->size);
349267f6646SMarc-André Lureau }
350267f6646SMarc-André Lureau
351267f6646SMarc-André Lureau if (con && qemu_console_is_gl_blocked(con)) {
352267f6646SMarc-André Lureau vhost_user_gpu_update_blocked(g, true);
353267f6646SMarc-André Lureau }
354267f6646SMarc-André Lureau }
355267f6646SMarc-André Lureau
356267f6646SMarc-André Lureau static void
vhost_user_gpu_chr_read(void * opaque)357267f6646SMarc-André Lureau vhost_user_gpu_chr_read(void *opaque)
358267f6646SMarc-André Lureau {
359267f6646SMarc-André Lureau VhostUserGPU *g = opaque;
360267f6646SMarc-André Lureau VhostUserGpuMsg *msg = NULL;
361267f6646SMarc-André Lureau VhostUserGpuRequest request;
362267f6646SMarc-André Lureau uint32_t size, flags;
363267f6646SMarc-André Lureau int r;
364267f6646SMarc-André Lureau
365267f6646SMarc-André Lureau r = qemu_chr_fe_read_all(&g->vhost_chr,
366267f6646SMarc-André Lureau (uint8_t *)&request, sizeof(uint32_t));
367267f6646SMarc-André Lureau if (r != sizeof(uint32_t)) {
368267f6646SMarc-André Lureau error_report("failed to read msg header: %d, %d", r, errno);
369267f6646SMarc-André Lureau goto end;
370267f6646SMarc-André Lureau }
371267f6646SMarc-André Lureau
372267f6646SMarc-André Lureau r = qemu_chr_fe_read_all(&g->vhost_chr,
373267f6646SMarc-André Lureau (uint8_t *)&flags, sizeof(uint32_t));
374267f6646SMarc-André Lureau if (r != sizeof(uint32_t)) {
375267f6646SMarc-André Lureau error_report("failed to read msg flags");
376267f6646SMarc-André Lureau goto end;
377267f6646SMarc-André Lureau }
378267f6646SMarc-André Lureau
379267f6646SMarc-André Lureau r = qemu_chr_fe_read_all(&g->vhost_chr,
380267f6646SMarc-André Lureau (uint8_t *)&size, sizeof(uint32_t));
381267f6646SMarc-André Lureau if (r != sizeof(uint32_t)) {
382267f6646SMarc-André Lureau error_report("failed to read msg size");
383267f6646SMarc-André Lureau goto end;
384267f6646SMarc-André Lureau }
385267f6646SMarc-André Lureau
386267f6646SMarc-André Lureau msg = g_malloc(VHOST_USER_GPU_HDR_SIZE + size);
387267f6646SMarc-André Lureau
388267f6646SMarc-André Lureau r = qemu_chr_fe_read_all(&g->vhost_chr,
389267f6646SMarc-André Lureau (uint8_t *)&msg->payload, size);
390267f6646SMarc-André Lureau if (r != size) {
391267f6646SMarc-André Lureau error_report("failed to read msg payload %d != %d", r, size);
392267f6646SMarc-André Lureau goto end;
393267f6646SMarc-André Lureau }
394267f6646SMarc-André Lureau
395267f6646SMarc-André Lureau msg->request = request;
396d6192f3fSHaoran Zhang msg->flags = flags;
397267f6646SMarc-André Lureau msg->size = size;
398267f6646SMarc-André Lureau
399267f6646SMarc-André Lureau if (request == VHOST_USER_GPU_CURSOR_UPDATE ||
400267f6646SMarc-André Lureau request == VHOST_USER_GPU_CURSOR_POS ||
401267f6646SMarc-André Lureau request == VHOST_USER_GPU_CURSOR_POS_HIDE) {
402267f6646SMarc-André Lureau vhost_user_gpu_handle_cursor(g, msg);
403267f6646SMarc-André Lureau } else {
404267f6646SMarc-André Lureau vhost_user_gpu_handle_display(g, msg);
405267f6646SMarc-André Lureau }
406267f6646SMarc-André Lureau
407267f6646SMarc-André Lureau end:
408267f6646SMarc-André Lureau g_free(msg);
409267f6646SMarc-André Lureau }
410267f6646SMarc-André Lureau
411267f6646SMarc-André Lureau static void
vhost_user_gpu_update_blocked(VhostUserGPU * g,bool blocked)412267f6646SMarc-André Lureau vhost_user_gpu_update_blocked(VhostUserGPU *g, bool blocked)
413267f6646SMarc-André Lureau {
414267f6646SMarc-André Lureau qemu_set_fd_handler(g->vhost_gpu_fd,
415267f6646SMarc-André Lureau blocked ? NULL : vhost_user_gpu_chr_read, NULL, g);
416267f6646SMarc-André Lureau }
417267f6646SMarc-André Lureau
418267f6646SMarc-André Lureau static void
vhost_user_gpu_gl_flushed(VirtIOGPUBase * b)4193cddb8b9SMarc-André Lureau vhost_user_gpu_gl_flushed(VirtIOGPUBase *b)
420267f6646SMarc-André Lureau {
421267f6646SMarc-André Lureau VhostUserGPU *g = VHOST_USER_GPU(b);
422267f6646SMarc-André Lureau
423267f6646SMarc-André Lureau if (g->backend_blocked) {
4247d5b0d68SPhilippe Mathieu-Daudé vhost_user_gpu_unblock(g);
425267f6646SMarc-André Lureau g->backend_blocked = false;
426267f6646SMarc-André Lureau }
427267f6646SMarc-André Lureau
4287d5b0d68SPhilippe Mathieu-Daudé vhost_user_gpu_update_blocked(g, false);
429267f6646SMarc-André Lureau }
430267f6646SMarc-André Lureau
431267f6646SMarc-André Lureau static bool
vhost_user_gpu_do_set_socket(VhostUserGPU * g,Error ** errp)432267f6646SMarc-André Lureau vhost_user_gpu_do_set_socket(VhostUserGPU *g, Error **errp)
433267f6646SMarc-André Lureau {
434267f6646SMarc-André Lureau Chardev *chr;
435267f6646SMarc-André Lureau int sv[2];
436267f6646SMarc-André Lureau
4379cbda7b3SGuoyi Tu if (qemu_socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
438267f6646SMarc-André Lureau error_setg_errno(errp, errno, "socketpair() failed");
439267f6646SMarc-André Lureau return false;
440267f6646SMarc-André Lureau }
441267f6646SMarc-André Lureau
442267f6646SMarc-André Lureau chr = CHARDEV(object_new(TYPE_CHARDEV_SOCKET));
443267f6646SMarc-André Lureau if (!chr || qemu_chr_add_client(chr, sv[0]) == -1) {
444267f6646SMarc-André Lureau error_setg(errp, "Failed to make socket chardev");
445267f6646SMarc-André Lureau goto err;
446267f6646SMarc-André Lureau }
447267f6646SMarc-André Lureau if (!qemu_chr_fe_init(&g->vhost_chr, chr, errp)) {
448267f6646SMarc-André Lureau goto err;
449267f6646SMarc-André Lureau }
450267f6646SMarc-André Lureau if (vhost_user_gpu_set_socket(&g->vhost->dev, sv[1]) < 0) {
451267f6646SMarc-André Lureau error_setg(errp, "Failed to set vhost-user-gpu socket");
452267f6646SMarc-André Lureau qemu_chr_fe_deinit(&g->vhost_chr, false);
453267f6646SMarc-André Lureau goto err;
454267f6646SMarc-André Lureau }
455267f6646SMarc-André Lureau
456267f6646SMarc-André Lureau g->vhost_gpu_fd = sv[0];
457267f6646SMarc-André Lureau vhost_user_gpu_update_blocked(g, false);
458267f6646SMarc-André Lureau close(sv[1]);
459267f6646SMarc-André Lureau return true;
460267f6646SMarc-André Lureau
461267f6646SMarc-André Lureau err:
462267f6646SMarc-André Lureau close(sv[0]);
463267f6646SMarc-André Lureau close(sv[1]);
464267f6646SMarc-André Lureau if (chr) {
465267f6646SMarc-André Lureau object_unref(OBJECT(chr));
466267f6646SMarc-André Lureau }
467267f6646SMarc-André Lureau return false;
468267f6646SMarc-André Lureau }
469267f6646SMarc-André Lureau
470267f6646SMarc-André Lureau static void
vhost_user_gpu_get_config(VirtIODevice * vdev,uint8_t * config_data)471267f6646SMarc-André Lureau vhost_user_gpu_get_config(VirtIODevice *vdev, uint8_t *config_data)
472267f6646SMarc-André Lureau {
473267f6646SMarc-André Lureau VhostUserGPU *g = VHOST_USER_GPU(vdev);
474267f6646SMarc-André Lureau VirtIOGPUBase *b = VIRTIO_GPU_BASE(vdev);
475267f6646SMarc-André Lureau struct virtio_gpu_config *vgconfig =
476267f6646SMarc-André Lureau (struct virtio_gpu_config *)config_data;
47750de5138SKevin Wolf Error *local_err = NULL;
478267f6646SMarc-André Lureau int ret;
479267f6646SMarc-André Lureau
480267f6646SMarc-André Lureau memset(config_data, 0, sizeof(struct virtio_gpu_config));
481267f6646SMarc-André Lureau
482267f6646SMarc-André Lureau ret = vhost_dev_get_config(&g->vhost->dev,
48350de5138SKevin Wolf config_data, sizeof(struct virtio_gpu_config),
48450de5138SKevin Wolf &local_err);
485267f6646SMarc-André Lureau if (ret) {
48650de5138SKevin Wolf error_report_err(local_err);
487267f6646SMarc-André Lureau return;
488267f6646SMarc-André Lureau }
489267f6646SMarc-André Lureau
490267f6646SMarc-André Lureau /* those fields are managed by qemu */
491267f6646SMarc-André Lureau vgconfig->num_scanouts = b->virtio_config.num_scanouts;
492267f6646SMarc-André Lureau vgconfig->events_read = b->virtio_config.events_read;
493267f6646SMarc-André Lureau vgconfig->events_clear = b->virtio_config.events_clear;
494267f6646SMarc-André Lureau }
495267f6646SMarc-André Lureau
496267f6646SMarc-André Lureau static void
vhost_user_gpu_set_config(VirtIODevice * vdev,const uint8_t * config_data)497267f6646SMarc-André Lureau vhost_user_gpu_set_config(VirtIODevice *vdev,
498267f6646SMarc-André Lureau const uint8_t *config_data)
499267f6646SMarc-André Lureau {
500267f6646SMarc-André Lureau VhostUserGPU *g = VHOST_USER_GPU(vdev);
501267f6646SMarc-André Lureau VirtIOGPUBase *b = VIRTIO_GPU_BASE(vdev);
502267f6646SMarc-André Lureau const struct virtio_gpu_config *vgconfig =
503267f6646SMarc-André Lureau (const struct virtio_gpu_config *)config_data;
504267f6646SMarc-André Lureau int ret;
505267f6646SMarc-André Lureau
506267f6646SMarc-André Lureau if (vgconfig->events_clear) {
507267f6646SMarc-André Lureau b->virtio_config.events_read &= ~vgconfig->events_clear;
508267f6646SMarc-André Lureau }
509267f6646SMarc-André Lureau
510267f6646SMarc-André Lureau ret = vhost_dev_set_config(&g->vhost->dev, config_data,
511267f6646SMarc-André Lureau 0, sizeof(struct virtio_gpu_config),
512f8ed3648SManos Pitsidianakis VHOST_SET_CONFIG_TYPE_FRONTEND);
513267f6646SMarc-André Lureau if (ret) {
514267f6646SMarc-André Lureau error_report("vhost-user-gpu: set device config space failed");
515267f6646SMarc-André Lureau return;
516267f6646SMarc-André Lureau }
517267f6646SMarc-André Lureau }
518267f6646SMarc-André Lureau
519*bc85aae4SHaoqian He static int
vhost_user_gpu_set_status(VirtIODevice * vdev,uint8_t val)520267f6646SMarc-André Lureau vhost_user_gpu_set_status(VirtIODevice *vdev, uint8_t val)
521267f6646SMarc-André Lureau {
522267f6646SMarc-André Lureau VhostUserGPU *g = VHOST_USER_GPU(vdev);
523267f6646SMarc-André Lureau Error *err = NULL;
524267f6646SMarc-André Lureau
525267f6646SMarc-André Lureau if (val & VIRTIO_CONFIG_S_DRIVER_OK && vdev->vm_running) {
526267f6646SMarc-André Lureau if (!vhost_user_gpu_do_set_socket(g, &err)) {
527267f6646SMarc-André Lureau error_report_err(err);
528*bc85aae4SHaoqian He return 0;
529267f6646SMarc-André Lureau }
530267f6646SMarc-André Lureau vhost_user_backend_start(g->vhost);
531267f6646SMarc-André Lureau } else {
532*bc85aae4SHaoqian He int ret;
533*bc85aae4SHaoqian He
534267f6646SMarc-André Lureau /* unblock any wait and stop processing */
535267f6646SMarc-André Lureau if (g->vhost_gpu_fd != -1) {
536267f6646SMarc-André Lureau vhost_user_gpu_update_blocked(g, true);
537267f6646SMarc-André Lureau qemu_chr_fe_deinit(&g->vhost_chr, true);
538267f6646SMarc-André Lureau g->vhost_gpu_fd = -1;
539267f6646SMarc-André Lureau }
540*bc85aae4SHaoqian He ret = vhost_user_backend_stop(g->vhost);
541*bc85aae4SHaoqian He if (ret < 0) {
542*bc85aae4SHaoqian He return ret;
543267f6646SMarc-André Lureau }
544267f6646SMarc-André Lureau }
545*bc85aae4SHaoqian He return 0;
546*bc85aae4SHaoqian He }
547267f6646SMarc-André Lureau
548267f6646SMarc-André Lureau static bool
vhost_user_gpu_guest_notifier_pending(VirtIODevice * vdev,int idx)549267f6646SMarc-André Lureau vhost_user_gpu_guest_notifier_pending(VirtIODevice *vdev, int idx)
550267f6646SMarc-André Lureau {
551267f6646SMarc-André Lureau VhostUserGPU *g = VHOST_USER_GPU(vdev);
552267f6646SMarc-André Lureau
553544f0278SCindy Lu /*
554544f0278SCindy Lu * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1
5557e8094f0SAlex Bennée * as the macro of configure interrupt's IDX, If this driver does not
556544f0278SCindy Lu * support, the function will return
557544f0278SCindy Lu */
558544f0278SCindy Lu
559544f0278SCindy Lu if (idx == VIRTIO_CONFIG_IRQ_IDX) {
560544f0278SCindy Lu return false;
561544f0278SCindy Lu }
562267f6646SMarc-André Lureau return vhost_virtqueue_pending(&g->vhost->dev, idx);
563267f6646SMarc-André Lureau }
564267f6646SMarc-André Lureau
565267f6646SMarc-André Lureau static void
vhost_user_gpu_guest_notifier_mask(VirtIODevice * vdev,int idx,bool mask)566267f6646SMarc-André Lureau vhost_user_gpu_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask)
567267f6646SMarc-André Lureau {
568267f6646SMarc-André Lureau VhostUserGPU *g = VHOST_USER_GPU(vdev);
569267f6646SMarc-André Lureau
570544f0278SCindy Lu /*
571544f0278SCindy Lu * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1
5727e8094f0SAlex Bennée * as the macro of configure interrupt's IDX, If this driver does not
573544f0278SCindy Lu * support, the function will return
574544f0278SCindy Lu */
575544f0278SCindy Lu
576544f0278SCindy Lu if (idx == VIRTIO_CONFIG_IRQ_IDX) {
577544f0278SCindy Lu return;
578544f0278SCindy Lu }
579267f6646SMarc-André Lureau vhost_virtqueue_mask(&g->vhost->dev, vdev, idx, mask);
580267f6646SMarc-André Lureau }
581267f6646SMarc-André Lureau
582267f6646SMarc-André Lureau static void
vhost_user_gpu_instance_init(Object * obj)583267f6646SMarc-André Lureau vhost_user_gpu_instance_init(Object *obj)
584267f6646SMarc-André Lureau {
585267f6646SMarc-André Lureau VhostUserGPU *g = VHOST_USER_GPU(obj);
586267f6646SMarc-André Lureau
587267f6646SMarc-André Lureau g->vhost = VHOST_USER_BACKEND(object_new(TYPE_VHOST_USER_BACKEND));
588267f6646SMarc-André Lureau object_property_add_alias(obj, "chardev",
589d2623129SMarkus Armbruster OBJECT(g->vhost), "chardev");
590267f6646SMarc-André Lureau }
591267f6646SMarc-André Lureau
592267f6646SMarc-André Lureau static void
vhost_user_gpu_instance_finalize(Object * obj)593267f6646SMarc-André Lureau vhost_user_gpu_instance_finalize(Object *obj)
594267f6646SMarc-André Lureau {
595267f6646SMarc-André Lureau VhostUserGPU *g = VHOST_USER_GPU(obj);
596267f6646SMarc-André Lureau
597267f6646SMarc-André Lureau object_unref(OBJECT(g->vhost));
598267f6646SMarc-André Lureau }
599267f6646SMarc-André Lureau
600267f6646SMarc-André Lureau static void
vhost_user_gpu_reset(VirtIODevice * vdev)601267f6646SMarc-André Lureau vhost_user_gpu_reset(VirtIODevice *vdev)
602267f6646SMarc-André Lureau {
603267f6646SMarc-André Lureau VhostUserGPU *g = VHOST_USER_GPU(vdev);
604267f6646SMarc-André Lureau
605267f6646SMarc-André Lureau virtio_gpu_base_reset(VIRTIO_GPU_BASE(vdev));
606267f6646SMarc-André Lureau
607267f6646SMarc-André Lureau vhost_user_backend_stop(g->vhost);
608267f6646SMarc-André Lureau }
609267f6646SMarc-André Lureau
610267f6646SMarc-André Lureau static int
vhost_user_gpu_config_change(struct vhost_dev * dev)611267f6646SMarc-André Lureau vhost_user_gpu_config_change(struct vhost_dev *dev)
612267f6646SMarc-André Lureau {
613267f6646SMarc-André Lureau error_report("vhost-user-gpu: unhandled backend config change");
614267f6646SMarc-André Lureau return -1;
615267f6646SMarc-André Lureau }
616267f6646SMarc-André Lureau
617267f6646SMarc-André Lureau static const VhostDevConfigOps config_ops = {
618267f6646SMarc-André Lureau .vhost_dev_config_notifier = vhost_user_gpu_config_change,
619267f6646SMarc-André Lureau };
620267f6646SMarc-André Lureau
621267f6646SMarc-André Lureau static void
vhost_user_gpu_device_realize(DeviceState * qdev,Error ** errp)622267f6646SMarc-André Lureau vhost_user_gpu_device_realize(DeviceState *qdev, Error **errp)
623267f6646SMarc-André Lureau {
624267f6646SMarc-André Lureau VhostUserGPU *g = VHOST_USER_GPU(qdev);
625267f6646SMarc-André Lureau VirtIODevice *vdev = VIRTIO_DEVICE(g);
626267f6646SMarc-André Lureau
627267f6646SMarc-André Lureau vhost_dev_set_config_notifier(&g->vhost->dev, &config_ops);
628267f6646SMarc-André Lureau if (vhost_user_backend_dev_init(g->vhost, vdev, 2, errp) < 0) {
629267f6646SMarc-André Lureau return;
630267f6646SMarc-André Lureau }
631267f6646SMarc-André Lureau
632ff64d44fSMarc-André Lureau /* existing backend may send DMABUF, so let's add that requirement */
633ff64d44fSMarc-André Lureau g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_DMABUF_ENABLED;
634267f6646SMarc-André Lureau if (virtio_has_feature(g->vhost->dev.features, VIRTIO_GPU_F_VIRGL)) {
635267f6646SMarc-André Lureau g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED;
636267f6646SMarc-André Lureau }
637326a51f3SMarc-André Lureau if (virtio_has_feature(g->vhost->dev.features, VIRTIO_GPU_F_EDID)) {
638326a51f3SMarc-André Lureau g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_EDID_ENABLED;
639326a51f3SMarc-André Lureau } else {
640326a51f3SMarc-André Lureau error_report("EDID requested but the backend doesn't support it.");
641326a51f3SMarc-André Lureau g->parent_obj.conf.flags &= ~(1 << VIRTIO_GPU_FLAG_EDID_ENABLED);
642326a51f3SMarc-André Lureau }
6431e77a4a3SDorinda Bassey if (virtio_has_feature(g->vhost->dev.features,
6441e77a4a3SDorinda Bassey VIRTIO_GPU_F_RESOURCE_UUID)) {
6451e77a4a3SDorinda Bassey g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_RESOURCE_UUID_ENABLED;
6461e77a4a3SDorinda Bassey }
6471e77a4a3SDorinda Bassey if (virtio_has_feature(g->vhost->dev.features,
6481e77a4a3SDorinda Bassey VIRTIO_GPU_F_RESOURCE_UUID)) {
6491e77a4a3SDorinda Bassey g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_RESOURCE_UUID_ENABLED;
6501e77a4a3SDorinda Bassey }
651267f6646SMarc-André Lureau
652267f6646SMarc-André Lureau if (!virtio_gpu_base_device_realize(qdev, NULL, NULL, errp)) {
653267f6646SMarc-André Lureau return;
654267f6646SMarc-André Lureau }
655267f6646SMarc-André Lureau
656267f6646SMarc-André Lureau g->vhost_gpu_fd = -1;
657267f6646SMarc-André Lureau }
658267f6646SMarc-André Lureau
vhost_user_gpu_get_vhost(VirtIODevice * vdev)659c255488dSJonah Palmer static struct vhost_dev *vhost_user_gpu_get_vhost(VirtIODevice *vdev)
660c255488dSJonah Palmer {
661c255488dSJonah Palmer VhostUserGPU *g = VHOST_USER_GPU(vdev);
66200adced5SHanna Czenczek return g->vhost ? &g->vhost->dev : NULL;
663c255488dSJonah Palmer }
664c255488dSJonah Palmer
665d432edd5SRichard Henderson static const Property vhost_user_gpu_properties[] = {
666267f6646SMarc-André Lureau VIRTIO_GPU_BASE_PROPERTIES(VhostUserGPU, parent_obj.conf),
667267f6646SMarc-André Lureau };
668267f6646SMarc-André Lureau
669267f6646SMarc-André Lureau static void
vhost_user_gpu_class_init(ObjectClass * klass,const void * data)67012d1a768SPhilippe Mathieu-Daudé vhost_user_gpu_class_init(ObjectClass *klass, const void *data)
671267f6646SMarc-André Lureau {
672267f6646SMarc-André Lureau DeviceClass *dc = DEVICE_CLASS(klass);
673267f6646SMarc-André Lureau VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
674267f6646SMarc-André Lureau VirtIOGPUBaseClass *vgc = VIRTIO_GPU_BASE_CLASS(klass);
675267f6646SMarc-André Lureau
6763cddb8b9SMarc-André Lureau vgc->gl_flushed = vhost_user_gpu_gl_flushed;
677267f6646SMarc-André Lureau
678267f6646SMarc-André Lureau vdc->realize = vhost_user_gpu_device_realize;
679267f6646SMarc-André Lureau vdc->reset = vhost_user_gpu_reset;
680267f6646SMarc-André Lureau vdc->set_status = vhost_user_gpu_set_status;
681267f6646SMarc-André Lureau vdc->guest_notifier_mask = vhost_user_gpu_guest_notifier_mask;
682267f6646SMarc-André Lureau vdc->guest_notifier_pending = vhost_user_gpu_guest_notifier_pending;
683267f6646SMarc-André Lureau vdc->get_config = vhost_user_gpu_get_config;
684267f6646SMarc-André Lureau vdc->set_config = vhost_user_gpu_set_config;
685c255488dSJonah Palmer vdc->get_vhost = vhost_user_gpu_get_vhost;
686267f6646SMarc-André Lureau
6874f67d30bSMarc-André Lureau device_class_set_props(dc, vhost_user_gpu_properties);
688267f6646SMarc-André Lureau }
689267f6646SMarc-André Lureau
690267f6646SMarc-André Lureau static const TypeInfo vhost_user_gpu_info = {
691267f6646SMarc-André Lureau .name = TYPE_VHOST_USER_GPU,
692267f6646SMarc-André Lureau .parent = TYPE_VIRTIO_GPU_BASE,
693267f6646SMarc-André Lureau .instance_size = sizeof(VhostUserGPU),
694267f6646SMarc-André Lureau .instance_init = vhost_user_gpu_instance_init,
695267f6646SMarc-André Lureau .instance_finalize = vhost_user_gpu_instance_finalize,
696267f6646SMarc-André Lureau .class_init = vhost_user_gpu_class_init,
697267f6646SMarc-André Lureau };
698561d0f45SGerd Hoffmann module_obj(TYPE_VHOST_USER_GPU);
69924ce7aa7SJose R. Ziviani module_kconfig(VHOST_USER_GPU);
700267f6646SMarc-André Lureau
vhost_user_gpu_register_types(void)701267f6646SMarc-André Lureau static void vhost_user_gpu_register_types(void)
702267f6646SMarc-André Lureau {
703267f6646SMarc-André Lureau type_register_static(&vhost_user_gpu_info);
704267f6646SMarc-André Lureau }
705267f6646SMarc-André Lureau
706267f6646SMarc-André Lureau type_init(vhost_user_gpu_register_types)
707