Binary/legacy signal operations on a syncobj work by replacing the dma_fence held within the syncobj. Whe dealing with timeline semaphores we would like to avoid this as this would effectivelly lead to looser synchronization (by discarding the dma_fence_chain mechanism waiting on all previous dma_fence to signal before signal itself). This change adds a flags that can be used at creation of the syncobj to mean that the syncobj will hold a timeline of dma_fence (using dma_fence_chain). When flagged as such, the dma_fence held by the syncobj should not be replaced but instead we should always adding to the timeline. Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@xxxxxxxxx> --- drivers/gpu/drm/drm_syncobj.c | 30 +++++++++++++++++++++++++++++- include/drm/drm_syncobj.h | 8 ++++++++ include/uapi/drm/drm.h | 1 + 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 72d083acd388..69d43c791a42 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -476,6 +476,8 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags, if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) drm_syncobj_assign_null_handle(syncobj); + if (flags & DRM_SYNCOBJ_CREATE_TIMELINE) + syncobj->is_timeline = true; if (fence) drm_syncobj_replace_fence(syncobj, fence); @@ -661,6 +663,10 @@ static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private, dma_fence_put(fence); return -ENOENT; } + if (syncobj->is_timeline) { + dma_fence_put(fence); + return -EINVAL; + } drm_syncobj_replace_fence(syncobj, fence); dma_fence_put(fence); @@ -749,7 +755,13 @@ drm_syncobj_create_ioctl(struct drm_device *dev, void *data, return -EOPNOTSUPP; /* no valid flags yet */ - if (args->flags & ~DRM_SYNCOBJ_CREATE_SIGNALED) + if (args->flags & ~(DRM_SYNCOBJ_CREATE_SIGNALED | + DRM_SYNCOBJ_CREATE_TIMELINE)) + return -EINVAL; + + /* Creating a signaled timeline makes no sense. */ + if ((args->flags & DRM_SYNCOBJ_CREATE_SIGNALED) && + (args->flags & DRM_SYNCOBJ_CREATE_TIMELINE)) return -EINVAL; return drm_syncobj_create_as_handle(file_private, @@ -862,6 +874,10 @@ drm_syncobj_transfer_to_binary(struct drm_file *file_private, binary_syncobj = drm_syncobj_find(file_private, args->dst_handle); if (!binary_syncobj) return -ENOENT; + if (binary_syncobj->is_timeline) { + ret = -EINVAL; + goto err; + } ret = drm_syncobj_find_fence(file_private, args->src_handle, args->src_point, args->flags, &fence); if (ret) @@ -1137,6 +1153,7 @@ static int drm_syncobj_array_wait(struct drm_device *dev, static int drm_syncobj_array_find(struct drm_file *file_private, void __user *user_handles, uint32_t count_handles, + bool no_timeline, struct drm_syncobj ***syncobjs_out) { uint32_t i, *handles; @@ -1165,6 +1182,10 @@ static int drm_syncobj_array_find(struct drm_file *file_private, ret = -ENOENT; goto err_put_syncobjs; } + if (no_timeline && syncobjs[i]->is_timeline) { + ret = -EINVAL; + goto err_put_syncobjs; + } } kfree(handles); @@ -1211,6 +1232,7 @@ drm_syncobj_wait_ioctl(struct drm_device *dev, void *data, ret = drm_syncobj_array_find(file_private, u64_to_user_ptr(args->handles), args->count_handles, + false, &syncobjs); if (ret < 0) return ret; @@ -1245,6 +1267,7 @@ drm_syncobj_timeline_wait_ioctl(struct drm_device *dev, void *data, ret = drm_syncobj_array_find(file_private, u64_to_user_ptr(args->handles), args->count_handles, + false, &syncobjs); if (ret < 0) return ret; @@ -1279,6 +1302,7 @@ drm_syncobj_reset_ioctl(struct drm_device *dev, void *data, ret = drm_syncobj_array_find(file_private, u64_to_user_ptr(args->handles), args->count_handles, + false, &syncobjs); if (ret < 0) return ret; @@ -1314,6 +1338,7 @@ drm_syncobj_signal_ioctl(struct drm_device *dev, void *data, ret = drm_syncobj_array_find(file_private, u64_to_user_ptr(args->handles), args->count_handles, + true, &syncobjs); if (ret < 0) return ret; @@ -1349,6 +1374,7 @@ drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data, ret = drm_syncobj_array_find(file_private, u64_to_user_ptr(args->handles), args->count_handles, + false, &syncobjs); if (ret < 0) return ret; @@ -1420,6 +1446,7 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, ret = drm_syncobj_array_find(file_private, u64_to_user_ptr(args->handles), args->count_handles, + false, &syncobjs); if (ret < 0) return ret; @@ -1484,6 +1511,7 @@ int drm_syncobj_binary_ioctl(struct drm_device *dev, void *data, ret = drm_syncobj_array_find(file_private, u64_to_user_ptr(args->handles), args->count_handles, + false, &syncobjs); if (ret < 0) return ret; diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h index aa76cb3f9107..f96a95fbe025 100644 --- a/include/drm/drm_syncobj.h +++ b/include/drm/drm_syncobj.h @@ -70,6 +70,14 @@ struct drm_syncobj { * seqno will be put into the syncobj. */ atomic64_t binary_payload; + /** + * @is_timeline: Whether the syncobj holds a timeline. + * + * Holding a timeline adds some restriction to prevent userspace from + * accidentally "losing" the timeline. This could happen for example + * by replacing &fence. + */ + bool is_timeline; }; void drm_syncobj_free(struct kref *kref); diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 78a0a413b788..b3c46b2993be 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -719,6 +719,7 @@ struct drm_prime_handle { struct drm_syncobj_create { __u32 handle; #define DRM_SYNCOBJ_CREATE_SIGNALED (1 << 0) +#define DRM_SYNCOBJ_CREATE_TIMELINE (1 << 1) __u32 flags; }; -- 2.23.0 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel