<div dir="ltr"><div class="gmail_quote"><div dir="ltr" class="gmail_attr"></div><div dir="ltr" class="gmail_attr">On Wed, Aug 21, 2019 at 8:12 AM Lionel Landwerlin <<a href="mailto:lionel.g.landwerlin@intel.com">lionel.g.landwerlin@intel.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Introduces a new parameters to execbuf so that we can specify syncobj<br>
handles as well as timeline points.<br>
<br>
v2: Reuse i915_user_extension_fn<br>
<br>
v3: Check that the chained extension is only present once (Chris)<br>
<br>
v4: Check that dma_fence_chain_find_seqno returns a non NULL fence (Lionel)<br>
<br>
v5: Use BIT_ULL (Chris)<br>
<br>
v6: Fix issue with already signaled timeline points,<br>
dma_fence_chain_find_seqno() setting fence to NULL (Chris)<br>
<br>
v7: Report ENOENT with invalid syncobj handle (Lionel)<br>
<br>
v8: Check for out of order timeline point insertion (Chris)<br>
<br>
v9: After explanations on<br>
<a href="https://lists.freedesktop.org/archives/dri-devel/2019-August/229287.html" rel="noreferrer" target="_blank">https://lists.freedesktop.org/archives/dri-devel/2019-August/229287.html</a><br>
drop the ordering check from v8 (Lionel)<br>
<br>
Signed-off-by: Lionel Landwerlin <<a href="mailto:lionel.g.landwerlin@intel.com" target="_blank">lionel.g.landwerlin@intel.com</a>><br>
---<br>
.../gpu/drm/i915/gem/i915_gem_execbuffer.c | 307 ++++++++++++++----<br>
drivers/gpu/drm/i915/i915_drv.c | 3 +-<br>
drivers/gpu/drm/i915/i915_getparam.c | 1 +<br>
include/uapi/drm/i915_drm.h | 39 +++<br>
4 files changed, 293 insertions(+), 57 deletions(-)<br>
<br>
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c<br>
index 8d1946556bc0..6d5a234f9f9b 100644<br>
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c<br>
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c<br>
@@ -214,6 +214,13 @@ enum {<br>
* the batchbuffer in trusted mode, otherwise the ioctl is rejected.<br>
*/<br>
<br>
+struct i915_eb_fences {<br>
+ struct drm_syncobj *syncobj; /* Use with ptr_mask_bits() */<br>
+ struct dma_fence *dma_fence;<br>
+ u64 value;<br>
+ struct dma_fence_chain *chain_fence;<br>
+};<br>
+<br>
struct i915_execbuffer {<br>
struct drm_i915_private *i915; /** i915 backpointer */<br>
struct drm_file *file; /** per-file lookup tables and limits */<br>
@@ -275,6 +282,7 @@ struct i915_execbuffer {<br>
<br>
struct {<br>
u64 flags; /** Available extensions parameters */<br>
+ struct drm_i915_gem_execbuffer_ext_timeline_fences timeline_fences;<br>
} extensions;<br>
};<br>
<br>
@@ -2295,67 +2303,217 @@ eb_pin_engine(struct i915_execbuffer *eb,<br>
}<br>
<br>
static void<br>
-__free_fence_array(struct drm_syncobj **fences, unsigned int n)<br>
+__free_fence_array(struct i915_eb_fences *fences, unsigned int n)<br>
{<br>
- while (n--)<br>
- drm_syncobj_put(ptr_mask_bits(fences[n], 2));<br>
+ while (n--) {<br>
+ drm_syncobj_put(ptr_mask_bits(fences[n].syncobj, 2));<br>
+ dma_fence_put(fences[n].dma_fence);<br>
+ kfree(fences[n].chain_fence);<br>
+ }<br>
kvfree(fences);<br>
}<br>
<br>
-static struct drm_syncobj **<br>
-get_fence_array(struct drm_i915_gem_execbuffer2 *args,<br>
- struct drm_file *file)<br>
+static struct i915_eb_fences *<br>
+get_timeline_fence_array(struct i915_execbuffer *eb, int *out_n_fences)<br>
{<br>
- const unsigned long nfences = args->num_cliprects;<br>
+ struct drm_i915_gem_execbuffer_ext_timeline_fences *timeline_fences =<br>
+ &eb->extensions.timeline_fences;<br>
+ struct drm_i915_gem_exec_fence __user *user_fences;<br>
+ struct i915_eb_fences *fences;<br>
+ u64 __user *user_values;<br>
+ u64 num_fences, num_user_fences = timeline_fences->fence_count;<br>
+ unsigned long n;<br>
+ int err;<br>
+<br>
+ /* Check multiplication overflow for access_ok() and kvmalloc_array() */<br>
+ BUILD_BUG_ON(sizeof(size_t) > sizeof(unsigned long));<br>
+ if (num_user_fences > min_t(unsigned long,<br>
+ ULONG_MAX / sizeof(*user_fences),<br>
+ SIZE_MAX / sizeof(*fences)))<br>
+ return ERR_PTR(-EINVAL);<br>
+<br>
+ user_fences = u64_to_user_ptr(timeline_fences->handles_ptr);<br>
+ if (!access_ok(user_fences, num_user_fences * sizeof(*user_fences)))<br>
+ return ERR_PTR(-EFAULT);<br>
+<br>
+ user_values = u64_to_user_ptr(timeline_fences->values_ptr);<br>
+ if (!access_ok(user_values, num_user_fences * sizeof(*user_values)))<br>
+ return ERR_PTR(-EFAULT);<br>
+<br>
+ fences = kvmalloc_array(num_user_fences, sizeof(*fences),<br>
+ __GFP_NOWARN | GFP_KERNEL);<br>
+ if (!fences)<br>
+ return ERR_PTR(-ENOMEM);<br>
+<br>
+ BUILD_BUG_ON(~(ARCH_KMALLOC_MINALIGN - 1) &<br>
+ ~__I915_EXEC_FENCE_UNKNOWN_FLAGS);<br>
+<br>
+ for (n = 0, num_fences = 0; n < timeline_fences->fence_count; n++) {<br>
+ struct drm_i915_gem_exec_fence user_fence;<br>
+ struct drm_syncobj *syncobj;<br>
+ struct dma_fence *fence = NULL;<br>
+ u64 point;<br>
+<br>
+ if (__copy_from_user(&user_fence, user_fences++, sizeof(user_fence))) {<br>
+ err = -EFAULT;<br>
+ goto err;<br>
+ }<br>
+<br>
+ if (user_fence.flags & __I915_EXEC_FENCE_UNKNOWN_FLAGS) {<br>
+ err = -EINVAL;<br>
+ goto err;<br>
+ }<br>
+<br>
+ if (__get_user(point, user_values++)) {<br>
+ err = -EFAULT;<br>
+ goto err;<br>
+ }<br>
+<br>
+ syncobj = drm_syncobj_find(eb->file, user_fence.handle);<br>
+ if (!syncobj) {<br>
+ DRM_DEBUG("Invalid syncobj handle provided\n");<br>
+ err = -ENOENT;<br>
+ goto err;<br>
+ }<br>
+<br>
+ if (user_fence.flags & I915_EXEC_FENCE_WAIT) {<br>
+ fence = drm_syncobj_fence_get(syncobj);<br>
+ if (!fence) {<br>
+ DRM_DEBUG("Syncobj handle has no fence\n");<br>
+ drm_syncobj_put(syncobj);<br>
+ err = -EINVAL;<br>
+ goto err;<br>
+ }<br>
+<br>
+ err = dma_fence_chain_find_seqno(&fence, point);<br>
+ if (err) {<br>
+ DRM_DEBUG("Syncobj handle missing requested point %llu\n", point);<br>
+ drm_syncobj_put(syncobj);<br>
+ goto err;<br>
+ }<br>
+<br>
+ /* A point might have been signaled already and<br>
+ * garbage collected from the timeline. In this case<br>
+ * just ignore the point and carry on.<br>
+ */<br>
+ if (!fence) {<br>
+ drm_syncobj_put(syncobj);<br>
+ continue;<br>
+ }<br>
+ }<br>
+<br>
+ /*<br>
+ * For timeline syncobjs we need to preallocate chains for<br>
+ * later signaling.<br>
+ */<br>
+ if (point != 0 && user_fence.flags & I915_EXEC_FENCE_SIGNAL) {<br>
+ /*<br>
+ * Waiting and signaling the same point (when point !=<br>
+ * 0) would break the timeline.<br>
+ */<br>
+ if (user_fence.flags & I915_EXEC_FENCE_WAIT) {<br>
+ DRM_DEBUG("Tring to wait & signal the same timeline point.\n");<br>
+ err = -EINVAL;<br>
+ drm_syncobj_put(syncobj);<br>
+ goto err;<br>
+ }<br>
+<br>
+ fences[num_fences].chain_fence =<br>
+ kmalloc(sizeof(*fences[num_fences].chain_fence),<br>
+ GFP_KERNEL);<br>
+ if (!fences[num_fences].chain_fence) {<br>
+ drm_syncobj_put(syncobj);<br>
+ err = -ENOMEM;<br>
+ DRM_DEBUG("Unable to alloc chain_fence\n");<br>
+ goto err;<br>
+ }<br>
+ } else {<br>
+ fences[num_fences].chain_fence = NULL;<br>
+ }<br>
+<br>
+ fences[num_fences].syncobj = ptr_pack_bits(syncobj, user_fence.flags, 2);<br>
+ fences[num_fences].dma_fence = fence;<br>
+ fences[num_fences].value = point;<br>
+ num_fences++;<br>
+ }<br>
+<br>
+ *out_n_fences = num_fences;<br>
+<br>
+ return fences;<br>
+<br>
+err:<br>
+ __free_fence_array(fences, num_fences);<br>
+ return ERR_PTR(err);<br>
+}<br>
+<br>
+static struct i915_eb_fences *<br>
+get_legacy_fence_array(struct i915_execbuffer *eb,<br>
+ int *out_n_fences)<br>
+{<br>
+ struct drm_i915_gem_execbuffer2 *args = eb->args;<br>
struct drm_i915_gem_exec_fence __user *user;<br>
- struct drm_syncobj **fences;<br>
+ struct i915_eb_fences *fences;<br>
+ const u32 num_fences = args->num_cliprects;<br>
unsigned long n;<br>
int err;<br>
<br>
- if (!(args->flags & I915_EXEC_FENCE_ARRAY))<br>
- return NULL;<br>
+ *out_n_fences = num_fences;<br>
<br>
/* Check multiplication overflow for access_ok() and kvmalloc_array() */<br>
BUILD_BUG_ON(sizeof(size_t) > sizeof(unsigned long));<br>
- if (nfences > min_t(unsigned long,<br>
- ULONG_MAX / sizeof(*user),<br>
- SIZE_MAX / sizeof(*fences)))<br>
+ if (*out_n_fences > min_t(unsigned long,<br>
+ ULONG_MAX / sizeof(*user),<br>
+ SIZE_MAX / sizeof(*fences)))<br>
return ERR_PTR(-EINVAL);<br>
<br>
user = u64_to_user_ptr(args->cliprects_ptr);<br>
- if (!access_ok(user, nfences * sizeof(*user)))<br>
+ if (!access_ok(user, *out_n_fences * sizeof(*user)))<br>
return ERR_PTR(-EFAULT);<br>
<br>
- fences = kvmalloc_array(nfences, sizeof(*fences),<br>
+ fences = kvmalloc_array(*out_n_fences, sizeof(*fences),<br>
__GFP_NOWARN | GFP_KERNEL);<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>
+ for (n = 0; n < *out_n_fences; n++) {<br>
+ struct drm_i915_gem_exec_fence user_fence;<br>
struct drm_syncobj *syncobj;<br>
+ struct dma_fence *fence = NULL;<br>
<br>
- if (__copy_from_user(&fence, user++, sizeof(fence))) {<br>
+ if (__copy_from_user(&user_fence, user++, sizeof(user_fence))) {<br>
err = -EFAULT;<br>
goto err;<br>
}<br>
<br>
- if (fence.flags & __I915_EXEC_FENCE_UNKNOWN_FLAGS) {<br>
+ if (user_fence.flags & __I915_EXEC_FENCE_UNKNOWN_FLAGS) {<br>
err = -EINVAL;<br>
goto err;<br>
}<br>
<br>
- syncobj = drm_syncobj_find(file, fence.handle);<br>
+ syncobj = drm_syncobj_find(eb->file, user_fence.handle);<br>
if (!syncobj) {<br>
DRM_DEBUG("Invalid syncobj handle provided\n");<br>
err = -ENOENT;<br>
goto err;<br>
}<br>
<br>
+ if (user_fence.flags & I915_EXEC_FENCE_WAIT) {<br>
+ fence = drm_syncobj_fence_get(syncobj);<br>
+ if (!fence) {<br>
+ DRM_DEBUG("Syncobj handle has no fence\n");<br>
+ drm_syncobj_put(syncobj);<br>
+ err = -EINVAL;<br>
+ goto err;<br>
+ }<br>
+ }<br>
+<br>
BUILD_BUG_ON(~(ARCH_KMALLOC_MINALIGN - 1) &<br>
~__I915_EXEC_FENCE_UNKNOWN_FLAGS);<br>
<br>
- fences[n] = ptr_pack_bits(syncobj, fence.flags, 2);<br>
+ fences[n].syncobj = ptr_pack_bits(syncobj, user_fence.flags, 2);<br>
+ fences[n].dma_fence = fence;<br>
+ fences[n].value = 0;<br>
+ fences[n].chain_fence = NULL;<br>
}<br>
<br>
return fences;<br>
@@ -2365,37 +2523,44 @@ get_fence_array(struct drm_i915_gem_execbuffer2 *args,<br>
return ERR_PTR(err);<br>
}<br>
<br>
+static struct i915_eb_fences *<br>
+get_fence_array(struct i915_execbuffer *eb, int *out_n_fences)<br>
+{<br>
+ if (eb->args->flags & I915_EXEC_FENCE_ARRAY)<br>
+ return get_legacy_fence_array(eb, out_n_fences);<br>
+<br>
+ if (eb->extensions.flags & BIT_ULL(DRM_I915_GEM_EXECBUFFER_EXT_TIMELINE_FENCES))<br>
+ return get_timeline_fence_array(eb, out_n_fences);<br>
+<br>
+ *out_n_fences = 0;<br>
+ return NULL;<br>
+}<br>
+<br>
static void<br>
-put_fence_array(struct drm_i915_gem_execbuffer2 *args,<br>
- struct drm_syncobj **fences)<br>
+put_fence_array(struct i915_eb_fences *fences, int nfences)<br>
{<br>
if (fences)<br>
- __free_fence_array(fences, args->num_cliprects);<br>
+ __free_fence_array(fences, nfences);<br>
}<br>
<br>
static int<br>
await_fence_array(struct i915_execbuffer *eb,<br>
- struct drm_syncobj **fences)<br>
+ struct i915_eb_fences *fences,<br>
+ int nfences)<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>
+ syncobj = ptr_unpack_bits(fences[n].syncobj, &flags, 2);<br>
if (!(flags & I915_EXEC_FENCE_WAIT))<br>
continue;<br>
<br>
- fence = drm_syncobj_fence_get(syncobj);<br>
- if (!fence)<br>
- return -EINVAL;<br>
-<br>
- err = i915_request_await_dma_fence(eb->request, fence);<br>
- dma_fence_put(fence);<br>
+ err = i915_request_await_dma_fence(eb->request,<br>
+ fences[n].dma_fence);<br>
if (err < 0)<br>
return err;<br>
}<br>
@@ -2405,9 +2570,9 @@ await_fence_array(struct i915_execbuffer *eb,<br>
<br>
static void<br>
signal_fence_array(struct i915_execbuffer *eb,<br>
- struct drm_syncobj **fences)<br>
+ struct i915_eb_fences *fences,<br>
+ int nfences)<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>
@@ -2415,15 +2580,46 @@ signal_fence_array(struct i915_execbuffer *eb,<br>
struct drm_syncobj *syncobj;<br>
unsigned int flags;<br>
<br>
- syncobj = ptr_unpack_bits(fences[n], &flags, 2);<br>
+ syncobj = ptr_unpack_bits(fences[n].syncobj, &flags, 2);<br>
if (!(flags & I915_EXEC_FENCE_SIGNAL))<br>
continue;<br>
<br>
- drm_syncobj_replace_fence(syncobj, fence);<br>
+ if (fences[n].chain_fence) {<br>
+ drm_syncobj_add_point(syncobj, fences[n].chain_fence,<br>
+ fence, fences[n].value);<br>
+ /*<br>
+ * The chain's ownership is transfered to the<br>
+ * timeline.<br>
+ */<br>
+ fences[n].chain_fence = NULL;<br>
+ } else {<br>
+ drm_syncobj_replace_fence(syncobj, fence);<br>
+ }<br>
}<br>
}<br>
<br>
+static int parse_timeline_fences(struct i915_user_extension __user *ext, void *data)<br>
+{<br>
+ struct i915_execbuffer *eb = data;<br>
+<br>
+ /* Timeline fences are incompatible with the fence array flag. */<br>
+ if (eb->args->flags & I915_EXEC_FENCE_ARRAY)<br>
+ return -EINVAL;<br>
+<br>
+ if (eb->extensions.flags & BIT_ULL(DRM_I915_GEM_EXECBUFFER_EXT_TIMELINE_FENCES))<br>
+ return -EINVAL;<br>
+<br>
+ if (copy_from_user(&eb->extensions.timeline_fences, ext,<br>
+ sizeof(eb->extensions.timeline_fences)))<br>
+ return -EFAULT;<br>
+<br>
+ eb->extensions.flags |= BIT_ULL(DRM_I915_GEM_EXECBUFFER_EXT_TIMELINE_FENCES);<br>
+<br>
+ return 0;<br>
+}<br>
+<br>
static const i915_user_extension_fn execbuf_extensions[] = {<br>
+ [DRM_I915_GEM_EXECBUFFER_EXT_TIMELINE_FENCES] = parse_timeline_fences,<br>
};<br>
<br>
static int<br>
@@ -2454,14 +2650,15 @@ 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_syncobj **fences)<br>
+ struct drm_i915_gem_exec_object2 *exec)<br>
{<br>
struct i915_execbuffer eb;<br>
struct dma_fence *in_fence = NULL;<br>
struct dma_fence *exec_fence = NULL;<br>
struct sync_file *out_fence = NULL;<br>
+ struct i915_eb_fences *fences = NULL;<br>
int out_fence_fd = -1;<br>
+ int nfences = 0;<br>
int err;<br>
<br>
BUILD_BUG_ON(__EXEC_INTERNAL_FLAGS & ~__I915_EXEC_ILLEGAL_FLAGS);<br>
@@ -2500,10 +2697,16 @@ i915_gem_do_execbuffer(struct drm_device *dev,<br>
if (err)<br>
return err;<br>
<br>
+ fences = get_fence_array(&eb, &nfences);<br>
+ if (IS_ERR(fences))<br>
+ return PTR_ERR(fences);<br>
+<br>
if (args->flags & I915_EXEC_FENCE_IN) {<br>
in_fence = sync_file_get_fence(lower_32_bits(args->rsvd2));<br>
- if (!in_fence)<br>
- return -EINVAL;<br>
+ if (!in_fence) {<br>
+ err = -EINVAL;<br>
+ goto err_fences;<br>
+ }<br>
}<br>
<br>
if (args->flags & I915_EXEC_FENCE_SUBMIT) {<br>
@@ -2648,7 +2851,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,<br>
}<br>
<br>
if (fences) {<br>
- err = await_fence_array(&eb, fences);<br>
+ err = await_fence_array(&eb, fences, nfences);<br>
if (err)<br>
goto err_request;<br>
}<br>
@@ -2679,7 +2882,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,<br>
i915_request_add(eb.request);<br>
<br>
if (fences)<br>
- signal_fence_array(&eb, fences);<br>
+ signal_fence_array(&eb, fences, nfences);<br>
<br>
if (out_fence) {<br>
if (err == 0) {<br>
@@ -2714,6 +2917,8 @@ i915_gem_do_execbuffer(struct drm_device *dev,<br>
dma_fence_put(exec_fence);<br>
err_in_fence:<br>
dma_fence_put(in_fence);<br>
+err_fences:<br>
+ put_fence_array(fences, nfences);<br>
return err;<br>
}<br>
<br>
@@ -2807,7 +3012,7 @@ i915_gem_execbuffer_ioctl(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, NULL);<br>
+ err = i915_gem_do_execbuffer(dev, file, &exec2, exec2_list);<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_ptr);<br>
@@ -2838,7 +3043,6 @@ i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data,<br>
{<br>
struct drm_i915_gem_execbuffer2 *args = data;<br>
struct drm_i915_gem_exec_object2 *exec2_list;<br>
- struct drm_syncobj **fences = NULL;<br>
const size_t count = args->buffer_count;<br>
int err;<br>
<br>
@@ -2866,15 +3070,7 @@ i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data,<br>
return -EFAULT;<br>
}<br>
<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>
+ err = i915_gem_do_execbuffer(dev, file, args, exec2_list);<br>
<br>
/*<br>
* Now that we have begun execution of the batchbuffer, we ignore<br>
@@ -2914,7 +3110,6 @@ end:;<br>
}<br>
<br>
args->flags &= ~__I915_EXEC_UNKNOWN_FLAGS;<br>
- put_fence_array(args, fences);<br>
kvfree(exec2_list);<br>
return err;<br>
}<br>
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c<br>
index b5b2a64753e6..4db24f06f323 100644<br>
--- a/drivers/gpu/drm/i915/i915_drv.c<br>
+++ b/drivers/gpu/drm/i915/i915_drv.c<br>
@@ -2851,7 +2851,8 @@ static struct drm_driver driver = {<br>
*/<br>
.driver_features =<br>
DRIVER_GEM |<br>
- DRIVER_RENDER | DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_SYNCOBJ,<br>
+ DRIVER_RENDER | DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_SYNCOBJ |<br>
+ DRIVER_SYNCOBJ_TIMELINE,<br>
.release = i915_driver_release,<br>
.open = i915_driver_open,<br>
.lastclose = i915_driver_lastclose,<br>
diff --git a/drivers/gpu/drm/i915/i915_getparam.c b/drivers/gpu/drm/i915/i915_getparam.c<br>
index 5d9101376a3d..da6faa84e5b8 100644<br>
--- a/drivers/gpu/drm/i915/i915_getparam.c<br>
+++ b/drivers/gpu/drm/i915/i915_getparam.c<br>
@@ -130,6 +130,7 @@ int i915_getparam_ioctl(struct drm_device *dev, void *data,<br>
case I915_PARAM_HAS_EXEC_BATCH_FIRST:<br>
case I915_PARAM_HAS_EXEC_FENCE_ARRAY:<br>
case I915_PARAM_HAS_EXEC_SUBMIT_FENCE:<br>
+ case I915_PARAM_HAS_EXEC_TIMELINE_FENCES:<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>
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h<br>
index 0a99c26730e1..e86691c18a56 100644<br>
--- a/include/uapi/drm/i915_drm.h<br>
+++ b/include/uapi/drm/i915_drm.h<br>
@@ -611,6 +611,13 @@ typedef struct drm_i915_irq_wait {<br>
* See I915_EXEC_FENCE_OUT and I915_EXEC_FENCE_SUBMIT.<br>
*/<br>
#define I915_PARAM_HAS_EXEC_SUBMIT_FENCE 53<br>
+<br>
+/* Query whether DRM_I915_GEM_EXECBUFFER2 supports supplying an array of<br>
+ * timeline syncobj through drm_i915_gem_execbuf_ext_timeline_fences. See<br>
+ * I915_EXEC_USE_EXTENSIONS.<br>
+ */<br>
+#define I915_PARAM_HAS_EXEC_TIMELINE_FENCES 54<br>
+<br>
/* Must be kept compact -- no holes and well documented */<br>
<br>
typedef struct drm_i915_getparam {<br>
@@ -1008,9 +1015,41 @@ struct drm_i915_gem_exec_fence {<br>
};<br>
<br>
enum drm_i915_gem_execbuffer_ext {<br>
+ /**<br>
+ * See drm_i915_gem_execbuf_ext_timeline_fences.<br>
+ */<br>
+ DRM_I915_GEM_EXECBUFFER_EXT_TIMELINE_FENCES = 0,<br></blockquote><div><br></div><div>Just pointed out a "bug" in the userspace code where it memset the drm_i915_gem_execbuffer_ext_timeline_fences struct to 0 and never set the ext name. It worked because TIMELINE_FENCES magically happens to be 0. We should make 0 reserved in the extension API and -EINVAL if we ever see it.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
DRM_I915_GEM_EXECBUFFER_EXT_MAX /* non-ABI */<br>
};<br>
<br>
+/**<br>
+ * This structure describes an array of drm_syncobj and associated points for<br>
+ * timeline variants of drm_syncobj. It is invalid to append this structure to<br>
+ * the execbuf if I915_EXEC_FENCE_ARRAY is set.<br>
+ */<br>
+struct drm_i915_gem_execbuffer_ext_timeline_fences {<br>
+ struct i915_user_extension base;<br>
+<br>
+ /**<br>
+ * Number of element in the handles_ptr & value_ptr arrays.<br>
+ */<br>
+ __u64 fence_count;<br>
+<br>
+ /**<br>
+ * Pointer to an array of struct drm_i915_gem_exec_fence of length<br>
+ * fence_count.<br>
+ */<br>
+ __u64 handles_ptr;<br>
+<br>
+ /**<br>
+ * Pointer to an array of u64 values of length fence_count. Values<br>
+ * must be 0 for a binary drm_syncobj. A Value of 0 for a timeline<br>
+ * drm_syncobj is invalid as it turns a drm_syncobj into a binary one.<br>
+ */<br>
+ __u64 values_ptr;<br>
+};<br>
+<br>
struct drm_i915_gem_execbuffer2 {<br>
/**<br>
* List of gem_exec_object2 structs<br>
-- <br>
2.23.0<br>
<br>
_______________________________________________<br>
Intel-gfx mailing list<br>
<a href="mailto:Intel-gfx@lists.freedesktop.org" target="_blank">Intel-gfx@lists.freedesktop.org</a><br>
<a href="https://lists.freedesktop.org/mailman/listinfo/intel-gfx" rel="noreferrer" target="_blank">https://lists.freedesktop.org/mailman/listinfo/intel-gfx</a></blockquote></div></div>