[PATCH] amdkfd: fix deadlock in set_perfcount
Zhu Lingshan <[email protected]> Fri, 31 Jul 2026 17:51:05 +0800
| Newsgroups | org.freedesktop.lists.amd-gfx |
|---|---|
| Message-ID | <[email protected]> |
set_perfcount holds the DQM lock (dqm_lock(dqm) while walking queues, but pqm_update_mqd calls update_queue, which acquires the same lock by dqm_lock(dqm), causing deadlocks. This commit introduces update_queue_locked which assumes the dqm lock is already held, and update_queue calls it with proper lockings. set_perfcount calls update_queue_locked instead of pqm_update_mqd, therefore the deadlock is fixed. Signed-off-by: Zhu Lingshan <[email protected]> --- .../drm/amd/amdkfd/kfd_device_queue_manager.c | 44 ++++++++++++------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 51ee9c39104b..c34c5f6a5541 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -77,6 +77,9 @@ static struct queue *find_queue_by_doorbell_offset(struct device_queue_manager * static void set_queue_as_reset(struct device_queue_manager *dqm, struct queue *q, struct qcm_process_device *qpd); static int reset_queues_mes(struct device_queue_manager *dqm, struct queue *q); +static int update_queue_locked(struct device_queue_manager *dqm, + struct queue *q, + struct mqd_update_info *minfo); static inline enum KFD_MQD_TYPE get_mqd_type_from_queue_type(enum kfd_queue_type type) @@ -341,8 +344,7 @@ static void set_perfcount(struct device_queue_manager *dqm, int enable) list_for_each_entry(cur, &dqm->queues, list) { qpd = cur->qpd; list_for_each_entry(q, &qpd->queues_list, list) { - pqm_update_mqd(qpd->pqm, q->properties.queue_id, - &minfo); + update_queue_locked(dqm, q, &minfo); } } dqm_unlock(dqm); @@ -1059,8 +1061,9 @@ static int destroy_queue_nocpsch(struct device_queue_manager *dqm, return retval; } -static int update_queue(struct device_queue_manager *dqm, struct queue *q, - struct mqd_update_info *minfo) +static int update_queue_locked(struct device_queue_manager *dqm, + struct queue *q, + struct mqd_update_info *minfo) { int retval = 0; struct device *dev = dqm->dev->adev->dev; @@ -1068,12 +1071,11 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q, struct kfd_process_device *pdd; bool prev_active = false; - dqm_lock(dqm); + lockdep_assert_held(&dqm->lock_hidden); + pdd = kfd_get_process_device_data(q->device, q->process); - if (!pdd) { - retval = -ENODEV; - goto out_unlock; - } + if (!pdd) + return -ENODEV; mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type( q->properties.type)]; @@ -1089,14 +1091,12 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q, retval = remove_queue_mes(dqm, q, &pdd->qpd); /* queue is reset so inaccessable */ - if (pdd->has_reset_queue) { - retval = -EACCES; - goto out_unlock; - } + if (pdd->has_reset_queue) + return -EACCES; if (retval) { dev_err(dev, "unmap queue failed\n"); - goto out_unlock; + return retval; } } else if (prev_active && (q->properties.type == KFD_QUEUE_TYPE_COMPUTE || @@ -1105,7 +1105,7 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q, if (!dqm->sched_running) { WARN_ONCE(1, "Update non-HWS queue while stopped\n"); - goto out_unlock; + return -EIO; } retval = mqd_mgr->destroy_mqd(mqd_mgr, q->mqd, @@ -1115,7 +1115,7 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q, KFD_UNMAP_LATENCY_MS, q->pipe, q->queue); if (retval) { dev_err(dev, "destroy mqd failed\n"); - goto out_unlock; + return retval; } } @@ -1163,8 +1163,18 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q, &q->properties, current->mm); } -out_unlock: + return retval; +} + +static int update_queue(struct device_queue_manager *dqm, struct queue *q, + struct mqd_update_info *minfo) +{ + int retval; + + dqm_lock(dqm); + retval = update_queue_locked(dqm, q, minfo); dqm_unlock(dqm); + return retval; } -- 2.53.0