Commit 58893392 authored by Lijo Lazar's avatar Lijo Lazar Committed by Alex Deucher
Browse files

drm/amd/pm: Revert state if force level fails



Before forcing level, CG/PG is disabled or enabled depending on the new
level. However if the force level operation fails, CG/PG state remains
modified. Revert the state change on failure. Also, move invalid
operation checks to the beginning before any logic that could change SOC
state.

Signed-off-by: default avatarLijo Lazar <lijo.lazar@amd.com>
Reviewed-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 178ad3a9
Loading
Loading
Loading
Loading
+35 −23
Original line number Diff line number Diff line
@@ -987,6 +987,24 @@ enum amd_dpm_forced_level amdgpu_dpm_get_performance_level(struct amdgpu_device
	return level;
}

static void amdgpu_dpm_enter_umd_state(struct amdgpu_device *adev)
{
	/* enter UMD Pstate */
	amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_GFX,
					       AMD_PG_STATE_UNGATE);
	amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_GFX,
					       AMD_CG_STATE_UNGATE);
}

static void amdgpu_dpm_exit_umd_state(struct amdgpu_device *adev)
{
	/* exit UMD Pstate */
	amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_GFX,
					       AMD_CG_STATE_GATE);
	amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_GFX,
					       AMD_PG_STATE_GATE);
}

int amdgpu_dpm_force_performance_level(struct amdgpu_device *adev,
				       enum amd_dpm_forced_level level)
{
@@ -1007,6 +1025,10 @@ int amdgpu_dpm_force_performance_level(struct amdgpu_device *adev,
	if (current_level == level)
		return 0;

	if (!(current_level & profile_mode_mask) &&
	    (level == AMD_DPM_FORCED_LEVEL_PROFILE_EXIT))
		return -EINVAL;

	if (adev->asic_type == CHIP_RAVEN) {
		if (!(adev->apu_flags & AMD_APU_IS_RAVEN2)) {
			if (current_level != AMD_DPM_FORCED_LEVEL_MANUAL &&
@@ -1018,35 +1040,25 @@ int amdgpu_dpm_force_performance_level(struct amdgpu_device *adev,
		}
	}

	if (!(current_level & profile_mode_mask) &&
	    (level == AMD_DPM_FORCED_LEVEL_PROFILE_EXIT))
		return -EINVAL;

	if (!(current_level & profile_mode_mask) &&
	      (level & profile_mode_mask)) {
		/* enter UMD Pstate */
		amdgpu_device_ip_set_powergating_state(adev,
						       AMD_IP_BLOCK_TYPE_GFX,
						       AMD_PG_STATE_UNGATE);
		amdgpu_device_ip_set_clockgating_state(adev,
						       AMD_IP_BLOCK_TYPE_GFX,
						       AMD_CG_STATE_UNGATE);
	} else if ((current_level & profile_mode_mask) &&
		    !(level & profile_mode_mask)) {
		/* exit UMD Pstate */
		amdgpu_device_ip_set_clockgating_state(adev,
						       AMD_IP_BLOCK_TYPE_GFX,
						       AMD_CG_STATE_GATE);
		amdgpu_device_ip_set_powergating_state(adev,
						       AMD_IP_BLOCK_TYPE_GFX,
						       AMD_PG_STATE_GATE);
	}
	if (!(current_level & profile_mode_mask) && (level & profile_mode_mask))
		amdgpu_dpm_enter_umd_state(adev);
	else if ((current_level & profile_mode_mask) &&
		 !(level & profile_mode_mask))
		amdgpu_dpm_exit_umd_state(adev);

	mutex_lock(&adev->pm.mutex);

	if (pp_funcs->force_performance_level(adev->powerplay.pp_handle,
					      level)) {
		mutex_unlock(&adev->pm.mutex);
		/* If new level failed, retain the umd state as before */
		if (!(current_level & profile_mode_mask) &&
		    (level & profile_mode_mask))
			amdgpu_dpm_exit_umd_state(adev);
		else if ((current_level & profile_mode_mask) &&
			 !(level & profile_mode_mask))
			amdgpu_dpm_enter_umd_state(adev);

		return -EINVAL;
	}