drm/amdgpu: Avoid overflows/divide-by-zero in latency_watermark calculations.
authorMario Kleiner <mario.kleiner.de@gmail.com>
Wed, 29 Mar 2017 20:09:12 +0000 (22:09 +0200)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 7 Apr 2017 16:20:42 +0000 (12:20 -0400)
At dot clocks > approx. 250 Mhz, some of these calcs will overflow and
cause miscalculation of latency watermarks, and for some overflows also
divide-by-zero driver crash ("divide error: 0000 [#1] PREEMPT SMP" in
"dce_v10_0_latency_watermark+0x12d/0x190").

This zero-divide happened, e.g., on AMD Tonga Pro under DCE-10,
on a Displayport panel when trying to set a video mode of 2560x1440
at 165 Hz vrefresh with a dot clock of 635.540 Mhz.

Refine calculations to avoid the overflows.

Tested for DCE-10 with R9 380 Tonga + ASUS ROG PG279 panel.

Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
drivers/gpu/drm/amd/amdgpu/dce_v8_0.c

index 67e7d8ee1aab29f2214e6a3dcc62151a368bd6ba..2b78d58c9c35fa819a41676a68936e27bedd9f5c 100644 (file)
@@ -1090,23 +1090,10 @@ static u32 dce_v10_0_latency_watermark(struct dce10_wm_params *wm)
        a.full = dfixed_const(available_bandwidth);
        b.full = dfixed_const(wm->num_heads);
        a.full = dfixed_div(a, b);
+       tmp = div_u64((u64) dmif_size * (u64) wm->disp_clk, mc_latency + 512);
+       tmp = min(dfixed_trunc(a), tmp);
 
-       b.full = dfixed_const(mc_latency + 512);
-       c.full = dfixed_const(wm->disp_clk);
-       b.full = dfixed_div(b, c);
-
-       c.full = dfixed_const(dmif_size);
-       b.full = dfixed_div(c, b);
-
-       tmp = min(dfixed_trunc(a), dfixed_trunc(b));
-
-       b.full = dfixed_const(1000);
-       c.full = dfixed_const(wm->disp_clk);
-       b.full = dfixed_div(c, b);
-       c.full = dfixed_const(wm->bytes_per_pixel);
-       b.full = dfixed_mul(b, c);
-
-       lb_fill_bw = min(tmp, dfixed_trunc(b));
+       lb_fill_bw = min(tmp, wm->disp_clk * wm->bytes_per_pixel / 1000);
 
        a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
        b.full = dfixed_const(1000);
index 7a91afba019861acd8b119c5f1a99569b00041d0..fec2a69f3ae248a35677285501675cbf20f40aba 100644 (file)
@@ -1059,23 +1059,10 @@ static u32 dce_v11_0_latency_watermark(struct dce10_wm_params *wm)
        a.full = dfixed_const(available_bandwidth);
        b.full = dfixed_const(wm->num_heads);
        a.full = dfixed_div(a, b);
+       tmp = div_u64((u64) dmif_size * (u64) wm->disp_clk, mc_latency + 512);
+       tmp = min(dfixed_trunc(a), tmp);
 
-       b.full = dfixed_const(mc_latency + 512);
-       c.full = dfixed_const(wm->disp_clk);
-       b.full = dfixed_div(b, c);
-
-       c.full = dfixed_const(dmif_size);
-       b.full = dfixed_div(c, b);
-
-       tmp = min(dfixed_trunc(a), dfixed_trunc(b));
-
-       b.full = dfixed_const(1000);
-       c.full = dfixed_const(wm->disp_clk);
-       b.full = dfixed_div(c, b);
-       c.full = dfixed_const(wm->bytes_per_pixel);
-       b.full = dfixed_mul(b, c);
-
-       lb_fill_bw = min(tmp, dfixed_trunc(b));
+       lb_fill_bw = min(tmp, wm->disp_clk * wm->bytes_per_pixel / 1000);
 
        a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
        b.full = dfixed_const(1000);
index b20cc07eea6446ff31eaf031554db037b24cb579..6604bcf783b7d234ad91f414eaa337f519089ae1 100644 (file)
@@ -861,23 +861,10 @@ static u32 dce_v6_0_latency_watermark(struct dce6_wm_params *wm)
        a.full = dfixed_const(available_bandwidth);
        b.full = dfixed_const(wm->num_heads);
        a.full = dfixed_div(a, b);
+       tmp = div_u64((u64) dmif_size * (u64) wm->disp_clk, mc_latency + 512);
+       tmp = min(dfixed_trunc(a), tmp);
 
-       b.full = dfixed_const(mc_latency + 512);
-       c.full = dfixed_const(wm->disp_clk);
-       b.full = dfixed_div(b, c);
-
-       c.full = dfixed_const(dmif_size);
-       b.full = dfixed_div(c, b);
-
-       tmp = min(dfixed_trunc(a), dfixed_trunc(b));
-
-       b.full = dfixed_const(1000);
-       c.full = dfixed_const(wm->disp_clk);
-       b.full = dfixed_div(c, b);
-       c.full = dfixed_const(wm->bytes_per_pixel);
-       b.full = dfixed_mul(b, c);
-
-       lb_fill_bw = min(tmp, dfixed_trunc(b));
+       lb_fill_bw = min(tmp, wm->disp_clk * wm->bytes_per_pixel / 1000);
 
        a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
        b.full = dfixed_const(1000);
index b420051e9da463722e2f266b85b856a01ad8de2b..e10c82f7a37a44169eb86450eb9c71722dad4829 100644 (file)
@@ -974,23 +974,10 @@ static u32 dce_v8_0_latency_watermark(struct dce8_wm_params *wm)
        a.full = dfixed_const(available_bandwidth);
        b.full = dfixed_const(wm->num_heads);
        a.full = dfixed_div(a, b);
+       tmp = div_u64((u64) dmif_size * (u64) wm->disp_clk, mc_latency + 512);
+       tmp = min(dfixed_trunc(a), tmp);
 
-       b.full = dfixed_const(mc_latency + 512);
-       c.full = dfixed_const(wm->disp_clk);
-       b.full = dfixed_div(b, c);
-
-       c.full = dfixed_const(dmif_size);
-       b.full = dfixed_div(c, b);
-
-       tmp = min(dfixed_trunc(a), dfixed_trunc(b));
-
-       b.full = dfixed_const(1000);
-       c.full = dfixed_const(wm->disp_clk);
-       b.full = dfixed_div(c, b);
-       c.full = dfixed_const(wm->bytes_per_pixel);
-       b.full = dfixed_mul(b, c);
-
-       lb_fill_bw = min(tmp, dfixed_trunc(b));
+       lb_fill_bw = min(tmp, wm->disp_clk * wm->bytes_per_pixel / 1000);
 
        a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
        b.full = dfixed_const(1000);