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 expose them through GET_PARAM: 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. Bump the driver minor version so userspace can detect the feature. Signed-off-by: Christian Gmeiner <[email protected]> --- drivers/gpu/drm/etnaviv/etnaviv_drv.c | 5 +++-- drivers/gpu/drm/etnaviv/etnaviv_drv.h | 1 + drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 12 +++++++++++- drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 6 +++++- drivers/gpu/drm/etnaviv/etnaviv_sched.c | 3 +++ include/uapi/drm/etnaviv_drm.h | 2 ++ 6 files changed, 25 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index a27ed014fb4e..14f2fe5fb98c 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -293,7 +293,8 @@ static int etnaviv_ioctl_get_param(struct drm_device *dev, void *data, if (!gpu) return -ENXIO; - return etnaviv_gpu_get_param(gpu, args->param, &args->value); + return etnaviv_gpu_get_param(gpu, file->driver_priv, args->param, + &args->value); } static int etnaviv_ioctl_gem_new(struct drm_device *dev, void *data, @@ -530,7 +531,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..fbbb0544130c 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]; + atomic_t reset_counter; }; struct etnaviv_drm_private { diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index c314b3cb5e70..4253560caa14 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -39,7 +39,9 @@ static const struct platform_device_id gpu_ids[] = { * Driver functions: */ -int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value) +int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, + struct etnaviv_file_private *ctx, + u32 param, u64 *value) { struct etnaviv_drm_private *priv = gpu->drm->dev_private; @@ -167,6 +169,14 @@ int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value) *value = gpu->identity.eco_id; break; + case ETNAVIV_PARAM_GLOBAL_RESET_COUNTER: + *value = atomic_read(&gpu->reset_counter); + break; + + case ETNAVIV_PARAM_CONTEXT_RESET_COUNTER: + *value = atomic_read(&ctx->reset_counter); + break; + default: DBG("%s: invalid param: %u", dev_name(gpu->dev), param); return -EINVAL; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h index 5cb46c84e03a..a5d7c2158eb5 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; + atomic_t reset_counter; + void __iomem *mmio; int irq; @@ -204,7 +206,9 @@ static inline u32 gpu_read_power(struct etnaviv_gpu *gpu, u32 reg) return readl(gpu->mmio + gpu_fix_power_address(gpu, reg)); } -int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value); +int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, + struct etnaviv_file_private *ctx, + u32 param, u64 *value); int etnaviv_gpu_init(struct etnaviv_gpu *gpu); bool etnaviv_fill_identity_from_hwdb(struct etnaviv_gpu *gpu); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c index 139e6e38784b..398608009924 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c @@ -79,6 +79,9 @@ static enum drm_gpu_sched_stat etnaviv_sched_timedout_job(struct drm_sched_job if(sched_job) drm_sched_increase_karma(sched_job); + atomic_inc(&gpu->reset_counter); + atomic_inc(&submit->ctx->reset_counter); + /* 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..977f6ae82fae 100644 --- a/include/uapi/drm/etnaviv_drm.h +++ b/include/uapi/drm/etnaviv_drm.h @@ -77,6 +77,8 @@ struct drm_etnaviv_timespec { #define ETNAVIV_PARAM_GPU_PRODUCT_ID 0x1c #define ETNAVIV_PARAM_GPU_CUSTOMER_ID 0x1d #define ETNAVIV_PARAM_GPU_ECO_ID 0x1e +#define ETNAVIV_PARAM_GLOBAL_RESET_COUNTER 0x1f +#define ETNAVIV_PARAM_CONTEXT_RESET_COUNTER 0x20 #define ETNA_MAX_PIPES 4 -- 2.54.0
