Skip to content

Commit

Permalink
serial: samsung: check DMA engine capabilities before using DMA mode
Browse files Browse the repository at this point in the history
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 <m.szyprowski@samsung.com>
Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Marek Szyprowski authored and Greg Kroah-Hartman committed May 24, 2018
1 parent b6da31b commit d8db840
Showing 1 changed file with 29 additions and 4 deletions.
33 changes: 29 additions & 4 deletions drivers/tty/serial/samsung.c
Original file line number Diff line number Diff line change
Expand Up @@ -856,6 +856,8 @@ static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
{
struct s3c24xx_uart_dma *dma = p->dma;
struct dma_slave_caps dma_caps;
const char *reason = NULL;
int ret;

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

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

if (IS_ERR(dma->rx_chan))
return PTR_ERR(dma->rx_chan);
if (IS_ERR(dma->rx_chan)) {
reason = "DMA RX channel request failed";
ret = PTR_ERR(dma->rx_chan);
goto err_warn;
}

ret = dma_get_slave_caps(dma->rx_chan, &dma_caps);
if (ret < 0 ||
dma_caps.residue_granularity < DMA_RESIDUE_GRANULARITY_BURST) {
reason = "insufficient DMA RX engine capabilities";
ret = -EOPNOTSUPP;
goto err_release_rx;
}

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

dma->tx_chan = dma_request_chan(p->port.dev, "tx");
if (IS_ERR(dma->tx_chan)) {
reason = "DMA TX channel request failed";
ret = PTR_ERR(dma->tx_chan);
goto err_release_rx;
}

ret = dma_get_slave_caps(dma->tx_chan, &dma_caps);
if (ret < 0 ||
dma_caps.residue_granularity < DMA_RESIDUE_GRANULARITY_BURST) {
reason = "insufficient DMA TX engine capabilities";
ret = -EOPNOTSUPP;
goto err_release_tx;
}

dmaengine_slave_config(dma->tx_chan, &dma->tx_conf);

/* RX buffer */
Expand All @@ -896,6 +918,7 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
dma->rx_addr = dma_map_single(p->port.dev, dma->rx_buf,
dma->rx_size, DMA_FROM_DEVICE);
if (dma_mapping_error(p->port.dev, dma->rx_addr)) {
reason = "DMA mapping error for RX buffer";
ret = -EIO;
goto err_free_rx;
}
Expand All @@ -904,6 +927,7 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
dma->tx_addr = dma_map_single(p->port.dev, p->port.state->xmit.buf,
UART_XMIT_SIZE, DMA_TO_DEVICE);
if (dma_mapping_error(p->port.dev, dma->tx_addr)) {
reason = "DMA mapping error for TX buffer";
ret = -EIO;
goto err_unmap_rx;
}
Expand All @@ -919,6 +943,9 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
dma_release_channel(dma->tx_chan);
err_release_rx:
dma_release_channel(dma->rx_chan);
err_warn:
if (reason)
dev_warn(p->port.dev, "%s, DMA will not be used\n", reason);
return ret;
}

Expand Down Expand Up @@ -1037,8 +1064,6 @@ static int s3c64xx_serial_startup(struct uart_port *port)
if (ourport->dma) {
ret = s3c24xx_serial_request_dma(ourport);
if (ret < 0) {
dev_warn(port->dev,
"DMA request failed, DMA will not be used\n");
devm_kfree(port->dev, ourport->dma);
ourport->dma = NULL;
}
Expand Down

0 comments on commit d8db840

Please sign in to comment.