[ 038/187] bnx2x: fix panic when TX ring is full

From: Greg Kroah-Hartman
Date: Thu Jul 12 2012 - 19:42:23 EST


From: Greg KH <gregkh@xxxxxxxxxxxxxxxxxxx>

3.4-stable review patch. If anyone has any objections, please let me know.

------------------


From: Eric Dumazet <edumazet@xxxxxxxxxx>

[ Upstream commit bc14786a100cc6a81cd060e8031ec481241b418c ]

There is a off by one error in the minimal number of BD in
bnx2x_start_xmit() and bnx2x_tx_int() before stopping/resuming tx queue.

A full size GSO packet, with data included in skb->head really needs
(MAX_SKB_FRAGS + 4) BDs, because of bnx2x_tx_split()

This error triggers if BQL is disabled and heavy TCP transmit traffic
occurs.

bnx2x_tx_split() definitely can be called, remove a wrong comment.

Reported-by: Tomas Hruby <thruby@xxxxxxxxxx>
Signed-off-by: Eric Dumazet <edumazet@xxxxxxxxxx>
Cc: Eilon Greenstein <eilong@xxxxxxxxxxxx>
Cc: Yaniv Rosner <yanivr@xxxxxxxxxxxx>
Cc: Merav Sicron <meravs@xxxxxxxxxxxx>
Cc: Tom Herbert <therbert@xxxxxxxxxx>
Cc: Robert Evans <evansr@xxxxxxxxxx>
Cc: Willem de Bruijn <willemb@xxxxxxxxxx>
Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)

--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -191,7 +191,7 @@ int bnx2x_tx_int(struct bnx2x *bp, struc

if ((netif_tx_queue_stopped(txq)) &&
(bp->state == BNX2X_STATE_OPEN) &&
- (bnx2x_tx_avail(bp, txdata) >= MAX_SKB_FRAGS + 3))
+ (bnx2x_tx_avail(bp, txdata) >= MAX_SKB_FRAGS + 4))
netif_tx_wake_queue(txq);

__netif_tx_unlock(txq);
@@ -2349,8 +2349,6 @@ int bnx2x_poll(struct napi_struct *napi,
/* we split the first BD into headers and data BDs
* to ease the pain of our fellow microcode engineers
* we use one mapping for both BDs
- * So far this has only been observed to happen
- * in Other Operating Systems(TM)
*/
static noinline u16 bnx2x_tx_split(struct bnx2x *bp,
struct bnx2x_fp_txdata *txdata,
@@ -3002,7 +3000,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_b

txdata->tx_bd_prod += nbd;

- if (unlikely(bnx2x_tx_avail(bp, txdata) < MAX_SKB_FRAGS + 3)) {
+ if (unlikely(bnx2x_tx_avail(bp, txdata) < MAX_SKB_FRAGS + 4)) {
netif_tx_stop_queue(txq);

/* paired memory barrier is in bnx2x_tx_int(), we have to keep
@@ -3011,7 +3009,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_b
smp_mb();

fp->eth_q_stats.driver_xoff++;
- if (bnx2x_tx_avail(bp, txdata) >= MAX_SKB_FRAGS + 3)
+ if (bnx2x_tx_avail(bp, txdata) >= MAX_SKB_FRAGS + 4)
netif_tx_wake_queue(txq);
}
txdata->tx_pkt++;


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/