TTY / Serial / VT driver fixes for 7.2-rc7

Here are some small serial and vt tty driver fixes for 7.2-rc7 that
 resolve some reported problems.  Included in here are:
   - 2 vt core fixes
   - amba-pl011 serial driver fixes
   - 8250_of and 8250_dma driver fixes
   - qcom-geni serial driver fix
   - sc16is7xx serial driver fix
 
 All of these have been in linux-next this week with no reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCandKkg8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ylnjQCeND+mnhXzo7wmT4E2vHER2FG8UEEAmwXRTNe6
 QzKAPXT2BgHPFW7Gy8dk
 =UY5p
 -----END PGP SIGNATURE-----

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

Pull tty / serial / vt driver fixes from Greg KH:
 "Here are some small serial and vt tty driver fixes for 7.2-rc7 that
  resolve some reported problems. Included in here are:

   - two vt core fixes

   - amba-pl011 serial driver fixes

   - 8250_of and 8250_dma driver fixes

   - qcom-geni serial driver fix

   - sc16is7xx serial driver fix

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

* tag 'tty-7.2-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  serial: amba-pl011: synchronize DMA teardown
  serial: amba-pl011: cancel RS485 hrtimers after freeing IRQ
  serial: amba-pl011: fix indefinite RS485 post-send delay
  vt: add permission check for KDSKBMETA ioctl
  vt: stabilize tty reference in kbd_keycode with tty_port_tty_get
  serial: 8250_of: clear stuck empty-FIFO RX-timeout on LPC32xx
  serial: qcom-geni: fix TX DMA buffer flush
  serial: 8250_dma: Clear stale RX state on shutdown
  serial: sc16is7xx: enable THRI before filling TX FIFO
This commit is contained in:
Linus Torvalds 2026-08-08 16:31:15 -07:00
commit e4836b67ba
7 changed files with 130 additions and 59 deletions

View File

@ -211,11 +211,12 @@ void serial8250_rx_dma_flush(struct uart_8250_port *p)
{
struct uart_8250_dma *dma = p->dma;
if (dma->rx_running) {
dmaengine_pause(dma->rxchan);
__dma_rx_complete(p);
dmaengine_terminate_async(dma->rxchan);
}
if (!dma || !dma->rxchan || !dma->rx_running)
return;
dmaengine_pause(dma->rxchan);
__dma_rx_complete(p);
dmaengine_terminate_async(dma->rxchan);
}
EXPORT_SYMBOL_GPL(serial8250_rx_dma_flush);
@ -324,6 +325,7 @@ void serial8250_release_dma(struct uart_8250_port *p)
/* Release RX resources */
dmaengine_terminate_sync(dma->rxchan);
dma->rx_running = 0;
dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf,
dma->rx_addr);
dma_release_channel(dma->rxchan);

View File

