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:
> @@ -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