TTY/Serial fixes for 6.8-rc8 (or -final)

Here are some small remaining tty/serial driver fixes for 6.8-rc8.
 Included in here is fixes for:
   - vt unicode buffer corruption fix
   - imx serial driver fixes, again
   - port suspend fix
   - 8250_dw driver fix
   - fsl_lpuart driver fix
   - revert for the qcom_geni_serial driver to fix a reported regression
 
 All of these have been in linux-next with no reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZetKOg8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ylrgACg1Ro50Xu8pgExHSDbTwoPPybjJrcAoJtpv3/f
 EN3V+fWc4o0+RVT9JNnM
 =iG2L
 -----END PGP SIGNATURE-----

Merge tag 'tty-6.8-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty / serial fixes from Greg KH:
 "Here are some small remaining tty/serial driver fixes. Included in
  here is fixes for:

   - vt unicode buffer corruption fix

   - imx serial driver fixes, again

   - port suspend fix

   - 8250_dw driver fix

   - fsl_lpuart driver fix

   - revert for the qcom_geni_serial driver to fix a reported regression

  All of these have been in linux-next with no reported issues"

* tag 'tty-6.8-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  Revert "tty: serial: simplify qcom_geni_serial_send_chunk_fifo()"
  tty: serial: fsl_lpuart: avoid idle preamble pending if CTS is enabled
  vt: fix unicode buffer corruption when deleting characters
  serial: port: Don't suspend if the port is still busy
  serial: 8250_dw: Do not reclock if already at correct rate
  tty: serial: imx: Fix broken RS485
This commit is contained in:
Linus Torvalds 2024-03-08 13:33:04 -08:00
commit 563c5b02f2
6 changed files with 57 additions and 15 deletions

View file

@ -357,9 +357,9 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
long rate;
int ret;
clk_disable_unprepare(d->clk);
rate = clk_round_rate(d->clk, newrate);
if (rate > 0) {
if (rate > 0 && p->uartclk != rate) {
clk_disable_unprepare(d->clk);
/*
* Note that any clock-notifer worker will block in
* serial8250_update_uartclk() until we are done.
@ -367,8 +367,8 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
ret = clk_set_rate(d->clk, newrate);
if (!ret)
p->uartclk = rate;
clk_prepare_enable(d->clk);
}
clk_prepare_enable(d->clk);
dw8250_do_set_termios(p, termios, old);
}

View file

@ -2345,9 +2345,12 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
lpuart32_write(&sport->port, bd, UARTBAUD);
lpuart32_serial_setbrg(sport, baud);
lpuart32_write(&sport->port, modem, UARTMODIR);
lpuart32_write(&sport->port, ctrl, UARTCTRL);
/* disable CTS before enabling UARTCTRL_TE to avoid pending idle preamble */
lpuart32_write(&sport->port, modem & ~UARTMODIR_TXCTSE, UARTMODIR);
/* restore control register */
lpuart32_write(&sport->port, ctrl, UARTCTRL);
/* re-enable the CTS if needed */
lpuart32_write(&sport->port, modem, UARTMODIR);
if ((ctrl & (UARTCTRL_PE | UARTCTRL_M)) == UARTCTRL_PE)
sport->is_cs7 = true;

View file

@ -462,8 +462,7 @@ static void imx_uart_stop_tx(struct uart_port *port)
}
}
/* called with port.lock taken and irqs off */
static void imx_uart_stop_rx(struct uart_port *port)
static void imx_uart_stop_rx_with_loopback_ctrl(struct uart_port *port, bool loopback)
{
struct imx_port *sport = (struct imx_port *)port;
u32 ucr1, ucr2, ucr4, uts;
@ -485,7 +484,7 @@ static void imx_uart_stop_rx(struct uart_port *port)
/* See SER_RS485_ENABLED/UTS_LOOP comment in imx_uart_probe() */
if (port->rs485.flags & SER_RS485_ENABLED &&
port->rs485.flags & SER_RS485_RTS_ON_SEND &&
sport->have_rtscts && !sport->have_rtsgpio) {
sport->have_rtscts && !sport->have_rtsgpio && loopback) {
uts = imx_uart_readl(sport, imx_uart_uts_reg(sport));
uts |= UTS_LOOP;
imx_uart_writel(sport, uts, imx_uart_uts_reg(sport));
@ -497,6 +496,16 @@ static void imx_uart_stop_rx(struct uart_port *port)
imx_uart_writel(sport, ucr2, UCR2);
}
/* called with port.lock taken and irqs off */
static void imx_uart_stop_rx(struct uart_port *port)
{
/*
* Stop RX and enable loopback in order to make sure RS485 bus
* is not blocked. Se comment in imx_uart_probe().
*/
imx_uart_stop_rx_with_loopback_ctrl(port, true);
}
/* called with port.lock taken and irqs off */
static void imx_uart_enable_ms(struct uart_port *port)
{
@ -682,9 +691,14 @@ static void imx_uart_start_tx(struct uart_port *port)
imx_uart_rts_inactive(sport, &ucr2);
imx_uart_writel(sport, ucr2, UCR2);
/*
* Since we are about to transmit we can not stop RX
* with loopback enabled because that will make our
* transmitted data being just looped to RX.
*/
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX) &&
!port->rs485_rx_during_tx_gpio)
imx_uart_stop_rx(port);
imx_uart_stop_rx_with_loopback_ctrl(port, false);
sport->tx_state = WAIT_AFTER_RTS;

