From: Colin Xu Date: Fri, 16 Apr 2021 08:33:55 +0000 (+0800) Subject: drm/i915/gvt: Prevent divided by zero when calculating refresh rate X-Git-Tag: v5.13-rc1~2^2~2^2^2 X-Git-Url: https://git.kernel.dk/?a=commitdiff_plain;h=d385c16173f28a18866abf54c764200c276dace0;p=linux-block.git drm/i915/gvt: Prevent divided by zero when calculating refresh rate To get refresh rate as vblank timer period and keep the precision, the calculation of rate is multiplied by 1000. However old logic was using: rate = pixel clock / (h * v / 1000). When the h/v total is invalid, like all 0, h * v / 1000 will be rounded to 0, which leads to a divided by 0 fault. 0 H/V are already checked above. Instead of divide after divide, refine the calculation to divide after multiply: "pixel clock * 1000 / (h * v)" Guest driver should guarantee the correctness of the timing regs' value. Fixes: 6a4500c7b83f ("drm/i915/gvt: Get accurate vGPU virtual display refresh rate from vreg") Reported-by: Zhenyu Wang Signed-off-by: Colin Xu Signed-off-by: Zhenyu Wang Link: http://patchwork.freedesktop.org/patch/msgid/20210416083355.159305-1-colin.xu@intel.com Reviewed-by: Zhenyu Wang --- diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index 477badfcb258..dda320749c65 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -669,8 +669,8 @@ static void vgpu_update_refresh_rate(struct intel_vgpu *vgpu) link_n = vgpu_vreg_t(vgpu, PIPE_LINK_N1(TRANSCODER_A)); /* Get H/V total from transcoder timing */ - htotal = (vgpu_vreg_t(vgpu, HTOTAL(TRANSCODER_A)) >> TRANS_HTOTAL_SHIFT) + 1; - vtotal = (vgpu_vreg_t(vgpu, VTOTAL(TRANSCODER_A)) >> TRANS_VTOTAL_SHIFT) + 1; + htotal = (vgpu_vreg_t(vgpu, HTOTAL(TRANSCODER_A)) >> TRANS_HTOTAL_SHIFT); + vtotal = (vgpu_vreg_t(vgpu, VTOTAL(TRANSCODER_A)) >> TRANS_VTOTAL_SHIFT); if (dp_br && link_n && htotal && vtotal) { u64 pixel_clk = 0; @@ -682,7 +682,7 @@ static void vgpu_update_refresh_rate(struct intel_vgpu *vgpu) pixel_clk *= MSEC_PER_SEC; /* Calcuate refresh rate by (pixel_clk / (h_total * v_total)) */ - new_rate = DIV64_U64_ROUND_CLOSEST(pixel_clk, div64_u64(mul_u32_u32(htotal, vtotal), MSEC_PER_SEC)); + new_rate = DIV64_U64_ROUND_CLOSEST(mul_u64_u32_shr(pixel_clk, MSEC_PER_SEC, 0), mul_u32_u32(htotal + 1, vtotal + 1)); if (*old_rate != new_rate) *old_rate = new_rate;