Commit 50ceb1fe authored by Kenneth Feng's avatar Kenneth Feng Committed by Alex Deucher
Browse files

drm/amd/pm: bug fix for pcie dpm



Currently the pcie dpm has two problems.
1. Only the high dpm level speed/width can be overrided
if the requested values are out of the pcie capability.
2. The high dpm level is always overrided though sometimes
it's not necesarry.

Signed-off-by: default avatarKenneth Feng <kenneth.feng@amd.com>
Reviewed-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
parent 521f04f9
Loading
Loading
Loading
Loading
+48 −0
Original line number Diff line number Diff line
@@ -1505,6 +1505,48 @@ static int vega10_populate_single_lclk_level(struct pp_hwmgr *hwmgr,
	return 0;
}

static int vega10_override_pcie_parameters(struct pp_hwmgr *hwmgr)
{
	struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
	struct vega10_hwmgr *data =
			(struct vega10_hwmgr *)(hwmgr->backend);
	uint32_t pcie_gen = 0, pcie_width = 0;
	PPTable_t *pp_table = &(data->smc_state_table.pp_table);
	int i;

	if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4)
		pcie_gen = 3;
	else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
		pcie_gen = 2;
	else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
		pcie_gen = 1;
	else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1)
		pcie_gen = 0;

	if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X16)
		pcie_width = 6;
	else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X12)
		pcie_width = 5;
	else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X8)
		pcie_width = 4;
	else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X4)
		pcie_width = 3;
	else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X2)
		pcie_width = 2;
	else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X1)
		pcie_width = 1;

	for (i = 0; i < NUM_LINK_LEVELS; i++) {
		if (pp_table->PcieGenSpeed[i] > pcie_gen)
			pp_table->PcieGenSpeed[i] = pcie_gen;

		if (pp_table->PcieLaneCount[i] > pcie_width)
			pp_table->PcieLaneCount[i] = pcie_width;
	}

	return 0;
}

static int vega10_populate_smc_link_levels(struct pp_hwmgr *hwmgr)
{
	int result = -1;
@@ -2556,6 +2598,11 @@ static int vega10_init_smc_table(struct pp_hwmgr *hwmgr)
			"Failed to initialize Link Level!",
			return result);

	result = vega10_override_pcie_parameters(hwmgr);
	PP_ASSERT_WITH_CODE(!result,
			"Failed to override pcie parameters!",
			return result);

	result = vega10_populate_all_graphic_levels(hwmgr);
	PP_ASSERT_WITH_CODE(!result,
			"Failed to initialize Graphics Level!",
@@ -2922,6 +2969,7 @@ static int vega10_start_dpm(struct pp_hwmgr *hwmgr, uint32_t bitmap)
	return 0;
}


static int vega10_enable_disable_PCC_limit_feature(struct pp_hwmgr *hwmgr, bool enable)
{
	struct vega10_hwmgr *data = hwmgr->backend;
+66 −0
Original line number Diff line number Diff line
@@ -481,6 +481,67 @@ static void vega12_init_dpm_state(struct vega12_dpm_state *dpm_state)
	dpm_state->hard_max_level = 0xffff;
}

static int vega12_override_pcie_parameters(struct pp_hwmgr *hwmgr)
{
	struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
	struct vega12_hwmgr *data =
			(struct vega12_hwmgr *)(hwmgr->backend);
	uint32_t pcie_gen = 0, pcie_width = 0, smu_pcie_arg, pcie_gen_arg, pcie_width_arg;
	PPTable_t *pp_table = &(data->smc_state_table.pp_table);
	int i;
	int ret;

	if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4)
		pcie_gen = 3;
	else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
		pcie_gen = 2;
	else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
		pcie_gen = 1;
	else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1)
		pcie_gen = 0;

	if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X16)
		pcie_width = 6;
	else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X12)
		pcie_width = 5;
	else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X8)
		pcie_width = 4;
	else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X4)
		pcie_width = 3;
	else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X2)
		pcie_width = 2;
	else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X1)
		pcie_width = 1;

	/* Bit 31:16: LCLK DPM level. 0 is DPM0, and 1 is DPM1
	 * Bit 15:8:  PCIE GEN, 0 to 3 corresponds to GEN1 to GEN4
	 * Bit 7:0:   PCIE lane width, 1 to 7 corresponds is x1 to x32
	 */
	for (i = 0; i < NUM_LINK_LEVELS; i++) {
		pcie_gen_arg = (pp_table->PcieGenSpeed[i] > pcie_gen) ? pcie_gen :
			pp_table->PcieGenSpeed[i];
		pcie_width_arg = (pp_table->PcieLaneCount[i] > pcie_width) ? pcie_width :
			pp_table->PcieLaneCount[i];

		if (pcie_gen_arg != pp_table->PcieGenSpeed[i] || pcie_width_arg !=
		    pp_table->PcieLaneCount[i]) {
			smu_pcie_arg = (i << 16) | (pcie_gen_arg << 8) | pcie_width_arg;
			ret = smum_send_msg_to_smc_with_parameter(hwmgr,
				PPSMC_MSG_OverridePcieParameters, smu_pcie_arg,
				NULL);
			PP_ASSERT_WITH_CODE(!ret,
				"[OverridePcieParameters] Attempt to override pcie params failed!",
				return ret);
		}

		/* update the pptable */
		pp_table->PcieGenSpeed[i] = pcie_gen_arg;
		pp_table->PcieLaneCount[i] = pcie_width_arg;
	}

	return 0;
}

