CHROMIUM: virtwl: add dmabuf sync ioctl This can be used to synchronize access to dmabuf backed virtio buffers. The virtio wayland device will use this to issue matching DMA_BUF_SYNC ioctls. The dmabuf driver on the host side can then handle this correctly (e.g. flush memory before it is potentially scanned out by display hardware). TEST=cache-line artifacts no longer noticeable BUG=chromium:837209 Change-Id: I0e797123fc0cfbc179a44e98ffd2ce7def53e2f5 Signed-off-by: David Reveman <reveman@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1076927 Reviewed-by: Dmitry Torokhov <dtor@chromium.org> Reviewed-by: Zach Reizner <zachr@chromium.org>
diff --git a/drivers/virtio/virtio_wl.c b/drivers/virtio/virtio_wl.c index 2e5f9d6..6636313 100644 --- a/drivers/virtio/virtio_wl.c +++ b/drivers/virtio/virtio_wl.c
@@ -58,6 +58,8 @@ #include <linux/virtio.h> #include <linux/virtio_wl.h> +#include <uapi/linux/dma-buf.h> + #define VFD_ILLEGAL_SIGN_BIT 0x80000000 #define VFD_HOST_VFD_ID_BIT 0x40000000 @@ -774,6 +776,46 @@ static int virtwl_vfd_send(struct file *filp, const char __user *buffer, return ret; } +static int virtwl_vfd_dmabuf_sync(struct file *filp, u32 flags) +{ + struct virtio_wl_ctrl_vfd_dmabuf_sync *ctrl_dmabuf_sync; + struct virtwl_vfd *vfd = filp->private_data; + struct virtwl_info *vi = vfd->vi; + struct completion finish_completion; + struct scatterlist out_sg; + struct scatterlist in_sg; + int ret = 0; + + ctrl_dmabuf_sync = kzalloc(sizeof(*ctrl_dmabuf_sync), GFP_KERNEL); + if (!ctrl_dmabuf_sync) + return -ENOMEM; + + ctrl_dmabuf_sync->hdr.type = VIRTIO_WL_CMD_VFD_DMABUF_SYNC; + ctrl_dmabuf_sync->vfd_id = vfd->id; + ctrl_dmabuf_sync->flags = flags; + + sg_init_one(&in_sg, &ctrl_dmabuf_sync->hdr, + sizeof(struct virtio_wl_ctrl_vfd_dmabuf_sync)); + sg_init_one(&out_sg, &ctrl_dmabuf_sync->hdr, + sizeof(struct virtio_wl_ctrl_hdr)); + + init_completion(&finish_completion); + ret = vq_queue_out(vi, &out_sg, &in_sg, &finish_completion, + false /* block */); + if (ret) { + pr_warn("virtwl: failed to queue dmabuf sync vfd id %u: %d\n", + vfd->id, + ret); + goto free_ctrl_dmabuf_sync; + } + + wait_for_completion(&finish_completion); + +free_ctrl_dmabuf_sync: + kfree(ctrl_dmabuf_sync); + return ret; +} + static ssize_t virtwl_vfd_read(struct file *filp, char __user *buffer, size_t size, loff_t *pos) { @@ -1074,6 +1116,22 @@ static long virtwl_ioctl_recv(struct file *filp, void __user *ptr) return ret; } +static long virtwl_ioctl_dmabuf_sync(struct file *filp, void __user *ptr) +{ + struct virtwl_ioctl_dmabuf_sync ioctl_dmabuf_sync; + int ret; + + ret = copy_from_user(&ioctl_dmabuf_sync, ptr, + sizeof(struct virtwl_ioctl_dmabuf_sync)); + if (ret) + return -EFAULT; + + if (ioctl_dmabuf_sync.flags & ~DMA_BUF_SYNC_VALID_FLAGS_MASK) + return -EINVAL; + + return virtwl_vfd_dmabuf_sync(filp, ioctl_dmabuf_sync.flags); +} + static long virtwl_vfd_ioctl(struct file *filp, unsigned int cmd, void __user *ptr) { @@ -1082,6 +1140,8 @@ static long virtwl_vfd_ioctl(struct file *filp, unsigned int cmd, return virtwl_ioctl_send(filp, ptr); case VIRTWL_IOCTL_RECV: return virtwl_ioctl_recv(filp, ptr); + case VIRTWL_IOCTL_DMABUF_SYNC: + return virtwl_ioctl_dmabuf_sync(filp, ptr); default: return -ENOTTY; }
diff --git a/include/uapi/linux/virtio_wl.h b/include/uapi/linux/virtio_wl.h index 89e0e42..76bf43e 100644 --- a/include/uapi/linux/virtio_wl.h +++ b/include/uapi/linux/virtio_wl.h
@@ -35,6 +35,7 @@ enum virtio_wl_ctrl_type { VIRTIO_WL_CMD_VFD_NEW_PIPE, /* virtio_wl_ctrl_vfd_new */ VIRTIO_WL_CMD_VFD_HUP, /* virtio_wl_ctrl_vfd */ VIRTIO_WL_CMD_VFD_NEW_DMABUF, /* virtio_wl_ctrl_vfd_new */ + VIRTIO_WL_CMD_VFD_DMABUF_SYNC, /* virtio_wl_ctrl_vfd_dmabuf_sync */ VIRTIO_WL_RESP_OK = 0x1000, VIRTIO_WL_RESP_VFD_NEW = 0x1001, /* virtio_wl_ctrl_vfd_new */ @@ -104,4 +105,10 @@ struct virtio_wl_ctrl_vfd_recv { /* the remainder is raw data */ }; +struct virtio_wl_ctrl_vfd_dmabuf_sync { + struct virtio_wl_ctrl_hdr hdr; + __le32 vfd_id; + __le32 flags; +}; + #endif /* _LINUX_VIRTIO_WL_H */
diff --git a/include/uapi/linux/virtwl.h b/include/uapi/linux/virtwl.h index b9c0ed7..9390413 100644 --- a/include/uapi/linux/virtwl.h +++ b/include/uapi/linux/virtwl.h
@@ -51,9 +51,14 @@ struct virtwl_ioctl_txn { __u8 data[0]; }; +struct virtwl_ioctl_dmabuf_sync { + __u32 flags; /* synchronization flags (see dma-buf.h) */ +}; + #define VIRTWL_IOCTL_NEW VIRTWL_IOWR(0x00, struct virtwl_ioctl_new) #define VIRTWL_IOCTL_SEND VIRTWL_IOR(0x01, struct virtwl_ioctl_txn) #define VIRTWL_IOCTL_RECV VIRTWL_IOW(0x02, struct virtwl_ioctl_txn) -#define VIRTWL_IOCTL_MAXNR 3 +#define VIRTWL_IOCTL_DMABUF_SYNC VIRTWL_IOR(0x03, \ + struct virtwl_ioctl_dmabuf_sync) #endif /* _LINUX_VIRTWL_H */