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 */