drm/vmwgfx: Add support for imported Fence File Descriptor
authorSinclair Yeh <syeh@vmware.com>
Wed, 5 Jul 2017 08:45:40 +0000 (01:45 -0700)
committerSinclair Yeh <syeh@vmware.com>
Mon, 28 Aug 2017 15:51:38 +0000 (17:51 +0200)
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 <syeh@vmware.com>
Reviewed-by: Deepak Singh Rawat <drawat@vmware.com>
Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com>
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
drivers/gpu/drm/vmwgfx/vmwgfx_fence.h

index 178dabcdb198f545cded6ebd0cdc00b42d77a71a..f94f43cca58ec3e3e171d624166bd8b3989ee963 100644 (file)
@@ -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;
 }
index c812570ff159fb5dd75f30bce4c1f573386a80f1..21563ca8ac1e724f58eb1f41f2919689f6d34387 100644 (file)
@@ -644,6 +644,51 @@ out_no_object:
 }
 
 
+/**
+ * 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.
  */
index d9d85aa6ed2048a96e1ae0df0637b25161b74132..20224dba9d8e02f94ae17f6671eaeee74a392663 100644 (file)
@@ -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);