Commit 33d9b8b2 authored by Peter Hurley's avatar Peter Hurley Committed by Greg Kroah-Hartman

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: default avatarPeter Hurley <peter@hurleysoftware.com>
Reviewed-by: default avatarHeikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent b74fdd23
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
struct uart_8250_dma { struct uart_8250_dma {
int (*tx_dma)(struct uart_8250_port *p); 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 */ /* Filter function */
dma_filter_fn fn; dma_filter_fn fn;
...@@ -189,7 +189,8 @@ static inline int is_omap1510_8250(struct uart_8250_port *pt) ...@@ -189,7 +189,8 @@ static inline int is_omap1510_8250(struct uart_8250_port *pt)
#ifdef CONFIG_SERIAL_8250_DMA #ifdef CONFIG_SERIAL_8250_DMA
extern int serial8250_tx_dma(struct uart_8250_port *); 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 int serial8250_request_dma(struct uart_8250_port *);
extern void serial8250_release_dma(struct uart_8250_port *); extern void serial8250_release_dma(struct uart_8250_port *);
#else #else
...@@ -197,10 +198,11 @@ static inline int serial8250_tx_dma(struct uart_8250_port *p) ...@@ -197,10 +198,11 @@ static inline int serial8250_tx_dma(struct uart_8250_port *p)
{ {
return -1; 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; 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) static inline int serial8250_request_dma(struct uart_8250_port *p)
{ {
return -1; return -1;
......
...@@ -110,30 +110,11 @@ int serial8250_tx_dma(struct uart_8250_port *p) ...@@ -110,30 +110,11 @@ int serial8250_tx_dma(struct uart_8250_port *p)
return ret; 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 uart_8250_dma *dma = p->dma;
struct dma_async_tx_descriptor *desc; 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) if (dma->rx_running)
return 0; return 0;
...@@ -154,6 +135,17 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) ...@@ -154,6 +135,17 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
return 0; 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) int serial8250_request_dma(struct uart_8250_port *p)
{ {
struct uart_8250_dma *dma = p->dma; struct uart_8250_dma *dma = p->dma;
......
...@@ -115,6 +115,12 @@ struct omap8250_priv { ...@@ -115,6 +115,12 @@ struct omap8250_priv {
bool rx_dma_broken; 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) static u32 uart_read(struct uart_8250_port *up, u32 reg)
{ {
return readl(up->port.membase + (reg << up->port.regshift)); return readl(up->port.membase + (reg << up->port.regshift));
...@@ -635,7 +641,7 @@ static int omap_8250_startup(struct uart_port *port) ...@@ -635,7 +641,7 @@ static int omap_8250_startup(struct uart_port *port)
serial_out(up, UART_OMAP_WER, priv->wer); serial_out(up, UART_OMAP_WER, priv->wer);
if (up->dma) if (up->dma)
up->dma->rx_dma(up, 0); up->dma->rx_dma(up);
pm_runtime_mark_last_busy(port->dev); pm_runtime_mark_last_busy(port->dev);
pm_runtime_put_autosuspend(port->dev); pm_runtime_put_autosuspend(port->dev);
...@@ -654,7 +660,7 @@ static void omap_8250_shutdown(struct uart_port *port) ...@@ -654,7 +660,7 @@ static void omap_8250_shutdown(struct uart_port *port)
flush_work(&priv->qos_work); flush_work(&priv->qos_work);
if (up->dma) if (up->dma)
up->dma->rx_dma(up, UART_IIR_RX_TIMEOUT); omap_8250_rx_dma_flush(up);
pm_runtime_get_sync(port->dev); pm_runtime_get_sync(port->dev);
...@@ -742,7 +748,7 @@ static void omap_8250_unthrottle(struct uart_port *port) ...@@ -742,7 +748,7 @@ static void omap_8250_unthrottle(struct uart_port *port)
} }
#ifdef CONFIG_SERIAL_8250_DMA #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) static void __dma_rx_do_complete(struct uart_8250_port *p)
{ {
...@@ -778,7 +784,7 @@ static void __dma_rx_do_complete(struct uart_8250_port *p) ...@@ -778,7 +784,7 @@ static void __dma_rx_do_complete(struct uart_8250_port *p)
static void __dma_rx_complete(void *param) static void __dma_rx_complete(void *param)
{ {
__dma_rx_do_complete(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) 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) ...@@ -804,7 +810,7 @@ static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
__dma_rx_do_complete(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 omap8250_priv *priv = p->port.private_data;
struct uart_8250_dma *dma = p->dma; 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) ...@@ -812,35 +818,6 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
struct dma_async_tx_descriptor *desc; struct dma_async_tx_descriptor *desc;
unsigned long flags; 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) if (priv->rx_dma_broken)
return -EINVAL; return -EINVAL;
...@@ -1014,6 +991,18 @@ static int omap_8250_tx_dma(struct uart_8250_port *p) ...@@ -1014,6 +991,18 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
return ret; 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 * 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 * 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) ...@@ -1039,9 +1028,9 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
status = serial_port_in(port, UART_LSR); status = serial_port_in(port, UART_LSR);
if (status & (UART_LSR_DR | UART_LSR_BI)) { 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); status = serial8250_rx_chars(up, status);
omap_8250_rx_dma(up, 0); omap_8250_rx_dma(up);
} }
} }
serial8250_modem_status(up); serial8250_modem_status(up);
...@@ -1072,7 +1061,7 @@ static bool the_no_dma_filter_fn(struct dma_chan *chan, void *param) ...@@ -1072,7 +1061,7 @@ static bool the_no_dma_filter_fn(struct dma_chan *chan, void *param)
#else #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; return -EINVAL;
} }
...@@ -1383,7 +1372,7 @@ static int omap8250_runtime_suspend(struct device *dev) ...@@ -1383,7 +1372,7 @@ static int omap8250_runtime_suspend(struct device *dev)
} }
if (up->dma && up->dma->rxchan) 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; priv->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
schedule_work(&priv->qos_work); schedule_work(&priv->qos_work);
...@@ -1406,7 +1395,7 @@ static int omap8250_runtime_resume(struct device *dev) ...@@ -1406,7 +1395,7 @@ static int omap8250_runtime_resume(struct device *dev)
omap8250_restore_regs(up); omap8250_restore_regs(up);
if (up->dma && up->dma->rxchan) if (up->dma && up->dma->rxchan)
omap_8250_rx_dma(up, 0); omap_8250_rx_dma(up);
priv->latency = priv->calc_latency; priv->latency = priv->calc_latency;
schedule_work(&priv->qos_work); schedule_work(&priv->qos_work);
......
...@@ -1788,6 +1788,18 @@ unsigned int serial8250_modem_status(struct uart_8250_port *up) ...@@ -1788,6 +1788,18 @@ unsigned int serial8250_modem_status(struct uart_8250_port *up)
} }
EXPORT_SYMBOL_GPL(serial8250_modem_status); 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. * This handles the interrupt from one port.
*/ */
...@@ -1807,7 +1819,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) ...@@ -1807,7 +1819,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
DEBUG_INTR("status = %x...", status); DEBUG_INTR("status = %x...", status);
if (status & (UART_LSR_DR | UART_LSR_BI)) { 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); status = serial8250_rx_chars(up, status);
} }
serial8250_modem_status(up); serial8250_modem_status(up);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment