[lkml]   [2014]   [Sep]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
Patch in this message
Subject[PATCH 11/16] 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.

Reviewed-by: Tony Lindgren <>
Tested-by: Tony Lindgren <>
Signed-off-by: Sebastian Andrzej Siewior <>
drivers/tty/serial/8250/8250.h | 1 +
drivers/tty/serial/8250/8250_dma.c | 14 ++++++++------
2 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 09489b391568..a7581b37f264 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -42,6 +42,7 @@ struct uart_8250_dma {

unsigned char tx_running:1;
unsigned char tx_err: 1;
+ unsigned char rx_running:1;

struct old_serial_port {
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index e836d128e63a..fa1dc966f394 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -60,6 +60,7 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
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);

@@ -173,21 +174,21 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
struct uart_8250_dma *dma = p->dma;
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) {
/* 8250_core handles errors and break interrupts */
+ if (dma->rx_running) {
+ dmaengine_pause(dma->rxchan);
+ __dma_rx_do_complete(p, true);
+ }
return -EIO;
* 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) {
+ if (dma->rx_running) {
__dma_rx_do_complete(p, true);
@@ -196,7 +197,7 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)

- if (dma_status)
+ if (dma->rx_running)
return 0;

desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
@@ -205,6 +206,7 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
if (!desc)
return -EBUSY;

+ dma->rx_running = 1;
desc->callback = __dma_rx_complete;
desc->callback_param = p;

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to
More majordomo info at
Please read the FAQ at

 \ /
  Last update: 2014-09-10 22:41    [W:0.297 / U:12.052 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site