diff options
author | Shinya Kuribayashi <shinya.kuribayashi.px@renesas.com> | 2012-11-15 20:54:49 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-11-15 21:02:51 -0500 |
commit | 33b48e1633f738c5ae78234c2dd5e3a9ba115437 (patch) | |
tree | 09193c93ad60bdd24e34e382439baa129e2aa02b /drivers/tty/serial/sh-sci.c | |
parent | 40f70c03e33a1eed3f3fcd13418e76abad77d117 (diff) |
serial: sh-sci: fix possible race cases on SCSCR register accesses
In the previous commit, console write function (serial_console_write)
is changed to disable SCI interrupts while printing console strings.
This introduces possible race cases in the serial startup / shutdown
functions on SMP systems.
This patch fixes the sh-sci in the same way as commit 9ec1882df2
(tty: serial: imx: console write routing is unsafe on SMP, from
Xinyu Chen <xinyu.chen@freescale.com>, 2012-08-27) did.
There could be several consumers of the console,
* the kernel printk
* the init process using /dev/kmsg to call printk to show log
* shell, which opens /dev/console and writes with sys_write()
The shell goes into the normal UART open() and write() system calls,
while the other two go into the console operations. The open() call
invokes serial startup function (sci_startup), which will write to
the SCSCR register (to enable or disable SCI interrupts) without any
locking. This will conflict with the console serial function.
Add spinlock protections in sci_startup() and sci_shutdown() properly.
Signed-off-by: Shinya Kuribayashi <shinya.kuribayashi.px@renesas.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/sh-sci.c')
-rw-r--r-- | drivers/tty/serial/sh-sci.c | 6 |
1 files changed, 6 insertions, 0 deletions
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 63a23eadd7e8..d38c0f546032 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c | |||
@@ -1743,6 +1743,7 @@ static inline void sci_free_dma(struct uart_port *port) | |||
1743 | static int sci_startup(struct uart_port *port) | 1743 | static int sci_startup(struct uart_port *port) |
1744 | { | 1744 | { |
1745 | struct sci_port *s = to_sci_port(port); | 1745 | struct sci_port *s = to_sci_port(port); |
1746 | unsigned long flags; | ||
1746 | int ret; | 1747 | int ret; |
1747 | 1748 | ||
1748 | dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); | 1749 | dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); |
@@ -1753,8 +1754,10 @@ static int sci_startup(struct uart_port *port) | |||
1753 | 1754 | ||
1754 | sci_request_dma(port); | 1755 | sci_request_dma(port); |
1755 | 1756 | ||
1757 | spin_lock_irqsave(&port->lock, flags); | ||
1756 | sci_start_tx(port); | 1758 | sci_start_tx(port); |
1757 | sci_start_rx(port); | 1759 | sci_start_rx(port); |
1760 | spin_unlock_irqrestore(&port->lock, flags); | ||
1758 | 1761 | ||
1759 | return 0; | 1762 | return 0; |
1760 | } | 1763 | } |
@@ -1762,11 +1765,14 @@ static int sci_startup(struct uart_port *port) | |||
1762 | static void sci_shutdown(struct uart_port *port) | 1765 | static void sci_shutdown(struct uart_port *port) |
1763 | { | 1766 | { |
1764 | struct sci_port *s = to_sci_port(port); | 1767 | struct sci_port *s = to_sci_port(port); |
1768 | unsigned long flags; | ||
1765 | 1769 | ||
1766 | dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); | 1770 | dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); |
1767 | 1771 | ||
1772 | spin_lock_irqsave(&port->lock, flags); | ||
1768 | sci_stop_rx(port); | 1773 | sci_stop_rx(port); |
1769 | sci_stop_tx(port); | 1774 | sci_stop_tx(port); |
1775 | spin_unlock_irqrestore(&port->lock, flags); | ||
1770 | 1776 | ||
1771 | sci_free_dma(port); | 1777 | sci_free_dma(port); |
1772 | sci_free_irq(s); | 1778 | sci_free_irq(s); |