mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-13 01:08:50 +00:00
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>
This commit is contained in:
parent
b74fdd23d8
commit
33d9b8b23a
@ -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)
|
|||||||
|
|
||||||
#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)
|
|||||||
{
|
{
|
||||||
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 @@ err:
|
|||||||
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)
|
|||||||
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 {
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#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 @@ unlock:
|
|||||||
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)
|
|||||||
__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)
|
|||||||
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 @@ err:
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
#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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user