⬢ DragonFlyBSD Kernel Audit
DF-3909 / fix.diff
← back to finding ↓ download raw
--- 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,