# ChangeSet # 2004/02/04 03:05:56-05:00 scott.feldman@xxxxxxxxx # [netdrvr e1000] tx_lock # # * Fix race in Tx performance path with tx_lock. Between checking # if we're out of resources and stopping the queue, we can get # a hard interrupt which will clean up all Tx work, and wake # the queue. Coming out of hard interrupt context, we stop the # queue even though no work was queued, and all work completed # has been cleaned up. Scenario requires ring to be completely # filled, which is more likely to happen with TSO, since each # TSO send consumes multiple ring entries. # # drivers/net/e1000/e1000_main.c # 2004/02/02 15:08:10-05:00 scott.feldman@xxxxxxxxx +12 -0 # tx_lock # # drivers/net/e1000/e1000.h # 2004/02/02 15:07:29-05:00 scott.feldman@xxxxxxxxx +1 -0 # tx_lock # diff -Nru a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h --- a/drivers/net/e1000/e1000.h Sat Feb 28 18:40:30 2004 +++ b/drivers/net/e1000/e1000.h Sat Feb 28 18:40:30 2004 @@ -202,6 +202,7 @@ /* TX */ struct e1000_desc_ring tx_ring; + spinlock_t tx_lock; uint32_t txd_cmd; uint32_t tx_int_delay; uint32_t tx_abs_int_delay; diff -Nru a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c --- a/drivers/net/e1000/e1000_main.c Sat Feb 28 18:40:30 2004 +++ b/drivers/net/e1000/e1000_main.c Sat Feb 28 18:40:30 2004 @@ -678,6 +678,7 @@ atomic_set(&adapter->irq_sem, 1); spin_lock_init(&adapter->stats_lock); + spin_lock_init(&adapter->tx_lock); return 0; } @@ -1765,6 +1766,7 @@ struct e1000_adapter *adapter = netdev->priv; unsigned int first; unsigned int tx_flags = 0; + unsigned long flags; int count; if(skb->len <= 0) { @@ -1772,10 +1774,13 @@ return 0; } + spin_lock_irqsave(&adapter->tx_lock, flags); + if(adapter->hw.mac_type == e1000_82547) { if(e1000_82547_fifo_workaround(adapter, skb)) { netif_stop_queue(netdev); mod_timer(&adapter->tx_fifo_stall_timer, jiffies); + spin_unlock_irqrestore(&adapter->tx_lock, flags); return 1; } } @@ -1796,11 +1801,14 @@ e1000_tx_queue(adapter, count, tx_flags); else { netif_stop_queue(netdev); + spin_unlock_irqrestore(&adapter->tx_lock, flags); return 1; } netdev->trans_start = jiffies; + spin_unlock_irqrestore(&adapter->tx_lock, flags); + return 0; } @@ -2154,6 +2162,8 @@ unsigned int i, eop; boolean_t cleaned = FALSE; + spin_lock(&adapter->tx_lock); + i = tx_ring->next_to_clean; eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); @@ -2197,6 +2207,8 @@ if(cleaned && netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) netif_wake_queue(netdev); + + spin_unlock(&adapter->tx_lock); return cleaned; }