From d3b277129e054fa5a53bf4f27da5090b286c643d Mon Sep 17 00:00:00 2001 From: Huibin Hong Date: Fri, 31 Aug 2018 17:16:16 +0800 Subject: [PATCH] serial: 8250: fix cpu and dmac access uart fifo at the same time If cpu frequency was 1.0 GHz, bluetooth music is unstable. But it is stable when cpu frequency is 400 MHz. Although I had test the uart dma driver many days on rk3088, maybe the cpu frequency was low, and I couldn't produce the issue. In one word, the code is unlogical. The new logic is that increase the fifo water level, if dmac bursts before it, wait until dmac finishes and read the rest data. If dmac doesn't burst after it, then read data from fifo directly. Change-Id: I6fec42a0895df8a0faeba97d05fd36b761744fa2 Signed-off-by: Huibin Hong --- drivers/tty/serial/8250/8250_dma.c | 37 ++++++++++++++---------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index cbac385b01c6..f0b3a84565dd 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -160,37 +160,34 @@ err: int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) { - unsigned int rfl, i = 0, fcr = 0; + unsigned int rfl, i = 0, fcr = 0, cur_index = 0; unsigned char buf[MAX_FIFO_SIZE]; struct uart_port *port = &p->port; struct tty_port *tty_port = &p->port.state->port; + struct dma_tx_state state; + struct uart_8250_dma *dma = p->dma; + if ((iir & 0xf) != UART_IIR_RX_TIMEOUT) return 0; - rfl = serial_port_in(port, UART_RFL_16550A); + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_T_TRIG_10 | UART_FCR_R_TRIG_11; + serial_port_out(port, UART_FCR, fcr); - 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); - } + do { + dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); + cur_index = dma->rx_size - state.residue; + } while (cur_index % dma->rxconf.src_maxburst); + + rfl = serial_port_in(port, UART_RFL_16550A); + while (i < rfl) + buf[i++] = serial_port_in(port, UART_RX); __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); - } + 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);