Add DRM_SYNCOBJ_WAIT_FLAGS_ABORT_ON_ERROR ioctl flag for the ioctls DRM_IOCTL_SYNCOBJ_WAIT and DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, which will make them abort their wait and return the error code and its associated syncobj.
Suggested-by: Christian König <[email protected]> Suggested-by: Michel Dänzer <[email protected]> Signed-off-by: Yicong Hui <[email protected]> --- drivers/gpu/drm/drm_syncobj.c | 25 +++++++++++++++++++++---- include/uapi/drm/drm.h | 1 + 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 322f64b72775..fb55fd46fb84 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -1139,6 +1139,13 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs, if (!fence) continue; + if ((flags & DRM_SYNCOBJ_WAIT_FLAGS_ABORT_ON_ERROR) && fence->error) { + if (idx) + *idx = i; + timeout = fence->error; + goto done_waiting; + } + if ((flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE) || dma_fence_is_signaled(fence) || (!entries[i].fence_cb.func && @@ -1242,8 +1249,12 @@ static int drm_syncobj_array_wait(struct drm_device *dev, wait->flags, timeout, &first, deadline); - if (timeout < 0) + if (timeout < 0) { + if (wait->flags & DRM_SYNCOBJ_WAIT_FLAGS_ABORT_ON_ERROR) + wait->first_signaled = first; + return timeout; + } wait->first_signaled = first; } else { timeout = drm_timeout_abs_to_jiffies(timeline_wait->timeout_nsec); @@ -1253,8 +1264,12 @@ static int drm_syncobj_array_wait(struct drm_device *dev, timeline_wait->flags, timeout, &first, deadline); - if (timeout < 0) + if (timeout < 0) { + if (timeline_wait->flags & DRM_SYNCOBJ_WAIT_FLAGS_ABORT_ON_ERROR) + timeline_wait->first_signaled = first; + return timeout; + } timeline_wait->first_signaled = first; } return 0; @@ -1332,7 +1347,8 @@ drm_syncobj_wait_ioctl(struct drm_device *dev, void *data, possible_flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL | DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT | - DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE; + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE | + DRM_SYNCOBJ_WAIT_FLAGS_ABORT_ON_ERROR; if (args->flags & ~possible_flags) return -EINVAL; @@ -1376,7 +1392,8 @@ drm_syncobj_timeline_wait_ioctl(struct drm_device *dev, void *data, possible_flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL | DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT | DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE | - DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE; + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE | + DRM_SYNCOBJ_WAIT_FLAGS_ABORT_ON_ERROR; if (args->flags & ~possible_flags) return -EINVAL; diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 2640cc0a09fe..bc958af5a910 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -977,6 +977,7 @@ struct drm_syncobj_transfer { #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1) #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2) /* wait for time point to become available */ #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE (1 << 3) /* set fence deadline to deadline_nsec */ +#define DRM_SYNCOBJ_WAIT_FLAGS_ABORT_ON_ERROR (1 << 4) /* abort upon any fence failure return err */ struct drm_syncobj_wait { __u64 handles; /* absolute timeout */ -- 2.53.0
