From patchwork Fri Jan 26 13:58:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomeu Vizoso X-Patchwork-Id: 125983 Delivered-To: patch@linaro.org Received: by 10.46.84.92 with SMTP id y28csp352858ljd; Fri, 26 Jan 2018 05:58:40 -0800 (PST) X-Google-Smtp-Source: AH8x224kKBAt1VrkRI+W2KUKPhAwQHwWLLvqBw8xGMUVRYedXTDzS+N2H6XO0IGs6NRVbGLZvm8p X-Received: by 10.98.194.212 with SMTP id w81mr18848775pfk.232.1516975120036; Fri, 26 Jan 2018 05:58:40 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516975120; cv=none; d=google.com; s=arc-20160816; b=IFJf3uFQb8Vh0FZbbvnl9lKPcrSJPDL3euFA+XM6qE/kYoSd5B5/UK0yTMSZr1RgrV fXV57Kx8BegdJMpF6p34I21Dgs59UnpRNLVHfyDq0/4qhIfq3i/2gDAdzWDIOAWo8THF o1473pBDD7mcC3zO5KJLkI6qlA/qTJpxUu8/XglnLo57KRHaiFAfMgLm+VZTWHSCAcdM zk5YNqlxqOPksxsr8fxet1rylTpNfpJgN55PVQELAZMD8M52qV5RGLEjzko9iAATXlXq J7ulO1yqMXxNiRoyc4vH+m9zK3wbFDEBRjMUBqlGB1FjbQ5CNoj+4b+c49e/4PZq+vLa A27Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=khBSF+6CjDbiF/vL/JG9Fyk3vwkNp5z1G6emgNKNFO8=; b=UdyemFBaomTygFbJp95W1C6bqVrg2bXocgltuG7ej4lWKtoqATl74O/kxLB+IK1uWY Um6rpuLOr/YLmxIAVAnJlB8nruBYQVH4aD9SndbCVLHXtsAZM4ZyKc+XCbaJBe2chbjA /vKbRGxr15bzBk9P+CUkvLDmanQWXvra6UEUDe3nXb/LTWhg4W4rN7GsEf7EjfoqXMl7 Y9zNwjS9xQA8wXxyR7JxY4/bv1Pkl0mouPXtWvKGu+tHlTV6kJNpBoc2ejOUDaj5LqJH +VBc6ZY57csTpdKdEI01IHcsSqZZAACxPPhL+1CW5wpQAVnMgXJjXEskJZKVWp0GqRna UC5Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@gmail.com header.s=20161025 header.b=VnFelF0T; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=collabora.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 62-v6si3796526pla.713.2018.01.26.05.58.39; Fri, 26 Jan 2018 05:58:40 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=fail header.i=@gmail.com header.s=20161025 header.b=VnFelF0T; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=collabora.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753277AbeAZN6g (ORCPT + 28 others); Fri, 26 Jan 2018 08:58:36 -0500 Received: from mail-wm0-f67.google.com ([74.125.82.67]:50453 "EHLO mail-wm0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752261AbeAZN6Q (ORCPT ); Fri, 26 Jan 2018 08:58:16 -0500 Received: by mail-wm0-f67.google.com with SMTP id f71so1443187wmf.0 for ; Fri, 26 Jan 2018 05:58:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=khBSF+6CjDbiF/vL/JG9Fyk3vwkNp5z1G6emgNKNFO8=; b=VnFelF0TxgN2tohsaobC7cS+rvWM6JTS7ISKfJwy5Qh9E+9DVotPYODEQRZlPVP34V eQIQ17//0bg8Q8OxUaxcY/Vgd4bOfZ9Zt564BZOpgmVDTfuPykTrfKQxguBGtmjMS3g/ MnJgsPSQfKa+fXaVnQ0CMwQW1I6U7UveXJgcvQZNexauHb5+mni3XUtsA3Oou/IyNBEx ZNFMwkaFj21EKsE4kmCkhqTcmjo7uQUSsbG7EppXPmAMaLdqnIOF25ytJ7cPJg5dlqyd Fa0xQwn+3I2JNkLSFqN/1axL92cGE1Unn4Ek6IBbj2rv09MF1wYcgmGAQR6nu19/oxAE nXBw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=khBSF+6CjDbiF/vL/JG9Fyk3vwkNp5z1G6emgNKNFO8=; b=Szm6wcQ5hXuxhfbpogD1hd7OQ4gSgUjw+2o1HrBvBDjbv4OY2oylk7AJ+OJ5dOhb/s RjIuOEkt85VMlWwosSuOPNHxpFHa/ufydeHCGT3LY9UY0Qzg2RSaFkbPcCtUnfiaNRyW mc8lUAWKdXn6eV7eEVLsM0RY79r64NBI9tDv5IRHO+F1WiZKJxa82ddCpl3X0TU02Ine cAShjaVttwM+erwAjIirBWOCwCfsh4Hh8nhaZK5EOySRRSw8VKRJJe6x9D7/qv3UR9Yt rIdDbVmHQpzWh9vpzOzimu+gyuPlUjWeh9ado5XfJxaFfvxKCFOyVFYlp3UlXi2wq5rq QapQ== X-Gm-Message-State: AKwxytfTUEcpYc1qGpF+sJNylK+exi8VfYJE10IdVckL7v40E3XbB8/d x/WlIRz3gYpB6o5DIk6LdGIHEUz0 X-Received: by 10.28.166.20 with SMTP id p20mr10301849wme.85.1516975094665; Fri, 26 Jan 2018 05:58:14 -0800 (PST) Received: from cizrna.lan ([109.72.12.188]) by smtp.gmail.com with ESMTPSA id c19sm3674481wmd.5.2018.01.26.05.58.13 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 26 Jan 2018 05:58:13 -0800 (PST) From: Tomeu Vizoso To: linux-kernel@vger.kernel.org Cc: Zach Reizner , kernel@collabora.com, Tomeu Vizoso , dri-devel@lists.freedesktop.org, virtualization@lists.linux-foundation.org, "Michael S. Tsirkin" , David Airlie , Jason Wang , Gerd Hoffmann Subject: [PATCH v3 1/2] drm/virtio: Add window server support Date: Fri, 26 Jan 2018 14:58:01 +0100 Message-Id: <20180126135803.29781-2-tomeu.vizoso@collabora.com> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180126135803.29781-1-tomeu.vizoso@collabora.com> References: <20180126135803.29781-1-tomeu.vizoso@collabora.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This is to allow clients running within VMs to be able to communicate with a compositor in the host. Clients will use the communication protocol that the compositor supports, and virtio-gpu will assist with making buffers available in both sides, and copying content as needed. It is expected that a service in the guest will act as a proxy, interacting with virtio-gpu to support unmodified clients. For some features of the protocol, the hypervisor might have to intervene and also parse the protocol data to properly bridge resources. The following IOCTLs have been added to this effect: *_WINSRV_CONNECT: Opens a connection to the compositor in the host, returns a FD that represents this connection and on which the following IOCTLs can be used. Callers are expected to poll this FD for new messages from the compositor. *_WINSRV_TX: Asks the hypervisor to forward a message to the compositor *_WINSRV_RX: Returns all queued messages Alongside protocol data that is opaque to the kernel, the client can send file descriptors that reference GEM buffers allocated by virtio-gpu. The guest proxy is expected to figure out when a client is passing a FD that refers to shared memory in the guest and allocate a virtio-gpu buffer of the same size with DRM_VIRTGPU_RESOURCE_CREATE. When the client notifies the compositor that it can read from that buffer, the proxy should copy the contents from the SHM region to the virtio-gpu resource and call DRM_VIRTGPU_TRANSFER_TO_HOST. This has been tested with Wayland clients that make use of wl_shm to pass buffers to the compositor, but is expected to work similarly for X clients that make use of MIT-SHM with FD passing. v2: * Add padding to two virtio command structs * Properly cast two __user pointers (kbuild test robot) v3: * Handle absence of winsrv support in QEMU (Dave Airlie) Signed-off-by: Tomeu Vizoso --- drivers/gpu/drm/virtio/virtgpu_drv.c | 1 + drivers/gpu/drm/virtio/virtgpu_drv.h | 39 ++++- drivers/gpu/drm/virtio/virtgpu_ioctl.c | 165 +++++++++++++++++++ drivers/gpu/drm/virtio/virtgpu_kms.c | 66 ++++++-- drivers/gpu/drm/virtio/virtgpu_vq.c | 285 ++++++++++++++++++++++++++++++++- include/uapi/drm/virtgpu_drm.h | 29 ++++ include/uapi/linux/virtio_gpu.h | 43 +++++ 7 files changed, 613 insertions(+), 15 deletions(-) -- 2.14.3 diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index 49a3d8d5a249..a528ddedd09f 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -79,6 +79,7 @@ static unsigned int features[] = { */ VIRTIO_GPU_F_VIRGL, #endif + VIRTIO_GPU_F_WINSRV, }; static struct virtio_driver virtio_gpu_driver = { .feature_table = features, diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index da2fb585fea4..268b386e1232 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -178,6 +178,8 @@ struct virtio_gpu_device { struct virtio_gpu_queue ctrlq; struct virtio_gpu_queue cursorq; + struct virtio_gpu_queue winsrv_rxq; + struct virtio_gpu_queue winsrv_txq; struct kmem_cache *vbufs; bool vqs_ready; @@ -205,10 +207,32 @@ struct virtio_gpu_device { struct virtio_gpu_fpriv { uint32_t ctx_id; + + struct list_head winsrv_conns; /* list of virtio_gpu_winsrv_conn */ + spinlock_t winsrv_lock; +}; + +struct virtio_gpu_winsrv_rx_qentry { + struct virtio_gpu_winsrv_rx *cmd; + struct list_head next; +}; + +struct virtio_gpu_winsrv_conn { + struct virtio_gpu_device *vgdev; + + spinlock_t lock; + + int fd; + struct drm_file *drm_file; + + struct list_head cmdq; /* queue of virtio_gpu_winsrv_rx_qentry */ + wait_queue_head_t cmdwq; + + struct list_head next; }; /* virtio_ioctl.c */ -#define DRM_VIRTIO_NUM_IOCTLS 10 +#define DRM_VIRTIO_NUM_IOCTLS 11 extern struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS]; /* virtio_kms.c */ @@ -318,9 +342,22 @@ virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, void virtio_gpu_ctrl_ack(struct virtqueue *vq); void virtio_gpu_cursor_ack(struct virtqueue *vq); void virtio_gpu_fence_ack(struct virtqueue *vq); +void virtio_gpu_winsrv_tx_ack(struct virtqueue *vq); +void virtio_gpu_winsrv_rx_read(struct virtqueue *vq); void virtio_gpu_dequeue_ctrl_func(struct work_struct *work); void virtio_gpu_dequeue_cursor_func(struct work_struct *work); +void virtio_gpu_dequeue_winsrv_rx_func(struct work_struct *work); +void virtio_gpu_dequeue_winsrv_tx_func(struct work_struct *work); void virtio_gpu_dequeue_fence_func(struct work_struct *work); +void virtio_gpu_fill_winsrv_rx(struct virtio_gpu_device *vgdev); +void virtio_gpu_queue_winsrv_rx_in(struct virtio_gpu_device *vgdev, + struct virtio_gpu_winsrv_rx *cmd); +int virtio_gpu_cmd_winsrv_connect(struct virtio_gpu_device *vgdev, int fd); +void virtio_gpu_cmd_winsrv_disconnect(struct virtio_gpu_device *vgdev, int fd); +int virtio_gpu_cmd_winsrv_tx(struct virtio_gpu_device *vgdev, + const char __user *buffer, u32 len, + int *fds, struct virtio_gpu_winsrv_conn *conn, + bool nonblock); /* virtio_gpu_display.c */ int virtio_gpu_framebuffer_init(struct drm_device *dev, diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index 0528edb4a2bf..d4230b1fa91d 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -25,6 +25,9 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include +#include + #include #include #include @@ -527,6 +530,165 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev, return 0; } +static unsigned int winsrv_poll(struct file *filp, + struct poll_table_struct *wait) +{ + struct virtio_gpu_winsrv_conn *conn = filp->private_data; + unsigned int mask = 0; + + spin_lock(&conn->lock); + poll_wait(filp, &conn->cmdwq, wait); + if (!list_empty(&conn->cmdq)) + mask |= POLLIN | POLLRDNORM; + spin_unlock(&conn->lock); + + return mask; +} + +static int winsrv_ioctl_rx(struct virtio_gpu_device *vgdev, + struct virtio_gpu_winsrv_conn *conn, + struct drm_virtgpu_winsrv *cmd) +{ + struct virtio_gpu_winsrv_rx_qentry *qentry, *tmp; + struct virtio_gpu_winsrv_rx *virtio_cmd; + int available_len = cmd->len; + int read_count = 0; + + list_for_each_entry_safe(qentry, tmp, &conn->cmdq, next) { + virtio_cmd = qentry->cmd; + if (virtio_cmd->len > available_len) + return 0; + + if (copy_to_user((void __user *)cmd->data + read_count, + virtio_cmd->data, + virtio_cmd->len)) { + /* return error unless we have some data to return */ + if (read_count == 0) + return -EFAULT; + } + + available_len -= virtio_cmd->len; + read_count += virtio_cmd->len; + + virtio_gpu_queue_winsrv_rx_in(vgdev, virtio_cmd); + + list_del(&qentry->next); + kfree(qentry); + } + + cmd->len = read_count; + + return 0; +} + +static long winsrv_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct virtio_gpu_winsrv_conn *conn = filp->private_data; + struct virtio_gpu_device *vgdev = conn->vgdev; + struct drm_virtgpu_winsrv winsrv_cmd; + int ret; + + if (_IOC_SIZE(cmd) > sizeof(winsrv_cmd)) + return -EINVAL; + + if (copy_from_user(&winsrv_cmd, (void __user *)arg, + _IOC_SIZE(cmd)) != 0) + return -EFAULT; + + switch (cmd) { + case DRM_IOCTL_VIRTGPU_WINSRV_RX: + ret = winsrv_ioctl_rx(vgdev, conn, &winsrv_cmd); + if (copy_to_user((void __user *)arg, &winsrv_cmd, + _IOC_SIZE(cmd)) != 0) + return -EFAULT; + + break; + + case DRM_IOCTL_VIRTGPU_WINSRV_TX: + ret = virtio_gpu_cmd_winsrv_tx(vgdev, + u64_to_user_ptr(winsrv_cmd.data), + winsrv_cmd.len, + winsrv_cmd.fds, + conn, + filp->f_flags & O_NONBLOCK); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int winsrv_release(struct inode *inodep, struct file *filp) +{ + struct virtio_gpu_winsrv_conn *conn = filp->private_data; + struct virtio_gpu_device *vgdev = conn->vgdev; + + virtio_gpu_cmd_winsrv_disconnect(vgdev, conn->fd); + + list_del(&conn->next); + kfree(conn); + + return 0; +} + +static const struct file_operations winsrv_fops = { + .poll = winsrv_poll, + .unlocked_ioctl = winsrv_ioctl, + .release = winsrv_release, +}; + +static int virtio_gpu_winsrv_connect(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct virtio_gpu_device *vgdev = dev->dev_private; + struct virtio_gpu_fpriv *vfpriv = file->driver_priv; + struct drm_virtgpu_winsrv_connect *args = data; + struct virtio_gpu_winsrv_conn *conn; + int ret; + + if (!virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_WINSRV)) + return -ENODEV; + + conn = kzalloc(sizeof(*conn), GFP_KERNEL); + if (!conn) + return -ENOMEM; + + conn->vgdev = vgdev; + conn->drm_file = file; + spin_lock_init(&conn->lock); + INIT_LIST_HEAD(&conn->cmdq); + init_waitqueue_head(&conn->cmdwq); + + ret = anon_inode_getfd("[virtgpu_winsrv]", &winsrv_fops, conn, + O_CLOEXEC | O_RDWR); + if (ret < 0) + goto free_conn; + + conn->fd = ret; + + ret = virtio_gpu_cmd_winsrv_connect(vgdev, conn->fd); + if (ret < 0) + goto close_fd; + + spin_lock(&vfpriv->winsrv_lock); + list_add_tail(&conn->next, &vfpriv->winsrv_conns); + spin_unlock(&vfpriv->winsrv_lock); + + args->fd = conn->fd; + + return 0; + +close_fd: + sys_close(conn->fd); + +free_conn: + kfree(conn); + + return ret; +} + struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS] = { DRM_IOCTL_DEF_DRV(VIRTGPU_MAP, virtio_gpu_map_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), @@ -558,4 +720,7 @@ struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS] = { DRM_IOCTL_DEF_DRV(VIRTGPU_GET_CAPS, virtio_gpu_get_caps_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + + DRM_IOCTL_DEF_DRV(VIRTGPU_WINSRV_CONNECT, virtio_gpu_winsrv_connect, + DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), }; diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index 6400506a06b0..87b118d4b13c 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c @@ -128,13 +128,16 @@ static void virtio_gpu_get_capsets(struct virtio_gpu_device *vgdev, int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) { static vq_callback_t *callbacks[] = { - virtio_gpu_ctrl_ack, virtio_gpu_cursor_ack + virtio_gpu_ctrl_ack, virtio_gpu_cursor_ack, + virtio_gpu_winsrv_rx_read, virtio_gpu_winsrv_tx_ack }; - static const char * const names[] = { "control", "cursor" }; + static const char * const names[] = { "control", "cursor", + "winsrv-rx", "winsrv-tx" }; struct virtio_gpu_device *vgdev; /* this will expand later */ - struct virtqueue *vqs[2]; + struct virtqueue *vqs[4]; + int nr_queues = 2; u32 num_scanouts, num_capsets; int ret; @@ -158,6 +161,10 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) init_waitqueue_head(&vgdev->resp_wq); virtio_gpu_init_vq(&vgdev->ctrlq, virtio_gpu_dequeue_ctrl_func); virtio_gpu_init_vq(&vgdev->cursorq, virtio_gpu_dequeue_cursor_func); + virtio_gpu_init_vq(&vgdev->winsrv_rxq, + virtio_gpu_dequeue_winsrv_rx_func); + virtio_gpu_init_vq(&vgdev->winsrv_txq, + virtio_gpu_dequeue_winsrv_tx_func); vgdev->fence_drv.context = dma_fence_context_alloc(1); spin_lock_init(&vgdev->fence_drv.lock); @@ -175,13 +182,21 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) DRM_INFO("virgl 3d acceleration not supported by guest\n"); #endif - ret = virtio_find_vqs(vgdev->vdev, 2, vqs, callbacks, names, NULL); + if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_WINSRV)) + nr_queues += 2; + + ret = virtio_find_vqs(vgdev->vdev, nr_queues, vqs, callbacks, names, + NULL); if (ret) { DRM_ERROR("failed to find virt queues\n"); goto err_vqs; } vgdev->ctrlq.vq = vqs[0]; vgdev->cursorq.vq = vqs[1]; + if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_WINSRV)) { + vgdev->winsrv_rxq.vq = vqs[2]; + vgdev->winsrv_txq.vq = vqs[3]; + } ret = virtio_gpu_alloc_vbufs(vgdev); if (ret) { DRM_ERROR("failed to alloc vbufs\n"); @@ -215,6 +230,10 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) goto err_modeset; virtio_device_ready(vgdev->vdev); + + if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_WINSRV)) + virtio_gpu_fill_winsrv_rx(vgdev); + vgdev->vqs_ready = true; if (num_capsets) @@ -256,6 +275,8 @@ void virtio_gpu_driver_unload(struct drm_device *dev) vgdev->vqs_ready = false; flush_work(&vgdev->ctrlq.dequeue_work); flush_work(&vgdev->cursorq.dequeue_work); + flush_work(&vgdev->winsrv_rxq.dequeue_work); + flush_work(&vgdev->winsrv_txq.dequeue_work); flush_work(&vgdev->config_changed_work); vgdev->vdev->config->del_vqs(vgdev->vdev); @@ -274,25 +295,43 @@ int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file) uint32_t id; char dbgname[64], tmpname[TASK_COMM_LEN]; - /* can't create contexts without 3d renderer */ - if (!vgdev->has_virgl_3d) - return 0; - - get_task_comm(tmpname, current); - snprintf(dbgname, sizeof(dbgname), "%s", tmpname); - dbgname[63] = 0; /* allocate a virt GPU context for this opener */ vfpriv = kzalloc(sizeof(*vfpriv), GFP_KERNEL); if (!vfpriv) return -ENOMEM; - virtio_gpu_context_create(vgdev, strlen(dbgname), dbgname, &id); + /* can't create contexts without 3d renderer */ + if (vgdev->has_virgl_3d) { + get_task_comm(tmpname, current); + snprintf(dbgname, sizeof(dbgname), "%s", tmpname); + dbgname[63] = 0; + + virtio_gpu_context_create(vgdev, strlen(dbgname), dbgname, &id); + + vfpriv->ctx_id = id; + } + + spin_lock_init(&vfpriv->winsrv_lock); + INIT_LIST_HEAD(&vfpriv->winsrv_conns); - vfpriv->ctx_id = id; file->driver_priv = vfpriv; + return 0; } +static void virtio_gpu_cleanup_conns(struct virtio_gpu_fpriv *vfpriv) +{ + struct virtio_gpu_winsrv_conn *conn, *tmp; + struct virtio_gpu_winsrv_rx_qentry *qentry, *tmp2; + + list_for_each_entry_safe(conn, tmp, &vfpriv->winsrv_conns, next) { + list_for_each_entry_safe(qentry, tmp2, &conn->cmdq, next) { + kfree(qentry); + } + kfree(conn); + } +} + void virtio_gpu_driver_postclose(struct drm_device *dev, struct drm_file *file) { struct virtio_gpu_device *vgdev = dev->dev_private; @@ -303,6 +342,7 @@ void virtio_gpu_driver_postclose(struct drm_device *dev, struct drm_file *file) vfpriv = file->driver_priv; + virtio_gpu_cleanup_conns(vfpriv); virtio_gpu_context_destroy(vgdev, vfpriv->ctx_id); kfree(vfpriv); file->driver_priv = NULL; diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 9eb96fb2c147..ea5f9352d364 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -32,7 +32,7 @@ #include #include -#define MAX_INLINE_CMD_SIZE 96 +#define MAX_INLINE_CMD_SIZE 144 #define MAX_INLINE_RESP_SIZE 24 #define VBUFFER_SIZE (sizeof(struct virtio_gpu_vbuffer) \ + MAX_INLINE_CMD_SIZE \ @@ -72,6 +72,67 @@ void virtio_gpu_cursor_ack(struct virtqueue *vq) schedule_work(&vgdev->cursorq.dequeue_work); } +void virtio_gpu_winsrv_rx_read(struct virtqueue *vq) +{ + struct drm_device *dev = vq->vdev->priv; + struct virtio_gpu_device *vgdev = dev->dev_private; + + schedule_work(&vgdev->winsrv_rxq.dequeue_work); +} + +void virtio_gpu_winsrv_tx_ack(struct virtqueue *vq) +{ + struct drm_device *dev = vq->vdev->priv; + struct virtio_gpu_device *vgdev = dev->dev_private; + + schedule_work(&vgdev->winsrv_txq.dequeue_work); +} + +void virtio_gpu_queue_winsrv_rx_in(struct virtio_gpu_device *vgdev, + struct virtio_gpu_winsrv_rx *cmd) +{ + struct virtqueue *vq = vgdev->winsrv_rxq.vq; + struct scatterlist sg[1]; + int ret; + + sg_init_one(sg, cmd, sizeof(*cmd)); + + spin_lock(&vgdev->winsrv_rxq.qlock); +retry: + ret = virtqueue_add_inbuf(vq, sg, 1, cmd, GFP_KERNEL); + if (ret == -ENOSPC) { + spin_unlock(&vgdev->winsrv_rxq.qlock); + wait_event(vgdev->winsrv_rxq.ack_queue, vq->num_free); + spin_lock(&vgdev->winsrv_rxq.qlock); + goto retry; + } + virtqueue_kick(vq); + spin_unlock(&vgdev->winsrv_rxq.qlock); +} + +void virtio_gpu_fill_winsrv_rx(struct virtio_gpu_device *vgdev) +{ + struct virtqueue *vq = vgdev->winsrv_rxq.vq; + struct virtio_gpu_winsrv_rx *cmd; + int ret = 0; + + while (vq->num_free > 0) { + cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto clear_queue; + } + + virtio_gpu_queue_winsrv_rx_in(vgdev, cmd); + } + + return; + +clear_queue: + while ((cmd = virtqueue_detach_unused_buf(vq))) + kfree(cmd); +} + int virtio_gpu_alloc_vbufs(struct virtio_gpu_device *vgdev) { vgdev->vbufs = kmem_cache_create("virtio-gpu-vbufs", @@ -258,6 +319,96 @@ void virtio_gpu_dequeue_cursor_func(struct work_struct *work) wake_up(&vgdev->cursorq.ack_queue); } +void virtio_gpu_dequeue_winsrv_tx_func(struct work_struct *work) +{ + struct virtio_gpu_device *vgdev = + container_of(work, struct virtio_gpu_device, + winsrv_txq.dequeue_work); + struct virtio_gpu_vbuffer *vbuf; + int len; + + spin_lock(&vgdev->winsrv_txq.qlock); + do { + while ((vbuf = virtqueue_get_buf(vgdev->winsrv_txq.vq, &len))) + free_vbuf(vgdev, vbuf); + } while (!virtqueue_enable_cb(vgdev->winsrv_txq.vq)); + spin_unlock(&vgdev->winsrv_txq.qlock); + + wake_up(&vgdev->winsrv_txq.ack_queue); +} + +static struct virtio_gpu_winsrv_conn *find_conn(struct virtio_gpu_device *vgdev, + int fd) +{ + struct virtio_gpu_winsrv_conn *conn; + struct drm_device *ddev = vgdev->ddev; + struct drm_file *file; + struct virtio_gpu_fpriv *vfpriv; + + mutex_lock(&ddev->filelist_mutex); + list_for_each_entry(file, &ddev->filelist, lhead) { + vfpriv = file->driver_priv; + spin_lock(&vfpriv->winsrv_lock); + list_for_each_entry(conn, &vfpriv->winsrv_conns, next) { + if (conn->fd == fd) { + spin_lock(&conn->lock); + spin_unlock(&vfpriv->winsrv_lock); + mutex_unlock(&ddev->filelist_mutex); + return conn; + } + } + spin_unlock(&vfpriv->winsrv_lock); + } + mutex_unlock(&ddev->filelist_mutex); + + return NULL; +} + +static void handle_rx_cmd(struct virtio_gpu_device *vgdev, + struct virtio_gpu_winsrv_rx *cmd) +{ + struct virtio_gpu_winsrv_conn *conn; + struct virtio_gpu_winsrv_rx_qentry *qentry; + + conn = find_conn(vgdev, cmd->client_fd); + if (!conn) { + DRM_DEBUG("recv for unknown client fd %u\n", cmd->client_fd); + return; + } + + qentry = kzalloc(sizeof(*qentry), GFP_KERNEL); + if (!qentry) { + spin_unlock(&conn->lock); + DRM_DEBUG("failed to allocate qentry for winsrv connection\n"); + return; + } + + qentry->cmd = cmd; + + list_add_tail(&qentry->next, &conn->cmdq); + wake_up_interruptible(&conn->cmdwq); + spin_unlock(&conn->lock); +} + +void virtio_gpu_dequeue_winsrv_rx_func(struct work_struct *work) +{ + struct virtio_gpu_device *vgdev = + container_of(work, struct virtio_gpu_device, + winsrv_rxq.dequeue_work); + struct virtio_gpu_winsrv_rx *cmd; + unsigned int len; + + spin_lock(&vgdev->winsrv_rxq.qlock); + while ((cmd = virtqueue_get_buf(vgdev->winsrv_rxq.vq, &len)) != NULL) { + spin_unlock(&vgdev->winsrv_rxq.qlock); + handle_rx_cmd(vgdev, cmd); + spin_lock(&vgdev->winsrv_rxq.qlock); + } + spin_unlock(&vgdev->winsrv_rxq.qlock); + + virtqueue_kick(vgdev->winsrv_rxq.vq); +} + static int virtio_gpu_queue_ctrl_buffer_locked(struct virtio_gpu_device *vgdev, struct virtio_gpu_vbuffer *vbuf) __releases(&vgdev->ctrlq.qlock) @@ -380,6 +531,41 @@ static int virtio_gpu_queue_cursor(struct virtio_gpu_device *vgdev, return ret; } +static int virtio_gpu_queue_winsrv_tx(struct virtio_gpu_device *vgdev, + struct virtio_gpu_vbuffer *vbuf) +{ + struct virtqueue *vq = vgdev->winsrv_txq.vq; + struct scatterlist *sgs[2], vcmd, vout; + int ret; + + if (!vgdev->vqs_ready) + return -ENODEV; + + sg_init_one(&vcmd, vbuf->buf, vbuf->size); + sgs[0] = &vcmd; + + sg_init_one(&vout, vbuf->data_buf, vbuf->data_size); + sgs[1] = &vout; + + spin_lock(&vgdev->winsrv_txq.qlock); +retry: + ret = virtqueue_add_sgs(vq, sgs, 2, 0, vbuf, GFP_ATOMIC); + if (ret == -ENOSPC) { + spin_unlock(&vgdev->winsrv_txq.qlock); + wait_event(vgdev->winsrv_txq.ack_queue, vq->num_free); + spin_lock(&vgdev->winsrv_txq.qlock); + goto retry; + } + + virtqueue_kick(vq); + + spin_unlock(&vgdev->winsrv_txq.qlock); + + if (!ret) + ret = vq->num_free; + return ret; +} + /* just create gem objects for userspace and long lived objects, just use dma_alloced pages for the queue objects? */ @@ -890,3 +1076,100 @@ void virtio_gpu_cursor_ping(struct virtio_gpu_device *vgdev, memcpy(cur_p, &output->cursor, sizeof(output->cursor)); virtio_gpu_queue_cursor(vgdev, vbuf); } + +int virtio_gpu_cmd_winsrv_connect(struct virtio_gpu_device *vgdev, int fd) +{ + struct virtio_gpu_winsrv_connect *cmd_p; + struct virtio_gpu_vbuffer *vbuf; + + cmd_p = virtio_gpu_alloc_cmd(vgdev, &vbuf, sizeof(*cmd_p)); + memset(cmd_p, 0, sizeof(*cmd_p)); + + cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_WINSRV_CONNECT); + cmd_p->client_fd = cpu_to_le32(fd); + return virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); +} + +void virtio_gpu_cmd_winsrv_disconnect(struct virtio_gpu_device *vgdev, int fd) +{ + struct virtio_gpu_winsrv_disconnect *cmd_p; + struct virtio_gpu_vbuffer *vbuf; + + cmd_p = virtio_gpu_alloc_cmd(vgdev, &vbuf, sizeof(*cmd_p)); + memset(cmd_p, 0, sizeof(*cmd_p)); + + cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_WINSRV_DISCONNECT); + cmd_p->client_fd = cpu_to_le32(fd); + virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); +} + +int virtio_gpu_cmd_winsrv_tx(struct virtio_gpu_device *vgdev, + const char __user *buffer, u32 len, + int *fds, struct virtio_gpu_winsrv_conn *conn, + bool nonblock) +{ + int client_fd = conn->fd; + struct drm_file *file = conn->drm_file; + struct virtio_gpu_winsrv_tx *cmd_p; + struct virtio_gpu_vbuffer *vbuf; + uint32_t gem_handle; + struct drm_gem_object *gobj = NULL; + struct virtio_gpu_object *qobj = NULL; + int ret, i, fd; + + cmd_p = virtio_gpu_alloc_cmd(vgdev, &vbuf, sizeof(*cmd_p)); + memset(cmd_p, 0, sizeof(*cmd_p)); + + cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_WINSRV_TX); + + for (i = 0; i < VIRTIO_GPU_WINSRV_MAX_ALLOCS; i++) { + cmd_p->resource_ids[i] = -1; + + fd = fds[i]; + if (fd < 0) + break; + + ret = drm_gem_prime_fd_to_handle(vgdev->ddev, file, fd, + &gem_handle); + if (ret != 0) + goto err_free_vbuf; + + gobj = drm_gem_object_lookup(file, gem_handle); + if (gobj == NULL) { + ret = -ENOENT; + goto err_free_vbuf; + } + + qobj = gem_to_virtio_gpu_obj(gobj); + cmd_p->resource_ids[i] = qobj->hw_res_handle; + } + + cmd_p->client_fd = client_fd; + cmd_p->len = cpu_to_le32(len); + + /* gets freed when the ring has consumed it */ + vbuf->data_buf = kmalloc(cmd_p->len, GFP_KERNEL); + if (!vbuf->data_buf) { + DRM_ERROR("failed to allocate winsrv tx buffer\n"); + ret = -ENOMEM; + goto err_free_vbuf; + } + + vbuf->data_size = cmd_p->len; + + if (copy_from_user(vbuf->data_buf, buffer, cmd_p->len)) { + ret = -EFAULT; + goto err_free_databuf; + } + + virtio_gpu_queue_winsrv_tx(vgdev, vbuf); + + return 0; + +err_free_databuf: + kfree(vbuf->data_buf); +err_free_vbuf: + free_vbuf(vgdev, vbuf); + + return ret; +} diff --git a/include/uapi/drm/virtgpu_drm.h b/include/uapi/drm/virtgpu_drm.h index 91a31ffed828..89b0a1a707a7 100644 --- a/include/uapi/drm/virtgpu_drm.h +++ b/include/uapi/drm/virtgpu_drm.h @@ -46,6 +46,11 @@ extern "C" { #define DRM_VIRTGPU_TRANSFER_TO_HOST 0x07 #define DRM_VIRTGPU_WAIT 0x08 #define DRM_VIRTGPU_GET_CAPS 0x09 +#define DRM_VIRTGPU_WINSRV_CONNECT 0x0a +#define DRM_VIRTGPU_WINSRV_TX 0x0b +#define DRM_VIRTGPU_WINSRV_RX 0x0c + +#define VIRTGPU_WINSRV_MAX_ALLOCS 28 struct drm_virtgpu_map { __u64 offset; /* use for mmap system call */ @@ -132,6 +137,18 @@ struct drm_virtgpu_get_caps { __u32 pad; }; +struct drm_virtgpu_winsrv { + __s32 fds[VIRTGPU_WINSRV_MAX_ALLOCS]; + __u64 data; + __u32 len; + __u32 pad; +}; + +struct drm_virtgpu_winsrv_connect { + __u32 fd; /* returned by kernel */ + __u32 pad; +}; + #define DRM_IOCTL_VIRTGPU_MAP \ DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_MAP, struct drm_virtgpu_map) @@ -167,6 +184,18 @@ struct drm_virtgpu_get_caps { DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_GET_CAPS, \ struct drm_virtgpu_get_caps) +#define DRM_IOCTL_VIRTGPU_WINSRV_CONNECT \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_WINSRV_CONNECT, \ + struct drm_virtgpu_winsrv_connect) + +#define DRM_IOCTL_VIRTGPU_WINSRV_TX \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_WINSRV_TX, \ + struct drm_virtgpu_winsrv) + +#define DRM_IOCTL_VIRTGPU_WINSRV_RX \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_WINSRV_RX, \ + struct drm_virtgpu_winsrv) + #if defined(__cplusplus) } #endif diff --git a/include/uapi/linux/virtio_gpu.h b/include/uapi/linux/virtio_gpu.h index 4b04ead26cd9..3567f84d03e9 100644 --- a/include/uapi/linux/virtio_gpu.h +++ b/include/uapi/linux/virtio_gpu.h @@ -41,6 +41,7 @@ #include #define VIRTIO_GPU_F_VIRGL 0 +#define VIRTIO_GPU_F_WINSRV 1 enum virtio_gpu_ctrl_type { VIRTIO_GPU_UNDEFINED = 0, @@ -71,6 +72,12 @@ enum virtio_gpu_ctrl_type { VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300, VIRTIO_GPU_CMD_MOVE_CURSOR, + /* window server commands */ + VIRTIO_GPU_CMD_WINSRV_CONNECT = 0x0400, + VIRTIO_GPU_CMD_WINSRV_DISCONNECT, + VIRTIO_GPU_CMD_WINSRV_TX, + VIRTIO_GPU_CMD_WINSRV_RX, + /* success responses */ VIRTIO_GPU_RESP_OK_NODATA = 0x1100, VIRTIO_GPU_RESP_OK_DISPLAY_INFO, @@ -290,6 +297,42 @@ struct virtio_gpu_resp_capset { __u8 capset_data[]; }; +/* VIRTIO_GPU_CMD_WINSRV_CONNECT */ +struct virtio_gpu_winsrv_connect { + struct virtio_gpu_ctrl_hdr hdr; + __le32 client_fd; + __le32 padding; +}; + +/* VIRTIO_GPU_CMD_WINSRV_DISCONNECT */ +struct virtio_gpu_winsrv_disconnect { + struct virtio_gpu_ctrl_hdr hdr; + __le32 client_fd; + __le32 padding; +}; + +#define VIRTIO_GPU_WINSRV_MAX_ALLOCS 28 +#define VIRTIO_GPU_WINSRV_TX_MAX_DATA 4096 + +/* VIRTIO_GPU_CMD_WINSRV_TX */ +/* these commands are followed in the queue descriptor by protocol buffers */ +struct virtio_gpu_winsrv_tx { + struct virtio_gpu_ctrl_hdr hdr; + __u32 client_fd; + __u32 len; + __le32 resource_ids[VIRTIO_GPU_WINSRV_MAX_ALLOCS]; +}; + +/* VIRTIO_GPU_CMD_WINSRV_RX */ +struct virtio_gpu_winsrv_rx { + struct virtio_gpu_ctrl_hdr hdr; + __le32 client_fd; + __u8 data[VIRTIO_GPU_WINSRV_TX_MAX_DATA]; + __u32 len; + __u64 pfns[VIRTIO_GPU_WINSRV_MAX_ALLOCS]; + __u32 lens[VIRTIO_GPU_WINSRV_MAX_ALLOCS]; +}; + #define VIRTIO_GPU_EVENT_DISPLAY (1 << 0) struct virtio_gpu_config { From patchwork Fri Jan 26 13:58:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomeu Vizoso X-Patchwork-Id: 125984 Delivered-To: patch@linaro.org Received: by 10.46.84.92 with SMTP id y28csp352954ljd; Fri, 26 Jan 2018 05:58:51 -0800 (PST) X-Google-Smtp-Source: AH8x224ylHjsBhHOyTa6Rx4QkGq/Cw0HheFV1DtJqK316enFj63d3NmIdp4tvRuvlng4fJpLJfl3 X-Received: by 2002:a17:902:9683:: with SMTP id n3-v6mr14084697plp.177.1516975131555; Fri, 26 Jan 2018 05:58:51 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516975131; cv=none; d=google.com; s=arc-20160816; b=tXh4BvOAGDCDhYK3dBQbvvIJlaet/VS5KTuhbvXd9WPu6OpvCHdIYEGxArKyQcM6hw qS/sLjE4bX4kqX2wjYKf2+CzggRKKAcicI0g4QqtlYfswx99JwreU9OPLCC011L9mWFE EFGXRAil8Psg+OOkdxo4XSo+ZV0pJShpzflk5RuCfHhCZiPLrEwL2qHnOiLhyvFQkfsR Ym5MR0WetSHDjDwREVL40mYaJG9riPofFSITOm8SIhCEg7nUYkclI9K1wgJQoVfDMB5R nidc+nLsypoDuf+I0imUjUhbj+oBN74xV8+BgkzIZ9PrKaNaA96QDtrMAPccIZNh1XAd G5cg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=EK/Hg/YN7WzYLMliKDElUmSFxLjQPmm4IiBK5bRf1yk=; b=Ps1ImPUCzufkcd1RSL4/EJHrtKFkAzC5R/ab0nIP4+Vj68DCm/W30ZIYCGU/dpn19F 5EkX6Nn6yuxUuuzymNj+4in25TcjDW7p8UwJXOU5eFMDuSlhL6MQrvHlODsFxIhavZjP JLlAg9339lS3vX8SWdQy/iK4bNqGX2eGrE3wnlU0vbIG2DOgqLB4kCJLOdl64Z2hbFQT ad+YE/JsWjCGbi3rgwtC/j2q2ppTfsgU5wqqkBUeT6NL64X9FohuXs3h7piCFmujDGJK y4g3v2YtXzm74OP+5elqKZu2QVm8HNQgrOnCX/lBVdLAL+v2Fmo/esx4NB3cZWc64Gq9 JLlw== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@gmail.com header.s=20161025 header.b=RzGGTHJ9; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=collabora.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s6si3050975pgr.221.2018.01.26.05.58.51; Fri, 26 Jan 2018 05:58:51 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=fail header.i=@gmail.com header.s=20161025 header.b=RzGGTHJ9; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=collabora.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753066AbeAZN6f (ORCPT + 28 others); Fri, 26 Jan 2018 08:58:35 -0500 Received: from mail-wm0-f68.google.com ([74.125.82.68]:34856 "EHLO mail-wm0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752842AbeAZN6R (ORCPT ); Fri, 26 Jan 2018 08:58:17 -0500 Received: by mail-wm0-f68.google.com with SMTP id r78so21437348wme.0 for ; Fri, 26 Jan 2018 05:58:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=EK/Hg/YN7WzYLMliKDElUmSFxLjQPmm4IiBK5bRf1yk=; b=RzGGTHJ9pFvZ0XZ3P6ZuWFW9HZS4XNtwys95zeMy9iNvVF5Wrw+zSb171EUw6njt8V hIMW8BarMHhtjsHhLpLMtDY4G8SZCbowh3RE9c4bYEIeMY/z/jwMQlVeJsVcicTD2cV9 9wJXoZl3EQWpGSXDuzZXIi4qmG2CkwwIdM3UaCNEf/YwtXpwjHp1UjbVPFcJy59VrcX8 I06wEG8RVIYHfjEJ7kuGHCq3/ZHXRmuSosIPKzjQaLfnbau+ubWgpBNhjzn9eY9dVqm3 Nbyhh+bKAyv1r4LeGcU+L1E/jXLyDwCVkZznWnwdGfo+hsf523CdjbNeFUgIs+r+ffBr Ajaw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=EK/Hg/YN7WzYLMliKDElUmSFxLjQPmm4IiBK5bRf1yk=; b=Y4yo12/O9eR+4NhVXcp06Bc5jBpBfXH5r1FXxoSKcu1ZyHDBybht0PYAejMRHd+YZ4 vm8n5BneUk4dJQqYxjb3mJpqAaHhdbGSlG4E7SIAdk0y/FGRauLlSgFOYBTM+pQXBaQp Hb8W0m2n/4j8Dlf+Oo0Oodx6oburaP4PMxHli/AFWKbQJ0c1+qKWjruBf8NKE+nH22tg nw+w6WnZK48XHS3+CPa2GzXckDS69iwfdWuyeSqQ5kPD2gXbbvQbQ+iKdku6PotlRIop BjOLj7KWzDlwSJKqBvqkZXOnNrXiAK6PLOO4RUWQgzQoZgqaSK8StDGVUovoJ4ecqB38 yMyg== X-Gm-Message-State: AKwxytfWSkZp0nDYXJ8bXD7Lhbx9/ue3V4nDYW3Oxm8e5Ri1c6a0TLpl jPENUQBPv4krCjK399bzhba5Kc6M X-Received: by 10.28.20.8 with SMTP id 8mr10395743wmu.106.1516975096315; Fri, 26 Jan 2018 05:58:16 -0800 (PST) Received: from cizrna.lan ([109.72.12.188]) by smtp.gmail.com with ESMTPSA id c19sm3674481wmd.5.2018.01.26.05.58.14 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 26 Jan 2018 05:58:15 -0800 (PST) From: Tomeu Vizoso To: linux-kernel@vger.kernel.org Cc: Zach Reizner , kernel@collabora.com, Tomeu Vizoso , David Airlie , Gerd Hoffmann , dri-devel@lists.freedesktop.org, virtualization@lists.linux-foundation.org Subject: [PATCH v3 2/2] drm/virtio: Handle buffers from the compositor Date: Fri, 26 Jan 2018 14:58:02 +0100 Message-Id: <20180126135803.29781-3-tomeu.vizoso@collabora.com> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180126135803.29781-1-tomeu.vizoso@collabora.com> References: <20180126135803.29781-1-tomeu.vizoso@collabora.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org When retrieving queued messages from the compositor in the host for clients in the guest, handle buffers that may be passed. These buffers should have been mapped to the guest's address space, for example via the KVM_SET_USER_MEMORY_REGION ioctl. Signed-off-by: Tomeu Vizoso --- drivers/gpu/drm/virtio/virtgpu_ioctl.c | 54 ++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) -- 2.14.3 diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index d4230b1fa91d..57b1ad51d251 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -545,14 +545,58 @@ static unsigned int winsrv_poll(struct file *filp, return mask; } +struct virtio_gpu_winsrv_region { + uint64_t pfn; + size_t size; +}; + +static int winsrv_fd_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct virtio_gpu_winsrv_region *region = filp->private_data; + unsigned long vm_size = vma->vm_end - vma->vm_start; + int ret = 0; + + if (vm_size + + (vma->vm_pgoff << PAGE_SHIFT) > PAGE_ALIGN(region->size)) + return -EINVAL; + + ret = io_remap_pfn_range(vma, vma->vm_start, region->pfn, vm_size, + vma->vm_page_prot); + if (ret) + return ret; + + vma->vm_flags |= VM_PFNMAP | VM_IO | VM_DONTEXPAND | VM_DONTDUMP; + + return ret; +} + +static int winsrv_fd_release(struct inode *inodep, struct file *filp) +{ + struct virtio_gpu_winsrv_region *region = filp->private_data; + + kfree(region); + + return 0; +} + +static const struct file_operations winsrv_fd_fops = { + .mmap = winsrv_fd_mmap, + .release = winsrv_fd_release, +}; + static int winsrv_ioctl_rx(struct virtio_gpu_device *vgdev, struct virtio_gpu_winsrv_conn *conn, struct drm_virtgpu_winsrv *cmd) { struct virtio_gpu_winsrv_rx_qentry *qentry, *tmp; struct virtio_gpu_winsrv_rx *virtio_cmd; + struct virtio_gpu_winsrv_region *region; int available_len = cmd->len; int read_count = 0; + int i; + + for (i = 0; i < VIRTGPU_WINSRV_MAX_ALLOCS; i++) + cmd->fds[i] = -1; list_for_each_entry_safe(qentry, tmp, &conn->cmdq, next) { virtio_cmd = qentry->cmd; @@ -567,6 +611,16 @@ static int winsrv_ioctl_rx(struct virtio_gpu_device *vgdev, return -EFAULT; } + for (i = 0; virtio_cmd->pfns[i]; i++) { + region = kmalloc(sizeof(*region), GFP_KERNEL); + region->pfn = virtio_cmd->pfns[i]; + region->size = virtio_cmd->lens[i]; + cmd->fds[i] = anon_inode_getfd("[winsrv_fd]", + &winsrv_fd_fops, + region, + O_CLOEXEC | O_RDWR); + } + available_len -= virtio_cmd->len; read_count += virtio_cmd->len;