--- a/sys/dev/drm/amd/powerplay/smumgr/tonga_smumgr.c +++ b/sys/dev/drm/amd/powerplay/smumgr/tonga_smumgr.c @@ -703,10 +703,16 @@ uint8_t lowest_pcie_level_enabled = 0, mid_pcie_level_enabled = 0; uint8_t count = 0; int result = 0; + /* smc_state_table.GraphicsLevel[] is fixed at SMU72_MAX_LEVELS_GRAPHICS; + * the VBIOS-controlled sclk DPM count is only bounded by the u8 + * dependency-table entry count and must be clamped before indexing. + */ + uint32_t sclk_count = MIN(dpm_table->sclk_table.count, + SMU72_MAX_LEVELS_GRAPHICS); memset(levels, 0x00, level_array_size); - for (i = 0; i < dpm_table->sclk_table.count; i++) { + for (i = 0; i < sclk_count; i++) { result = tonga_populate_single_graphic_level(hwmgr, dpm_table->sclk_table.dpm_levels[i].value, &(smu_data->smc_state_table.GraphicsLevel[i])); @@ -722,12 +728,12 @@ smu_data->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1; /* set highest level watermark to high */ - if (dpm_table->sclk_table.count > 1) - smu_data->smc_state_table.GraphicsLevel[dpm_table->sclk_table.count-1].DisplayWatermark = + if (sclk_count > 1) + smu_data->smc_state_table.GraphicsLevel[sclk_count-1].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH; smu_data->smc_state_table.GraphicsDpmLevelCount = - (uint8_t)dpm_table->sclk_table.count; + (uint8_t)sclk_count; data->dpm_level_enable_mask.sclk_dpm_enable_mask = phm_get_dpm_level_enable_mask_value(&dpm_table->sclk_table); @@ -736,7 +742,7 @@ "There must be 1 or more PCIE levels defined in PPTable.", return -EINVAL); max_entry = pcie_entry_count - 1; /* for indexing, we need to decrement by 1.*/ - for (i = 0; i < dpm_table->sclk_table.count; i++) { + for (i = 0; i < sclk_count; i++) { smu_data->smc_state_table.GraphicsLevel[i].pcieDpmLevel = (uint8_t) ((i < max_entry) ? i : max_entry); } @@ -766,7 +772,7 @@ /* set pcieDpmLevel to highest_pcie_level_enabled*/ - for (i = 2; i < dpm_table->sclk_table.count; i++) + for (i = 2; i < sclk_count; i++) smu_data->smc_state_table.GraphicsLevel[i].pcieDpmLevel = highest_pcie_level_enabled; /* set pcieDpmLevel to lowest_pcie_level_enabled*/ @@ -1101,10 +1107,16 @@ SMU72_Discrete_MemoryLevel *levels = smu_data->smc_state_table.MemoryLevel; uint32_t i; + /* smc_state_table.MemoryLevel[] is fixed at SMU72_MAX_LEVELS_MEMORY (4); + * the VBIOS-controlled mclk DPM count is only bounded by the u8 + * dependency-table entry count and must be clamped before indexing. + */ + uint32_t mclk_count = MIN(dpm_table->mclk_table.count, + SMU72_MAX_LEVELS_MEMORY); memset(levels, 0x00, level_array_size); - for (i = 0; i < dpm_table->mclk_table.count; i++) { + for (i = 0; i < mclk_count; i++) { PP_ASSERT_WITH_CODE((0 != dpm_table->mclk_table.dpm_levels[i].value), "can not populate memory level as memory clock is zero", return -EINVAL); @@ -1127,10 +1139,11 @@ smu_data->smc_state_table.MemoryLevel[0].ActivityLevel = 0x1F; CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.MemoryLevel[0].ActivityLevel); - smu_data->smc_state_table.MemoryDpmLevelCount = (uint8_t)dpm_table->mclk_table.count; + smu_data->smc_state_table.MemoryDpmLevelCount = (uint8_t)mclk_count; data->dpm_level_enable_mask.mclk_dpm_enable_mask = phm_get_dpm_level_enable_mask_value(&dpm_table->mclk_table); /* set highest level watermark to high*/ - smu_data->smc_state_table.MemoryLevel[dpm_table->mclk_table.count-1].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH; + if (mclk_count > 0) + smu_data->smc_state_table.MemoryLevel[mclk_count-1].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH; /* level count will send to smc once at init smc table and never change*/ result = smu7_copy_bytes_to_smc(hwmgr,