summaryrefslogtreecommitdiff
path: root/drivers/tty
diff options
context:
space:
mode:
authorRabin Vincent <rabin.vincent@stericsson.com>2012-01-17 11:52:28 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-02-03 09:19:00 -0800
commitf0661faa597be0c7fb7612e8968c2f508e168adf (patch)
treeade6518f2a4d07fbf14744eb5699c6e323fa2668 /drivers/tty
parent47f7a05bd076caf9bc2d60555a1282517c6eca31 (diff)
downloadlwn-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.c14
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);
}