Browse Source

bnx2x: add gro_check

The patch provides workaround for BUG in FW 7.2.16,
which in GRO mode may miscalculate buffer and
place on SGE one frag less than it could.
It may happen only for some MTUs, we mark these MTUs
with gro_check flag during device initialization or
MTU change.

Next FW should include fix for the issue and the
patch could be reverted.

Signed-off-by: Dmitry Kravkov <dmitry@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Dmitry Kravkov 13 years ago
parent
commit
fe603b4d68

+ 4 - 0
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h

@@ -341,6 +341,7 @@ union db_prod {
 #define SGE_PAGE_SIZE		PAGE_SIZE
 #define SGE_PAGE_SIZE		PAGE_SIZE
 #define SGE_PAGE_SHIFT		PAGE_SHIFT
 #define SGE_PAGE_SHIFT		PAGE_SHIFT
 #define SGE_PAGE_ALIGN(addr)	PAGE_ALIGN((typeof(PAGE_SIZE))(addr))
 #define SGE_PAGE_ALIGN(addr)	PAGE_ALIGN((typeof(PAGE_SIZE))(addr))
+#define SGE_PAGES		(SGE_PAGE_SIZE * PAGES_PER_SGE)
 
 
 /* SGE ring related macros */
 /* SGE ring related macros */
 #define NUM_RX_SGE_PAGES	2
 #define NUM_RX_SGE_PAGES	2
@@ -1210,6 +1211,7 @@ struct bnx2x {
 #define ETH_MAX_JUMBO_PACKET_SIZE	9600
 #define ETH_MAX_JUMBO_PACKET_SIZE	9600
 /* TCP with Timestamp Option (32) + IPv6 (40) */
 /* TCP with Timestamp Option (32) + IPv6 (40) */
 #define ETH_MAX_TPA_HEADER_SIZE		72
 #define ETH_MAX_TPA_HEADER_SIZE		72
+#define ETH_MIN_TPA_HEADER_SIZE		40
 
 
 	/* Max supported alignment is 256 (8 shift) */
 	/* Max supported alignment is 256 (8 shift) */
 #define BNX2X_RX_ALIGN_SHIFT		min(8, L1_CACHE_SHIFT)
 #define BNX2X_RX_ALIGN_SHIFT		min(8, L1_CACHE_SHIFT)
@@ -1329,6 +1331,8 @@ struct bnx2x {
 
 
 	u8			wol;
 	u8			wol;
 
 
+	bool			gro_check;
+
 	int			rx_ring_size;
 	int			rx_ring_size;
 
 
 	u16			tx_quick_cons_trip_int;
 	u16			tx_quick_cons_trip_int;

+ 12 - 0
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c

@@ -330,6 +330,16 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
 		u16 gro_size = le16_to_cpu(cqe->pkt_len_or_gro_seg_len);
 		u16 gro_size = le16_to_cpu(cqe->pkt_len_or_gro_seg_len);
 		tpa_info->full_page =
 		tpa_info->full_page =
 			SGE_PAGE_SIZE * PAGES_PER_SGE / gro_size * gro_size;
 			SGE_PAGE_SIZE * PAGES_PER_SGE / gro_size * gro_size;
+		/*
+		 * FW 7.2.16 BUG workaround:
+		 * if SGE size is (exactly) multiple gro_size
+		 * fw will place one less frag on SGE.
+		 * the calculation is done only for potentially
+		 * dangerous MTUs.
+		 */
+		if (unlikely(bp->gro_check))
+			if (!(SGE_PAGE_SIZE * PAGES_PER_SGE % gro_size))
+				tpa_info->full_page -= gro_size;
 		tpa_info->gro_size = gro_size;
 		tpa_info->gro_size = gro_size;
 	}
 	}
 
 
@@ -3486,6 +3496,8 @@ int bnx2x_change_mtu(struct net_device *dev, int new_mtu)
 	 */
 	 */
 	dev->mtu = new_mtu;
 	dev->mtu = new_mtu;
 
 
+	bp->gro_check = bnx2x_need_gro_check(new_mtu);
+
 	return bnx2x_reload_if_running(dev);
 	return bnx2x_reload_if_running(dev);
 }
 }
 
 

+ 7 - 0
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h

@@ -1504,6 +1504,13 @@ static inline bool bnx2x_mtu_allows_gro(int mtu)
 	 */
 	 */
 	return mtu <= SGE_PAGE_SIZE && (U_ETH_SGL_SIZE * fpp) <= MAX_SKB_FRAGS;
 	return mtu <= SGE_PAGE_SIZE && (U_ETH_SGL_SIZE * fpp) <= MAX_SKB_FRAGS;
 }
 }
+
+static inline bool bnx2x_need_gro_check(int mtu)
+{
+	return (SGE_PAGES / (mtu - ETH_MAX_TPA_HEADER_SIZE - 1)) !=
+		(SGE_PAGES / (mtu - ETH_MIN_TPA_HEADER_SIZE + 1));
+}
+
 /**
 /**
  * bnx2x_bz_fp - zero content of the fastpath structure.
  * bnx2x_bz_fp - zero content of the fastpath structure.
  *
  *

+ 2 - 0
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c

@@ -10214,6 +10214,8 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
 	if (CHIP_IS_E3B0(bp))
 	if (CHIP_IS_E3B0(bp))
 		bp->max_cos = BNX2X_MULTI_TX_COS_E3B0;
 		bp->max_cos = BNX2X_MULTI_TX_COS_E3B0;
 
 
+	bp->gro_check = bnx2x_need_gro_check(bp->dev->mtu);
+
 	return rc;
 	return rc;
 }
 }