aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJon Medhurst <tixy@linaro.org>2013-12-10 05:18:58 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-12-17 12:35:37 -0500
commitfe43390702a1b5741fdf217063b05c7612b38303 (patch)
tree6bd4b42a7ba001a36a3f9a901dd6eeb19f96682a /drivers
parent8f898bfd048f65856d8911a89b1616ad3e677c6c (diff)
serial: amba-pl011: use port lock to guard control register access
When the pl011 is being used for a console, pl011_console_write forces the control register (CR) to enable the UART for transmission and then restores this to the original value afterwards. It does this while holding the port lock. Unfortunately, when the uart is started or shutdown - say in response to userland using the serial device for a terminal - then this updates the control register without any locking. This means we can have pl011_console_write Save CR pl011_startup Initialise CR, e.g. enable receive pl011_console_write Restore old CR with receive not enabled this result is a serial port which doesn't respond to any input. A similar race in reverse could happen when the device is shutdown. We can fix these problems by taking the port lock when updating CR. Signed-off-by: Jon Medhurst <tixy@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/tty/serial/amba-pl011.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index a183aceb6d15..a576a5bc2d15 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1535,6 +1535,8 @@ static int pl011_startup(struct uart_port *port)
1535 /* 1535 /*
1536 * Provoke TX FIFO interrupt into asserting. 1536 * Provoke TX FIFO interrupt into asserting.
1537 */ 1537 */
1538 spin_lock_irq(&uap->port.lock);
1539
1538 cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE; 1540 cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE;
1539 writew(cr, uap->port.membase + UART011_CR); 1541 writew(cr, uap->port.membase + UART011_CR);
1540 writew(0, uap->port.membase + UART011_FBRD); 1542 writew(0, uap->port.membase + UART011_FBRD);
@@ -1559,6 +1561,8 @@ static int pl011_startup(struct uart_port *port)
1559 cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; 1561 cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
1560 writew(cr, uap->port.membase + UART011_CR); 1562 writew(cr, uap->port.membase + UART011_CR);
1561 1563
1564 spin_unlock_irq(&uap->port.lock);
1565
1562 /* 1566 /*
1563 * initialise the old status of the modem signals 1567 * initialise the old status of the modem signals
1564 */ 1568 */
@@ -1627,11 +1631,13 @@ static void pl011_shutdown(struct uart_port *port)
1627 * it during startup(). 1631 * it during startup().
1628 */ 1632 */
1629 uap->autorts = false; 1633 uap->autorts = false;
1634 spin_lock_irq(&uap->port.lock);
1630 cr = readw(uap->port.membase + UART011_CR); 1635 cr = readw(uap->port.membase + UART011_CR);
1631 uap->old_cr = cr; 1636 uap->old_cr = cr;
1632 cr &= UART011_CR_RTS | UART011_CR_DTR; 1637 cr &= UART011_CR_RTS | UART011_CR_DTR;
1633 cr |= UART01x_CR_UARTEN | UART011_CR_TXE; 1638 cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
1634 writew(cr, uap->port.membase + UART011_CR); 1639 writew(cr, uap->port.membase + UART011_CR);
1640 spin_unlock_irq(&uap->port.lock);
1635 1641
1636 /* 1642 /*
1637 * disable break condition and fifos 1643 * disable break condition and fifos