static void sci_dma_rx_complete(void *arg)
{
struct sci_port *s = arg;
+ struct dma_chan *chan = s->chan_rx;
struct uart_port *port = &s->port;
struct dma_async_tx_descriptor *desc;
unsigned long flags;
s->active_rx = s->cookie_rx[!active];
+ dma_async_issue_pending(chan);
+
dev_dbg(port->dev, "%s: cookie %d #%d, new active cookie %d\n",
__func__, s->cookie_rx[active], active, s->active_rx);
spin_unlock_irqrestore(&port->lock, flags);
static void rx_timer_fn(unsigned long arg)
{
struct sci_port *s = (struct sci_port *)arg;
+ struct dma_chan *chan = s->chan_rx;
struct uart_port *port = &s->port;
struct dma_tx_state state;
enum dma_status status;
spin_lock_irqsave(&port->lock, flags);
dev_dbg(port->dev, "DMA Rx timed out\n");
- scr = serial_port_in(port, SCSCR);
- if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
- scr &= ~SCSCR_RDRQE;
- enable_irq(s->irqs[SCIx_RXI_IRQ]);
- }
- serial_port_out(port, SCSCR, scr | SCSCR_RIE);
active = sci_dma_rx_find_active(s);
if (active < 0) {
}
status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state);
- if (status == DMA_COMPLETE)
+ if (status == DMA_COMPLETE) {
dev_dbg(port->dev, "Cookie %d #%d has already completed\n",
s->active_rx, active);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ /* Let packet complete handler take care of the packet */
+ return;
+ }
+
+ dmaengine_pause(chan);
+
+ /*
+ * sometimes DMA transfer doesn't stop even if it is stopped and
+ * data keeps on coming until transaction is complete so check
+ * for DMA_COMPLETE again
+ * Let packet complete handler take care of the packet
+ */
+ status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state);
+ if (status == DMA_COMPLETE) {
+ spin_unlock_irqrestore(&port->lock, flags);
+ dev_dbg(port->dev, "Transaction complete after DMA engine was stopped");
+ return;
+ }
/* Handle incomplete DMA receive */
dmaengine_terminate_all(s->chan_rx);
tty_flip_buffer_push(&port->state->port);
}
- spin_unlock_irqrestore(&port->lock, flags);
-
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
sci_submit_rx(s);
+
+ /* Direct new serial port interrupts back to CPU */
+ scr = serial_port_in(port, SCSCR);
+ if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+ scr &= ~SCSCR_RDRQE;
+ enable_irq(s->irqs[SCIx_RXI_IRQ]);
+ }
+ serial_port_out(port, SCSCR, scr | SCSCR_RIE);
+
+ spin_unlock_irqrestore(&port->lock, flags);
}
static void sci_request_dma(struct uart_port *port)