aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2009-05-06 16:46:47 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2009-06-11 20:01:20 -0700
commit44c94aa0806d36ee902350027c20c63283923112 (patch)
tree3eec017eec09438aba3314e8604e67c17d71dd72
parent73eb6ac73febd6dea38603b39f78d88ab3cda27a (diff)
bnx2: Fix panic in bnx2_poll_work().
commit 581daf7e00c5e766f26aff80a61a860a17b0d75a upstream. Add barrier() to bnx2_get_hw_{tx|rx}_cons() to fix this issue: http://bugzilla.kernel.org/show_bug.cgi?id=12698 This issue was reported by multiple i386 users. Without barrier(), the compiled code looks like the following where %eax contains the address of the tx_cons or rx_cons in the DMA status block. The status block contents can change between the cmpb and the movzwl instruction. The driver would crash if the value was not 0xff during the cmpb instruction, but changed to 0xff during the movzwl instruction. 6828: 80 38 ff cmpb $0xff,(%eax) 682b: 0f b7 10 movzwl (%eax),%edx With the added barrier(), the compiled code now looks correct: 683d: 0f b7 10 movzwl (%eax),%edx 6840: 0f b6 c2 movzbl %dl,%eax 6843: 3d ff 00 00 00 cmp $0xff,%eax Thanks to Pascal de Bruijn <pmjdebruijn@pcode.nl> for reporting the problem and Holger Noefer <hnoefer@pironet-ndh.com> for patiently testing test patches for us. [greg - took out version change] Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/net/bnx2.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 2486a656f12..ba91aeeef6d 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -2574,6 +2574,7 @@ bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi)
/* Tell compiler that status block fields can change. */
barrier();
cons = *bnapi->hw_tx_cons_ptr;
+ barrier();
if (unlikely((cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT))
cons++;
return cons;
@@ -2849,6 +2850,7 @@ bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi)
/* Tell compiler that status block fields can change. */
barrier();
cons = *bnapi->hw_rx_cons_ptr;
+ barrier();
if (unlikely((cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT))
cons++;
return cons;