tty: serial: 8250_omap: add custom DMA-RX callback
The omap needs a DMA request pending right away. If it is enqueued once the bytes are in the FIFO then nothing will happen and the FIFO will be later purged via RX-timeout interrupt. This patch enqueues RX-DMA request on completion but not if it was aborted on error. The first enqueue will happen in the driver in startup. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Reviewed-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
31a171328e
commit
0e31c8d173
@@ -619,6 +619,102 @@ static void omap_8250_unthrottle(struct uart_port *port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_8250_DMA
|
#ifdef CONFIG_SERIAL_8250_DMA
|
||||||
|
static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir);
|
||||||
|
|
||||||
|
static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
|
||||||
|
{
|
||||||
|
struct uart_8250_dma *dma = p->dma;
|
||||||
|
struct tty_port *tty_port = &p->port.state->port;
|
||||||
|
struct dma_tx_state state;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
|
||||||
|
dma->rx_size, DMA_FROM_DEVICE);
|
||||||
|
|
||||||
|
dma->rx_running = 0;
|
||||||
|
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
||||||
|
dmaengine_terminate_all(dma->rxchan);
|
||||||
|
|
||||||
|
count = dma->rx_size - state.residue;
|
||||||
|
|
||||||
|
tty_insert_flip_string(tty_port, dma->rx_buf, count);
|
||||||
|
p->port.icount.rx += count;
|
||||||
|
if (!error)
|
||||||
|
omap_8250_rx_dma(p, 0);
|
||||||
|
|
||||||
|
tty_flip_buffer_push(tty_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __dma_rx_complete(void *param)
|
||||||
|
{
|
||||||
|
__dma_rx_do_complete(param, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
||||||
|
{
|
||||||
|
struct uart_8250_dma *dma = p->dma;
|
||||||
|
struct dma_async_tx_descriptor *desc;
|
||||||
|
|
||||||
|
switch (iir & 0x3f) {
|
||||||
|
case UART_IIR_RLSI:
|
||||||
|
/* 8250_core handles errors and break interrupts */
|
||||||
|
if (dma->rx_running) {
|
||||||
|
dmaengine_pause(dma->rxchan);
|
||||||
|
__dma_rx_do_complete(p, true);
|
||||||
|
}
|
||||||
|
return -EIO;
|
||||||
|
case UART_IIR_RX_TIMEOUT:
|
||||||
|
/*
|
||||||
|
* If RCVR FIFO trigger level was not reached, complete the
|
||||||
|
* transfer and let 8250_core copy the remaining data.
|
||||||
|
*/
|
||||||
|
if (dma->rx_running) {
|
||||||
|
dmaengine_pause(dma->rxchan);
|
||||||
|
__dma_rx_do_complete(p, true);
|
||||||
|
}
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
case UART_IIR_RDI:
|
||||||
|
/*
|
||||||
|
* The OMAP UART is a special BEAST. If we receive RDI we _have_
|
||||||
|
* a DMA transfer programmed but it didn't work. One reason is
|
||||||
|
* that we were too slow and there were too many bytes in the
|
||||||
|
* FIFO, the UART counted wrong and never kicked the DMA engine
|
||||||
|
* to do anything. That means once we receive RDI on OMAP then
|
||||||
|
* the DMA won't do anything soon so we have to cancel the DMA
|
||||||
|
* transfer and purge the FIFO manually.
|
||||||
|
*/
|
||||||
|
if (dma->rx_running) {
|
||||||
|
dmaengine_pause(dma->rxchan);
|
||||||
|
__dma_rx_do_complete(p, true);
|
||||||
|
}
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dma->rx_running)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
|
||||||
|
dma->rx_size, DMA_DEV_TO_MEM,
|
||||||
|
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||||
|
if (!desc)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
dma->rx_running = 1;
|
||||||
|
desc->callback = __dma_rx_complete;
|
||||||
|
desc->callback_param = p;
|
||||||
|
|
||||||
|
dma->rx_cookie = dmaengine_submit(desc);
|
||||||
|
|
||||||
|
dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr,
|
||||||
|
dma->rx_size, DMA_FROM_DEVICE);
|
||||||
|
|
||||||
|
dma_async_issue_pending(dma->rxchan);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int omap_8250_tx_dma(struct uart_8250_port *p);
|
static int omap_8250_tx_dma(struct uart_8250_port *p);
|
||||||
|
|
||||||
static void omap_8250_dma_tx_complete(void *param)
|
static void omap_8250_dma_tx_complete(void *param)
|
||||||
|
|||||||
Reference in New Issue
Block a user