From nobody Fri May 17 09:18:30 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1612830699; cv=none; d=zohomail.com; s=zohoarc; b=md/1Br56QbWmUuyKlyHFT6JlhK8QabktucFu5L5q7c9NZr9BpwmFzw7e9sOIyAjZ8az+mv0+3QBM+W+0+IQXdxoqeK1SMENHA1p+Bvyh/l0zId1+oQosXHwaQformGSl+P0HKtofTovd73i+Zwv5XJwWf0Pr5AcYlQl3KLg4uOI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1612830699; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=s2YQo1R7sj7MY3CodsubGuMMK6J22mbeZIWCdhmk5AI=; b=hzbpnBCZRmKEsXtZRPPDTqYaLX3LDLCc6w4nkth38GlTmxX0N2+oJengMDeAPQ1AipOwbIh4e0BwpeidZafAz3V4MX2GtzJ7b9+eWNU/iDko03cJkQKFTwom9dJXJXNVRONKkHxy/73uSV51rmXf1NrclO9XTW/N7LiMMaOZYgo= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1612830699310582.9468951625264; Mon, 8 Feb 2021 16:31:39 -0800 (PST) Received: from localhost ([::1]:48628 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1l9GwL-0003xz-VE for importer@patchew.org; Mon, 08 Feb 2021 19:31:37 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:45370) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1l9GBW-0001NJ-VA for qemu-devel@nongnu.org; Mon, 08 Feb 2021 18:43:15 -0500 Received: from mga06.intel.com ([134.134.136.31]:53603) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1l9GBP-0002m2-UP for qemu-devel@nongnu.org; Mon, 08 Feb 2021 18:43:14 -0500 Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 08 Feb 2021 15:42:59 -0800 Received: from vkasired-desk2.fm.intel.com ([10.105.128.127]) by fmsmga005-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 08 Feb 2021 15:42:59 -0800 IronPort-SDR: jTzEJ/nRsmOT7oSEhfwX29aCQj4f5oYLpiAKN0YKmQiCCc1+F+9a6gcjKgkOL2HLUMc8eMPAQS HoVps/7MBgHA== X-IronPort-AV: E=McAfee;i="6000,8403,9889"; a="243298080" X-IronPort-AV: E=Sophos;i="5.81,163,1610438400"; d="scan'208";a="243298080" IronPort-SDR: eQ/dSLbnECex2hN+pfU/gFKxfjyF3uJzkH2eBSCnlMDrKrLk0odgoayMuttLBfd5M0xUWbtP3m 1yqQR2M7C4Nw== X-IronPort-AV: E=Sophos;i="5.81,163,1610438400"; d="scan'208";a="585858969" From: Vivek Kasireddy To: qemu-devel@nongnu.org Subject: [RFC 1/1] vhost-vdmabuf: Add virtio based Dmabuf device Date: Mon, 8 Feb 2021 15:32:25 -0800 Message-Id: <20210208233225.2084469-2-vivek.kasireddy@intel.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210208233225.2084469-1-vivek.kasireddy@intel.com> References: <20210208233225.2084469-1-vivek.kasireddy@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=134.134.136.31; envelope-from=vivek.kasireddy@intel.com; helo=mga06.intel.com X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, T_SPF_TEMPERROR=0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Vivek Kasireddy , kraxel@redhat.com, dongwon.kim@intel.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" This patch provides the implementation of the virtio dmabuf device that is used to share a dmabuf created in the Guest with the Host. Once the vhost vdmabuf kernel driver on the Host alerts Qemu about a new dmabuf from the Guest, it is first imported and then converted into a texture using EGL and eventually displayed on the screen. Cc: Gerd Hoffmann Signed-off-by: Vivek Kasireddy Signed-off-by: Dongwon Kim --- configure | 8 + hw/virtio/meson.build | 1 + hw/virtio/vhost-backend.c | 10 + hw/virtio/vhost-vdmabuf.c | 526 ++++++++++++++++++++ include/hw/pci/pci.h | 1 + include/hw/virtio/vhost-backend.h | 2 + include/hw/virtio/vhost-vdmabuf.h | 76 +++ include/standard-headers/linux/virtio_ids.h | 1 + include/ui/console.h | 1 + linux-headers/linux/vhost.h | 3 + meson.build | 1 + ui/console.c | 7 + 12 files changed, 637 insertions(+) create mode 100644 hw/virtio/vhost-vdmabuf.c create mode 100644 include/hw/virtio/vhost-vdmabuf.h diff --git a/configure b/configure index a34f91171d..90a35317bf 100755 --- a/configure +++ b/configure @@ -345,6 +345,7 @@ vhost_net=3D"$default_feature" vhost_crypto=3D"$default_feature" vhost_scsi=3D"$default_feature" vhost_vsock=3D"$default_feature" +vhost_vdmabuf=3D"$default_feature" vhost_user=3D"no" vhost_user_blk_server=3D"auto" vhost_user_fs=3D"$default_feature" @@ -1263,6 +1264,10 @@ for opt do ;; --enable-vhost-vsock) vhost_vsock=3D"yes" ;; + --disable-vhost-vdmabuf) vhost_vdmabuf=3D"no" + ;; + --enable-vhost-vdmabuf) vhost_vdmabuf=3D"yes" + ;; --disable-vhost-user-blk-server) vhost_user_blk_server=3D"disabled" ;; --enable-vhost-user-blk-server) vhost_user_blk_server=3D"enabled" @@ -5766,6 +5771,9 @@ if test "$vhost_vsock" =3D "yes" ; then echo "CONFIG_VHOST_USER_VSOCK=3Dy" >> $config_host_mak fi fi +if test "$vhost_vdmabuf" =3D "yes" ; then + echo "CONFIG_VHOST_VDMABUF=3Dy" >> $config_host_mak +fi if test "$vhost_kernel" =3D "yes" ; then echo "CONFIG_VHOST_KERNEL=3Dy" >> $config_host_mak fi diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index fbff9bc9d4..f2f5408fda 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -21,6 +21,7 @@ virtio_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: file= s('vhost-user-fs.c')) virtio_ss.add(when: ['CONFIG_VHOST_USER_FS', 'CONFIG_VIRTIO_PCI'], if_true= : files('vhost-user-fs-pci.c')) virtio_ss.add(when: 'CONFIG_VIRTIO_PMEM', if_true: files('virtio-pmem.c')) virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock.c', = 'vhost-vsock-common.c')) +virtio_ss.add(when: 'CONFIG_VHOST_VDMABUF', if_true: files('vhost-vdmabuf.= c')) virtio_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-= vsock.c', 'vhost-vsock-common.c')) virtio_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng.c')) virtio_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: files('virtio-iommu.c'= )) diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c index 31b33bde37..39a64e101d 100644 --- a/hw/virtio/vhost-backend.c +++ b/hw/virtio/vhost-backend.c @@ -214,6 +214,13 @@ static int vhost_kernel_vsock_set_running(struct vhost= _dev *dev, int start) } #endif /* CONFIG_VHOST_VSOCK */ =20 +#ifdef CONFIG_VHOST_VDMABUF +static int vhost_kernel_vdmabuf_set_running(struct vhost_dev *dev, int sta= rt) +{ + return vhost_kernel_call(dev, VHOST_VDMABUF_SET_RUNNING, &start); +} +#endif /* CONFIG_VHOST_VDMABUF */ + static void vhost_kernel_iotlb_read(void *opaque) { struct vhost_dev *dev =3D opaque; @@ -321,6 +328,9 @@ static const VhostOps kernel_ops =3D { .vhost_vsock_set_guest_cid =3D vhost_kernel_vsock_set_guest_cid, .vhost_vsock_set_running =3D vhost_kernel_vsock_set_running, #endif /* CONFIG_VHOST_VSOCK */ +#ifdef CONFIG_VHOST_VDMABUF + .vhost_vdmabuf_set_running =3D vhost_kernel_vdmabuf_set_running, +#endif /* CONFIG_VHOST_VDMABUF */ .vhost_set_iotlb_callback =3D vhost_kernel_set_iotlb_callback, .vhost_send_device_iotlb_msg =3D vhost_kernel_send_device_iotlb_ms= g, }; diff --git a/hw/virtio/vhost-vdmabuf.c b/hw/virtio/vhost-vdmabuf.c new file mode 100644 index 0000000000..06890e6b2a --- /dev/null +++ b/hw/virtio/vhost-vdmabuf.c @@ -0,0 +1,526 @@ +/* + * Implementation of Virtio based Dmabuf device -- mostly inspired by + * vfio/display.c and vhost-vsock.c. + * + * Copyright 2021 Intel Corporation. + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + */ + +#include +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qemu/typedefs.h" +#include "monitor/monitor.h" +#include "virtio-pci.h" +#include "qemu/module.h" +#include "qemu/uuid.h" +#include "sysemu/sysemu.h" +#include "ui/console.h" +#include "qapi/error.h" +#include "trace.h" + +#include "standard-headers/linux/virtio_ids.h" +#include "standard-headers/drm/drm_fourcc.h" +#include "hw/qdev-properties.h" + +#include "hw/virtio/virtio.h" +#include "hw/virtio/vhost.h" +#include "hw/virtio/virtio-access.h" +#include "hw/virtio/vhost-vdmabuf.h" + +#define TYPE_VHOST_VDMABUF "vhost-vdmabuf" +#define VHOST_VDMABUF(obj) \ + OBJECT_CHECK(VHostVdmabuf, (obj), TYPE_VHOST_VDMABUF) + +#define TYPE_VHOST_VDMABUF_PCI "vhost-vdmabuf-pci-base" +#define VHOST_VDMABUF_PCI(obj) \ + OBJECT_CHECK(VHostVdmabufPCI, (obj), TYPE_VHOST_VDMABUF_PCI) + +#define VHOST_VDMABUF_QUEUE_SIZE 128 +#define QEMU_UUID_SIZE_BYTES 16 + +static bool have_event =3D false; + +typedef struct VHostVdmabufPCI VHostVdmabufPCI; + +typedef struct VDMABUFDMABuf { + QemuDmaBuf buf; + QemuUUID dmabuf_id; + QTAILQ_ENTRY(VDMABUFDMABuf) next; +} VDMABUFDMABuf; + +typedef struct VDMABUFDisplay { + QemuConsole *con; + DisplaySurface *surface; + struct { + QTAILQ_HEAD(, VDMABUFDMABuf) bufs; + VDMABUFDMABuf *guest_fb; + } dmabuf; +} VDMABUFDisplay; + +typedef struct { + VirtIODevice parent; + + struct vhost_dev vhost_dev; + struct vhost_virtqueue vhost_vqs[2]; + + VirtQueue *send_vq; + VirtQueue *recv_vq; + VDMABUFDisplay *dpy; + int vhostfd; +} VHostVdmabuf; + +struct VHostVdmabufPCI { + VirtIOPCIProxy parent_obj; + VHostVdmabuf vdev; +}; + +typedef struct VDMABUFBlob { + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t format; + uint64_t modifier; +} VDMABUFBlob; + +static int vhost_vdmabuf_start(VirtIODevice *vdev) +{ + VHostVdmabuf *vdmabuf =3D VHOST_VDMABUF(vdev); + BusState *bs =3D BUS(qdev_get_parent_bus(DEVICE(vdev))); + VirtioBusClass *bc =3D VIRTIO_BUS_GET_CLASS(bs); + int ret, i; + + if (!bc->set_guest_notifiers) { + error_report("No support for guest notifiers"); + return -ENOSYS; + } + + ret =3D vhost_dev_enable_notifiers(&vdmabuf->vhost_dev, vdev); + if (ret < 0) { + error_report("Cannot enable host notifiers: %d", -ret); + return ret; + } + + ret =3D bc->set_guest_notifiers(bs->parent, vdmabuf->vhost_dev.nvqs, t= rue); + if (ret < 0) { + error_report("Cannot set guest notifier: %d", -ret); + return ret; + } + + vdmabuf->vhost_dev.acked_features =3D vdev->guest_features; + ret =3D vhost_dev_start(&vdmabuf->vhost_dev, vdev); + if (ret < 0) { + error_report("Cannot start vhost: %d", -ret); + return ret; + } + + for (i =3D 0; i < vdmabuf->vhost_dev.nvqs; i++) { + vhost_virtqueue_mask(&vdmabuf->vhost_dev, vdev, i, false); + } + + return 0; +} + +static void vhost_vdmabuf_stop(VirtIODevice *vdev) +{ + VHostVdmabuf *vdmabuf =3D VHOST_VDMABUF(vdev); + BusState *bs =3D BUS(qdev_get_parent_bus(DEVICE(vdev))); + VirtioBusClass *bc =3D VIRTIO_BUS_GET_CLASS(bs); + + if (!bc->set_guest_notifiers) { + return; + } + + vhost_dev_stop(&vdmabuf->vhost_dev, vdev); + vhost_dev_disable_notifiers(&vdmabuf->vhost_dev, vdev); +} + +static int vhost_vdmabuf_set_running(VirtIODevice *vdev, int start) +{ + VHostVdmabuf *vdmabuf =3D VHOST_VDMABUF(vdev); + const VhostOps *vhost_ops =3D vdmabuf->vhost_dev.vhost_ops; + int ret; + + if (!vhost_ops->vhost_vdmabuf_set_running) { + return -ENOSYS; + } + + ret =3D vhost_ops->vhost_vdmabuf_set_running(&vdmabuf->vhost_dev, star= t); + if (ret < 0) { + return -errno; + } + + return 0; +} + +static void vhost_vdmabuf_set_status(VirtIODevice *vdev, uint8_t status) +{ + VHostVdmabuf *vdmabuf =3D VHOST_VDMABUF(vdev); + bool should_start =3D status & VIRTIO_CONFIG_S_DRIVER_OK; + int ret =3D 0; + + if (!vdev->vm_running) { + should_start =3D false; + } + + if (vdmabuf->vhost_dev.started =3D=3D should_start) { + return; + } + + if (should_start) { + ret =3D vhost_vdmabuf_start(vdev); + if (ret < 0) { + error_report("Cannot start vhost vdmabuf: %d", -ret); + return; + } + + ret =3D vhost_vdmabuf_set_running(vdev, 1); + if (ret < 0) { + vhost_vdmabuf_stop(vdev); + error_report("vhost vdmabuf set running failed: %d", ret); + return; + } + } else { + ret =3D vhost_vdmabuf_set_running(vdev, 0); + if (ret < 0) { + error_report("vhost vdmabuf set running failed: %d", ret); + return; + } + + vhost_vdmabuf_stop(vdev); + } +} + +static int vhost_vdmabuf_pre_save(void *opaque) +{ + return 0; +} + +static int vhost_vdmabuf_post_load(void *opaque, int version_id) +{ + return 0; +} + +static const VMStateDescription vmstate_virtio_vhost_vdmabuf =3D { + .name =3D "virtio-vhost_vdmabuf", + .minimum_version_id =3D 0, + .version_id =3D 0, + .fields =3D (VMStateField[]) { + VMSTATE_VIRTIO_DEVICE, + VMSTATE_END_OF_LIST() + }, + .pre_save =3D vhost_vdmabuf_pre_save, + .post_load =3D vhost_vdmabuf_post_load, +}; + +static void vhost_vdmabuf_handle_output(VirtIODevice *vdev, VirtQueue *vq) +{ + return; +} + +static void vhost_vdmabuf_guest_notifier_mask(VirtIODevice *vdev, int idx, + bool mask) +{ + VHostVdmabuf *vdmabuf =3D VHOST_VDMABUF(vdev); + + vhost_virtqueue_mask(&vdmabuf->vhost_dev, vdev, idx, mask); +} + +static bool vhost_vdmabuf_guest_notifier_pending(VirtIODevice *vdev, + int idx) +{ + VHostVdmabuf *vdmabuf =3D VHOST_VDMABUF(vdev); + + return vhost_virtqueue_pending(&vdmabuf->vhost_dev, idx); +} + +static void vhost_vdmabuf_device_unrealize(DeviceState *dev) +{ + VHostVdmabuf *vdmabuf =3D VHOST_VDMABUF(dev); + VirtIODevice *vdev =3D VIRTIO_DEVICE(dev); + + vhost_vdmabuf_set_status(vdev, 0); + vhost_dev_cleanup(&vdmabuf->vhost_dev); + + virtio_delete_queue(vdmabuf->send_vq); + virtio_delete_queue(vdmabuf->recv_vq); + virtio_cleanup(vdev); +} + +static VDMABUFDMABuf *vdmabuf_display_get_dmabuf(VHostVdmabuf *vdmabuf) +{ + VDMABUFDisplay *dpy =3D vdmabuf->dpy; + VDMABUFDMABuf *dmabuf; + VDMABUFBlob *dmabuf_blob; + QemuUUID uuid; + struct virtio_vdmabuf_import msg; + struct virtio_vdmabuf_e_hdr *ev_hdr; + int fd =3D vdmabuf->vhostfd; + char data[256] =3D {0}; + long ret =3D 0; + + ret =3D read(fd, data, sizeof *ev_hdr + sizeof *dmabuf_blob); + if (ret <=3D 0) { + error_report("Cannot read event: %ld", -ret); + return NULL; + } + + ev_hdr =3D (struct virtio_vdmabuf_e_hdr *)data; + memcpy(&uuid, &ev_hdr->buf_id, QEMU_UUID_SIZE_BYTES); + dmabuf_blob =3D (VDMABUFBlob *)(data + sizeof *ev_hdr); + + QTAILQ_FOREACH(dmabuf, &dpy->dmabuf.bufs, next) { + if (qemu_uuid_is_equal(&uuid, &dmabuf->dmabuf_id)) { + QTAILQ_REMOVE(&dpy->dmabuf.bufs, dmabuf, next); + QTAILQ_INSERT_HEAD(&dpy->dmabuf.bufs, dmabuf, next); + return dmabuf; + } + } + + memcpy(&msg.buf_id, &uuid, QEMU_UUID_SIZE_BYTES); + ret =3D ioctl(fd, VIRTIO_VDMABUF_IOCTL_IMPORT, &msg); + if (ret) { + error_report("Cannot import dmabuf: %ld", -ret); + return NULL; + } + + dmabuf =3D g_new0(VDMABUFDMABuf, 1); + memcpy(&dmabuf->dmabuf_id, &uuid, QEMU_UUID_SIZE_BYTES); + dmabuf->buf.fd =3D msg.fd; + + dmabuf->buf.width =3D dmabuf_blob->width; + dmabuf->buf.height =3D dmabuf_blob->height; + dmabuf->buf.stride =3D dmabuf_blob->stride; + dmabuf->buf.fourcc =3D dmabuf_blob->format; + dmabuf->buf.modifier =3D dmabuf_blob->modifier; + + QTAILQ_INSERT_HEAD(&dpy->dmabuf.bufs, dmabuf, next); + return dmabuf; +} + +static void vdmabuf_display_free_one_dmabuf(VHostVdmabuf *vdmabuf, + VDMABUFDisplay *dpy, + VDMABUFDMABuf *dmabuf) +{ + struct virtio_vdmabuf_import msg; + int fd =3D vdmabuf->vhostfd; + + QTAILQ_REMOVE(&dpy->dmabuf.bufs, dmabuf, next); + dpy_gl_release_dmabuf(dpy->con, &dmabuf->buf); + + memcpy(&msg.buf_id, &dmabuf->dmabuf_id, QEMU_UUID_SIZE_BYTES); + if (ioctl(fd, VIRTIO_VDMABUF_IOCTL_RELEASE, &msg)) + error_report("Error releasing dmabuf"); + + close(dmabuf->buf.fd); + g_free(dmabuf); +} + +static void vdmabuf_display_free_dmabufs(VHostVdmabuf *vdmabuf) +{ + VDMABUFDisplay *dpy =3D vdmabuf->dpy; + VDMABUFDMABuf *dmabuf, *tmp; + uint32_t keep =3D 2; + + QTAILQ_FOREACH_SAFE(dmabuf, &dpy->dmabuf.bufs, next, tmp) { + if (keep > 0) { + keep--; + continue; + } + + assert(dmabuf !=3D dpy->dmabuf.guest_fb); + vdmabuf_display_free_one_dmabuf(vdmabuf, dpy, dmabuf); + } +} + +static void vdmabuf_display_dmabuf_update(void *opaque) +{ + VHostVdmabuf *vdmabuf =3D opaque; + VDMABUFDisplay *dpy =3D vdmabuf->dpy; + VDMABUFDMABuf *guest_fb; + bool free_bufs =3D false; + + if (!have_event) + return; + + guest_fb =3D vdmabuf_display_get_dmabuf(vdmabuf); + if (guest_fb =3D=3D NULL) { + return; + } + + if (dpy->dmabuf.guest_fb !=3D guest_fb) { + dpy->dmabuf.guest_fb =3D guest_fb; + qemu_console_resize(dpy->con, + guest_fb->buf.width, guest_fb->buf.height); + dpy_gl_scanout_dmabuf(dpy->con, &guest_fb->buf); + free_bufs =3D true; + } + + dpy_gl_update(dpy->con, 0, 0, guest_fb->buf.width, guest_fb->buf.heigh= t); + + if (free_bufs) { + vdmabuf_display_free_dmabufs(vdmabuf); + } + + have_event =3D false; +} + +static void vdmabuf_event_handler(void *opaque) +{ + VHostVdmabuf *vdmabuf =3D opaque; + VDMABUFDisplay *dpy =3D vdmabuf->dpy; + + have_event =3D true; + graphic_hw_dpy_refresh(dpy->con); +} + +static const GraphicHwOps vdmabuf_display_dmabuf_ops =3D { + .gfx_update =3D vdmabuf_display_dmabuf_update, +}; + +static int vdmabuf_display_dmabuf_init(VHostVdmabuf *vdmabuf, Error **errp) +{ + if (!display_opengl) { + error_setg(errp, "vhost-vdmabuf: opengl not available"); + return -1; + } + + vdmabuf->dpy =3D g_new0(VDMABUFDisplay, 1); + vdmabuf->dpy->con =3D graphic_console_init(NULL, 0, + &vdmabuf_display_dmabuf_ops, + vdmabuf); + return 0; +} + + +static void vhost_vdmabuf_device_realize(DeviceState *dev, Error **errp) +{ + VHostVdmabuf *vdmabuf =3D VHOST_VDMABUF(dev); + VirtIODevice *vdev =3D VIRTIO_DEVICE(dev); + int vhostfd; + int ret; + + vhostfd =3D open("/dev/vhost-vdmabuf", O_RDWR); + if (vhostfd < 0) { + error_setg_errno(errp, errno, + "vhost-vdmabuf: failed to open vhost device"); + return; + } + + virtio_init(vdev, "vhost-vdmabuf", VIRTIO_ID_VDMABUF, 0); + vdmabuf->send_vq =3D virtio_add_queue(vdev, VHOST_VDMABUF_QUEUE_SIZE, + vhost_vdmabuf_handle_output); + vdmabuf->recv_vq =3D virtio_add_queue(vdev, VHOST_VDMABUF_QUEUE_SIZE, + vhost_vdmabuf_handle_output); + + vdmabuf->vhost_dev.nvqs =3D ARRAY_SIZE(vdmabuf->vhost_vqs); + vdmabuf->vhost_dev.vqs =3D vdmabuf->vhost_vqs; + =20 + ret =3D vhost_dev_init(&vdmabuf->vhost_dev, (void *)(uintptr_t)vhostfd, + VHOST_BACKEND_TYPE_KERNEL, 0); + if (ret < 0) { + error_setg_errno(errp, -ret, "vhost-vdmabuf: vhost_dev_init failed= "); + goto err_virtio; + } + + vdmabuf->vhostfd =3D vhostfd; + qemu_set_fd_handler(vhostfd, vdmabuf_event_handler, NULL, vdmabuf); + + ret =3D vdmabuf_display_dmabuf_init(vdmabuf, errp); + if (ret < 0) { + error_setg_errno(errp, -ret, "vhost-vdmabuf: dmabuf_init failed"); + goto err_virtio; + } + + return; + +err_virtio: + vhost_vdmabuf_device_unrealize(dev); + if (vhostfd >=3D 0) { + close(vhostfd); + } +} + +static uint64_t vhost_vdmabuf_get_features(VirtIODevice *vdev, + uint64_t req_features, + Error **errp) +{ + return req_features; +} + +static void vhost_vdmabuf_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + VirtioDeviceClass *vdc =3D VIRTIO_DEVICE_CLASS(klass); + + dc->vmsd =3D &vmstate_virtio_vhost_vdmabuf; + vdc->realize =3D vhost_vdmabuf_device_realize; + vdc->unrealize =3D vhost_vdmabuf_device_unrealize; + vdc->get_features =3D vhost_vdmabuf_get_features; + vdc->set_status =3D vhost_vdmabuf_set_status; + + vdc->guest_notifier_mask =3D vhost_vdmabuf_guest_notifier_mask; + vdc->guest_notifier_pending =3D vhost_vdmabuf_guest_notifier_pending; +} + +static const TypeInfo vhost_vdmabuf_info =3D { + .name =3D TYPE_VHOST_VDMABUF, + .parent =3D TYPE_VIRTIO_DEVICE, + .instance_size =3D sizeof(VHostVdmabuf), + .class_init =3D vhost_vdmabuf_class_init, +}; + +static void vhost_vdmabuf_register_types(void) +{ + type_register_static(&vhost_vdmabuf_info); +} + +static void vhost_vdmabuf_pci_realize(VirtIOPCIProxy *vpci_dev, Error **er= rp) +{ + VHostVdmabufPCI *dev =3D VHOST_VDMABUF_PCI(vpci_dev); + DeviceState *vdev =3D DEVICE(&dev->vdev); + + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); +} + +static void vhost_vdmabuf_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + VirtioPCIClass *pc =3D VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k =3D PCI_DEVICE_CLASS(klass); + + pc->realize =3D vhost_vdmabuf_pci_realize; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + + pcidev_k->vendor_id =3D PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id =3D PCI_DEVICE_ID_VIRTIO_VDMABUF; + pcidev_k->revision =3D 0x00; + pcidev_k->class_id =3D PCI_CLASS_COMMUNICATION_OTHER; +} + +static void vhost_vdmabuf_pci_instance_init(Object *obj) +{ + VHostVdmabufPCI *dev =3D VHOST_VDMABUF_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_VDMABUF); +} + +static const VirtioPCIDeviceTypeInfo vhost_vdmabuf_pci_info =3D { + .base_name =3D TYPE_VHOST_VDMABUF_PCI, + .generic_name =3D "vhost-vdmabuf-pci", + .instance_size =3D sizeof(VHostVdmabufPCI), + .instance_init =3D vhost_vdmabuf_pci_instance_init, + .class_init =3D vhost_vdmabuf_pci_class_init, +}; + +static void virtio_pci_vhost_register(void) +{ + virtio_pci_types_register(&vhost_vdmabuf_pci_info); +} + +type_init(virtio_pci_vhost_register) +type_init(vhost_vdmabuf_register_types) diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 1bc231480f..fe4dd2443c 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -89,6 +89,7 @@ extern bool pci_available; #define PCI_DEVICE_ID_VIRTIO_PMEM 0x1013 #define PCI_DEVICE_ID_VIRTIO_IOMMU 0x1014 #define PCI_DEVICE_ID_VIRTIO_MEM 0x1015 +#define PCI_DEVICE_ID_VIRTIO_VDMABUF 0x1016 =20 #define PCI_VENDOR_ID_REDHAT 0x1b36 #define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001 diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-ba= ckend.h index 8a6f8e2a7a..f00ab76e70 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -89,6 +89,7 @@ typedef bool (*vhost_backend_can_merge_op)(struct vhost_d= ev *dev, typedef int (*vhost_vsock_set_guest_cid_op)(struct vhost_dev *dev, uint64_t guest_cid); typedef int (*vhost_vsock_set_running_op)(struct vhost_dev *dev, int start= ); +typedef int (*vhost_vdmabuf_set_running_op)(struct vhost_dev *dev, int sta= rt); typedef void (*vhost_set_iotlb_callback_op)(struct vhost_dev *dev, int enabled); typedef int (*vhost_send_device_iotlb_msg_op)(struct vhost_dev *dev, @@ -157,6 +158,7 @@ typedef struct VhostOps { vhost_backend_can_merge_op vhost_backend_can_merge; vhost_vsock_set_guest_cid_op vhost_vsock_set_guest_cid; vhost_vsock_set_running_op vhost_vsock_set_running; + vhost_vdmabuf_set_running_op vhost_vdmabuf_set_running; vhost_set_iotlb_callback_op vhost_set_iotlb_callback; vhost_send_device_iotlb_msg_op vhost_send_device_iotlb_msg; vhost_get_config_op vhost_get_config; diff --git a/include/hw/virtio/vhost-vdmabuf.h b/include/hw/virtio/vhost-vd= mabuf.h new file mode 100644 index 0000000000..aef99cbae2 --- /dev/null +++ b/include/hw/virtio/vhost-vdmabuf.h @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: (MIT OR GPL-2.0) + +/* + * Copyright =C2=A9 2021 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software= "), + * to deal in the Software without restriction, including without limitati= on + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the ne= xt + * paragraph) shall be included in all copies or substantial portions of t= he + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS= OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OT= HER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEA= LINGS + * IN THE SOFTWARE. + * + */ + +#ifndef _UAPI_LINUX_VIRTIO_VDMABUF_H +#define _UAPI_LINUX_VIRTIO_VDMABUF_H + +typedef struct { + __u64 id; + /* 8B long Random number */ + int rng_key[2]; +} virtio_vdmabuf_buf_id_t; + +struct virtio_vdmabuf_e_hdr { + /* buf_id of new buf */ + virtio_vdmabuf_buf_id_t buf_id; + /* size of private data */ + int size; +}; + +struct virtio_vdmabuf_e_data { + struct virtio_vdmabuf_e_hdr hdr; + /* ptr to private data */ + void *data; +}; + +#define VIRTIO_VDMABUF_IOCTL_IMPORT \ +_IOC(_IOC_NONE, 'G', 2, sizeof(struct virtio_vdmabuf_import)) +#define VIRTIO_VDMABUF_IOCTL_RELEASE \ +_IOC(_IOC_NONE, 'G', 3, sizeof(struct virtio_vdmabuf_import)) +struct virtio_vdmabuf_import { + /* IN parameters */ + /* vdmabuf id to be imported */ + virtio_vdmabuf_buf_id_t buf_id; + /* flags */ + int flags; + /* OUT parameters */ + /* exported dma buf fd */ + int fd; +}; + +#define VIRTIO_VDMABUF_IOCTL_EXPORT \ +_IOC(_IOC_NONE, 'G', 4, sizeof(struct virtio_vdmabuf_export)) +struct virtio_vdmabuf_export { + /* IN parameters */ + /* DMA buf fd to be exported */ + int fd; + /* exported dma buf id */ + virtio_vdmabuf_buf_id_t buf_id; + int sz_priv; + char *priv; +}; + +#endif diff --git a/include/standard-headers/linux/virtio_ids.h b/include/standard= -headers/linux/virtio_ids.h index bc1c0621f5..6c8c19fb6b 100644 --- a/include/standard-headers/linux/virtio_ids.h +++ b/include/standard-headers/linux/virtio_ids.h @@ -54,5 +54,6 @@ #define VIRTIO_ID_FS 26 /* virtio filesystem */ #define VIRTIO_ID_PMEM 27 /* virtio pmem */ #define VIRTIO_ID_MAC80211_HWSIM 29 /* virtio mac80211-hwsim */ +#define VIRTIO_ID_VDMABUF 37 /* virtio vdmabuf */ =20 #endif /* _LINUX_VIRTIO_IDS_H */ diff --git a/include/ui/console.h b/include/ui/console.h index d30e972d0b..892b7ff03f 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -400,6 +400,7 @@ void graphic_console_close(QemuConsole *con); =20 void graphic_hw_update(QemuConsole *con); void graphic_hw_update_done(QemuConsole *con); +void graphic_hw_dpy_refresh(QemuConsole *con); void graphic_hw_invalidate(QemuConsole *con); void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata); void graphic_hw_gl_block(QemuConsole *con, bool block); diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h index c998860d7b..d53faa59e9 100644 --- a/linux-headers/linux/vhost.h +++ b/linux-headers/linux/vhost.h @@ -150,4 +150,7 @@ /* Get the valid iova range */ #define VHOST_VDPA_GET_IOVA_RANGE _IOR(VHOST_VIRTIO, 0x78, \ struct vhost_vdpa_iova_range) +/* VHOST_VDMABUF specific defines */ +#define VHOST_VDMABUF_SET_RUNNING _IOW(VHOST_VIRTIO, 0x79, int) + #endif diff --git a/meson.build b/meson.build index 2d8b433ff0..1847abf9a4 100644 --- a/meson.build +++ b/meson.build @@ -2417,6 +2417,7 @@ summary_info +=3D {'vhost-net support': config_host.h= as_key('CONFIG_VHOST_NET')} summary_info +=3D {'vhost-crypto support': config_host.has_key('CONFIG_VHO= ST_CRYPTO')} summary_info +=3D {'vhost-scsi support': config_host.has_key('CONFIG_VHOST= _SCSI')} summary_info +=3D {'vhost-vsock support': config_host.has_key('CONFIG_VHOS= T_VSOCK')} +summary_info +=3D {'vhost-vdmabuf support': config_host.has_key('CONFIG_VH= OST_VDMABUF')} summary_info +=3D {'vhost-user support': config_host.has_key('CONFIG_VHOST= _USER')} summary_info +=3D {'vhost-user-blk server support': have_vhost_user_blk_se= rver} summary_info +=3D {'vhost-user-fs support': config_host.has_key('CONFIG_VH= OST_USER_FS')} diff --git a/ui/console.c b/ui/console.c index c5d11bc701..8a80e97195 100644 --- a/ui/console.c +++ b/ui/console.c @@ -284,6 +284,13 @@ void graphic_hw_update(QemuConsole *con) } } =20 +void graphic_hw_dpy_refresh(QemuConsole *con) +{ + DisplayState *ds =3D con ? con->ds : active_console->ds; + + dpy_refresh(ds); +} + void graphic_hw_gl_block(QemuConsole *con, bool block) { assert(con !=3D NULL); --=20 2.26.2