diff options
Diffstat (limited to 'drivers/tty/serial/8250/8250_dma.c')
-rw-r--r-- | drivers/tty/serial/8250/8250_dma.c | 52 |
1 files changed, 34 insertions, 18 deletions
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index b9f7fd28112e..7046769608d4 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -33,10 +33,8 @@ static void __dma_tx_complete(void *param) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&p->port); - if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) { + if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) serial8250_tx_dma(p); - uart_write_wakeup(&p->port); - } } static void __dma_rx_complete(void *param) @@ -67,12 +65,11 @@ int serial8250_tx_dma(struct uart_8250_port *p) struct circ_buf *xmit = &p->port.state->xmit; struct dma_async_tx_descriptor *desc; - if (dma->tx_running) - return -EBUSY; + if (uart_tx_stopped(&p->port) || dma->tx_running || + uart_circ_empty(xmit)) + return 0; dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); - if (!dma->tx_size) - return -EINVAL; desc = dmaengine_prep_slave_single(dma->txchan, dma->tx_addr + xmit->tail, @@ -104,20 +101,29 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) struct dma_tx_state state; int dma_status; - /* - * If RCVR FIFO trigger level was not reached, complete the transfer and - * let 8250.c copy the remaining data. - */ - if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) { - dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, - &state); + dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); + + switch (iir & 0x3f) { + case UART_IIR_RLSI: + /* 8250_core handles errors and break interrupts */ + 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_status == DMA_IN_PROGRESS) { dmaengine_pause(dma->rxchan); __dma_rx_complete(p); } return -ETIMEDOUT; + default: + break; } + if (dma_status) + 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); @@ -143,21 +149,31 @@ int serial8250_request_dma(struct uart_8250_port *p) struct uart_8250_dma *dma = p->dma; dma_cap_mask_t mask; - dma->rxconf.src_addr = p->port.mapbase + UART_RX; - dma->txconf.dst_addr = p->port.mapbase + UART_TX; + /* Default slave configuration parameters */ + 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->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_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); /* Get a channel for RX */ - dma->rxchan = dma_request_channel(mask, dma->fn, dma->rx_param); + dma->rxchan = dma_request_slave_channel_compat(mask, + dma->fn, dma->rx_param, + p->port.dev, "rx"); if (!dma->rxchan) return -ENODEV; dmaengine_slave_config(dma->rxchan, &dma->rxconf); /* Get a channel for TX */ - dma->txchan = dma_request_channel(mask, dma->fn, dma->tx_param); + dma->txchan = dma_request_slave_channel_compat(mask, + dma->fn, dma->tx_param, + p->port.dev, "tx"); if (!dma->txchan) { dma_release_channel(dma->rxchan); return -ENODEV; |