Re: [PATCH v7 2/5] serial: serialize asynchronous write wakeups with the port lock
flat view
From: Raul E Rangel <hidden>
Date: 2026-10-28 20:48:51
Also in:
imx, linux-arm-kernel, linux-serial, lkml
Hi James, A few issues in this patch across the serial drivers: 1. Recursive self-deadlock on ltq_port->lock in drivers/tty/serial/lantiq.c:
quoted hunk ↗ jump to hunk
@@ -239,7 +239,8 @@ lqasc_tx_int(int irq, void *_port) spin_lock_irqsave(<q_port->lock, flags); __raw_writel(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR); spin_unlock_irqrestore(<q_port->lock, flags); - lqasc_start_tx(port); + scoped_guard(uart_port_lock_irqsave, port) + lqasc_start_tx(port); return IRQ_HANDLED; }
Inside lqasc_start_tx(): spin_lock_irqsave(<q_port->lock, flags); uart_port_tx(port, ch, lqasc_tx_ready(port), writeb(ch, port->membase + LTQ_ASC_TBUF)); spin_unlock_irqrestore(<q_port->lock, flags); uart_port_tx() invokes uart_write_wakeup(port) while ltq_port->lock is still held (nested inside port->lock). If anything in the wakeup path or printk() invokes lqasc_console_write() (which takes spin_lock_irqsave(<q_port->lock, flags) at line 612), the CPU will immediately self-deadlock on ltq_port->lock. ltq_port->lock should not be held across uart_write_wakeup(port). 2. Missed unlocked callers in drivers/tty/serial/dz.c, drivers/tty/serial/zs.c, and drivers/tty/serial/jsm/jsm_cls.c: The commit description states: "Ensure every driver caller of uart_write_wakeup(), directly or through uart_port_tx*() and uart_handle_cts_change(), holds the port lock first." However: - In drivers/tty/serial/dz.c: dz_transmit_chars() (lines 266-288) only locks &dport->port around dz_stop_tx(), calling uart_fifo_get(&dport->port, &tmp) at line 267 and uart_write_wakeup(&dport->port) at line 281 without holding dport->port.lock. - In drivers/tty/serial/zs.c: zs_transmit_chars() (line 641) only acquires &scc->zlock, so zs_raw_transmit_chars() calls uart_fifo_get(&zport->port, &ch) (line 621) and uart_write_wakeup(&zport->port) (line 630) without holding zport->port.lock. In addition, zs_status_handle() (lines 673-680) drops &scc->zlock and calls uart_handle_cts_change(uport, ...) and uart_handle_dcd_change(uport, ...) with no lock held at all, which triggers lockdep_assert_held_once(&uport->lock) in serial_core.c. - In drivers/tty/serial/jsm/jsm_cls.c: while jsm_neo.c wrapped neo_parse_modem() in scoped_guard(uart_port_lock_irqsave, &ch->uart_port), cls_parse_isr() in jsm_cls.c (line 585) still calls cls_parse_modem() -> uart_handle_dcd_change(&ch->uart_port, ...) without holding ch->uart_port.lock. Also, in Patch 3/5, adding lockdep_assert_held_once(&port->lock); to uart_write_wakeup() alongside uart_xmit_block() / uart_xmit_unblock() would help catch any unlocked callers automatically. Thanks, Raul