diff options
-rw-r--r-- | drivers/tty/serial/8250/8250_dma.c | 27 |
1 files changed, 21 insertions, 6 deletions
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index 78259d3c6a55..cf7a2e3288a6 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -158,6 +158,8 @@ int serial8250_request_dma(struct uart_8250_port *p) { struct uart_8250_dma *dma = p->dma; dma_cap_mask_t mask; + struct dma_slave_caps caps; + int ret; /* Default slave configuration parameters */ dma->rxconf.direction = DMA_DEV_TO_MEM; @@ -178,6 +180,16 @@ int serial8250_request_dma(struct uart_8250_port *p) if (!dma->rxchan) return -ENODEV; + /* 8250 rx dma requires dmaengine driver to support pause/terminate */ + ret = dma_get_slave_caps(dma->rxchan, &caps); + if (ret) + goto release_rx; + if (!caps.cmd_pause || !caps.cmd_terminate || + caps.residue_granularity == DMA_RESIDUE_GRANULARITY_DESCRIPTOR) { + ret = -EINVAL; + goto release_rx; + } + dmaengine_slave_config(dma->rxchan, &dma->rxconf); /* Get a channel for TX */ @@ -185,8 +197,8 @@ int serial8250_request_dma(struct uart_8250_port *p) dma->fn, dma->tx_param, p->port.dev, "tx"); if (!dma->txchan) { - dma_release_channel(dma->rxchan); - return -ENODEV; + ret = -ENODEV; + goto release_rx; } dmaengine_slave_config(dma->txchan, &dma->txconf); @@ -197,8 +209,10 @@ int serial8250_request_dma(struct uart_8250_port *p) dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size, &dma->rx_addr, GFP_KERNEL); - if (!dma->rx_buf) + if (!dma->rx_buf) { + ret = -ENOMEM; goto err; + } /* TX buffer */ dma->tx_addr = dma_map_single(dma->txchan->device->dev, @@ -208,6 +222,7 @@ int serial8250_request_dma(struct uart_8250_port *p) if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) { dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf, dma->rx_addr); + ret = -ENOMEM; goto err; } @@ -215,10 +230,10 @@ int serial8250_request_dma(struct uart_8250_port *p) return 0; err: - dma_release_channel(dma->rxchan); dma_release_channel(dma->txchan); - - return -ENOMEM; +release_rx: + dma_release_channel(dma->rxchan); + return ret; } EXPORT_SYMBOL_GPL(serial8250_request_dma); |