serial: 8250_dma: add timer for dma receive
[firefly-linux-kernel-4.4.55.git] / drivers / tty / serial / 8250 / 8250_dma.c
index 78259d3c6a55592281a5c6aaad88c5ae727d9615..9e6c1d34181ef6e759f5dad8aceef4b715d3ad21 100644 (file)
@@ -53,16 +53,52 @@ static void __dma_rx_complete(void *param)
        struct tty_port         *tty_port = &p->port.state->port;
        struct dma_tx_state     state;
        int                     count;
+       unsigned long           flags;
 
+       spin_lock_irqsave(&p->port.lock, flags);
+       del_timer(&dma->dma_rx_timer);
        dma->rx_running = 0;
        dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
 
-       count = dma->rx_size - state.residue;
+       count = dma->rx_size - state.residue - dma->rx_index;
+       tty_insert_flip_string(tty_port, dma->rx_buf + dma->rx_index, count);
+       p->port.icount.rx += count;
+       dma->rx_index = dma->rx_size - state.residue;
+
+       tty_flip_buffer_push(tty_port);
+
+       /* RDI can be enable again, so that dma transfer can be restarted */
+       p->ier |= (UART_IER_RLSI | UART_IER_RDI);
+       p->port.read_status_mask |= UART_LSR_DR;
+       serial_port_out(&p->port, UART_IER, p->ier);
+
+       spin_unlock_irqrestore(&p->port.lock, flags);
+}
+
+void __dma_rx_timer_callback(unsigned long param)
+{
+       struct uart_8250_port   *p = (struct uart_8250_port *)param;
+       struct uart_8250_dma    *dma = p->dma;
+       struct tty_port         *tty_port = &p->port.state->port;
+       struct dma_tx_state     state;
+       int                     count;
+       unsigned long           flags;
+
+       if (dma->rx_running == 0)
+               return;
+
+       spin_lock_irqsave(&p->port.lock, flags);
+       dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
 
-       tty_insert_flip_string(tty_port, dma->rx_buf, count);
+       count = dma->rx_size - state.residue - dma->rx_index;
+       tty_insert_flip_string(tty_port, dma->rx_buf + dma->rx_index, count);
        p->port.icount.rx += count;
+       dma->rx_index = dma->rx_size - state.residue;
 
        tty_flip_buffer_push(tty_port);
+       spin_unlock_irqrestore(&p->port.lock, flags);
+
+       mod_timer(&dma->dma_rx_timer, jiffies + msecs_to_jiffies(10));
 }
 
 int serial8250_tx_dma(struct uart_8250_port *p)
@@ -150,6 +186,9 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
        dma->rx_cookie = dmaengine_submit(desc);
 
        dma_async_issue_pending(dma->rxchan);
+       dma->rx_index = 0;
+
+       mod_timer(&dma->dma_rx_timer, jiffies + msecs_to_jiffies(10));
 
        return 0;
 }
@@ -163,10 +202,12 @@ int serial8250_request_dma(struct uart_8250_port *p)
        dma->rxconf.direction           = DMA_DEV_TO_MEM;
        dma->rxconf.src_addr_width      = DMA_SLAVE_BUSWIDTH_1_BYTE;
        dma->rxconf.src_addr            = p->port.mapbase + UART_RX;
+       dma->rxconf.src_maxburst        = 1;
 
        dma->txconf.direction           = DMA_MEM_TO_DEV;
        dma->txconf.dst_addr_width      = DMA_SLAVE_BUSWIDTH_1_BYTE;
        dma->txconf.dst_addr            = p->port.mapbase + UART_TX;
+       dma->txconf.dst_maxburst        = 1;
 
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
@@ -213,6 +254,12 @@ int serial8250_request_dma(struct uart_8250_port *p)
 
        dev_dbg_ratelimited(p->port.dev, "got both dma channels\n");
 
+       /* init rx timer */
+       dma->dma_rx_timer.function = __dma_rx_timer_callback;
+       dma->dma_rx_timer.data = (unsigned long)p;
+       dma->dma_rx_timer.expires = jiffies + msecs_to_jiffies(10);
+       init_timer(&dma->dma_rx_timer);
+
        return 0;
 err:
        dma_release_channel(dma->rxchan);
@@ -229,6 +276,8 @@ void serial8250_release_dma(struct uart_8250_port *p)
        if (!dma)
                return;
 
+       del_timer_sync(&dma->dma_rx_timer);
+
        /* Release RX resources */
        dmaengine_terminate_all(dma->rxchan);
        dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf,