A hung user queue must not be replayed after reset because its context may be corrupted. Keep the guilty state on the queue and report it through the sticky HUNG status. Skip guilty queues and queues whose VM generation has changed when mapping or restoring them.
Signed-off-by: Prike Liang <[email protected]> --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 30 ++++++++++++++++++++--- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h | 3 +++ include/uapi/drm/amdgpu_drm.h | 11 ++++++--- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 4ddd22af63c5..8ac63beca995 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -148,6 +148,8 @@ static void amdgpu_userq_hang_detect_work(struct work_struct *work) } } + WRITE_ONCE(queue->guilty, true); + if (amdgpu_userq_is_reset_type_supported(adev, queue->queue_type, AMDGPU_RESET_TYPE_PER_QUEUE)) { int r; @@ -174,7 +176,7 @@ static void amdgpu_userq_hang_detect_work(struct work_struct *work) * handler to another is illegal if you don't take extra precautions! */ if (gpu_reset) - amdgpu_userq_mgr_reset_work(&queue->userq_mgr->reset_work); + amdgpu_userq_mgr_reset_work(&uq_mgr->reset_work); } /* @@ -338,6 +340,10 @@ static int amdgpu_userq_restore_helper(struct amdgpu_usermode_queue *queue) adev->userq_funcs[queue->queue_type]; int r = 0; + if (READ_ONCE(queue->guilty) || + queue->generation != amdgpu_vm_generation(adev, queue->vm)) + return 0; + if (queue->state == AMDGPU_USERQ_STATE_PREEMPTED) { trace_amdgpu_userq_state_start(queue); @@ -388,6 +394,10 @@ static int amdgpu_userq_map_helper(struct amdgpu_usermode_queue *queue) adev->userq_funcs[queue->queue_type]; int r; + if (READ_ONCE(queue->guilty) || + queue->generation != amdgpu_vm_generation(adev, queue->vm)) + return 0; + if (queue->state == AMDGPU_USERQ_STATE_UNMAPPED) { trace_amdgpu_userq_state_start(queue); @@ -692,6 +702,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) queue->queue_type = args->in.ip_type; queue->vm = &fpriv->vm; queue->priority = priority; + queue->reset_counter = atomic_read(&adev->gpu_reset_counter); queue->generation = amdgpu_vm_generation(adev, &fpriv->vm); queue->xcp_id = (fpriv->xcp_id != AMDGPU_XCP_NO_PARTITION) ? fpriv->xcp_id : 0; @@ -831,14 +842,20 @@ amdgpu_userq_query_status(struct drm_file *filp, union drm_amdgpu_userq *args) } args->out_qs.flags = 0; - if (queue->state == AMDGPU_USERQ_STATE_HUNG) + if (queue->reset_counter != atomic_read(&adev->gpu_reset_counter)) + args->out_qs.flags |= AMDGPU_USERQ_QUERY_STATUS_FLAGS_RESET; + if (queue->state == AMDGPU_USERQ_STATE_HUNG || + READ_ONCE(queue->guilty)) args->out_qs.flags |= AMDGPU_USERQ_QUERY_STATUS_FLAGS_HUNG; if (queue->generation != amdgpu_vm_generation(adev, &fpriv->vm)) args->out_qs.flags |= AMDGPU_USERQ_QUERY_STATUS_FLAGS_VRAMLOST; if (queue->state == AMDGPU_USERQ_STATE_INVALID_VA) args->out_qs.flags |= AMDGPU_USERQ_QUERY_STATUS_FLAGS_INVALID_VA; - amdgpu_userq_put(queue); + if (amdgpu_in_reset(adev)) + args->out_qs.flags |= AMDGPU_USERQ_QUERY_STATUS_FLAGS_RESET_IN_PROGRESS; mutex_unlock(&uq_mgr->userq_mutex); + /* The final put may destroy the queue and take userq_mutex. */ + amdgpu_userq_put(queue); return 0; } @@ -900,6 +917,7 @@ static int amdgpu_userq_input_args_validate(struct drm_device *dev, } break; case AMDGPU_USERQ_OP_FREE: + case AMDGPU_USERQ_OP_QUERY_STATUS: if (args->in.ip_type || args->in.doorbell_handle || args->in.doorbell_offset || @@ -1596,7 +1614,11 @@ int amdgpu_userq_post_reset(struct amdgpu_device *adev, bool vram_lost) int ret = 0, r; xa_for_each(&adev->userq_doorbell_xa, queue_id, queue) { - if (queue->state == AMDGPU_USERQ_STATE_HUNG && !vram_lost) { + if (vram_lost || READ_ONCE(queue->guilty) || + queue->generation != amdgpu_vm_generation(adev, queue->vm)) + continue; + + if (queue->state == AMDGPU_USERQ_STATE_HUNG) { trace_amdgpu_userq_state_start(queue); userq_funcs = adev->userq_funcs[queue->queue_type]; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h index d1a2e2a45861..c2349115f404 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h @@ -51,6 +51,8 @@ struct amdgpu_userq_obj { struct amdgpu_usermode_queue { int queue_type; enum amdgpu_userq_state state; + /* Reset due to a hang; must not be re-mapped, userspace recreates. */ + bool guilty; uint64_t doorbell_handle; uint64_t doorbell_index; u32 doorbell_offset; @@ -79,6 +81,7 @@ struct amdgpu_usermode_queue { struct dma_fence *last_fence; u32 xcp_id; int priority; + unsigned int reset_counter; uint64_t generation; struct dentry *debugfs_queue; diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index 2f81ec3265cd..7e928c4e8868 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -360,18 +360,23 @@ union drm_amdgpu_ctx { #define AMDGPU_USERQ_QUERY_STATUS_FLAGS_VRAMLOST (1 << 1) /* the invalid userq VA unmapped */ #define AMDGPU_USERQ_QUERY_STATUS_FLAGS_INVALID_VA (1 << 2) +/* indicate a GPU reset occurred since the queue was created */ +#define AMDGPU_USERQ_QUERY_STATUS_FLAGS_RESET (1 << 3) +/* indicate that a GPU reset has not completed yet */ +#define AMDGPU_USERQ_QUERY_STATUS_FLAGS_RESET_IN_PROGRESS (1 << 4) + /* * This structure is a container to pass input configuration * info for all supported userqueue related operations. * For operation AMDGPU_USERQ_OP_CREATE: user is expected * to set all fields, excep the parameter 'queue_id'. - * For operation AMDGPU_USERQ_OP_FREE: the only input parameter expected - * to be set is 'queue_id', eveything else is ignored. + * For operations AMDGPU_USERQ_OP_FREE and AMDGPU_USERQ_OP_QUERY_STATUS: + * only 'op' and 'queue_id' should be set; all other fields must be zero. */ struct drm_amdgpu_userq_in { /** AMDGPU_USERQ_OP_* */ __u32 op; - /** Queue id passed for operation USERQ_OP_FREE */ + /** Queue id passed for operations USERQ_OP_FREE and USERQ_OP_QUERY_STATUS */ __u32 queue_id; /** the target GPU engine to execute workload (AMDGPU_HW_IP_*) */ __u32 ip_type; -- 2.34.1
