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:
parent
06c5e362ce
commit
ec5a11a91e
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue