diff options
author | Vladislav Zolotarov <vladz@broadcom.com> | 2010-12-07 20:43:09 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-12-09 23:50:00 -0500 |
commit | 2297a2da5a8507bf6596dc30ace3483c00bd85ed (patch) | |
tree | 6cd0e65985c1666a3b9863c1ae29df5d953fec77 | |
parent | 4bc65dd8d88671712d71592a83374cfb0b5fce7a (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.c | 42 |
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 | ||
1798 | static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, | 1798 | static 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 | */ |
1850 | static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb, | 1850 | static 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 */ |