xref: /freebsd/sys/dev/virtio/gpu/virtio_gpu.c (revision dd51cef58311ee0024be99116238d1c0032bdf2b)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2013, Bryan Venteicher <bryanv@FreeBSD.org>
5  * All rights reserved.
6  * Copyright (c) 2023, Arm Ltd
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice unmodified, this list of conditions, and the following
13  *    disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /* Driver for VirtIO GPU device. */
31 
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/bus.h>
35 #include <sys/callout.h>
36 #include <sys/fbio.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 #include <sys/module.h>
40 #include <sys/sglist.h>
41 
42 #include <machine/atomic.h>
43 #include <machine/bus.h>
44 #include <machine/resource.h>
45 
46 #include <vm/vm.h>
47 #include <vm/pmap.h>
48 
49 #include <dev/virtio/virtio.h>
50 #include <dev/virtio/virtqueue.h>
51 #include <dev/virtio/gpu/virtio_gpu.h>
52 
53 #include <dev/vt/vt.h>
54 #include <dev/vt/hw/fb/vt_fb.h>
55 #include <dev/vt/colors/vt_termcolors.h>
56 
57 #include "fb_if.h"
58 
59 #define VTGPU_FEATURES	0
60 
61 /* The guest can allocate resource IDs, we only need one */
62 #define	VTGPU_RESOURCE_ID	1
63 
64 #if _BYTE_ORDER == _BIG_ENDIAN
65 #define	VTGPU_FORMAT		VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM
66 #else
67 #define	VTGPU_FORMAT		VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM
68 #endif
69 
70 struct vtgpu_softc {
71 	/* Must be first so we can cast from info -> softc */
72 	struct fb_info 		 vtgpu_fb_info;
73 	struct virtio_gpu_config vtgpu_gpucfg;
74 
75 	device_t		 vtgpu_dev;
76 	uint64_t		 vtgpu_features;
77 
78 	struct virtqueue	*vtgpu_ctrl_vq;
79 
80 	uint64_t		 vtgpu_next_fence;
81 
82 	bool			 vtgpu_have_fb_info;
83 };
84 
85 static int	vtgpu_modevent(module_t, int, void *);
86 
87 static int	vtgpu_probe(device_t);
88 static int	vtgpu_attach(device_t);
89 static int	vtgpu_detach(device_t);
90 
91 static int	vtgpu_negotiate_features(struct vtgpu_softc *);
92 static int	vtgpu_setup_features(struct vtgpu_softc *);
93 static void	vtgpu_read_config(struct vtgpu_softc *,
94 		    struct virtio_gpu_config *);
95 static int	vtgpu_alloc_virtqueue(struct vtgpu_softc *);
96 static int	vtgpu_get_display_info(struct vtgpu_softc *);
97 static int	vtgpu_create_2d(struct vtgpu_softc *);
98 static int	vtgpu_attach_backing(struct vtgpu_softc *);
99 static int	vtgpu_set_scanout(struct vtgpu_softc *, uint32_t, uint32_t,
100 		    uint32_t, uint32_t);
101 static int	vtgpu_transfer_to_host_2d(struct vtgpu_softc *, uint32_t,
102 		    uint32_t, uint32_t, uint32_t);
103 static int	vtgpu_resource_flush(struct vtgpu_softc *, uint32_t, uint32_t,
104 		    uint32_t, uint32_t);
105 
106 static vd_blank_t		vtgpu_fb_blank;
107 static vd_bitblt_text_t		vtgpu_fb_bitblt_text;
108 static vd_bitblt_bmp_t		vtgpu_fb_bitblt_bitmap;
109 static vd_drawrect_t		vtgpu_fb_drawrect;
110 static vd_setpixel_t		vtgpu_fb_setpixel;
111 static vd_bitblt_argb_t		vtgpu_fb_bitblt_argb;
112 
113 static struct vt_driver vtgpu_fb_driver = {
114 	.vd_name = "virtio_gpu",
115 	.vd_init = vt_fb_init,
116 	.vd_fini = vt_fb_fini,
117 	.vd_blank = vtgpu_fb_blank,
118 	.vd_bitblt_text = vtgpu_fb_bitblt_text,
119 	.vd_invalidate_text = vt_fb_invalidate_text,
120 	.vd_bitblt_bmp = vtgpu_fb_bitblt_bitmap,
121 	.vd_bitblt_argb = vtgpu_fb_bitblt_argb,
122 	.vd_drawrect = vtgpu_fb_drawrect,
123 	.vd_setpixel = vtgpu_fb_setpixel,
124 	.vd_postswitch = vt_fb_postswitch,
125 	.vd_priority = VD_PRIORITY_GENERIC+10,
126 	.vd_fb_ioctl = vt_fb_ioctl,
127 	.vd_fb_mmap = NULL,	/* No mmap as we need to signal the host */
128 	.vd_suspend = vt_fb_suspend,
129 	.vd_resume = vt_fb_resume,
130 };
131 
132 VT_DRIVER_DECLARE(vt_vtgpu, vtgpu_fb_driver);
133 
134 static void
135 vtgpu_fb_blank(struct vt_device *vd, term_color_t color)
136 {
137 	struct vtgpu_softc *sc;
138 	struct fb_info *info;
139 
140 	info = vd->vd_softc;
141 	sc = (struct vtgpu_softc *)info;
142 
143 	vt_fb_blank(vd, color);
144 
145 	vtgpu_transfer_to_host_2d(sc, 0, 0, sc->vtgpu_fb_info.fb_width,
146 	    sc->vtgpu_fb_info.fb_height);
147 	vtgpu_resource_flush(sc, 0, 0, sc->vtgpu_fb_info.fb_width,
148 	    sc->vtgpu_fb_info.fb_height);
149 }
150 
151 static void
152 vtgpu_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
153     const term_rect_t *area)
154 {
155 	struct vtgpu_softc *sc;
156 	struct fb_info *info;
157 	int x, y, width, height;
158 
159 	info = vd->vd_softc;
160 	sc = (struct vtgpu_softc *)info;
161 
162 	vt_fb_bitblt_text(vd, vw, area);
163 
164 	x = area->tr_begin.tp_col * vw->vw_font->vf_width + vw->vw_draw_area.tr_begin.tp_col;
165 	y = area->tr_begin.tp_row * vw->vw_font->vf_height + vw->vw_draw_area.tr_begin.tp_row;
166 	width = area->tr_end.tp_col * vw->vw_font->vf_width + vw->vw_draw_area.tr_begin.tp_col - x;
167 	height = area->tr_end.tp_row * vw->vw_font->vf_height + vw->vw_draw_area.tr_begin.tp_row - y;
168 
169 	vtgpu_transfer_to_host_2d(sc, x, y, width, height);
170 	vtgpu_resource_flush(sc, x, y, width, height);
171 }
172 
173 static void
174 vtgpu_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
175     const uint8_t *pattern, const uint8_t *mask,
176     unsigned int width, unsigned int height,
177     unsigned int x, unsigned int y, term_color_t fg, term_color_t bg)
178 {
179 	struct vtgpu_softc *sc;
180 	struct fb_info *info;
181 
182 	info = vd->vd_softc;
183 	sc = (struct vtgpu_softc *)info;
184 
185 	vt_fb_bitblt_bitmap(vd, vw, pattern, mask, width, height, x, y, fg, bg);
186 
187 	vtgpu_transfer_to_host_2d(sc, x, y, width, height);
188 	vtgpu_resource_flush(sc, x, y, width, height);
189 }
190 
191 static int
192 vtgpu_fb_bitblt_argb(struct vt_device *vd, const struct vt_window *vw,
193     const uint8_t *argb,
194     unsigned int width, unsigned int height,
195     unsigned int x, unsigned int y)
196 {
197 
198 	return (EOPNOTSUPP);
199 }
200 
201 static void
202 vtgpu_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2,
203     int fill, term_color_t color)
204 {
205 	struct vtgpu_softc *sc;
206 	struct fb_info *info;
207 	int width, height;
208 
209 	info = vd->vd_softc;
210 	sc = (struct vtgpu_softc *)info;
211 
212 	vt_fb_drawrect(vd, x1, y1, x2, y2, fill, color);
213 
214 	width = x2 - x1 + 1;
215 	height = y2 - y1 + 1;
216 	vtgpu_transfer_to_host_2d(sc, x1, y1, width, height);
217 	vtgpu_resource_flush(sc, x1, y1, width, height);
218 }
219 
220 static void
221 vtgpu_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color)
222 {
223 	struct vtgpu_softc *sc;
224 	struct fb_info *info;
225 
226 	info = vd->vd_softc;
227 	sc = (struct vtgpu_softc *)info;
228 
229 	vt_fb_setpixel(vd, x, y, color);
230 
231 	vtgpu_transfer_to_host_2d(sc, x, y, 1, 1);
232 	vtgpu_resource_flush(sc, x, y, 1, 1);
233 }
234 
235 static struct virtio_feature_desc vtgpu_feature_desc[] = {
236 	{ VIRTIO_GPU_F_VIRGL,		"VirGL"		},
237 	{ VIRTIO_GPU_F_EDID,		"EDID"		},
238 	{ VIRTIO_GPU_F_RESOURCE_UUID,	"ResUUID"	},
239 	{ VIRTIO_GPU_F_RESOURCE_BLOB,	"ResBlob"	},
240 	{ VIRTIO_GPU_F_CONTEXT_INIT,	"ContextInit"	},
241 	{ 0, NULL }
242 };
243 
244 static device_method_t vtgpu_methods[] = {
245 	/* Device methods. */
246 	DEVMETHOD(device_probe,		vtgpu_probe),
247 	DEVMETHOD(device_attach,	vtgpu_attach),
248 	DEVMETHOD(device_detach,	vtgpu_detach),
249 
250 	DEVMETHOD_END
251 };
252 
253 static driver_t vtgpu_driver = {
254 	"vtgpu",
255 	vtgpu_methods,
256 	sizeof(struct vtgpu_softc)
257 };
258 
259 VIRTIO_DRIVER_MODULE(virtio_gpu, vtgpu_driver, vtgpu_modevent, NULL);
260 MODULE_VERSION(virtio_gpu, 1);
261 MODULE_DEPEND(virtio_gpu, virtio, 1, 1, 1);
262 
263 VIRTIO_SIMPLE_PNPINFO(virtio_gpu, VIRTIO_ID_GPU,
264     "VirtIO GPU");
265 
266 static int
267 vtgpu_modevent(module_t mod, int type, void *unused)
268 {
269 	int error;
270 
271 	switch (type) {
272 	case MOD_LOAD:
273 	case MOD_QUIESCE:
274 	case MOD_UNLOAD:
275 	case MOD_SHUTDOWN:
276 		error = 0;
277 		break;
278 	default:
279 		error = EOPNOTSUPP;
280 		break;
281 	}
282 
283 	return (error);
284 }
285 
286 static int
287 vtgpu_probe(device_t dev)
288 {
289 	return (VIRTIO_SIMPLE_PROBE(dev, virtio_gpu));
290 }
291 
292 static int
293 vtgpu_attach(device_t dev)
294 {
295 	struct vtgpu_softc *sc;
296 	int error;
297 
298 	sc = device_get_softc(dev);
299 	sc->vtgpu_have_fb_info = false;
300 	sc->vtgpu_dev = dev;
301 	sc->vtgpu_next_fence = 1;
302 	virtio_set_feature_desc(dev, vtgpu_feature_desc);
303 
304 	error = vtgpu_setup_features(sc);
305 	if (error != 0) {
306 		device_printf(dev, "cannot setup features\n");
307 		goto fail;
308 	}
309 
310 	vtgpu_read_config(sc, &sc->vtgpu_gpucfg);
311 
312 	error = vtgpu_alloc_virtqueue(sc);
313 	if (error != 0) {
314 		device_printf(dev, "cannot allocate virtqueue\n");
315 		goto fail;
316 	}
317 
318 	virtio_setup_intr(dev, INTR_TYPE_TTY);
319 
320 	/* Read the device info to get the display size */
321 	error = vtgpu_get_display_info(sc);
322 	if (error != 0) {
323 		goto fail;
324 	}
325 
326 	/*
327 	 * TODO: This doesn't need to be contigmalloc as we
328 	 * can use scatter-gather lists.
329 	 */
330 	sc->vtgpu_fb_info.fb_vbase = (vm_offset_t)contigmalloc(
331 	    sc->vtgpu_fb_info.fb_size, M_DEVBUF, M_WAITOK|M_ZERO, 0, ~0, 4, 0);
332 	sc->vtgpu_fb_info.fb_pbase = pmap_kextract(sc->vtgpu_fb_info.fb_vbase);
333 
334 	/* Create the 2d resource */
335 	error = vtgpu_create_2d(sc);
336 	if (error != 0) {
337 		goto fail;
338 	}
339 
340 	/* Attach the backing memory */
341 	error = vtgpu_attach_backing(sc);
342 	if (error != 0) {
343 		goto fail;
344 	}
345 
346 	/* Set the scanout to link the framebuffer to the display scanout */
347 	error = vtgpu_set_scanout(sc, 0, 0, sc->vtgpu_fb_info.fb_width,
348 	    sc->vtgpu_fb_info.fb_height);
349 	if (error != 0) {
350 		goto fail;
351 	}
352 
353 	vt_allocate(&vtgpu_fb_driver, &sc->vtgpu_fb_info);
354 	sc->vtgpu_have_fb_info = true;
355 
356 	error = vtgpu_transfer_to_host_2d(sc, 0, 0, sc->vtgpu_fb_info.fb_width,
357 	    sc->vtgpu_fb_info.fb_height);
358 	if (error != 0)
359 		goto fail;
360 	error = vtgpu_resource_flush(sc, 0, 0, sc->vtgpu_fb_info.fb_width,
361 	    sc->vtgpu_fb_info.fb_height);
362 
363 fail:
364 	if (error != 0)
365 		vtgpu_detach(dev);
366 
367 	return (error);
368 }
369 
370 static int
371 vtgpu_detach(device_t dev)
372 {
373 	struct vtgpu_softc *sc;
374 
375 	sc = device_get_softc(dev);
376 	if (sc->vtgpu_have_fb_info)
377 		vt_deallocate(&vtgpu_fb_driver, &sc->vtgpu_fb_info);
378 	if (sc->vtgpu_fb_info.fb_vbase != 0) {
379 		MPASS(sc->vtgpu_fb_info.fb_size != 0);
380 		free((void *)sc->vtgpu_fb_info.fb_vbase,
381 		    M_DEVBUF);
382 	}
383 
384 	/* TODO: Tell the host we are detaching */
385 
386 	return (0);
387 }
388 
389 static int
390 vtgpu_negotiate_features(struct vtgpu_softc *sc)
391 {
392 	device_t dev;
393 	uint64_t features;
394 
395 	dev = sc->vtgpu_dev;
396 	features = VTGPU_FEATURES;
397 
398 	sc->vtgpu_features = virtio_negotiate_features(dev, features);
399 	return (virtio_finalize_features(dev));
400 }
401 
402 static int
403 vtgpu_setup_features(struct vtgpu_softc *sc)
404 {
405 	int error;
406 
407 	error = vtgpu_negotiate_features(sc);
408 	if (error != 0)
409 		return (error);
410 
411 	return (0);
412 }
413 
414 static void
415 vtgpu_read_config(struct vtgpu_softc *sc,
416     struct virtio_gpu_config *gpucfg)
417 {
418 	device_t dev;
419 
420 	dev = sc->vtgpu_dev;
421 
422 	bzero(gpucfg, sizeof(struct virtio_gpu_config));
423 
424 #define VTGPU_GET_CONFIG(_dev, _field, _cfg)			\
425 	virtio_read_device_config(_dev,				\
426 	    offsetof(struct virtio_gpu_config, _field),	\
427 	    &(_cfg)->_field, sizeof((_cfg)->_field))		\
428 
429 	VTGPU_GET_CONFIG(dev, events_read, gpucfg);
430 	VTGPU_GET_CONFIG(dev, events_clear, gpucfg);
431 	VTGPU_GET_CONFIG(dev, num_scanouts, gpucfg);
432 	VTGPU_GET_CONFIG(dev, num_capsets, gpucfg);
433 
434 #undef VTGPU_GET_CONFIG
435 }
436 
437 static int
438 vtgpu_alloc_virtqueue(struct vtgpu_softc *sc)
439 {
440 	device_t dev;
441 	struct vq_alloc_info vq_info[2];
442 	int nvqs;
443 
444 	dev = sc->vtgpu_dev;
445 	nvqs = 1;
446 
447 	VQ_ALLOC_INFO_INIT(&vq_info[0], 0, NULL, sc, &sc->vtgpu_ctrl_vq,
448 	    "%s control", device_get_nameunit(dev));
449 
450 	return (virtio_alloc_virtqueues(dev, nvqs, vq_info));
451 }
452 
453 static int
454 vtgpu_req_resp2(struct vtgpu_softc *sc, void *req1, size_t req1len,
455     void *req2, size_t req2len, void *resp, size_t resplen)
456 {
457 	struct sglist sg;
458 	struct sglist_seg segs[3];
459 	int error, rcount;
460 
461 	sglist_init(&sg, 3, segs);
462 
463 	rcount = 1;
464 	error = sglist_append(&sg, req1, req1len);
465 	if (error != 0) {
466 		device_printf(sc->vtgpu_dev,
467 		    "Unable to append the request to the sglist: %d\n",
468 		    error);
469 		return (error);
470 	}
471 	if (req2 != NULL) {
472 		error = sglist_append(&sg, req2, req2len);
473 		if (error != 0) {
474 			device_printf(sc->vtgpu_dev,
475 			    "Unable to append the request to the sglist: %d\n",
476 			    error);
477 			return (error);
478 		}
479 		rcount++;
480 	}
481 	error = sglist_append(&sg, resp, resplen);
482 	if (error != 0) {
483 		device_printf(sc->vtgpu_dev,
484 		    "Unable to append the response buffer to the sglist: %d\n",
485 		    error);
486 		return (error);
487 	}
488 	error = virtqueue_enqueue(sc->vtgpu_ctrl_vq, resp, &sg, rcount, 1);
489 	if (error != 0) {
490 		device_printf(sc->vtgpu_dev, "Enqueue failed: %d\n", error);
491 		return (error);
492 	}
493 
494 	virtqueue_notify(sc->vtgpu_ctrl_vq);
495 	virtqueue_poll(sc->vtgpu_ctrl_vq, NULL);
496 
497 	return (0);
498 }
499 
500 static int
501 vtgpu_req_resp(struct vtgpu_softc *sc, void *req, size_t reqlen,
502     void *resp, size_t resplen)
503 {
504 	return (vtgpu_req_resp2(sc, req, reqlen, NULL, 0, resp, resplen));
505 }
506 
507 static int
508 vtgpu_get_display_info(struct vtgpu_softc *sc)
509 {
510 	struct {
511 		struct virtio_gpu_ctrl_hdr req;
512 		char pad;
513 		struct virtio_gpu_resp_display_info resp;
514 	} s = { 0 };
515 	int error;
516 
517 	s.req.type = htole32(VIRTIO_GPU_CMD_GET_DISPLAY_INFO);
518 	s.req.flags = htole32(VIRTIO_GPU_FLAG_FENCE);
519 	s.req.fence_id = htole64(atomic_fetchadd_64(&sc->vtgpu_next_fence, 1));
520 
521 	error = vtgpu_req_resp(sc, &s.req, sizeof(s.req), &s.resp,
522 	    sizeof(s.resp));
523 	if (error != 0)
524 		return (error);
525 
526 	for (int i = 0; i < sc->vtgpu_gpucfg.num_scanouts; i++) {
527 		if (s.resp.pmodes[i].enabled != 0)
528 			MPASS(i == 0);
529 			sc->vtgpu_fb_info.fb_name =
530 			    device_get_nameunit(sc->vtgpu_dev);
531 
532 			sc->vtgpu_fb_info.fb_width =
533 			    le32toh(s.resp.pmodes[i].r.width);
534 			sc->vtgpu_fb_info.fb_height =
535 			    le32toh(s.resp.pmodes[i].r.height);
536 			/* 32 bits per pixel */
537 			sc->vtgpu_fb_info.fb_bpp = 32;
538 			sc->vtgpu_fb_info.fb_depth = 32;
539 			sc->vtgpu_fb_info.fb_size = sc->vtgpu_fb_info.fb_width *
540 			    sc->vtgpu_fb_info.fb_height * 4;
541 			sc->vtgpu_fb_info.fb_stride =
542 			    sc->vtgpu_fb_info.fb_width * 4;
543 			return (0);
544 	}
545 
546 	return (ENXIO);
547 }
548 
549 static int
550 vtgpu_create_2d(struct vtgpu_softc *sc)
551 {
552 	struct {
553 		struct virtio_gpu_resource_create_2d req;
554 		char pad;
555 		struct virtio_gpu_ctrl_hdr resp;
556 	} s = { 0 };
557 	int error;
558 
559 	s.req.hdr.type = htole32(VIRTIO_GPU_CMD_RESOURCE_CREATE_2D);
560 	s.req.hdr.flags = htole32(VIRTIO_GPU_FLAG_FENCE);
561 	s.req.hdr.fence_id = htole64(
562 	    atomic_fetchadd_64(&sc->vtgpu_next_fence, 1));
563 
564 	s.req.resource_id = htole32(VTGPU_RESOURCE_ID);
565 	s.req.format = htole32(VTGPU_FORMAT);
566 	s.req.width = htole32(sc->vtgpu_fb_info.fb_width);
567 	s.req.height = htole32(sc->vtgpu_fb_info.fb_height);
568 
569 	error = vtgpu_req_resp(sc, &s.req, sizeof(s.req), &s.resp,
570 	    sizeof(s.resp));
571 	if (error != 0)
572 		return (error);
573 
574 	if (s.resp.type != htole32(VIRTIO_GPU_RESP_OK_NODATA)) {
575 		device_printf(sc->vtgpu_dev, "Invalid response type %x\n",
576 		    le32toh(s.resp.type));
577 		return (EINVAL);
578 	}
579 
580 	return (0);
581 }
582 
583 static int
584 vtgpu_attach_backing(struct vtgpu_softc *sc)
585 {
586 	struct {
587 		/*
588 		 * Split the backing and mem request arguments as some
589 		 * hypervisors, e.g. Parallels Desktop, don't work when
590 		 * they are enqueued together.
591 		 */
592 		struct {
593 			struct virtio_gpu_resource_attach_backing backing;
594 			char pad;
595 			struct virtio_gpu_mem_entry mem;
596 		} req;
597 		char pad;
598 		struct virtio_gpu_ctrl_hdr resp;
599 	} s = { 0 };
600 	int error;
601 
602 	s.req.backing.hdr.type =
603 	    htole32(VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING);
604 	s.req.backing.hdr.flags = htole32(VIRTIO_GPU_FLAG_FENCE);
605 	s.req.backing.hdr.fence_id = htole64(
606 	    atomic_fetchadd_64(&sc->vtgpu_next_fence, 1));
607 
608 	s.req.backing.resource_id = htole32(VTGPU_RESOURCE_ID);
609 	s.req.backing.nr_entries = htole32(1);
610 
611 	s.req.mem.addr = htole64(sc->vtgpu_fb_info.fb_pbase);
612 	s.req.mem.length = htole32(sc->vtgpu_fb_info.fb_size);
613 
614 	error = vtgpu_req_resp2(sc, &s.req.backing, sizeof(s.req.backing),
615 	    &s.req.mem, sizeof(s.req.mem), &s.resp, sizeof(s.resp));
616 	if (error != 0)
617 		return (error);
618 
619 	if (s.resp.type != htole32(VIRTIO_GPU_RESP_OK_NODATA)) {
620 		device_printf(sc->vtgpu_dev, "Invalid response type %x\n",
621 		    le32toh(s.resp.type));
622 		return (EINVAL);
623 	}
624 
625 	return (0);
626 }
627 
628 static int
629 vtgpu_set_scanout(struct vtgpu_softc *sc, uint32_t x, uint32_t y,
630     uint32_t width, uint32_t height)
631 {
632 	struct {
633 		struct virtio_gpu_set_scanout req;
634 		char pad;
635 		struct virtio_gpu_ctrl_hdr resp;
636 	} s = { 0 };
637 	int error;
638 
639 	s.req.hdr.type = htole32(VIRTIO_GPU_CMD_SET_SCANOUT);
640 	s.req.hdr.flags = htole32(VIRTIO_GPU_FLAG_FENCE);
641 	s.req.hdr.fence_id = htole64(
642 	    atomic_fetchadd_64(&sc->vtgpu_next_fence, 1));
643 
644 	s.req.r.x = htole32(x);
645 	s.req.r.y = htole32(y);
646 	s.req.r.width = htole32(width);
647 	s.req.r.height = htole32(height);
648 
649 	s.req.scanout_id = 0;
650 	s.req.resource_id = htole32(VTGPU_RESOURCE_ID);
651 
652 	error = vtgpu_req_resp(sc, &s.req, sizeof(s.req), &s.resp,
653 	    sizeof(s.resp));
654 	if (error != 0)
655 		return (error);
656 
657 	if (s.resp.type != htole32(VIRTIO_GPU_RESP_OK_NODATA)) {
658 		device_printf(sc->vtgpu_dev, "Invalid response type %x\n",
659 		    le32toh(s.resp.type));
660 		return (EINVAL);
661 	}
662 
663 	return (0);
664 }
665 
666 static int
667 vtgpu_transfer_to_host_2d(struct vtgpu_softc *sc, uint32_t x, uint32_t y,
668     uint32_t width, uint32_t height)
669 {
670 	struct {
671 		struct virtio_gpu_transfer_to_host_2d req;
672 		char pad;
673 		struct virtio_gpu_ctrl_hdr resp;
674 	} s = { 0 };
675 	int error;
676 
677 	s.req.hdr.type = htole32(VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D);
678 	s.req.hdr.flags = htole32(VIRTIO_GPU_FLAG_FENCE);
679 	s.req.hdr.fence_id = htole64(
680 	    atomic_fetchadd_64(&sc->vtgpu_next_fence, 1));
681 
682 	s.req.r.x = htole32(x);
683 	s.req.r.y = htole32(y);
684 	s.req.r.width = htole32(width);
685 	s.req.r.height = htole32(height);
686 
687 	s.req.offset = htole64((y * sc->vtgpu_fb_info.fb_width + x)
688 	 * (sc->vtgpu_fb_info.fb_bpp / 8));
689 	s.req.resource_id = htole32(VTGPU_RESOURCE_ID);
690 
691 	error = vtgpu_req_resp(sc, &s.req, sizeof(s.req), &s.resp,
692 	    sizeof(s.resp));
693 	if (error != 0)
694 		return (error);
695 
696 	if (s.resp.type != htole32(VIRTIO_GPU_RESP_OK_NODATA)) {
697 		device_printf(sc->vtgpu_dev, "Invalid response type %x\n",
698 		    le32toh(s.resp.type));
699 		return (EINVAL);
700 	}
701 
702 	return (0);
703 }
704 
705 static int
706 vtgpu_resource_flush(struct vtgpu_softc *sc, uint32_t x, uint32_t y,
707     uint32_t width, uint32_t height)
708 {
709 	struct {
710 		struct virtio_gpu_resource_flush req;
711 		char pad;
712 		struct virtio_gpu_ctrl_hdr resp;
713 	} s = { 0 };
714 	int error;
715 
716 	s.req.hdr.type = htole32(VIRTIO_GPU_CMD_RESOURCE_FLUSH);
717 	s.req.hdr.flags = htole32(VIRTIO_GPU_FLAG_FENCE);
718 	s.req.hdr.fence_id = htole64(
719 	    atomic_fetchadd_64(&sc->vtgpu_next_fence, 1));
720 
721 	s.req.r.x = htole32(x);
722 	s.req.r.y = htole32(y);
723 	s.req.r.width = htole32(width);
724 	s.req.r.height = htole32(height);
725 
726 	s.req.resource_id = htole32(VTGPU_RESOURCE_ID);
727 
728 	error = vtgpu_req_resp(sc, &s.req, sizeof(s.req), &s.resp,
729 	    sizeof(s.resp));
730 	if (error != 0)
731 		return (error);
732 
733 	if (s.resp.type != htole32(VIRTIO_GPU_RESP_OK_NODATA)) {
734 		device_printf(sc->vtgpu_dev, "Invalid response type %x\n",
735 		    le32toh(s.resp.type));
736 		return (EINVAL);
737 	}
738 
739 	return (0);
740 }
741