diff options
author | Michael Chan <mchan@broadcom.com> | 2006-08-15 01:39:10 -0700 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-08-17 16:29:51 -0700 |
commit | 2f8af120a159a843948749ea88bcacda9779b132 (patch) | |
tree | e633037a72db856b8078e814e3451dd8f44c14de /net/atm | |
parent | fb33f82568d32016b3b3c00819574f9526e52be3 (diff) | |
download | op-kernel-dev-2f8af120a159a843948749ea88bcacda9779b132.zip op-kernel-dev-2f8af120a159a843948749ea88bcacda9779b132.tar.gz |
[BNX2]: Fix tx race condition.
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: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/atm')
0 files changed, 0 insertions, 0 deletions