Skip to content

Commit

Permalink
tty/serial: at91: Handle shutdown more safely
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Marek Roszko authored and Greg Kroah-Hartman committed Jan 8, 2014
1 parent df8d4aa commit 0cc7c6c
Showing 1 changed file with 13 additions and 7 deletions.
20 changes: 13 additions & 7 deletions drivers/tty/serial/atmel_serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -1650,12 +1650,24 @@ static int atmel_startup(struct uart_port *port)
static void atmel_shutdown(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);

/*
* Ensure everything is stopped.
* Clear out any scheduled tasklets before
* we destroy the buffers
*/
tasklet_kill(&atmel_port->tasklet);

/*
* Ensure everything is stopped and
* disable all interrupts, port and break condition.
*/
atmel_stop_rx(port);
atmel_stop_tx(port);

UART_PUT_CR(port, ATMEL_US_RSTSTA);
UART_PUT_IDR(port, -1);


/*
* Shut-down the DMA.
*/
Expand All @@ -1664,12 +1676,6 @@ static void atmel_shutdown(struct uart_port *port)
if (atmel_port->release_tx)
atmel_port->release_tx(port);

/*
* Disable all interrupts, port and break condition.
*/
UART_PUT_CR(port, ATMEL_US_RSTSTA);
UART_PUT_IDR(port, -1);

/*
* Free the interrupt
*/
Expand Down

0 comments on commit 0cc7c6c

Please sign in to comment.