diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 540a746b87f2cd..c56e7a389a19e4 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1763,12 +1763,31 @@ 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); + + /* + * Prevent any tasklets being scheduled during + * cleanup + */ + if (!atmel_port->is_usart) + del_timer_sync(&atmel_port->uart_timer); + /* - * 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. */ @@ -1784,9 +1803,6 @@ static void atmel_shutdown(struct uart_port *port) DMA_FROM_DEVICE); kfree(pdc->buf); } - - if (!atmel_port->is_usart) - del_timer_sync(&atmel_port->uart_timer); } if (atmel_use_pdc_tx(port)) { struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; @@ -1802,12 +1818,6 @@ static void atmel_shutdown(struct uart_port *port) if (atmel_use_dma_tx(port)) atmel_tx_dma_release(atmel_port); - /* - * Disable all interrupts, port and break condition. - */ - UART_PUT_CR(port, ATMEL_US_RSTSTA); - UART_PUT_IDR(port, -1); - /* * Free the interrupt */ @@ -2670,12 +2680,13 @@ static int __devexit atmel_serial_remove(struct platform_device *pdev) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); int ret = 0; + tasklet_kill(&atmel_port->tasklet); + device_init_wakeup(&pdev->dev, 0); platform_set_drvdata(pdev, NULL); ret = uart_remove_one_port(&atmel_uart, port); - tasklet_kill(&atmel_port->tasklet); kfree(atmel_port->rx_ring.buf); /* "port" is allocated statically, so we shouldn't free it */