mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 12:17:12 +09:00
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:
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user