[PATCH 08/32] drm/i915: Extract the in-fence from a dma-buf reservation object

Chris Wilson chris at chris-wilson.co.uk
Wed Feb 22 23:05:27 UTC 2017


The dma-buf holds an array of fences, which unlike the sync_file are not
sealed and may be modified at runtime. For the purpose of computing
dependencies, we can take a snapshot of the fences within the
dma-buf's reservation object (converting them into a fence-array) and
uses that as our input fence to this execbuf. It also provides a means
for us to pass in an array of fences and ask to only wait on the first
being signaled.

In short, it allows dma-buf to be used as a *reusable* container for
multiple signaling objects, and for scheduling execbuf between clients.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
Cc: Mika Kuoppala <mika.kuoppala at linux.intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen at linux.intel.com>
Cc: Jason Ekstrand <jason.ekstrand at intel.com>
Cc: Gustavo Padovan <gustavo at padovan.org>
---
 drivers/gpu/drm/i915/i915_drv.c            |  1 +
 drivers/gpu/drm/i915/i915_gem_execbuffer.c | 62 ++++++++++++++++++++++++++++--
 include/uapi/drm/i915_drm.h                | 26 +++++++++++--
 3 files changed, 83 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index b76e8f7ac174..409fc32ce2bd 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -352,6 +352,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
 	case I915_PARAM_HAS_EXEC_SOFTPIN:
 	case I915_PARAM_HAS_EXEC_ASYNC:
 	case I915_PARAM_HAS_EXEC_FENCE:
+	case I915_PARAM_HAS_EXEC_FENCE_DMABUF:
 		/* For the time being all of these are always true;
 		 * if some supported hardware does not have one of these
 		 * features this value needs to be provided from
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 35d2cb979452..3f2796131410 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -26,6 +26,7 @@
  *
  */
 
+#include <linux/dma-buf.h>
 #include <linux/dma_remapping.h>
 #include <linux/reservation.h>
 #include <linux/sync_file.h>
@@ -1574,6 +1575,49 @@ eb_select_engine(struct drm_i915_private *dev_priv,
 	return engine;
 }
 
+static struct dma_fence *
+dma_buf_get_fence(int fd, unsigned int flags)
+{
+	struct dma_buf *dmabuf;
+	struct dma_fence_array *array;
+	struct dma_fence **shared, *excl;
+	unsigned int count, i;
+
+	dmabuf = dma_buf_get(fd);
+	if (IS_ERR(dmabuf))
+		return ERR_CAST(dmabuf);
+
+	shared = NULL;
+	count = 0;
+	if (flags & I915_EXEC_FENCE_EXCL) {
+		excl = reservation_object_get_excl_rcu(dmabuf->resv);
+	} else {
+		int err;
+
+		err = reservation_object_get_fences_rcu(dmabuf->resv,
+							&excl, &count, &shared);
+		if (err) {
+			array = ERR_PTR(err);
+			goto out_put;
+		}
+	}
+
+	if (excl)
+		array = dma_fence_array_create(1, &excl, 0, 0, false);
+	else if (shared)
+		array = dma_fence_array_create(count, shared, 0, 0,
+					       flags & I915_EXEC_FENCE_ANY);
+	else
+		array = NULL;
+
+	for (i = 0 ; i < count; i++)
+		dma_fence_put(shared[i]);
+	kfree(shared);
+out_put:
+	dma_buf_put(dmabuf);
+	return &array->base;
+}
+
 static int
 i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 		       struct drm_file *file,
@@ -1638,9 +1682,21 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 	}
 
 	if (args->flags & I915_EXEC_FENCE_IN) {
-		in_fence = sync_file_get_fence(lower_32_bits(args->rsvd2));
-		if (!in_fence)
-			return -EINVAL;
+		int fd = lower_32_bits(args->rsvd2);
+
+		in_fence = dma_buf_get_fence(fd, args->flags);
+		if (IS_ERR(in_fence)) {
+			if (in_fence != ERR_PTR(-EINVAL))
+				return PTR_ERR(in_fence);
+
+			if (args->flags &
+			    (I915_EXEC_FENCE_ANY | I915_EXEC_FENCE_EXCL))
+				return -EINVAL;
+
+			in_fence = sync_file_get_fence(fd);
+			if (!in_fence)
+				return -EINVAL;
+		}
 	}
 
 	if (args->flags & I915_EXEC_FENCE_OUT) {
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 3554495bef13..ebc7641b5252 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -412,6 +412,12 @@ typedef struct drm_i915_irq_wait {
  */
 #define I915_PARAM_HAS_EXEC_FENCE	 44
 
+/* Query whether DRM_I915_GEM_EXECBUFFER2 supports using a dma-buf fd as the
+ * in-fence for explicit fence support. See I915_EXEC_FENCE_IN and
+ * I915_EXEC_FENCE_ANY.
+ */
+#define I915_PARAM_HAS_EXEC_FENCE_DMABUF 45
+
 typedef struct drm_i915_getparam {
 	__s32 param;
 	/*
@@ -865,8 +871,8 @@ struct drm_i915_gem_execbuffer2 {
 #define I915_EXEC_RESOURCE_STREAMER     (1<<15)
 
 /* Setting I915_EXEC_FENCE_IN implies that lower_32_bits(rsvd2) represent
- * a sync_file fd to wait upon (in a nonblocking manner) prior to executing
- * the batch.
+ * a sync_file or dma-buf fd to wait upon (in a nonblocking manner) prior
+ * to executing the batch.
  *
  * Returns -EINVAL if the sync_file fd cannot be found.
  */
@@ -889,7 +895,21 @@ struct drm_i915_gem_execbuffer2 {
  */
 #define I915_EXEC_FENCE_OUT		(1<<17)
 
-#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_OUT<<1))
+/* If the I915_EXEC_FENCE_IN refers to a dma-buf fd, a fence is created from
+ * its reservation object and it may contain just the exclusive fence, or
+ * an array of all shared fences. Setting I915_EXEC_FENCE_EXCL implies that
+ * the execbuf should only wait for the current exclusive fence to be signaled
+ * before execution.
+ */
+#define I915_EXEC_FENCE_EXCL		(1<<18)
+
+/* If the I915_EXEC_FENCE_IN refers to a dma-buf fd, a fence is created from
+ * its reservation object and it may either be signaled on the first fence
+ * within to complet or it may wait for all fences within to be complete.
+ */
+#define I915_EXEC_FENCE_ANY		(1<<19)
+
+#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_ANY<<1))
 
 #define I915_EXEC_CONTEXT_ID_MASK	(0xffffffff)
 #define i915_execbuffer2_set_context_id(eb2, context) \
-- 
2.11.0



More information about the Intel-gfx-trybot mailing list