Hi Jiaxun, On Wed, 17 Jul 2024 at 15:34, Jiaxun Yang <jiaxun.y...@flygoat.com> wrote: > > > > 在2024年5月24日五月 下午9:02,Jiaxun Yang写道: > > This driver is implemened based on latest VirtIO spec. > > It follows operation prodcure as defined in the spec. > > > > It implemented multihead (mirroring) support as well. > > > > Signed-off-by: Jiaxun Yang <jiaxun.y...@flygoat.com> > > Ping > > > --- > > v2: > > - Add big endian code path > > - Reword typical resolution for Kconfig symbol > > --- > > drivers/virtio/Kconfig | 29 +++ > > drivers/virtio/Makefile | 1 + > > drivers/virtio/virtio-uclass.c | 1 + > > drivers/virtio/virtio_gpu.c | 302 +++++++++++++++++++++++++++++ > > drivers/virtio/virtio_gpu.h | 428 > > +++++++++++++++++++++++++++++++++++++++++ > > include/virtio.h | 4 +- > > 6 files changed, 764 insertions(+), 1 deletion(-)
Reviewed-by: Simon Glass <s...@chromium.org> Nits below > > > > diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig > > index 1de68867d52e..a4838278fabc 100644 > > --- a/drivers/virtio/Kconfig > > +++ b/drivers/virtio/Kconfig > > @@ -76,4 +76,33 @@ config VIRTIO_RNG > > help > > This is the virtual random number generator driver. It can be used > > with QEMU based targets. > > + > > + config VIRTIO_GPU > > + bool "virtio GPU driver" > > + depends on VIRTIO && VIDEO > > + default y > > + help > > + This is the virtual GPU display for virtio. It can be used with QEMU > > + based targets. QEMU-based Can you add a bit more info about its capabilities? Should we be using this instead of Bochs? > > + > > +if VIRTIO_GPU > > +config VIRTIO_GPU_SIZE_X > > + int "Width of display (X resolution)" > > + default 1280 > > + help > > + Sets the width of the display. > > + > > + These two options control the size of the display set up by QEMU. > > + Typical size is 1280 x 1024 for compatibility. > > + > > +config VIRTIO_GPU_SIZE_Y > > + int "High of display (Y resolution)" Height > > + default 1024 > > + help > > + Sets the height of the display. > > + > > + These two options control the size of the display set up by QEMU. > > + Typical size is 1280 x 1024 for compatibility. > > + > > +endif > > endmenu > > diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile > > index 4c63a6c69043..c830fb6e6049 100644 > > --- a/drivers/virtio/Makefile > > +++ b/drivers/virtio/Makefile > > @@ -11,3 +11,4 @@ obj-$(CONFIG_VIRTIO_SANDBOX) += virtio_sandbox.o > > obj-$(CONFIG_VIRTIO_NET) += virtio_net.o > > obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o > > obj-$(CONFIG_VIRTIO_RNG) += virtio_rng.o > > +obj-$(CONFIG_VIRTIO_GPU) += virtio_gpu.o > > diff --git a/drivers/virtio/virtio-uclass.c > > b/drivers/virtio/virtio-uclass.c > > index 1dbc1a56aa21..1f3cdbf689c4 100644 > > --- a/drivers/virtio/virtio-uclass.c > > +++ b/drivers/virtio/virtio-uclass.c > > @@ -30,6 +30,7 @@ static const char *const > > virtio_drv_name[VIRTIO_ID_MAX_NUM] = { > > [VIRTIO_ID_NET] = VIRTIO_NET_DRV_NAME, > > [VIRTIO_ID_BLOCK] = VIRTIO_BLK_DRV_NAME, > > [VIRTIO_ID_RNG] = VIRTIO_RNG_DRV_NAME, > > + [VIRTIO_ID_GPU] = VIRTIO_GPU_DRV_NAME, > > }; > > > > int virtio_get_config(struct udevice *vdev, unsigned int offset, > > diff --git a/drivers/virtio/virtio_gpu.c b/drivers/virtio/virtio_gpu.c > > new file mode 100644 > > index 000000000000..0b306bb9d2fa > > --- /dev/null > > +++ b/drivers/virtio/virtio_gpu.c > > @@ -0,0 +1,302 @@ > > +// SPDX-License-Identifier: GPL-2.0+ > > +/* > > + * Copyright (C) 2024, Jiaxun Yang <jiaxun.y...@flygoat.com> > > + */ > > + > > +#define pr_fmt(fmt) "virtio_gpu: " fmt > > + > > +#include <dm.h> > > +#include <log.h> > > +#include <malloc.h> > > +#include <video.h> > > +#include <virtio_types.h> > > +#include <virtio.h> > > +#include <virtio_ring.h> > > +#include "virtio_gpu.h" > > +#include <asm/io.h> > > + > > +struct virtio_gpu_priv { > > + struct virtqueue *vq; > > + u32 scanout_res_id; > > + u64 fence_id; > > + bool in_sync; > > +}; > > + > > +static int virtio_gpu_do_req(struct udevice *dev, > > + enum virtio_gpu_ctrl_type type, > > + void *in, size_t in_size, > > + void *out, size_t out_size, bool flush) Please add a function comment > > +{ > > + int ret; > > + uint len; > > + struct virtio_gpu_priv *priv = dev_get_priv(dev); > > + struct virtio_sg in_sg; > > + struct virtio_sg out_sg; > > + struct virtio_sg *sgs[] = { &in_sg, &out_sg }; > > + struct virtio_gpu_ctrl_hdr *ctrl_hdr_in = in; > > + struct virtio_gpu_ctrl_hdr *ctrl_hdr_out = out; > > + > > + ctrl_hdr_in->type = cpu_to_virtio32(dev, (u32)type); > > + if (flush) { > > + ctrl_hdr_in->flags = cpu_to_virtio32(dev, > > VIRTIO_GPU_FLAG_FENCE); > > + ctrl_hdr_in->fence_id = cpu_to_virtio64(dev, > > priv->fence_id++); > > + } else { > > + ctrl_hdr_in->flags = 0; > > + ctrl_hdr_in->fence_id = 0; > > + } > > + ctrl_hdr_in->ctx_id = 0; > > + ctrl_hdr_in->ring_idx = 0; > > + in_sg.addr = in; > > + in_sg.length = in_size; > > + out_sg.addr = out; > > + out_sg.length = out_size; > > + > > + ret = virtqueue_add(priv->vq, sgs, 1, 1); > > + if (ret) { > > + log_debug("virtqueue_add failed %d\n", ret); > > + return ret; > > + } > > + virtqueue_kick(priv->vq); > > + > > + debug("wait..."); > > + while (!virtqueue_get_buf(priv->vq, &len)) > > + ; > > + debug("done\n"); > > + > > + if (out_size != len) { > > + log_debug("Invalid response size %d, expected %d\n", > > + len, (uint)out_size); > > + } > > + > > + return virtio32_to_cpu(dev, ctrl_hdr_out->type); > > +} > > + > > +static int virtio_gpu_probe(struct udevice *dev) > > +{ > > + struct virtio_gpu_priv *priv = dev_get_priv(dev); > > + struct video_uc_plat *plat = dev_get_uclass_plat(dev); > > + struct video_priv *uc_priv = dev_get_uclass_priv(dev); > > + struct virtio_gpu_ctrl_hdr ctrl_hdr_in; > > + struct virtio_gpu_ctrl_hdr ctrl_hdr_out; > > + struct virtio_gpu_resp_display_info *disp_info_out; > > + struct virtio_gpu_display_one *disp; > > + struct virtio_gpu_resource_create_2d *res_create_2d_in; > > + void *res_buf_in; > > + struct virtio_gpu_resource_attach_backing *res_attach_backing_in; > > + struct virtio_gpu_mem_entry *mem_entry; > > + struct virtio_gpu_set_scanout *set_scanout_in; > > + unsigned int scanout_mask = 0; > > + int ret, i; > > + > > + if (!plat->base) { > > + log_warning("No framebuffer allocated\n"); > > + return -EINVAL; > > + } > > + > > + ret = virtio_find_vqs(dev, 1, &priv->vq); > > + if (ret < 0) { > > + log_warning("virtio_find_vqs failed\n"); > > + return ret; > > + } > > + > > + disp_info_out = malloc(sizeof(struct virtio_gpu_resp_display_info)); > > + ret = virtio_gpu_do_req(dev, VIRTIO_GPU_CMD_GET_DISPLAY_INFO, > > &ctrl_hdr_in, > > + sizeof(struct virtio_gpu_ctrl_hdr), > > disp_info_out, > > + sizeof(struct virtio_gpu_resp_display_info), > > false); > > + > > + if (ret != VIRTIO_GPU_RESP_OK_DISPLAY_INFO) { > > + log_warning("CMD_GET_DISPLAY_INFO failed %d\n", ret); > > + ret = -EINVAL; > > + goto out_free_disp; > > + } > > + > > + for (i = 0; i < VIRTIO_GPU_MAX_SCANOUTS; i++) { > > + disp = &disp_info_out->pmodes[i]; > > + if (!disp->enabled) > > + continue; > > + log_debug("Found available scanout: %d\n", i); > > + scanout_mask |= 1 << i; > > + } > > + > > + if (!scanout_mask) { > > + log_warning("No active scanout found\n"); > > + ret = -EINVAL; > > + goto out_free_disp; > > + } > > + > > + free(disp_info_out); > > + disp_info_out = NULL; > > + > > + /* TODO: We can parse EDID for those info */ > > + uc_priv->xsize = CONFIG_VAL(VIRTIO_GPU_SIZE_X); > > + uc_priv->ysize = CONFIG_VAL(VIRTIO_GPU_SIZE_Y); > > + uc_priv->bpix = VIDEO_BPP32; > > + > > + priv->scanout_res_id = 1; > > + res_create_2d_in = malloc(sizeof(struct > > virtio_gpu_resource_create_2d)); > > + res_create_2d_in->resource_id = cpu_to_virtio32(dev, > > priv->scanout_res_id); > > +#ifdef __BIG_ENDIAN > > + res_create_2d_in->format = cpu_to_virtio32(dev, > > VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM); > > +#else > > + res_create_2d_in->format = cpu_to_virtio32(dev, > > VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM); > > +#endif > > + res_create_2d_in->width = cpu_to_virtio32(dev, uc_priv->xsize); > > + res_create_2d_in->height = cpu_to_virtio32(dev, uc_priv->ysize); > > + > > + ret = virtio_gpu_do_req(dev, VIRTIO_GPU_CMD_RESOURCE_CREATE_2D, > > res_create_2d_in, > > + sizeof(struct virtio_gpu_resource_create_2d), > > &ctrl_hdr_out, > > + sizeof(struct virtio_gpu_ctrl_hdr), false); > > + if (ret != VIRTIO_GPU_RESP_OK_NODATA) { > > + log_warning("CMD_RESOURCE_CREATE_2D failed %d\n", ret); > > + ret = -EINVAL; > > + goto out_free_res_create_2d; > > + } > > + > > + free(res_create_2d_in); > > + res_create_2d_in = NULL; > > + > > + res_buf_in = malloc(sizeof(struct virtio_gpu_resource_attach_backing) > > + > > + sizeof(struct virtio_gpu_mem_entry)); > > + res_attach_backing_in = res_buf_in; > > + mem_entry = res_buf_in + sizeof(struct > > virtio_gpu_resource_attach_backing); > > + res_attach_backing_in->resource_id = cpu_to_virtio32(dev, > > priv->scanout_res_id); > > + res_attach_backing_in->nr_entries = cpu_to_virtio32(dev, 1); > > + mem_entry->addr = cpu_to_virtio64(dev, virt_to_phys((void > > *)plat->base)); > > + mem_entry->length = cpu_to_virtio32(dev, plat->size); > > + mem_entry->padding = 0; > > + > > + ret = virtio_gpu_do_req(dev, VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING, > > res_buf_in, > > + sizeof(struct > > virtio_gpu_resource_attach_backing) + > > + sizeof(struct virtio_gpu_mem_entry), > > &ctrl_hdr_out, > > + sizeof(struct virtio_gpu_ctrl_hdr), false); > > + > > + if (ret != VIRTIO_GPU_RESP_OK_NODATA) { > > + log_warning("CMD_RESOURCE_ATTACH_BACKING failed %d\n", ret); > > + ret = -EINVAL; > > + goto out_free_res_buf; > > + } > > + free(res_buf_in); > > + res_buf_in = NULL; > > + > > + set_scanout_in = malloc(sizeof(struct virtio_gpu_set_scanout)); Could these structs be inside priv instead of allocating each one? > > + while (scanout_mask) { > > + u32 active_scanout = ffs(scanout_mask) - 1; > > + > > + set_scanout_in->r.x = 0; > > + set_scanout_in->r.y = 0; > > + set_scanout_in->r.width = cpu_to_virtio32(dev, > > uc_priv->xsize); > > + set_scanout_in->r.height = cpu_to_virtio32(dev, > > uc_priv->ysize); > > + set_scanout_in->scanout_id = cpu_to_virtio32(dev, > > active_scanout); > > + set_scanout_in->resource_id = cpu_to_virtio32(dev, > > priv->scanout_res_id); > > + > > + ret = virtio_gpu_do_req(dev, VIRTIO_GPU_CMD_SET_SCANOUT, > > set_scanout_in, > > + sizeof(struct > > virtio_gpu_set_scanout), &ctrl_hdr_out, > > + sizeof(struct virtio_gpu_ctrl_hdr), > > false); > > + > > + if (ret != VIRTIO_GPU_RESP_OK_NODATA) { > > + log_warning("CMD_SET_SCANOUT failed %d for scanout > > %d\n", > > + ret, active_scanout); > > + ret = -EINVAL; > > + goto out_free_set_scanout; > > + } > > + scanout_mask &= ~(1 << active_scanout); > > + } > > + free(set_scanout_in); > > + set_scanout_in = NULL; > > + > > + return 0; > > +out_free_set_scanout: > > + if (set_scanout_in) > > + free(set_scanout_in); > > +out_free_res_buf: > > + if (res_buf_in) > > + free(res_buf_in); > > +out_free_res_create_2d: > > + if (res_create_2d_in) > > + free(res_create_2d_in); > > +out_free_disp: > > + if (disp_info_out) > > + free(disp_info_out); > > + return ret; > > +} > > + > > +static int virtio_gpu_bind(struct udevice *dev) > > +{ > > + struct virtio_dev_priv *virtio_uc_priv = > > dev_get_uclass_priv(dev->parent); > > + struct video_uc_plat *plat = dev_get_uclass_plat(dev); > > + > > + /* Indicate what driver features we support */ > > + virtio_driver_features_init(virtio_uc_priv, NULL, 0, NULL, 0); > > + plat->base = 0; /* Framebuffer will be allocated by the video-uclass > > */ > > + plat->size = CONFIG_VAL(VIRTIO_GPU_SIZE_X) * > > + CONFIG_VAL(VIRTIO_GPU_SIZE_X) * VNBYTES(VIDEO_BPP32); > > + > > + return 0; > > +} > > + > > +static int virtio_gpu_video_sync(struct udevice *dev) > > +{ > > + struct virtio_gpu_priv *priv = dev_get_priv(dev); > > + struct video_priv *uc_priv = dev_get_uclass_priv(dev); > > + struct virtio_gpu_transfer_to_host_2d to_host_2d_in; > > + struct virtio_gpu_resource_flush res_flush_in; > > + struct virtio_gpu_ctrl_hdr ctrl_hdr_out; > > + int ret; > > + > > + /* We need to protect sync function reentrance to prevent exausting > > VQ */ > > + if (priv->in_sync) > > + return 0; > > + > > + priv->in_sync = true; > > + > > + to_host_2d_in.r.x = 0; > > + to_host_2d_in.r.y = 0; > > + to_host_2d_in.r.width = cpu_to_virtio32(dev, uc_priv->xsize); > > + to_host_2d_in.r.height = cpu_to_virtio32(dev, uc_priv->ysize); > > + to_host_2d_in.offset = 0; > > + to_host_2d_in.resource_id = cpu_to_virtio32(dev, > > priv->scanout_res_id); > > + to_host_2d_in.padding = 0; > > + > > + ret = virtio_gpu_do_req(dev, VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D, > > &to_host_2d_in, > > + sizeof(struct > > virtio_gpu_transfer_to_host_2d), &ctrl_hdr_out, > > + sizeof(struct virtio_gpu_ctrl_hdr), true); > > + if (ret != VIRTIO_GPU_RESP_OK_NODATA) { > > + log_debug("CMD_TRANSFER_TO_HOST_2D failed %d\n", ret); > > + priv->in_sync = false; > > + return -EINVAL; > > + } > > + > > + res_flush_in.r.x = 0; > > + res_flush_in.r.y = 0; > > + res_flush_in.r.width = cpu_to_virtio32(dev, uc_priv->xsize); > > + res_flush_in.r.height = cpu_to_virtio32(dev, uc_priv->ysize); > > + res_flush_in.resource_id = cpu_to_virtio32(dev, priv->scanout_res_id); > > + res_flush_in.padding = 0; > > + > > + ret = virtio_gpu_do_req(dev, VIRTIO_GPU_CMD_RESOURCE_FLUSH, > > &res_flush_in, > > + sizeof(struct virtio_gpu_resource_flush), > > &ctrl_hdr_out, > > + sizeof(struct virtio_gpu_ctrl_hdr), true); > > + if (ret != VIRTIO_GPU_RESP_OK_NODATA) { > > + log_debug("CMD_RESOURCE_FLUSH failed %d\n", ret); > > + priv->in_sync = false; > > + return -EINVAL; > > + } > > + > > + priv->in_sync = false; > > + return 0; > > +} > > + > > +static struct video_ops virtio_gpu_ops = { > > + .video_sync = virtio_gpu_video_sync, > > +}; > > + > > +U_BOOT_DRIVER(virtio_gpu) = { > > + .name = VIRTIO_GPU_DRV_NAME, > > + .id = UCLASS_VIDEO, > > + .bind = virtio_gpu_bind, > > + .probe = virtio_gpu_probe, > > + .remove = virtio_reset, > > + .ops = &virtio_gpu_ops, > > + .priv_auto = sizeof(struct virtio_gpu_priv), > > + .flags = DM_FLAG_ACTIVE_DMA, > > +}; > > diff --git a/drivers/virtio/virtio_gpu.h b/drivers/virtio/virtio_gpu.h > > new file mode 100644 > > index 000000000000..d2e5c0e02f13 > > --- /dev/null > > +++ b/drivers/virtio/virtio_gpu.h > > @@ -0,0 +1,428 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause */ > > +/* > > + * Copyright (C) 2024, Jiaxun Yang <jiaxun.y...@flygoat.com> > > + * > > + * From Linux kernel include/uapi/linux/virtio_gpu.h > > + */ > > + > > +#ifndef VIRTIO_GPU_HW_H > > +#define VIRTIO_GPU_HW_H > > + > > +#include <linux/types.h> > > + > > +/* > > + * VIRTIO_GPU_CMD_CTX_* > > + * VIRTIO_GPU_CMD_*_3D > > + */ > > +#define VIRTIO_GPU_F_VIRGL 0 > > + > > +/* > > + * VIRTIO_GPU_CMD_GET_EDID > > + */ > > +#define VIRTIO_GPU_F_EDID 1 > > +/* > > + * VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID > > + */ > > +#define VIRTIO_GPU_F_RESOURCE_UUID 2 > > + > > +/* > > + * VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB > > + */ > > +#define VIRTIO_GPU_F_RESOURCE_BLOB 3 > > +/* > > + * VIRTIO_GPU_CMD_CREATE_CONTEXT with > > + * context_init and multiple timelines > > + */ > > +#define VIRTIO_GPU_F_CONTEXT_INIT 4 > > + > > +enum virtio_gpu_ctrl_type { > > + VIRTIO_GPU_UNDEFINED = 0, > > + > > + /* 2d commands */ > > + VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100, > > + VIRTIO_GPU_CMD_RESOURCE_CREATE_2D, > > + VIRTIO_GPU_CMD_RESOURCE_UNREF, > > + VIRTIO_GPU_CMD_SET_SCANOUT, > > + VIRTIO_GPU_CMD_RESOURCE_FLUSH, > > + VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D, > > + VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING, > > + VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING, > > + VIRTIO_GPU_CMD_GET_CAPSET_INFO, > > + VIRTIO_GPU_CMD_GET_CAPSET, > > + VIRTIO_GPU_CMD_GET_EDID, > > + VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID, > > + VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB, > > + VIRTIO_GPU_CMD_SET_SCANOUT_BLOB, > > + > > + /* 3d commands */ > > + VIRTIO_GPU_CMD_CTX_CREATE = 0x0200, > > + VIRTIO_GPU_CMD_CTX_DESTROY, > > + VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE, > > + VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE, > > + VIRTIO_GPU_CMD_RESOURCE_CREATE_3D, > > + VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D, > > + VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D, > > + VIRTIO_GPU_CMD_SUBMIT_3D, > > + VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB, > > + VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB, > > + > > + /* cursor commands */ > > + VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300, > > + VIRTIO_GPU_CMD_MOVE_CURSOR, > > + > > + /* success responses */ > > + VIRTIO_GPU_RESP_OK_NODATA = 0x1100, > > + VIRTIO_GPU_RESP_OK_DISPLAY_INFO, > > + VIRTIO_GPU_RESP_OK_CAPSET_INFO, > > + VIRTIO_GPU_RESP_OK_CAPSET, > > + VIRTIO_GPU_RESP_OK_EDID, > > + VIRTIO_GPU_RESP_OK_RESOURCE_UUID, > > + VIRTIO_GPU_RESP_OK_MAP_INFO, > > + > > + /* error responses */ > > + VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200, > > + VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY, > > + VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID, > > + VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID, > > + VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID, > > + VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER, > > +}; > > + > > +enum virtio_gpu_shm_id { > > + VIRTIO_GPU_SHM_ID_UNDEFINED = 0, > > + /* > > + * VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB > > + * VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB > > + */ > > + VIRTIO_GPU_SHM_ID_HOST_VISIBLE = 1 > > +}; > > + > > +#define VIRTIO_GPU_FLAG_FENCE (1 << 0) > > +/* > > + * If the following flag is set, then ring_idx contains the index > > + * of the command ring that needs to used when creating the fence > > + */ > > +#define VIRTIO_GPU_FLAG_INFO_RING_IDX (1 << 1) > > + > > +struct virtio_gpu_ctrl_hdr { > > + __le32 type; > > + __le32 flags; > > + __le64 fence_id; > > + __le32 ctx_id; > > + __u8 ring_idx; > > + __u8 padding[3]; > > +}; > > + > > +/* data passed in the cursor vq */ > > + > > +struct virtio_gpu_cursor_pos { > > + __le32 scanout_id; > > + __le32 x; > > + __le32 y; > > + __le32 padding; > > +}; > > + > > +/* VIRTIO_GPU_CMD_UPDATE_CURSOR, VIRTIO_GPU_CMD_MOVE_CURSOR */ > > +struct virtio_gpu_update_cursor { > > + struct virtio_gpu_ctrl_hdr hdr; > > + struct virtio_gpu_cursor_pos pos; /* update & move */ > > + __le32 resource_id; /* update only */ > > + __le32 hot_x; /* update only */ > > + __le32 hot_y; /* update only */ > > + __le32 padding; > > +}; > > + > > +/* data passed in the control vq, 2d related */ But there are no comments so we don't know what these structs are for or what the fields do. Can you add documentation, or a pointer to somewhere where it exists? > > + > > +struct virtio_gpu_rect { > > + __le32 x; > > + __le32 y; > > + __le32 width; > > + __le32 height; > > +}; > > + > > +/* VIRTIO_GPU_CMD_RESOURCE_UNREF */ > > +struct virtio_gpu_resource_unref { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __le32 resource_id; > > + __le32 padding; > > +}; > > + > > +/* VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: create a 2d resource with a > > format */ > > +struct virtio_gpu_resource_create_2d { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __le32 resource_id; > > + __le32 format; > > + __le32 width; > > + __le32 height; > > +}; > > + > > +/* VIRTIO_GPU_CMD_SET_SCANOUT */ > > +struct virtio_gpu_set_scanout { > > + struct virtio_gpu_ctrl_hdr hdr; > > + struct virtio_gpu_rect r; > > + __le32 scanout_id; > > + __le32 resource_id; > > +}; > > + > > +/* VIRTIO_GPU_CMD_RESOURCE_FLUSH */ > > +struct virtio_gpu_resource_flush { > > + struct virtio_gpu_ctrl_hdr hdr; > > + struct virtio_gpu_rect r; > > + __le32 resource_id; > > + __le32 padding; > > +}; > > + > > +/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: simple transfer to_host */ > > +struct virtio_gpu_transfer_to_host_2d { > > + struct virtio_gpu_ctrl_hdr hdr; > > + struct virtio_gpu_rect r; > > + __le64 offset; > > + __le32 resource_id; > > + __le32 padding; > > +}; > > + > > +struct virtio_gpu_mem_entry { > > + __le64 addr; > > + __le32 length; > > + __le32 padding; > > +}; > > + > > +/* VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING */ > > +struct virtio_gpu_resource_attach_backing { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __le32 resource_id; > > + __le32 nr_entries; > > +}; > > + > > +/* VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING */ > > +struct virtio_gpu_resource_detach_backing { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __le32 resource_id; > > + __le32 padding; > > +}; > > + > > +/* VIRTIO_GPU_RESP_OK_DISPLAY_INFO */ > > +#define VIRTIO_GPU_MAX_SCANOUTS 16 > > +struct virtio_gpu_resp_display_info { > > + struct virtio_gpu_ctrl_hdr hdr; > > + struct virtio_gpu_display_one { > > + struct virtio_gpu_rect r; > > + __le32 enabled; > > + __le32 flags; > > + } pmodes[VIRTIO_GPU_MAX_SCANOUTS]; > > +}; > > + > > +/* data passed in the control vq, 3d related */ > > + > > +struct virtio_gpu_box { > > + __le32 x, y, z; > > + __le32 w, h, d; > > +}; > > + > > +/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D, > > VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D */ > > +struct virtio_gpu_transfer_host_3d { > > + struct virtio_gpu_ctrl_hdr hdr; > > + struct virtio_gpu_box box; > > + __le64 offset; > > + __le32 resource_id; > > + __le32 level; > > + __le32 stride; > > + __le32 layer_stride; > > +}; > > + > > +/* VIRTIO_GPU_CMD_RESOURCE_CREATE_3D */ > > +#define VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP (1 << 0) > > +struct virtio_gpu_resource_create_3d { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __le32 resource_id; > > + __le32 target; > > + __le32 format; > > + __le32 bind; > > + __le32 width; > > + __le32 height; > > + __le32 depth; > > + __le32 array_size; > > + __le32 last_level; > > + __le32 nr_samples; > > + __le32 flags; > > + __le32 padding; > > +}; > > + > > +/* VIRTIO_GPU_CMD_CTX_CREATE */ > > +#define VIRTIO_GPU_CONTEXT_INIT_CAPSET_ID_MASK 0x000000ff > > +struct virtio_gpu_ctx_create { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __le32 nlen; > > + __le32 context_init; > > + char debug_name[64]; > > +}; > > + > > +/* VIRTIO_GPU_CMD_CTX_DESTROY */ > > +struct virtio_gpu_ctx_destroy { > > + struct virtio_gpu_ctrl_hdr hdr; > > +}; > > + > > +/* VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE, > > VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE */ > > +struct virtio_gpu_ctx_resource { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __le32 resource_id; > > + __le32 padding; > > +}; > > + > > +/* VIRTIO_GPU_CMD_SUBMIT_3D */ > > +struct virtio_gpu_cmd_submit { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __le32 size; > > + __le32 padding; > > +}; > > + > > +#define VIRTIO_GPU_CAPSET_VIRGL 1 > > +#define VIRTIO_GPU_CAPSET_VIRGL2 2 > > +/* 3 is reserved for gfxstream */ > > +#define VIRTIO_GPU_CAPSET_VENUS 4 > > + > > +/* VIRTIO_GPU_CMD_GET_CAPSET_INFO */ > > +struct virtio_gpu_get_capset_info { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __le32 capset_index; > > + __le32 padding; > > +}; > > + > > +/* VIRTIO_GPU_RESP_OK_CAPSET_INFO */ > > +struct virtio_gpu_resp_capset_info { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __le32 capset_id; > > + __le32 capset_max_version; > > + __le32 capset_max_size; > > + __le32 padding; > > +}; > > + > > +/* VIRTIO_GPU_CMD_GET_CAPSET */ > > +struct virtio_gpu_get_capset { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __le32 capset_id; > > + __le32 capset_version; > > +}; > > + > > +/* VIRTIO_GPU_RESP_OK_CAPSET */ > > +struct virtio_gpu_resp_capset { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __u8 capset_data[]; > > +}; > > + > > +/* VIRTIO_GPU_CMD_GET_EDID */ > > +struct virtio_gpu_cmd_get_edid { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __le32 scanout; > > + __le32 padding; > > +}; > > + > > +/* VIRTIO_GPU_RESP_OK_EDID */ > > +struct virtio_gpu_resp_edid { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __le32 size; > > + __le32 padding; > > + __u8 edid[1024]; > > +}; > > + > > +#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0) > > + > > +struct virtio_gpu_config { > > + __le32 events_read; > > + __le32 events_clear; > > + __le32 num_scanouts; > > + __le32 num_capsets; > > +}; > > + > > +/* simple formats for fbcon/X use */ > > +enum virtio_gpu_formats { > > + VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM = 1, > > + VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM = 2, > > + VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM = 3, > > + VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM = 4, > > + > > + VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM = 67, > > + VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM = 68, > > + > > + VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM = 121, > > + VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM = 134, > > +}; > > + > > +/* VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID */ > > +struct virtio_gpu_resource_assign_uuid { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __le32 resource_id; > > + __le32 padding; > > +}; > > + > > +/* VIRTIO_GPU_RESP_OK_RESOURCE_UUID */ > > +struct virtio_gpu_resp_resource_uuid { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __u8 uuid[16]; > > +}; > > + > > +/* VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB */ > > +struct virtio_gpu_resource_create_blob { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __le32 resource_id; > > +#define VIRTIO_GPU_BLOB_MEM_GUEST 0x0001 > > +#define VIRTIO_GPU_BLOB_MEM_HOST3D 0x0002 > > +#define VIRTIO_GPU_BLOB_MEM_HOST3D_GUEST 0x0003 > > + > > +#define VIRTIO_GPU_BLOB_FLAG_USE_MAPPABLE 0x0001 > > +#define VIRTIO_GPU_BLOB_FLAG_USE_SHAREABLE 0x0002 > > +#define VIRTIO_GPU_BLOB_FLAG_USE_CROSS_DEVICE 0x0004 > > + /* zero is invalid blob mem */ > > + __le32 blob_mem; > > + __le32 blob_flags; > > + __le32 nr_entries; > > + __le64 blob_id; > > + __le64 size; > > + /* > > + * sizeof(nr_entries * virtio_gpu_mem_entry) bytes follow > > + */ > > +}; > > + > > +/* VIRTIO_GPU_CMD_SET_SCANOUT_BLOB */ > > +struct virtio_gpu_set_scanout_blob { > > + struct virtio_gpu_ctrl_hdr hdr; > > + struct virtio_gpu_rect r; > > + __le32 scanout_id; > > + __le32 resource_id; > > + __le32 width; > > + __le32 height; > > + __le32 format; > > + __le32 padding; > > + __le32 strides[4]; > > + __le32 offsets[4]; > > +}; > > + > > +/* VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB */ > > +struct virtio_gpu_resource_map_blob { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __le32 resource_id; > > + __le32 padding; > > + __le64 offset; > > +}; > > + > > +/* VIRTIO_GPU_RESP_OK_MAP_INFO */ > > +#define VIRTIO_GPU_MAP_CACHE_MASK 0x0f > > +#define VIRTIO_GPU_MAP_CACHE_NONE 0x00 > > +#define VIRTIO_GPU_MAP_CACHE_CACHED 0x01 > > +#define VIRTIO_GPU_MAP_CACHE_UNCACHED 0x02 > > +#define VIRTIO_GPU_MAP_CACHE_WC 0x03 > > +struct virtio_gpu_resp_map_info { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __u32 map_info; > > + __u32 padding; > > +}; > > + > > +/* VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB */ > > +struct virtio_gpu_resource_unmap_blob { > > + struct virtio_gpu_ctrl_hdr hdr; > > + __le32 resource_id; > > + __le32 padding; > > +}; > > + > > +#endif > > diff --git a/include/virtio.h b/include/virtio.h > > index 1ab0ec5f39f5..93a6f5e92a48 100644 > > --- a/include/virtio.h > > +++ b/include/virtio.h > > @@ -27,11 +27,13 @@ > > #define VIRTIO_ID_NET 1 /* virtio net */ > > #define VIRTIO_ID_BLOCK 2 /* virtio block */ > > #define VIRTIO_ID_RNG 4 /* virtio rng */ > > -#define VIRTIO_ID_MAX_NUM 5 > > +#define VIRTIO_ID_GPU 16 /* virtio GPU */ > > +#define VIRTIO_ID_MAX_NUM 17 > > > > #define VIRTIO_NET_DRV_NAME "virtio-net" > > #define VIRTIO_BLK_DRV_NAME "virtio-blk" > > #define VIRTIO_RNG_DRV_NAME "virtio-rng" > > +#define VIRTIO_GPU_DRV_NAME "virtio-gpu" > > > > /* Status byte for guest to report progress, and synchronize features */ > > > > > > -- > > 2.43.0 > Regards, Simon