summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorHuibin Hong <huibin.hong@rock-chips.com>2018-01-03 14:32:56 +0800
committerTao Huang <huangtao@rock-chips.com>2018-01-08 09:17:59 +0800
commit13659af22214ddd9994c416018f9a4fd766ddd93 (patch)
tree9f0f5442293de94dff0110972092f0b87b8ebb47 /drivers
parentfc46944d433a3b47d282ae4c127e37f9b2d7edcc (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.c31
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;
}