|
@@ -36,8 +36,16 @@ 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))
|
|
|
- serial8250_tx_dma(p);
|
|
|
+ if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) {
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = serial8250_tx_dma(p);
|
|
|
+ if (ret) {
|
|
|
+ dma->tx_err = 1;
|
|
|
+ p->ier |= UART_IER_THRI;
|
|
|
+ serial_port_out(&p->port, UART_IER, p->ier);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
spin_unlock_irqrestore(&p->port.lock, flags);
|
|
|
}
|
|
@@ -69,6 +77,7 @@ int serial8250_tx_dma(struct uart_8250_port *p)
|
|
|
struct uart_8250_dma *dma = p->dma;
|
|
|
struct circ_buf *xmit = &p->port.state->xmit;
|
|
|
struct dma_async_tx_descriptor *desc;
|
|
|
+ int ret;
|
|
|
|
|
|
if (uart_tx_stopped(&p->port) || dma->tx_running ||
|
|
|
uart_circ_empty(xmit))
|
|
@@ -80,8 +89,10 @@ int serial8250_tx_dma(struct uart_8250_port *p)
|
|
|
dma->tx_addr + xmit->tail,
|
|
|
dma->tx_size, DMA_MEM_TO_DEV,
|
|
|
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
|
|
- if (!desc)
|
|
|
- return -EBUSY;
|
|
|
+ if (!desc) {
|
|
|
+ ret = -EBUSY;
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
|
|
|
dma->tx_running = 1;
|
|
|
|
|
@@ -94,8 +105,17 @@ int serial8250_tx_dma(struct uart_8250_port *p)
|
|
|
UART_XMIT_SIZE, DMA_TO_DEVICE);
|
|
|
|
|
|
dma_async_issue_pending(dma->txchan);
|
|
|
-
|
|
|
+ if (dma->tx_err) {
|
|
|
+ dma->tx_err = 0;
|
|
|
+ if (p->ier & UART_IER_THRI) {
|
|
|
+ p->ier &= ~UART_IER_THRI;
|
|
|
+ serial_out(p, UART_IER, p->ier);
|
|
|
+ }
|
|
|
+ }
|
|
|
return 0;
|
|
|
+err:
|
|
|
+ dma->tx_err = 1;
|
|
|
+ return ret;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(serial8250_tx_dma);
|
|
|
|