Message ID | 20220712115306.26471-2-kabel@kernel.org |
---|---|
State | New |
Headers | show |
Series | ftdi_sio driver improvements | expand |
On Tue, Jul 12, 2022 at 01:53:00PM +0200, Marek Behún wrote: > From: Pali Rohár <pali@kernel.org> > > The baud rate generating divisor is a 17-bit wide (14 bits integer part > and 3 bits fractional part). > > Example: > base clock = 48 MHz > requested baud rate = 180 Baud > divisor = 48,000,000 / (16 * 180) = 0b100000100011010.101 > > In this case the MSB gets discarded because of the overflow, and the > actually used divisor will be 0b100011010.101 = 282.625, resulting > in baud rate 10615 Baud, instead of the requested 180 Baud. > > The best possible thing to do in this case is to generate lowest possible > baud rate (in the example it would be 183 Baud), by using maximum possible > divisor. Actually, the best way to handle this is to add a sanity check for the lowest supported check as you do in the next patch. That one makes this change superfluous. > In case of divisor overflow, use maximum possible divisor. Johan
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index b440d338a895..ea40f367e70c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1157,6 +1157,8 @@ static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base) int divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud); if ((divisor3 & 0x7) == 7) divisor3++; /* round x.7/8 up to x+1 */ + if (divisor3 > GENMASK(16, 0)) + divisor3 = GENMASK(16, 0); divisor = divisor3 >> 3; divisor3 &= 0x7; if (divisor3 == 1) @@ -1181,6 +1183,8 @@ static u32 ftdi_232bm_baud_base_to_divisor(int baud, int base) u32 divisor; /* divisor shifted 3 bits to the left */ int divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud); + if (divisor3 > GENMASK(16, 0)) + divisor3 = GENMASK(16, 0); divisor = divisor3 >> 3; divisor |= (u32)divfrac[divisor3 & 0x7] << 14; /* Deal with special cases for highest baud rates. */ @@ -1204,6 +1208,8 @@ static u32 ftdi_2232h_baud_base_to_divisor(int baud, int base) /* hi-speed baud rate is 10-bit sampling instead of 16-bit */ divisor3 = DIV_ROUND_CLOSEST(8 * base, 10 * baud); + if (divisor3 > GENMASK(16, 0)) + divisor3 = GENMASK(16, 0); divisor = divisor3 >> 3; divisor |= (u32)divfrac[divisor3 & 0x7] << 14;