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 <huibin.hong@rock-chips.com>
This commit is contained in:
Huibin Hong 2018-08-31 17:16:16 +08:00
parent fc182ebc51
commit d3b277129e

View File

@ -160,37 +160,34 @@ int serial8250_tx_dma(struct uart_8250_port *p)
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);