• Michael Chan's avatar
    [BNX2]: Fix tx race condition. · 2f8af120
    Michael Chan authored
    Fix a subtle race condition between bnx2_start_xmit() and bnx2_tx_int()
    similar to the one in tg3 discovered by Herbert Xu:
    
    CPU0					CPU1
    bnx2_start_xmit()
    	if (tx_ring_full) {
    		tx_lock
    					bnx2_tx()
    						if (!netif_queue_stopped)
    		netif_stop_queue()
    		if (!tx_ring_full)
    						update_tx_ring
    			netif_wake_queue()
    		tx_unlock
    	}
    
    Even though tx_ring is updated before the if statement in bnx2_tx_int() in
    program order, it can be re-ordered by the CPU as shown above.  This
    scenario can cause the tx queue to be stopped forever if bnx2_tx_int() has
    just freed up the entire tx_ring.  The possibility of this happening
    should be very rare though.
    
    The following changes are made, very much identical to the tg3 fix:
    
    1. Add memory barrier to fix the above race condition.
    
    2. Eliminate the private tx_lock altogether and rely solely on
    netif_tx_lock.  This eliminates one spinlock in bnx2_start_xmit()
    when the ring is full.
    
    3. Because of 2, use netif_tx_lock in bnx2_tx_int() before calling
    netif_wake_queue().
    
    4. Add memory barrier to bnx2_tx_avail().
    
    5. Add bp->tx_wake_thresh which is set to half the tx ring size.
    
    6. Check for the full wake queue condition before getting
    netif_tx_lock in tg3_tx().  This reduces the number of unnecessary
    spinlocks when the tx ring is full in a steady-state condition.
    Signed-off-by: default avatarMichael Chan <mchan@broadcom.com>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    2f8af120
bnx2.h 186 KB