Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tty: serial: fsl_lpuart: lock port on console write

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>

authored by

Stefan Agner and committed by
Greg Kroah-Hartman
abf1e0a9 4d9d7d89

+20
+20
drivers/tty/serial/fsl_lpuart.c
··· 1705 1705 { 1706 1706 struct lpuart_port *sport = lpuart_ports[co->index]; 1707 1707 unsigned char old_cr2, cr2; 1708 + unsigned long flags; 1709 + int locked = 1; 1710 + 1711 + if (sport->port.sysrq || oops_in_progress) 1712 + locked = spin_trylock_irqsave(&sport->port.lock, flags); 1713 + else 1714 + spin_lock_irqsave(&sport->port.lock, flags); 1708 1715 1709 1716 /* first save CR2 and then disable interrupts */ 1710 1717 cr2 = old_cr2 = readb(sport->port.membase + UARTCR2); ··· 1726 1719 barrier(); 1727 1720 1728 1721 writeb(old_cr2, sport->port.membase + UARTCR2); 1722 + 1723 + if (locked) 1724 + spin_unlock_irqrestore(&sport->port.lock, flags); 1729 1725 } 1730 1726 1731 1727 static void ··· 1736 1726 { 1737 1727 struct lpuart_port *sport = lpuart_ports[co->index]; 1738 1728 unsigned long old_cr, cr; 1729 + unsigned long flags; 1730 + int locked = 1; 1731 + 1732 + if (sport->port.sysrq || oops_in_progress) 1733 + locked = spin_trylock_irqsave(&sport->port.lock, flags); 1734 + else 1735 + spin_lock_irqsave(&sport->port.lock, flags); 1739 1736 1740 1737 /* first save CR2 and then disable interrupts */ 1741 1738 cr = old_cr = lpuart32_read(sport->port.membase + UARTCTRL); ··· 1757 1740 barrier(); 1758 1741 1759 1742 lpuart32_write(old_cr, sport->port.membase + UARTCTRL); 1743 + 1744 + if (locked) 1745 + spin_unlock_irqrestore(&sport->port.lock, flags); 1760 1746 } 1761 1747 1762 1748 /*