[PATCH 16/24] serial: 8250_lpss: don't divide by 0 above 6.25 Mbaud
From: Greg Kroah-Hartman
Date: Tue Oct 27 2026 - 07:13:07 EST
From: Josef Bacik <josef@xxxxxxxxxxxxxx>
byt_set_termios() derives the clock of the UART from the baud rate in
the termios, which nobody has looked at yet:
fuart = baud * 16;
...
fuart *= rounddown_pow_of_two(fref / fuart);
...
p->uartclk = fuart;
fref is 100 MHz. For a baud rate above 6250000, which BOTHER allows,
fref / fuart is 0, and rounddown_pow_of_two(0) shifts 1UL by -1. On x86
that is 1UL << 63, the product with a multiple of 16 is 0, and so is
uartclk. serial8250_get_baud_rate() then passes 0 for both limits,
uart_get_baud_rate() finds no rate which fits, WARNs and returns 0, and
uart_get_divisor() or dw8250_get_divisor() divide by 16 * 0.
Everybody who may open the tty can oops the kernel with one TCSETS2.
Don't ask for more than fref. The limits are those of a 100 MHz clock
then, and uart_get_baud_rate() falls back to the old rate as for any
other rate that the port cannot do. 8250_mid, which has the same
formula, treats this case separately.
Fixes: 21947ba654a6 ("serial: 8250_pci: replace switch-case by formula")
Cc: stable <stable@xxxxxxxxxx>
Cc: "Ilpo Järvinen" <ilpo.jarvinen@xxxxxxxxxxxxxxx>
Cc: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx>
Cc: Jiri Slaby <jirislaby@xxxxxxxxxx>
Cc: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx>
Cc: Peter Hurley <peter@xxxxxxxxxxxxxxxxxx>
Signed-off-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
drivers/tty/serial/8250/8250_lpss.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c
index f1b4b975571a..7e88f2b793b5 100644
--- a/drivers/tty/serial/8250/8250_lpss.c
+++ b/drivers/tty/serial/8250/8250_lpss.c
@@ -83,6 +83,9 @@ static void byt_set_termios(struct uart_port *p, struct ktermios *termios,
/* Gracefully handle the B0 case: fall back to B9600 */
fuart = fuart ? fuart : 9600 * 16;
+ /* Fuart <= Fref: leave it to the core to refuse a higher baud rate */
+ fuart = min(fuart, fref);
+
/* Get Fuart closer to Fref */
fuart *= rounddown_pow_of_two(fref / fuart);
--
2.56.0