aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Brandeburg <jesse.brandeburg@intel.com>2009-09-25 08:18:07 -0400
committerDavid S. Miller <davem@davemloft.net>2009-09-26 23:15:42 -0400
commitcdd7549e27bf5e8abc4e19d5e8d110b8252b4fe4 (patch)
tree20682463abca2954c6a50ec1ac77971e989becc3
parentbe0f071956e2142e2e88e9d6d5655ba1c75d07c8 (diff)
e1000: fix tx waking queue after queue stopped during shutdown
This fix closes a race where the adapter can be shutting down while hard_start_xmit is being called and interrupts are being handled. Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com> Signed-off-by: Don Skidmore <donald.c.skidmore@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/e1000/e1000_main.c15
1 files changed, 9 insertions, 6 deletions
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 11508afdfdb9..8c64363faaf3 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -2733,8 +2733,9 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
2733 size -= 4; 2733 size -= 4;
2734 2734
2735 buffer_info->length = size; 2735 buffer_info->length = size;
2736 buffer_info->dma = skb_shinfo(skb)->dma_head + offset; 2736 /* set time_stamp *before* dma to help avoid a possible race */
2737 buffer_info->time_stamp = jiffies; 2737 buffer_info->time_stamp = jiffies;
2738 buffer_info->dma = skb_shinfo(skb)->dma_head + offset;
2738 buffer_info->next_to_watch = i; 2739 buffer_info->next_to_watch = i;
2739 2740
2740 len -= size; 2741 len -= size;
@@ -2774,8 +2775,8 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
2774 size -= 4; 2775 size -= 4;
2775 2776
2776 buffer_info->length = size; 2777 buffer_info->length = size;
2777 buffer_info->dma = map[f] + offset;
2778 buffer_info->time_stamp = jiffies; 2778 buffer_info->time_stamp = jiffies;
2779 buffer_info->dma = map[f] + offset;
2779 buffer_info->next_to_watch = i; 2780 buffer_info->next_to_watch = i;
2780 2781
2781 len -= size; 2782 len -= size;
@@ -3459,7 +3460,9 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
3459 * sees the new next_to_clean. 3460 * sees the new next_to_clean.
3460 */ 3461 */
3461 smp_mb(); 3462 smp_mb();
3462 if (netif_queue_stopped(netdev)) { 3463
3464 if (netif_queue_stopped(netdev) &&
3465 !(test_bit(__E1000_DOWN, &adapter->flags))) {
3463 netif_wake_queue(netdev); 3466 netif_wake_queue(netdev);
3464 ++adapter->restart_queue; 3467 ++adapter->restart_queue;
3465 } 3468 }
@@ -3469,8 +3472,8 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
3469 /* Detect a transmit hang in hardware, this serializes the 3472 /* Detect a transmit hang in hardware, this serializes the
3470 * check with the clearing of time_stamp and movement of i */ 3473 * check with the clearing of time_stamp and movement of i */
3471 adapter->detect_tx_hung = false; 3474 adapter->detect_tx_hung = false;
3472 if (tx_ring->buffer_info[i].time_stamp && 3475 if (tx_ring->buffer_info[eop].time_stamp &&
3473 time_after(jiffies, tx_ring->buffer_info[i].time_stamp + 3476 time_after(jiffies, tx_ring->buffer_info[eop].time_stamp +
3474 (adapter->tx_timeout_factor * HZ)) 3477 (adapter->tx_timeout_factor * HZ))
3475 && !(er32(STATUS) & E1000_STATUS_TXOFF)) { 3478 && !(er32(STATUS) & E1000_STATUS_TXOFF)) {
3476 3479
@@ -3492,7 +3495,7 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
3492 readl(hw->hw_addr + tx_ring->tdt), 3495 readl(hw->hw_addr + tx_ring->tdt),
3493 tx_ring->next_to_use, 3496 tx_ring->next_to_use,
3494 tx_ring->next_to_clean, 3497 tx_ring->next_to_clean,
3495 tx_ring->buffer_info[i].time_stamp, 3498 tx_ring->buffer_info[eop].time_stamp,
3496 eop, 3499 eop,
3497 jiffies, 3500 jiffies,
3498 eop_desc->upper.fields.status); 3501 eop_desc->upper.fields.status);