linux-serial.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/1] serial: 8250_dma: Rearm DMA Rx if more data is pending
@ 2022-11-07 10:21 Ilpo Järvinen
  2022-11-07 11:31 ` Andy Shevchenko
  0 siblings, 1 reply; 3+ messages in thread
From: Ilpo Järvinen @ 2022-11-07 10:21 UTC (permalink / raw)
  To: Andy Shevchenko, Greg Kroah-Hartman, Jiri Slaby, linux-serial,
	linux-kernel
  Cc: Ilpo Järvinen, Gilles BULOZ

When DMA Rx completes, the current behavior is to just exit the DMA
completion handler without future actions. If the transfer is still
on-going, UART will trigger an interrupt and that eventually rearms the
DMA Rx. The extra interrupt round-trip has an inherent latency cost
that increases the risk of FIFO overrun. In such situations, the
latency margin tends to already be less due to FIFO not being empty.

Add check into DMA Rx completion handler to detect if LSR has DR (Data
Ready) still set. DR indicates there will be more characters pending
and DMA Rx can be rearmed right away to handle them.

Cc: Gilles BULOZ <gilles.buloz@kontron.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
 drivers/tty/serial/8250/8250_dma.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index b85c82616e8c..37d6af2ec427 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -38,9 +38,8 @@ static void __dma_tx_complete(void *param)
 	spin_unlock_irqrestore(&p->port.lock, flags);
 }
 
-static void __dma_rx_complete(void *param)
+static void __dma_rx_complete(struct uart_8250_port *p)
 {
-	struct uart_8250_port	*p = param;
 	struct uart_8250_dma	*dma = p->dma;
 	struct tty_port		*tty_port = &p->port.state->port;
 	struct dma_tx_state	state;
@@ -57,6 +56,20 @@ static void __dma_rx_complete(void *param)
 	tty_flip_buffer_push(tty_port);
 }
 
+static void dma_rx_complete(void *param)
+{
+	struct uart_8250_port *p = param;
+	struct uart_8250_dma *dma = p->dma;
+	unsigned long flags;
+
+	__dma_rx_complete(p);
+
+	spin_lock_irqsave(&p->port.lock, flags);
+	if (!dma->rx_running && (serial_lsr_in(p) & UART_LSR_DR))
+		p->dma->rx_dma(p);
+	spin_unlock_irqrestore(&p->port.lock, flags);
+}
+
 int serial8250_tx_dma(struct uart_8250_port *p)
 {
 	struct uart_8250_dma		*dma = p->dma;
@@ -130,7 +143,7 @@ int serial8250_rx_dma(struct uart_8250_port *p)
 		return -EBUSY;
 
 	dma->rx_running = 1;
-	desc->callback = __dma_rx_complete;
+	desc->callback = dma_rx_complete;
 	desc->callback_param = p;
 
 	dma->rx_cookie = dmaengine_submit(desc);
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH 1/1] serial: 8250_dma: Rearm DMA Rx if more data is pending
  2022-11-07 10:21 [PATCH 1/1] serial: 8250_dma: Rearm DMA Rx if more data is pending Ilpo Järvinen
@ 2022-11-07 11:31 ` Andy Shevchenko
  2022-11-08 12:57   ` Andy Shevchenko
  0 siblings, 1 reply; 3+ messages in thread
From: Andy Shevchenko @ 2022-11-07 11:31 UTC (permalink / raw)
  To: Ilpo Järvinen
  Cc: Greg Kroah-Hartman, Jiri Slaby, linux-serial, linux-kernel,
	Gilles BULOZ

On Mon, Nov 07, 2022 at 12:21:26PM +0200, Ilpo Järvinen wrote:
> When DMA Rx completes, the current behavior is to just exit the DMA
> completion handler without future actions. If the transfer is still
> on-going, UART will trigger an interrupt and that eventually rearms the
> DMA Rx. The extra interrupt round-trip has an inherent latency cost
> that increases the risk of FIFO overrun. In such situations, the
> latency margin tends to already be less due to FIFO not being empty.
> 
> Add check into DMA Rx completion handler to detect if LSR has DR (Data
> Ready) still set. DR indicates there will be more characters pending
> and DMA Rx can be rearmed right away to handle them.

Yep, I used to have something like draft of the below change locally.
Thanks for putting it in shape and upstreamimg!

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

> Cc: Gilles BULOZ <gilles.buloz@kontron.com>
> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
> ---
>  drivers/tty/serial/8250/8250_dma.c | 19 ++++++++++++++++---
>  1 file changed, 16 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
> index b85c82616e8c..37d6af2ec427 100644
> --- a/drivers/tty/serial/8250/8250_dma.c
> +++ b/drivers/tty/serial/8250/8250_dma.c
> @@ -38,9 +38,8 @@ static void __dma_tx_complete(void *param)
>  	spin_unlock_irqrestore(&p->port.lock, flags);
>  }
>  
> -static void __dma_rx_complete(void *param)
> +static void __dma_rx_complete(struct uart_8250_port *p)
>  {
> -	struct uart_8250_port	*p = param;
>  	struct uart_8250_dma	*dma = p->dma;
>  	struct tty_port		*tty_port = &p->port.state->port;
>  	struct dma_tx_state	state;
> @@ -57,6 +56,20 @@ static void __dma_rx_complete(void *param)
>  	tty_flip_buffer_push(tty_port);
>  }
>  
> +static void dma_rx_complete(void *param)
> +{
> +	struct uart_8250_port *p = param;
> +	struct uart_8250_dma *dma = p->dma;
> +	unsigned long flags;
> +
> +	__dma_rx_complete(p);
> +
> +	spin_lock_irqsave(&p->port.lock, flags);
> +	if (!dma->rx_running && (serial_lsr_in(p) & UART_LSR_DR))
> +		p->dma->rx_dma(p);
> +	spin_unlock_irqrestore(&p->port.lock, flags);
> +}
> +
>  int serial8250_tx_dma(struct uart_8250_port *p)
>  {
>  	struct uart_8250_dma		*dma = p->dma;
> @@ -130,7 +143,7 @@ int serial8250_rx_dma(struct uart_8250_port *p)
>  		return -EBUSY;
>  
>  	dma->rx_running = 1;
> -	desc->callback = __dma_rx_complete;
> +	desc->callback = dma_rx_complete;
>  	desc->callback_param = p;
>  
>  	dma->rx_cookie = dmaengine_submit(desc);
> -- 
> 2.30.2
> 

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH 1/1] serial: 8250_dma: Rearm DMA Rx if more data is pending
  2022-11-07 11:31 ` Andy Shevchenko
