Am Freitag, dem 10.07.2026 um 14:03 +0200 schrieb Christian Gmeiner: > From: Christian Gmeiner <[email protected]> > > The OpenGL and Vulkan robustness extensions let an application detect a > GPU reset and check if its own context caused it, so the application can > drop the broken context and build a new one. The kernel knows both > facts, but etnaviv has no way to report them to userspace. > > Add two counters and a RESET_QUERY ioctl that returns both in one call: > a per-GPU counter that counts every reset of that GPU, and a per-context > counter that only counts the resets this context was guilty of. > Userspace compares the counters with saved values: if the context > counter moved the context was guilty, if only the GPU counter moved the > context was an innocent victim. > > The GPU counter is per GPU core and not per device, so a hang on one > pipe does not look like an innocent reset to contexts that only use > another pipe. > > The timeout handler updates both counters and the ioctl reads both > under the GPU lock. Without the lock the query could run between the > two updates, see only the GPU counter move and report an innocent > reset to the guilty context. > > Bump the driver minor version so userspace can detect the feature. > > Signed-off-by: Christian Gmeiner <[email protected]>
Reviewed-by: Lucas Stach <[email protected]> > --- > drivers/gpu/drm/etnaviv/etnaviv_drv.c | 29 ++++++++++++++++++++++++++++- > drivers/gpu/drm/etnaviv/etnaviv_drv.h | 1 + > drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 2 ++ > drivers/gpu/drm/etnaviv/etnaviv_sched.c | 5 +++++ > include/uapi/drm/etnaviv_drm.h | 19 ++++++++++++++++++- > 5 files changed, 54 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c > b/drivers/gpu/drm/etnaviv/etnaviv_drv.c > index a27ed014fb4e..5c50e5a24408 100644 > --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c > +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c > @@ -296,6 +296,32 @@ static int etnaviv_ioctl_get_param(struct drm_device > *dev, void *data, > return etnaviv_gpu_get_param(gpu, args->param, &args->value); > } > > +static int etnaviv_ioctl_reset_query(struct drm_device *dev, void *data, > + struct drm_file *file) > +{ > + struct etnaviv_drm_private *priv = dev->dev_private; > + struct etnaviv_file_private *ctx = file->driver_priv; > + struct drm_etnaviv_reset_query *args = data; > + struct etnaviv_gpu *gpu; > + > + if (args->flags) > + return -EINVAL; > + > + if (args->pipe >= ETNA_MAX_PIPES) > + return -EINVAL; > + > + gpu = priv->gpu[args->pipe]; > + if (!gpu) > + return -ENXIO; > + > + mutex_lock(&gpu->lock); > + args->global_reset_counter = gpu->reset_counter; > + args->context_reset_counter = ctx->reset_counter; > + mutex_unlock(&gpu->lock); > + > + return 0; > +} > + > static int etnaviv_ioctl_gem_new(struct drm_device *dev, void *data, > struct drm_file *file) > { > @@ -502,6 +528,7 @@ static const struct drm_ioctl_desc etnaviv_ioctls[] = { > ETNA_IOCTL(GEM_WAIT, gem_wait, DRM_RENDER_ALLOW), > ETNA_IOCTL(PM_QUERY_DOM, pm_query_dom, DRM_RENDER_ALLOW), > ETNA_IOCTL(PM_QUERY_SIG, pm_query_sig, DRM_RENDER_ALLOW), > + ETNA_IOCTL(RESET_QUERY, reset_query, DRM_RENDER_ALLOW), > }; > > static void etnaviv_show_fdinfo(struct drm_printer *p, struct drm_file *file) > @@ -530,7 +557,7 @@ static const struct drm_driver etnaviv_drm_driver = { > .name = "etnaviv", > .desc = "etnaviv DRM", > .major = 1, > - .minor = 4, > + .minor = 5, > }; > > /* > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h > b/drivers/gpu/drm/etnaviv/etnaviv_drv.h > index cba4323ae589..9c348aa7f8d3 100644 > --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h > +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h > @@ -34,6 +34,7 @@ struct etnaviv_file_private { > int id; > struct etnaviv_iommu_context *mmu; > struct drm_sched_entity sched_entity[ETNA_MAX_PIPES]; > + u32 reset_counter; > }; > > struct etnaviv_drm_private { > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h > b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h > index 5cb46c84e03a..a97780131426 100644 > --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h > +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h > @@ -148,6 +148,8 @@ struct etnaviv_gpu { > u32 hangcheck_primid; > u32 hangcheck_fence; > > + u32 reset_counter; > + > void __iomem *mmio; > int irq; > > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c > b/drivers/gpu/drm/etnaviv/etnaviv_sched.c > index 139e6e38784b..6e9b677122e3 100644 > --- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c > +++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c > @@ -79,6 +79,11 @@ static enum drm_gpu_sched_stat > etnaviv_sched_timedout_job(struct drm_sched_job > if(sched_job) > drm_sched_increase_karma(sched_job); > > + mutex_lock(&gpu->lock); > + gpu->reset_counter++; > + submit->ctx->reset_counter++; > + mutex_unlock(&gpu->lock); > + > /* get the GPU back into the init state */ > etnaviv_core_dump(submit); > etnaviv_gpu_recover_hang(submit); > diff --git a/include/uapi/drm/etnaviv_drm.h b/include/uapi/drm/etnaviv_drm.h > index af024d90453d..b50a3a0799e6 100644 > --- a/include/uapi/drm/etnaviv_drm.h > +++ b/include/uapi/drm/etnaviv_drm.h > @@ -265,6 +265,21 @@ struct drm_etnaviv_pm_signal { > char name[64]; /* out, name of domain */ > }; > > +/* > + * Reset status query: > + * > + * Both counters start at zero and only ever increase. Userspace saves > + * both values and compares them on a later query: if the context > + * counter moved this context caused a reset, if only the global > + * counter moved the GPU was reset on behalf of another context. > + */ > +struct drm_etnaviv_reset_query { > + __u32 pipe; /* in */ > + __u32 flags; /* in, must be 0 */ > + __u32 global_reset_counter; /* out, all resets of this GPU core */ > + __u32 context_reset_counter; /* out, resets caused by this context */ > +}; > + > #define DRM_ETNAVIV_GET_PARAM 0x00 > /* placeholder: > #define DRM_ETNAVIV_SET_PARAM 0x01 > @@ -279,7 +294,8 @@ struct drm_etnaviv_pm_signal { > #define DRM_ETNAVIV_GEM_WAIT 0x09 > #define DRM_ETNAVIV_PM_QUERY_DOM 0x0a > #define DRM_ETNAVIV_PM_QUERY_SIG 0x0b > -#define DRM_ETNAVIV_NUM_IOCTLS 0x0c > +#define DRM_ETNAVIV_RESET_QUERY 0x0c > +#define DRM_ETNAVIV_NUM_IOCTLS 0x0d > > #define DRM_IOCTL_ETNAVIV_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + > DRM_ETNAVIV_GET_PARAM, struct drm_etnaviv_param) > #define DRM_IOCTL_ETNAVIV_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + > DRM_ETNAVIV_GEM_NEW, struct drm_etnaviv_gem_new) > @@ -292,6 +308,7 @@ struct drm_etnaviv_pm_signal { > #define DRM_IOCTL_ETNAVIV_GEM_WAIT DRM_IOW(DRM_COMMAND_BASE + > DRM_ETNAVIV_GEM_WAIT, struct drm_etnaviv_gem_wait) > #define DRM_IOCTL_ETNAVIV_PM_QUERY_DOM DRM_IOWR(DRM_COMMAND_BASE + > DRM_ETNAVIV_PM_QUERY_DOM, struct drm_etnaviv_pm_domain) > #define DRM_IOCTL_ETNAVIV_PM_QUERY_SIG DRM_IOWR(DRM_COMMAND_BASE + > DRM_ETNAVIV_PM_QUERY_SIG, struct drm_etnaviv_pm_signal) > +#define DRM_IOCTL_ETNAVIV_RESET_QUERY DRM_IOWR(DRM_COMMAND_BASE + > DRM_ETNAVIV_RESET_QUERY, struct drm_etnaviv_reset_query) > > #if defined(__cplusplus) > }
