diff options
author | Michael Trimarchi <trimarchimichael@yahoo.it> | 2008-04-02 16:04:41 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-02 18:28:19 -0400 |
commit | ba0657ff0527bab83387e19eb98b423fcc290674 (patch) | |
tree | e7644086f7425033950980bdae8a457ab151503a /drivers/serial | |
parent | dd135ebbd2a6b5e07dadb66c4dd033bb69531051 (diff) |
atmel_serial: avoid stopping pdc during transmission
I found a problem related to losing data during pdc transmission in
atmel_serial: connect ttyS1 with ttyS2 using a loopback cable, send 30
byte of packet from one to the other and waiting for 30 byte. On the
other side just read and echo the data received.
We always call atmel_tx_dma() from the tasklet regardless of what interrupt
triggered it.
Signed-off-by: michael <trimarchi@gandalf.sssup.it>
Acked-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/atmel_serial.c | 19 |
1 files changed, 10 insertions, 9 deletions
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index d57bf3e708d8..e99a28387505 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c | |||
@@ -96,6 +96,7 @@ | |||
96 | 96 | ||
97 | /* PDC registers */ | 97 | /* PDC registers */ |
98 | #define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR) | 98 | #define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR) |
99 | #define UART_GET_TCR(port) __raw_readl((port)->membase + ATMEL_PDC_TCR) | ||
99 | #define UART_GET_PTSR(port) __raw_readl((port)->membase + ATMEL_PDC_PTSR) | 100 | #define UART_GET_PTSR(port) __raw_readl((port)->membase + ATMEL_PDC_PTSR) |
100 | 101 | ||
101 | #define UART_PUT_RPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RPR) | 102 | #define UART_PUT_RPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RPR) |
@@ -562,17 +563,22 @@ static void atmel_tx_dma(struct uart_port *port) | |||
562 | struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; | 563 | struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; |
563 | int count; | 564 | int count; |
564 | 565 | ||
566 | /* nothing left to transmit? */ | ||
567 | if (UART_GET_TCR(port)) | ||
568 | return; | ||
569 | |||
565 | xmit->tail += pdc->ofs; | 570 | xmit->tail += pdc->ofs; |
566 | xmit->tail &= UART_XMIT_SIZE - 1; | 571 | xmit->tail &= UART_XMIT_SIZE - 1; |
567 | 572 | ||
568 | port->icount.tx += pdc->ofs; | 573 | port->icount.tx += pdc->ofs; |
569 | pdc->ofs = 0; | 574 | pdc->ofs = 0; |
570 | 575 | ||
571 | if (!uart_circ_empty(xmit)) { | 576 | /* more to transmit - setup next transfer */ |
572 | /* more to transmit - setup next transfer */ | ||
573 | 577 | ||
574 | /* disable PDC transmit */ | 578 | /* disable PDC transmit */ |
575 | UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); | 579 | UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); |
580 | |||
581 | if (!uart_circ_empty(xmit)) { | ||
576 | dma_sync_single_for_device(port->dev, | 582 | dma_sync_single_for_device(port->dev, |
577 | pdc->dma_addr, | 583 | pdc->dma_addr, |
578 | pdc->dma_size, | 584 | pdc->dma_size, |
@@ -586,11 +592,6 @@ static void atmel_tx_dma(struct uart_port *port) | |||
586 | /* re-enable PDC transmit and interrupts */ | 592 | /* re-enable PDC transmit and interrupts */ |
587 | UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); | 593 | UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); |
588 | UART_PUT_IER(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE); | 594 | UART_PUT_IER(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE); |
589 | } else { | ||
590 | /* nothing left to transmit - disable the transmitter */ | ||
591 | |||
592 | /* disable PDC transmit */ | ||
593 | UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); | ||
594 | } | 595 | } |
595 | 596 | ||
596 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | 597 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) |