Re: [PATCH 1/3] serial: sh-sci: Postpone DMA release when falling back to PIO

2018-06-29 Thread Geert Uytterhoeven
On Fri, Jun 29, 2018 at 4:26 PM Geert Uytterhoeven
 wrote:
> When the sh-sci driver detects an issue with DMA during operation, it
> falls backs to PIO, and releases all DMA resources.
>
> As releasing DMA resources immediately has no advantages, but
> complicates the code, and is susceptible to races, it is better to
> postpone this to port shutdown.
>
> This allows to remove the locking from sci_rx_dma_release() and
> sci_tx_dma_release(), but requires keeping a copy of the DMA channel
> pointers for release during port shutdown.
>
> Signed-off-by: Geert Uytterhoeven 

> --- a/drivers/tty/serial/sh-sci.c
> +++ b/drivers/tty/serial/sh-sci.c

> @@ -1212,25 +1214,17 @@ static int sci_dma_rx_find_active(struct sci_port *s)
> return -1;
>  }
>
> -static void sci_rx_dma_release(struct sci_port *s, bool enable_pio)
> +static void sci_rx_dma_release(struct sci_port *s)
>  {
> -   struct dma_chan *chan = s->chan_rx;
> +   struct dma_chan *chan = s->chan_rx_saved;
> struct uart_port *port = >port;

Brown paper bag #2: unused variable port. Let's blame it on the warm Friday
afternoon.

So yes, there will be a v2, eventually...

Gr{oetje,eeting}s,

Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- ge...@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds


[PATCH 1/3] serial: sh-sci: Postpone DMA release when falling back to PIO

2018-06-29 Thread Geert Uytterhoeven
When the sh-sci driver detects an issue with DMA during operation, it
falls backs to PIO, and releases all DMA resources.

As releasing DMA resources immediately has no advantages, but
complicates the code, and is susceptible to races, it is better to
postpone this to port shutdown.

This allows to remove the locking from sci_rx_dma_release() and
sci_tx_dma_release(), but requires keeping a copy of the DMA channel
pointers for release during port shutdown.

Signed-off-by: Geert Uytterhoeven 
---
 drivers/tty/serial/sh-sci.c | 81 +++--
 1 file changed, 41 insertions(+), 40 deletions(-)

diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index c181eb37f98509e6..0ed91692f53ad859 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -135,6 +135,8 @@ struct sci_port {
struct dma_chan *chan_rx;
 
 #ifdef CONFIG_SERIAL_SH_SCI_DMA
+   struct dma_chan *chan_tx_saved;
+   struct dma_chan *chan_rx_saved;
dma_cookie_tcookie_tx;
dma_cookie_tcookie_rx[2];
dma_cookie_tactive_rx;
@@ -1212,25 +1214,17 @@ static int sci_dma_rx_find_active(struct sci_port *s)
return -1;
 }
 
-static void sci_rx_dma_release(struct sci_port *s, bool enable_pio)
+static void sci_rx_dma_release(struct sci_port *s)
 {
-   struct dma_chan *chan = s->chan_rx;
+   struct dma_chan *chan = s->chan_rx_saved;
struct uart_port *port = >port;
-   unsigned long flags;
 
-   spin_lock_irqsave(>lock, flags);
-   s->chan_rx = NULL;
+   s->chan_rx_saved = s->chan_rx = NULL;
s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL;
-   spin_unlock_irqrestore(>lock, flags);
dmaengine_terminate_all(chan);
dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0],
  sg_dma_address(>sg_rx[0]));
dma_release_channel(chan);
-   if (enable_pio) {
-   spin_lock_irqsave(>lock, flags);
-   sci_start_rx(port);
-   spin_unlock_irqrestore(>lock, flags);
-   }
 }
 
 static void start_hrtimer_us(struct hrtimer *hrt, unsigned long usec)
@@ -1289,33 +1283,31 @@ static void sci_dma_rx_complete(void *arg)
 fail:
spin_unlock_irqrestore(>lock, flags);
dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
-   sci_rx_dma_release(s, true);
+   /* Switch to PIO */
+   spin_lock_irqsave(>lock, flags);
+   s->chan_rx = NULL;
+   sci_start_rx(port);
+   spin_unlock_irqrestore(>lock, flags);
 }
 
-static void sci_tx_dma_release(struct sci_port *s, bool enable_pio)
+static void sci_tx_dma_release(struct sci_port *s)
 {
-   struct dma_chan *chan = s->chan_tx;
+   struct dma_chan *chan = s->chan_tx_saved;
struct uart_port *port = >port;
-   unsigned long flags;
 
-   spin_lock_irqsave(>lock, flags);
-   s->chan_tx = NULL;
+   s->chan_tx_saved = s->chan_tx = NULL;
s->cookie_tx = -EINVAL;
-   spin_unlock_irqrestore(>lock, flags);
dmaengine_terminate_all(chan);
dma_unmap_single(chan->device->dev, s->tx_dma_addr, UART_XMIT_SIZE,
 DMA_TO_DEVICE);
dma_release_channel(chan);
-   if (enable_pio) {
-   spin_lock_irqsave(>lock, flags);
-   sci_start_tx(port);
-   spin_unlock_irqrestore(>lock, flags);
-   }
 }
 
 static void sci_submit_rx(struct sci_port *s)
 {
struct dma_chan *chan = s->chan_rx;
+   struct uart_port *port = >port;
+   unsigned long flags;
int i;
 
for (i = 0; i < 2; i++) {
@@ -1347,7 +1339,11 @@ static void sci_submit_rx(struct sci_port *s)
for (i = 0; i < 2; i++)
s->cookie_rx[i] = -EINVAL;
s->active_rx = -EINVAL;
-   sci_rx_dma_release(s, true);
+   /* Switch to PIO */
+   spin_lock_irqsave(>lock, flags);
+   s->chan_rx = NULL;
+   sci_start_rx(port);
+   spin_unlock_irqrestore(>lock, flags);
 }
 
 static void work_fn_tx(struct work_struct *work)
@@ -1357,6 +1353,7 @@ static void work_fn_tx(struct work_struct *work)
struct dma_chan *chan = s->chan_tx;
struct uart_port *port = >port;
struct circ_buf *xmit = >state->xmit;
+   unsigned long flags;
dma_addr_t buf;
 
/*
@@ -1378,9 +1375,7 @@ static void work_fn_tx(struct work_struct *work)
   DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
dev_warn(port->dev, "Failed preparing Tx DMA descriptor\n");
-   /* switch to PIO */
-   sci_tx_dma_release(s, true);
-   return;
+   goto switch_to_pio;
}
 
dma_sync_single_for_device(chan->device->dev, buf, s->tx_dma_len,
@@ -1393,15 +1388,21 @@ static void work_fn_tx(struct work_struct *work)