diff options
author | Huibin Hong <huibin.hong@rock-chips.com> | 2018-01-03 14:32:56 +0800 |
---|---|---|
committer | Tao Huang <huangtao@rock-chips.com> | 2018-01-08 09:17:59 +0800 |
commit | 13659af22214ddd9994c416018f9a4fd766ddd93 (patch) | |
tree | 9f0f5442293de94dff0110972092f0b87b8ebb47 /drivers | |
parent | fc46944d433a3b47d282ae4c127e37f9b2d7edcc (diff) |
serial: 8250: fix bug cpu and DMA read uart fifo concurrently
Change-Id: I5284caff8cd684e890e6d7136158db042d724f57
Signed-off-by: Huibin Hong <huibin.hong@rock-chips.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/tty/serial/8250/8250_dma.c | 31 |
1 files changed, 23 insertions, 8 deletions
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index b2da90f1538c..cbac385b01c6 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -81,7 +81,6 @@ static void __dma_rx_complete(void *param) p->port.icount.rx += count; dma->rx_index = cur_index; - tty_flip_buffer_push(tty_port); } #else @@ -112,7 +111,7 @@ int serial8250_tx_dma(struct uart_8250_port *p) struct uart_8250_dma *dma = p->dma; struct circ_buf *xmit = &p->port.state->xmit; struct dma_async_tx_descriptor *desc; - int ret; + int ret = 0; if (uart_tx_stopped(&p->port) || dma->tx_running || uart_circ_empty(xmit)) @@ -120,8 +119,10 @@ int serial8250_tx_dma(struct uart_8250_port *p) dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); #ifdef CONFIG_ARCH_ROCKCHIP - if (dma->tx_size < MAX_TX_BYTES) + if (dma->tx_size < MAX_TX_BYTES) { + ret = -EBUSY; goto err; + } #endif desc = dmaengine_prep_slave_single(dma->txchan, dma->tx_addr + xmit->tail, @@ -159,7 +160,7 @@ err: int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) { - unsigned int rfl, i = 0; + unsigned int rfl, i = 0, fcr = 0; unsigned char buf[MAX_FIFO_SIZE]; struct uart_port *port = &p->port; struct tty_port *tty_port = &p->port.state->port; @@ -169,16 +170,30 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) rfl = serial_port_in(port, UART_RFL_16550A); - while (i < rfl) - buf[i++] = serial_port_in(port, UART_RX); + if (rfl > (p->port.fifosize / 2 - 4)) { + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_T_TRIG_10 | UART_FCR_R_TRIG_01; + serial_port_out(port, UART_FCR, fcr); + } else { + while (i < rfl) + buf[i++] = serial_port_in(port, UART_RX); + } - if (i > 0) { - __dma_rx_complete(p); + __dma_rx_complete(p); + + if (i == 0) { + rfl = serial_port_in(port, UART_RFL_16550A); + if (rfl == 0) { + __dma_rx_complete(p); + tty_flip_buffer_push(tty_port); + } + } else { tty_insert_flip_string(tty_port, buf, i); p->port.icount.rx += i; tty_flip_buffer_push(tty_port); } + if (fcr) + serial_port_out(port, UART_FCR, p->fcr); return 0; } |