On Tue, Aug 19, 2025 at 5:28 AM Lijo Lazar <[email protected]> wrote: > > 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. > > Signed-off-by: Lijo Lazar <[email protected]>
Reviewed-by: Alex Deucher <[email protected]> > --- > drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | 85 ++++++++++++++++--------- > drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h | 3 + > drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c | 27 +------- > 3 files changed, 61 insertions(+), 54 deletions(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c > b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c > index 9a76e11d1c18..f3eb64edf6d2 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c > @@ -410,6 +410,59 @@ 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); > + > + return; > +} > + > +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); > + > + return; > +} > + > static void amdgpu_vcn_idle_work_handler(struct work_struct *work) > { > struct amdgpu_vcn_inst *vcn_inst = > @@ -417,7 +470,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 +498,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 +509,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 +541,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 b3fb1d0e43fc..6d9acd36041d 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 3a7c137a83ef..904b94bc8693 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.49.0 >
