diff options
author | Rabin Vincent <rabin.vincent@stericsson.com> | 2012-01-17 11:52:28 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-02-03 09:19:00 -0800 |
commit | f0661faa597be0c7fb7612e8968c2f508e168adf (patch) | |
tree | ade6518f2a4d07fbf14744eb5699c6e323fa2668 /drivers/tty | |
parent | 47f7a05bd076caf9bc2d60555a1282517c6eca31 (diff) | |
download | lwn-f0661faa597be0c7fb7612e8968c2f508e168adf.tar.gz lwn-f0661faa597be0c7fb7612e8968c2f508e168adf.zip |
serial: amba-pl011: lock console writes against interrupts
commit ef605fdb33883d687cff5ba75095a91b313b4966 upstream.
Protect against pl011_console_write() and the interrupt for
the console UART running concurrently on different CPUs.
Otherwise the console_write could spin for a long time
waiting for the UART to become not busy, while the other
CPU continuously services UART interrupts and keeps the
UART busy.
The checks for sysrq and oops_in_progress are taken
from 8250.c.
Signed-off-by: Rabin Vincent <rabin.vincent@stericsson.com>
Reviewed-by: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
Reviewed-by: Bibek Basu <bibek.basu@stericsson.com>
Reviewed-by: Shreshtha Kumar Sahu <shreshthakumar.sahu@stericsson.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/serial/amba-pl011.c | 14 |
1 files changed, 14 insertions, 0 deletions
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index f5f6831b0a64..4a4733e601d8 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1733,9 +1733,19 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) { struct uart_amba_port *uap = amba_ports[co->index]; unsigned int status, old_cr, new_cr; + unsigned long flags; + int locked = 1; clk_enable(uap->clk); + local_irq_save(flags); + if (uap->port.sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock(&uap->port.lock); + else + spin_lock(&uap->port.lock); + /* * First save the CR then disable the interrupts */ @@ -1755,6 +1765,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) } while (status & UART01x_FR_BUSY); writew(old_cr, uap->port.membase + UART011_CR); + if (locked) + spin_unlock(&uap->port.lock); + local_irq_restore(flags); + clk_disable(uap->clk); } |