• Michael Chan's avatar
    [TG3]: Fix tx race condition · 1b2a7205
    Michael Chan authored
    Fix a subtle race condition between tg3_start_xmit() and tg3_tx()
    discovered by Herbert Xu <herbert@gondor.apana.org.au>:
    
    CPU0					CPU1
    tg3_start_xmit()
    	if (tx_ring_full) {
    		tx_lock
    					tg3_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 tg3_tx() 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 tg3_tx() has
    just freed up the entire tx_ring.  The possibility of this happening
    should be very rare though.
    
    The following changes are made:
    
    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 tg3_start_xmit()
    when the ring is full.
    
    3. Because of 2, use netif_tx_lock in tg3_tx() before calling
    netif_wake_queue().
    
    4. Change TX_BUFFS_AVAIL to an inline function with a memory barrier.
    Herbert and David suggested using the memory barrier instead of
    volatile.
    
    5. 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.
    
    6. Update version to 3.65.
    Signed-off-by: default avatarMichael Chan <mchan@broadcom.com>
    Acked-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    1b2a7205
tg3.h 85.4 KB