⬢ DragonFlyBSD Kernel Audit
DF-4000 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/amd/powerplay/smumgr/iceland_smumgr.c
+++ b/sys/dev/drm/amd/powerplay/smumgr/iceland_smumgr.c
@@ -974,10 +974,16 @@
 	uint8_t lowest_pcie_level_enabled = 0, mid_pcie_level_enabled = 0;
 	uint8_t count = 0;
 	int result = 0;
+	uint32_t sclk_count;
 
 	memset(levels, 0x00, level_array_size);
 
-	for (i = 0; i < dpm_table->sclk_table.count; i++) {
+	/* The VBIOS-provided SCLK DPM count is unclamped upstream; the SMC
+	 * state table only has SMU71_MAX_LEVELS_GRAPHICS slots. */
+	sclk_count = min(dpm_table->sclk_table.count,
+			(uint32_t)SMU71_MAX_LEVELS_GRAPHICS);
+
+	for (i = 0; i < sclk_count; i++) {
 		result = iceland_populate_single_graphic_level(hwmgr,
 					dpm_table->sclk_table.dpm_levels[i].value,
 					&(smu_data->smc_state_table.GraphicsLevel[i]));
@@ -993,12 +999,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);
 
@@ -1023,7 +1029,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;
 	}
 
@@ -1355,10 +1361,16 @@
 	uint32_t level_array_size = sizeof(SMU71_Discrete_MemoryLevel) * SMU71_MAX_LEVELS_MEMORY;
 	SMU71_Discrete_MemoryLevel *levels = smu_data->smc_state_table.MemoryLevel;
 	uint32_t i;
+	uint32_t mclk_count;
 
 	memset(levels, 0x00, level_array_size);
 
-	for (i = 0; i < dpm_table->mclk_table.count; i++) {
+	/* The VBIOS-provided MCLK DPM count is unclamped upstream; the SMC
+	 * state table only has SMU71_MAX_LEVELS_MEMORY slots. */
+	mclk_count = min(dpm_table->mclk_table.count,
+			(uint32_t)SMU71_MAX_LEVELS_MEMORY);
+
+	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);
 		result = iceland_populate_single_memory_level(hwmgr, dpm_table->mclk_table.dpm_levels[i].value,
@@ -1379,10 +1391,10 @@
 	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;
+	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,
@@ -1618,8 +1630,10 @@
 
 	memset(&arb_regs, 0x00, sizeof(SMU71_Discrete_MCArbDramTimingTable));
 
-	for (i = 0; i < data->dpm_table.sclk_table.count; i++) {
-		for (j = 0; j < data->dpm_table.mclk_table.count; j++) {
+	for (i = 0; i < data->dpm_table.sclk_table.count &&
+			i < SMU71_MAX_LEVELS_GRAPHICS; i++) {
+		for (j = 0; j < data->dpm_table.mclk_table.count &&
+				j < SMU71_MAX_LEVELS_MEMORY; j++) {
 			result = iceland_populate_memory_timing_parameters
 				(hwmgr, data->dpm_table.sclk_table.dpm_levels[i].value,
 				 data->dpm_table.mclk_table.dpm_levels[j].value,
@@ -1758,7 +1772,8 @@
 	int res;
 	uint32_t i;
 
-	for (i = 0; i < data->dpm_table.mclk_table.count; i++) {
+	for (i = 0; i < data->dpm_table.mclk_table.count &&
+			i < SMU71_DISCRETE_MC_REGISTER_ARRAY_SET_COUNT; i++) {
 		res = iceland_convert_mc_reg_table_entry_to_smc(
 				hwmgr,
 				data->dpm_table.mclk_table.dpm_levels[i].value,
@@ -1795,7 +1810,9 @@
 
 	return  smu7_copy_bytes_to_smc(hwmgr, address,
 				 (uint8_t *)&smu_data->mc_regs.data[0],
-				sizeof(SMU71_Discrete_MCRegisterSet) * data->dpm_table.mclk_table.count,
+				sizeof(SMU71_Discrete_MCRegisterSet) *
+				min(data->dpm_table.mclk_table.count,
+					(uint32_t)SMU71_DISCRETE_MC_REGISTER_ARRAY_SET_COUNT),
 				SMC_RAM_END);
 }