The idea here is: if we run the vm headless, we don't really need to communicate with VMM, and we even don't need any VMM support for virtio-gpu. Of course, only 2d works. But it's enough for some use case. And this looks simpler than vkms. Signed-off-by: Lepton Wu <ytht.net@xxxxxxxxx> --- drivers/gpu/drm/virtio/Kconfig | 9 ++ drivers/gpu/drm/virtio/Makefile | 3 + drivers/gpu/drm/virtio/virtgpu_dummy.c | 161 +++++++++++++++++++++++++ 3 files changed, 173 insertions(+) create mode 100644 drivers/gpu/drm/virtio/virtgpu_dummy.c diff --git a/drivers/gpu/drm/virtio/Kconfig b/drivers/gpu/drm/virtio/Kconfig index eff3047052d4..9c18aace38ed 100644 --- a/drivers/gpu/drm/virtio/Kconfig +++ b/drivers/gpu/drm/virtio/Kconfig @@ -9,3 +9,12 @@ config DRM_VIRTIO_GPU QEMU based VMMs (like KVM or Xen). If unsure say M. + +config DRM_VIRTIO_GPU_DUMMY + tristate "Virtio dummy GPU driver" + depends on DRM_VIRTIO_GPU + help + This add a new virtio GPU device which handles the virtio ring buffers + inline so it doesn't rely on VMM to provide the virtio GPU device. + Currently it only handle VIRTIO_GPU_CMD_GET_DISPLAY_INFO which is enough + for a dummy 2D VGA device. diff --git a/drivers/gpu/drm/virtio/Makefile b/drivers/gpu/drm/virtio/Makefile index 92aa2b3d349d..26d8fee1bc41 100644 --- a/drivers/gpu/drm/virtio/Makefile +++ b/drivers/gpu/drm/virtio/Makefile @@ -8,4 +8,7 @@ virtio-gpu-y := virtgpu_drv.o virtgpu_kms.o virtgpu_gem.o \ virtgpu_fence.o virtgpu_object.o virtgpu_debugfs.o virtgpu_plane.o \ virtgpu_ioctl.o virtgpu_prime.o virtgpu_trace_points.o +virtio-gpu-dummy-y := virtgpu_dummy.o + obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio-gpu.o +obj-$(CONFIG_DRM_VIRTIO_GPU_DUMMY) += virtio-gpu-dummy.o diff --git a/drivers/gpu/drm/virtio/virtgpu_dummy.c b/drivers/gpu/drm/virtio/virtgpu_dummy.c new file mode 100644 index 000000000000..8c2eb6fea47c --- /dev/null +++ b/drivers/gpu/drm/virtio/virtgpu_dummy.c @@ -0,0 +1,161 @@ +#include <linux/module.h> +#include <linux/virtio.h> +#include <linux/virtio_ids.h> +#include <linux/virtio_config.h> +#include <linux/virtio_ring.h> +#include <linux/virtio_gpu.h> + +#include "virtgpu_drv.h" + +static int virtgpu_dummy_width = 1024; +static int virtgpu_dummy_height = 768; + +MODULE_PARM_DESC(width, "Dummy VGA width"); +module_param_named(width, virtgpu_dummy_width, int, 0400); +MODULE_PARM_DESC(height, "Dummy VGA height"); +module_param_named(height, virtgpu_dummy_height, int, 0400); + +static struct bus_type dummy_bus = { + .name = "", +}; + +static struct dummy_gpu { + struct device *root; + struct virtio_device vdev; + unsigned char status; +} dummy; + +static u64 dummy_get_features(struct virtio_device *vdev) +{ + return 1ULL << VIRTIO_F_VERSION_1; +} + +static int dummy_finalize_features(struct virtio_device *vdev) +{ + return 0; +} + +static void dummy_get(struct virtio_device *vdev, unsigned int offset, + void *buf, unsigned len) +{ + static struct virtio_gpu_config config = { + .num_scanouts = 1, + }; + BUG_ON(offset + len > sizeof(config)); + memcpy(buf, (char *)&config + offset, len); +} + +static u8 dummy_get_status(struct virtio_device *vdev) +{ + struct dummy_gpu* gpu = container_of(vdev, struct dummy_gpu, vdev); + return gpu->status; +} + +static void dummy_set_status(struct virtio_device *vdev, u8 status) +{ + struct dummy_gpu* gpu = container_of(vdev, struct dummy_gpu, vdev); + BUG_ON(!status); + gpu->status = status; +} + +void process_cmd(struct vring_desc *desc, int idx) +{ + // FIXME, use chain to get resp buffer addr + char *buf = __va(desc[idx].addr); + struct virtio_gpu_vbuffer *vbuf = + (struct virtio_gpu_vbuffer *)(buf - sizeof(*vbuf)); + struct virtio_gpu_ctrl_hdr *cmd_p = (struct virtio_gpu_ctrl_hdr *)buf; + struct virtio_gpu_resp_display_info *resp; + BUG_ON(vbuf->buf != buf); + if (cmd_p->type != cpu_to_le32(VIRTIO_GPU_CMD_GET_DISPLAY_INFO)) + return; + BUG_ON(vbuf->resp_size != sizeof(struct virtio_gpu_resp_display_info)); + resp = (struct virtio_gpu_resp_display_info *)vbuf->resp_buf; + resp->pmodes[0].r.width = virtgpu_dummy_width; + resp->pmodes[0].r.height = virtgpu_dummy_height; + resp->pmodes[0].enabled = 1; +} + +static bool dummy_notify(struct virtqueue *vq) +{ + struct vring *r = (struct vring *)(vq + 1); + int used, avail; + // FIXME, handle multiple avail and also fix for big endian. + used = r->used->idx & (r->num - 1); + avail = (r->avail->idx - 1) & (r->num - 1); + r->used->ring[used].id = r->avail->ring[avail]; + r->used->idx++; + if (!strcmp(vq->name, "control")) + process_cmd(r->desc, r->avail->ring[avail]); + vq->callback(vq); + return true; +} + +static int dummy_find_vqs(struct virtio_device *vdev, unsigned nvqs, + struct virtqueue *vqs[], + vq_callback_t * callbacks[], + const char *const names[], + const bool *ctx, struct irq_affinity *desc) +{ + int i, j; + for (i = 0; i < nvqs; ++i) { + vqs[i] = vring_create_virtqueue(i, 256, SMP_CACHE_BYTES, vdev, + true, false, false, + dummy_notify, callbacks[i], + names[i]); + if (!vqs[i]) + goto err; + } + return 0; +err: + for (j = 0; j < i; ++j) { + vring_del_virtqueue(vqs[j]); + vqs[j] = NULL; + } + return -ENOMEM; +} + +static void dummy_reset(struct virtio_device *vdev) +{ +} + +static const struct virtio_config_ops dummy_vq_ops = { + .get_features = dummy_get_features, + .finalize_features = dummy_finalize_features, + .get = dummy_get, + .get_status = dummy_get_status, + .set_status = dummy_set_status, + .reset = dummy_reset, + .find_vqs = dummy_find_vqs, +}; + +static int __init virtio_gpu_dummy_init(void) +{ + int ret; + struct device * root = root_device_register("dummy"); + if (PTR_ERR_OR_ZERO(root)) + return PTR_ERR(root); + root->bus = &dummy_bus; + dummy.vdev.dev.parent = root; + dummy.vdev.id.device = VIRTIO_ID_GPU; + dummy.vdev.config = &dummy_vq_ops; + ret = register_virtio_device(&dummy.vdev); + if (ret) { + pr_err("Failed to register virtio device %d", ret); + root_device_unregister(root); + return ret; + } + dummy.root = root; + return 0; +} + +static void virtio_gpu_dummy_exit(void) +{ + if (!dummy.root) + return; + unregister_virtio_device(&dummy.vdev); + root_device_unregister(dummy.root); +} + +module_init(virtio_gpu_dummy_init); +module_exit(virtio_gpu_dummy_exit); -- 2.25.0.265.gbab2e86ba0-goog _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel