| From 084f49bc429917e209346c9ee99b2b8926c65dfc Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 19 May 2023 08:33:27 -0700 |
| Subject: drm/radeon: fix possible division-by-zero errors |
| |
| From: Nikita Zhandarovich <n.zhandarovich@fintech.ru> |
| |
| [ Upstream commit 1becc57cd1a905e2aa0e1eca60d2a37744525c4a ] |
| |
| Function rv740_get_decoded_reference_divider() may return 0 due to |
| unpredictable reference divider value calculated in |
| radeon_atom_get_clock_dividers(). This will lead to |
| division-by-zero error once that value is used as a divider |
| in calculating 'clk_s'. |
| While unlikely, this issue should nonetheless be prevented so add a |
| sanity check for such cases by testing 'decoded_ref' value against 0. |
| |
| Found by Linux Verification Center (linuxtesting.org) with static |
| analysis tool SVACE. |
| |
| v2: minor coding style fixes (Alex) |
| In practice this should actually happen as the vbios should be |
| properly populated. |
| |
| Fixes: 66229b200598 ("drm/radeon/kms: add dpm support for rv7xx (v4)") |
| Signed-off-by: Nikita Zhandarovich <n.zhandarovich@fintech.ru> |
| Signed-off-by: Alex Deucher <alexander.deucher@amd.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/gpu/drm/radeon/cypress_dpm.c | 8 ++++++-- |
| drivers/gpu/drm/radeon/ni_dpm.c | 8 ++++++-- |
| drivers/gpu/drm/radeon/rv740_dpm.c | 8 ++++++-- |
| 3 files changed, 18 insertions(+), 6 deletions(-) |
| |
| diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c |
| index fdddbbaecbb74..72a0768df00f7 100644 |
| --- a/drivers/gpu/drm/radeon/cypress_dpm.c |
| +++ b/drivers/gpu/drm/radeon/cypress_dpm.c |
| @@ -557,8 +557,12 @@ static int cypress_populate_mclk_value(struct radeon_device *rdev, |
| ASIC_INTERNAL_MEMORY_SS, vco_freq)) { |
| u32 reference_clock = rdev->clock.mpll.reference_freq; |
| u32 decoded_ref = rv740_get_decoded_reference_divider(dividers.ref_div); |
| - u32 clk_s = reference_clock * 5 / (decoded_ref * ss.rate); |
| - u32 clk_v = ss.percentage * |
| + u32 clk_s, clk_v; |
| + |
| + if (!decoded_ref) |
| + return -EINVAL; |
| + clk_s = reference_clock * 5 / (decoded_ref * ss.rate); |
| + clk_v = ss.percentage * |
| (0x4000 * dividers.whole_fb_div + 0x800 * dividers.frac_fb_div) / (clk_s * 625); |
| |
| mpll_ss1 &= ~CLKV_MASK; |
| diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c |
| index 672d2239293e0..3e1c1a392fb7b 100644 |
| --- a/drivers/gpu/drm/radeon/ni_dpm.c |
| +++ b/drivers/gpu/drm/radeon/ni_dpm.c |
| @@ -2241,8 +2241,12 @@ static int ni_populate_mclk_value(struct radeon_device *rdev, |
| ASIC_INTERNAL_MEMORY_SS, vco_freq)) { |
| u32 reference_clock = rdev->clock.mpll.reference_freq; |
| u32 decoded_ref = rv740_get_decoded_reference_divider(dividers.ref_div); |
| - u32 clk_s = reference_clock * 5 / (decoded_ref * ss.rate); |
| - u32 clk_v = ss.percentage * |
| + u32 clk_s, clk_v; |
| + |
| + if (!decoded_ref) |
| + return -EINVAL; |
| + clk_s = reference_clock * 5 / (decoded_ref * ss.rate); |
| + clk_v = ss.percentage * |
| (0x4000 * dividers.whole_fb_div + 0x800 * dividers.frac_fb_div) / (clk_s * 625); |
| |
| mpll_ss1 &= ~CLKV_MASK; |
| diff --git a/drivers/gpu/drm/radeon/rv740_dpm.c b/drivers/gpu/drm/radeon/rv740_dpm.c |
| index d57a3e1df8d63..4464fd21a3029 100644 |
| --- a/drivers/gpu/drm/radeon/rv740_dpm.c |
| +++ b/drivers/gpu/drm/radeon/rv740_dpm.c |
| @@ -249,8 +249,12 @@ int rv740_populate_mclk_value(struct radeon_device *rdev, |
| ASIC_INTERNAL_MEMORY_SS, vco_freq)) { |
| u32 reference_clock = rdev->clock.mpll.reference_freq; |
| u32 decoded_ref = rv740_get_decoded_reference_divider(dividers.ref_div); |
| - u32 clk_s = reference_clock * 5 / (decoded_ref * ss.rate); |
| - u32 clk_v = 0x40000 * ss.percentage * |
| + u32 clk_s, clk_v; |
| + |
| + if (!decoded_ref) |
| + return -EINVAL; |
| + clk_s = reference_clock * 5 / (decoded_ref * ss.rate); |
| + clk_v = 0x40000 * ss.percentage * |
| (dividers.whole_fb_div + (dividers.frac_fb_div / 8)) / (clk_s * 10000); |
| |
| mpll_ss1 &= ~CLKV_MASK; |
| -- |
| 2.39.2 |
| |