Protect media idle workers with a reset-domain read trylock. On contention,
requeue the idle timeout and return without hardware access. Keep the
ordinary end-use scheduling event, including from reset-time ring tests,
so otherwise idle engines eventually power down and VCN drops its profile.

A blocking read acquisition would deadlock with reset-time synchronous
cancellation of these workers, so the workers must only try the lock.

Signed-off-by: Prike Liang <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c | 7 +++++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c  | 7 +++++++
 2 files changed, 14 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c
index 9887a4f99aed..7b10260ad0d4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c
@@ -114,6 +114,12 @@ static void amdgpu_jpeg_idle_work_handler(struct 
work_struct *work)
        unsigned int fences = 0;
        unsigned int i, j;
 
+       /* Reset may cancel this worker synchronously while holding the writer. 
*/
+       if (!down_read_trylock(&adev->reset_domain->sem)) {
+               schedule_delayed_work(&adev->jpeg.idle_work, JPEG_IDLE_TIMEOUT);
+               return;
+       }
+
        for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) {
                if (adev->jpeg.harvest_config & (1U << i))
                        continue;
@@ -129,6 +135,7 @@ static void amdgpu_jpeg_idle_work_handler(struct 
work_struct *work)
                mutex_unlock(&adev->jpeg.jpeg_pg_lock);
        } else
                schedule_delayed_work(&adev->jpeg.idle_work, JPEG_IDLE_TIMEOUT);
+       up_read(&adev->reset_domain->sem);
 }
 
 void amdgpu_jpeg_ring_begin_use(struct amdgpu_ring *ring)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
index 17db7264269e..f851a6ecea1b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
@@ -470,6 +470,12 @@ static void amdgpu_vcn_idle_work_handler(struct 
work_struct *work)
        if (adev->vcn.harvest_config & (1 << i))
                return;
 
+       /* Reset may cancel this worker synchronously while holding the writer. 
*/
+       if (!down_read_trylock(&adev->reset_domain->sem)) {
+               schedule_delayed_work(&vcn_inst->idle_work, VCN_IDLE_TIMEOUT);
+               return;
+       }
+
        for (j = 0; j < adev->vcn.inst[i].num_enc_rings; ++j)
                fence[i] += amdgpu_fence_count_emitted(&vcn_inst->ring_enc[j]);
 
@@ -499,6 +505,7 @@ static void amdgpu_vcn_idle_work_handler(struct work_struct 
*work)
        } else {
                schedule_delayed_work(&vcn_inst->idle_work, VCN_IDLE_TIMEOUT);
        }
+       up_read(&adev->reset_domain->sem);
 }
 
 void amdgpu_vcn_ring_begin_use(struct amdgpu_ring *ring)
-- 
2.34.1

Reply via email to