diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index d54dcd87c67e..61cb31163fae 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -45,6 +45,9 @@ struct uart_8250_dma { unsigned char tx_running; unsigned char tx_err; unsigned char rx_running; + + size_t rx_index; + struct timer_list dma_rx_timer; }; struct old_serial_port { diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index 78259d3c6a55..9e6c1d34181e 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -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; - - 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); + + /* 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); + + 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,