DF-4120 / fix.diff
Fix for DF-4120: second divide-by-zero window in cypress_populate_mclk_value (clk_s == 0 at cypress_dpm.c:566-567; sibling of DF-1387). DF-1387 (known, lines 553-565) covers ss.rate == 0 making clk_s = reference_clock * 5 / (decoded_ref * ss.rate) (:565) divide by zero. A SECOND, different window exists one expression later even when ss.rate != 0: clk_s = reference_clock * 5 / (decoded_ref * ss.rate); (:565) clk_v = ss.percentage * (0x4000 * dividers.whole_fb_div + 0x800 * dividers.frac_fb_div) / (clk_s * 625); (:566-567) Integer division truncates: whenever decoded_ref * ss.rate > reference_clock * 5, clk_s becomes 0 and the division at :567 is a divide-by-zero (#DE -> kernel panic). All three inputs are VBIOS-controlled: ss.rate is a raw u16 (usSpreadRateInKhz, radeon_atombios.c:1546, max 65535), decoded_ref comes from rv740_get_decoded_reference_divider() over the computed ref divider (values 1..~15), and reference_clock = rdev->clock.mpll.reference_freq (commonly 10000 in 10 kHz units; 2700 on 27 MHz-reference boards). E.g. reference_freq=2700, decoded_ref=2, ss.rate=6751+ kHz, or reference_freq=10000, decoded_ref=2, ss.rate=25001+ kHz => panic at DPM enable / every power-state change on the affected mclk level. Physically implausible spread rates for real SS silicon, trivially craftable in a VBIOS image — same acceptance basis as DF-1387 ("no zero check upstream"). Fix: bail out when clk_s truncates to zero (keeps the DF-1387 guard for the zero divisor at :565 as a separate, already-known fix). --- a/sys/dev/drm/radeon/cypress_dpm.c +++ b/sys/dev/drm/radeon/cypress_dpm.c @@ -562,6 +562,10 @@ static int cypress_populate_mclk_value(struct radeon_device *rdev, if (!decoded_ref) return -EINVAL; clk_s = reference_clock * 5 / (decoded_ref * ss.rate); + if (clk_s == 0) { + /* DF-4120: divisor would be zero at clk_v */ + return -EINVAL; + } clk_v = ss.percentage * (0x4000 * dividers.whole_fb_div + 0x800 * dividers.frac_fb_div) / (clk_s * 625); |