diff options
author | Michael Chan <mchan@broadcom.com> | 2009-05-06 16:46:47 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-06-15 09:40:13 -0700 |
commit | c31ee0b36f2f808870d52f2ad5ad0dbb21786f4d (patch) | |
tree | 0ac77382b12cc4c5d83991f7e6e2318a7892a7f6 /drivers | |
parent | 56009774704b0cf6052466b82300b4cdd5ccc855 (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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/bnx2.c | 2 |
1 files changed, 2 insertions, 0 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 6b6530ffdf19..a7e688af1cca 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -2585,6 +2585,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; @@ -2864,6 +2865,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; |