serial/mxs-auart: fix race condition in interrupt handler
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Thu, 4 Jul 2013 09:28:51 +0000 (11:28 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 12 Aug 2013 01:35:21 +0000 (18:35 -0700)
commit d970d7fe65adff5efe75b4a73c4ffc9be57089f7 upstream.

The handler needs to ack the pending events before actually handling them.
Otherwise a new event might come in after it it considered non-pending or
handled and is acked then without being handled. So this event is only
noticed when the next interrupt happens.

Without this patch an i.MX28 based machine running an rt-patched kernel
regularly hangs during boot.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/mxs-auart.c

index 4f5f161896a139852e46f93f30239be979838bda..3de0fb2712f596ff0b1b768375e4fd2acf3a1b28 100644 (file)
@@ -678,11 +678,18 @@ static void mxs_auart_settermios(struct uart_port *u,
 
 static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
 {
-       u32 istatus, istat;
+       u32 istat;
        struct mxs_auart_port *s = context;
        u32 stat = readl(s->port.membase + AUART_STAT);
 
-       istatus = istat = readl(s->port.membase + AUART_INTR);
+       istat = readl(s->port.membase + AUART_INTR);
+
+       /* ack irq */
+       writel(istat & (AUART_INTR_RTIS
+               | AUART_INTR_TXIS
+               | AUART_INTR_RXIS
+               | AUART_INTR_CTSMIS),
+                       s->port.membase + AUART_INTR_CLR);
 
        if (istat & AUART_INTR_CTSMIS) {
                uart_handle_cts_change(&s->port, stat & AUART_STAT_CTS);
@@ -702,12 +709,6 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
                istat &= ~AUART_INTR_TXIS;
        }
 
-       writel(istatus & (AUART_INTR_RTIS
-               | AUART_INTR_TXIS
-               | AUART_INTR_RXIS
-               | AUART_INTR_CTSMIS),
-                       s->port.membase + AUART_INTR_CLR);
-
        return IRQ_HANDLED;
 }