From: Marek Szyprowski Date: Thu, 17 May 2018 11:37:14 +0000 (+0200) Subject: serial: samsung: check DMA engine capabilities before using DMA mode X-Git-Tag: v5.15~8711^2~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d8db840dcb9e6d9d7f3d2527a3f96c6bb07414f7;p=platform%2Fkernel%2Flinux-starfive.git 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 Reviewed-by: Krzysztof Kozlowski Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 64e9692..2f8fa18 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -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 @@ err_release_tx: 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; }