[PATCH] e1000: Avoid race between e1000_watchdog

Linux Kernel Mailing List <[email protected]> Thu, 24 Feb 2005 05:40:41 +0000
Newsgroups gmane.linux.kernel.commits.2-4
Message-ID <[email protected]>
ChangeSet 1.1548.1.3, 2005/02/24 00:40:41-05:00, [email protected]

	[PATCH] e1000: Avoid race between e1000_watchdog
	
	3 Avoid race condition between e1000_watchdog and e1000_clean_tx_irq
	Signed-off-by: Mallikarjuna R Chilakala <[email protected]>
	Signed-off-by: Ganesh Venkatesan <[email protected]>
	Signed-off-by: John Ronciak <[email protected]>
	Signed-off-by: Jeff Garzik <[email protected]>



 e1000.h      |    1 +
 e1000_main.c |   19 ++++++++++++-------
 2 files changed, 13 insertions(+), 7 deletions(-)


diff -Nru a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
--- a/drivers/net/e1000/e1000.h	2005-03-04 12:02:48 -08:00
+++ b/drivers/net/e1000/e1000.h	2005-03-04 12:02:48 -08:00
@@ -224,6 +224,7 @@
 	uint32_t tx_fifo_size;
 	atomic_t tx_fifo_stall;
 	boolean_t pcix_82544;
+	boolean_t detect_tx_hung;
 
 	/* RX */
 	struct e1000_desc_ring rx_ring;
diff -Nru a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
--- a/drivers/net/e1000/e1000_main.c	2005-03-04 12:02:48 -08:00
+++ b/drivers/net/e1000/e1000_main.c	2005-03-04 12:02:48 -08:00
@@ -1422,7 +1422,6 @@
 	struct e1000_adapter *adapter = (struct e1000_adapter *) data;
 	struct net_device *netdev = adapter->netdev;
 	struct e1000_desc_ring *txdr = &adapter->tx_ring;
-	unsigned int i;
 	uint32_t link;
 
 	e1000_check_for_link(&adapter->hw);
@@ -1502,12 +1501,8 @@
 	/* Cause software interrupt to ensure rx ring is cleaned */
 	E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_RXDMT0);
 
-	/* Early detection of hung controller */
-	i = txdr->next_to_clean;
-	if(txdr->buffer_info[i].dma &&
-	   time_after(jiffies, txdr->buffer_info[i].time_stamp + HZ) &&
-	   !(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF))
-		netif_stop_queue(netdev);
+	/* Force detection of hung controller every watchdog period*/
+	adapter->detect_tx_hung = TRUE;
 
 	/* Reset the timer */
 	mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
@@ -2226,6 +2221,16 @@
 		netif_wake_queue(netdev);
 
 	spin_unlock(&adapter->tx_lock);
+ 
+	if(adapter->detect_tx_hung) {
+		/* detect a transmit hang in hardware, this serializes the
+		 * check with the clearing of time_stamp and movement of i */
+		adapter->detect_tx_hung = FALSE;
+		if(tx_ring->buffer_info[i].dma &&
+		   time_after(jiffies, tx_ring->buffer_info[i].time_stamp + HZ) &&
+		   !(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF))
+			netif_stop_queue(netdev);
+	}
 
 	return cleaned;
 }