* [RFC PATCH v2 0/3] Querying errors from drm_syncobj
@ 2026-02-20 2:26 Yicong Hui
2026-02-20 2:26 ` [RFC PATCH v2 1/3] drm/syncobj: Add flag DRM_SYNCOBJ_QUERY_FLAGS_ERROR to query errors Yicong Hui
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Yicong Hui @ 2026-02-20 2:26 UTC (permalink / raw)
To: christian.koenig, michel.daenzer
Cc: dri-devel, linux-kernel, skhan, david.hunter.linux, Yicong Hui
This patch series adds 2 new flags, DRM_SYNCOBJ_QUERY_FLAGS_ERROR and
DRM_SYNCOBJ_WAIT_FLAGS_ABORT_ON_ERROR for 3 ioctl operations
DRM_IOCTL_SYNCOBJ_QUERY, DRM_IOCTL_SYNCOBJ_WAIT and
DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT to allow them to batch-request error
codes from multiple syncobjs and abort early upon error of any of them.
Based on discussions from Michel Dänzer and Christian König, and a
starter task from the DRM todo documentation.
See https://gitlab.gnome.org/GNOME/mutter/-/issues/4624 for discussions
on userspace implementation.
---
Changes:
v2:
* Went from adding a new ioctl to implementing flags for existing ones.
v1: https://lore.kernel.org/all/20260213120836.81283-1-yiconghui@gmail.com/T/#mfdbc7f97e91ca5731b51b69c8cf8173cb0b2fb3e
Yicong Hui (3):
drm/syncobj: Add flag DRM_SYNCOBJ_QUERY_FLAGS_ERROR to query errors
drm/syncobj: Add DRM_SYNCOBJ_WAIT_FLAGS_ABORT_ON_ERROR ioctl flag
drm/syncobj/doc: Remove starter task from todo list
Documentation/gpu/todo.rst | 16 ----------
drivers/dma-buf/dma-fence-chain.c | 52 +++++++++++++++++++++++++++++++
drivers/gpu/drm/drm_syncobj.c | 46 ++++++++++++++++++++++++---
include/linux/dma-fence-chain.h | 1 +
include/uapi/drm/drm.h | 2 ++
5 files changed, 96 insertions(+), 21 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 9+ messages in thread* [RFC PATCH v2 1/3] drm/syncobj: Add flag DRM_SYNCOBJ_QUERY_FLAGS_ERROR to query errors 2026-02-20 2:26 [RFC PATCH v2 0/3] Querying errors from drm_syncobj Yicong Hui @ 2026-02-20 2:26 ` Yicong Hui 2026-02-20 13:13 ` Christian König 2026-02-20 2:26 ` [RFC PATCH v2 2/3] drm/syncobj: Add DRM_SYNCOBJ_WAIT_FLAGS_ABORT_ON_ERROR ioctl flag Yicong Hui 2026-02-20 2:26 ` [RFC PATCH v2 3/3] drm/syncobj/doc: Remove starter task from todo list Yicong Hui 2 siblings, 1 reply; 9+ messages in thread From: Yicong Hui @ 2026-02-20 2:26 UTC (permalink / raw) To: christian.koenig, michel.daenzer Cc: dri-devel, linux-kernel, skhan, david.hunter.linux, Yicong Hui Add flag DRM_SYNCOBJ_QUERY_FLAGS_ERROR to make the DRM_IOCTL_SYNCOBJ_QUERY ioctl fill out the handles array with the error code of the first fence found per syncobj and 0 if one is not found and maintain the normal return value in points. Suggested-by: Christian König <christian.koenig@amd.com> Suggested-by: Michel Dänzer <michel.daenzer@mailbox.org> Signed-off-by: Yicong Hui <yiconghui@gmail.com> --- drivers/dma-buf/dma-fence-chain.c | 52 +++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_syncobj.c | 21 ++++++++++++- include/linux/dma-fence-chain.h | 1 + include/uapi/drm/drm.h | 1 + 4 files changed, 74 insertions(+), 1 deletion(-) diff --git a/drivers/dma-buf/dma-fence-chain.c b/drivers/dma-buf/dma-fence-chain.c index a8a90acf4f34..076d78b73379 100644 --- a/drivers/dma-buf/dma-fence-chain.c +++ b/drivers/dma-buf/dma-fence-chain.c @@ -76,6 +76,58 @@ struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence) } EXPORT_SYMBOL(dma_fence_chain_walk); +/** + * dma_fence_chain_find_error - find the latest error + * @fence: current chain node + * + * Walk the chain repeatedly until reaches a fence with error, or the + * end of the fence chain. Does not garbage collect. + * + * Returns the first error it finds in the chain. + */ +int64_t dma_fence_chain_find_error(struct dma_fence *fence) +{ + struct dma_fence_chain *chain, *prev_chain; + struct dma_fence *prev; + int64_t error = 0; + + chain = to_dma_fence_chain(fence); + if (!chain) + return fence->error; + + if (chain->fence->error) + return chain->fence->error; + + while ((prev = dma_fence_chain_get_prev(chain))) { + prev_chain = to_dma_fence_chain(prev); + + if (prev_chain) { + + if (prev_chain->fence->error) { + error = prev_chain->fence->error; + dma_fence_put(prev); + break; + } + + chain = prev_chain; + } else { + + if (prev->error) + error = prev->error; + dma_fence_put(prev); + break; + } + + + dma_fence_put(prev); + + } + + + return error; +} +EXPORT_SYMBOL(dma_fence_chain_find_error); + /** * dma_fence_chain_find_seqno - find fence chain node by seqno * @pfence: pointer to the chain node where to start diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 2d4ab745fdad..322f64b72775 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -1654,14 +1654,17 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, { struct drm_syncobj_timeline_array *args = data; struct drm_syncobj **syncobjs; + unsigned int valid_flags = DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED | + DRM_SYNCOBJ_QUERY_FLAGS_ERROR; uint64_t __user *points = u64_to_user_ptr(args->points); + uint64_t __user *handles = u64_to_user_ptr(args->handles); uint32_t i; int ret; if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) return -EOPNOTSUPP; - if (args->flags & ~DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED) + if (args->flags & ~valid_flags) return -EINVAL; if (args->count_handles == 0) @@ -1680,6 +1683,22 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, uint64_t point; fence = drm_syncobj_fence_get(syncobjs[i]); + + if (args->flags & DRM_SYNCOBJ_QUERY_FLAGS_ERROR) { + int64_t error = 0; + + if (fence) + error = dma_fence_chain_find_error(fence); + + ret = copy_to_user(&handles[i], &error, sizeof(int64_t)); + ret = ret ? -EFAULT : 0; + if (ret) { + dma_fence_put(fence); + break; + } + + } + chain = to_dma_fence_chain(fence); if (chain) { struct dma_fence *iter, *last_signaled = diff --git a/include/linux/dma-fence-chain.h b/include/linux/dma-fence-chain.h index 68c3c1e41014..b4ada124d7b6 100644 --- a/include/linux/dma-fence-chain.h +++ b/include/linux/dma-fence-chain.h @@ -122,6 +122,7 @@ static inline void dma_fence_chain_free(struct dma_fence_chain *chain) iter = dma_fence_chain_walk(iter)) struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence); +int64_t dma_fence_chain_find_error(struct dma_fence *fence); int dma_fence_chain_find_seqno(struct dma_fence **pfence, uint64_t seqno); void dma_fence_chain_init(struct dma_fence_chain *chain, struct dma_fence *prev, diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 27cc159c1d27..2640cc0a09fe 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -1044,6 +1044,7 @@ struct drm_syncobj_array { }; #define DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED (1 << 0) /* last available point on timeline syncobj */ +#define DRM_SYNCOBJ_QUERY_FLAGS_ERROR (1 << 1) /* fill out error codes if they are found */ struct drm_syncobj_timeline_array { __u64 handles; __u64 points; -- 2.53.0 ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v2 1/3] drm/syncobj: Add flag DRM_SYNCOBJ_QUERY_FLAGS_ERROR to query errors 2026-02-20 2:26 ` [RFC PATCH v2 1/3] drm/syncobj: Add flag DRM_SYNCOBJ_QUERY_FLAGS_ERROR to query errors Yicong Hui @ 2026-02-20 13:13 ` Christian König 2026-02-20 17:05 ` Yicong Hui 0 siblings, 1 reply; 9+ messages in thread From: Christian König @ 2026-02-20 13:13 UTC (permalink / raw) To: Yicong Hui, michel.daenzer Cc: dri-devel, linux-kernel, skhan, david.hunter.linux On 2/20/26 03:26, Yicong Hui wrote: > Add flag DRM_SYNCOBJ_QUERY_FLAGS_ERROR to make the > DRM_IOCTL_SYNCOBJ_QUERY ioctl fill out the handles array with the > error code of the first fence found per syncobj and 0 if one is not > found and maintain the normal return value in points. > > Suggested-by: Christian König <christian.koenig@amd.com> > Suggested-by: Michel Dänzer <michel.daenzer@mailbox.org> > Signed-off-by: Yicong Hui <yiconghui@gmail.com> > --- > drivers/dma-buf/dma-fence-chain.c | 52 +++++++++++++++++++++++++++++++ > drivers/gpu/drm/drm_syncobj.c | 21 ++++++++++++- > include/linux/dma-fence-chain.h | 1 + > include/uapi/drm/drm.h | 1 + > 4 files changed, 74 insertions(+), 1 deletion(-) > > diff --git a/drivers/dma-buf/dma-fence-chain.c b/drivers/dma-buf/dma-fence-chain.c > index a8a90acf4f34..076d78b73379 100644 > --- a/drivers/dma-buf/dma-fence-chain.c > +++ b/drivers/dma-buf/dma-fence-chain.c > @@ -76,6 +76,58 @@ struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence) > } > EXPORT_SYMBOL(dma_fence_chain_walk); > > +/** > + * dma_fence_chain_find_error - find the latest error > + * @fence: current chain node > + * > + * Walk the chain repeatedly until reaches a fence with error, or the > + * end of the fence chain. Does not garbage collect. > + * > + * Returns the first error it finds in the chain. > + */ > +int64_t dma_fence_chain_find_error(struct dma_fence *fence) > +{ > + struct dma_fence_chain *chain, *prev_chain; > + struct dma_fence *prev; > + int64_t error = 0; > + > + chain = to_dma_fence_chain(fence); > + if (!chain) > + return fence->error; > + > + if (chain->fence->error) > + return chain->fence->error; > + > + while ((prev = dma_fence_chain_get_prev(chain))) { > + prev_chain = to_dma_fence_chain(prev); > + > + if (prev_chain) { > + > + if (prev_chain->fence->error) { > + error = prev_chain->fence->error; > + dma_fence_put(prev); > + break; > + } > + > + chain = prev_chain; > + } else { > + > + if (prev->error) > + error = prev->error; > + dma_fence_put(prev); > + break; > + } > + > + > + dma_fence_put(prev); > + > + } > + > + > + return error; > +} > +EXPORT_SYMBOL(dma_fence_chain_find_error); That is superfluous, only signaled fences can have an error. > + > /** > * dma_fence_chain_find_seqno - find fence chain node by seqno > * @pfence: pointer to the chain node where to start > diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c > index 2d4ab745fdad..322f64b72775 100644 > --- a/drivers/gpu/drm/drm_syncobj.c > +++ b/drivers/gpu/drm/drm_syncobj.c > @@ -1654,14 +1654,17 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, > { > struct drm_syncobj_timeline_array *args = data; > struct drm_syncobj **syncobjs; > + unsigned int valid_flags = DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED | > + DRM_SYNCOBJ_QUERY_FLAGS_ERROR; > uint64_t __user *points = u64_to_user_ptr(args->points); > + uint64_t __user *handles = u64_to_user_ptr(args->handles); > uint32_t i; > int ret; > > if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) > return -EOPNOTSUPP; > > - if (args->flags & ~DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED) > + if (args->flags & ~valid_flags) > return -EINVAL; > > if (args->count_handles == 0) > @@ -1680,6 +1683,22 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, > uint64_t point; Make a local variable "int error" here. > > fence = drm_syncobj_fence_get(syncobjs[i]); > + > + if (args->flags & DRM_SYNCOBJ_QUERY_FLAGS_ERROR) { That should probably be just another functionality before the existing copy, but see below after the "if (chain)". > + int64_t error = 0; The error code is an int and only 32bits. > + > + if (fence) > + error = dma_fence_chain_find_error(fence); > + > + ret = copy_to_user(&handles[i], &error, sizeof(int64_t)); The handles are also only 32bits! > + ret = ret ? -EFAULT : 0; > + if (ret) { > + dma_fence_put(fence); > + break; > + } > + > + } > + > chain = to_dma_fence_chain(fence); > if (chain) { In this code path whenever point is assigned something do a "error = dma_fence_get_status(fence);" and then eventually copy the error to userspace after copying the point. > struct dma_fence *iter, *last_signaled = > diff --git a/include/linux/dma-fence-chain.h b/include/linux/dma-fence-chain.h > index 68c3c1e41014..b4ada124d7b6 100644 > --- a/include/linux/dma-fence-chain.h > +++ b/include/linux/dma-fence-chain.h > @@ -122,6 +122,7 @@ static inline void dma_fence_chain_free(struct dma_fence_chain *chain) > iter = dma_fence_chain_walk(iter)) > > struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence); > +int64_t dma_fence_chain_find_error(struct dma_fence *fence); > int dma_fence_chain_find_seqno(struct dma_fence **pfence, uint64_t seqno); > void dma_fence_chain_init(struct dma_fence_chain *chain, > struct dma_fence *prev, > diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h > index 27cc159c1d27..2640cc0a09fe 100644 > --- a/include/uapi/drm/drm.h > +++ b/include/uapi/drm/drm.h > @@ -1044,6 +1044,7 @@ struct drm_syncobj_array { > }; > > #define DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED (1 << 0) /* last available point on timeline syncobj */ > +#define DRM_SYNCOBJ_QUERY_FLAGS_ERROR (1 << 1) /* fill out error codes if they are found */ First of all comments please never after a define! The existing code has that already messed up. Then the new define needs more documentation. Something like: /* * Copy the status of the fence as output into the handles array. * The handles array is overwritten by that. */ Regards, Christian. > struct drm_syncobj_timeline_array { > __u64 handles; > __u64 points; ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v2 1/3] drm/syncobj: Add flag DRM_SYNCOBJ_QUERY_FLAGS_ERROR to query errors 2026-02-20 13:13 ` Christian König @ 2026-02-20 17:05 ` Yicong Hui 2026-02-20 17:07 ` Christian König 0 siblings, 1 reply; 9+ messages in thread From: Yicong Hui @ 2026-02-20 17:05 UTC (permalink / raw) To: Christian König, michel.daenzer Cc: dri-devel, linux-kernel, skhan, david.hunter.linux >> + >> /** >> * dma_fence_chain_find_seqno - find fence chain node by seqno >> * @pfence: pointer to the chain node where to start >> diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c >> index 2d4ab745fdad..322f64b72775 100644 >> --- a/drivers/gpu/drm/drm_syncobj.c >> +++ b/drivers/gpu/drm/drm_syncobj.c >> @@ -1654,14 +1654,17 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, >> { >> struct drm_syncobj_timeline_array *args = data; >> struct drm_syncobj **syncobjs; >> + unsigned int valid_flags = DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED | >> + DRM_SYNCOBJ_QUERY_FLAGS_ERROR; >> uint64_t __user *points = u64_to_user_ptr(args->points); >> + uint64_t __user *handles = u64_to_user_ptr(args->handles); >> uint32_t i; >> int ret; >> >> if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) >> return -EOPNOTSUPP; >> >> - if (args->flags & ~DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED) >> + if (args->flags & ~valid_flags) >> return -EINVAL; >> >> if (args->count_handles == 0) >> @@ -1680,6 +1683,22 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, >> uint64_t point; > > Make a local variable "int error" here. > > ... > >> + int64_t error = 0; > > The error code is an int and only 32bits. Understood, will change that! > >> + >> + if (fence) >> + error = dma_fence_chain_find_error(fence); >> + >> + ret = copy_to_user(&handles[i], &error, sizeof(int64_t)); > > The handles are also only 32bits! Ah, that's my mistake. Was thrown off by the __u64 in the struct definition but it is obvious now that it is a u32. Fixed as well! > >> + ret = ret ? -EFAULT : 0; >> + if (ret) { >> + dma_fence_put(fence); >> + break; >> + } >> + >> + } >> + >> chain = to_dma_fence_chain(fence); >> if (chain) { > > In this code path whenever point is assigned something do a "error = dma_fence_get_status(fence);" and then eventually copy the error to userspace after copying the point. > Hi! Were you thinking something that looks a little bit like this? diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 2d4ab745fdad..b74e491f9d8b 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -1654,14 +1654,17 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, { struct drm_syncobj_timeline_array *args = data; struct drm_syncobj **syncobjs; + unsigned int valid_flags = DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED | + DRM_SYNCOBJ_QUERY_FLAGS_ERROR; uint64_t __user *points = u64_to_user_ptr(args->points); + uint32_t __user *handles = u64_to_user_ptr(args->handles); uint32_t i; - int ret; + int ret, error; if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) return -EOPNOTSUPP; - if (args->flags & ~DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED) + if (args->flags & ~valid_flags) return -EINVAL; if (args->count_handles == 0) @@ -1681,6 +1684,7 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, fence = drm_syncobj_fence_get(syncobjs[i]); chain = to_dma_fence_chain(fence); + if (chain) { struct dma_fence *iter, *last_signaled = dma_fence_get(fence); @@ -1688,6 +1692,8 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, if (args->flags & DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED) { point = fence->seqno; + error = dma_fence_get_status(fence); + } else { dma_fence_chain_for_each(iter, fence) { if (iter->context != fence->context) { @@ -1702,16 +1708,28 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, point = dma_fence_is_signaled(last_signaled) ? last_signaled->seqno : to_dma_fence_chain(last_signaled)->prev_seqno; + + error = dma_fence_get_status(last_signaled); } dma_fence_put(last_signaled); } else { point = 0; + error = fence ? dma_fence_get_status(fence) : 0; } dma_fence_put(fence); + ret = copy_to_user(&points[i], &point, sizeof(uint64_t)); ret = ret ? -EFAULT : 0; if (ret) break; + + if (args->flags & DRM_SYNCOBJ_QUERY_FLAGS_ERROR) { + ret = copy_to_user(&handles[i], &error, sizeof(*handles)); + + ret = ret ? -EFAULT : 0; + if (ret) + break; + } } drm_syncobj_array_free(syncobjs, args->count_handles); ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v2 1/3] drm/syncobj: Add flag DRM_SYNCOBJ_QUERY_FLAGS_ERROR to query errors 2026-02-20 17:05 ` Yicong Hui @ 2026-02-20 17:07 ` Christian König 2026-02-20 19:40 ` Yicong Hui 0 siblings, 1 reply; 9+ messages in thread From: Christian König @ 2026-02-20 17:07 UTC (permalink / raw) To: Yicong Hui, michel.daenzer Cc: dri-devel, linux-kernel, skhan, david.hunter.linux On 2/20/26 18:05, Yicong Hui wrote: >>> + >>> /** >>> * dma_fence_chain_find_seqno - find fence chain node by seqno >>> * @pfence: pointer to the chain node where to start >>> diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c >>> index 2d4ab745fdad..322f64b72775 100644 >>> --- a/drivers/gpu/drm/drm_syncobj.c >>> +++ b/drivers/gpu/drm/drm_syncobj.c >>> @@ -1654,14 +1654,17 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, >>> { >>> struct drm_syncobj_timeline_array *args = data; >>> struct drm_syncobj **syncobjs; >>> + unsigned int valid_flags = DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED | >>> + DRM_SYNCOBJ_QUERY_FLAGS_ERROR; >>> uint64_t __user *points = u64_to_user_ptr(args->points); >>> + uint64_t __user *handles = u64_to_user_ptr(args->handles); >>> uint32_t i; >>> int ret; >>> if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) >>> return -EOPNOTSUPP; >>> - if (args->flags & ~DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED) >>> + if (args->flags & ~valid_flags) >>> return -EINVAL; >>> if (args->count_handles == 0) >>> @@ -1680,6 +1683,22 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, >>> uint64_t point; >> >> Make a local variable "int error" here. >> >> ... >> >>> + int64_t error = 0; >> >> The error code is an int and only 32bits. > Understood, will change that! > >> >>> + >>> + if (fence) >>> + error = dma_fence_chain_find_error(fence); >>> + >>> + ret = copy_to_user(&handles[i], &error, sizeof(int64_t)); >> >> The handles are also only 32bits! > Ah, that's my mistake. Was thrown off by the __u64 in the struct definition but it is obvious now that it is a u32. Fixed as well! > >> >>> + ret = ret ? -EFAULT : 0; >>> + if (ret) { >>> + dma_fence_put(fence); >>> + break; >>> + } >>> + >>> + } >>> + >>> chain = to_dma_fence_chain(fence); >>> if (chain) { >> >> In this code path whenever point is assigned something do a "error = dma_fence_get_status(fence);" and then eventually copy the error to userspace after copying the point. >> > > Hi! Were you thinking something that looks a little bit like this? Yeah that looks like what I had in mind to. Thanks, Christian. > > diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c > index 2d4ab745fdad..b74e491f9d8b 100644 > --- a/drivers/gpu/drm/drm_syncobj.c > +++ b/drivers/gpu/drm/drm_syncobj.c > @@ -1654,14 +1654,17 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, > { > struct drm_syncobj_timeline_array *args = data; > struct drm_syncobj **syncobjs; > + unsigned int valid_flags = DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED | > + DRM_SYNCOBJ_QUERY_FLAGS_ERROR; > uint64_t __user *points = u64_to_user_ptr(args->points); > + uint32_t __user *handles = u64_to_user_ptr(args->handles); > uint32_t i; > - int ret; > + int ret, error; > > if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) > return -EOPNOTSUPP; > > - if (args->flags & ~DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED) > + if (args->flags & ~valid_flags) > return -EINVAL; > > if (args->count_handles == 0) > @@ -1681,6 +1684,7 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, > > fence = drm_syncobj_fence_get(syncobjs[i]); > chain = to_dma_fence_chain(fence); > + > if (chain) { > struct dma_fence *iter, *last_signaled = > dma_fence_get(fence); > @@ -1688,6 +1692,8 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, > if (args->flags & > DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED) { > point = fence->seqno; > + error = dma_fence_get_status(fence); > + > } else { > dma_fence_chain_for_each(iter, fence) { > if (iter->context != fence->context) { > @@ -1702,16 +1708,28 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, > point = dma_fence_is_signaled(last_signaled) ? > last_signaled->seqno : > to_dma_fence_chain(last_signaled)->prev_seqno; > + > + error = dma_fence_get_status(last_signaled); > } > dma_fence_put(last_signaled); > } else { > point = 0; > + error = fence ? dma_fence_get_status(fence) : 0; > } > dma_fence_put(fence); > + > ret = copy_to_user(&points[i], &point, sizeof(uint64_t)); > ret = ret ? -EFAULT : 0; > if (ret) > break; > + > + if (args->flags & DRM_SYNCOBJ_QUERY_FLAGS_ERROR) { > + ret = copy_to_user(&handles[i], &error, sizeof(*handles)); > + > + ret = ret ? -EFAULT : 0; > + if (ret) > + break; > + } > } > drm_syncobj_array_free(syncobjs, args->count_handles); > ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v2 1/3] drm/syncobj: Add flag DRM_SYNCOBJ_QUERY_FLAGS_ERROR to query errors 2026-02-20 17:07 ` Christian König @ 2026-02-20 19:40 ` Yicong Hui 2026-02-23 9:38 ` Christian König 0 siblings, 1 reply; 9+ messages in thread From: Yicong Hui @ 2026-02-20 19:40 UTC (permalink / raw) To: Christian König, michel.daenzer Cc: dri-devel, linux-kernel, skhan, david.hunter.linux On 2/20/26 5:07 PM, Christian König wrote: > On 2/20/26 18:05, Yicong Hui wrote: >>>> + >>>> /** >>>> * dma_fence_chain_find_seqno - find fence chain node by seqno >>>> * @pfence: pointer to the chain node where to start >>>> diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c >>>> index 2d4ab745fdad..322f64b72775 100644 >>>> --- a/drivers/gpu/drm/drm_syncobj.c >>>> +++ b/drivers/gpu/drm/drm_syncobj.c >>>> @@ -1654,14 +1654,17 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, >>>> { >>>> struct drm_syncobj_timeline_array *args = data; >>>> struct drm_syncobj **syncobjs; >>>> + unsigned int valid_flags = DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED | >>>> + DRM_SYNCOBJ_QUERY_FLAGS_ERROR; >>>> uint64_t __user *points = u64_to_user_ptr(args->points); >>>> + uint64_t __user *handles = u64_to_user_ptr(args->handles); >>>> uint32_t i; >>>> int ret; >>>> if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) >>>> return -EOPNOTSUPP; >>>> - if (args->flags & ~DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED) >>>> + if (args->flags & ~valid_flags) >>>> return -EINVAL; >>>> if (args->count_handles == 0) >>>> @@ -1680,6 +1683,22 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, >>>> uint64_t point; >>> >>> Make a local variable "int error" here. >>> >>> ... >>> >>>> + int64_t error = 0; >>> >>> The error code is an int and only 32bits. >> Understood, will change that! >> >>> >>>> + >>>> + if (fence) >>>> + error = dma_fence_chain_find_error(fence); >>>> + >>>> + ret = copy_to_user(&handles[i], &error, sizeof(int64_t)); >>> >>> The handles are also only 32bits! >> Ah, that's my mistake. Was thrown off by the __u64 in the struct definition but it is obvious now that it is a u32. Fixed as well! >> >>> >>>> + ret = ret ? -EFAULT : 0; >>>> + if (ret) { >>>> + dma_fence_put(fence); >>>> + break; >>>> + } >>>> + >>>> + } >>>> + >>>> chain = to_dma_fence_chain(fence); >>>> if (chain) { >>> >>> In this code path whenever point is assigned something do a "error = dma_fence_get_status(fence);" and then eventually copy the error to userspace after copying the point. >>> >> >> Hi! Were you thinking something that looks a little bit like this? > > Yeah that looks like what I had in mind to. > > Thanks, > Christian. > Hi! What should I do at this point? Send a v3, or..? Thanks! Yicong ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v2 1/3] drm/syncobj: Add flag DRM_SYNCOBJ_QUERY_FLAGS_ERROR to query errors 2026-02-20 19:40 ` Yicong Hui @ 2026-02-23 9:38 ` Christian König 0 siblings, 0 replies; 9+ messages in thread From: Christian König @ 2026-02-23 9:38 UTC (permalink / raw) To: Yicong Hui, michel.daenzer Cc: dri-devel, linux-kernel, skhan, david.hunter.linux On 2/20/26 20:40, Yicong Hui wrote: > On 2/20/26 5:07 PM, Christian König wrote: >> On 2/20/26 18:05, Yicong Hui wrote: >>>>> + >>>>> /** >>>>> * dma_fence_chain_find_seqno - find fence chain node by seqno >>>>> * @pfence: pointer to the chain node where to start >>>>> diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c >>>>> index 2d4ab745fdad..322f64b72775 100644 >>>>> --- a/drivers/gpu/drm/drm_syncobj.c >>>>> +++ b/drivers/gpu/drm/drm_syncobj.c >>>>> @@ -1654,14 +1654,17 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, >>>>> { >>>>> struct drm_syncobj_timeline_array *args = data; >>>>> struct drm_syncobj **syncobjs; >>>>> + unsigned int valid_flags = DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED | >>>>> + DRM_SYNCOBJ_QUERY_FLAGS_ERROR; >>>>> uint64_t __user *points = u64_to_user_ptr(args->points); >>>>> + uint64_t __user *handles = u64_to_user_ptr(args->handles); >>>>> uint32_t i; >>>>> int ret; >>>>> if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) >>>>> return -EOPNOTSUPP; >>>>> - if (args->flags & ~DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED) >>>>> + if (args->flags & ~valid_flags) >>>>> return -EINVAL; >>>>> if (args->count_handles == 0) >>>>> @@ -1680,6 +1683,22 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, >>>>> uint64_t point; >>>> >>>> Make a local variable "int error" here. >>>> >>>> ... >>>> >>>>> + int64_t error = 0; >>>> >>>> The error code is an int and only 32bits. >>> Understood, will change that! >>> >>>> >>>>> + >>>>> + if (fence) >>>>> + error = dma_fence_chain_find_error(fence); >>>>> + >>>>> + ret = copy_to_user(&handles[i], &error, sizeof(int64_t)); >>>> >>>> The handles are also only 32bits! >>> Ah, that's my mistake. Was thrown off by the __u64 in the struct definition but it is obvious now that it is a u32. Fixed as well! >>> >>>> >>>>> + ret = ret ? -EFAULT : 0; >>>>> + if (ret) { >>>>> + dma_fence_put(fence); >>>>> + break; >>>>> + } >>>>> + >>>>> + } >>>>> + >>>>> chain = to_dma_fence_chain(fence); >>>>> if (chain) { >>>> >>>> In this code path whenever point is assigned something do a "error = dma_fence_get_status(fence);" and then eventually copy the error to userspace after copying the point. >>>> >>> >>> Hi! Were you thinking something that looks a little bit like this? >> >> Yeah that looks like what I had in mind to. >> >> Thanks, >> Christian. >> > > Hi! What should I do at this point? Send a v3, or..? You can go ahead and send a v3. But after that I think we need some userspace code using that. Could you also look into writing IGT tests for this? Thanks, Christian. > > Thanks! > Yicong ^ permalink raw reply [flat|nested] 9+ messages in thread
* [RFC PATCH v2 2/3] drm/syncobj: Add DRM_SYNCOBJ_WAIT_FLAGS_ABORT_ON_ERROR ioctl flag 2026-02-20 2:26 [RFC PATCH v2 0/3] Querying errors from drm_syncobj Yicong Hui 2026-02-20 2:26 ` [RFC PATCH v2 1/3] drm/syncobj: Add flag DRM_SYNCOBJ_QUERY_FLAGS_ERROR to query errors Yicong Hui @ 2026-02-20 2:26 ` Yicong Hui 2026-02-20 2:26 ` [RFC PATCH v2 3/3] drm/syncobj/doc: Remove starter task from todo list Yicong Hui 2 siblings, 0 replies; 9+ messages in thread From: Yicong Hui @ 2026-02-20 2:26 UTC (permalink / raw) To: christian.koenig, michel.daenzer Cc: dri-devel, linux-kernel, skhan, david.hunter.linux, Yicong Hui 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 <christian.koenig@amd.com> Suggested-by: Michel Dänzer <michel.daenzer@mailbox.org> Signed-off-by: Yicong Hui <yiconghui@gmail.com> --- 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 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [RFC PATCH v2 3/3] drm/syncobj/doc: Remove starter task from todo list 2026-02-20 2:26 [RFC PATCH v2 0/3] Querying errors from drm_syncobj Yicong Hui 2026-02-20 2:26 ` [RFC PATCH v2 1/3] drm/syncobj: Add flag DRM_SYNCOBJ_QUERY_FLAGS_ERROR to query errors Yicong Hui 2026-02-20 2:26 ` [RFC PATCH v2 2/3] drm/syncobj: Add DRM_SYNCOBJ_WAIT_FLAGS_ABORT_ON_ERROR ioctl flag Yicong Hui @ 2026-02-20 2:26 ` Yicong Hui 2 siblings, 0 replies; 9+ messages in thread From: Yicong Hui @ 2026-02-20 2:26 UTC (permalink / raw) To: christian.koenig, michel.daenzer Cc: dri-devel, linux-kernel, skhan, david.hunter.linux, Yicong Hui Remove the starter task for adding a way to query syncobjs error codes through an ioctl. Signed-off-by: Yicong Hui <yiconghui@gmail.com> --- Documentation/gpu/todo.rst | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 520da44a04a6..8dcb1901142e 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -878,22 +878,6 @@ Contact: Javier Martinez Canillas <javierm@redhat.com> Level: Advanced -Querying errors from drm_syncobj -================================ - -The drm_syncobj container can be used by driver independent code to signal -complection of submission. - -One minor feature still missing is a generic DRM IOCTL to query the error -status of binary and timeline drm_syncobj. - -This should probably be improved by implementing the necessary kernel interface -and adding support for that in the userspace stack. - -Contact: Christian König - -Level: Starter - DRM GPU Scheduler ================= -- 2.53.0 ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-02-23 9:38 UTC | newest] Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-02-20 2:26 [RFC PATCH v2 0/3] Querying errors from drm_syncobj Yicong Hui 2026-02-20 2:26 ` [RFC PATCH v2 1/3] drm/syncobj: Add flag DRM_SYNCOBJ_QUERY_FLAGS_ERROR to query errors Yicong Hui 2026-02-20 13:13 ` Christian König 2026-02-20 17:05 ` Yicong Hui 2026-02-20 17:07 ` Christian König 2026-02-20 19:40 ` Yicong Hui 2026-02-23 9:38 ` Christian König 2026-02-20 2:26 ` [RFC PATCH v2 2/3] drm/syncobj: Add DRM_SYNCOBJ_WAIT_FLAGS_ABORT_ON_ERROR ioctl flag Yicong Hui 2026-02-20 2:26 ` [RFC PATCH v2 3/3] drm/syncobj/doc: Remove starter task from todo list Yicong Hui
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®