serial: sirf: fix kernel panic caused by unpaired spinlock

commit 8b9ade9f74 coming from Viresh Kumar "tty: serial: sirfsoc: drop
uart_port->lock before calling tty_flip_buffer_push()" broke sirfsoc uart
driver by knic:

	[    5.129122] BUG: spinlock already unlocked on CPU#0, ip6tables/1331
	[    5.132554]  lock: sirfsoc_uart_ports+0x4/0x8a0, .magic: dead4ead,
	.owner: <none>/-1, .owner_cpu: -1
	[    5.141651] CPU: 0 PID: 1331 Comm: ip6tables Tainted: G
	W  O 3.10.16 #3
	[    5.148866] [<c0013528>] (unwind_backtrace+0x0/0xe0) from
	[<c0010e70>] (show_stack+0x10/0x14)
	[    5.157362] [<c0010e70>] (show_stack+0x10/0x14) from
	[<c01a5e68>] (do_raw_spin_unlock+0x40/0xc8)
	[    5.166125] [<c01a5e68>] (do_raw_spin_unlock+0x40/0xc8) from
	[<c03ff8b4>] (_raw_spin_unlock+0x8/0x40)
	[    5.175322] [<c03ff8b4>] (_raw_spin_unlock+0x8/0x40) from
	[<c0203fcc>] (sirfsoc_uart_pio_rx_chars+0xa4/0xc0)
	[    5.185120] [<c0203fcc>]
	(sirfsoc_uart_pio_rx_chars+0xa4/0xc0) from [<c0204fb8>]
	(sirfsoc_rx_tmo_process_tl+0xdc/0x1e0)
	[    5.195875] [<c0204fb8>]
	(sirfsoc_rx_tmo_process_tl+0xdc/0x1e0) from [<c0024b50>]
	(tasklet_action+0x8c/0xec)
	[    5.205673] [<c0024b50>] (tasklet_action+0x8c/0xec) from
	[<c00242a8>] (__do_softirq+0xec/0x1d4)
	[    5.214347] [<c00242a8>] (__do_softirq+0xec/0x1d4) from
	[<c0024428>] (do_softirq+0x48/0x54)
	[    5.222674] [<c0024428>] (do_softirq+0x48/0x54) from
	[<c0024690>] (irq_exit+0x74/0xc0)
	[    5.230573] [<c0024690>] (irq_exit+0x74/0xc0) from
	[<c000e1e8>] (handle_IRQ+0x6c/0x90)
	[    5.238465] [<c000e1e8>] (handle_IRQ+0x6c/0x90) from
	[<c000d500>] (__irq_svc+0x40/0x70)
	[    5.246446] [<c000d500>] (__irq_svc+0x40/0x70) from
	[<c0092e7c>] (mark_page_accessed+0xc/0x68)
	[    5.255034] [<c0092e7c>] (mark_page_accessed+0xc/0x68) from
	[<c00a2a4c>] (unmap_single_vma+0x3bc/0x550)
	[    5.264402] [<c00a2a4c>] (unmap_single_vma+0x3bc/0x550) from
	[<c00a3b4c>] (unmap_vmas+0x44/0x54)
	[    5.273164] [<c00a3b4c>] (unmap_vmas+0x44/0x54) from
	[<c00a81a8>] (exit_mmap+0xc4/0x1e0)
	[    5.281233] [<c00a81a8>] (exit_mmap+0xc4/0x1e0) from
	[<c001bb78>] (mmput+0x3c/0xdc)
	[    5.288868] [<c001bb78>] (mmput+0x3c/0xdc) from [<c0021b0c>]
	(do_exit+0x30c/0x828)
	[    5.296413] [<c0021b0c>] (do_exit+0x30c/0x828) from
	[<c0022dac>] (do_group_exit+0x4c/0xb0)
	[    5.304653] [<c0022dac>] (do_group_exit+0x4c/0xb0) from
	[<c0022e20>] (__wake_up_parent+0x0/0x18)

Root cause:
the commit dropped uart_port->lock before calling tty_flip_buffer_push(), but in sirfsoc-uart,
sirfsoc_uart_pio_rx_chars() can be called by sirfsoc_rx_tmo_process_tl(). here uart_port->lock
has not been taken yet. so that caused unpaired lock/unlock.

Solution:
This patch is doing a quick fix for that, it adds spin_lock/unlock(&port->lock) protect to
sirfsoc_uart_pio_rx_chars() in sirfsoc_rx_tmo_process_tl() to keep spin_lock/unlock in pair.

Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Cc: stable <stable@vger.kernel.org> # 3.12
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Qipan Li 2014-01-27 14:23:39 +08:00 committed by Greg Kroah-Hartman
parent 333c085e4b
commit fb78b81142

View File

@ -542,8 +542,10 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
SIRFUART_IO_MODE);
sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
spin_lock(&port->lock);
sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
spin_unlock(&port->lock);
if (sirfport->rx_io_count == 4) {
spin_lock_irqsave(&sirfport->rx_lock, flags);
sirfport->rx_io_count = 0;