⬢ DragonFlyBSD Kernel Audit
DF-3665 / fix.diff
← back to finding ↓ download raw
fix.diff — DF-3665: guard the divide-by-zero in evergreen_latency_watermark() (evergreen.c:2048-2050)

available_bandwidth is min(dram, data_return, dmif) fixed-point products and is zero when:
  (a) a DRM-master user mode has pixel clock <= ~38 kHz (drm_mode_validate_basic()
      only rejects clock == 0; radeon has no mode_valid hook),
  (b) mclk/sclk land in the u32 fixed20_12 dfixed_const() wrap windows (e.g.
      exactly 524288/1048576/1572864 kHz), or
  (c) VBIOS reports zero clocks.
In all three cases evergreen.c:2048/2049 divides by zero -> #DE -> kernel panic.

Minimal fix: return the same 'no latency' value the function already returns for
num_heads == 0.  Also guards wm->disp_clk for the 40000000/wm->disp_clk division.

Validated with 'git apply --check' against this tree. NOT applied (sys/ is a
read-only audit target).

--- a/sys/dev/drm/radeon/evergreen.c
+++ b/sys/dev/drm/radeon/evergreen.c
@@ -2045,6 +2045,12 @@
 	/* First calcualte the latency in ns */
 	u32 mc_latency = 2000; /* 2000 ns. */
 	u32 available_bandwidth = evergreen_available_bandwidth(wm);
+
+	/* avoid a divide-by-zero (#DE panic) when the bandwidth math
+	 * truncates to zero (tiny mode clocks, u32 fixed-point wrap of
+	 * mclk/sclk, or missing clock info) */
+	if (!available_bandwidth || !wm->disp_clk)
+		return 0;
 	u32 worst_chunk_return_time = (512 * 8 * 1000) / available_bandwidth;
 	u32 cursor_line_pair_return_time = (128 * 4 * 1000) / available_bandwidth;
 	u32 dc_latency = 40000000 / wm->disp_clk; /* dc pipe latency */