diff mbox

[v5,1/2] serial: fsl_lpuart: Add DMA quirk

Message ID 1459806792-7729-2-git-send-email-andrew@lunn.ch (mailing list archive)
State New, archived
Headers show

Commit Message

Andrew Lunn April 4, 2016, 9:53 p.m. UTC
Using DMA with the vf610 and other Vybrid devices results in a corrupt
serial stream. Add a quirk to disable the use of DMA.

Refactor the existing code to add a 32 bit access quirk for the
fsl,ls1021a-lpuart.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/tty/serial/fsl_lpuart.c | 36 ++++++++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 10 deletions(-)

Comments

Stefan Agner April 5, 2016, 5:01 a.m. UTC | #1
On 2016-04-04 14:53, Andrew Lunn wrote:
> Using DMA with the vf610 and other Vybrid devices results in a corrupt
> serial stream. Add a quirk to disable the use of DMA.
> 
> Refactor the existing code to add a 32 bit access quirk for the
> fsl,ls1021a-lpuart.

Hi Andrew,

[also added Greg and Jiri, maintainers of the tty subsystem]

Well, I am not sure if that is the right approach. Quirks are usually
used to hint to issues in the hardware. However, in this case we deal
with (a) software issue(s)...

At Toradex we were carry a patch which disabled DMA by default using a
module parameter:
http://git.toradex.com/cgit/linux-toradex.git/commit/?h=toradex_vf_4.4-next&id=f5baad61b77dd4b0ac0c7beeee284e12d49ba442

This allowed to re-enable the DMA easily for testing... Not sure if that
is the better approach.

However, we are working on a re-implementation of the DMA modes, I hope
we can post some patches soon.

IMHO we can just omit adding such a disable work around, people lived
with the current situation since 3.13, one more release probably doesn't
really matter... :-)

--
Stefan


> 
> Signed-off-by: Andrew Lunn <andrew@lunn.ch>
> ---
>  drivers/tty/serial/fsl_lpuart.c | 36 ++++++++++++++++++++++++++----------
>  1 file changed, 26 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
> index 3d790033744e..8d2f67b93e1f 100644
> --- a/drivers/tty/serial/fsl_lpuart.c
> +++ b/drivers/tty/serial/fsl_lpuart.c
> @@ -257,12 +257,17 @@ struct lpuart_port {
>  	struct timer_list	lpuart_timer;
>  };
>  
> +#define QUIRK_LPUART32		BIT(0)
> +#define QUIRK_NO_DMA		BIT(1)
> +
>  static const struct of_device_id lpuart_dt_ids[] = {
>  	{
>  		.compatible = "fsl,vf610-lpuart",
> +		.data = (void *)QUIRK_NO_DMA,
>  	},
>  	{
>  		.compatible = "fsl,ls1021a-lpuart",
> +		.data = (void *)QUIRK_LPUART32,
>  	},
>  	{ /* sentinel */ }
>  };
> @@ -1803,7 +1808,9 @@ static struct uart_driver lpuart_reg = {
>  static int lpuart_probe(struct platform_device *pdev)
>  {
>  	struct device_node *np = pdev->dev.of_node;
> +	const struct of_device_id *match;
>  	struct lpuart_port *sport;
> +	kernel_ulong_t quirks;
>  	struct resource *res;
>  	int ret;
>  
> @@ -1819,7 +1826,10 @@ static int lpuart_probe(struct platform_device *pdev)
>  		return ret;
>  	}
>  	sport->port.line = ret;
> -	sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart");
> +
> +	match = of_match_node(lpuart_dt_ids, np);
> +	quirks = (kernel_ulong_t)match->data;
> +	sport->lpuart32 = quirks & QUIRK_LPUART32;
>  
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	sport->port.membase = devm_ioremap_resource(&pdev->dev, res);
> @@ -1867,15 +1877,21 @@ static int lpuart_probe(struct platform_device *pdev)
>  		return ret;
>  	}
>  
> -	sport->dma_tx_chan = dma_request_slave_channel(sport->port.dev, "tx");
> -	if (!sport->dma_tx_chan)
> -		dev_info(sport->port.dev, "DMA tx channel request failed, "
> -				"operating without tx DMA\n");
> -
> -	sport->dma_rx_chan = dma_request_slave_channel(sport->port.dev, "rx");
> -	if (!sport->dma_rx_chan)
> -		dev_info(sport->port.dev, "DMA rx channel request failed, "
> -				"operating without rx DMA\n");
> +	if (quirks & QUIRK_NO_DMA) {
> +		dev_info(sport->port.dev, "Not using DMA\n");
> +	} else {
> +		sport->dma_tx_chan = dma_request_slave_channel(
> +			sport->port.dev, "tx");
> +		if (!sport->dma_tx_chan)
> +			dev_info(sport->port.dev,
> +				 "DMA tx channel request failed, operating without tx DMA\n");
> +
> +		sport->dma_rx_chan = dma_request_slave_channel(
> +			sport->port.dev, "rx");
> +		if (!sport->dma_rx_chan)
> +			dev_info(sport->port.dev,
> +				 "DMA rx channel request failed, operating without rx DMA\n");
> +	}
>  
>  	return 0;
>  }
Andrew Lunn April 5, 2016, 1:42 p.m. UTC | #2
On Mon, Apr 04, 2016 at 10:01:12PM -0700, Stefan Agner wrote:
> On 2016-04-04 14:53, Andrew Lunn wrote:
> > Using DMA with the vf610 and other Vybrid devices results in a corrupt
> > serial stream. Add a quirk to disable the use of DMA.
> > 
> > Refactor the existing code to add a 32 bit access quirk for the
> > fsl,ls1021a-lpuart.
> 
> Hi Andrew,
> 
> [also added Greg and Jiri, maintainers of the tty subsystem]
> 
> Well, I am not sure if that is the right approach. Quirks are usually
> used to hint to issues in the hardware. However, in this case we deal
> with (a) software issue(s)...

I've been lazy and not investigated what is happening. I'm using the
serial port for console, so don't need performance. However, when it
does corrupt the stream, minicom tends to go crazy, and i have to
reset it to get a working console.

Have you investigated it sufficiently to be sure it is a software
issue?

> At Toradex we were carry a patch which disabled DMA by default using a
> module parameter:
> http://git.toradex.com/cgit/linux-toradex.git/commit/?h=toradex_vf_4.4-next&id=f5baad61b77dd4b0ac0c7beeee284e12d49ba442

Module parameters are frowned upon. Also, once this issue is fixed,
they often leave cruft behind, e.g. in bootloaders configuration. The
advantage of the quirk is that it purely in the driver. When the
driver is fixed, the quirk code can be cleanly removed.

> This allowed to re-enable the DMA easily for testing... Not sure if that
> is the better approach.

If you are testing, you are modifying the driver anyway. It is very
easy to remove the quirk bit to re-enable DMA.

> IMHO we can just omit adding such a disable work around, people lived
> with the current situation since 3.13, one more release probably doesn't
> really matter... :-)

People lived with it by hacking the dts file with empty dma
nodes. Compared to that, a quirk is cleaner.

       Andrew
diff mbox

Patch

diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 3d790033744e..8d2f67b93e1f 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -257,12 +257,17 @@  struct lpuart_port {
 	struct timer_list	lpuart_timer;
 };
 
+#define QUIRK_LPUART32		BIT(0)
+#define QUIRK_NO_DMA		BIT(1)
+
 static const struct of_device_id lpuart_dt_ids[] = {
 	{
 		.compatible = "fsl,vf610-lpuart",
+		.data = (void *)QUIRK_NO_DMA,
 	},
 	{
 		.compatible = "fsl,ls1021a-lpuart",
+		.data = (void *)QUIRK_LPUART32,
 	},
 	{ /* sentinel */ }
 };
@@ -1803,7 +1808,9 @@  static struct uart_driver lpuart_reg = {
 static int lpuart_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
+	const struct of_device_id *match;
 	struct lpuart_port *sport;
+	kernel_ulong_t quirks;
 	struct resource *res;
 	int ret;
 
@@ -1819,7 +1826,10 @@  static int lpuart_probe(struct platform_device *pdev)
 		return ret;
 	}
 	sport->port.line = ret;
-	sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart");
+
+	match = of_match_node(lpuart_dt_ids, np);
+	quirks = (kernel_ulong_t)match->data;
+	sport->lpuart32 = quirks & QUIRK_LPUART32;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	sport->port.membase = devm_ioremap_resource(&pdev->dev, res);
@@ -1867,15 +1877,21 @@  static int lpuart_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	sport->dma_tx_chan = dma_request_slave_channel(sport->port.dev, "tx");
-	if (!sport->dma_tx_chan)
-		dev_info(sport->port.dev, "DMA tx channel request failed, "
-				"operating without tx DMA\n");
-
-	sport->dma_rx_chan = dma_request_slave_channel(sport->port.dev, "rx");
-	if (!sport->dma_rx_chan)
-		dev_info(sport->port.dev, "DMA rx channel request failed, "
-				"operating without rx DMA\n");
+	if (quirks & QUIRK_NO_DMA) {
+		dev_info(sport->port.dev, "Not using DMA\n");
+	} else {
+		sport->dma_tx_chan = dma_request_slave_channel(
+			sport->port.dev, "tx");
+		if (!sport->dma_tx_chan)
+			dev_info(sport->port.dev,
+				 "DMA tx channel request failed, operating without tx DMA\n");
+
+		sport->dma_rx_chan = dma_request_slave_channel(
+			sport->port.dev, "rx");
+		if (!sport->dma_rx_chan)
+			dev_info(sport->port.dev,
+				 "DMA rx channel request failed, operating without rx DMA\n");
+	}
 
 	return 0;
 }