Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d92aca3a authored by Jon Hunter's avatar Jon Hunter Committed by Greg Kroah-Hartman
Browse files

serial: tegra: Correct shutdown of UARTs



There are two issues in the shutdown path of the UARTs which are:
1. The function tegra_uart_shutdown() calls tegra_uart_flush_buffer()
   to stop DMA TX transfers. However, tegra_uart_flush_buffer() is
   called after the DMA channels have already been freed and so actually
   does nothing.
2. The function that frees the DMA channels
   (tegra_uart_dma_channel_free()), unmaps the dma buffer before
   freeing the DMA channel and does not ensure the DMA has been
   stopped.

Resolve this by fixing the code in tegra_uart_dma_channel_free() to
ensure the DMA is stopped, free the DMA channel and then unmap the DMA
buffer. Finally, remove the unnecessary call to tegra_uart_flush_buffer().

Signed-off-by: default avatarJon Hunter <jonathanh@nvidia.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 49433c80
Loading
Loading
Loading
Loading
+4 −7
Original line number Original line Diff line number Diff line
@@ -1020,24 +1020,23 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup,
static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup,
static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup,
		bool dma_to_memory)
		bool dma_to_memory)
{
{
	struct dma_chan *dma_chan;

	if (dma_to_memory) {
	if (dma_to_memory) {
		dmaengine_terminate_all(tup->rx_dma_chan);
		dma_release_channel(tup->rx_dma_chan);
		dma_free_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE,
		dma_free_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE,
				tup->rx_dma_buf_virt, tup->rx_dma_buf_phys);
				tup->rx_dma_buf_virt, tup->rx_dma_buf_phys);
		dma_chan = tup->rx_dma_chan;
		tup->rx_dma_chan = NULL;
		tup->rx_dma_chan = NULL;
		tup->rx_dma_buf_phys = 0;
		tup->rx_dma_buf_phys = 0;
		tup->rx_dma_buf_virt = NULL;
		tup->rx_dma_buf_virt = NULL;
	} else {
	} else {
		dmaengine_terminate_all(tup->tx_dma_chan);
		dma_release_channel(tup->tx_dma_chan);
		dma_unmap_single(tup->uport.dev, tup->tx_dma_buf_phys,
		dma_unmap_single(tup->uport.dev, tup->tx_dma_buf_phys,
			UART_XMIT_SIZE, DMA_TO_DEVICE);
			UART_XMIT_SIZE, DMA_TO_DEVICE);
		dma_chan = tup->tx_dma_chan;
		tup->tx_dma_chan = NULL;
		tup->tx_dma_chan = NULL;
		tup->tx_dma_buf_phys = 0;
		tup->tx_dma_buf_phys = 0;
		tup->tx_dma_buf_virt = NULL;
		tup->tx_dma_buf_virt = NULL;
	}
	}
	dma_release_channel(dma_chan);
}
}


static int tegra_uart_startup(struct uart_port *u)
static int tegra_uart_startup(struct uart_port *u)
@@ -1104,8 +1103,6 @@ static void tegra_uart_shutdown(struct uart_port *u)
	tegra_uart_dma_channel_free(tup, true);
	tegra_uart_dma_channel_free(tup, true);
	tegra_uart_dma_channel_free(tup, false);
	tegra_uart_dma_channel_free(tup, false);
	free_irq(u->irq, tup);
	free_irq(u->irq, tup);

	tegra_uart_flush_buffer(u);
}
}


static void tegra_uart_enable_ms(struct uart_port *u)
static void tegra_uart_enable_ms(struct uart_port *u)