Title: [7720] trunk: Split uart rx lock from uart lock to avoid dead lock.
Revision
7720
Author
sonicz
Date
2009-10-27 06:19:14 -0400 (Tue, 27 Oct 2009)

Log Message

Split uart rx lock from uart lock to avoid dead lock.

rx lock in bfin serial driver is used to protect rx buffer from
concurrent access in DMA mode in timer and rx interrupt routines
on different CPUs. It is independant from uart lock which is to
protect tx buffer. Uart tx transfer may be started up from rx
interrupt handler with lock held if low latency is expected. This
dead lock is avoided by splitting rx and tx lock.

In PIO mode, rx lock is not necessary, because handle_simple_irq
and handle_level_irq ensure driver interrupt handler is called once
on one core.

Modified Paths

Diff

Modified: trunk/arch/blackfin/include/asm/bfin_serial.h (7719 => 7720)


--- trunk/arch/blackfin/include/asm/bfin_serial.h	2009-10-27 09:57:14 UTC (rev 7719)
+++ trunk/arch/blackfin/include/asm/bfin_serial.h	2009-10-27 10:19:14 UTC (rev 7720)
@@ -12,6 +12,7 @@
 #include <linux/serial_core.h>
 #include <mach/anomaly.h>
 #include <mach/bfin_serial.h>
+#include <linux/spinlock.h>
 
 #if defined(CONFIG_BFIN_UART0_CTSRTS) || \
     defined(CONFIG_BFIN_UART1_CTSRTS) || \
@@ -37,6 +38,7 @@
 	struct circ_buf rx_dma_buf;
 	struct timer_list rx_dma_timer;
 	int rx_dma_nrows;
+	spinlock_t rx_lock;
 	unsigned int tx_dma_channel;
 	unsigned int rx_dma_channel;
 	struct work_struct tx_dma_workqueue;

Modified: trunk/drivers/serial/bfin_5xx.c (7719 => 7720)


--- trunk/drivers/serial/bfin_5xx.c	2009-10-27 09:57:14 UTC (rev 7719)
+++ trunk/drivers/serial/bfin_5xx.c	2009-10-27 10:19:14 UTC (rev 7720)
@@ -365,10 +365,8 @@
 {
 	struct bfin_serial_port *uart = dev_id;
 
-	spin_lock(&uart->port.lock);
 	while (UART_GET_LSR(uart) & DR)
 		bfin_serial_rx_chars(uart);
-	spin_unlock(&uart->port.lock);
 
 	return IRQ_HANDLED;
 }
@@ -487,7 +485,7 @@
 
 	dma_disable_irq(uart->tx_dma_channel);
 	dma_disable_irq(uart->rx_dma_channel);
-	spin_lock_bh(&uart->port.lock);
+	spin_lock_bh(&uart->rx_lock);
 
 	/* 2D DMA RX buffer ring is used. Because curr_y_count and
 	 * curr_x_count can't be read as an atomic operation,
@@ -518,7 +516,7 @@
 		uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
 	}
 
-	spin_unlock_bh(&uart->port.lock);
+	spin_unlock_bh(&uart->rx_lock);
 	dma_enable_irq(uart->tx_dma_channel);
 	dma_enable_irq(uart->rx_dma_channel);
 
@@ -566,7 +564,7 @@
 	unsigned short irqstat;
 	int x_pos, pos;
 
-	spin_lock(&uart->port.lock);
+	spin_lock(&uart->rx_lock);
 	irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
 	clear_dma_irqstat(uart->rx_dma_channel);
 
@@ -584,7 +582,7 @@
 		uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
 	}
 
-	spin_unlock(&uart->port.lock);
+	spin_unlock(&uart->rx_lock);
 
 	return IRQ_HANDLED;
 }
@@ -1333,6 +1331,7 @@
 		}
 
 #ifdef CONFIG_SERIAL_BFIN_DMA
+		spin_lock_init(&uart->rx_lock);
 		uart->tx_done	    = 1;
 		uart->tx_count	    = 0;
 
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits

Reply via email to