1,introduce a member field guilty for amdgpu_ctx 2,free ctx if found it guilty in amdgpu_ctx_get, 3,change interface of amdgpu_ctx_get : return -ENODEV if an alive ctx is detected guilty return -EINVAL if ctx hanler invalid the amdgpu_ctx* will be hold in the @out parm this way we can let UMD differentiate a guilty ctx or a wrong ctx handler. Change-Id: Ib9cd3230e982b72ceb3b7b2fb14e48c32f63493f Signed-off-by: Monk Liu <Monk.Liu at amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 3 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 24 +++++++++++------------- drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 30 ++++++++++++++++++++++++------ 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 8e031d6..6312cc5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -793,6 +793,7 @@ struct amdgpu_ctx { struct fence **fences; struct amdgpu_ctx_ring rings[AMDGPU_MAX_RINGS]; bool preamble_presented; + bool guilty; /* if this context is considered guilty so will be removed */ }; struct amdgpu_ctx_mgr { @@ -802,7 +803,7 @@ struct amdgpu_ctx_mgr { struct idr ctx_handles; }; -struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id); +int amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id, struct amdgpu_ctx **out); int amdgpu_ctx_put(struct amdgpu_ctx *ctx); struct amdgpu_ctx *amdgpu_ctx_kref_get(struct amdgpu_ctx *ctx); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 267fb65..baa90dd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -154,11 +154,9 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) if (!chunk_array) return -ENOMEM; - p->ctx = amdgpu_ctx_get(fpriv, cs->in.ctx_id); - if (!p->ctx) { - ret = -EINVAL; + ret = amdgpu_ctx_get(fpriv, cs->in.ctx_id, &p->ctx); + if (ret) goto free_chunk; - } /* get chunks */ chunk_array_user = (uint64_t __user *)(uintptr_t)(cs->in.chunks); @@ -1026,9 +1024,9 @@ static int amdgpu_cs_dependencies(struct amdgpu_device *adev, if (r) return r; - ctx = amdgpu_ctx_get(fpriv, deps[j].ctx_id); - if (ctx == NULL) - return -EINVAL; + r = amdgpu_ctx_get(fpriv, deps[j].ctx_id, &ctx); + if (r) + return r; fence = amdgpu_ctx_get_fence(ctx, ring, deps[j].handle); @@ -1164,9 +1162,9 @@ int amdgpu_cs_wait_ioctl(struct drm_device *dev, void *data, if (r) return r; - ctx = amdgpu_ctx_get(filp->driver_priv, wait->in.ctx_id); - if (ctx == NULL) - return -EINVAL; + r = amdgpu_ctx_get(filp->driver_priv, wait->in.ctx_id, &ctx); + if (r) + return r; fence = amdgpu_ctx_get_fence(ctx, ring, wait->in.handle); if (IS_ERR(fence)) @@ -1208,9 +1206,9 @@ static struct fence *amdgpu_cs_get_fence(struct amdgpu_device *adev, if (r) return ERR_PTR(r); - ctx = amdgpu_ctx_get(filp->driver_priv, user->ctx_id); - if (ctx == NULL) - return ERR_PTR(-EINVAL); + r = amdgpu_ctx_get(filp->driver_priv, user->ctx_id, &ctx); + if (r) + return r; fence = amdgpu_ctx_get_fence(ctx, ring, user->seq_no); amdgpu_ctx_put(ctx); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index 81438af..3947f63 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -146,6 +146,9 @@ static int amdgpu_ctx_free(struct amdgpu_fpriv *fpriv, uint32_t id) mutex_lock(&mgr->lock); ctx = idr_find(&mgr->ctx_handles, id); if (ctx) { + if (ctx->guilty) + DRM_ERROR("Guilty context:%u detected! ID removed\n", id); + idr_remove(&mgr->ctx_handles, id); kref_put(&ctx->refcount, amdgpu_ctx_do_release); mutex_unlock(&mgr->lock); @@ -222,22 +225,37 @@ int amdgpu_ctx_ioctl(struct drm_device *dev, void *data, return r; } -struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id) +int amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id, struct amdgpu_ctx **out) { struct amdgpu_ctx *ctx; struct amdgpu_ctx_mgr *mgr; + int r = -EINVAL; - if (!fpriv) - return NULL; + if (!fpriv || !out) + return r; mgr = &fpriv->ctx_mgr; mutex_lock(&mgr->lock); ctx = idr_find(&mgr->ctx_handles, id); - if (ctx) - kref_get(&ctx->refcount); + if (ctx) { + if (!ctx->guilty) { + kref_get(&ctx->refcount); + *out = ctx; + r = 0; + } else { + DRM_ERROR("Guilty context:%u detected! handler removed\n", id); + /* if a guilty context is alive but used by upper client, we distory it + * manually and return NULL, thus libdrm_amdgpu should re-create one. + */ + idr_remove(&mgr->ctx_handles, id); + kref_put(&ctx->refcount, amdgpu_ctx_do_release); + r = -ENODEV; + } + } + mutex_unlock(&mgr->lock); - return ctx; + return r; } int amdgpu_ctx_put(struct amdgpu_ctx *ctx) -- 2.7.4