<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Aug 3, 2017 at 11:58 AM, Chris Wilson <span dir="ltr"><<a href="mailto:chris@chris-wilson.co.uk" target="_blank">chris@chris-wilson.co.uk</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">From: Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>><br>
<br>
This commit adds support for waiting on or signaling DRM syncobjs as<br>
part of execbuf. It does so by hijacking the currently unused cliprects<br>
pointer to instead point to an array of i915_gem_exec_fence structs<br>
which containe a DRM syncobj and a flags parameter which specifies<br>
whether to wait on it or to signal it. This implementation<br>
theoretically allows for both flags to be set in which case it waits on<br>
the dma_fence that was in the syncobj and then immediately replaces it<br>
with the dma_fence from the current execbuf.<br>
<br>
v2:<br>
- Rebase on new syncobj API<br>
v3:<br>
- Pull everything out into helpers<br>
- Do all allocation in gem_execbuffer2<br>
- Pack the flags in the bottom 2 bits of the drm_syncobj*<br>
v4:<br>
- Prevent a potential race on syncobj->fence<br>
<br>
Testcase: igt/gem_exec_fence/syncobj*<br>
Signed-off-by: Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>><br>
Link: <a href="https://patchwork.freedesktop.org/patch/msgid/1499289202-25441-1-git-send-email-jason.ekstrand@intel.com" rel="noreferrer" target="_blank">https://patchwork.freedesktop.<wbr>org/patch/msgid/1499289202-<wbr>25441-1-git-send-email-jason.<wbr>ekstrand@intel.com</a><br>
Reviewed-by: Chris Wilson <<a href="mailto:chris@chris-wilson.co.uk">chris@chris-wilson.co.uk</a>><br>
Signed-off-by: Chris Wilson <<a href="mailto:chris@chris-wilson.co.uk">chris@chris-wilson.co.uk</a>><br>
---<br>
drivers/gpu/drm/i915/i915_drv.<wbr>c | 3 +-<br>
drivers/gpu/drm/i915/i915_gem_<wbr>execbuffer.c | 146 ++++++++++++++++++++++++++++-<br>
include/uapi/drm/i915_drm.h | 31 +++++-<br>
3 files changed, 172 insertions(+), 8 deletions(-)<br>
<br>
diff --git a/drivers/gpu/drm/i915/i915_<wbr>drv.c b/drivers/gpu/drm/i915/i915_<wbr>drv.c<br>
index cc25115c2db7..e55d1224a74f 100644<br>
--- a/drivers/gpu/drm/i915/i915_<wbr>drv.c<br>
+++ b/drivers/gpu/drm/i915/i915_<wbr>drv.c<br>
@@ -388,6 +388,7 @@ static int i915_getparam(struct drm_device *dev, void *data,<br>
case I915_PARAM_HAS_EXEC_FENCE:<br>
case I915_PARAM_HAS_EXEC_CAPTURE:<br>
case I915_PARAM_HAS_EXEC_BATCH_<wbr>FIRST:<br>
+ case I915_PARAM_HAS_EXEC_FENCE_<wbr>ARRAY:<br>
/* For the time being all of these are always true;<br>
* if some supported hardware does not have one of these<br>
* features this value needs to be provided from<br>
@@ -2739,7 +2740,7 @@ static struct drm_driver driver = {<br>
*/<br>
.driver_features =<br>
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | DRIVER_PRIME |<br>
- DRIVER_RENDER | DRIVER_MODESET | DRIVER_ATOMIC,<br>
+ DRIVER_RENDER | DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_SYNCOBJ,<br>
.release = i915_driver_release,<br>
.open = i915_driver_open,<br>
.lastclose = i915_driver_lastclose,<br>
diff --git a/drivers/gpu/drm/i915/i915_<wbr>gem_execbuffer.c b/drivers/gpu/drm/i915/i915_<wbr>gem_execbuffer.c<br>
index 5fa44767c29e..c4db64cfcdae 100644<br>
--- a/drivers/gpu/drm/i915/i915_<wbr>gem_execbuffer.c<br>
+++ b/drivers/gpu/drm/i915/i915_<wbr>gem_execbuffer.c<br>
@@ -32,6 +32,7 @@<br>
#include <linux/uaccess.h><br>
<br>
#include <drm/drmP.h><br>
+#include <drm/drm_syncobj.h><br>
#include <drm/i915_drm.h><br>
<br>
#include "i915_drv.h"<br>
@@ -1884,8 +1885,10 @@ static bool i915_gem_check_execbuffer(<wbr>struct drm_i915_gem_execbuffer2 *exec)<br>
return false;<br>
<br>
/* Kernel clipping was a DRI1 misfeature */<br>
- if (exec->num_cliprects || exec->cliprects_ptr)<br>
- return false;<br>
+ if (!(exec->flags & I915_EXEC_FENCE_ARRAY)) {<br>
+ if (exec->num_cliprects || exec->cliprects_ptr)<br>
+ return false;<br>
+ }<br>
<br>
if (exec->DR4 == 0xffffffff) {<br>
DRM_DEBUG("UXA submitting garbage DR4, fixing up\n");<br>
@@ -2116,11 +2119,125 @@ eb_select_engine(struct drm_i915_private *dev_priv,<br>
return engine;<br>
}<br>
<br>
+static void __free_fence_array(struct drm_syncobj **fences, unsigned int n)<br>
+{<br>
+ while (n--)<br>
+ drm_syncobj_put(ptr_mask_bits(<wbr>fences[n], 2));<br>
+ kvfree(fences);<br>
+}<br>
+<br>
+static struct drm_syncobj **get_fence_array(struct drm_i915_gem_execbuffer2 *args,<br>
+ struct drm_file *file)<br>
+{<br>
+ const unsigned int nfences = args->num_cliprects;<br>
+ struct drm_i915_gem_exec_fence __user *user;<br>
+ struct drm_syncobj **fences;<br>
+ unsigned int n;<br>
+ int err;<br>
+<br>
+ if (!(args->flags & I915_EXEC_FENCE_ARRAY))<br>
+ return NULL;<br>
+<br>
+ if (nfences > SIZE_MAX / sizeof(*fences))<br>
+ return ERR_PTR(-EINVAL);<br>
+<br>
+ user = u64_to_user_ptr(args-><wbr>cliprects_ptr);<br>
+ if (!access_ok(VERIFY_READ, user, nfences * 2 * sizeof(u32)))<br>
+ return ERR_PTR(-EFAULT);<br>
+<br>
+ fences = kvmalloc_array(args->num_<wbr>cliprects, sizeof(*fences),<br>
+ __GFP_NOWARN | GFP_TEMPORARY);<br>
+ if (!fences)<br>
+ return ERR_PTR(-ENOMEM);<br>
+<br>
+ for (n = 0; n < nfences; n++) {<br>
+ struct drm_i915_gem_exec_fence fence;<br>
+ struct drm_syncobj *syncobj;<br>
+<br>
+ if (__copy_from_user(&fence, user++, sizeof(fence))) {<br>
+ err = -EFAULT;<br>
+ goto err;<br>
+ }<br>
+<br>
+ syncobj = drm_syncobj_find(file, fence.handle);<br>
+ if (!syncobj) {<br>
+ DRM_DEBUG("Invalid syncobj handle provided\n");<br>
+ err = -ENOENT;<br>
+ goto err;<br>
+ }<br>
+<br>
+ fences[n] = ptr_pack_bits(syncobj, fence.flags, 2);<br>
+ }<br>
+<br>
+ return fences;<br>
+<br>
+err:<br>
+ __free_fence_array(fences, n);<br>
+ return ERR_PTR(err);<br>
+}<br>
+<br>
+static void put_fence_array(struct drm_i915_gem_execbuffer2 *args,<br>
+ struct drm_syncobj **fences)<br>
+{<br>
+ if (!fences)<br>
+ return;<br>
+ __free_fence_array(fences, args->num_cliprects);<br>
+}<br>
+<br>
+static int await_fence_array(struct i915_execbuffer *eb,<br>
+ struct drm_syncobj **fences)<br>
+{<br>
+ const unsigned int nfences = eb->args->num_cliprects;<br>
+ unsigned int n;<br>
+ int err;<br>
+<br>
+ for (n = 0; n < nfences; n++) {<br>
+ struct drm_syncobj *syncobj;<br>
+ struct dma_fence *fence;<br>
+ unsigned int flags;<br>
+<br>
+ syncobj = ptr_unpack_bits(fences[n], &flags, 2);<br>
+ if (!(flags & I915_EXEC_FENCE_WAIT))<br>
+ continue;<br>
+<br>
+ fence = dma_fence_get_rcu_safe(&<wbr>syncobj->fence);<br></blockquote><div><br></div><div>drm_syncobj does not currently use RCU (though dma-fence does). Is this a problem?<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+ if (!fence)<br>
+ return -EINVAL;<br>
+<br>
+ err = i915_gem_request_await_dma_<wbr>fence(eb->request, fence);<br>
+ dma_fence_put(fence);<br>
+ if (err < 0)<br>
+ return err;<br>
+ }<br>
+<br>
+ return 0;<br>
+}<br>
+<br>
+static void signal_fence_array(struct i915_execbuffer *eb,<br>
+ struct drm_syncobj **fences)<br>
+{<br>
+ const unsigned int nfences = eb->args->num_cliprects;<br>
+ struct dma_fence * const fence = &eb->request->fence;<br>
+ unsigned int n;<br>
+<br>
+ for (n = 0; n < nfences; n++) {<br>
+ struct drm_syncobj *syncobj;<br>
+ unsigned int flags;<br>
+<br>
+ syncobj = ptr_unpack_bits(fences[n], &flags, 2);<br>
+ if (!(flags & I915_EXEC_FENCE_SIGNAL))<br>
+ continue;<br>
+<br>
+ drm_syncobj_replace_fence(<wbr>syncobj, fence);<br>
+ }<br>
+}<br>
+<br>
static int<br>
i915_gem_do_execbuffer(struct drm_device *dev,<br>
struct drm_file *file,<br>
struct drm_i915_gem_execbuffer2 *args,<br>
- struct drm_i915_gem_exec_object2 *exec)<br>
+ struct drm_i915_gem_exec_object2 *exec,<br>
+ struct drm_syncobj **fences)<br>
{<br>
struct i915_execbuffer eb;<br>
struct dma_fence *in_fence = NULL;<br>
@@ -2306,6 +2423,12 @@ i915_gem_do_execbuffer(struct drm_device *dev,<br>
goto err_request;<br>
}<br>
<br>
+ if (fences) {<br>
+ err = await_fence_array(&eb, fences);<br>
+ if (err < 0)<br>
+ goto err_request;<br>
+ }<br>
+<br>
if (out_fence_fd != -1) {<br>
out_fence = sync_file_create(&eb.request-><wbr>fence);<br>
if (!out_fence) {<br>
@@ -2329,6 +2452,9 @@ i915_gem_do_execbuffer(struct drm_device *dev,<br>
__i915_add_request(eb.request, err == 0);<br>
add_to_client(eb.request, file);<br>
<br>
+ if (fences)<br>
+ signal_fence_array(&eb, fences);<br>
+<br>
if (out_fence) {<br>
if (err == 0) {<br>
fd_install(out_fence_fd, out_fence->file);<br>
@@ -2430,7 +2556,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,<br>
exec2_list[i].flags = 0;<br>
}<br>
<br>
- err = i915_gem_do_execbuffer(dev, file, &exec2, exec2_list);<br>
+ err = i915_gem_do_execbuffer(dev, file, &exec2, exec2_list, NULL);<br>
if (exec2.flags & __EXEC_HAS_RELOC) {<br>
struct drm_i915_gem_exec_object __user *user_exec_list =<br>
u64_to_user_ptr(args->buffers_<wbr>ptr);<br>
@@ -2462,6 +2588,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,<br>
const size_t sz = sizeof(struct drm_i915_gem_exec_object2);<br>
struct drm_i915_gem_execbuffer2 *args = data;<br>
struct drm_i915_gem_exec_object2 *exec2_list;<br>
+ struct drm_syncobj **fences = NULL;<br>
int err;<br>
<br>
if (args->buffer_count < 1 || args->buffer_count > SIZE_MAX / sz - 1) {<br>
@@ -2488,7 +2615,15 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,<br>
return -EFAULT;<br>
}<br>
<br>
- err = i915_gem_do_execbuffer(dev, file, args, exec2_list);<br>
+ if (args->flags & I915_EXEC_FENCE_ARRAY) {<br>
+ fences = get_fence_array(args, file);<br>
+ if (IS_ERR(fences)) {<br>
+ kvfree(exec2_list);<br>
+ return PTR_ERR(fences);<br>
+ }<br>
+ }<br>
+<br>
+ err = i915_gem_do_execbuffer(dev, file, args, exec2_list, fences);<br>
<br>
/*<br>
* Now that we have begun execution of the batchbuffer, we ignore<br>
@@ -2519,5 +2654,6 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,<br>
<br>
args->flags &= ~__I915_EXEC_UNKNOWN_FLAGS;<br>
kvfree(exec2_list);<br>
+ put_fence_array(args, fences);<br>
return err;<br>
}<br>
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h<br>
index ce3833fa1e06..a12b45fa6ce4 100644<br>
--- a/include/uapi/drm/i915_drm.h<br>
+++ b/include/uapi/drm/i915_drm.h<br>
@@ -435,6 +435,11 @@ typedef struct drm_i915_irq_wait {<br>
*/<br>
#define I915_PARAM_HAS_EXEC_BATCH_<wbr>FIRST 48<br>
<br>
+/* Query whether DRM_I915_GEM_EXECBUFFER2 supports supplying an array of<br>
+ * drm_i915_gem_exec_fence structures. See I915_EXEC_FENCE_ARRAY.<br>
+ */<br>
+#define I915_PARAM_HAS_EXEC_FENCE_<wbr>ARRAY 49<br>
+<br>
typedef struct drm_i915_getparam {<br>
__s32 param;<br>
/*<br>
@@ -816,6 +821,17 @@ struct drm_i915_gem_exec_object2 {<br>
__u64 rsvd2;<br>
};<br>
<br>
+struct drm_i915_gem_exec_fence {<br>
+ /**<br>
+ * User's handle for a dma-fence to wait on or signal.<br>
+ */<br>
+ __u32 handle;<br>
+<br>
+#define I915_EXEC_FENCE_WAIT (1<<0)<br>
+#define I915_EXEC_FENCE_SIGNAL (1<<1)<br>
+ __u32 flags;<br>
+};<br>
+<br>
struct drm_i915_gem_execbuffer2 {<br>
/**<br>
* List of gem_exec_object2 structs<br>
@@ -830,7 +846,11 @@ struct drm_i915_gem_execbuffer2 {<br>
__u32 DR1;<br>
__u32 DR4;<br>
__u32 num_cliprects;<br>
- /** This is a struct drm_clip_rect *cliprects */<br>
+ /**<br>
+ * This is a struct drm_clip_rect *cliprects if I915_EXEC_FENCE_ARRAY<br>
+ * is not set. If I915_EXEC_FENCE_ARRAY is set, then this is a<br>
+ * struct drm_i915_gem_exec_fence *fences.<br>
+ */<br>
__u64 cliprects_ptr;<br>
#define I915_EXEC_RING_MASK (7<<0)<br>
#define I915_EXEC_DEFAULT (0<<0)<br>
@@ -931,7 +951,14 @@ struct drm_i915_gem_execbuffer2 {<br>
* element).<br>
*/<br>
#define I915_EXEC_BATCH_FIRST (1<<18)<br>
-#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_BATCH_FIRST<<1))<br>
+<br>
+/* Setting I915_FENCE_ARRAY implies that num_cliprects and cliprects_ptr<br>
+ * define an array of i915_gem_exec_fence structures which specify a set of<br>
+ * dma fences to wait upon or signal.<br>
+ */<br>
+#define I915_EXEC_FENCE_ARRAY (1<<19)<br>
+<br>
+#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_ARRAY<<1))<br>
<br>
#define I915_EXEC_CONTEXT_ID_MASK (0xffffffff)<br>
#define i915_execbuffer2_set_context_<wbr>id(eb2, context) \<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.13.3<br>
<br>
</font></span></blockquote></div><br></div></div>