提交 d8db840d 编写于 作者: M Marek Szyprowski 提交者: Greg Kroah-Hartman

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: NMarek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: NKrzysztof Kozlowski <krzk@kernel.org>
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
上级 b6da31b2
......@@ -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 */
......@@ -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 */
......@@ -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;
}
......@@ -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;
}
......@@ -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;
}
......@@ -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;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册