⬢ DragonFlyBSD Kernel Audit
DF-3878 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/amd/amdgpu/dce_v8_0.c
+++ b/sys/dev/drm/amd/amdgpu/dce_v8_0.c
@@ -813,19 +813,31 @@ static u32 dce_v8_0_latency_watermark(st
 {
 	/* First calculate the latency in ns */
 	u32 mc_latency = 2000; /* 2000 ns. */
-	u32 available_bandwidth = dce_v8_0_available_bandwidth(wm);
-	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 */
-	u32 other_heads_data_return_time = ((wm->num_heads + 1) * worst_chunk_return_time) +
-		(wm->num_heads * cursor_line_pair_return_time);
-	u32 latency = mc_latency + other_heads_data_return_time + dc_latency;
+	u32 available_bandwidth, worst_chunk_return_time;
+	u32 cursor_line_pair_return_time, dc_latency;
+	u32 other_heads_data_return_time;
+	u32 latency;
 	u32 max_src_lines_per_dst_line, lb_fill_bw, line_fill_time;
 	u32 tmp, dmif_size = 12288;
 	fixed20_12 a, b, c;
 
+	/* DF-3878: the divides below used to execute before this guard and
+	 * took #DE when the clock terms collapsed to 0 (unguarded VBIOS
+	 * default clocks with DPM disabled). Validate every divisor first. */
 	if (wm->num_heads == 0)
 		return 0;
+	if (wm->disp_clk == 0)
+		return 0;
+	available_bandwidth = dce_v8_0_available_bandwidth(wm);
+	if (available_bandwidth == 0)
+		return 0;
+
+	worst_chunk_return_time = (512 * 8 * 1000) / available_bandwidth;
+	cursor_line_pair_return_time = (128 * 4 * 1000) / available_bandwidth;
+	dc_latency = 40000000 / wm->disp_clk; /* dc pipe latency */
+	other_heads_data_return_time = ((wm->num_heads + 1) * worst_chunk_return_time) +
+		(wm->num_heads * cursor_line_pair_return_time);
+	latency = mc_latency + other_heads_data_return_time + dc_latency;
 
 	a.full = dfixed_const(2);
 	b.full = dfixed_const(1);
--- a/sys/dev/drm/amd/amdgpu/amdgpu_atombios.c
+++ b/sys/dev/drm/amd/amdgpu/amdgpu_atombios.c
@@ -679,6 +679,15 @@ int amdgpu_atombios_get_clock_info(struc
 		adev->clock.default_mclk =
 		    le32_to_cpu(firmware_info->info.ulDefaultMemoryClock);
 
+		/* DF-3878: zero VBIOS default clocks flow into the DCE
+		 * watermark math (pm.current_sclk/current_mclk below) and
+		 * divide by zero on the first mode set. Clamp like the
+		 * neighboring clock fields above. */
+		if (adev->clock.default_sclk == 0)
+			adev->clock.default_sclk = 20000;	/* 200 MHz */
+		if (adev->clock.default_mclk == 0)
+			adev->clock.default_mclk = 20000;	/* 200 MHz */
+
 		mpll->min_post_div = 1;
 		mpll->max_post_div = 1;
 		mpll->min_ref_div = 2;