Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 262db3ff authored by Nikita Zhandarovich's avatar Nikita Zhandarovich Committed by Greg Kroah-Hartman
Browse files

drm/radeon: fix possible division-by-zero errors



[ 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: 66229b20 ("drm/radeon/kms: add dpm support for rv7xx (v4)")
Signed-off-by: default avatarNikita Zhandarovich <n.zhandarovich@fintech.ru>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent cacc0506
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -559,8 +559,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;
+6 −2
Original line number Diff line number Diff line
@@ -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;
+6 −2
Original line number Diff line number Diff line
@@ -250,8 +250,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;