Skip to content

Commit 551e553

Browse files
fancergregkh
authored andcommitted
serial: 8250_mtk: Fix high-speed baud rates clamping
Commit 7b668c0 ("serial: 8250: Fix max baud limit in generic 8250 port") fixed limits of a baud rate setting for a generic 8250 port. In other words since that commit the baud rate has been permitted to be within [uartclk / 16 / UART_DIV_MAX; uartclk / 16], which is absolutely normal for a standard 8250 UART port. But there are custom 8250 ports, which provide extended baud rate limits. In particular the Mediatek 8250 port can work with baud rates up to "uartclk" speed. Normally that and any other peculiarity is supposed to be handled in a custom set_termios() callback implemented in the vendor-specific 8250-port glue-driver. Currently that is how it's done for the most of the vendor-specific 8250 ports, but for some reason for Mediatek a solution has been spread out to both the glue-driver and to the generic 8250-port code. Due to that a bug has been introduced, which permitted the extended baud rate limit for all even for standard 8250-ports. The bug has been fixed by the commit 7b668c0 ("serial: 8250: Fix max baud limit in generic 8250 port") by narrowing the baud rates limit back down to the normal bounds. Unfortunately by doing so we also broke the Mediatek-specific extended bauds feature. A fix of the problem described above is twofold. First since we can't get back the extended baud rate limits feature to the generic set_termios() function and that method supports only a standard baud rates range, the requested baud rate must be locally stored before calling it and then restored back to the new termios structure after the generic set_termios() finished its magic business. By doing so we still use the serial8250_do_set_termios() method to set the LCR/MCR/FCR/etc. registers, while the extended baud rate setting procedure will be performed later in the custom Mediatek-specific set_termios() callback. Second since a true baud rate is now fully calculated in the custom set_termios() method we need to locally update the port timeout by calling the uart_update_timeout() function. After the fixes described above are implemented in the 8250_mtk.c driver, the Mediatek 8250-port should get back to normally working with extended baud rates. Link: https://lore.kernel.org/linux-serial/[email protected] Fixes: 7b668c0 ("serial: 8250: Fix max baud limit in generic 8250 port") Reported-by: Daniel Winkler <[email protected]> Signed-off-by: Serge Semin <[email protected]> Cc: stable <[email protected]> Tested-by: Claire Chang <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent f4c23a1 commit 551e553

File tree

1 file changed

+18
-0
lines changed

1 file changed

+18
-0
lines changed

drivers/tty/serial/8250/8250_mtk.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,21 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
306306
}
307307
#endif
308308

309+
/*
310+
* Store the requested baud rate before calling the generic 8250
311+
* set_termios method. Standard 8250 port expects bauds to be
312+
* no higher than (uartclk / 16) so the baud will be clamped if it
313+
* gets out of that bound. Mediatek 8250 port supports speed
314+
* higher than that, therefore we'll get original baud rate back
315+
* after calling the generic set_termios method and recalculate
316+
* the speed later in this method.
317+
*/
318+
baud = tty_termios_baud_rate(termios);
319+
309320
serial8250_do_set_termios(port, termios, old);
310321

322+
tty_termios_encode_baud_rate(termios, baud, baud);
323+
311324
/*
312325
* Mediatek UARTs use an extra highspeed register (MTK_UART_HIGHS)
313326
*
@@ -339,6 +352,11 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
339352
*/
340353
spin_lock_irqsave(&port->lock, flags);
341354

355+
/*
356+
* Update the per-port timeout.
357+
*/
358+
uart_update_timeout(port, termios->c_cflag, baud);
359+
342360
/* set DLAB we have cval saved in up->lcr from the call to the core */
343361
serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB);
344362
serial_dl_write(up, quot);

0 commit comments

Comments
 (0)