lkml.org 
[lkml]   [2012]   [Sep]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[ 139/218] tty: serial: imx: console write routing is unsafe on SMP
    Date
    3.4-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Xinyu Chen <xinyu.chen@freescale.com>

    commit 9ec1882df244c4ee1baa692676fef5e8b0f5487d upstream.

    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>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/tty/serial/imx.c | 12 +++++++++++-
    1 file changed, 11 insertions(+), 1 deletion(-)

    --- a/drivers/tty/serial/imx.c
    +++ b/drivers/tty/serial/imx.c
    @@ -756,6 +756,7 @@ static int imx_startup(struct uart_port
    }
    }

    + spin_lock_irqsave(&sport->port.lock, flags);
    /*
    * Finally, clear and enable interrupts
    */
    @@ -809,7 +810,6 @@ static int imx_startup(struct uart_port
    /*
    * Enable modem status interrupts
    */
    - spin_lock_irqsave(&sport->port.lock,flags);
    imx_enable_ms(&sport->port);
    spin_unlock_irqrestore(&sport->port.lock,flags);

    @@ -839,10 +839,13 @@ static void imx_shutdown(struct uart_por
    {
    struct imx_port *sport = (struct imx_port *)port;
    unsigned long temp;
    + unsigned long flags;

    + spin_lock_irqsave(&sport->port.lock, flags);
    temp = readl(sport->port.membase + UCR2);
    temp &= ~(UCR2_TXEN);
    writel(temp, sport->port.membase + UCR2);
    + spin_unlock_irqrestore(&sport->port.lock, flags);

    if (USE_IRDA(sport)) {
    struct imxuart_platform_data *pdata;
    @@ -871,12 +874,14 @@ static void imx_shutdown(struct uart_por
    * Disable all interrupts, port and break condition.
    */

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

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

    static void
    @@ -1219,6 +1224,9 @@ imx_console_write(struct console *co, co
    struct imx_port *sport = imx_ports[co->index];
    struct imx_port_ucrs old_ucr;
    unsigned int ucr1;
    + unsigned long flags;
    +
    + spin_lock_irqsave(&sport->port.lock, flags);

    /*
    * First, save UCR1/2/3 and then disable interrupts
    @@ -1244,6 +1252,8 @@ imx_console_write(struct console *co, co
    while (!(readl(sport->port.membase + USR2) & USR2_TXDC));

    imx_port_ucrs_restore(&sport->port, &old_ucr);
    +
    + spin_unlock_irqrestore(&sport->port.lock, flags);
    }

    /*



    \
     
     \ /
      Last update: 2012-09-28 23:41    [W:4.055 / U:0.012 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site