From: Stanislaw Gruszka <sgruszka@redhat.com> Date: Fri, 30 Apr 2010 08:26:45 -0400 Subject: [net] bnx2x: fix memory barriers Message-id: <1272616006-3012-1-git-send-email-sgruszka@redhat.com> Patchwork-id: 24703 O-Subject: [RHEL5.6 PATCH 1/2] bnx2x: fix memory barriers Bugzilla: 569370 RH-Acked-by: David S. Miller <davem@redhat.com> From: Stanislaw Gruszka <sgruszka@redhat.com> BZ#569370 Description: Fix memory barriers in TX path. Upstream: Patches are in Linus tree commit 9baddeb8c6c7faa7da8706ad629f09ca221850c1 Author: Stanislaw Gruszka <sgruszka@redhat.com> Date: Tue Mar 9 06:55:02 2010 +0000 bnx2x: change smp_mb() comment to conform the true commit 0efc22f3afa5d8f070a33fea06162d7d9d518e38 Author: Stanislaw Gruszka <sgruszka@redhat.com> Date: Tue Mar 9 06:55:01 2010 +0000 bnx2x: remove not necessary compiler barrier commit 2d99cf16f42b1979a2c498bb6d09498dbd689978 Author: Stanislaw Gruszka <sgruszka@redhat.com> Date: Tue Mar 9 06:55:00 2010 +0000 bnx2x: use smp_mb() to keep ordering of read write operations commit c16cc0b464b8876cfd57ce1c1dbcb6f9a6a0bce3 Author: Vladislav Zolotarov <vladz@broadcom.com> Date: Sun Feb 28 00:12:02 2010 +0000 bnx2x: Tx barriers and locks Testing: Tested by me by trying to stress driver on 1Gbit link :/ diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index b68c9d8..2202ad3 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -56,8 +56,8 @@ #include "bnx2x_init_ops.h" #include "bnx2x_dump.h" -#define DRV_MODULE_VERSION "1.52.1-6" -#define DRV_MODULE_RELDATE "2010/02/16" +#define DRV_MODULE_VERSION "1.52.1-7" +#define DRV_MODULE_RELDATE "2010/02/28" #define BNX2X_BC_VER 0x040200 #include <linux/firmware.h> @@ -885,7 +885,6 @@ static inline u16 bnx2x_tx_avail(struct bnx2x_fastpath *fp) u16 prod; u16 cons; - barrier(); /* Tell compiler that prod and cons can change */ prod = fp->tx_bd_prod; cons = fp->tx_bd_cons; @@ -950,19 +949,28 @@ static int bnx2x_tx_int(struct bnx2x_fastpath *fp) fp->tx_pkt_cons = sw_cons; fp->tx_bd_cons = bd_cons; + /* Need to make the tx_bd_cons update visible to start_xmit() + * before checking for netif_tx_queue_stopped(). Without the + * memory barrier, there is a small possibility that + * start_xmit() will miss it and cause the queue to be stopped + * forever. + */ + smp_mb(); + /* TBD need a thresh? */ if (unlikely(netif_queue_stopped(bp->dev))) { + /* Taking tx_lock() is needed to prevent reenabling the queue + * while it's empty. This could have happen if rx_action() gets + * suspended in bnx2x_tx_int() after the condition before + * netif_tx_wake_queue(), while tx_action (bnx2x_start_xmit()): + * + * stops the queue->sees fresh tx_bd_cons->releases the queue-> + * sends some packets consuming the whole queue again-> + * stops the queue + */ netif_tx_lock(bp->dev); - /* Need to make the tx_bd_cons update visible to start_xmit() - * before checking for netif_tx_queue_stopped(). Without the - * memory barrier, there is a small possibility that - * start_xmit() will miss it and cause the queue to be stopped - * forever. - */ - smp_mb(); - if ((netif_queue_stopped(bp->dev)) && (bp->state == BNX2X_STATE_OPEN) && (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3)) @@ -11449,9 +11457,12 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) { netif_stop_queue(dev); - /* We want bnx2x_tx_int to "see" the updated tx_bd_prod - if we put Tx into XOFF state. */ + + /* paired memory barrier is in bnx2x_tx_int(), we have to keep + * ordering of set_bit() in netif_tx_stop_queue() and read of + * fp->bd_tx_cons */ smp_mb(); + fp->eth_q_stats.driver_xoff++; if (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3) netif_wake_queue(dev);