On Thu, May 07, 2020 at 02:31:32AM +0300, Serge Semin wrote: > Standard 8250 UART ports are designed in a way so they can communicate > with baud rates up to 1/16 of a reference frequency. It's expected from > most of the currently supported UART controllers. That's why the former > version of serial8250_get_baud_rate() method called uart_get_baud_rate() > with min and max baud rates passed as (port->uartclk / 16 / UART_DIV_MAX) > and ((port->uartclk + tolerance) / 16) respectively. Doing otherwise, like > it was suggested in commit ("serial: 8250_mtk: support big baud rate."), > caused acceptance of bauds, which was higher than the normal UART > controllers actually supported. As a result if some user-space program > requested to set a baud greater than (uartclk / 16) it would have been > permitted without truncation, but then serial8250_get_divisor(baud) > (which calls uart_get_divisor() to get the reference clock divisor) would > have returned a zero divisor. Setting zero divisor will cause an > unpredictable effect varying from chip to chip. In case of DW APB UART the > communications just stop. > > Lets fix this problem by getting back the limitation of (uartclk + > tolerance) / 16 maximum baud supported by the generic 8250 port. Mediatek > 8250 UART ports driver developer shouldn't have touched it in the first > place notably seeing he already provided a custom version of set_termios() > callback in that glue-driver which took into account the extended baud > rate values and accordingly updated the standard and vendor-specific > divisor latch registers anyway. Some of the hardware support PS != 16 (8250_mid), but for now it lies to UART core for real UART clock because of its (core) hard cored assumption PS == 16 here and there. Reviewed-by: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx> > > Fixes: 81bb549fdf14 ("serial: 8250_mtk: support big baud rate.") > Signed-off-by: Serge Semin <Sergey.Semin@xxxxxxxxxxxxxxxxxxxx> > Cc: Alexey Malahov <Alexey.Malahov@xxxxxxxxxxxxxxxxxxxx> > Cc: Thomas Bogendoerfer <tsbogend@xxxxxxxxxxxxxxxx> > Cc: Paul Burton <paulburton@xxxxxxxxxx> > Cc: Ralf Baechle <ralf@xxxxxxxxxxxxxx> > Cc: Arnd Bergmann <arnd@xxxxxxxx> > Cc: Long Cheng <long.cheng@xxxxxxxxxxxx> > Cc: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx> > Cc: Maxime Ripard <mripard@xxxxxxxxxx> > Cc: Catalin Marinas <catalin.marinas@xxxxxxx> > Cc: Will Deacon <will@xxxxxxxxxx> > Cc: Russell King <linux@xxxxxxxxxxxxxxx> > Cc: linux-mips@xxxxxxxxxxxxxxx > Cc: linux-arm-kernel@xxxxxxxxxxxxxxxxxxx > Cc: linux-mediatek@xxxxxxxxxxxxxxxxxxx > --- > drivers/tty/serial/8250/8250_port.c | 4 +++- > 1 file changed, 3 insertions(+), 1 deletion(-) > > diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c > index f77bf820b7a3..4d83c85a7389 100644 > --- a/drivers/tty/serial/8250/8250_port.c > +++ b/drivers/tty/serial/8250/8250_port.c > @@ -2615,6 +2615,8 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, > struct ktermios *termios, > struct ktermios *old) > { > + unsigned int tolerance = port->uartclk / 100; > + > /* > * Ask the core to calculate the divisor for us. > * Allow 1% tolerance at the upper limit so uart clks marginally > @@ -2623,7 +2625,7 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, > */ > return uart_get_baud_rate(port, termios, old, > port->uartclk / 16 / UART_DIV_MAX, > - port->uartclk); > + (port->uartclk + tolerance) / 16); > } > > void > -- > 2.25.1 > -- With Best Regards, Andy Shevchenko