102f27066SAndrew Turner /*-
202f27066SAndrew Turner * SPDX-License-Identifier: BSD-2-Clause
302f27066SAndrew Turner *
402f27066SAndrew Turner * Copyright (c) 2013, Bryan Venteicher <bryanv@FreeBSD.org>
502f27066SAndrew Turner * All rights reserved.
602f27066SAndrew Turner * Copyright (c) 2023, Arm Ltd
702f27066SAndrew Turner *
802f27066SAndrew Turner * Redistribution and use in source and binary forms, with or without
902f27066SAndrew Turner * modification, are permitted provided that the following conditions
1002f27066SAndrew Turner * are met:
1102f27066SAndrew Turner * 1. Redistributions of source code must retain the above copyright
1202f27066SAndrew Turner * notice unmodified, this list of conditions, and the following
1302f27066SAndrew Turner * disclaimer.
1402f27066SAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright
1502f27066SAndrew Turner * notice, this list of conditions and the following disclaimer in the
1602f27066SAndrew Turner * documentation and/or other materials provided with the distribution.
1702f27066SAndrew Turner *
1802f27066SAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1902f27066SAndrew Turner * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2002f27066SAndrew Turner * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2102f27066SAndrew Turner * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2202f27066SAndrew Turner * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2302f27066SAndrew Turner * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2402f27066SAndrew Turner * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2502f27066SAndrew Turner * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2602f27066SAndrew Turner * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2702f27066SAndrew Turner * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2802f27066SAndrew Turner */
2902f27066SAndrew Turner
3002f27066SAndrew Turner /* Driver for VirtIO GPU device. */
3102f27066SAndrew Turner
3202f27066SAndrew Turner #include <sys/param.h>
3302f27066SAndrew Turner #include <sys/types.h>
3402f27066SAndrew Turner #include <sys/bus.h>
3502f27066SAndrew Turner #include <sys/callout.h>
3602f27066SAndrew Turner #include <sys/fbio.h>
3702f27066SAndrew Turner #include <sys/kernel.h>
3802f27066SAndrew Turner #include <sys/malloc.h>
3902f27066SAndrew Turner #include <sys/module.h>
4002f27066SAndrew Turner #include <sys/sglist.h>
4102f27066SAndrew Turner
4202f27066SAndrew Turner #include <machine/atomic.h>
4302f27066SAndrew Turner #include <machine/bus.h>
4402f27066SAndrew Turner #include <machine/resource.h>
4502f27066SAndrew Turner
4602f27066SAndrew Turner #include <vm/vm.h>
4702f27066SAndrew Turner #include <vm/pmap.h>
4802f27066SAndrew Turner
4902f27066SAndrew Turner #include <dev/virtio/virtio.h>
5002f27066SAndrew Turner #include <dev/virtio/virtqueue.h>
5102f27066SAndrew Turner #include <dev/virtio/gpu/virtio_gpu.h>
5202f27066SAndrew Turner
5302f27066SAndrew Turner #include <dev/vt/vt.h>
5402f27066SAndrew Turner #include <dev/vt/hw/fb/vt_fb.h>
5502f27066SAndrew Turner #include <dev/vt/colors/vt_termcolors.h>
5602f27066SAndrew Turner
5702f27066SAndrew Turner #include "fb_if.h"
5802f27066SAndrew Turner
5902f27066SAndrew Turner #define VTGPU_FEATURES 0
6002f27066SAndrew Turner
6102f27066SAndrew Turner /* The guest can allocate resource IDs, we only need one */
6202f27066SAndrew Turner #define VTGPU_RESOURCE_ID 1
6302f27066SAndrew Turner
6402f27066SAndrew Turner struct vtgpu_softc {
6502f27066SAndrew Turner /* Must be first so we can cast from info -> softc */
6602f27066SAndrew Turner struct fb_info vtgpu_fb_info;
6702f27066SAndrew Turner struct virtio_gpu_config vtgpu_gpucfg;
6802f27066SAndrew Turner
6902f27066SAndrew Turner device_t vtgpu_dev;
7002f27066SAndrew Turner uint64_t vtgpu_features;
7102f27066SAndrew Turner
7202f27066SAndrew Turner struct virtqueue *vtgpu_ctrl_vq;
7302f27066SAndrew Turner
7402f27066SAndrew Turner uint64_t vtgpu_next_fence;
7502f27066SAndrew Turner
7602f27066SAndrew Turner bool vtgpu_have_fb_info;
7702f27066SAndrew Turner };
7802f27066SAndrew Turner
7902f27066SAndrew Turner static int vtgpu_modevent(module_t, int, void *);
8002f27066SAndrew Turner
8102f27066SAndrew Turner static int vtgpu_probe(device_t);
8202f27066SAndrew Turner static int vtgpu_attach(device_t);
8302f27066SAndrew Turner static int vtgpu_detach(device_t);
8402f27066SAndrew Turner
8502f27066SAndrew Turner static int vtgpu_negotiate_features(struct vtgpu_softc *);
8602f27066SAndrew Turner static int vtgpu_setup_features(struct vtgpu_softc *);
8702f27066SAndrew Turner static void vtgpu_read_config(struct vtgpu_softc *,
8802f27066SAndrew Turner struct virtio_gpu_config *);
8902f27066SAndrew Turner static int vtgpu_alloc_virtqueue(struct vtgpu_softc *);
9002f27066SAndrew Turner static int vtgpu_get_display_info(struct vtgpu_softc *);
9102f27066SAndrew Turner static int vtgpu_create_2d(struct vtgpu_softc *);
9202f27066SAndrew Turner static int vtgpu_attach_backing(struct vtgpu_softc *);
9302f27066SAndrew Turner static int vtgpu_set_scanout(struct vtgpu_softc *, uint32_t, uint32_t,
9402f27066SAndrew Turner uint32_t, uint32_t);
9502f27066SAndrew Turner static int vtgpu_transfer_to_host_2d(struct vtgpu_softc *, uint32_t,
9602f27066SAndrew Turner uint32_t, uint32_t, uint32_t);
9702f27066SAndrew Turner static int vtgpu_resource_flush(struct vtgpu_softc *, uint32_t, uint32_t,
9802f27066SAndrew Turner uint32_t, uint32_t);
9902f27066SAndrew Turner
10002f27066SAndrew Turner static vd_blank_t vtgpu_fb_blank;
10102f27066SAndrew Turner static vd_bitblt_text_t vtgpu_fb_bitblt_text;
10202f27066SAndrew Turner static vd_bitblt_bmp_t vtgpu_fb_bitblt_bitmap;
10302f27066SAndrew Turner static vd_drawrect_t vtgpu_fb_drawrect;
10402f27066SAndrew Turner static vd_setpixel_t vtgpu_fb_setpixel;
105b93028d8SEmmanuel Vadot static vd_bitblt_argb_t vtgpu_fb_bitblt_argb;
10602f27066SAndrew Turner
10702f27066SAndrew Turner static struct vt_driver vtgpu_fb_driver = {
10802f27066SAndrew Turner .vd_name = "virtio_gpu",
10902f27066SAndrew Turner .vd_init = vt_fb_init,
11002f27066SAndrew Turner .vd_fini = vt_fb_fini,
11102f27066SAndrew Turner .vd_blank = vtgpu_fb_blank,
11202f27066SAndrew Turner .vd_bitblt_text = vtgpu_fb_bitblt_text,
11302f27066SAndrew Turner .vd_invalidate_text = vt_fb_invalidate_text,
11402f27066SAndrew Turner .vd_bitblt_bmp = vtgpu_fb_bitblt_bitmap,
115b93028d8SEmmanuel Vadot .vd_bitblt_argb = vtgpu_fb_bitblt_argb,
11602f27066SAndrew Turner .vd_drawrect = vtgpu_fb_drawrect,
11702f27066SAndrew Turner .vd_setpixel = vtgpu_fb_setpixel,
11802f27066SAndrew Turner .vd_postswitch = vt_fb_postswitch,
11902f27066SAndrew Turner .vd_priority = VD_PRIORITY_GENERIC+10,
12002f27066SAndrew Turner .vd_fb_ioctl = vt_fb_ioctl,
12102f27066SAndrew Turner .vd_fb_mmap = NULL, /* No mmap as we need to signal the host */
12202f27066SAndrew Turner .vd_suspend = vt_fb_suspend,
12302f27066SAndrew Turner .vd_resume = vt_fb_resume,
12402f27066SAndrew Turner };
12502f27066SAndrew Turner
12602f27066SAndrew Turner VT_DRIVER_DECLARE(vt_vtgpu, vtgpu_fb_driver);
12702f27066SAndrew Turner
12802f27066SAndrew Turner static void
vtgpu_fb_blank(struct vt_device * vd,term_color_t color)12902f27066SAndrew Turner vtgpu_fb_blank(struct vt_device *vd, term_color_t color)
13002f27066SAndrew Turner {
13102f27066SAndrew Turner struct vtgpu_softc *sc;
13202f27066SAndrew Turner struct fb_info *info;
13302f27066SAndrew Turner
13402f27066SAndrew Turner info = vd->vd_softc;
13502f27066SAndrew Turner sc = (struct vtgpu_softc *)info;
13602f27066SAndrew Turner
13702f27066SAndrew Turner vt_fb_blank(vd, color);
13802f27066SAndrew Turner
13902f27066SAndrew Turner vtgpu_transfer_to_host_2d(sc, 0, 0, sc->vtgpu_fb_info.fb_width,
14002f27066SAndrew Turner sc->vtgpu_fb_info.fb_height);
14102f27066SAndrew Turner vtgpu_resource_flush(sc, 0, 0, sc->vtgpu_fb_info.fb_width,
14202f27066SAndrew Turner sc->vtgpu_fb_info.fb_height);
14302f27066SAndrew Turner }
14402f27066SAndrew Turner
14502f27066SAndrew Turner static void
vtgpu_fb_bitblt_text(struct vt_device * vd,const struct vt_window * vw,const term_rect_t * area)14602f27066SAndrew Turner vtgpu_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
14702f27066SAndrew Turner const term_rect_t *area)
14802f27066SAndrew Turner {
14902f27066SAndrew Turner struct vtgpu_softc *sc;
15002f27066SAndrew Turner struct fb_info *info;
15102f27066SAndrew Turner int x, y, width, height;
15202f27066SAndrew Turner
15302f27066SAndrew Turner info = vd->vd_softc;
15402f27066SAndrew Turner sc = (struct vtgpu_softc *)info;
15502f27066SAndrew Turner
15602f27066SAndrew Turner vt_fb_bitblt_text(vd, vw, area);
15702f27066SAndrew Turner
15802f27066SAndrew Turner x = area->tr_begin.tp_col * vw->vw_font->vf_width + vw->vw_draw_area.tr_begin.tp_col;
15902f27066SAndrew Turner y = area->tr_begin.tp_row * vw->vw_font->vf_height + vw->vw_draw_area.tr_begin.tp_row;
16002f27066SAndrew Turner width = area->tr_end.tp_col * vw->vw_font->vf_width + vw->vw_draw_area.tr_begin.tp_col - x;
16102f27066SAndrew Turner height = area->tr_end.tp_row * vw->vw_font->vf_height + vw->vw_draw_area.tr_begin.tp_row - y;
16202f27066SAndrew Turner
16302f27066SAndrew Turner vtgpu_transfer_to_host_2d(sc, x, y, width, height);
16402f27066SAndrew Turner vtgpu_resource_flush(sc, x, y, width, height);
16502f27066SAndrew Turner }
16602f27066SAndrew Turner
16702f27066SAndrew Turner static void
vtgpu_fb_bitblt_bitmap(struct vt_device * vd,const struct vt_window * vw,const uint8_t * pattern,const uint8_t * mask,unsigned int width,unsigned int height,unsigned int x,unsigned int y,term_color_t fg,term_color_t bg)16802f27066SAndrew Turner vtgpu_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
16902f27066SAndrew Turner const uint8_t *pattern, const uint8_t *mask,
17002f27066SAndrew Turner unsigned int width, unsigned int height,
17102f27066SAndrew Turner unsigned int x, unsigned int y, term_color_t fg, term_color_t bg)
17202f27066SAndrew Turner {
17302f27066SAndrew Turner struct vtgpu_softc *sc;
17402f27066SAndrew Turner struct fb_info *info;
17502f27066SAndrew Turner
17602f27066SAndrew Turner info = vd->vd_softc;
17702f27066SAndrew Turner sc = (struct vtgpu_softc *)info;
17802f27066SAndrew Turner
17902f27066SAndrew Turner vt_fb_bitblt_bitmap(vd, vw, pattern, mask, width, height, x, y, fg, bg);
18002f27066SAndrew Turner
18102f27066SAndrew Turner vtgpu_transfer_to_host_2d(sc, x, y, width, height);
18202f27066SAndrew Turner vtgpu_resource_flush(sc, x, y, width, height);
18302f27066SAndrew Turner }
18402f27066SAndrew Turner
185b93028d8SEmmanuel Vadot static int
vtgpu_fb_bitblt_argb(struct vt_device * vd,const struct vt_window * vw,const uint8_t * argb,unsigned int width,unsigned int height,unsigned int x,unsigned int y)186b93028d8SEmmanuel Vadot vtgpu_fb_bitblt_argb(struct vt_device *vd, const struct vt_window *vw,
187b93028d8SEmmanuel Vadot const uint8_t *argb,
188b93028d8SEmmanuel Vadot unsigned int width, unsigned int height,
189b93028d8SEmmanuel Vadot unsigned int x, unsigned int y)
190b93028d8SEmmanuel Vadot {
191b93028d8SEmmanuel Vadot
192b93028d8SEmmanuel Vadot return (EOPNOTSUPP);
193b93028d8SEmmanuel Vadot }
194b93028d8SEmmanuel Vadot
19502f27066SAndrew Turner static void
vtgpu_fb_drawrect(struct vt_device * vd,int x1,int y1,int x2,int y2,int fill,term_color_t color)19602f27066SAndrew Turner vtgpu_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2,
19702f27066SAndrew Turner int fill, term_color_t color)
19802f27066SAndrew Turner {
19902f27066SAndrew Turner struct vtgpu_softc *sc;
20002f27066SAndrew Turner struct fb_info *info;
20102f27066SAndrew Turner int width, height;
20202f27066SAndrew Turner
20302f27066SAndrew Turner info = vd->vd_softc;
20402f27066SAndrew Turner sc = (struct vtgpu_softc *)info;
20502f27066SAndrew Turner
20602f27066SAndrew Turner vt_fb_drawrect(vd, x1, y1, x2, y2, fill, color);
20702f27066SAndrew Turner
20802f27066SAndrew Turner width = x2 - x1 + 1;
20902f27066SAndrew Turner height = y2 - y1 + 1;
21002f27066SAndrew Turner vtgpu_transfer_to_host_2d(sc, x1, y1, width, height);
21102f27066SAndrew Turner vtgpu_resource_flush(sc, x1, y1, width, height);
21202f27066SAndrew Turner }
21302f27066SAndrew Turner
21402f27066SAndrew Turner static void
vtgpu_fb_setpixel(struct vt_device * vd,int x,int y,term_color_t color)21502f27066SAndrew Turner vtgpu_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color)
21602f27066SAndrew Turner {
21702f27066SAndrew Turner struct vtgpu_softc *sc;
21802f27066SAndrew Turner struct fb_info *info;
21902f27066SAndrew Turner
22002f27066SAndrew Turner info = vd->vd_softc;
22102f27066SAndrew Turner sc = (struct vtgpu_softc *)info;
22202f27066SAndrew Turner
22302f27066SAndrew Turner vt_fb_setpixel(vd, x, y, color);
22402f27066SAndrew Turner
22502f27066SAndrew Turner vtgpu_transfer_to_host_2d(sc, x, y, 1, 1);
22602f27066SAndrew Turner vtgpu_resource_flush(sc, x, y, 1, 1);
22702f27066SAndrew Turner }
22802f27066SAndrew Turner
22902f27066SAndrew Turner static struct virtio_feature_desc vtgpu_feature_desc[] = {
23002f27066SAndrew Turner { VIRTIO_GPU_F_VIRGL, "VirGL" },
23102f27066SAndrew Turner { VIRTIO_GPU_F_EDID, "EDID" },
23202f27066SAndrew Turner { VIRTIO_GPU_F_RESOURCE_UUID, "ResUUID" },
23302f27066SAndrew Turner { VIRTIO_GPU_F_RESOURCE_BLOB, "ResBlob" },
23402f27066SAndrew Turner { VIRTIO_GPU_F_CONTEXT_INIT, "ContextInit" },
23502f27066SAndrew Turner { 0, NULL }
23602f27066SAndrew Turner };
23702f27066SAndrew Turner
23802f27066SAndrew Turner static device_method_t vtgpu_methods[] = {
23902f27066SAndrew Turner /* Device methods. */
24002f27066SAndrew Turner DEVMETHOD(device_probe, vtgpu_probe),
24102f27066SAndrew Turner DEVMETHOD(device_attach, vtgpu_attach),
24202f27066SAndrew Turner DEVMETHOD(device_detach, vtgpu_detach),
24302f27066SAndrew Turner
24402f27066SAndrew Turner DEVMETHOD_END
24502f27066SAndrew Turner };
24602f27066SAndrew Turner
24702f27066SAndrew Turner static driver_t vtgpu_driver = {
24802f27066SAndrew Turner "vtgpu",
24902f27066SAndrew Turner vtgpu_methods,
25002f27066SAndrew Turner sizeof(struct vtgpu_softc)
25102f27066SAndrew Turner };
25202f27066SAndrew Turner
25302f27066SAndrew Turner VIRTIO_DRIVER_MODULE(virtio_gpu, vtgpu_driver, vtgpu_modevent, NULL);
25402f27066SAndrew Turner MODULE_VERSION(virtio_gpu, 1);
25502f27066SAndrew Turner MODULE_DEPEND(virtio_gpu, virtio, 1, 1, 1);
25602f27066SAndrew Turner
25702f27066SAndrew Turner VIRTIO_SIMPLE_PNPINFO(virtio_gpu, VIRTIO_ID_GPU,
25802f27066SAndrew Turner "VirtIO GPU");
25902f27066SAndrew Turner
26002f27066SAndrew Turner static int
vtgpu_modevent(module_t mod,int type,void * unused)26102f27066SAndrew Turner vtgpu_modevent(module_t mod, int type, void *unused)
26202f27066SAndrew Turner {
26302f27066SAndrew Turner int error;
26402f27066SAndrew Turner
26502f27066SAndrew Turner switch (type) {
26602f27066SAndrew Turner case MOD_LOAD:
26702f27066SAndrew Turner case MOD_QUIESCE:
26802f27066SAndrew Turner case MOD_UNLOAD:
26902f27066SAndrew Turner case MOD_SHUTDOWN:
27002f27066SAndrew Turner error = 0;
27102f27066SAndrew Turner break;
27202f27066SAndrew Turner default:
27302f27066SAndrew Turner error = EOPNOTSUPP;
27402f27066SAndrew Turner break;
27502f27066SAndrew Turner }
27602f27066SAndrew Turner
27702f27066SAndrew Turner return (error);
27802f27066SAndrew Turner }
27902f27066SAndrew Turner
28002f27066SAndrew Turner static int
vtgpu_probe(device_t dev)28102f27066SAndrew Turner vtgpu_probe(device_t dev)
28202f27066SAndrew Turner {
28302f27066SAndrew Turner return (VIRTIO_SIMPLE_PROBE(dev, virtio_gpu));
28402f27066SAndrew Turner }
28502f27066SAndrew Turner
28602f27066SAndrew Turner static int
vtgpu_attach(device_t dev)28702f27066SAndrew Turner vtgpu_attach(device_t dev)
28802f27066SAndrew Turner {
28902f27066SAndrew Turner struct vtgpu_softc *sc;
29002f27066SAndrew Turner int error;
29102f27066SAndrew Turner
29202f27066SAndrew Turner sc = device_get_softc(dev);
29302f27066SAndrew Turner sc->vtgpu_have_fb_info = false;
29402f27066SAndrew Turner sc->vtgpu_dev = dev;
29502f27066SAndrew Turner sc->vtgpu_next_fence = 1;
29602f27066SAndrew Turner virtio_set_feature_desc(dev, vtgpu_feature_desc);
29702f27066SAndrew Turner
29802f27066SAndrew Turner error = vtgpu_setup_features(sc);
29902f27066SAndrew Turner if (error != 0) {
30002f27066SAndrew Turner device_printf(dev, "cannot setup features\n");
30102f27066SAndrew Turner goto fail;
30202f27066SAndrew Turner }
30302f27066SAndrew Turner
30402f27066SAndrew Turner vtgpu_read_config(sc, &sc->vtgpu_gpucfg);
30502f27066SAndrew Turner
30602f27066SAndrew Turner error = vtgpu_alloc_virtqueue(sc);
30702f27066SAndrew Turner if (error != 0) {
30802f27066SAndrew Turner device_printf(dev, "cannot allocate virtqueue\n");
30902f27066SAndrew Turner goto fail;
31002f27066SAndrew Turner }
31102f27066SAndrew Turner
31202f27066SAndrew Turner virtio_setup_intr(dev, INTR_TYPE_TTY);
31302f27066SAndrew Turner
31402f27066SAndrew Turner /* Read the device info to get the display size */
31502f27066SAndrew Turner error = vtgpu_get_display_info(sc);
31602f27066SAndrew Turner if (error != 0) {
31702f27066SAndrew Turner goto fail;
31802f27066SAndrew Turner }
31902f27066SAndrew Turner
32002f27066SAndrew Turner /*
32102f27066SAndrew Turner * TODO: This doesn't need to be contigmalloc as we
32202f27066SAndrew Turner * can use scatter-gather lists.
32302f27066SAndrew Turner */
32402f27066SAndrew Turner sc->vtgpu_fb_info.fb_vbase = (vm_offset_t)contigmalloc(
32502f27066SAndrew Turner sc->vtgpu_fb_info.fb_size, M_DEVBUF, M_WAITOK|M_ZERO, 0, ~0, 4, 0);
32602f27066SAndrew Turner sc->vtgpu_fb_info.fb_pbase = pmap_kextract(sc->vtgpu_fb_info.fb_vbase);
32702f27066SAndrew Turner
32802f27066SAndrew Turner /* Create the 2d resource */
32902f27066SAndrew Turner error = vtgpu_create_2d(sc);
33002f27066SAndrew Turner if (error != 0) {
33102f27066SAndrew Turner goto fail;
33202f27066SAndrew Turner }
33302f27066SAndrew Turner
33402f27066SAndrew Turner /* Attach the backing memory */
33502f27066SAndrew Turner error = vtgpu_attach_backing(sc);
33602f27066SAndrew Turner if (error != 0) {
33702f27066SAndrew Turner goto fail;
33802f27066SAndrew Turner }
33902f27066SAndrew Turner
34002f27066SAndrew Turner /* Set the scanout to link the framebuffer to the display scanout */
34102f27066SAndrew Turner error = vtgpu_set_scanout(sc, 0, 0, sc->vtgpu_fb_info.fb_width,
34202f27066SAndrew Turner sc->vtgpu_fb_info.fb_height);
34302f27066SAndrew Turner if (error != 0) {
34402f27066SAndrew Turner goto fail;
34502f27066SAndrew Turner }
34602f27066SAndrew Turner
34702f27066SAndrew Turner vt_allocate(&vtgpu_fb_driver, &sc->vtgpu_fb_info);
34802f27066SAndrew Turner sc->vtgpu_have_fb_info = true;
34902f27066SAndrew Turner
35002f27066SAndrew Turner error = vtgpu_transfer_to_host_2d(sc, 0, 0, sc->vtgpu_fb_info.fb_width,
35102f27066SAndrew Turner sc->vtgpu_fb_info.fb_height);
35202f27066SAndrew Turner if (error != 0)
35302f27066SAndrew Turner goto fail;
35402f27066SAndrew Turner error = vtgpu_resource_flush(sc, 0, 0, sc->vtgpu_fb_info.fb_width,
35502f27066SAndrew Turner sc->vtgpu_fb_info.fb_height);
35602f27066SAndrew Turner
35702f27066SAndrew Turner fail:
35802f27066SAndrew Turner if (error != 0)
35902f27066SAndrew Turner vtgpu_detach(dev);
36002f27066SAndrew Turner
36102f27066SAndrew Turner return (error);
36202f27066SAndrew Turner }
36302f27066SAndrew Turner
36402f27066SAndrew Turner static int
vtgpu_detach(device_t dev)36502f27066SAndrew Turner vtgpu_detach(device_t dev)
36602f27066SAndrew Turner {
36702f27066SAndrew Turner struct vtgpu_softc *sc;
36802f27066SAndrew Turner
36902f27066SAndrew Turner sc = device_get_softc(dev);
37002f27066SAndrew Turner if (sc->vtgpu_have_fb_info)
37102f27066SAndrew Turner vt_deallocate(&vtgpu_fb_driver, &sc->vtgpu_fb_info);
37202f27066SAndrew Turner if (sc->vtgpu_fb_info.fb_vbase != 0) {
37302f27066SAndrew Turner MPASS(sc->vtgpu_fb_info.fb_size != 0);
374d1bdc282SBjoern A. Zeeb free((void *)sc->vtgpu_fb_info.fb_vbase,
375d1bdc282SBjoern A. Zeeb M_DEVBUF);
37602f27066SAndrew Turner }
37702f27066SAndrew Turner
37802f27066SAndrew Turner /* TODO: Tell the host we are detaching */
37902f27066SAndrew Turner
38002f27066SAndrew Turner return (0);
38102f27066SAndrew Turner }
38202f27066SAndrew Turner
38302f27066SAndrew Turner static int
vtgpu_negotiate_features(struct vtgpu_softc * sc)38402f27066SAndrew Turner vtgpu_negotiate_features(struct vtgpu_softc *sc)
38502f27066SAndrew Turner {
38602f27066SAndrew Turner device_t dev;
38702f27066SAndrew Turner uint64_t features;
38802f27066SAndrew Turner
38902f27066SAndrew Turner dev = sc->vtgpu_dev;
39002f27066SAndrew Turner features = VTGPU_FEATURES;
39102f27066SAndrew Turner
39202f27066SAndrew Turner sc->vtgpu_features = virtio_negotiate_features(dev, features);
39302f27066SAndrew Turner return (virtio_finalize_features(dev));
39402f27066SAndrew Turner }
39502f27066SAndrew Turner
39602f27066SAndrew Turner static int
vtgpu_setup_features(struct vtgpu_softc * sc)39702f27066SAndrew Turner vtgpu_setup_features(struct vtgpu_softc *sc)
39802f27066SAndrew Turner {
39902f27066SAndrew Turner int error;
40002f27066SAndrew Turner
40102f27066SAndrew Turner error = vtgpu_negotiate_features(sc);
40202f27066SAndrew Turner if (error != 0)
40302f27066SAndrew Turner return (error);
40402f27066SAndrew Turner
40502f27066SAndrew Turner return (0);
40602f27066SAndrew Turner }
40702f27066SAndrew Turner
40802f27066SAndrew Turner static void
vtgpu_read_config(struct vtgpu_softc * sc,struct virtio_gpu_config * gpucfg)40902f27066SAndrew Turner vtgpu_read_config(struct vtgpu_softc *sc,
41002f27066SAndrew Turner struct virtio_gpu_config *gpucfg)
41102f27066SAndrew Turner {
41202f27066SAndrew Turner device_t dev;
41302f27066SAndrew Turner
41402f27066SAndrew Turner dev = sc->vtgpu_dev;
41502f27066SAndrew Turner
41602f27066SAndrew Turner bzero(gpucfg, sizeof(struct virtio_gpu_config));
41702f27066SAndrew Turner
41802f27066SAndrew Turner #define VTGPU_GET_CONFIG(_dev, _field, _cfg) \
41902f27066SAndrew Turner virtio_read_device_config(_dev, \
42002f27066SAndrew Turner offsetof(struct virtio_gpu_config, _field), \
42102f27066SAndrew Turner &(_cfg)->_field, sizeof((_cfg)->_field)) \
42202f27066SAndrew Turner
42302f27066SAndrew Turner VTGPU_GET_CONFIG(dev, events_read, gpucfg);
42402f27066SAndrew Turner VTGPU_GET_CONFIG(dev, events_clear, gpucfg);
42502f27066SAndrew Turner VTGPU_GET_CONFIG(dev, num_scanouts, gpucfg);
42602f27066SAndrew Turner VTGPU_GET_CONFIG(dev, num_capsets, gpucfg);
42702f27066SAndrew Turner
42802f27066SAndrew Turner #undef VTGPU_GET_CONFIG
42902f27066SAndrew Turner }
43002f27066SAndrew Turner
43102f27066SAndrew Turner static int
vtgpu_alloc_virtqueue(struct vtgpu_softc * sc)43202f27066SAndrew Turner vtgpu_alloc_virtqueue(struct vtgpu_softc *sc)
43302f27066SAndrew Turner {
43402f27066SAndrew Turner device_t dev;
43502f27066SAndrew Turner struct vq_alloc_info vq_info[2];
43602f27066SAndrew Turner int nvqs;
43702f27066SAndrew Turner
43802f27066SAndrew Turner dev = sc->vtgpu_dev;
43902f27066SAndrew Turner nvqs = 1;
44002f27066SAndrew Turner
44102f27066SAndrew Turner VQ_ALLOC_INFO_INIT(&vq_info[0], 0, NULL, sc, &sc->vtgpu_ctrl_vq,
44202f27066SAndrew Turner "%s control", device_get_nameunit(dev));
44302f27066SAndrew Turner
444180c0240SMina Galić return (virtio_alloc_virtqueues(dev, nvqs, vq_info));
44502f27066SAndrew Turner }
44602f27066SAndrew Turner
44702f27066SAndrew Turner static int
vtgpu_req_resp2(struct vtgpu_softc * sc,void * req1,size_t req1len,void * req2,size_t req2len,void * resp,size_t resplen)448*1ea0721eSAndrew Turner vtgpu_req_resp2(struct vtgpu_softc *sc, void *req1, size_t req1len,
449*1ea0721eSAndrew Turner void *req2, size_t req2len, void *resp, size_t resplen)
45002f27066SAndrew Turner {
45102f27066SAndrew Turner struct sglist sg;
452*1ea0721eSAndrew Turner struct sglist_seg segs[3];
453*1ea0721eSAndrew Turner int error, rcount;
45402f27066SAndrew Turner
455*1ea0721eSAndrew Turner sglist_init(&sg, 3, segs);
45602f27066SAndrew Turner
457*1ea0721eSAndrew Turner rcount = 1;
458*1ea0721eSAndrew Turner error = sglist_append(&sg, req1, req1len);
45902f27066SAndrew Turner if (error != 0) {
46002f27066SAndrew Turner device_printf(sc->vtgpu_dev,
461*1ea0721eSAndrew Turner "Unable to append the request to the sglist: %d\n",
462*1ea0721eSAndrew Turner error);
46302f27066SAndrew Turner return (error);
46402f27066SAndrew Turner }
465*1ea0721eSAndrew Turner if (req2 != NULL) {
466*1ea0721eSAndrew Turner error = sglist_append(&sg, req2, req2len);
467*1ea0721eSAndrew Turner if (error != 0) {
468*1ea0721eSAndrew Turner device_printf(sc->vtgpu_dev,
469*1ea0721eSAndrew Turner "Unable to append the request to the sglist: %d\n",
470*1ea0721eSAndrew Turner error);
471*1ea0721eSAndrew Turner return (error);
472*1ea0721eSAndrew Turner }
473*1ea0721eSAndrew Turner rcount++;
474*1ea0721eSAndrew Turner }
47502f27066SAndrew Turner error = sglist_append(&sg, resp, resplen);
47602f27066SAndrew Turner if (error != 0) {
47702f27066SAndrew Turner device_printf(sc->vtgpu_dev,
47802f27066SAndrew Turner "Unable to append the response buffer to the sglist: %d\n",
47902f27066SAndrew Turner error);
48002f27066SAndrew Turner return (error);
48102f27066SAndrew Turner }
482*1ea0721eSAndrew Turner error = virtqueue_enqueue(sc->vtgpu_ctrl_vq, resp, &sg, rcount, 1);
48302f27066SAndrew Turner if (error != 0) {
48402f27066SAndrew Turner device_printf(sc->vtgpu_dev, "Enqueue failed: %d\n", error);
48502f27066SAndrew Turner return (error);
48602f27066SAndrew Turner }
48702f27066SAndrew Turner
48802f27066SAndrew Turner virtqueue_notify(sc->vtgpu_ctrl_vq);
48902f27066SAndrew Turner virtqueue_poll(sc->vtgpu_ctrl_vq, NULL);
49002f27066SAndrew Turner
49102f27066SAndrew Turner return (0);
49202f27066SAndrew Turner }
49302f27066SAndrew Turner
49402f27066SAndrew Turner static int
vtgpu_req_resp(struct vtgpu_softc * sc,void * req,size_t reqlen,void * resp,size_t resplen)495*1ea0721eSAndrew Turner vtgpu_req_resp(struct vtgpu_softc *sc, void *req, size_t reqlen,
496*1ea0721eSAndrew Turner void *resp, size_t resplen)
497*1ea0721eSAndrew Turner {
498*1ea0721eSAndrew Turner return (vtgpu_req_resp2(sc, req, reqlen, NULL, 0, resp, resplen));
499*1ea0721eSAndrew Turner }
500*1ea0721eSAndrew Turner
501*1ea0721eSAndrew Turner static int
vtgpu_get_display_info(struct vtgpu_softc * sc)50202f27066SAndrew Turner vtgpu_get_display_info(struct vtgpu_softc *sc)
50302f27066SAndrew Turner {
50402f27066SAndrew Turner struct {
50502f27066SAndrew Turner struct virtio_gpu_ctrl_hdr req;
50602f27066SAndrew Turner char pad;
50702f27066SAndrew Turner struct virtio_gpu_resp_display_info resp;
50802f27066SAndrew Turner } s = { 0 };
50902f27066SAndrew Turner int error;
51002f27066SAndrew Turner
51102f27066SAndrew Turner s.req.type = htole32(VIRTIO_GPU_CMD_GET_DISPLAY_INFO);
51202f27066SAndrew Turner s.req.flags = htole32(VIRTIO_GPU_FLAG_FENCE);
51302f27066SAndrew Turner s.req.fence_id = htole64(atomic_fetchadd_64(&sc->vtgpu_next_fence, 1));
51402f27066SAndrew Turner
51502f27066SAndrew Turner error = vtgpu_req_resp(sc, &s.req, sizeof(s.req), &s.resp,
51602f27066SAndrew Turner sizeof(s.resp));
51702f27066SAndrew Turner if (error != 0)
51802f27066SAndrew Turner return (error);
51902f27066SAndrew Turner
52002f27066SAndrew Turner for (int i = 0; i < sc->vtgpu_gpucfg.num_scanouts; i++) {
52102f27066SAndrew Turner if (s.resp.pmodes[i].enabled != 0)
52202f27066SAndrew Turner MPASS(i == 0);
52302f27066SAndrew Turner sc->vtgpu_fb_info.fb_name =
52402f27066SAndrew Turner device_get_nameunit(sc->vtgpu_dev);
52502f27066SAndrew Turner
52602f27066SAndrew Turner sc->vtgpu_fb_info.fb_width =
52702f27066SAndrew Turner le32toh(s.resp.pmodes[i].r.width);
52802f27066SAndrew Turner sc->vtgpu_fb_info.fb_height =
52902f27066SAndrew Turner le32toh(s.resp.pmodes[i].r.height);
53002f27066SAndrew Turner /* 32 bits per pixel */
53102f27066SAndrew Turner sc->vtgpu_fb_info.fb_bpp = 32;
53202f27066SAndrew Turner sc->vtgpu_fb_info.fb_depth = 32;
53302f27066SAndrew Turner sc->vtgpu_fb_info.fb_size = sc->vtgpu_fb_info.fb_width *
53402f27066SAndrew Turner sc->vtgpu_fb_info.fb_height * 4;
53502f27066SAndrew Turner sc->vtgpu_fb_info.fb_stride =
53602f27066SAndrew Turner sc->vtgpu_fb_info.fb_width * 4;
53702f27066SAndrew Turner return (0);
53802f27066SAndrew Turner }
53902f27066SAndrew Turner
54002f27066SAndrew Turner return (ENXIO);
54102f27066SAndrew Turner }
54202f27066SAndrew Turner
54302f27066SAndrew Turner static int
vtgpu_create_2d(struct vtgpu_softc * sc)54402f27066SAndrew Turner vtgpu_create_2d(struct vtgpu_softc *sc)
54502f27066SAndrew Turner {
54602f27066SAndrew Turner struct {
54702f27066SAndrew Turner struct virtio_gpu_resource_create_2d req;
54802f27066SAndrew Turner char pad;
54902f27066SAndrew Turner struct virtio_gpu_ctrl_hdr resp;
55002f27066SAndrew Turner } s = { 0 };
55102f27066SAndrew Turner int error;
55202f27066SAndrew Turner
55302f27066SAndrew Turner s.req.hdr.type = htole32(VIRTIO_GPU_CMD_RESOURCE_CREATE_2D);
55402f27066SAndrew Turner s.req.hdr.flags = htole32(VIRTIO_GPU_FLAG_FENCE);
55502f27066SAndrew Turner s.req.hdr.fence_id = htole64(
55602f27066SAndrew Turner atomic_fetchadd_64(&sc->vtgpu_next_fence, 1));
55702f27066SAndrew Turner
55802f27066SAndrew Turner s.req.resource_id = htole32(VTGPU_RESOURCE_ID);
55902f27066SAndrew Turner s.req.format = htole32(VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM);
56002f27066SAndrew Turner s.req.width = htole32(sc->vtgpu_fb_info.fb_width);
56102f27066SAndrew Turner s.req.height = htole32(sc->vtgpu_fb_info.fb_height);
56202f27066SAndrew Turner
56302f27066SAndrew Turner error = vtgpu_req_resp(sc, &s.req, sizeof(s.req), &s.resp,
56402f27066SAndrew Turner sizeof(s.resp));
56502f27066SAndrew Turner if (error != 0)
56602f27066SAndrew Turner return (error);
56702f27066SAndrew Turner
56802f27066SAndrew Turner if (s.resp.type != htole32(VIRTIO_GPU_RESP_OK_NODATA)) {
569e9058e14SGordon Bergling device_printf(sc->vtgpu_dev, "Invalid response type %x\n",
57002f27066SAndrew Turner le32toh(s.resp.type));
57102f27066SAndrew Turner return (EINVAL);
57202f27066SAndrew Turner }
57302f27066SAndrew Turner
57402f27066SAndrew Turner return (0);
57502f27066SAndrew Turner }
57602f27066SAndrew Turner
57702f27066SAndrew Turner static int
vtgpu_attach_backing(struct vtgpu_softc * sc)57802f27066SAndrew Turner vtgpu_attach_backing(struct vtgpu_softc *sc)
57902f27066SAndrew Turner {
58002f27066SAndrew Turner struct {
581*1ea0721eSAndrew Turner /*
582*1ea0721eSAndrew Turner * Split the backing and mem request arguments as some
583*1ea0721eSAndrew Turner * hypervisors, e.g. Parallels Desktop, don't work when
584*1ea0721eSAndrew Turner * they are enqueued together.
585*1ea0721eSAndrew Turner */
58602f27066SAndrew Turner struct {
58702f27066SAndrew Turner struct virtio_gpu_resource_attach_backing backing;
588*1ea0721eSAndrew Turner char pad;
589*1ea0721eSAndrew Turner struct virtio_gpu_mem_entry mem;
59002f27066SAndrew Turner } req;
59102f27066SAndrew Turner char pad;
59202f27066SAndrew Turner struct virtio_gpu_ctrl_hdr resp;
59302f27066SAndrew Turner } s = { 0 };
59402f27066SAndrew Turner int error;
59502f27066SAndrew Turner
59602f27066SAndrew Turner s.req.backing.hdr.type =
59702f27066SAndrew Turner htole32(VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING);
59802f27066SAndrew Turner s.req.backing.hdr.flags = htole32(VIRTIO_GPU_FLAG_FENCE);
59902f27066SAndrew Turner s.req.backing.hdr.fence_id = htole64(
60002f27066SAndrew Turner atomic_fetchadd_64(&sc->vtgpu_next_fence, 1));
60102f27066SAndrew Turner
60202f27066SAndrew Turner s.req.backing.resource_id = htole32(VTGPU_RESOURCE_ID);
60302f27066SAndrew Turner s.req.backing.nr_entries = htole32(1);
60402f27066SAndrew Turner
605*1ea0721eSAndrew Turner s.req.mem.addr = htole64(sc->vtgpu_fb_info.fb_pbase);
606*1ea0721eSAndrew Turner s.req.mem.length = htole32(sc->vtgpu_fb_info.fb_size);
60702f27066SAndrew Turner
608*1ea0721eSAndrew Turner error = vtgpu_req_resp2(sc, &s.req.backing, sizeof(s.req.backing),
609*1ea0721eSAndrew Turner &s.req.mem, sizeof(s.req.mem), &s.resp, sizeof(s.resp));
61002f27066SAndrew Turner if (error != 0)
61102f27066SAndrew Turner return (error);
61202f27066SAndrew Turner
61302f27066SAndrew Turner if (s.resp.type != htole32(VIRTIO_GPU_RESP_OK_NODATA)) {
614e9058e14SGordon Bergling device_printf(sc->vtgpu_dev, "Invalid response type %x\n",
61502f27066SAndrew Turner le32toh(s.resp.type));
61602f27066SAndrew Turner return (EINVAL);
61702f27066SAndrew Turner }
61802f27066SAndrew Turner
61902f27066SAndrew Turner return (0);
62002f27066SAndrew Turner }
62102f27066SAndrew Turner
62202f27066SAndrew Turner static int
vtgpu_set_scanout(struct vtgpu_softc * sc,uint32_t x,uint32_t y,uint32_t width,uint32_t height)62302f27066SAndrew Turner vtgpu_set_scanout(struct vtgpu_softc *sc, uint32_t x, uint32_t y,
62402f27066SAndrew Turner uint32_t width, uint32_t height)
62502f27066SAndrew Turner {
62602f27066SAndrew Turner struct {
62702f27066SAndrew Turner struct virtio_gpu_set_scanout req;
62802f27066SAndrew Turner char pad;
62902f27066SAndrew Turner struct virtio_gpu_ctrl_hdr resp;
63002f27066SAndrew Turner } s = { 0 };
63102f27066SAndrew Turner int error;
63202f27066SAndrew Turner
63302f27066SAndrew Turner s.req.hdr.type = htole32(VIRTIO_GPU_CMD_SET_SCANOUT);
63402f27066SAndrew Turner s.req.hdr.flags = htole32(VIRTIO_GPU_FLAG_FENCE);
63502f27066SAndrew Turner s.req.hdr.fence_id = htole64(
63602f27066SAndrew Turner atomic_fetchadd_64(&sc->vtgpu_next_fence, 1));
63702f27066SAndrew Turner
63802f27066SAndrew Turner s.req.r.x = htole32(x);
63902f27066SAndrew Turner s.req.r.y = htole32(y);
64002f27066SAndrew Turner s.req.r.width = htole32(width);
64102f27066SAndrew Turner s.req.r.height = htole32(height);
64202f27066SAndrew Turner
64302f27066SAndrew Turner s.req.scanout_id = 0;
64402f27066SAndrew Turner s.req.resource_id = htole32(VTGPU_RESOURCE_ID);
64502f27066SAndrew Turner
64602f27066SAndrew Turner error = vtgpu_req_resp(sc, &s.req, sizeof(s.req), &s.resp,
64702f27066SAndrew Turner sizeof(s.resp));
64802f27066SAndrew Turner if (error != 0)
64902f27066SAndrew Turner return (error);
65002f27066SAndrew Turner
65102f27066SAndrew Turner if (s.resp.type != htole32(VIRTIO_GPU_RESP_OK_NODATA)) {
652e9058e14SGordon Bergling device_printf(sc->vtgpu_dev, "Invalid response type %x\n",
65302f27066SAndrew Turner le32toh(s.resp.type));
65402f27066SAndrew Turner return (EINVAL);
65502f27066SAndrew Turner }
65602f27066SAndrew Turner
65702f27066SAndrew Turner return (0);
65802f27066SAndrew Turner }
65902f27066SAndrew Turner
66002f27066SAndrew Turner static int
vtgpu_transfer_to_host_2d(struct vtgpu_softc * sc,uint32_t x,uint32_t y,uint32_t width,uint32_t height)66102f27066SAndrew Turner vtgpu_transfer_to_host_2d(struct vtgpu_softc *sc, uint32_t x, uint32_t y,
66202f27066SAndrew Turner uint32_t width, uint32_t height)
66302f27066SAndrew Turner {
66402f27066SAndrew Turner struct {
66502f27066SAndrew Turner struct virtio_gpu_transfer_to_host_2d req;
66602f27066SAndrew Turner char pad;
66702f27066SAndrew Turner struct virtio_gpu_ctrl_hdr resp;
66802f27066SAndrew Turner } s = { 0 };
66902f27066SAndrew Turner int error;
67002f27066SAndrew Turner
67102f27066SAndrew Turner s.req.hdr.type = htole32(VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D);
67202f27066SAndrew Turner s.req.hdr.flags = htole32(VIRTIO_GPU_FLAG_FENCE);
67302f27066SAndrew Turner s.req.hdr.fence_id = htole64(
67402f27066SAndrew Turner atomic_fetchadd_64(&sc->vtgpu_next_fence, 1));
67502f27066SAndrew Turner
67602f27066SAndrew Turner s.req.r.x = htole32(x);
67702f27066SAndrew Turner s.req.r.y = htole32(y);
67802f27066SAndrew Turner s.req.r.width = htole32(width);
67902f27066SAndrew Turner s.req.r.height = htole32(height);
68002f27066SAndrew Turner
68102f27066SAndrew Turner s.req.offset = htole64((y * sc->vtgpu_fb_info.fb_width + x)
68202f27066SAndrew Turner * (sc->vtgpu_fb_info.fb_bpp / 8));
68302f27066SAndrew Turner s.req.resource_id = htole32(VTGPU_RESOURCE_ID);
68402f27066SAndrew Turner
68502f27066SAndrew Turner error = vtgpu_req_resp(sc, &s.req, sizeof(s.req), &s.resp,
68602f27066SAndrew Turner sizeof(s.resp));
68702f27066SAndrew Turner if (error != 0)
68802f27066SAndrew Turner return (error);
68902f27066SAndrew Turner
69002f27066SAndrew Turner if (s.resp.type != htole32(VIRTIO_GPU_RESP_OK_NODATA)) {
691e9058e14SGordon Bergling device_printf(sc->vtgpu_dev, "Invalid response type %x\n",
69202f27066SAndrew Turner le32toh(s.resp.type));
69302f27066SAndrew Turner return (EINVAL);
69402f27066SAndrew Turner }
69502f27066SAndrew Turner
69602f27066SAndrew Turner return (0);
69702f27066SAndrew Turner }
69802f27066SAndrew Turner
69902f27066SAndrew Turner static int
vtgpu_resource_flush(struct vtgpu_softc * sc,uint32_t x,uint32_t y,uint32_t width,uint32_t height)70002f27066SAndrew Turner vtgpu_resource_flush(struct vtgpu_softc *sc, uint32_t x, uint32_t y,
70102f27066SAndrew Turner uint32_t width, uint32_t height)
70202f27066SAndrew Turner {
70302f27066SAndrew Turner struct {
70402f27066SAndrew Turner struct virtio_gpu_resource_flush req;
70502f27066SAndrew Turner char pad;
70602f27066SAndrew Turner struct virtio_gpu_ctrl_hdr resp;
70702f27066SAndrew Turner } s = { 0 };
70802f27066SAndrew Turner int error;
70902f27066SAndrew Turner
71002f27066SAndrew Turner s.req.hdr.type = htole32(VIRTIO_GPU_CMD_RESOURCE_FLUSH);
71102f27066SAndrew Turner s.req.hdr.flags = htole32(VIRTIO_GPU_FLAG_FENCE);
71202f27066SAndrew Turner s.req.hdr.fence_id = htole64(
71302f27066SAndrew Turner atomic_fetchadd_64(&sc->vtgpu_next_fence, 1));
71402f27066SAndrew Turner
71502f27066SAndrew Turner s.req.r.x = htole32(x);
71602f27066SAndrew Turner s.req.r.y = htole32(y);
71702f27066SAndrew Turner s.req.r.width = htole32(width);
71802f27066SAndrew Turner s.req.r.height = htole32(height);
71902f27066SAndrew Turner
72002f27066SAndrew Turner s.req.resource_id = htole32(VTGPU_RESOURCE_ID);
72102f27066SAndrew Turner
72202f27066SAndrew Turner error = vtgpu_req_resp(sc, &s.req, sizeof(s.req), &s.resp,
72302f27066SAndrew Turner sizeof(s.resp));
72402f27066SAndrew Turner if (error != 0)
72502f27066SAndrew Turner return (error);
72602f27066SAndrew Turner
72702f27066SAndrew Turner if (s.resp.type != htole32(VIRTIO_GPU_RESP_OK_NODATA)) {
728e9058e14SGordon Bergling device_printf(sc->vtgpu_dev, "Invalid response type %x\n",
72902f27066SAndrew Turner le32toh(s.resp.type));
73002f27066SAndrew Turner return (EINVAL);
73102f27066SAndrew Turner }
73202f27066SAndrew Turner
73302f27066SAndrew Turner return (0);
73402f27066SAndrew Turner }
735