summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c76
1 files changed, 45 insertions, 31 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
index 616967519869..fe504f1a3fc8 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
@@ -506,9 +506,8 @@ void amdgpu_vcn_ring_begin_use(struct amdgpu_ring *ring)
struct amdgpu_device *adev = ring->adev;
struct amdgpu_vcn_inst *vcn_inst = &adev->vcn.inst[ring->me];
- atomic_inc(&vcn_inst->total_submission_cnt);
-
- cancel_delayed_work_sync(&vcn_inst->idle_work);
+ if (!atomic_fetch_inc(&vcn_inst->total_submission_cnt))
+ cancel_delayed_work_sync(&vcn_inst->idle_work);
mutex_lock(&vcn_inst->vcn_pg_lock);
vcn_inst->set_pg_state(vcn_inst, AMD_PG_STATE_UNGATE);
@@ -550,10 +549,9 @@ void amdgpu_vcn_ring_end_use(struct amdgpu_ring *ring)
!adev->vcn.inst[ring->me].using_unified_queue)
atomic_dec(&ring->adev->vcn.inst[ring->me].dpg_enc_submission_cnt);
- atomic_dec(&ring->adev->vcn.inst[ring->me].total_submission_cnt);
-
- schedule_delayed_work(&ring->adev->vcn.inst[ring->me].idle_work,
- VCN_IDLE_TIMEOUT);
+ if (atomic_dec_and_test(&ring->adev->vcn.inst[ring->me].total_submission_cnt))
+ schedule_delayed_work(&ring->adev->vcn.inst[ring->me].idle_work,
+ VCN_IDLE_TIMEOUT);
}
int amdgpu_vcn_dec_ring_test_ring(struct amdgpu_ring *ring)
@@ -1485,6 +1483,37 @@ int vcn_set_powergating_state(struct amdgpu_ip_block *ip_block,
return ret;
}
+static struct amdgpu_fence *
+amdgpu_vcn_ring_reset_begin_helper(struct amdgpu_ring *ring,
+ struct amdgpu_ring *guilty_ring,
+ struct amdgpu_fence *timedout_fence)
+{
+ struct amdgpu_fence *fence;
+
+ drm_sched_wqueue_stop(&ring->sched);
+ if (ring == guilty_ring)
+ fence = timedout_fence;
+ else
+ fence = amdgpu_ring_find_guilty_fence(ring);
+ amdgpu_ring_reset_helper_begin(ring, fence);
+
+ return fence;
+}
+
+static int
+amdgpu_vcn_ring_reset_end_helper(struct amdgpu_ring *ring,
+ struct amdgpu_fence *fence)
+{
+ int r;
+
+ r = amdgpu_ring_reset_helper_end(ring, fence);
+ if (r)
+ return r;
+
+ drm_sched_wqueue_start(&ring->sched);
+ return 0;
+}
+
/**
* amdgpu_vcn_ring_reset - Reset a VCN ring
* @ring: ring to reset
@@ -1502,48 +1531,33 @@ int amdgpu_vcn_ring_reset(struct amdgpu_ring *ring,
{
struct amdgpu_device *adev = ring->adev;
struct amdgpu_vcn_inst *vinst = &adev->vcn.inst[ring->me];
+ struct amdgpu_fence *dec_fence;
+ struct amdgpu_fence *enc_fence[AMDGPU_VCN_MAX_ENC_RINGS];
int r, i;
if (adev->vcn.inst[ring->me].using_unified_queue)
return -EINVAL;
mutex_lock(&vinst->engine_reset_mutex);
- /* Stop the scheduler's work queue for the dec and enc rings if they are running.
- * This ensures that no new tasks are submitted to the queues while
- * the reset is in progress.
- */
- drm_sched_wqueue_stop(&vinst->ring_dec.sched);
+ dec_fence = amdgpu_vcn_ring_reset_begin_helper(&vinst->ring_dec, ring,
+ timedout_fence);
for (i = 0; i < vinst->num_enc_rings; i++)
- drm_sched_wqueue_stop(&vinst->ring_enc[i].sched);
+ enc_fence[i] = amdgpu_vcn_ring_reset_begin_helper(&vinst->ring_enc[i], ring,
+ timedout_fence);
/* Perform the VCN reset for the specified instance */
r = vinst->reset(vinst);
if (r)
goto unlock;
- r = amdgpu_ring_test_ring(&vinst->ring_dec);
+
+ r = amdgpu_vcn_ring_reset_end_helper(&vinst->ring_dec, dec_fence);
if (r)
goto unlock;
for (i = 0; i < vinst->num_enc_rings; i++) {
- r = amdgpu_ring_test_ring(&vinst->ring_enc[i]);
+ r = amdgpu_vcn_ring_reset_end_helper(&vinst->ring_enc[i], enc_fence[i]);
if (r)
goto unlock;
}
- amdgpu_fence_driver_force_completion(&vinst->ring_dec,
- (&vinst->ring_dec == ring) ?
- &timedout_fence->base : NULL);
- for (i = 0; i < vinst->num_enc_rings; i++)
- amdgpu_fence_driver_force_completion(&vinst->ring_enc[i],
- (&vinst->ring_enc[i] == ring) ?
- &timedout_fence->base : NULL);
-
- /* Restart the scheduler's work queue for the dec and enc rings
- * if they were stopped by this function. This allows new tasks
- * to be submitted to the queues after the reset is complete.
- */
- drm_sched_wqueue_start(&vinst->ring_dec.sched);
- for (i = 0; i < vinst->num_enc_rings; i++)
- drm_sched_wqueue_start(&vinst->ring_enc[i].sched);
-
unlock:
mutex_unlock(&vinst->engine_reset_mutex);