summary refs log tree commit diff
path: root/drivers/serial
diff options
context:
space:
mode:
authorSonic Zhang <sonic.zhang@analog.com>2008-02-25 15:16:50 +0800
committerBryan Wu <cooloney@kernel.org>2008-02-25 15:16:50 +0800
commit0711d857605ba598cd6d4254462d1419b233321b (patch)
treecb8793180ab496b299eaab0c21fc29fb6f3e763b /drivers/serial
parentdb288381e26e592b11572ce8199bedeadf0c0830 (diff)
downloadlinux-0711d857605ba598cd6d4254462d1419b233321b.tar.gz
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.c32
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);
 static void bfin_serial_stop_tx(struct uart_port *port)
 {
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+	struct circ_buf *xmit = &uart->port.info->xmit;
 #if !defined(CONFIG_BF54x) && !defined(CONFIG_SERIAL_BFIN_DMA)
 	unsigned short ier;
 #endif
 
 	while (!(UART_GET_LSR(uart) & TEMT))
-		continue;
+		cpu_relax();
 
 #ifdef CONFIG_SERIAL_BFIN_DMA
 	disable_dma(uart->tx_dma_channel);
+	xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
+	uart->port.icount.tx += uart->tx_count;
+	uart->tx_count = 0;
+	uart->tx_done = 1;
 #else
 #ifdef CONFIG_BF54x
 	/* Clear TFI bit */
@@ -94,7 +99,8 @@ static void bfin_serial_start_tx(struct uart_port *port)
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
 
 #ifdef CONFIG_SERIAL_BFIN_DMA
-	bfin_serial_dma_tx_chars(uart);
+	if (uart->tx_done)
+		bfin_serial_dma_tx_chars(uart);
 #else
 #ifdef CONFIG_BF54x
 	UART_SET_IER(uart, ETBEI);
@@ -389,12 +395,10 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
 	unsigned short ier;
 	int flags = 0;
 
-	if (!uart->tx_done)
-		return;
 	uart->tx_done = 0;
 
 	if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
-		bfin_serial_stop_tx(&uart->port);
+		uart->tx_count = 0;
 		uart->tx_done = 1;
 		return;
 	}
@@ -428,9 +432,6 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
 	set_dma_x_modify(uart->tx_dma_channel, 1);
 	enable_dma(uart->tx_dma_channel);
 
-	xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
-	uart->port.icount.tx += uart->tx_count;
-
 #ifdef CONFIG_BF54x
 	UART_SET_IER(uart, ETBEI);
 #else
@@ -515,8 +516,8 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
 
 	spin_lock(&uart->port.lock);
 	if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
-		clear_dma_irqstat(uart->tx_dma_channel);
 		disable_dma(uart->tx_dma_channel);
+		clear_dma_irqstat(uart->tx_dma_channel);
 #ifdef CONFIG_BF54x
 		UART_CLEAR_IER(uart, ETBEI);
 #else
@@ -527,7 +528,8 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
 		if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 			uart_write_wakeup(&uart->port);
 
-		uart->tx_done = 1;
+		xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
+		uart->port.icount.tx += uart->tx_count;
 
 		bfin_serial_dma_tx_chars(uart);
 	}
@@ -542,12 +544,14 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
 	unsigned short irqstat;
 
 	uart->rx_dma_nrows++;
-	if (uart->rx_dma_nrows == DMA_RX_YCOUNT) {
+	uart->rx_dma_buf.tail = DMA_RX_XCOUNT * uart->rx_dma_nrows;
+	bfin_serial_dma_rx_chars(uart);
+	if (uart->rx_dma_nrows >= DMA_RX_YCOUNT) {
 		uart->rx_dma_nrows = 0;
-		uart->rx_dma_buf.tail = DMA_RX_XCOUNT*DMA_RX_YCOUNT;
-		bfin_serial_dma_rx_chars(uart);
-		uart->rx_dma_buf.head = uart->rx_dma_buf.tail = 0;
+		uart->rx_dma_buf.tail = 0;
 	}
+	uart->rx_dma_buf.head = uart->rx_dma_buf.tail;
+
 	spin_lock(&uart->port.lock);
 	irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
 	clear_dma_irqstat(uart->rx_dma_channel);