]> git.baikalelectronics.ru Git - kernel.git/commit
ARM: 8517/1: ICST: avoid arithmetic overflow in icst_hz()
authorLinus Walleij <linus.walleij@linaro.org>
Mon, 8 Feb 2016 08:14:37 +0000 (09:14 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Mon, 8 Feb 2016 16:40:36 +0000 (16:40 +0000)
commit46ee94bd3a863f5820259b94c7fcd9a4e2d8a69d
tree71eda55c9a5647635fe8f01b5caec276877dff89
parent9fff6992d8229bd987885d85cc14b561f21dbd74
ARM: 8517/1: ICST: avoid arithmetic overflow in icst_hz()

When trying to set the ICST 307 clock to 25174000 Hz I ran into
this arithmetic error: the icst_hz_to_vco() correctly figure out
DIVIDE=2, RDW=100 and VDW=99 yielding a frequency of
25174000 Hz out of the VCO. (I replicated the icst_hz() function
in a spreadsheet to verify this.)

However, when I called icst_hz() on these VCO settings it would
instead return 4122709 Hz. This causes an error in the common
clock driver for ICST as the common clock framework will call
.round_rate() on the clock which will utilize icst_hz_to_vco()
followed by icst_hz() suggesting the erroneous frequency, and
then the clock gets set to this.

The error did not manifest in the old clock framework since
this high frequency was only used by the CLCD, which calls
clk_set_rate() without first calling clk_round_rate() and since
the old clock framework would not call clk_round_rate() before
setting the frequency, the correct values propagated into
the VCO.

After some experimenting I figured out that it was due to a simple
arithmetic overflow: the divisor for 24Mhz reference frequency
as reference becomes 24000000*2*(99+8)=0x132212400 and the "1"
in bit 32 overflows and is lost.

But introducing an explicit 64-by-32 bit do_div() and casting
the divisor into (u64) we get the right frequency back, and the
right frequency gets set.

Tested on the ARM Versatile.

Cc: stable@vger.kernel.org
Cc: linux-clk@vger.kernel.org
Cc: Pawel Moll <pawel.moll@arm.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/common/icst.c