Skip to content

Commit

Permalink
serial: 8250: Validate dmaengine rx chan meets requirements
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Heikki Krogerus <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
peterhurley authored and gregkh committed Apr 30, 2016
1 parent 06c5e36 commit ec5a11a
Showing 1 changed file with 21 additions and 6 deletions.
27 changes: 21 additions & 6 deletions drivers/tty/serial/8250/8250_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -178,15 +180,25 @@ 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 */
dma->txchan = dma_request_slave_channel_compat(mask,
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);
Expand All @@ -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,
Expand All @@ -208,17 +222,18 @@ 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;
}

dev_dbg_ratelimited(p->port.dev, "got both dma channels\n");

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

Expand Down

0 comments on commit ec5a11a

Please sign in to comment.