This commit implements device PMC handler This commit introduces a new helper amdgpu_userq_xa_find. This helper finds a queue from a XArray which has the lowest index that is at least the given index, and hold its kref.
Signed-off-by: Zhu Lingshan <[email protected]> Reviewed-by: Benjamin Welton <[email protected]> --- drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.c | 5 +- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 134 +++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h | 2 + 3 files changed, 140 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.c index 276dc75f0e7d..41826f4e7dac 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.c @@ -106,7 +106,10 @@ int amdgpu_profiler_set_perfcount(struct amdgpu_device *adev, out: mutex_unlock(&adev->pmc_profiler.lock); - return ret; + if (ret) + return ret; + + return amdgpu_set_perfcount(adev, enable); } static int amdgpu_profiler_check_access(struct drm_device *dev) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index db09e879b85e..b4a2164068e3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -623,6 +623,54 @@ void amdgpu_userq_put(struct amdgpu_usermode_queue *queue) kref_put(&queue->refcount, amdgpu_userq_kref_destroy); } +/** + * amdgpu_userq_xa_find - search the XArray for a queue + * @xa: user queue XArray + * @index: first index to search, updated by every iteration of the search + * + * Return: a queue which has the lowest index that is at least @index, + * or NULL when no queue was found. + * + * The caller must release the kref of a queue with amdgpu_userq_put() after use. + */ +static struct amdgpu_usermode_queue * +amdgpu_userq_xa_find(struct xarray *xa, unsigned long *index) +{ + struct amdgpu_usermode_queue *queue; + unsigned long flags; + + xa_lock_irqsave(xa, flags); + queue = xa_find(xa, index, ULONG_MAX, XA_PRESENT); + while (queue) { + /* + * If found a queue but failed to get a kref, + * it means the queue is in destruction process, + * so skip it by continuing the loop. + * + * If get a kref of the queue, break the loop and return it. + */ + if (kref_get_unless_zero(&queue->refcount)) + break; + + /* + * If the index is ULONG_MAX, we have reached the end of the XArray. + * Break the loop and return NULL because ULONG_MAX + 1 = 0, + * which is the start of the XArray. + */ + if (*index == ULONG_MAX) { + queue = NULL; + break; + } + + (*index)++; + queue = xa_find(xa, index, ULONG_MAX, XA_PRESENT); + } + + xa_unlock_irqrestore(xa, flags); + + return queue; +} + static int amdgpu_userq_priority_permit(struct drm_file *filp, int priority) { @@ -1432,6 +1480,92 @@ int amdgpu_userq_resume(struct amdgpu_device *adev) return 0; } +static void amdgpu_userq_set_perfcount(struct amdgpu_usermode_queue *queue, + bool enable) +{ + struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr; + struct amdgpu_device *adev = uq_mgr->adev; + struct amdgpu_mqd *mqd_funcs = &adev->mqds[queue->queue_type]; + int r; + bool mapped; + + if (queue->queue_type != AMDGPU_HW_IP_COMPUTE) + return; + + mutex_lock(&uq_mgr->userq_mutex); + + if (queue->state != AMDGPU_USERQ_STATE_MAPPED && + queue->state != AMDGPU_USERQ_STATE_UNMAPPED) { + drm_file_err(uq_mgr->file, + "user queue %llu is in state %d, skip it when updating PMC\n", + queue->doorbell_index, queue->state); + goto out; + } + + mapped = queue->state == AMDGPU_USERQ_STATE_MAPPED; + queue->userq_prop->perfcount_enable = enable; + queue->userq_prop->modify = true; + + if (queue->state == AMDGPU_USERQ_STATE_MAPPED) { + r = amdgpu_userq_unmap_helper(queue); + if (r) { + drm_file_err(uq_mgr->file, + "Failed to unmap user queue %llu when updating PMC\n", + queue->doorbell_index); + goto out; + } + } + + r = mqd_funcs->init_mqd(adev, (void *)queue->mqd.cpu_ptr, queue->userq_prop); + if (r) { + drm_file_err(uq_mgr->file, + "Failed to update mqd for user queue %llu when updating PMC\n", + queue->doorbell_index); + goto out; + } + + if (mapped) { + r = amdgpu_userq_map_helper(queue); + if (r) { + drm_file_err(uq_mgr->file, + "Failed to map user queue %llu when updating PMC\n", + queue->doorbell_index); + } + } + +out: + mutex_unlock(&uq_mgr->userq_mutex); +} + +/* set perfcount for every queue on the device. */ +int amdgpu_set_perfcount(struct amdgpu_device *adev, bool enable) +{ + struct amdgpu_usermode_queue *queue; + unsigned long queue_id = 0; + + if (amdgpu_in_reset(adev)) + return -EIO; + + if (adev->userq_halt_for_enforce_isolation) + return -EAGAIN; + + queue = amdgpu_userq_xa_find(&adev->userq_doorbell_xa, &queue_id); + while (queue) { + amdgpu_userq_set_perfcount(queue, enable); + amdgpu_userq_put(queue); + + if (queue_id == ULONG_MAX) + break; + + /* find next queue */ + queue_id++; + queue = amdgpu_userq_xa_find(&adev->userq_doorbell_xa, + &queue_id); + } + + return 0; +} + int amdgpu_userq_stop_sched_for_enforce_isolation(struct amdgpu_device *adev, u32 idx) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h index 3e19bc6103a0..8f95b2c338f7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h @@ -178,6 +178,8 @@ int amdgpu_userq_stop_sched_for_enforce_isolation(struct amdgpu_device *adev, u32 idx); int amdgpu_userq_start_sched_for_enforce_isolation(struct amdgpu_device *adev, u32 idx); + +int amdgpu_set_perfcount(struct amdgpu_device *adev, bool enable); void amdgpu_userq_reset_work(struct work_struct *work); void amdgpu_userq_pre_reset(struct amdgpu_device *adev); int amdgpu_userq_post_reset(struct amdgpu_device *adev, bool vram_lost); -- 2.53.0
