Commit 53faca2f authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Greg Kroah-Hartman
Browse files

serial: pl011: Fix lockdep splat when handling magic-sysrq interrupt

commit 534cf755d9df99e214ddbe26b91cd4d81d2603e2 upstream.

Issuing a magic-sysrq via the PL011 causes the following lockdep splat,
which is easily reproducible under QEMU:

  | sysrq: Changing Loglevel
  | sysrq: Loglevel set to 9
  |
  | ======================================================
  | WARNING: possible circular locking dependency detected
  | 5.9.0-rc7 #1 Not tainted
  | ------------------------------------------------------
  | systemd-journal/138 is trying to acquire lock:
  | ffffab133ad950c0 (console_owner){-.-.}-{0:0}, at: console_lock_spinning_enable+0x34/0x70
  |
  | but task is already holding lock:
  | ffff0001fd47b098 (&port_lock_key){-.-.}-{2:2}, at: pl011_int+0x40/0x488
  |
  | which lock already depends on the new lock.

  [...]

  |  Possible unsafe locking scenario:
  |
  |        CPU0                    CPU1
  |        ----                    ----
  |   lock(&port_lock_key);
  |                                lock(console_owner);
  |                                lock(&port_lock_key);
  |   lock(console_owner);
  |
  |  *** DEADLOCK ***

The issue being that CPU0 takes 'port_lock' on the irq path in pl011_int()
before taking 'console_owner' on the printk() path, whereas CPU1 takes
the two locks in the opposite order on the printk() path due to setting
the "console_owner" prior to calling into into the actual console driver.

Fix this in the same way as the msm-serial driver by dropping 'port_lock'
before handling the sysrq.

Cc: <stable@vger.kernel.org> # 4.19+
Cc: Russell King <linux@armlinux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jirislaby@kernel.org>
Link: https://lore.kernel.org/r/20200811101313.GA6970@willie-the-truck

Signed-off-by: default avatarPeter Zijlstra <peterz@infradead.org>
Tested-by: default avatarWill Deacon <will@kernel.org>
Signed-off-by: default avatarWill Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20200930120432.16551-1-will@kernel.org

Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent e3f6c126
...@@ -308,8 +308,9 @@ static void pl011_write(unsigned int val, const struct uart_amba_port *uap, ...@@ -308,8 +308,9 @@ static void pl011_write(unsigned int val, const struct uart_amba_port *uap,
*/ */
static int pl011_fifo_to_tty(struct uart_amba_port *uap) static int pl011_fifo_to_tty(struct uart_amba_port *uap)
{ {
u16 status;
unsigned int ch, flag, fifotaken; unsigned int ch, flag, fifotaken;
int sysrq;
u16 status;
for (fifotaken = 0; fifotaken != 256; fifotaken++) { for (fifotaken = 0; fifotaken != 256; fifotaken++) {
status = pl011_read(uap, REG_FR); status = pl011_read(uap, REG_FR);
...@@ -344,10 +345,12 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap) ...@@ -344,10 +345,12 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)
flag = TTY_FRAME; flag = TTY_FRAME;
} }
if (uart_handle_sysrq_char(&uap->port, ch & 255)) spin_unlock(&uap->port.lock);
continue; sysrq = uart_handle_sysrq_char(&uap->port, ch & 255);
spin_lock(&uap->port.lock);
uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); if (!sysrq)
uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
} }
return fifotaken; return fifotaken;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment