DragonFlyBSD Kernel Audit
DF-1204 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/radeon/radeon_atombios.c b/sys/dev/drm/radeon/radeon_atombios.c
--- a/sys/dev/drm/radeon/radeon_atombios.c
+++ b/sys/dev/drm/radeon/radeon_atombios.c
@@ -1563,10 +1563,21 @@
 					ss->type = ss_assign->v2.ucSpreadSpectrumMode;
 					ss->rate = le16_to_cpu(ss_assign->v2.usSpreadRateIn10Hz);
 					ss->percentage_divider = 100;
+					/*
+					 * The table is misnamed: rate is in
+					 * 100 Hz units here, so divide by 100.
+					 * A malformed VBIOS reporting <100
+					 * truncates to 0 and triggers a #DE
+					 * in ni_calculate_sclk_params() /
+					 * ni_populate_mclk_value() (DF-1204).
+					 */
 					if ((crev == 2) &&
 					    ((id == ASIC_INTERNAL_ENGINE_SS) ||
-					     (id == ASIC_INTERNAL_MEMORY_SS)))
+					     (id == ASIC_INTERNAL_MEMORY_SS))) {
+						if (ss->rate < 100)
+							return false;
 						ss->rate /= 100;
+					}
 					return true;
 				}
 				ss_assign = (union asic_ss_assignment *)
@@ -1589,9 +1600,16 @@
 						ss->percentage_divider = 1000;
 					else
 						ss->percentage_divider = 100;
+					/*
+					 * Same divide-by-100 hazard as the v2
+					 * case above (DF-1204).
+					 */
 					if ((id == ASIC_INTERNAL_ENGINE_SS) ||
-					    (id == ASIC_INTERNAL_MEMORY_SS))
+					    (id == ASIC_INTERNAL_MEMORY_SS)) {
+						if (ss->rate < 100)
+							return false;
 						ss->rate /= 100;
+					}
 					if (rdev->flags & RADEON_IS_IGP)
 						radeon_atombios_get_igp_ss_overrides(rdev, ss, id);
 					return true;