<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Thu, Jun 23, 2016 at 10:35 AM Chris Wilson <<a href="mailto:chris@chris-wilson.co.uk">chris@chris-wilson.co.uk</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">vGEM buffers are useful for passing data between software clients and<br>
hardware renders. By allowing the user to create and attach fences to<br>
the exported vGEM buffers (on the dma-buf), the user can implement a<br>
deferred renderer and queue hardware operations like flipping and then<br>
signal the buffer readiness (i.e. this allows the user to schedule<br>
operations out-of-order, but have them complete in-order).<br>
<br>
This also makes it much easier to write tightly controlled testcases for<br>
dma-buf fencing and signaling between hardware drivers.<br>
<br>
Testcase: igt/vgem_basic/dmabuf-fence<br>
Signed-off-by: Chris Wilson <<a href="mailto:chris@chris-wilson.co.uk" target="_blank">chris@chris-wilson.co.uk</a>><br>
Cc: Sean Paul <<a href="mailto:seanpaul@chromium.org" target="_blank">seanpaul@chromium.org</a>><br>
Cc: Zach Reizner <<a href="mailto:zachr@google.com" target="_blank">zachr@google.com</a>><br>
---<br>
 drivers/gpu/drm/vgem/Makefile     |   2 +-<br>
 drivers/gpu/drm/vgem/vgem_drv.c   |  34 ++++++<br>
 drivers/gpu/drm/vgem/vgem_drv.h   |  18 ++++<br>
 drivers/gpu/drm/vgem/vgem_fence.c | 217 ++++++++++++++++++++++++++++++++++++++<br>
 include/uapi/drm/vgem_drm.h       |  62 +++++++++++<br>
 5 files changed, 332 insertions(+), 1 deletion(-)<br>
 create mode 100644 drivers/gpu/drm/vgem/vgem_fence.c<br>
 create mode 100644 include/uapi/drm/vgem_drm.h<br>
<br>
diff --git a/drivers/gpu/drm/vgem/Makefile b/drivers/gpu/drm/vgem/Makefile<br>
index 3f4c7b842028..bfcdea1330e6 100644<br>
--- a/drivers/gpu/drm/vgem/Makefile<br>
+++ b/drivers/gpu/drm/vgem/Makefile<br>
@@ -1,4 +1,4 @@<br>
 ccflags-y := -Iinclude/drm<br>
-vgem-y := vgem_drv.o<br>
+vgem-y := vgem_drv.o vgem_fence.o<br>
<br>
 obj-$(CONFIG_DRM_VGEM) += vgem.o<br>
diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c<br>
index 69468b5f3d82..56e348701382 100644<br>
--- a/drivers/gpu/drm/vgem/vgem_drv.c<br>
+++ b/drivers/gpu/drm/vgem/vgem_drv.c<br>
@@ -83,6 +83,34 @@ static const struct vm_operations_struct vgem_gem_vm_ops = {<br>
        .close = drm_gem_vm_close,<br>
 };<br>
<br>
+static int vgem_open(struct drm_device *dev, struct drm_file *file)<br>
+{<br>
+       struct vgem_file *vfile;<br>
+       int ret;<br>
+<br>
+       vfile = kzalloc(sizeof(*vfile), GFP_KERNEL);<br>
+       if (!vfile)<br>
+               return -ENOMEM;<br>
+<br>
+       file->driver_priv = vfile;<br>
+<br>
+       ret = vgem_fence_open(vfile);<br>
+       if (ret) {<br>
+               kfree(vfile);<br>
+               return ret;<br>
+       }<br>
+<br>
+       return 0;<br>
+}<br>
+<br>
+static void vgem_preclose(struct drm_device *dev, struct drm_file *file)<br>
+{<br>
+       struct vgem_file *vfile = file->driver_priv;<br>
+<br>
+       vgem_fence_close(vfile);<br>
+       kfree(vfile);<br>
+}<br>
+<br>
 /* ioctls */<br>
