Skip to content

Commit d8db840

Browse files
mszyprowgregkh
authored andcommitted
serial: samsung: check DMA engine capabilities before using DMA mode
DMA engine driver might not always provide all the features needed by serial driver to properly operate in DMA mode, so check that before selecting DMA mode. Signed-off-by: Marek Szyprowski <[email protected]> Reviewed-by: Krzysztof Kozlowski <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent b6da31b commit d8db840

File tree

1 file changed

+29
-4
lines changed

1 file changed

+29
-4
lines changed

drivers/tty/serial/samsung.c

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,8 @@ static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
856856
static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
857857
{
858858
struct s3c24xx_uart_dma *dma = p->dma;
859+
struct dma_slave_caps dma_caps;
860+
const char *reason = NULL;
859861
int ret;
860862

861863
/* Default slave configuration parameters */
@@ -871,17 +873,37 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
871873

872874
dma->rx_chan = dma_request_chan(p->port.dev, "rx");
873875

874-
if (IS_ERR(dma->rx_chan))
875-
return PTR_ERR(dma->rx_chan);
876+
if (IS_ERR(dma->rx_chan)) {
877+
reason = "DMA RX channel request failed";
878+
ret = PTR_ERR(dma->rx_chan);
879+
goto err_warn;
880+
}
881+
882+
ret = dma_get_slave_caps(dma->rx_chan, &dma_caps);
883+
if (ret < 0 ||
884+
dma_caps.residue_granularity < DMA_RESIDUE_GRANULARITY_BURST) {
885+
reason = "insufficient DMA RX engine capabilities";
886+
ret = -EOPNOTSUPP;
887+
goto err_release_rx;
888+
}
876889

877890
dmaengine_slave_config(dma->rx_chan, &dma->rx_conf);
878891

879892
dma->tx_chan = dma_request_chan(p->port.dev, "tx");
880893
if (IS_ERR(dma->tx_chan)) {
894+
reason = "DMA TX channel request failed";
881895
ret = PTR_ERR(dma->tx_chan);
882896
goto err_release_rx;
883897
}
884898

899+
ret = dma_get_slave_caps(dma->tx_chan, &dma_caps);
900+
if (ret < 0 ||
901+
dma_caps.residue_granularity < DMA_RESIDUE_GRANULARITY_BURST) {
902+
reason = "insufficient DMA TX engine capabilities";
903+
ret = -EOPNOTSUPP;
904+
goto err_release_tx;
905+
}
906+
885907
dmaengine_slave_config(dma->tx_chan, &dma->tx_conf);
886908

887909
/* RX buffer */
@@ -896,6 +918,7 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
896918
dma->rx_addr = dma_map_single(p->port.dev, dma->rx_buf,
897919
dma->rx_size, DMA_FROM_DEVICE);
898920
if (dma_mapping_error(p->port.dev, dma->rx_addr)) {
921+
reason = "DMA mapping error for RX buffer";
899922
ret = -EIO;
900923
goto err_free_rx;
901924
}
@@ -904,6 +927,7 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
904927
dma->tx_addr = dma_map_single(p->port.dev, p->port.state->xmit.buf,
905928
UART_XMIT_SIZE, DMA_TO_DEVICE);
906929
if (dma_mapping_error(p->port.dev, dma->tx_addr)) {
930+
reason = "DMA mapping error for TX buffer";
907931
ret = -EIO;
908932
goto err_unmap_rx;
909933
}
@@ -919,6 +943,9 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
919943
dma_release_channel(dma->tx_chan);
920944
err_release_rx:
921945
dma_release_channel(dma->rx_chan);
946+
err_warn:
947+
if (reason)
948+
dev_warn(p->port.dev, "%s, DMA will not be used\n", reason);
922949
return ret;
923950
}
924951

@@ -1037,8 +1064,6 @@ static int s3c64xx_serial_startup(struct uart_port *port)
10371064
if (ourport->dma) {
10381065
ret = s3c24xx_serial_request_dma(ourport);
10391066
if (ret < 0) {
1040-
dev_warn(port->dev,
1041-
"DMA request failed, DMA will not be used\n");
10421067
devm_kfree(port->dev, ourport->dma);
10431068
ourport->dma = NULL;
10441069
}

0 commit comments

Comments
 (0)