Commit de01e6cd authored by Geert Uytterhoeven's avatar Geert Uytterhoeven

serial: sh-sci: Avoid overflow in sci_baud_calc_hscif()

If bps >= 1048576, the multiplication of the predivider and "bps" will
overflow, and both br and err will contain bogus values.
Skip the current and all higher clock select predividers when overflow
is detected.  Simplify the calculations using intermediates while we're
at it.
Signed-off-by: default avatarGeert Uytterhoeven <geert+renesas@glider.be>
Acked-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 95a2703e
...@@ -1870,7 +1870,7 @@ static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps, ...@@ -1870,7 +1870,7 @@ static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq, int *brr, static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq, int *brr,
unsigned int *srr, unsigned int *cks) unsigned int *srr, unsigned int *cks)
{ {
unsigned int sr, br, c; unsigned int sr, br, prediv, scrate, c;
int err, recv_margin; int err, recv_margin;
int min_err = 1000; /* 100% */ int min_err = 1000; /* 100% */
int recv_max_margin = 0; int recv_max_margin = 0;
...@@ -1880,12 +1880,25 @@ static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq, int *brr, ...@@ -1880,12 +1880,25 @@ static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq, int *brr,
for (sr = 8; sr <= 32; sr++) { for (sr = 8; sr <= 32; sr++) {
for (c = 0; c <= 3; c++) { for (c = 0; c <= 3; c++) {
/* integerized formulas from HSCIF documentation */ /* integerized formulas from HSCIF documentation */
br = DIV_ROUND_CLOSEST(freq, (sr * prediv = sr * (1 << (2 * c + 1));
(1 << (2 * c + 1)) * bps));
/*
* We need to calculate:
*
* br = freq / (prediv * bps) clamped to [1..256]
* err = (freq / (br * prediv * bps / 1000)) - 1000
*
* Watch out for overflow when calculating the desired
* sampling clock rate!
*/
if (bps > UINT_MAX / prediv)
break;
scrate = prediv * bps;
br = DIV_ROUND_CLOSEST(freq, scrate);
br = clamp(br, 1U, 256U); br = clamp(br, 1U, 256U);
err = DIV_ROUND_CLOSEST(freq, (br * bps * sr * err = DIV_ROUND_CLOSEST(freq, (br * scrate) / 1000) -
(1 << (2 * c + 1)) / 1000)) - 1000;
1000;
/* Calc recv margin /* Calc recv margin
* M: Receive margin (%) * M: Receive margin (%)
* N: Ratio of bit rate to clock (N = sampling rate) * N: Ratio of bit rate to clock (N = sampling rate)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment