This patch adds a function which will change the GPU power profile based on a submitted job. This can optimize the power performance when the workload is on. v2: - Splitting workload_profile_set and workload_profile_put into two separate patches. - Addressed review comment. v3: - Adressed all the review comment. - Changing the function name from *_set() to *_get(). - Now setting a power profile when refcount is zero. Cc: Shashank Sharma <shashank.sharma@xxxxxxx> Cc: Christian Koenig <christian.koenig@xxxxxxx> Cc: Alex Deucher <alexander.deucher@xxxxxxx> Signed-off-by: Arvind Yadav <Arvind.Yadav@xxxxxxx> --- drivers/gpu/drm/amd/amdgpu/amdgpu_workload.c | 59 +++++++++++++++++++ drivers/gpu/drm/amd/include/amdgpu_workload.h | 3 + 2 files changed, 62 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_workload.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_workload.c index 32166f482f77..67eacaac6c9b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_workload.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_workload.c @@ -24,6 +24,65 @@ #include "amdgpu.h" +static enum PP_SMC_POWER_PROFILE +ring_to_power_profile(uint32_t ring_type) +{ + switch (ring_type) { + case AMDGPU_RING_TYPE_GFX: + return PP_SMC_POWER_PROFILE_FULLSCREEN3D; + case AMDGPU_RING_TYPE_COMPUTE: + return PP_SMC_POWER_PROFILE_COMPUTE; + case AMDGPU_RING_TYPE_UVD: + case AMDGPU_RING_TYPE_VCE: + case AMDGPU_RING_TYPE_UVD_ENC: + case AMDGPU_RING_TYPE_VCN_DEC: + case AMDGPU_RING_TYPE_VCN_ENC: + case AMDGPU_RING_TYPE_VCN_JPEG: + return PP_SMC_POWER_PROFILE_VIDEO; + default: + return PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; + } +} + +static int +amdgpu_power_profile_set(struct amdgpu_device *adev, + enum PP_SMC_POWER_PROFILE profile) +{ + int ret = amdgpu_dpm_switch_power_profile(adev, profile, true); + + if (!ret) { + /* Set the bit for the submitted workload profile */ + set_bit(profile, &adev->smu_workload.submit_workload_status); + } + + return ret; +} + +void amdgpu_workload_profile_get(struct amdgpu_device *adev, + uint32_t ring_type) +{ + struct amdgpu_smu_workload *workload = &adev->smu_workload; + enum PP_SMC_POWER_PROFILE profile = ring_to_power_profile(ring_type); + int ret, refcount; + + if (profile == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT) + return; + + mutex_lock(&workload->workload_lock); + + refcount = atomic_read(&workload->power_profile_ref[profile]); + if (!refcount) { + ret = amdgpu_power_profile_set(adev, profile); + if (ret) { + DRM_WARN("Failed to set workload profile to %s, error = %d\n", + amdgpu_workload_mode_name[profile], ret); + } + } + + atomic_inc(&adev->smu_workload.power_profile_ref[profile]); + mutex_unlock(&workload->workload_lock); +} + void amdgpu_workload_profile_init(struct amdgpu_device *adev) { adev->smu_workload.adev = adev; diff --git a/drivers/gpu/drm/amd/include/amdgpu_workload.h b/drivers/gpu/drm/amd/include/amdgpu_workload.h index dc12448764a3..5fc0bc2a74a4 100644 --- a/drivers/gpu/drm/amd/include/amdgpu_workload.h +++ b/drivers/gpu/drm/amd/include/amdgpu_workload.h @@ -46,6 +46,9 @@ static const char * const amdgpu_workload_mode_name[] = { "Window3D" }; +void amdgpu_workload_profile_get(struct amdgpu_device *adev, + uint32_t ring_type); + void amdgpu_workload_profile_init(struct amdgpu_device *adev); void amdgpu_workload_profile_fini(struct amdgpu_device *adev); -- 2.34.1