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

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
...@@ -1505,6 +1505,48 @@ static int vega10_populate_single_lclk_level(struct pp_hwmgr *hwmgr, ...@@ -1505,6 +1505,48 @@ static int vega10_populate_single_lclk_level(struct pp_hwmgr *hwmgr,
return 0; 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) static int vega10_populate_smc_link_levels(struct pp_hwmgr *hwmgr)
{ {
int result = -1; int result = -1;
...@@ -2556,6 +2598,11 @@ static int vega10_init_smc_table(struct pp_hwmgr *hwmgr) ...@@ -2556,6 +2598,11 @@ static int vega10_init_smc_table(struct pp_hwmgr *hwmgr)
"Failed to initialize Link Level!", "Failed to initialize Link Level!",
return result); 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); result = vega10_populate_all_graphic_levels(hwmgr);
PP_ASSERT_WITH_CODE(!result, PP_ASSERT_WITH_CODE(!result,
"Failed to initialize Graphics Level!", "Failed to initialize Graphics Level!",
...@@ -2922,6 +2969,7 @@ static int vega10_start_dpm(struct pp_hwmgr *hwmgr, uint32_t bitmap) ...@@ -2922,6 +2969,7 @@ static int vega10_start_dpm(struct pp_hwmgr *hwmgr, uint32_t bitmap)
return 0; return 0;
} }
static int vega10_enable_disable_PCC_limit_feature(struct pp_hwmgr *hwmgr, bool enable) static int vega10_enable_disable_PCC_limit_feature(struct pp_hwmgr *hwmgr, bool enable)
{ {
struct vega10_hwmgr *data = hwmgr->backend; struct vega10_hwmgr *data = hwmgr->backend;
......
...@@ -481,6 +481,67 @@ static void vega12_init_dpm_state(struct vega12_dpm_state *dpm_state) ...@@ -481,6 +481,67 @@ static void vega12_init_dpm_state(struct vega12_dpm_state *dpm_state)
dpm_state->hard_max_level = 0xffff; 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, static int vega12_get_number_of_dpm_level(struct pp_hwmgr *hwmgr,
PPCLK_e clk_id, uint32_t *num_of_levels) PPCLK_e clk_id, uint32_t *num_of_levels)
{ {
...@@ -968,6 +1029,11 @@ static int vega12_enable_dpm_tasks(struct pp_hwmgr *hwmgr) ...@@ -968,6 +1029,11 @@ static int vega12_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
"Failed to enable all smu features!", "Failed to enable all smu features!",
return result); 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); tmp_result = vega12_power_control_set_level(hwmgr);
PP_ASSERT_WITH_CODE(!tmp_result, PP_ASSERT_WITH_CODE(!tmp_result,
"Failed to power control set level!", "Failed to power control set level!",
......
...@@ -831,7 +831,9 @@ static int vega20_override_pcie_parameters(struct pp_hwmgr *hwmgr) ...@@ -831,7 +831,9 @@ static int vega20_override_pcie_parameters(struct pp_hwmgr *hwmgr)
struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev); struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
struct vega20_hwmgr *data = struct vega20_hwmgr *data =
(struct vega20_hwmgr *)(hwmgr->backend); (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; int ret;
if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4) 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) ...@@ -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 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 * 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++) {
ret = smum_send_msg_to_smc_with_parameter(hwmgr, pcie_gen_arg = (pp_table->PcieGenSpeed[i] > pcie_gen) ? pcie_gen :
PPSMC_MSG_OverridePcieParameters, smu_pcie_arg, pp_table->PcieGenSpeed[i];
NULL); pcie_width_arg = (pp_table->PcieLaneCount[i] > pcie_width) ? pcie_width :
PP_ASSERT_WITH_CODE(!ret, pp_table->PcieLaneCount[i];
"[OverridePcieParameters] Attempt to override pcie params failed!",
return ret); 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; /* update the pptable */
data->pcie_gen_level1 = pcie_gen; pp_table->PcieGenSpeed[i] = pcie_gen_arg;
data->pcie_width_level1 = pcie_width; pp_table->PcieLaneCount[i] = pcie_width_arg;
}
return 0; return 0;
} }
...@@ -3319,9 +3331,7 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, ...@@ -3319,9 +3331,7 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
data->od8_settings.od8_settings_array; data->od8_settings.od8_settings_array;
OverDriveTable_t *od_table = OverDriveTable_t *od_table =
&(data->smc_state_table.overdrive_table); &(data->smc_state_table.overdrive_table);
struct phm_ppt_v3_information *pptable_information = PPTable_t *pptable = &(data->smc_state_table.pp_table);
(struct phm_ppt_v3_information *)hwmgr->pptable;
PPTable_t *pptable = (PPTable_t *)pptable_information->smc_pptable;
struct pp_clock_levels_with_latency clocks; struct pp_clock_levels_with_latency clocks;
struct vega20_single_dpm_table *fclk_dpm_table = struct vega20_single_dpm_table *fclk_dpm_table =
&(data->dpm_table.fclk_table); &(data->dpm_table.fclk_table);
...@@ -3420,13 +3430,9 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, ...@@ -3420,13 +3430,9 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
current_lane_width = current_lane_width =
vega20_get_current_pcie_link_width_level(hwmgr); vega20_get_current_pcie_link_width_level(hwmgr);
for (i = 0; i < NUM_LINK_LEVELS; i++) { for (i = 0; i < NUM_LINK_LEVELS; i++) {
if (i == 1 && data->pcie_parameters_override) { gen_speed = pptable->PcieGenSpeed[i];
gen_speed = data->pcie_gen_level1; lane_width = pptable->PcieLaneCount[i];
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, size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i,
(gen_speed == 0) ? "2.5GT/s," : (gen_speed == 0) ? "2.5GT/s," :
(gen_speed == 1) ? "5.0GT/s," : (gen_speed == 1) ? "5.0GT/s," :
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment