aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVladislav Zolotarov <vladz@broadcom.com>2010-12-07 20:43:09 -0500
committerDavid S. Miller <davem@davemloft.net>2010-12-09 23:50:00 -0500
commit2297a2da5a8507bf6596dc30ace3483c00bd85ed (patch)
tree6cd0e65985c1666a3b9863c1ae29df5d953fec77
parent4bc65dd8d88671712d71592a83374cfb0b5fce7a (diff)
bnx2x: LSO code was broken on BE platforms
Make the LSO code work on BE platforms: parsing_data field of a parsing BD (PBD) for 57712 was improperly composed which made FW read wrong values for TCP header's length and offset and, as a result, the corresponding PCI device was performing bad DMA reads triggering EEH. Signed-off-by: Vladislav Zolotarov <vladz@broadcom.com> Signed-off-by: Eilon Greenstein <eilong@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/bnx2x/bnx2x_cmn.c42
1 files changed, 26 insertions, 16 deletions
diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c
index a4555edbe9ce..236c00c3f568 100644
--- a/drivers/net/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/bnx2x/bnx2x_cmn.c
@@ -1795,15 +1795,15 @@ exit_lbl:
1795} 1795}
1796#endif 1796#endif
1797 1797
1798static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, 1798static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data,
1799 struct eth_tx_parse_bd_e2 *pbd, 1799 u32 xmit_type)
1800 u32 xmit_type)
1801{ 1800{
1802 pbd->parsing_data |= cpu_to_le16(skb_shinfo(skb)->gso_size) << 1801 *parsing_data |= (skb_shinfo(skb)->gso_size <<
1803 ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT; 1802 ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT) &
1803 ETH_TX_PARSE_BD_E2_LSO_MSS;
1804 if ((xmit_type & XMIT_GSO_V6) && 1804 if ((xmit_type & XMIT_GSO_V6) &&
1805 (ipv6_hdr(skb)->nexthdr == NEXTHDR_IPV6)) 1805 (ipv6_hdr(skb)->nexthdr == NEXTHDR_IPV6))
1806 pbd->parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR; 1806 *parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR;
1807} 1807}
1808 1808
1809/** 1809/**
@@ -1848,15 +1848,15 @@ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb,
1848 * @return header len 1848 * @return header len
1849 */ 1849 */
1850static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb, 1850static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
1851 struct eth_tx_parse_bd_e2 *pbd, 1851 u32 *parsing_data, u32 xmit_type)
1852 u32 xmit_type)
1853{ 1852{
1854 pbd->parsing_data |= cpu_to_le16(tcp_hdrlen(skb)/4) << 1853 *parsing_data |= ((tcp_hdrlen(skb)/4) <<
1855 ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT; 1854 ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) &
1855 ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW;
1856 1856
1857 pbd->parsing_data |= cpu_to_le16(((unsigned char *)tcp_hdr(skb) - 1857 *parsing_data |= ((((u8 *)tcp_hdr(skb) - skb->data) / 2) <<
1858 skb->data) / 2) << 1858 ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) &
1859 ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT; 1859 ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W;
1860 1860
1861 return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data; 1861 return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data;
1862} 1862}
@@ -1925,6 +1925,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
1925 struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL; 1925 struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL;
1926 struct eth_tx_parse_bd_e1x *pbd_e1x = NULL; 1926 struct eth_tx_parse_bd_e1x *pbd_e1x = NULL;
1927 struct eth_tx_parse_bd_e2 *pbd_e2 = NULL; 1927 struct eth_tx_parse_bd_e2 *pbd_e2 = NULL;
1928 u32 pbd_e2_parsing_data = 0;
1928 u16 pkt_prod, bd_prod; 1929 u16 pkt_prod, bd_prod;
1929 int nbd, fp_index; 1930 int nbd, fp_index;
1930 dma_addr_t mapping; 1931 dma_addr_t mapping;
@@ -2046,8 +2047,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
2046 memset(pbd_e2, 0, sizeof(struct eth_tx_parse_bd_e2)); 2047 memset(pbd_e2, 0, sizeof(struct eth_tx_parse_bd_e2));
2047 /* Set PBD in checksum offload case */ 2048 /* Set PBD in checksum offload case */
2048 if (xmit_type & XMIT_CSUM) 2049 if (xmit_type & XMIT_CSUM)
2049 hlen = bnx2x_set_pbd_csum_e2(bp, 2050 hlen = bnx2x_set_pbd_csum_e2(bp, skb,
2050 skb, pbd_e2, xmit_type); 2051 &pbd_e2_parsing_data,
2052 xmit_type);
2051 } else { 2053 } else {
2052 pbd_e1x = &fp->tx_desc_ring[bd_prod].parse_bd_e1x; 2054 pbd_e1x = &fp->tx_desc_ring[bd_prod].parse_bd_e1x;
2053 memset(pbd_e1x, 0, sizeof(struct eth_tx_parse_bd_e1x)); 2055 memset(pbd_e1x, 0, sizeof(struct eth_tx_parse_bd_e1x));
@@ -2089,10 +2091,18 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
2089 bd_prod = bnx2x_tx_split(bp, fp, tx_buf, &tx_start_bd, 2091 bd_prod = bnx2x_tx_split(bp, fp, tx_buf, &tx_start_bd,
2090 hlen, bd_prod, ++nbd); 2092 hlen, bd_prod, ++nbd);
2091 if (CHIP_IS_E2(bp)) 2093 if (CHIP_IS_E2(bp))
2092 bnx2x_set_pbd_gso_e2(skb, pbd_e2, xmit_type); 2094 bnx2x_set_pbd_gso_e2(skb, &pbd_e2_parsing_data,
2095 xmit_type);
2093 else 2096 else
2094 bnx2x_set_pbd_gso(skb, pbd_e1x, xmit_type); 2097 bnx2x_set_pbd_gso(skb, pbd_e1x, xmit_type);
2095 } 2098 }
2099
2100 /* Set the PBD's parsing_data field if not zero
2101 * (for the chips newer than 57711).
2102 */
2103 if (pbd_e2_parsing_data)
2104 pbd_e2->parsing_data = cpu_to_le32(pbd_e2_parsing_data);
2105
2096 tx_data_bd = (struct eth_tx_bd *)tx_start_bd; 2106 tx_data_bd = (struct eth_tx_bd *)tx_start_bd;
2097 2107
2098 /* Handle fragmented skb */ 2108 /* Handle fragmented skb */