<br>
 static struct drm_gem_object *vgem_gem_create(struct drm_device *dev,<br>
@@ -164,6 +192,8 @@ unref:<br>
 }<br>
<br>
 static struct drm_ioctl_desc vgem_ioctls[] = {<br>
+       DRM_IOCTL_DEF_DRV(VGEM_FENCE_ATTACH, vgem_fence_attach_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),<br>
+       DRM_IOCTL_DEF_DRV(VGEM_FENCE_SIGNAL, vgem_fence_signal_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),<br>
 };<br>
<br>
 static int vgem_mmap(struct file *filp, struct vm_area_struct *vma)<br>
@@ -286,9 +316,12 @@ static int vgem_prime_mmap(struct drm_gem_object *obj,<br>
<br>
 static struct drm_driver vgem_driver = {<br>
        .driver_features                = DRIVER_GEM | DRIVER_PRIME,<br>
+       .open                           = vgem_open,<br>
+       .preclose                       = vgem_preclose,<br>
        .gem_free_object_unlocked       = vgem_gem_free_object,<br>
        .gem_vm_ops                     = &vgem_gem_vm_ops,<br>
        .ioctls                         = vgem_ioctls,<br>
+       .num_ioctls                     = ARRAY_SIZE(vgem_ioctls),<br>
        .fops                           = &vgem_driver_fops,<br>
<br>
        .dumb_create                    = vgem_gem_dumb_create,<br>
@@ -343,5 +376,6 @@ module_init(vgem_init);<br>
 module_exit(vgem_exit);<br>
<br>
 MODULE_AUTHOR("Red Hat, Inc.");<br>
+MODULE_AUTHOR("Intel Corporation");<br>
 MODULE_DESCRIPTION(DRIVER_DESC);<br>
 MODULE_LICENSE("GPL and additional rights");<br>
diff --git a/drivers/gpu/drm/vgem/vgem_drv.h b/drivers/gpu/drm/vgem/vgem_drv.h<br>
index 988cbaae7588..88ce21010e28 100644<br>
--- a/drivers/gpu/drm/vgem/vgem_drv.h<br>
+++ b/drivers/gpu/drm/vgem/vgem_drv.h<br>
@@ -32,9 +32,27 @@<br>
 #include <drm/drmP.h><br>
 #include <drm/drm_gem.h><br>
<br>
+#include <uapi/drm/vgem_drm.h><br>
+<br>
+struct vgem_file {<br>
+       struct idr fence_idr;<br>
+       struct mutex fence_mutex;<br>
+       u64 fence_context;<br>
+       atomic_t fence_seqno;<br>
+};<br>
+<br>
 #define to_vgem_bo(x) container_of(x, struct drm_vgem_gem_object, base)<br>
 struct drm_vgem_gem_object {<br>
        struct drm_gem_object base;<br>
 };<br>
<br>
+int vgem_fence_open(struct vgem_file *file);<br>
+int vgem_fence_attach_ioctl(struct drm_device *dev,<br>
+                           void *data,<br>
+                           struct drm_file *file);<br>
+int vgem_fence_signal_ioctl(struct drm_device *dev,<br>
+                           void *data,<br>
+                           struct drm_file *file);<br>
+void vgem_fence_close(struct vgem_file *file);<br>
+<br>
 #endif<br>
diff --git a/drivers/gpu/drm/vgem/vgem_fence.c b/drivers/gpu/drm/vgem/vgem_fence.c<br>
new file mode 100644<br>
index 000000000000..46130e4a3506<br>
--- /dev/null<br>
+++ b/drivers/gpu/drm/vgem/vgem_fence.c<br>
@@ -0,0 +1,217 @@<br>
+/*<br>
+ * Copyright 2016 Intel Corporation<br>
+ *<br>
+ * Permission is hereby granted, free of charge, to any person obtaining a<br>
+ * copy of this software and associated documentation files (the "Software")<br>
+ * to deal in the software without restriction, including without limitation<br>
+ * on the rights to use, copy, modify, merge, publish, distribute, sub<br>
+ * license, and/or sell copies of the Software, and to permit persons to whom<br>
+ * them Software is furnished to do so, subject to the following conditions:<br>
+ *<br>
+ * The above copyright notice and this permission notice (including the next<br>
+ * paragraph) shall be included in all copies or substantial portions of the<br>
+ * Software.<br>
+ *<br>
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY,<br>
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL<br>
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER<br>
+ * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN<br>
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.<br>
+ */<br>
+<br>
+#include <linux/dma-buf.h><br>
+#include <linux/reservation.h><br>
+<br>
+#include "vgem_drv.h"<br>
+<br>
+struct vgem_fence {<br>
+       struct fence base;<br>
+       struct spinlock lock;<br>
+};<br>
+<br>
+static const char *vgem_fence_get_driver_name(struct fence *fence)<br>
+{<br>
+       return "vgem";<br>
+}<br>
+<br>
+static const char *vgem_fence_get_timeline_name(struct fence *fence)<br>
+{<br>
+       return "file";<br>
+}<br>
+<br>
+static bool vgem_fence_signaled(struct fence *fence)<br>
+{<br>
+       return false;<br>
+}<br>
+<br>
+static bool vgem_fence_enable_signaling(struct fence *fence)<br>
+{<br>
+       return true;<br>
+}<br>
+<br>
+static void vgem_fence_value_str(struct fence *fence, char *str, int size)<br>
+{<br>
+       snprintf(str, size, "%u", fence->seqno);<br>
+}<br>
+<br>
+static void vgem_fence_timeline_value_str(struct fence *fence, char *str,<br>
+                                         int size)<br>
+{<br>
+       snprintf(str, size, "%u", 0);<br>
+}<br>
+<br>
+const struct fence_ops vgem_fence_ops = {<br>
+       .get_driver_name = vgem_fence_get_driver_name,<br>
+       .get_timeline_name = vgem_fence_get_timeline_name,<br>
+       .enable_signaling = vgem_fence_enable_signaling,<br>
+       .signaled = vgem_fence_signaled,<br>
+       .wait = fence_default_wait,<br>
+       .fence_value_str = vgem_fence_value_str,<br>
+       .timeline_value_str = vgem_fence_timeline_value_str,<br>
+};<br>
+<br>
+static u32 vgem_fence_next_seqno(struct vgem_file *vfile)<br>
+{<br>
+       u32 seqno;<br>
+<br>
+       seqno = atomic_inc_return(&vfile->fence_seqno);<br>
+       if (seqno == 0)<br>
+               seqno = atomic_inc_return(&vfile->fence_seqno);<br>
+<br>
+       return seqno;<br>
+}<br>
+<br>
+static struct fence *vgem_fence_create(struct vgem_file *vfile)<br>
+{<br>
+       struct vgem_fence *fence;<br>
+<br>
+       fence = kzalloc(sizeof(*fence), GFP_KERNEL);<br>
+       if (!fence)<br>
+               return NULL;<br>
+<br>
+       spin_lock_init(&fence->lock);<br>
+       fence_init(&fence->base,<br>
+                  &vgem_fence_ops,<br>
+                  &fence->lock,<br>
+                  vfile->fence_context,<br>
+                  vgem_fence_next_seqno(vfile));<br>
+<br>
+       return &fence->base;<br>
+}<br>
+<br>
+static int attach_dmabuf(struct drm_device *dev,<br>
+                        struct drm_gem_object *obj)<br>
+{<br>
+       struct dma_buf *dmabuf;<br>
+<br>
+       if (obj->dma_buf)<br>
+               return 0;<br>
+<br>
+       dmabuf = dev->driver->gem_prime_export(dev, obj, 0);<br>
+       if (IS_ERR(dmabuf))<br>
+               return PTR_ERR(dmabuf);<br>
+<br>
+       obj->dma_buf = dmabuf;<br>
+       drm_gem_object_reference(obj);<br>
+       return 0;<br>
+}<br>
+<br>
+int vgem_fence_attach_ioctl(struct drm_device *dev,<br>
+                           void *data,<br>
+                           struct drm_file *file)<br>
+{<br>
+       struct drm_vgem_fence_attach *arg = data;<br>
+       struct vgem_file *vfile = file->driver_priv;<br>
+       struct reservation_object *resv;<br>
+       struct drm_gem_object *obj;<br>
+       struct fence *fence;<br>
+       int ret;<br>
+<br>
+       if (arg->flags & ~VGEM_FENCE_WRITE)<br>
+               return -EINVAL;<br>
+<br>
+       obj = drm_gem_object_lookup(file, arg->handle);<br>
+       if (!obj)<br>
+               return -ENOENT;<br>
+<br>
+       ret = attach_dmabuf(dev, obj);<br>
+       if (ret)<br>
+               goto out;<br>
+<br>
+       fence = vgem_fence_create(vfile);<br>
+       if (!fence) {<br>
+               ret = -ENOMEM;<br>
+               goto out;<br>
+       }<br>
+<br>
+       ret = 0;<br>
+       resv = obj->dma_buf->resv;<br>
+       mutex_lock(&resv->lock.base);<br>
+       if (arg->flags & VGEM_FENCE_WRITE)<br>
+               reservation_object_add_excl_fence(resv, fence);<br>
+       else if ((ret = reservation_object_reserve_shared(resv)) == 0)<br>
+               reservation_object_add_shared_fence(resv, fence);<br>
+       mutex_unlock(&resv->lock.base);<br>
+<br>
+       if (ret == 0) {<br>
+               mutex_lock(&vfile->fence_mutex);<br>
+               ret = idr_alloc(&vfile->fence_idr, fence, 1, 0, GFP_KERNEL);<br>
+               mutex_unlock(&vfile->fence_mutex);<br>
+               if (ret > 0) {<br>
+                       arg->out_fence = ret;<br>
+                       ret = 0;<br>
+               }<br>
+       }<br>
+       if (ret)<br>
+               fence_put(fence);<br>
+out:<br>
+       drm_gem_object_unreference_unlocked(obj);<br>
+       return ret;<br>
+}<br>
+<br>
+int vgem_fence_signal_ioctl(struct drm_device *dev,<br>
+                           void *data,<br>
+                           struct drm_file *file)<br>
+{<br>
+       struct vgem_file *vfile = file->driver_priv;<br>
+       struct drm_vgem_fence_signal *arg = data;<br>
+       struct fence *fence;<br>
+<br>
+       if (arg->flags)<br>
+               return -EINVAL;<br>
+<br>
+       mutex_lock(&vfile->fence_mutex);<br>
+       fence = idr_replace(&vfile->fence_idr, NULL, arg->fence);<br>
+       mutex_unlock(&vfile->fence_mutex);<br>
+       if (!fence)<br>
+               return -ENOENT;<br>
+       if (IS_ERR(fence))<br>
+               return PTR_ERR(fence);<br>
+<br>
+       fence_signal(fence);<br>
+       fence_put(fence);<br>
+       return 0;<br>
+}<br>
+<br>
+int vgem_fence_open(struct vgem_file *vfile)<br>
+{<br>
+       mutex_init(&vfile->fence_mutex);<br>
+       idr_init(&vfile->fence_idr);<br>
+       vfile->fence_context = fence_context_alloc(1);<br>
+<br>
+       return 0;<br>
+}<br>
+<br>
+static int __vgem_fence_idr_fini(int id, void *p, void *data)<br>
+{<br>
+       fence_signal(p);<br>
+       fence_put(p);<br>
+       return 0;<br>
+}<br>
+<br>
+void vgem_fence_close(struct vgem_file *vfile)<br>
+{<br>
+       idr_for_each(&vfile->fence_idr, __vgem_fence_idr_fini, vfile);<br>
+       idr_destroy(&vfile->fence_idr);<br>
+}<br>
diff --git a/include/uapi/drm/vgem_drm.h b/include/uapi/drm/vgem_drm.h<br>
new file mode 100644<br>
index 000000000000..352d2fae8de9<br>
--- /dev/null<br>
+++ b/include/uapi/drm/vgem_drm.h<br>
@@ -0,0 +1,62 @@<br>
+/*<br>
+ * Copyright 2016 Intel Corporation<br>
+ * All Rights Reserved.<br>
+ *<br>
+ * Permission is hereby granted, free of charge, to any person obtaining a<br>
+ * copy of this software and associated documentation files (the<br>
+ * "Software"), to deal in the Software without restriction, including<br>
+ * without limitation the rights to use, copy, modify, merge, publish,<br>
+ * distribute, sub license, and/or sell copies of the Software, and to<br>
+ * permit persons to whom the Software is furnished to do so, subject to<br>
+ * the following conditions:<br>
+ *<br>
+ * The above copyright notice and this permission notice (including the<br>
+ * next paragraph) shall be included in all copies or substantial portions<br>
+ * of the Software.<br>
+ *<br>
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS<br>
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF<br>
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.<br>
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR<br>
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,<br>
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE<br>
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.<br>
+ *<br>
+ */<br>
+<br>
+#ifndef _UAPI_VGEM_DRM_H_<br>
+#define _UAPI_VGEM_DRM_H_<br>
+<br>
+#include "drm.h"<br>
+<br>
+#if defined(__cplusplus)<br>
+extern "C" {<br>
+#endif<br>
+<br>
+/* Please note that modifications to all structs defined here are<br>
+ * subject to backwards-compatibility constraints.<br>
+ */<br>
+#define DRM_VGEM_FENCE_ATTACH  0x1<br>
+#define DRM_VGEM_FENCE_SIGNAL  0x2<br>
+<br>
+#define DRM_IOCTL_VGEM_FENCE_ATTACH    DRM_IOWR( DRM_COMMAND_BASE + DRM_VGEM_FENCE_ATTACH, struct drm_vgem_fence_attach)<br>
+#define DRM_IOCTL_VGEM_FENCE_SIGNAL    DRM_IOW( DRM_COMMAND_BASE + DRM_VGEM_FENCE_SIGNAL, struct drm_vgem_fence_signal)<br>
+<br>
+struct drm_vgem_fence_attach {<br>
+       __u32 handle;<br>
+       __u32 flags;<br>
+#define VGEM_FENCE_WRITE 0x1<br>
+       __u32 out_fence;<br>
+       __u32 pad;<br>
+};<br>
+<br>
+struct drm_vgem_fence_signal {<br>
+       __u32 fence;<br>
+       __u32 flags;<br>
+};<br>
+<br>
+#if defined(__cplusplus)<br>
+}<br>
+#endif<br>
+<br>
+#endif /* _UAPI_VGEM_DRM_H_ */<br>
--<br>
2.8.1<br></blockquote><div><span style="line-height:1.5;font-size:13px;color:rgb(33,33,33);font-family:"helvetica neue",helvetica,arial,sans-serif">Acked-by: Zach Reizner <</span><a href="mailto:zachr@google.com" target="_blank" style="line-height:1.5;font-size:13px;font-family:"helvetica neue",helvetica,arial,sans-serif">zachr@google.com</a><span style="line-height:1.5;font-size:13px;color:rgb(33,33,33);font-family:"helvetica neue",helvetica,arial,sans-serif">> </span><span style="line-height:1.5;font-size:13px;color:rgb(33,33,33);font-family:"helvetica neue",helvetica,arial,sans-serif"> </span> </div><div> </div></div></div>