From 847fb1c21680ba02807a012011e5e33e3a2126c2 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Mon, 1 Jun 2026 15:08:27 +0100 Subject: [PATCH] drm/amdgpu: Convert context manager to xarray MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IDR is deprecated so let's convert the context manager to xarray. In doing so we remove the context manager mutex and switch call sites which required the guarantee context cannot go away while they walk the list of context, or otherwise operate on them, to use reference counting. This allows us to use the built in xarray spinlock for all operations and just temporarily drop it when we need to call sleeping functions. Signed-off-by: Tvrtko Ursulin Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 119 ++++++++-------------- drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h | 5 +- drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c | 8 +- 3 files changed, 48 insertions(+), 84 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index f1143f2bfafb..047b83ce86d3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -494,34 +494,26 @@ static int amdgpu_ctx_alloc(struct amdgpu_device *adev, if (!ctx) return -ENOMEM; - mutex_lock(&mgr->lock); - *id = 1; - r = idr_alloc_u32(&mgr->ctx_handles, ctx, id, UINT_MAX, GFP_KERNEL); + r = amdgpu_ctx_init(mgr, priority, filp, ctx); if (r) { - mutex_unlock(&mgr->lock); kfree(ctx); return r; } - r = amdgpu_ctx_init(mgr, priority, filp, ctx); - if (r) { - idr_remove(&mgr->ctx_handles, *id); - *id = 0; - kfree(ctx); - } - mutex_unlock(&mgr->lock); + r = xa_alloc(&mgr->ctx_handles, id, ctx, xa_limit_32b, GFP_KERNEL); + if (r) + amdgpu_ctx_put(ctx); + return r; } static int amdgpu_ctx_free(struct amdgpu_fpriv *fpriv, uint32_t id) { - struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr; struct amdgpu_ctx *ctx; - mutex_lock(&mgr->lock); - ctx = idr_remove(&mgr->ctx_handles, id); + ctx = xa_erase(&fpriv->ctx_mgr.ctx_handles, id); amdgpu_ctx_put(ctx); - mutex_unlock(&mgr->lock); + return ctx ? 0 : -EINVAL; } @@ -530,20 +522,12 @@ static int amdgpu_ctx_query(struct amdgpu_device *adev, union drm_amdgpu_ctx_out *out) { struct amdgpu_ctx *ctx; - struct amdgpu_ctx_mgr *mgr; unsigned reset_counter; - if (!fpriv) + ctx = amdgpu_ctx_get(fpriv, id); + if (!ctx) return -EINVAL; - mgr = &fpriv->ctx_mgr; - mutex_lock(&mgr->lock); - ctx = idr_find(&mgr->ctx_handles, id); - if (!ctx) { - mutex_unlock(&mgr->lock); - return -EINVAL; - } - /* TODO: these two are always zero */ out->state.flags = 0x0; out->state.hangs = 0x0; @@ -557,7 +541,8 @@ static int amdgpu_ctx_query(struct amdgpu_device *adev, out->state.reset_status = AMDGPU_CTX_UNKNOWN_RESET; ctx->reset_counter_query = reset_counter; - mutex_unlock(&mgr->lock); + amdgpu_ctx_put(ctx); + return 0; } @@ -590,19 +575,11 @@ static int amdgpu_ctx_query2(struct amdgpu_device *adev, { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); struct amdgpu_ctx *ctx; - struct amdgpu_ctx_mgr *mgr; - if (!fpriv) + ctx = amdgpu_ctx_get(fpriv, id); + if (!ctx) return -EINVAL; - mgr = &fpriv->ctx_mgr; - mutex_lock(&mgr->lock); - ctx = idr_find(&mgr->ctx_handles, id); - if (!ctx) { - mutex_unlock(&mgr->lock); - return -EINVAL; - } - out->state.flags = 0x0; out->state.hangs = 0x0; @@ -642,7 +619,8 @@ static int amdgpu_ctx_query2(struct amdgpu_device *adev, msecs_to_jiffies(AMDGPU_RAS_COUNTE_DELAY_MS)); } - mutex_unlock(&mgr->lock); + amdgpu_ctx_put(ctx); + return 0; } @@ -651,26 +629,18 @@ static int amdgpu_ctx_stable_pstate(struct amdgpu_device *adev, bool set, u32 *stable_pstate) { struct amdgpu_ctx *ctx; - struct amdgpu_ctx_mgr *mgr; int r = 0; - if (!fpriv) + ctx = amdgpu_ctx_get(fpriv, id); + if (!ctx) return -EINVAL; - mgr = &fpriv->ctx_mgr; - mutex_lock(&mgr->lock); - ctx = idr_find(&mgr->ctx_handles, id); - if (!ctx) { - mutex_unlock(&mgr->lock); - return -EINVAL; - } - if (set) r = amdgpu_ctx_set_stable_pstate(ctx, *stable_pstate); else *stable_pstate = amdgpu_get_stable_pstate(adev); - mutex_unlock(&mgr->lock); + amdgpu_ctx_put(ctx); return r; } @@ -749,11 +719,11 @@ struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id) mgr = &fpriv->ctx_mgr; - mutex_lock(&mgr->lock); - ctx = idr_find(&mgr->ctx_handles, id); + xa_lock(&mgr->ctx_handles); + ctx = xa_load(&mgr->ctx_handles, id); if (ctx) kref_get(&ctx->refcount); - mutex_unlock(&mgr->lock); + xa_unlock(&mgr->ctx_handles); return ctx; } @@ -890,8 +860,7 @@ void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr, unsigned int i; mgr->adev = adev; - mutex_init(&mgr->lock); - idr_init_base(&mgr->ctx_handles, 1); + xa_init_flags(&mgr->ctx_handles, XA_FLAGS_ALLOC1); for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) atomic64_set(&mgr->time_spend[i], 0); @@ -900,13 +869,13 @@ void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr, long amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout) { struct amdgpu_ctx *ctx; - struct idr *idp; - uint32_t id, i, j; + unsigned long id; + int i, j; - idp = &mgr->ctx_handles; - - mutex_lock(&mgr->lock); - idr_for_each_entry(idp, ctx, id) { + xa_lock(&mgr->ctx_handles); + xa_for_each(&mgr->ctx_handles, id, ctx) { + kref_get(&ctx->refcount); + xa_unlock(&mgr->ctx_handles); for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) { for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j) { struct drm_sched_entity *entity; @@ -918,25 +887,21 @@ long amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout) timeout = drm_sched_entity_flush(entity, timeout); } } - } - mutex_unlock(&mgr->lock); - return timeout; -} - -static void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr) -{ - struct amdgpu_ctx *ctx; - uint32_t id; - - idr_for_each_entry(&mgr->ctx_handles, ctx, id) amdgpu_ctx_put(ctx); + xa_lock(&mgr->ctx_handles); + } + xa_unlock(&mgr->ctx_handles); + return timeout; } void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr) { - amdgpu_ctx_mgr_entity_fini(mgr); - idr_destroy(&mgr->ctx_handles); - mutex_destroy(&mgr->lock); + struct amdgpu_ctx *ctx; + unsigned long id; + + xa_for_each(&mgr->ctx_handles, id, ctx) + amdgpu_ctx_put(ctx); + xa_destroy(&mgr->ctx_handles); } void amdgpu_ctx_mgr_usage(struct amdgpu_ctx_mgr *mgr, @@ -944,21 +909,21 @@ void amdgpu_ctx_mgr_usage(struct amdgpu_ctx_mgr *mgr, { struct amdgpu_ctx *ctx; unsigned int hw_ip, i; - uint32_t id; + unsigned long id; /* * This is a little bit racy because it can be that a ctx or a fence are * destroyed just in the moment we try to account them. But that is ok * since exactly that case is explicitely allowed by the interface. */ - mutex_lock(&mgr->lock); for (hw_ip = 0; hw_ip < AMDGPU_HW_IP_NUM; ++hw_ip) { uint64_t ns = atomic64_read(&mgr->time_spend[hw_ip]); usage[hw_ip] = ns_to_ktime(ns); } - idr_for_each_entry(&mgr->ctx_handles, ctx, id) { + xa_lock(&mgr->ctx_handles); + xa_for_each(&mgr->ctx_handles, id, ctx) { for (hw_ip = 0; hw_ip < AMDGPU_HW_IP_NUM; ++hw_ip) { for (i = 0; i < amdgpu_ctx_num_entities[hw_ip]; ++i) { struct amdgpu_ctx_entity *centity; @@ -972,5 +937,5 @@ void amdgpu_ctx_mgr_usage(struct amdgpu_ctx_mgr *mgr, } } } - mutex_unlock(&mgr->lock); + xa_unlock(&mgr->ctx_handles); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h index 90a56096fa3e..a4b89eca4169 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h @@ -25,6 +25,7 @@ #include #include +#include #include "amdgpu_ring.h" @@ -60,9 +61,7 @@ struct amdgpu_ctx { struct amdgpu_ctx_mgr { struct amdgpu_device *adev; - struct mutex lock; - /* protected by lock */ - struct idr ctx_handles; + struct xarray ctx_handles; atomic64_t time_spend[AMDGPU_HW_IP_NUM]; }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c index 0eecfaa3a94c..8effb1158430 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c @@ -39,7 +39,7 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv; struct amdgpu_ctx_mgr *mgr; struct amdgpu_ctx *ctx; - uint32_t id; + unsigned long id; int r; if (fd_empty(f)) @@ -50,10 +50,10 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev, return r; mgr = &fpriv->ctx_mgr; - mutex_lock(&mgr->lock); - idr_for_each_entry(&mgr->ctx_handles, ctx, id) + xa_lock(&mgr->ctx_handles); + xa_for_each(&mgr->ctx_handles, id, ctx) amdgpu_ctx_priority_override(ctx, priority); - mutex_unlock(&mgr->lock); + xa_unlock(&mgr->ctx_handles); return 0; }