Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ec5a11a9 authored by Peter Hurley's avatar Peter Hurley Committed by Greg Kroah-Hartman
Browse files

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: default avatarPeter Hurley <peter@hurleysoftware.com>
Reviewed-by: default avatarHeikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 06c5e362
Loading
Loading
Loading
Loading
+21 −6
Original line number Diff line number Diff line
@@ -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);