/* * 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 * use the default routine in the non-DMA case and this one for with DMA. */ static int omap_8250_dma_handle_irq(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); unsigned char status; unsigned long flags; u8 iir; int dma_err = 0; serial8250_rpm_get(up); iir = serial_port_in(port, UART_IIR); if (iir & UART_IIR_NO_INT) { serial8250_rpm_put(up); return 0; } spin_lock_irqsave(&port->lock, flags); status = serial_port_in(port, UART_LSR); if (status & (UART_LSR_DR | UART_LSR_BI)) { dma_err = omap_8250_rx_dma(up, iir); if (dma_err) { status = serial8250_rx_chars(up, status); omap_8250_rx_dma(up, 0); } } serial8250_modem_status(up); if (status & UART_LSR_THRE && up->dma->tx_err) { if (uart_tx_stopped(&up->port) || uart_circ_empty(&up->port.state->xmit)) { up->dma->tx_err = 0; serial8250_tx_chars(up); } else { /* * try again due to an earlier failer which * might have been resolved by now. */ dma_err = omap_8250_tx_dma(up); if (dma_err) serial8250_tx_chars(up); } } spin_unlock_irqrestore(&port->lock, flags); serial8250_rpm_put(up); return 1; }
static int omap8250_runtime_suspend(struct device *dev) { struct omap8250_priv *priv = dev_get_drvdata(dev); struct uart_8250_port *up; up = serial8250_get_port(priv->line); /* * When using 'no_console_suspend', the console UART must not be * suspended. Since driver suspend is managed by runtime suspend, * preventing runtime suspend (by returning error) will keep device * active during suspend. */ if (priv->is_suspending && !console_suspend_enabled) { if (uart_console(&up->port)) return -EBUSY; } omap8250_enable_wakeup(priv, true); if (up->dma) omap_8250_rx_dma(up, UART_IIR_RX_TIMEOUT); priv->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; schedule_work(&priv->qos_work); return 0; }
static void __dma_rx_complete(void *param) { struct uart_8250_port *p = param; struct omap8250_priv *priv = p->port.private_data; struct uart_8250_dma *dma = p->dma; struct dma_tx_state state; unsigned long flags; spin_lock_irqsave(&p->port.lock, flags); /* * If the tx status is not DMA_COMPLETE, then this is a delayed * completion callback. A previous RX timeout flush would have * already pushed the data, so exit. */ if (dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state) != DMA_COMPLETE) { spin_unlock_irqrestore(&p->port.lock, flags); return; } __dma_rx_do_complete(p); if (!priv->throttled) omap_8250_rx_dma(p); spin_unlock_irqrestore(&p->port.lock, flags); }
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); }
static int omap8250_runtime_resume(struct device *dev) { struct omap8250_priv *priv = dev_get_drvdata(dev); struct uart_8250_port *up; /* In case runtime-pm tries this before we are setup */ if (!priv) return 0; up = serial8250_get_port(priv->line); if (omap8250_lost_context(up)) omap8250_restore_regs(up); if (up->dma && up->dma->rxchan) omap_8250_rx_dma(up); priv->latency = priv->calc_latency; schedule_work(&priv->qos_work); return 0; }
static void __dma_rx_do_complete(struct uart_8250_port *p, bool error) { struct uart_8250_dma *dma = p->dma; struct tty_port *tty_port = &p->port.state->port; struct dma_tx_state state; int count; dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr, dma->rx_size, DMA_FROM_DEVICE); dma->rx_running = 0; dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); dmaengine_terminate_all(dma->rxchan); count = dma->rx_size - state.residue; tty_insert_flip_string(tty_port, dma->rx_buf, count); p->port.icount.rx += count; if (!error) omap_8250_rx_dma(p, 0); tty_flip_buffer_push(tty_port); }
static int omap8250_runtime_resume(struct device *dev) { struct omap8250_priv *priv = dev_get_drvdata(dev); struct uart_8250_port *up; int loss_cntx; /* In case runtime-pm tries this before we are setup */ if (!priv) return 0; up = serial8250_get_port(priv->line); omap8250_enable_wakeup(priv, false); loss_cntx = omap8250_lost_context(up); if (loss_cntx) omap8250_restore_regs(up); if (up->dma) omap_8250_rx_dma(up, 0); priv->latency = priv->calc_latency; schedule_work(&priv->qos_work); return 0; }
static void __dma_rx_complete(void *param) { __dma_rx_do_complete(param); omap_8250_rx_dma(param); }