Skip to content

Commit 0cc7c6c

Browse files
marekrgregkh
authored andcommitted
tty/serial: at91: Handle shutdown more safely
Interrupts were being cleaned up late in the shutdown handler, it is possible that an interrupt can occur and schedule a tasklet that runs after the port is cleaned up. There is a null dereference due to this race condition with the following stacktrace: [<c02092b0>] (atmel_tasklet_func+0x514/0x814) from [<c001fd34>] (tasklet_action+0x70/0xa8) [<c001fd34>] (tasklet_action+0x70/0xa8) from [<c001f60c>] (__do_softirq+0x90/0x144) [<c001f60c>] (__do_softirq+0x90/0x144) from [<c001fa18>] (irq_exit+0x40/0x4c) [<c001fa18>] (irq_exit+0x40/0x4c) from [<c000e298>] (handle_IRQ+0x64/0x84) [<c000e298>] (handle_IRQ+0x64/0x84) from [<c000d6c0>] (__irq_svc+0x40/0x50) [<c000d6c0>] (__irq_svc+0x40/0x50) from [<c0208060>] (atmel_rx_dma_release+0x88/0xb8) [<c0208060>] (atmel_rx_dma_release+0x88/0xb8) from [<c0209740>] (atmel_shutdown+0x104/0x160) [<c0209740>] (atmel_shutdown+0x104/0x160) from [<c0205e8c>] (uart_port_shutdown+0x2c/0x38) Signed-off-by: Marek Roszko <mark.roszko@gmail.com> Acked-by: Leilei Zhao <leilei.zhao@atmel.com> Cc: <stable@vger.kernel.org> # v3.12 Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent df8d4aa commit 0cc7c6c

File tree

1 file changed

+13
-7
lines changed

1 file changed

+13
-7
lines changed

drivers/tty/serial/atmel_serial.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,12 +1650,24 @@ static int atmel_startup(struct uart_port *port)
16501650
static void atmel_shutdown(struct uart_port *port)
16511651
{
16521652
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
1653+
16531654
/*
1654-
* Ensure everything is stopped.
1655+
* Clear out any scheduled tasklets before
1656+
* we destroy the buffers
1657+
*/
1658+
tasklet_kill(&atmel_port->tasklet);
1659+
1660+
/*
1661+
* Ensure everything is stopped and
1662+
* disable all interrupts, port and break condition.
16551663
*/
16561664
atmel_stop_rx(port);
16571665
atmel_stop_tx(port);
16581666

1667+
UART_PUT_CR(port, ATMEL_US_RSTSTA);
1668+
UART_PUT_IDR(port, -1);
1669+
1670+
16591671
/*
16601672
* Shut-down the DMA.
16611673
*/
@@ -1664,12 +1676,6 @@ static void atmel_shutdown(struct uart_port *port)
16641676
if (atmel_port->release_tx)
16651677
atmel_port->release_tx(port);
16661678

1667-
/*
1668-
* Disable all interrupts, port and break condition.
1669-
*/
1670-
UART_PUT_CR(port, ATMEL_US_RSTSTA);
1671-
UART_PUT_IDR(port, -1);
1672-
16731679
/*
16741680
* Free the interrupt
16751681
*/

0 commit comments

Comments
 (0)