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;
|
struct uart_8250_dma *dma = p->dma;
|
||||||
dma_cap_mask_t mask;
|
dma_cap_mask_t mask;
|
||||||
|
struct dma_slave_caps caps;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* Default slave configuration parameters */
|
/* Default slave configuration parameters */
|
||||||
dma->rxconf.direction = DMA_DEV_TO_MEM;
|
dma->rxconf.direction = DMA_DEV_TO_MEM;
|
||||||
|
@ -178,6 +180,16 @@ int serial8250_request_dma(struct uart_8250_port *p)
|
||||||
if (!dma->rxchan)
|
if (!dma->rxchan)
|
||||||
return -ENODEV;
|
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);
|
dmaengine_slave_config(dma->rxchan, &dma->rxconf);
|
||||||
|
|
||||||
/* Get a channel for TX */
|
/* Get a channel for TX */
|
||||||
|
@ -185,8 +197,8 @@ int serial8250_request_dma(struct uart_8250_port *p)
|
||||||
dma->fn, dma->tx_param,
|
dma->fn, dma->tx_param,
|
||||||
p->port.dev, "tx");
|
p->port.dev, "tx");
|
||||||
if (!dma->txchan) {
|
if (!dma->txchan) {
|
||||||
dma_release_channel(dma->rxchan);
|
ret = -ENODEV;
|
||||||
return -ENODEV;
|
goto release_rx;
|
||||||
}
|
}
|
||||||
|
|
||||||
dmaengine_slave_config(dma->txchan, &dma->txconf);
|
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_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,
|
||||||
&dma->rx_addr, GFP_KERNEL);
|
&dma->rx_addr, GFP_KERNEL);
|
||||||
if (!dma->rx_buf)
|
if (!dma->rx_buf) {
|
||||||
|
ret = -ENOMEM;
|
||||||
goto err;
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
/* TX buffer */
|
/* TX buffer */
|
||||||
dma->tx_addr = dma_map_single(dma->txchan->device->dev,
|
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)) {
|
if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) {
|
||||||
dma_free_coherent(dma->rxchan->device->dev, dma->rx_size,
|
dma_free_coherent(dma->rxchan->device->dev, dma->rx_size,
|
||||||
dma->rx_buf, dma->rx_addr);
|
dma->rx_buf, dma->rx_addr);
|
||||||
|
ret = -ENOMEM;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,10 +230,10 @@ int serial8250_request_dma(struct uart_8250_port *p)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
err:
|
err:
|
||||||
dma_release_channel(dma->rxchan);
|
|
||||||
dma_release_channel(dma->txchan);
|
dma_release_channel(dma->txchan);
|
||||||
|
release_rx:
|
||||||
return -ENOMEM;
|
dma_release_channel(dma->rxchan);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(serial8250_request_dma);
|
EXPORT_SYMBOL_GPL(serial8250_request_dma);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue