summary refs log tree commit diff
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@orcam.me.uk>2021-06-10 20:38:39 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-06-16 09:20:29 +0200
commitf7adc73878187be895e8790033cea1fb59ffbc16 (patch)
tree065c439d9ce2780b2e34ff16645789f913233407
parent78bcae8616ac277d6cb7f38e211493948ed73e30 (diff)
downloadlinux-f7adc73878187be895e8790033cea1fb59ffbc16.tar.gz
serial: 8250: Handle custom baud rates in UPF_MAGIC_MULTIPLIER range
Handle custom baud rates requested in the UPF_MAGIC_MULTIPLIER range
with BOTHER.  Currently matching is exact, that is if a baud rate that
is not either of clk/4 or clk/8 is requested, then we fall through to
the default case, which will just divide the clock rate by 16 times the
rate requested, round it to closest integer, and possibly yield even
worse results then if clamping to the extra baud rates was chosen.

So for example if we have the usual base rate of 115200 and request a
rate of 230399, then the fall-through divisor calculation will yield 1,
and consequently the baud rate of 115200 will be programmed even though
obviously the magic rate of 230400 would be more appropriate.

Make the selection of the magic rates range-qualified then and use clk/4
for rates from clk/6 up (assuming `serial8250_get_baud_rate' has already
rejected any rates too far beyond clk/4), and otherwise use clk/8 for
rates from clk/12 up, and finally fall through to the standard divisor
calculation.  Explicitly void using the undocumented rate of 153600bps
and stick to documented divisor values only.

Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Link: https://lore.kernel.org/r/alpine.DEB.2.21.2105200232090.29169@angie.orcam.me.uk
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/serial/8250/8250_port.c7
1 files changed, 3 insertions, 4 deletions
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 2cec419cd3cd..2164290cbd31 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -2512,6 +2512,7 @@ static unsigned int serial8250_do_get_divisor(struct uart_port *port,
 					      unsigned int baud,
 					      unsigned int *frac)
 {
+	upf_t magic_multiplier = port->flags & UPF_MAGIC_MULTIPLIER;
 	struct uart_8250_port *up = up_to_u8250p(port);
 	unsigned int quot;
 
@@ -2547,11 +2548,9 @@ static unsigned int serial8250_do_get_divisor(struct uart_port *port,
 	 * Baud Rate Generator is capable of dividing the internal PLL
 	 * clock by any divisor from 1 to 65535.
 	 */
-	if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
-	    baud == (port->uartclk/4))
+	if (magic_multiplier && baud >= port->uartclk / 6)
 		quot = 0x8001;
-	else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
-		 baud == (port->uartclk/8))
+	else if (magic_multiplier && baud >= port->uartclk / 12)
 		quot = 0x8002;
 	else if (up->port.type == PORT_NPCM)
 		quot = npcm_get_divisor(up, baud);