@ -81,6 +81,40 @@ static int of_platform_serial_clk_notifier_cb(struct notifier_block *nb, unsigne
return NOTIFY_DONE;
}
static int lpc32xx_handle_irq(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned int iir;
u16 status;
guard(serial8250_rpm)(up);
iir = serial_port_in(port, UART_IIR);
if (iir & UART_IIR_NO_INT)
return 0;
guard(uart_port_lock_check_sysrq_irqsave)(port);
/*
* The LPC32xx UART can assert an RX character-timeout interrupt while
* the RX FIFO is empty: IIR reports UART_IIR_RX_TIMEOUT but LSR.DR is
* clear. The timeout is only cleared by reading RHR, but the core RX
* path skips that read when the FIFO is empty, so the level-triggered
* IRQ re-fires forever and livelocks this single-core SoC. Do one
* throwaway RHR read to clear it; a healthy UART never reports a
* timeout with DR/BI clear, so no received data is ever discarded.
*/
if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) {
status = serial_lsr_in(up);
if (!(status & (UART_LSR_DR | UART_LSR_BI)))
serial_port_in(port, UART_RX);
}
serial8250_handle_irq_locked(port, iir);
return 1;
}
/*
* Fill a struct uart_port for a given device node
*/
@ -173,6 +207,9 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
case PORT_NPCM:
ret = npcm_setup(port);
break;
case PORT_LPC3220:
port->handle_irq = lpc32xx_handle_irq;
break;
default:
/* Nothing to do */
ret = 0;
@ -369,6 +406,7 @@ static struct platform_driver of_platform_serial_driver = {
module_platform_driver(of_platform_serial_driver);
MODULE_IMPORT_NS("SERIAL_8250");
MODULE_AUTHOR("Arnd Bergmann <arnd@arndb.de>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Serial Port driver for Open Firmware platform devices");

View File

@ -309,6 +309,7 @@ enum pl011_rs485_tx_state {
WAIT_AFTER_RTS,
SEND,
WAIT_AFTER_SEND,
WAIT_AFTER_SEND_DELAY,
};
/*
@ -1246,7 +1247,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
if (uap->using_tx_dma) {
/* In theory, this should already be done by pl011_dma_flush_buffer */
dmaengine_terminate_all(uap->dmatx.chan);
dmaengine_terminate_sync(uap->dmatx.chan);
if (uap->dmatx.queued) {
dma_unmap_single(uap->dmatx.chan->device->dev,
uap->dmatx.dma, uap->dmatx.len,
@ -1259,12 +1260,12 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
}
if (uap->using_rx_dma) {
dmaengine_terminate_all(uap->dmarx.chan);
if (uap->dmarx.poll_rate)
timer_delete_sync(&uap->dmarx.timer);
dmaengine_terminate_sync(uap->dmarx.chan);
/* Clean up the RX DMA */
pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a, DMA_FROM_DEVICE);
pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_b, DMA_FROM_DEVICE);
if (uap->dmarx.poll_rate)
timer_delete_sync(&uap->dmarx.timer);
uap->using_rx_dma = false;
}
}
@ -1333,33 +1334,11 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
#define pl011_dma_flush_buffer NULL
#endif
static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
static void pl011_rs485_tx_stop_now(struct uart_amba_port *uap)
{
struct uart_port *port = &uap->port;
u32 cr;
if (uap->rs485_tx_state == SEND)
uap->rs485_tx_state = WAIT_AFTER_SEND;
if (uap->rs485_tx_state == WAIT_AFTER_SEND) {
/* Schedule hrtimer if tx queue not empty */
if (!pl011_tx_empty(port)) {
hrtimer_start(&uap->trigger_stop_tx,
uap->rs485_tx_drain_interval,
HRTIMER_MODE_REL);
return;
}
if (port->rs485.delay_rts_after_send > 0) {
hrtimer_start(&uap->trigger_stop_tx,
ms_to_ktime(port->rs485.delay_rts_after_send),
HRTIMER_MODE_REL);
return;
}
/* Continue without any delay */
} else if (uap->rs485_tx_state == WAIT_AFTER_RTS) {
hrtimer_try_to_cancel(&uap->trigger_start_tx);
}
cr = pl011_read(uap, REG_CR);
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
@ -1375,6 +1354,36 @@ static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
uap->rs485_tx_state = OFF;
}
static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
{
struct uart_port *port = &uap->port;
if (uap->rs485_tx_state == SEND)
uap->rs485_tx_state = WAIT_AFTER_SEND;
if (uap->rs485_tx_state == WAIT_AFTER_SEND) {
/* Schedule hrtimer if tx queue not empty */
if (!pl011_tx_empty(port)) {
hrtimer_start(&uap->trigger_stop_tx,
uap->rs485_tx_drain_interval,
HRTIMER_MODE_REL);
return;
}
if (port->rs485.delay_rts_after_send > 0) {
uap->rs485_tx_state = WAIT_AFTER_SEND_DELAY;
hrtimer_start(&uap->trigger_stop_tx,
ms_to_ktime(port->rs485.delay_rts_after_send),
HRTIMER_MODE_REL);
return;
}
/* Continue without any delay */
} else if (uap->rs485_tx_state == WAIT_AFTER_RTS) {
hrtimer_try_to_cancel(&uap->trigger_start_tx);
}
pl011_rs485_tx_stop_now(uap);
}
static void pl011_stop_tx(struct uart_port *port)
{
struct uart_amba_port *uap =
@ -1415,7 +1424,8 @@ static void pl011_rs485_tx_start(struct uart_amba_port *uap)
uap->rs485_tx_state = SEND;
return;
}
if (uap->rs485_tx_state == WAIT_AFTER_SEND) {
if (uap->rs485_tx_state == WAIT_AFTER_SEND ||
uap->rs485_tx_state == WAIT_AFTER_SEND_DELAY) {
hrtimer_try_to_cancel(&uap->trigger_stop_tx);
uap->rs485_tx_state = SEND;
return;
@ -1482,7 +1492,8 @@ static enum hrtimer_restart pl011_trigger_stop_tx(struct hrtimer *t)
unsigned long flags;
uart_port_lock_irqsave(&uap->port, &flags);
if (uap->rs485_tx_state == WAIT_AFTER_SEND)
if (uap->rs485_tx_state == WAIT_AFTER_SEND ||
uap->rs485_tx_state == WAIT_AFTER_SEND_DELAY)
pl011_rs485_tx_stop(uap);
uart_port_unlock_irqrestore(&uap->port, flags);
@ -2080,11 +2091,20 @@ static void pl011_shutdown(struct uart_port *port)
pl011_dma_shutdown(uap);
if ((port->rs485.flags & SER_RS485_ENABLED && uap->rs485_tx_state != OFF))
pl011_rs485_tx_stop(uap);
free_irq(uap->port.irq, uap);
/*
* free_irq() drains the UART interrupt handler, which can arm either
* timer. Cancel the timers afterwards to drain their callbacks too.
*/
hrtimer_cancel(&uap->trigger_start_tx);
hrtimer_cancel(&uap->trigger_stop_tx);
uart_port_lock_irq(port);
if (uap->rs485_tx_state != OFF)
pl011_rs485_tx_stop_now(uap);
uart_port_unlock_irq(port);
pl011_disable_uart(uap);
/*
@ -3063,6 +3083,8 @@ static void pl011_remove(struct amba_device *dev)
struct uart_amba_port *uap = amba_get_drvdata(dev);
uart_remove_one_port(&amba_reg, &uap->port);
hrtimer_cancel(&uap->trigger_start_tx);
hrtimer_cancel(&uap->trigger_stop_tx);
pl011_unregister_port(uap);
}

View File

@ -158,6 +158,7 @@ static const struct uart_ops qcom_geni_uart_pops;
static struct uart_driver qcom_geni_console_driver;
static struct uart_driver qcom_geni_uart_driver;
static void qcom_geni_serial_stop_tx_dma(struct uart_port *uport);
static void __qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport);
static void qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport);
static int qcom_geni_serial_port_setup(struct uart_port *uport);
@ -636,35 +637,34 @@ static unsigned int qcom_geni_serial_tx_empty(struct uart_port *uport)
return !readl(uport->membase + SE_GENI_TX_FIFO_STATUS);
}
static void qcom_geni_serial_flush_buffer_dma(struct uart_port *uport)
{
struct qcom_geni_serial_port *port = to_dev_port(uport);
qcom_geni_serial_stop_tx_dma(uport);
port->tx_remaining = 0;
port->tx_queued = 0;
}
static void qcom_geni_serial_stop_tx_dma(struct uart_port *uport)
{
struct qcom_geni_serial_port *port = to_dev_port(uport);
bool done;
if (!qcom_geni_serial_main_active(uport))
return;
if (qcom_geni_serial_main_active(uport))
__qcom_geni_serial_cancel_tx_cmd(uport);
if (port->tx_dma_addr) {
writel(1, uport->membase + SE_DMA_TX_FSM_RST);
if (!qcom_geni_serial_poll_bit(uport, SE_DMA_TX_IRQ_STAT,
TX_RESET_DONE, true))
dev_err_ratelimited(uport->dev, "TX DMA reset failed");
writel(TX_RESET_DONE | TX_DMA_DONE,
uport->membase + SE_DMA_TX_IRQ_CLR);
geni_se_tx_dma_unprep(&port->se, port->tx_dma_addr,
port->tx_remaining);
port->tx_dma_addr = 0;
port->tx_remaining = 0;
}
geni_se_cancel_m_cmd(&port->se);
done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
M_CMD_CANCEL_EN, true);
if (!done) {
geni_se_abort_m_cmd(&port->se);
done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
M_CMD_ABORT_EN, true);
if (!done)
dev_err_ratelimited(uport->dev, "M_CMD_ABORT_EN not set");
writel(M_CMD_ABORT_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
}
writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
}
static void qcom_geni_serial_start_tx_dma(struct uart_port *uport)
@ -1180,7 +1180,7 @@ static void qcom_geni_serial_shutdown(struct uart_port *uport)
uart_port_unlock_irq(uport);
}
static void qcom_geni_serial_flush_buffer(struct uart_port *uport)
static void qcom_geni_serial_flush_buffer_fifo(struct uart_port *uport)
{
qcom_geni_serial_cancel_tx_cmd(uport);
}
@ -1769,7 +1769,7 @@ static const struct uart_ops qcom_geni_console_pops = {
.request_port = qcom_geni_serial_request_port,
.config_port = qcom_geni_serial_config_port,
.shutdown = qcom_geni_serial_shutdown,
.flush_buffer = qcom_geni_serial_flush_buffer,
.flush_buffer = qcom_geni_serial_flush_buffer_fifo,
.type = qcom_geni_serial_get_type,
.set_mctrl = qcom_geni_serial_set_mctrl,
.get_mctrl = qcom_geni_serial_get_mctrl,
@ -1792,6 +1792,7 @@ static const struct uart_ops qcom_geni_uart_pops = {
.request_port = qcom_geni_serial_request_port,
.config_port = qcom_geni_serial_config_port,
.shutdown = qcom_geni_serial_shutdown,
.flush_buffer = qcom_geni_serial_flush_buffer_dma,
.type = qcom_geni_serial_get_type,
.set_mctrl = qcom_geni_serial_set_mctrl,
.get_mctrl = qcom_geni_serial_get_mctrl,

View File

@ -827,6 +827,9 @@ static void sc16is7xx_tx_proc(struct kthread_work *ws)
msleep(port->rs485.delay_rts_before_send);
guard(mutex)(&one->lock);
sc16is7xx_port_update(port, SC16IS7XX_IER_REG,
SC16IS7XX_IER_THRI_BIT,
SC16IS7XX_IER_THRI_BIT);
sc16is7xx_handle_tx(port);
}

View File

@ -1437,7 +1437,7 @@ static void kbd_keycode(unsigned int keycode, int down, bool hw_raw)
struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down };
int rc;
tty = vc->port.tty;
tty = tty_port_tty_get(&vc->port);
if (tty && (!tty->driver_data)) {
/* No driver data? Strange. Okay we fix it then. */
@ -1497,9 +1497,12 @@ static void kbd_keycode(unsigned int keycode, int down, bool hw_raw)
* characters get aren't echoed locally. This makes key repeat
* usable with slow applications and under heavy loads.
*/
tty_kref_put(tty);
return;
}
tty_kref_put(tty);
param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate;
param.ledstate = kbd->ledflagstate;
key_map = key_maps[shift_final];

View File

@ -406,6 +406,8 @@ static int vt_k_ioctl(struct tty_struct *tty, unsigned int cmd,
/* this could be folded into KDSKBMODE, but for compatibility
reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
case KDSKBMETA:
if (!perm)
return -EPERM;
return vt_do_kdskbmeta(console, arg);
case KDGKBMETA: