diff options
author | Peter Hurley <peter@hurleysoftware.com> | 2016-04-09 22:14:36 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-04-30 09:26:55 -0700 |
commit | 33d9b8b23a73d5d8609a740d0adeea8235c2ae52 (patch) | |
tree | ef63a64eb25995cc3dd6f9912ced54560275e71c /drivers/tty/serial/8250/8250_omap.c | |
parent | b74fdd23d8fb4e349185ed9d963da8fc2b6eb34c (diff) |
serial: 8250: Extract IIR logic steering from rx dma
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>
Diffstat (limited to 'drivers/tty/serial/8250/8250_omap.c')
-rw-r--r-- | drivers/tty/serial/8250/8250_omap.c | 67 |
1 files changed, 28 insertions, 39 deletions
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 27702d5e8811..8579b0ced093 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -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); |