diff options
author | Michael Chan <mchan@broadcom.com> | 2010-07-19 10:15:04 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-07-19 23:30:06 -0400 |
commit | 11848b964777af9c68d9160582628c2eb11f46d5 (patch) | |
tree | 6b026650813b24b50da954c5978811246f811a76 /drivers | |
parent | 379b39a2ad613745bfbfe80256957d19689b7b94 (diff) |
bnx2: Remove some unnecessary smp_mb() in tx fast path.
smp_mb() inside bnx2_tx_avail() is used twice in the normal
bnx2_start_xmit() path (see illustration below). The full memory
barrier is only necessary during race conditions with tx completion.
We can speed up the tx path by replacing smp_mb() in bnx2_tx_avail()
with a compiler barrier. The compiler barrier is to force the
compiler to fetch the tx_prod and tx_cons from memory.
In the race condition between bnx2_start_xmit() and bnx2_tx_int(),
we have the following situation:
bnx2_start_xmit() bnx2_tx_int()
if (!bnx2_tx_avail())
BUG();
...
if (!bnx2_tx_avail())
netif_tx_stop_queue(); update_tx_index();
smp_mb(); smp_mb();
if (bnx2_tx_avail()) if (netif_tx_queue_stopped() &&
netif_tx_wake_queue(); bnx2_tx_avail())
With smp_mb() removed from bnx2_tx_avail(), we need to add smp_mb() to
bnx2_start_xmit() as shown above to properly order netif_tx_stop_queue()
and bnx2_tx_avail() to check the ring index. If it is not strictly
ordered, the tx queue can be stopped forever.
This improves performance by about 5% with 2 ports running bi-directional
64-byte packets.
Reviewed-by: Benjamin Li <benli@broadcom.com>
Reviewed-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/bnx2.c | 10 |
1 files changed, 9 insertions, 1 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index d44ecc30865f..2af570d7a2fb 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c | |||
@@ -253,7 +253,8 @@ static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr) | |||
253 | { | 253 | { |
254 | u32 diff; | 254 | u32 diff; |
255 | 255 | ||
256 | smp_mb(); | 256 | /* Tell compiler to fetch tx_prod and tx_cons from memory. */ |
257 | barrier(); | ||
257 | 258 | ||
258 | /* The ring uses 256 indices for 255 entries, one of them | 259 | /* The ring uses 256 indices for 255 entries, one of them |
259 | * needs to be skipped. | 260 | * needs to be skipped. |
@@ -6534,6 +6535,13 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
6534 | 6535 | ||
6535 | if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) { | 6536 | if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) { |
6536 | netif_tx_stop_queue(txq); | 6537 | netif_tx_stop_queue(txq); |
6538 | |||
6539 | /* netif_tx_stop_queue() must be done before checking | ||
6540 | * tx index in bnx2_tx_avail() below, because in | ||
6541 | * bnx2_tx_int(), we update tx index before checking for | ||
6542 | * netif_tx_queue_stopped(). | ||
6543 | */ | ||
6544 | smp_mb(); | ||
6537 | if (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh) | 6545 | if (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh) |
6538 | netif_tx_wake_queue(txq); | 6546 | netif_tx_wake_queue(txq); |
6539 | } | 6547 | } |