View file

@ -851,19 +851,21 @@ static void qcom_geni_serial_stop_tx(struct uart_port *uport)
}
static void qcom_geni_serial_send_chunk_fifo(struct uart_port *uport,
unsigned int remaining)
unsigned int chunk)
{
struct qcom_geni_serial_port *port = to_dev_port(uport);
struct circ_buf *xmit = &uport->state->xmit;
unsigned int tx_bytes;
unsigned int tx_bytes, c, remaining = chunk;
u8 buf[BYTES_PER_FIFO_WORD];
while (remaining) {
memset(buf, 0, sizeof(buf));
tx_bytes = min(remaining, BYTES_PER_FIFO_WORD);
memcpy(buf, &xmit->buf[xmit->tail], tx_bytes);
uart_xmit_advance(uport, tx_bytes);
for (c = 0; c < tx_bytes ; c++) {
buf[c] = xmit->buf[xmit->tail];
uart_xmit_advance(uport, 1);
}
iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1);

View file

@ -46,8 +46,31 @@ static int serial_port_runtime_resume(struct device *dev)
return 0;
}
static int serial_port_runtime_suspend(struct device *dev)
{
struct serial_port_device *port_dev = to_serial_base_port_device(dev);
struct uart_port *port = port_dev->port;
unsigned long flags;
bool busy;
if (port->flags & UPF_DEAD)
return 0;
uart_port_lock_irqsave(port, &flags);
busy = __serial_port_busy(port);
if (busy)
port->ops->start_tx(port);
uart_port_unlock_irqrestore(port, flags);
if (busy)
pm_runtime_mark_last_busy(dev);
return busy ? -EBUSY : 0;
}
static DEFINE_RUNTIME_DEV_PM_OPS(serial_port_pm,
NULL, serial_port_runtime_resume, NULL);
serial_port_runtime_suspend,
serial_port_runtime_resume, NULL);
static int serial_port_probe(struct device *dev)
{

View file

@ -381,7 +381,7 @@ static void vc_uniscr_delete(struct vc_data *vc, unsigned int nr)
u32 *ln = vc->vc_uni_lines[vc->state.y];
unsigned int x = vc->state.x, cols = vc->vc_cols;
memcpy(&ln[x], &ln[x + nr], (cols - x - nr) * sizeof(*ln));
memmove(&ln[x], &ln[x + nr], (cols - x - nr) * sizeof(*ln));
memset32(&ln[cols - nr], ' ', nr);
}
}