Skip to content

Commit

Permalink
tty: serial: fsl_lpuart: lock port on console write
Browse files Browse the repository at this point in the history
The console write code is not entirely race free (e.g. the operations
to disabling the UART interrupts are not atomic) hence locking is
required. This has been become apparent with the PREEMPT RT patchset
applied: With the fully preemptible kernel configuration the system
often ended up in a freeze already at startup.

Disable interrupts and lock using read_lock_irqsave. Try to lock in
the sysrq/oops case, but don't bother if locking fails.

Signed-off-by: Stefan Agner <stefan@agner.ch>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Stefan Agner authored and Greg Kroah-Hartman committed Mar 31, 2017
1 parent 4d9d7d8 commit abf1e0a
Showing 1 changed file with 20 additions and 0 deletions.
20 changes: 20 additions & 0 deletions drivers/tty/serial/fsl_lpuart.c
Original file line number Diff line number Diff line change
Expand Up @@ -1705,6 +1705,13 @@ lpuart_console_write(struct console *co, const char *s, unsigned int count)
{
struct lpuart_port *sport = lpuart_ports[co->index];
unsigned char old_cr2, cr2;
unsigned long flags;
int locked = 1;

if (sport->port.sysrq || oops_in_progress)
locked = spin_trylock_irqsave(&sport->port.lock, flags);
else
spin_lock_irqsave(&sport->port.lock, flags);

/* first save CR2 and then disable interrupts */
cr2 = old_cr2 = readb(sport->port.membase + UARTCR2);
Expand All @@ -1719,13 +1726,23 @@ lpuart_console_write(struct console *co, const char *s, unsigned int count)
barrier();

writeb(old_cr2, sport->port.membase + UARTCR2);

if (locked)
spin_unlock_irqrestore(&sport->port.lock, flags);
}

static void
lpuart32_console_write(struct console *co, const char *s, unsigned int count)
{
struct lpuart_port *sport = lpuart_ports[co->index];
unsigned long old_cr, cr;
unsigned long flags;
int locked = 1;

if (sport->port.sysrq || oops_in_progress)
locked = spin_trylock_irqsave(&sport->port.lock, flags);
else
spin_lock_irqsave(&sport->port.lock, flags);

/* first save CR2 and then disable interrupts */
cr = old_cr = lpuart32_read(sport->port.membase + UARTCTRL);
Expand All @@ -1740,6 +1757,9 @@ lpuart32_console_write(struct console *co, const char *s, unsigned int count)
barrier();

lpuart32_write(old_cr, sport->port.membase + UARTCTRL);

if (locked)
spin_unlock_irqrestore(&sport->port.lock, flags);
}

/*
Expand Down

0 comments on commit abf1e0a

Please sign in to comment.