serial: 8250: Validate dmaengine rx chan meets requirements

8250 dma support requires the dmaengine driver support error-free
pause/terminate and better-than-descriptor residue granularity. Query
slave caps to determine if necessary commands/properties are supported;
disable dma if not.

Note this means dmaengine driver must support slave caps reporting
as well.

Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Peter Hurley 2016-04-09 22:14:32 -07:00 committed by Greg Kroah-Hartman
parent 06c5e362ce
commit ec5a11a91e

View File

@ -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);