@ 2022-11-08 12:57   ` Andy Shevchenko
  0 siblings, 0 replies; 3+ messages in thread
From: Andy Shevchenko @ 2022-11-08 12:57 UTC (permalink / raw)
  To: Ilpo Järvinen
  Cc: Greg Kroah-Hartman, Jiri Slaby, linux-serial, linux-kernel,
	Gilles BULOZ

On Mon, Nov 07, 2022 at 01:31:52PM +0200, Andy Shevchenko wrote:
> On Mon, Nov 07, 2022 at 12:21:26PM +0200, Ilpo Järvinen wrote:

...

> Yep, I used to have something like draft of the below change locally.
> Thanks for putting it in shape and upstreamimg!
> 
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

...

> > -static void __dma_rx_complete(void *param)
> > +static void __dma_rx_complete(struct uart_8250_port *p)
> >  {
> > -	struct uart_8250_port	*p = param;
> >  	struct uart_8250_dma	*dma = p->dma;

Btw, looking into my patch in archives I noticed that dma can also be passed as
a parameter...

...

> > +static void dma_rx_complete(void *param)
> > +{
> > +	struct uart_8250_port *p = param;

> > +	struct uart_8250_dma *dma = p->dma;

...since you have it already here.

> > +	unsigned long flags;
> > +
> > +	__dma_rx_complete(p);

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2022-11-08 12:57 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-11-07 10:21 [PATCH 1/1] serial: 8250_dma: Rearm DMA Rx if more data is pending Ilpo Järvinen
2022-11-07 11:31 ` Andy Shevchenko
2022-11-08 12:57   ` Andy Shevchenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).