diff options
author | Jesse Brandeburg <jesse.brandeburg@intel.com> | 2009-09-25 08:18:07 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-09-26 23:15:42 -0400 |
commit | cdd7549e27bf5e8abc4e19d5e8d110b8252b4fe4 (patch) | |
tree | 20682463abca2954c6a50ec1ac77971e989becc3 /drivers/net/e1000/e1000_main.c | |
parent | be0f071956e2142e2e88e9d6d5655ba1c75d07c8 (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>
Diffstat (limited to 'drivers/net/e1000/e1000_main.c')
-rw-r--r-- | drivers/net/e1000/e1000_main.c | 15 |
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); |