We need to make sure the workload profile ref counts are
balanced.  This isn't currently the case because we can
increment the count on submissions, but the decrement may
be delayed as work comes in.  Track when we enable the
workload profile so the references are balanced.

v2: switch to a mutex and active flag

Fixes: 1443dd3c67f6 ("drm/amd/pm: fix and simplify workload handling”)
Cc: Yang Wang <[email protected]>
Cc: Kenneth Feng <[email protected]>
Signed-off-by: Alex Deucher <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | 26 +++++++++++++++++--------
 drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h |  3 +++
 drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c   | 26 +++++++++++++++++--------
 3 files changed, 39 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
index 8d8b39e6d197a..6b410e601bb65 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
@@ -438,10 +438,15 @@ static void amdgpu_vcn_idle_work_handler(struct 
work_struct *work)
 
        if (!fences && !atomic_read(&vcn_inst->total_submission_cnt)) {
                vcn_inst->set_pg_state(vcn_inst, AMD_PG_STATE_GATE);
-               r = amdgpu_dpm_switch_power_profile(adev, 
PP_SMC_POWER_PROFILE_VIDEO,
-                                                   false);
-               if (r)
-                       dev_warn(adev->dev, "(%d) failed to disable video power 
profile mode\n", r);
+               mutex_lock(&adev->vcn.workload_profile_mutex);
+               if (adev->vcn.workload_profile_active) {
+                       r = amdgpu_dpm_switch_power_profile(adev, 
PP_SMC_POWER_PROFILE_VIDEO,
+                                                           false);
+                       if (r)
+                               dev_warn(adev->dev, "(%d) failed to disable 
video power profile mode\n", r);
+                       adev->vcn.workload_profile_active = false;
+               }
+               mutex_unlock(&adev->vcn.workload_profile_mutex);
        } else {
                schedule_delayed_work(&vcn_inst->idle_work, VCN_IDLE_TIMEOUT);
        }
@@ -456,10 +461,15 @@ void amdgpu_vcn_ring_begin_use(struct amdgpu_ring *ring)
        atomic_inc(&vcn_inst->total_submission_cnt);
 
        if (!cancel_delayed_work_sync(&vcn_inst->idle_work)) {
-               r = amdgpu_dpm_switch_power_profile(adev, 
PP_SMC_POWER_PROFILE_VIDEO,
-                               true);
-               if (r)
-                       dev_warn(adev->dev, "(%d) failed to switch to video 
power profile mode\n", r);
+               mutex_lock(&adev->vcn.workload_profile_mutex);
+               if (!adev->vcn.workload_profile_active) {
+                       r = amdgpu_dpm_switch_power_profile(adev, 
PP_SMC_POWER_PROFILE_VIDEO,
+                                                           true);
+                       if (r)
+                               dev_warn(adev->dev, "(%d) failed to switch to 
video power profile mode\n", r);
+                       adev->vcn.workload_profile_active = true;
+               }
+               mutex_unlock(&adev->vcn.workload_profile_mutex);
        }
 
        mutex_lock(&vcn_inst->vcn_pg_lock);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
index 26c9c2d90f455..cdcdae7f71ce9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
@@ -358,6 +358,9 @@ struct amdgpu_vcn {
 
        bool                    per_inst_fw;
        unsigned                fw_version;
+
+       bool                    workload_profile_active;
+       struct mutex            workload_profile_mutex;
 };
 
 struct amdgpu_fw_shared_rb_ptrs_struct {
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c 
b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
index ff03436698a4f..b4b8091980ad5 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
@@ -147,10 +147,15 @@ static void vcn_v2_5_idle_work_handler(struct work_struct 
*work)
        if (!fences && !atomic_read(&adev->vcn.inst[0].total_submission_cnt)) {
                amdgpu_device_ip_set_powergating_state(adev, 
AMD_IP_BLOCK_TYPE_VCN,
                                                       AMD_PG_STATE_GATE);
-               r = amdgpu_dpm_switch_power_profile(adev, 
PP_SMC_POWER_PROFILE_VIDEO,
-                                                   false);
-               if (r)
-                       dev_warn(adev->dev, "(%d) failed to disable video power 
profile mode\n", r);
+               mutex_lock(&adev->vcn.workload_profile_mutex);
+               if (adev->vcn.workload_profile_active) {
+                       r = amdgpu_dpm_switch_power_profile(adev, 
PP_SMC_POWER_PROFILE_VIDEO,
+                                                           false);
+                       if (r)
+                               dev_warn(adev->dev, "(%d) failed to disable 
video power profile mode\n", r);
+                       adev->vcn.workload_profile_active = false;
+               }
+               mutex_unlock(&adev->vcn.workload_profile_mutex);
        } else {
                schedule_delayed_work(&adev->vcn.inst[0].idle_work, 
VCN_IDLE_TIMEOUT);
        }
@@ -165,10 +170,15 @@ static void vcn_v2_5_ring_begin_use(struct amdgpu_ring 
*ring)
        atomic_inc(&adev->vcn.inst[0].total_submission_cnt);
 
        if (!cancel_delayed_work_sync(&adev->vcn.inst[0].idle_work)) {
-               r = amdgpu_dpm_switch_power_profile(adev, 
PP_SMC_POWER_PROFILE_VIDEO,
-                                                   true);
-               if (r)
-                       dev_warn(adev->dev, "(%d) failed to switch to video 
power profile mode\n", r);
+               mutex_lock(&adev->vcn.workload_profile_mutex);
+               if (!adev->vcn.workload_profile_active) {
+                       r = amdgpu_dpm_switch_power_profile(adev, 
PP_SMC_POWER_PROFILE_VIDEO,
+                                                           true);
+                       if (r)
+                               dev_warn(adev->dev, "(%d) failed to switch to 
video power profile mode\n", r);
+                       adev->vcn.workload_profile_active = true;
+               }
+               mutex_unlock(&adev->vcn.workload_profile_mutex);
        }
 
        mutex_lock(&adev->vcn.inst[0].vcn_pg_lock);
-- 
2.48.1

Reply via email to