serial: 8250: Extract IIR logic steering from rx dma
authorPeter Hurley <peter@hurleysoftware.com>
Sun, 10 Apr 2016 05:14:36 +0000 (22:14 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 30 Apr 2016 16:26:55 +0000 (09:26 -0700)
Using fake IIR values to perform rx dma operations unnecessarily
conflates separate operations, stopping in-progress dma with starting
new dma.

Introduce serial8250_rx_dma_flush() to handle stopping in-progress dma
[omap8250 already has equivalent omap_8250_rx_dma_flush()].
Replace rx_dma(UART_IIR_RX_TIMEOUT) with the equivalent *_rx_dma_flush(),
and rx_dma(0) with the equivalent *_rx_dma(). Handle IIR steering
in the irq handler with handle_rx_dma() helper.

Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/8250/8250.h
drivers/tty/serial/8250/8250_dma.c
drivers/tty/serial/8250/8250_omap.c
drivers/tty/serial/8250/8250_port.c

index 8739d2214d4a3294bda37151be6b2c5f52337ebc..7a4c826339649b1c5b926365ada02fd82a97069e 100644 (file)
@@ -17,7 +17,7 @@
 
 struct uart_8250_dma {
        int (*tx_dma)(struct uart_8250_port *p);
-       int (*rx_dma)(struct uart_8250_port *p, unsigned int iir);
+       int (*rx_dma)(struct uart_8250_port *p);
 
        /* Filter function */
        dma_filter_fn           fn;
@@ -189,7 +189,8 @@ static inline int is_omap1510_8250(struct uart_8250_port *pt)
 
 #ifdef CONFIG_SERIAL_8250_DMA
 extern int serial8250_tx_dma(struct uart_8250_port *);
-extern int serial8250_rx_dma(struct uart_8250_port *, unsigned int iir);
+extern int serial8250_rx_dma(struct uart_8250_port *);
+extern void serial8250_rx_dma_flush(struct uart_8250_port *);
 extern int serial8250_request_dma(struct uart_8250_port *);
 extern void serial8250_release_dma(struct uart_8250_port *);
 #else
@@ -197,10 +198,11 @@ static inline int serial8250_tx_dma(struct uart_8250_port *p)
 {
        return -1;
 }
-static inline int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
+static inline int serial8250_rx_dma(struct uart_8250_port *p)
 {
        return -1;
 }
+static inline void serial8250_rx_dma_flush(struct uart_8250_port *p) { }
 static inline int serial8250_request_dma(struct uart_8250_port *p)
 {
        return -1;
index 7a26c4d13b18a18f6dbb336280361e5ff71a0318..7f33d1c8d1a952bc7c5de2953a796d3a0c044a40 100644 (file)
@@ -110,30 +110,11 @@ err:
        return ret;
 }
 
-int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
+int serial8250_rx_dma(struct uart_8250_port *p)
 {
        struct uart_8250_dma            *dma = p->dma;
        struct dma_async_tx_descriptor  *desc;
 
-       switch (iir & 0x3f) {
-       case UART_IIR_RLSI:
-               /* 8250_core handles errors and break interrupts */
-               return -EIO;
-       case UART_IIR_RX_TIMEOUT:
-               /*
-                * If RCVR FIFO trigger level was not reached, complete the
-                * transfer and let 8250_core copy the remaining data.
-                */
-               if (dma->rx_running) {
-                       dmaengine_pause(dma->rxchan);
-                       __dma_rx_complete(p);
-                       dmaengine_terminate_all(dma->rxchan);
-               }
-               return -ETIMEDOUT;
-       default:
-               break;
-       }
-
        if (dma->rx_running)
                return 0;
 
@@ -154,6 +135,17 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
        return 0;
 }
 
+void serial8250_rx_dma_flush(struct uart_8250_port *p)
+{
+       struct uart_8250_dma *dma = p->dma;
+
+       if (dma->rx_running) {
+               dmaengine_pause(dma->rxchan);
+               __dma_rx_complete(p);
+               dmaengine_terminate_all(dma->rxchan);
+       }
+}
+
 int serial8250_request_dma(struct uart_8250_port *p)
 {
        struct uart_8250_dma    *dma = p->dma;
index 27702d5e88111dfa301cc48668942a9c9ba29f41..8579b0ced093ebafa2b99d091f5b8ac8bb6e2e93 100644 (file)
@@ -115,6 +115,12 @@ struct omap8250_priv {
        bool rx_dma_broken;
 };
 
+#ifdef CONFIG_SERIAL_8250_DMA
+static void omap_8250_rx_dma_flush(struct uart_8250_port *p);
+#else
+static inline void omap_8250_rx_dma_flush(struct uart_8250_port *p) { }
+#endif
+
 static u32 uart_read(struct uart_8250_port *up, u32 reg)
 {
        return readl(up->port.membase + (reg << up->port.regshift));
@@ -635,7 +641,7 @@ static int omap_8250_startup(struct uart_port *port)
        serial_out(up, UART_OMAP_WER, priv->wer);
 
        if (up->dma)
-               up->dma->rx_dma(up, 0);
+               up->dma->rx_dma(up);
 
        pm_runtime_mark_last_busy(port->dev);
        pm_runtime_put_autosuspend(port->dev);
@@ -654,7 +660,7 @@ static void omap_8250_shutdown(struct uart_port *port)
 
        flush_work(&priv->qos_work);
        if (up->dma)
-               up->dma->rx_dma(up, UART_IIR_RX_TIMEOUT);
+               omap_8250_rx_dma_flush(up);
 
        pm_runtime_get_sync(port->dev);
 
@@ -742,7 +748,7 @@ static void omap_8250_unthrottle(struct uart_port *port)
 }
 
 #ifdef CONFIG_SERIAL_8250_DMA
-static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir);
+static int omap_8250_rx_dma(struct uart_8250_port *p);
 
 static void __dma_rx_do_complete(struct uart_8250_port *p)
 {
@@ -778,7 +784,7 @@ unlock:
 static void __dma_rx_complete(void *param)
 {
        __dma_rx_do_complete(param);
-       omap_8250_rx_dma(param, 0);
+       omap_8250_rx_dma(param);
 }
 
 static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
@@ -804,7 +810,7 @@ static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
        __dma_rx_do_complete(p);
 }
 
-static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
+static int omap_8250_rx_dma(struct uart_8250_port *p)
 {
        struct omap8250_priv            *priv = p->port.private_data;
        struct uart_8250_dma            *dma = p->dma;
@@ -812,35 +818,6 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
        struct dma_async_tx_descriptor  *desc;
        unsigned long                   flags;
 
-       switch (iir & 0x3f) {
-       case UART_IIR_RLSI:
-               /* 8250_core handles errors and break interrupts */
-               omap_8250_rx_dma_flush(p);
-               return -EIO;
-       case UART_IIR_RX_TIMEOUT:
-               /*
-                * If RCVR FIFO trigger level was not reached, complete the
-                * transfer and let 8250_core copy the remaining data.
-                */
-               omap_8250_rx_dma_flush(p);
-               return -ETIMEDOUT;
-       case UART_IIR_RDI:
-               /*
-                * The OMAP UART is a special BEAST. If we receive RDI we _have_
-                * a DMA transfer programmed but it didn't work. One reason is
-                * that we were too slow and there were too many bytes in the
-                * FIFO, the UART counted wrong and never kicked the DMA engine
-                * to do anything. That means once we receive RDI on OMAP then
-                * the DMA won't do anything soon so we have to cancel the DMA
-                * transfer and purge the FIFO manually.
-                */
-               omap_8250_rx_dma_flush(p);
-               return -ETIMEDOUT;
-
-       default:
-               break;
-       }
-
        if (priv->rx_dma_broken)
                return -EINVAL;
 
@@ -1014,6 +991,18 @@ err:
        return ret;
 }
 
+static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
+{
+       switch (iir & 0x3f) {
+       case UART_IIR_RLSI:
+       case UART_IIR_RX_TIMEOUT:
+       case UART_IIR_RDI:
+               omap_8250_rx_dma_flush(up);
+               return true;
+       }
+       return omap_8250_rx_dma(up);
+}
+
 /*
  * This is mostly serial8250_handle_irq(). We have a slightly different DMA
  * hoook for RX/TX and need different logic for them in the ISR. Therefore we
@@ -1039,9 +1028,9 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
        status = serial_port_in(port, UART_LSR);
 
        if (status & (UART_LSR_DR | UART_LSR_BI)) {
-               if (omap_8250_rx_dma(up, iir)) {
+               if (handle_rx_dma(up, iir)) {
                        status = serial8250_rx_chars(up, status);
-                       omap_8250_rx_dma(up, 0);
+                       omap_8250_rx_dma(up);
                }
        }
        serial8250_modem_status(up);
@@ -1072,7 +1061,7 @@ static bool the_no_dma_filter_fn(struct dma_chan *chan, void *param)
 
 #else
 
-static inline int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
+static inline int omap_8250_rx_dma(struct uart_8250_port *p)
 {
        return -EINVAL;
 }
@@ -1383,7 +1372,7 @@ static int omap8250_runtime_suspend(struct device *dev)
        }
 
        if (up->dma && up->dma->rxchan)
-               omap_8250_rx_dma(up, UART_IIR_RX_TIMEOUT);
+               omap_8250_rx_dma_flush(up);
 
        priv->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
        schedule_work(&priv->qos_work);
@@ -1406,7 +1395,7 @@ static int omap8250_runtime_resume(struct device *dev)
                omap8250_restore_regs(up);
 
        if (up->dma && up->dma->rxchan)
-               omap_8250_rx_dma(up, 0);
+               omap_8250_rx_dma(up);
 
        priv->latency = priv->calc_latency;
        schedule_work(&priv->qos_work);
index b2bbb9dcfa0bc1b46d6a37f6b4ce50d3e5fdc140..215e8da78a06db9437df2158b36c4362fa48b3f9 100644 (file)
@@ -1788,6 +1788,18 @@ unsigned int serial8250_modem_status(struct uart_8250_port *up)
 }
 EXPORT_SYMBOL_GPL(serial8250_modem_status);
 
+static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
+{
+       switch (iir & 0x3f) {
+       case UART_IIR_RX_TIMEOUT:
+               serial8250_rx_dma_flush(up);
+               /* fall-through */
+       case UART_IIR_RLSI:
+               return true;
+       }
+       return up->dma->rx_dma(up);
+}
+
 /*
  * This handles the interrupt from one port.
  */
@@ -1807,7 +1819,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
        DEBUG_INTR("status = %x...", status);
 
        if (status & (UART_LSR_DR | UART_LSR_BI)) {
-               if (!up->dma || up->dma->rx_dma(up, iir))
+               if (!up->dma || handle_rx_dma(up, iir))
                        status = serial8250_rx_chars(up, status);
        }
        serial8250_modem_status(up);