This allows vmwgfx to wait on a fence created by another
device.

v2:
* Remove special handling for vmwgfx fence and just use dma_fence_wait()
* Use interruptible waits
* Added function documentation

Signed-off-by: Sinclair Yeh <s...@vmware.com>
Reviewed-by: Deepak Singh Rawat <dra...@vmware.com>
Reviewed-by: Thomas Hellstrom <thellst...@vmware.com>
---
 drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 24 ++++++++++++++++--
 drivers/gpu/drm/vmwgfx/vmwgfx_fence.c   | 45 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/vmwgfx/vmwgfx_fence.h   |  4 +++
 3 files changed, 71 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index c8d7fb0..e9cdaa4 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -24,6 +24,7 @@
  * USE OR OTHER DEALINGS IN THE SOFTWARE.
  *
  **************************************************************************/
+#include <linux/sync_file.h>
 
 #include "vmwgfx_drv.h"
 #include "vmwgfx_reg.h"
@@ -4414,6 +4415,7 @@ int vmw_execbuf_ioctl(struct drm_device *dev, unsigned 
long data,
        static const size_t copy_offset[] = {
                offsetof(struct drm_vmw_execbuf_arg, context_handle),
                sizeof(struct drm_vmw_execbuf_arg)};
+       struct dma_fence *in_fence = NULL;
 
        if (unlikely(size < copy_offset[0])) {
                DRM_ERROR("Invalid command size, ioctl %d\n",
@@ -4453,6 +4455,21 @@ int vmw_execbuf_ioctl(struct drm_device *dev, unsigned 
long data,
                break;
        }
 
+
+       /* If imported a fence FD from elsewhere, then wait on it */
+       if (arg.flags & DRM_VMW_EXECBUF_FLAG_IMPORT_FENCE_FD) {
+               in_fence = sync_file_get_fence(arg.imported_fence_fd);
+
+               if (!in_fence) {
+                       DRM_ERROR("Cannot get imported fence\n");
+                       return -EINVAL;
+               }
+
+               ret = vmw_wait_dma_fence(dev_priv->fman, in_fence);
+               if (ret)
+                       goto out;
+       }
+
        ret = ttm_read_lock(&dev_priv->reservation_sem, true);
        if (unlikely(ret != 0))
                return ret;
@@ -4465,9 +4482,12 @@ int vmw_execbuf_ioctl(struct drm_device *dev, unsigned 
long data,
                                  NULL);
        ttm_read_unlock(&dev_priv->reservation_sem);
        if (unlikely(ret != 0))
-               return ret;
+               goto out;
 
        vmw_kms_cursor_post_execbuf(dev_priv);
 
-       return 0;
+out:
+       if (in_fence)
+               dma_fence_put(in_fence);
+       return ret;
 }
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
index e83841a..e62f027 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
@@ -644,6 +644,51 @@ int vmw_user_fence_create(struct drm_file *file_priv,
 
 
 /**
+ * vmw_wait_dma_fence - Wait for a dma fence
+ *
+ * @fman: pointer to a fence manager
+ * @fence: DMA fence to wait on
+ *
+ * This function handles the case when the fence is actually a fence
+ * array.  If that's the case, it'll wait on each of the child fence
+ */
+int vmw_wait_dma_fence(struct vmw_fence_manager *fman,
+                      struct dma_fence *fence)
+{
+       struct dma_fence_array *fence_array;
+       int ret = 0;
+       int i;
+
+
+       if (dma_fence_is_signaled(fence))
+               return 0;
+
+       if (!dma_fence_is_array(fence))
+               return dma_fence_wait(fence, true);
+
+       /* From i915: Note that if the fence-array was created in
+        * signal-on-any mode, we should *not* decompose it into its individual
+        * fences. However, we don't currently store which mode the fence-array
+        * is operating in. Fortunately, the only user of signal-on-any is
+        * private to amdgpu and we should not see any incoming fence-array
+        * from sync-file being in signal-on-any mode.
+        */
+
+       fence_array = to_dma_fence_array(fence);
+       for (i = 0; i < fence_array->num_fences; i++) {
+               struct dma_fence *child = fence_array->fences[i];
+
+               ret = dma_fence_wait(child, true);
+
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+
+/**
  * vmw_fence_fifo_down - signal all unsignaled fence objects.
  */
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h 
b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
index d9d85aa..20224db 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
@@ -28,6 +28,7 @@
 #ifndef _VMWGFX_FENCE_H_
 
 #include <linux/dma-fence.h>
+#include <linux/dma-fence-array.h>
 
 #define VMW_FENCE_WAIT_TIMEOUT (5*HZ)
 
@@ -102,6 +103,9 @@ extern int vmw_user_fence_create(struct drm_file *file_priv,
                                 struct vmw_fence_obj **p_fence,
                                 uint32_t *p_handle);
 
+extern int vmw_wait_dma_fence(struct vmw_fence_manager *fman,
+                             struct dma_fence *fence);
+
 extern void vmw_fence_fifo_up(struct vmw_fence_manager *fman);
 
 extern void vmw_fence_fifo_down(struct vmw_fence_manager *fman);
-- 
2.7.4

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to