]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drm/amdgpu: Check vcn state before profile switch
authorLijo Lazar <lijo.lazar@amd.com>
Thu, 14 Aug 2025 08:22:50 +0000 (13:52 +0530)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 29 Aug 2025 14:09:33 +0000 (10:09 -0400)
The patch uses power state of VCN instances for requesting video
profile.

In idle worker of a vcn instance, when there is no outstanding
submisssion or fence, the instance is put to power gated state. When
all instances are powered off that means video profile is no longer
required. A request is made to turn off video profile.

A job submission starts with begin_use of ring, and at that time
vcn instance state is changed to power on. Subsequently a check is
made for active video profile, and if not active, a request is made.

Fixes: 3b669df92c85 ("drm/amdgpu/vcn: adjust workload profile handling")
Signed-off-by: Lijo Lazar <lijo.lazar@amd.com>
Reviewed-by: Sathishkumar S <sathishkumar.sundararaju@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c

index 5a90abcea0ac1afab854f607d9a6d77531c0b717..ad415203d245d8d62b78ae06c990ec4eb99b12d1 100644 (file)
@@ -408,6 +408,54 @@ int amdgpu_vcn_resume(struct amdgpu_device *adev, int i)
        return 0;
 }
 
+void amdgpu_vcn_get_profile(struct amdgpu_device *adev)
+{
+       int r;
+
+       mutex_lock(&adev->vcn.workload_profile_mutex);
+
+       if (adev->vcn.workload_profile_active) {
+               mutex_unlock(&adev->vcn.workload_profile_mutex);
+               return;
+       }
+       r = amdgpu_dpm_switch_power_profile(adev, PP_SMC_POWER_PROFILE_VIDEO,
+                                           true);
+       if (r)
+               dev_warn(adev->dev,
+                        "(%d) failed to enable video power profile mode\n", r);
+       else
+               adev->vcn.workload_profile_active = true;
+       mutex_unlock(&adev->vcn.workload_profile_mutex);
+}
+
+void amdgpu_vcn_put_profile(struct amdgpu_device *adev)
+{
+       bool pg = true;
+       int r, i;
+
+       mutex_lock(&adev->vcn.workload_profile_mutex);
+       for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
+               if (adev->vcn.inst[i].cur_state != AMD_PG_STATE_GATE) {
+                       pg = false;
+                       break;
+               }
+       }
+
+       if (pg) {
+               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);
+               else
+                       adev->vcn.workload_profile_active = false;
+       }
+
+       mutex_unlock(&adev->vcn.workload_profile_mutex);
+}
+
 static void amdgpu_vcn_idle_work_handler(struct work_struct *work)
 {
        struct amdgpu_vcn_inst *vcn_inst =
@@ -415,7 +463,6 @@ static void amdgpu_vcn_idle_work_handler(struct work_struct *work)
        struct amdgpu_device *adev = vcn_inst->adev;
        unsigned int fences = 0, fence[AMDGPU_MAX_VCN_INSTANCES] = {0};
        unsigned int i = vcn_inst->inst, j;
-       int r = 0;
 
        if (adev->vcn.harvest_config & (1 << i))
                return;
@@ -444,15 +491,8 @@ static void amdgpu_vcn_idle_work_handler(struct work_struct *work)
                mutex_lock(&vcn_inst->vcn_pg_lock);
                vcn_inst->set_pg_state(vcn_inst, AMD_PG_STATE_GATE);
                mutex_unlock(&vcn_inst->vcn_pg_lock);
-               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);
+               amdgpu_vcn_put_profile(adev);
+
        } else {
                schedule_delayed_work(&vcn_inst->idle_work, VCN_IDLE_TIMEOUT);
        }
@@ -462,30 +502,11 @@ 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];
-       int r = 0;
 
        atomic_inc(&vcn_inst->total_submission_cnt);
 
        cancel_delayed_work_sync(&vcn_inst->idle_work);
 
-       /* We can safely return early here because we've cancelled the
-        * the delayed work so there is no one else to set it to false
-        * and we don't care if someone else sets it to true.
-        */
-       if (adev->vcn.workload_profile_active)
-               goto pg_lock;
-
-       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);
-
-pg_lock:
        mutex_lock(&vcn_inst->vcn_pg_lock);
        vcn_inst->set_pg_state(vcn_inst, AMD_PG_STATE_UNGATE);
 
@@ -513,6 +534,7 @@ pg_lock:
                vcn_inst->pause_dpg_mode(vcn_inst, &new_state);
        }
        mutex_unlock(&vcn_inst->vcn_pg_lock);
+       amdgpu_vcn_get_profile(adev);
 }
 
 void amdgpu_vcn_ring_end_use(struct amdgpu_ring *ring)
index b3fb1d0e43fc957ecd2e9ca1c86ca05d80b46240..6d9acd36041d09be1571b5efa192bb997539e1c5 100644 (file)
@@ -565,4 +565,7 @@ int amdgpu_vcn_reg_dump_init(struct amdgpu_device *adev,
                             const struct amdgpu_hwip_reg_entry *reg, u32 count);
 void amdgpu_vcn_dump_ip_state(struct amdgpu_ip_block *ip_block);
 void amdgpu_vcn_print_ip_state(struct amdgpu_ip_block *ip_block, struct drm_printer *p);
+void amdgpu_vcn_get_profile(struct amdgpu_device *adev);
+void amdgpu_vcn_put_profile(struct amdgpu_device *adev);
+
 #endif
index 3a7c137a83efb991dccf8f493923492ec230de7c..904b94bc8693c919bf89bc237832fdee6a2468da 100644 (file)
@@ -116,7 +116,6 @@ static void vcn_v2_5_idle_work_handler(struct work_struct *work)
        struct amdgpu_device *adev = vcn_inst->adev;
        unsigned int fences = 0, fence[AMDGPU_MAX_VCN_INSTANCES] = {0};
        unsigned int i, j;
-       int r = 0;
 
        for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
                struct amdgpu_vcn_inst *v = &adev->vcn.inst[i];
@@ -149,15 +148,7 @@ 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);
-               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);
+               amdgpu_vcn_put_profile(adev);
        } else {
                schedule_delayed_work(&adev->vcn.inst[0].idle_work, VCN_IDLE_TIMEOUT);
        }
@@ -167,7 +158,6 @@ static void vcn_v2_5_ring_begin_use(struct amdgpu_ring *ring)
 {
        struct amdgpu_device *adev = ring->adev;
        struct amdgpu_vcn_inst *v = &adev->vcn.inst[ring->me];
-       int r = 0;
 
        atomic_inc(&adev->vcn.inst[0].total_submission_cnt);
 
@@ -177,20 +167,6 @@ static void vcn_v2_5_ring_begin_use(struct amdgpu_ring *ring)
         * the delayed work so there is no one else to set it to false
         * and we don't care if someone else sets it to true.
         */
-       if (adev->vcn.workload_profile_active)
-               goto pg_lock;
-
-       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);
-
-pg_lock:
        mutex_lock(&adev->vcn.inst[0].vcn_pg_lock);
        amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCN,
                                               AMD_PG_STATE_UNGATE);
@@ -218,6 +194,7 @@ pg_lock:
                v->pause_dpg_mode(v, &new_state);
        }
        mutex_unlock(&adev->vcn.inst[0].vcn_pg_lock);
+       amdgpu_vcn_get_profile(adev);
 }
 
 static void vcn_v2_5_ring_end_use(struct amdgpu_ring *ring)