From: Johan Hovold johan@kernel.org
stable inclusion from stable-v5.10.145 commit 107c6b60582c99820916b19183b5c855e2d60434 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I6D0VF
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
commit d02b006b29de14968ba4afa998bede0d55469e29 upstream.
This reverts commit 32262e2e429cdb31f9e957e997d53458762931b7.
The commit in question claims to determine the inverse of serial8250_get_divisor() but failed to notice that some drivers override the default implementation using a get_divisor() callback.
This means that the computed line-speed values can be completely wrong and results in regular TCSETS requests failing (the incorrect values would also be passed to any overridden set_divisor() callback).
Similarly, it also failed to honour the old (deprecated) ASYNC_SPD_FLAGS and would break applications relying on those when re-encoding the actual line speed.
There are also at least two quirks, UART_BUG_QUOT and an OMAP1510 workaround, which were happily ignored and that are now broken.
Finally, even if the offending commit were to be implemented correctly, this is a new feature and not something which should be backported to stable.
Cc: Pali Rohár pali@kernel.org Fixes: 32262e2e429c ("serial: 8250: Fix reporting real baudrate value in c_ospeed field") Cc: stable stable@vger.kernel.org Signed-off-by: Johan Hovold johan@kernel.org Link: https://lore.kernel.org/r/20211007133146.28949-1-johan@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Jialin Zhang zhangjialin11@huawei.com Reviewed-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/tty/serial/8250/8250_port.c | 17 ----------------- 1 file changed, 17 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index eaf4eb33a78d..9d60418e4adb 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2547,19 +2547,6 @@ static unsigned int serial8250_get_divisor(struct uart_port *port, return serial8250_do_get_divisor(port, baud, frac); }
-static unsigned int serial8250_compute_baud_rate(struct uart_port *port, - unsigned int quot) -{ - if ((port->flags & UPF_MAGIC_MULTIPLIER) && quot == 0x8001) - return port->uartclk / 4; - else if ((port->flags & UPF_MAGIC_MULTIPLIER) && quot == 0x8002) - return port->uartclk / 8; - else if (port->type == PORT_NPCM) - return DIV_ROUND_CLOSEST(port->uartclk - 2 * (quot + 2), 16 * (quot + 2)); - else - return DIV_ROUND_CLOSEST(port->uartclk, 16 * quot); -} - static unsigned char serial8250_compute_lcr(struct uart_8250_port *up, tcflag_t c_cflag) { @@ -2701,14 +2688,11 @@ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk)
baud = serial8250_get_baud_rate(port, termios, NULL); quot = serial8250_get_divisor(port, baud, &frac); - baud = serial8250_compute_baud_rate(port, quot);
serial8250_rpm_get(up); spin_lock_irqsave(&port->lock, flags);
uart_update_timeout(port, termios->c_cflag, baud); - if (tty_termios_baud_rate(termios)) - tty_termios_encode_baud_rate(termios, baud, baud);
serial8250_set_divisor(port, baud, quot, frac); serial_port_out(port, UART_LCR, up->lcr); @@ -2742,7 +2726,6 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
baud = serial8250_get_baud_rate(port, termios, old); quot = serial8250_get_divisor(port, baud, &frac); - baud = serial8250_compute_baud_rate(port, quot);
/* * Ok, we're now changing the port state. Do it with