Skip to content

Commit ad909b3

Browse files
jonhuntergregkh
authored andcommitted
serial: tegra: Correct error handling on DMA setup
Function tegra_uart_dma_channel_allocate() does not check that dma_map_single() mapped the DMA buffer correctly. Add a check for this and appropriate error handling. Furthermore, if dmaengine_slave_config() (called by tegra_uart_dma_channel_allocate()) fails, then memory allocated/mapped is not freed/unmapped. Therefore, call tegra_uart_dma_channel_free() instead of just dma_release_channel() if dmaengine_slave_config() fails. Signed-off-by: Jon Hunter <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent d92aca3 commit ad909b3

File tree

1 file changed

+28
-23
lines changed

1 file changed

+28
-23
lines changed

drivers/tty/serial/serial-tegra.c

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,28 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)
949949
return 0;
950950
}
951951

952+
static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup,
953+
bool dma_to_memory)
954+
{
955+
if (dma_to_memory) {
956+
dmaengine_terminate_all(tup->rx_dma_chan);
957+
dma_release_channel(tup->rx_dma_chan);
958+
dma_free_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE,
959+
tup->rx_dma_buf_virt, tup->rx_dma_buf_phys);
960+
tup->rx_dma_chan = NULL;
961+
tup->rx_dma_buf_phys = 0;
962+
tup->rx_dma_buf_virt = NULL;
963+
} else {
964+
dmaengine_terminate_all(tup->tx_dma_chan);
965+
dma_release_channel(tup->tx_dma_chan);
966+
dma_unmap_single(tup->uport.dev, tup->tx_dma_buf_phys,
967+
UART_XMIT_SIZE, DMA_TO_DEVICE);
968+
tup->tx_dma_chan = NULL;
969+
tup->tx_dma_buf_phys = 0;
970+
tup->tx_dma_buf_virt = NULL;
971+
}
972+
}
973+
952974
static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup,
953975
bool dma_to_memory)
954976
{
@@ -981,6 +1003,11 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup,
9811003
dma_phys = dma_map_single(tup->uport.dev,
9821004
tup->uport.state->xmit.buf, UART_XMIT_SIZE,
9831005
DMA_TO_DEVICE);
1006+
if (dma_mapping_error(tup->uport.dev, dma_phys)) {
1007+
dev_err(tup->uport.dev, "dma_map_single tx failed\n");
1008+
dma_release_channel(dma_chan);
1009+
return -ENOMEM;
1010+
}
9841011
dma_buf = tup->uport.state->xmit.buf;
9851012
}
9861013

@@ -1013,32 +1040,10 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup,
10131040
return 0;
10141041

10151042
scrub:
1016-
dma_release_channel(dma_chan);
1043+
tegra_uart_dma_channel_free(tup, dma_to_memory);
10171044
return ret;
10181045
}
10191046

1020-
static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup,
1021-
bool dma_to_memory)
1022-
{
1023-
if (dma_to_memory) {
1024-
dmaengine_terminate_all(tup->rx_dma_chan);
1025-
dma_release_channel(tup->rx_dma_chan);
1026-
dma_free_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE,
1027-
tup->rx_dma_buf_virt, tup->rx_dma_buf_phys);
1028-
tup->rx_dma_chan = NULL;
1029-
tup->rx_dma_buf_phys = 0;
1030-
tup->rx_dma_buf_virt = NULL;
1031-
} else {
1032-
dmaengine_terminate_all(tup->tx_dma_chan);
1033-
dma_release_channel(tup->tx_dma_chan);
1034-
dma_unmap_single(tup->uport.dev, tup->tx_dma_buf_phys,
1035-
UART_XMIT_SIZE, DMA_TO_DEVICE);
1036-
tup->tx_dma_chan = NULL;
1037-
tup->tx_dma_buf_phys = 0;
1038-
tup->tx_dma_buf_virt = NULL;
1039-
}
1040-
}
1041-
10421047
static int tegra_uart_startup(struct uart_port *u)
10431048
{
10441049
struct tegra_uart_port *tup = to_tegra_uport(u);

0 commit comments

Comments
 (0)