diff options
author | Sonic Zhang <sonic.zhang@analog.com> | 2008-02-25 02:16:50 -0500 |
---|---|---|
committer | Bryan Wu <cooloney@kernel.org> | 2008-02-25 02:16:50 -0500 |
commit | 0711d857605ba598cd6d4254462d1419b233321b (patch) | |
tree | cb8793180ab496b299eaab0c21fc29fb6f3e763b /drivers/serial | |
parent | db288381e26e592b11572ce8199bedeadf0c0830 (diff) |
Blackfin Serial Driver: Fix bug - Increase buffer tail immediately before starting tx dma.
http://blackfin.uclinux.org/gf/project/uclinux-dist/tracker/?action=TrackerItemEdit&tracker_item_id=2920
Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
Signed-off-by: Bryan Wu <cooloney@kernel.org>
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/bfin_5xx.c | 32 |
1 files changed, 18 insertions, 14 deletions
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 69ac7007682e..2fb3081c5022 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c | |||
@@ -64,15 +64,20 @@ static void bfin_serial_mctrl_check(struct bfin_serial_port *uart); | |||
64 | static void bfin_serial_stop_tx(struct uart_port *port) | 64 | static void bfin_serial_stop_tx(struct uart_port *port) |
65 | { | 65 | { |
66 | struct bfin_serial_port *uart = (struct bfin_serial_port *)port; | 66 | struct bfin_serial_port *uart = (struct bfin_serial_port *)port; |
67 | struct circ_buf *xmit = &uart->port.info->xmit; | ||
67 | #if !defined(CONFIG_BF54x) && !defined(CONFIG_SERIAL_BFIN_DMA) | 68 | #if !defined(CONFIG_BF54x) && !defined(CONFIG_SERIAL_BFIN_DMA) |
68 | unsigned short ier; | 69 | unsigned short ier; |
69 | #endif | 70 | #endif |
70 | 71 | ||
71 | while (!(UART_GET_LSR(uart) & TEMT)) | 72 | while (!(UART_GET_LSR(uart) & TEMT)) |
72 | continue; | 73 | cpu_relax(); |
73 | 74 | ||
74 | #ifdef CONFIG_SERIAL_BFIN_DMA | 75 | #ifdef CONFIG_SERIAL_BFIN_DMA |
75 | disable_dma(uart->tx_dma_channel); | 76 | disable_dma(uart->tx_dma_channel); |
77 | xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); | ||
78 | uart->port.icount.tx += uart->tx_count; | ||
79 | uart->tx_count = 0; | ||
80 | uart->tx_done = 1; | ||
76 | #else | 81 | #else |
77 | #ifdef CONFIG_BF54x | 82 | #ifdef CONFIG_BF54x |
78 | /* Clear TFI bit */ | 83 | /* Clear TFI bit */ |
@@ -94,7 +99,8 @@ static void bfin_serial_start_tx(struct uart_port *port) | |||
94 | struct bfin_serial_port *uart = (struct bfin_serial_port *)port; | 99 | struct bfin_serial_port *uart = (struct bfin_serial_port *)port; |
95 | 100 | ||
96 | #ifdef CONFIG_SERIAL_BFIN_DMA | 101 | #ifdef CONFIG_SERIAL_BFIN_DMA |
97 | bfin_serial_dma_tx_chars(uart); | 102 | if (uart->tx_done) |
103 | bfin_serial_dma_tx_chars(uart); | ||
98 | #else | 104 | #else |
99 | #ifdef CONFIG_BF54x | 105 | #ifdef CONFIG_BF54x |
100 | UART_SET_IER(uart, ETBEI); | 106 | UART_SET_IER(uart, ETBEI); |
@@ -389,12 +395,10 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) | |||
389 | unsigned short ier; | 395 | unsigned short ier; |
390 | int flags = 0; | 396 | int flags = 0; |
391 | 397 | ||
392 | if (!uart->tx_done) | ||
393 | return; | ||
394 | uart->tx_done = 0; | 398 | uart->tx_done = 0; |
395 | 399 | ||
396 | if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { | 400 | if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { |
397 | bfin_serial_stop_tx(&uart->port); | 401 | uart->tx_count = 0; |
398 | uart->tx_done = 1; | 402 | uart->tx_done = 1; |
399 | return; | 403 | return; |
400 | } | 404 | } |
@@ -428,9 +432,6 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) | |||
428 | set_dma_x_modify(uart->tx_dma_channel, 1); | 432 | set_dma_x_modify(uart->tx_dma_channel, 1); |
429 | enable_dma(uart->tx_dma_channel); | 433 | enable_dma(uart->tx_dma_channel); |
430 | 434 | ||
431 | xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); | ||
432 | uart->port.icount.tx += uart->tx_count; | ||
433 | |||
434 | #ifdef CONFIG_BF54x | 435 | #ifdef CONFIG_BF54x |
435 | UART_SET_IER(uart, ETBEI); | 436 | UART_SET_IER(uart, ETBEI); |
436 | #else | 437 | #else |
@@ -515,8 +516,8 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id) | |||
515 | 516 | ||
516 | spin_lock(&uart->port.lock); | 517 | spin_lock(&uart->port.lock); |
517 | if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) { | 518 | if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) { |
518 | clear_dma_irqstat(uart->tx_dma_channel); | ||
519 | disable_dma(uart->tx_dma_channel); | 519 | disable_dma(uart->tx_dma_channel); |
520 | clear_dma_irqstat(uart->tx_dma_channel); | ||
520 | #ifdef CONFIG_BF54x | 521 | #ifdef CONFIG_BF54x |
521 | UART_CLEAR_IER(uart, ETBEI); | 522 | UART_CLEAR_IER(uart, ETBEI); |
522 | #else | 523 | #else |
@@ -527,7 +528,8 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id) | |||
527 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | 528 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) |
528 | uart_write_wakeup(&uart->port); | 529 | uart_write_wakeup(&uart->port); |
529 | 530 | ||
530 | uart->tx_done = 1; | 531 | xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); |
532 | uart->port.icount.tx += uart->tx_count; | ||
531 | 533 | ||
532 | bfin_serial_dma_tx_chars(uart); | 534 | bfin_serial_dma_tx_chars(uart); |
533 | } | 535 | } |
@@ -542,12 +544,14 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id) | |||
542 | unsigned short irqstat; | 544 | unsigned short irqstat; |
543 | 545 | ||
544 | uart->rx_dma_nrows++; | 546 | uart->rx_dma_nrows++; |
545 | if (uart->rx_dma_nrows == DMA_RX_YCOUNT) { | 547 | uart->rx_dma_buf.tail = DMA_RX_XCOUNT * uart->rx_dma_nrows; |
548 | bfin_serial_dma_rx_chars(uart); | ||
549 | if (uart->rx_dma_nrows >= DMA_RX_YCOUNT) { | ||
546 | uart->rx_dma_nrows = 0; | 550 | uart->rx_dma_nrows = 0; |
547 | uart->rx_dma_buf.tail = DMA_RX_XCOUNT*DMA_RX_YCOUNT; | 551 | uart->rx_dma_buf.tail = 0; |
548 | bfin_serial_dma_rx_chars(uart); | ||
549 | uart->rx_dma_buf.head = uart->rx_dma_buf.tail = 0; | ||
550 | } | 552 | } |
553 | uart->rx_dma_buf.head = uart->rx_dma_buf.tail; | ||
554 | |||
551 | spin_lock(&uart->port.lock); | 555 | spin_lock(&uart->port.lock); |
552 | irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); | 556 | irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); |
553 | clear_dma_irqstat(uart->rx_dma_channel); | 557 | clear_dma_irqstat(uart->rx_dma_channel); |