static int vega12_get_number_of_dpm_level(struct pp_hwmgr *hwmgr,
		PPCLK_e clk_id, uint32_t *num_of_levels)
{
@@ -968,6 +1029,11 @@ static int vega12_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
			"Failed to enable all smu features!",
			return result);

	result = vega12_override_pcie_parameters(hwmgr);
	PP_ASSERT_WITH_CODE(!result,
			"[EnableDPMTasks] Failed to override pcie parameters!",
			return result);

	tmp_result = vega12_power_control_set_level(hwmgr);
	PP_ASSERT_WITH_CODE(!tmp_result,
			"Failed to power control set level!",
+27 −21
Original line number Diff line number Diff line
@@ -831,7 +831,9 @@ static int vega20_override_pcie_parameters(struct pp_hwmgr *hwmgr)
	struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
	struct vega20_hwmgr *data =
			(struct vega20_hwmgr *)(hwmgr->backend);
	uint32_t pcie_gen = 0, pcie_width = 0, smu_pcie_arg;
	uint32_t pcie_gen = 0, pcie_width = 0, smu_pcie_arg, pcie_gen_arg, pcie_width_arg;
	PPTable_t *pp_table = &(data->smc_state_table.pp_table);
	int i;
	int ret;

	if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4)
@@ -860,17 +862,27 @@ static int vega20_override_pcie_parameters(struct pp_hwmgr *hwmgr)
	 * Bit 15:8:  PCIE GEN, 0 to 3 corresponds to GEN1 to GEN4
	 * Bit 7:0:   PCIE lane width, 1 to 7 corresponds is x1 to x32
	 */
	smu_pcie_arg = (1 << 16) | (pcie_gen << 8) | pcie_width;
	for (i = 0; i < NUM_LINK_LEVELS; i++) {
		pcie_gen_arg = (pp_table->PcieGenSpeed[i] > pcie_gen) ? pcie_gen :
			pp_table->PcieGenSpeed[i];
		pcie_width_arg = (pp_table->PcieLaneCount[i] > pcie_width) ? pcie_width :
			pp_table->PcieLaneCount[i];

		if (pcie_gen_arg != pp_table->PcieGenSpeed[i] || pcie_width_arg !=
		    pp_table->PcieLaneCount[i]) {
			smu_pcie_arg = (i << 16) | (pcie_gen_arg << 8) | pcie_width_arg;
			ret = smum_send_msg_to_smc_with_parameter(hwmgr,
				PPSMC_MSG_OverridePcieParameters, smu_pcie_arg,
				NULL);
			PP_ASSERT_WITH_CODE(!ret,
				"[OverridePcieParameters] Attempt to override pcie params failed!",
				return ret);
		}

	data->pcie_parameters_override = true;
	data->pcie_gen_level1 = pcie_gen;
	data->pcie_width_level1 = pcie_width;
		/* update the pptable */
		pp_table->PcieGenSpeed[i] = pcie_gen_arg;
		pp_table->PcieLaneCount[i] = pcie_width_arg;
	}

	return 0;
}
@@ -3319,9 +3331,7 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
			data->od8_settings.od8_settings_array;
	OverDriveTable_t *od_table =
			&(data->smc_state_table.overdrive_table);
	struct phm_ppt_v3_information *pptable_information =
		(struct phm_ppt_v3_information *)hwmgr->pptable;
	PPTable_t *pptable = (PPTable_t *)pptable_information->smc_pptable;
	PPTable_t *pptable = &(data->smc_state_table.pp_table);
	struct pp_clock_levels_with_latency clocks;
	struct vega20_single_dpm_table *fclk_dpm_table =
			&(data->dpm_table.fclk_table);
@@ -3420,13 +3430,9 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
		current_lane_width =
			vega20_get_current_pcie_link_width_level(hwmgr);
		for (i = 0; i < NUM_LINK_LEVELS; i++) {
			if (i == 1 && data->pcie_parameters_override) {
				gen_speed = data->pcie_gen_level1;
				lane_width = data->pcie_width_level1;
			} else {
			gen_speed = pptable->PcieGenSpeed[i];
			lane_width = pptable->PcieLaneCount[i];
			}

			size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i,
					(gen_speed == 0) ? "2.5GT/s," :
					(gen_speed == 1) ? "5.0GT/s," :