Skip to content

Commit 9ec1882

Browse files
Xinyu Chengregkh
Xinyu Chen
authored andcommitted
tty: serial: imx: console write routing is unsafe on SMP
The console feature's write routing is unsafe on SMP with the startup/shutdown call. 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 open /dev/console and write with sys_write() The shell goes into the normal uart open/write routing, but the other two go into the console operations. The open routing calls imx serial startup, which will write USR1/2 register without any lock and critical with imx_console_write call. Add a spin_lock for startup/shutdown/console_write routing. This patch is a port from Freescale's Android kernel. Signed-off-by: Xinyu Chen <xinyu.chen@freescale.com> Tested-by: Dirk Behme <dirk.behme@de.bosch.com> CC: Sascha Hauer <s.hauer@pengutronix.de> Acked-by: Shawn Guo <shawn.guo@linaro.org> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent fea7a08 commit 9ec1882

File tree

1 file changed

+11
-1
lines changed

1 file changed

+11
-1
lines changed

drivers/tty/serial/imx.c

+11-1
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,7 @@ static int imx_startup(struct uart_port *port)
754754
}
755755
}
756756

757+
spin_lock_irqsave(&sport->port.lock, flags);
757758
/*
758759
* Finally, clear and enable interrupts
759760
*/
@@ -807,7 +808,6 @@ static int imx_startup(struct uart_port *port)
807808
/*
808809
* Enable modem status interrupts
809810
*/
810-
spin_lock_irqsave(&sport->port.lock,flags);
811811
imx_enable_ms(&sport->port);
812812
spin_unlock_irqrestore(&sport->port.lock,flags);
813813

@@ -837,10 +837,13 @@ static void imx_shutdown(struct uart_port *port)
837837
{
838838
struct imx_port *sport = (struct imx_port *)port;
839839
unsigned long temp;
840+
unsigned long flags;
840841

842+
spin_lock_irqsave(&sport->port.lock, flags);
841843
temp = readl(sport->port.membase + UCR2);
842844
temp &= ~(UCR2_TXEN);
843845
writel(temp, sport->port.membase + UCR2);
846+
spin_unlock_irqrestore(&sport->port.lock, flags);
844847

845848
if (USE_IRDA(sport)) {
846849
struct imxuart_platform_data *pdata;
@@ -869,12 +872,14 @@ static void imx_shutdown(struct uart_port *port)
869872
* Disable all interrupts, port and break condition.
870873
*/
871874

875+
spin_lock_irqsave(&sport->port.lock, flags);
872876
temp = readl(sport->port.membase + UCR1);
873877
temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
874878
if (USE_IRDA(sport))
875879
temp &= ~(UCR1_IREN);
876880

877881
writel(temp, sport->port.membase + UCR1);
882+
spin_unlock_irqrestore(&sport->port.lock, flags);
878883
}
879884

880885
static void
@@ -1217,6 +1222,9 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
12171222
struct imx_port *sport = imx_ports[co->index];
12181223
struct imx_port_ucrs old_ucr;
12191224
unsigned int ucr1;
1225+
unsigned long flags;
1226+
1227+
spin_lock_irqsave(&sport->port.lock, flags);
12201228

12211229
/*
12221230
* First, save UCR1/2/3 and then disable interrupts
@@ -1242,6 +1250,8 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
12421250
while (!(readl(sport->port.membase + USR2) & USR2_TXDC));
12431251

12441252
imx_port_ucrs_restore(&sport->port, &old_ucr);
1253+
1254+
spin_unlock_irqrestore(&sport->port.lock, flags);
12451255
}
12461256

12471257
/*

0 commit comments

Comments
 (0)