diff --git a/sys/dev/drm/amd/amdgpu/amdgpu_pll.c b/sys/dev/drm/amd/amdgpu/amdgpu_pll.c index 1111111..2222222 100644 --- a/sys/dev/drm/amd/amdgpu/amdgpu_pll.c +++ b/sys/dev/drm/amd/amdgpu/amdgpu_pll.c @@ -48,11 +48,19 @@ static void amdgpu_pll_reduce_ratio(unsigned *nom, unsigned *den, unsigned tmp; /* reduce the numbers to a simpler ratio */ tmp = gcd(*nom, *den); + if (tmp == 0) /* gcd(0,0) == 0 -> would divide by zero */ + tmp = 1; *nom /= tmp; *den /= tmp; + /* degenerate inputs (fb_div/ref_div/reference_freq under-ran to 0): + * keep the ratio well-defined instead of dividing by zero below */ + if (*nom == 0) + *nom = 1; + if (*den == 0) + *den = 1; /* make sure nominator is large enough */ if (*nom < nom_min) { @@ -85,9 +93,14 @@ static void amdgpu_pll_get_fb_ref_div(unsigned nom, unsigned den, unsigned post_d unsigned *fb_div, unsigned *ref_div) { + if (post_div == 0) /* defense in depth (DF-2037 family) */ + post_div = 1; + /* limit reference * post divider to a maximum */ - ref_div_max = min(128 / post_div, ref_div_max); + /* post_div > 128 (e.g. firmware-supplied AMDGPU_PLL_USE_POST_DIV value + * of 129..255) drives this to 0 and forces ref_div = 0 -> 0/0 */ + ref_div_max = max(min(128 / post_div, ref_div_max), 1u); /* get matching reference and feedback divider */ *ref_div = min(max(DIV_ROUND_CLOSEST(den, post_div), 1u), ref_div_max);