serial: 8250_dma: add timer for dma receive

For rockchip serial, received data available and character timeout
interrupts are both enabled by IER[0]. Then when there is data in
the FIFO, received data available interrupt will occurd frequently.
So we must disable it, but which may disable the character timeout
interrput. Then it is useful to add a timer to report the data received
in dma buffer every 10 microsecond.

Change-Id: I6530b17800435b288a7309bb5998176decb94297
Signed-off-by: Huibin Hong <huibin.hong@rock-chips.com>
This commit is contained in:
Huibin Hong
2016-10-24 18:04:50 +08:00
parent e2f1d149c7
commit 12660c60ba
2 changed files with 55 additions and 3 deletions

View File

@@ -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 {

View File

@@ -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,