DF-3878 / fix.diff
--- 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; |