Browse Source

tty: serial: 8250_dma: keep own book keeping about RX transfers

After dmaengine_terminate_all() has been invoked then both DMA drivers
(edma and omap-dma) do not invoke dma_cookie_complete() to mark the
transfer as complete. This dma_cookie_complete() is performed by the
Synopsys DesignWare driver which is probably the only one that is used
by omap8250-dma and hence don't see following problem…
…which is that once a RX transfer has been terminated then following
query of channel status reports DMA_IN_PROGRESS (again: the actual
transfer has been canceled, there is nothing going on anymore).

This means that serial8250_rx_dma() never enqueues another DMA transfer
because it (wrongly) assumes that there is a transer already pending.

Vinod Koul refuses to accept a patch which adds this
dma_cookie_complete() to both drivers and so dmaengine_tx_status() would
report DMA_COMPLETE instead (and behave like the Synopsys DesignWare
driver already does). He argues that I am not allowed to use the cookie
to query the status and that the driver already cleaned everything up after
the invokation of dmaengine_terminate_all().

To end this I add a bookkeeping whether or not a RX-transfer has been
started to the 8250-dma code. It has already been done for the TX side.
*Now* we learn about the RX status based on our bookkeeping and don't
need dmaengine_tx_status() for this anymore.

Cc: vinod.koul@intel.com
Reviewed-by: Tony Lindgren <tony@atomide.com>
Tested-by: Tony Lindgren <tony@atomide.com>
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>
Sebastian Andrzej Siewior 11 years ago
parent
commit
0fcb7901f9
2 changed files with 5 additions and 6 deletions
  1. 1 0
      drivers/tty/serial/8250/8250.h
  2. 4 6
      drivers/tty/serial/8250/8250_dma.c

+ 1 - 0
drivers/tty/serial/8250/8250.h

@@ -42,6 +42,7 @@ struct uart_8250_dma {
 
 
 	unsigned char		tx_running:1;
 	unsigned char		tx_running:1;
 	unsigned char		tx_err: 1;
 	unsigned char		tx_err: 1;
+	unsigned char		rx_running:1;
 };
 };
 
 
 struct old_serial_port {
 struct old_serial_port {

+ 4 - 6
drivers/tty/serial/8250/8250_dma.c

@@ -61,6 +61,7 @@ static void __dma_rx_complete(void *param)
 	dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
 	dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
 				dma->rx_size, DMA_FROM_DEVICE);
 				dma->rx_size, DMA_FROM_DEVICE);
 
 
+	dma->rx_running = 0;
 	dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
 	dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
 	dmaengine_terminate_all(dma->rxchan);
 	dmaengine_terminate_all(dma->rxchan);
 
 
@@ -123,10 +124,6 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
 {
 {
 	struct uart_8250_dma		*dma = p->dma;
 	struct uart_8250_dma		*dma = p->dma;
 	struct dma_async_tx_descriptor	*desc;
 	struct dma_async_tx_descriptor	*desc;
-	struct dma_tx_state		state;
-	int				dma_status;
-
-	dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
 
 
 	switch (iir & 0x3f) {
 	switch (iir & 0x3f) {
 	case UART_IIR_RLSI:
 	case UART_IIR_RLSI:
@@ -137,7 +134,7 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
 		 * If RCVR FIFO trigger level was not reached, complete the
 		 * If RCVR FIFO trigger level was not reached, complete the
 		 * transfer and let 8250_core copy the remaining data.
 		 * transfer and let 8250_core copy the remaining data.
 		 */
 		 */
-		if (dma_status == DMA_IN_PROGRESS) {
+		if (dma->rx_running) {
 			dmaengine_pause(dma->rxchan);
 			dmaengine_pause(dma->rxchan);
 			__dma_rx_complete(p);
 			__dma_rx_complete(p);
 		}
 		}
@@ -146,7 +143,7 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
 		break;
 		break;
 	}
 	}
 
 
-	if (dma_status)
+	if (dma->rx_running)
 		return 0;
 		return 0;
 
 
 	desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
 	desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
@@ -155,6 +152,7 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
 	if (!desc)
 	if (!desc)
 		return -EBUSY;
 		return -EBUSY;
 
 
+	dma->rx_running = 1;
 	desc->callback = __dma_rx_complete;
 	desc->callback = __dma_rx_complete;
 	desc->callback_param = p;
 	desc->callback_param = p;