| From bbd90d289cc3b4b8e3c0bfe4f19fa3278b4fbd67 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 14 Aug 2025 13:52:50 +0530 |
| Subject: drm/amdgpu: Check vcn state before profile switch |
| |
| From: Lijo Lazar <lijo.lazar@amd.com> |
| |
| [ Upstream commit 9c0442286f84a5036958b3d8eb00bf0bb070dbd1 ] |
| |
| 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> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | 80 ++++++++++++++++--------- |
| drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h | 3 + |
| drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c | 27 +-------- |
| 3 files changed, 56 insertions(+), 54 deletions(-) |
| |
| diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c |
| index e965b624efdb1..e5e40d10bb14b 100644 |
| --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c |
| +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c |
| @@ -410,6 +410,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 = |
| @@ -417,7 +465,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; |
| @@ -446,15 +493,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); |
| } |
| @@ -464,30 +504,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); |
| |
| @@ -515,6 +536,7 @@ void amdgpu_vcn_ring_begin_use(struct amdgpu_ring *ring) |
| 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) |
| diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h |
| index b3fb1d0e43fc9..6d9acd36041d0 100644 |
| --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h |
| +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h |
| @@ -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 |
| diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c |
| index bc30a5326866c..f13ed3c1e29c2 100644 |
| --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c |
| +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c |
| @@ -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 @@ static void vcn_v2_5_ring_begin_use(struct amdgpu_ring *ring) |
| 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) |
| -- |
| 2.51.0 |
| |