VCN 2.5 uses the PG callback to enable VCN DPM which is a global state. As such, we need to make sure all instances are in the same state. v2: switch to a ref count (Lijo) Fixes: 4ce4fe27205c ("drm/amdgpu/vcn: use per instance callbacks for idle work handler") Signed-off-by: Alex Deucher <alexander.deucher@xxxxxxx> --- drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h | 4 +++ drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c | 41 +++++++++++++++++++------ 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h index 26c9c2d90f455..3bc4fe4aeb481 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h @@ -358,6 +358,10 @@ struct amdgpu_vcn { bool per_inst_fw; unsigned fw_version; + /* VCN 2.5 global PG handling */ + struct mutex global_pg_lock; + unsigned int global_pg_count; + enum amd_powergating_state global_pg_state; }; 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 dff1a88590363..972f0842ea47b 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c @@ -172,6 +172,8 @@ static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block) uint32_t *ptr; struct amdgpu_device *adev = ip_block->adev; + mutex_init(&adev->vcn.global_pg_lock); + for (j = 0; j < adev->vcn.num_vcn_inst; j++) { volatile struct amdgpu_fw_shared *fw_shared; @@ -1853,21 +1855,42 @@ static int vcn_v2_5_set_pg_state(struct amdgpu_vcn_inst *vinst, enum amd_powergating_state state) { struct amdgpu_device *adev = vinst->adev; - int ret; + struct amdgpu_vcn_inst *v; + int ret = 0, i; if (amdgpu_sriov_vf(adev)) return 0; - if (state == vinst->cur_state) - return 0; + mutex_lock(&adev->vcn.global_pg_lock); + if (state == AMD_PG_STATE_GATE) { + if (adev->vcn.global_pg_count == 0) + goto unlock; + adev->vcn.global_pg_count--; + if (adev->vcn.global_pg_count == 0 && + adev->vcn.global_pg_state == AMD_PG_STATE_UNGATE) { + for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { + v = &adev->vcn.inst[i]; + + ret = vcn_v2_5_stop(v); + } + adev->vcn.global_pg_state = AMD_PG_STATE_GATE; + } + } else { + if (adev->vcn.global_pg_count == 0 && + adev->vcn.global_pg_state == AMD_PG_STATE_GATE) { + for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { + v = &adev->vcn.inst[i]; - if (state == AMD_PG_STATE_GATE) - ret = vcn_v2_5_stop(vinst); - else - ret = vcn_v2_5_start(vinst); + ret = vcn_v2_5_start(v); + } + adev->vcn.global_pg_state = AMD_PG_STATE_UNGATE; + } + adev->vcn.global_pg_count++; + } - if (!ret) - vinst->cur_state = state; +unlock: + vinst->cur_state = state; + mutex_unlock(&adev->vcn.global_pg_lock); return ret; } -- 2.48.1