aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2006-06-29 23:15:54 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-06-30 17:11:57 -0400
commit52c0fd834ea0e7c6ef8616ce0a1f85bac4233ed7 (patch)
tree92897bedf97906699f654fd94985fbada0497daa /drivers/net
parent1661394e78b3b2cc868cd0e89c1066974302aaca (diff)
[TG3]: Add TSO workaround using GSO
Use GSO to workaround a rare TSO bug on some chips. This hardware bug may be triggered when the TSO header size is greater than 80 bytes. When this condition is detected in a TSO packet, the driver will use GSO to segment the packet to workaround the hardware bug. Thanks to Juergen Kreileder <jk@blackdown.de> for reporting the problem and collecting traces to help debug the problem. And thanks to Herbert Xu <herbert@gondor.apana.org.au> for providing the GSO mechanism that happens to be the perfect workaround for this problem. Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/tg3.c53
-rw-r--r--drivers/net/tg3.h3
2 files changed, 51 insertions, 5 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 2c36e70e37e5..63d4b2c797e8 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -3880,6 +3880,40 @@ out_unlock:
3880 return NETDEV_TX_OK; 3880 return NETDEV_TX_OK;
3881} 3881}
3882 3882
3883#if TG3_TSO_SUPPORT != 0
3884static int tg3_start_xmit_dma_bug(struct sk_buff *, struct net_device *);
3885
3886/* Use GSO to workaround a rare TSO bug that may be triggered when the
3887 * TSO header is greater than 80 bytes.
3888 */
3889static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb)
3890{
3891 struct sk_buff *segs, *nskb;
3892
3893 /* Estimate the number of fragments in the worst case */
3894 if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->gso_segs * 3))) {
3895 netif_stop_queue(tp->dev);
3896 return NETDEV_TX_BUSY;
3897 }
3898
3899 segs = skb_gso_segment(skb, tp->dev->features & ~NETIF_F_TSO);
3900 if (unlikely(IS_ERR(segs)))
3901 goto tg3_tso_bug_end;
3902
3903 do {
3904 nskb = segs;
3905 segs = segs->next;
3906 nskb->next = NULL;
3907 tg3_start_xmit_dma_bug(nskb, tp->dev);
3908 } while (segs);
3909
3910tg3_tso_bug_end:
3911 dev_kfree_skb(skb);
3912
3913 return NETDEV_TX_OK;
3914}
3915#endif
3916
3883/* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and 3917/* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and
3884 * support TG3_FLG2_HW_TSO_1 or firmware TSO only. 3918 * support TG3_FLG2_HW_TSO_1 or firmware TSO only.
3885 */ 3919 */
@@ -3916,7 +3950,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
3916 mss = 0; 3950 mss = 0;
3917 if (skb->len > (tp->dev->mtu + ETH_HLEN) && 3951 if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
3918 (mss = skb_shinfo(skb)->gso_size) != 0) { 3952 (mss = skb_shinfo(skb)->gso_size) != 0) {
3919 int tcp_opt_len, ip_tcp_len; 3953 int tcp_opt_len, ip_tcp_len, hdr_len;
3920 3954
3921 if (skb_header_cloned(skb) && 3955 if (skb_header_cloned(skb) &&
3922 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { 3956 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
@@ -3927,11 +3961,16 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
3927 tcp_opt_len = ((skb->h.th->doff - 5) * 4); 3961 tcp_opt_len = ((skb->h.th->doff - 5) * 4);
3928 ip_tcp_len = (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr); 3962 ip_tcp_len = (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr);
3929 3963
3964 hdr_len = ip_tcp_len + tcp_opt_len;
3965 if (unlikely((ETH_HLEN + hdr_len) > 80) &&
3966 (tp->tg3_flags2 & TG3_FLG2_HW_TSO_1_BUG))
3967 return (tg3_tso_bug(tp, skb));
3968
3930 base_flags |= (TXD_FLAG_CPU_PRE_DMA | 3969 base_flags |= (TXD_FLAG_CPU_PRE_DMA |
3931 TXD_FLAG_CPU_POST_DMA); 3970 TXD_FLAG_CPU_POST_DMA);
3932 3971
3933 skb->nh.iph->check = 0; 3972 skb->nh.iph->check = 0;
3934 skb->nh.iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len); 3973 skb->nh.iph->tot_len = htons(mss + hdr_len);
3935 if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) { 3974 if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
3936 skb->h.th->check = 0; 3975 skb->h.th->check = 0;
3937 base_flags &= ~TXD_FLAG_TCPUDP_CSUM; 3976 base_flags &= ~TXD_FLAG_TCPUDP_CSUM;
@@ -10192,8 +10231,14 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
10192 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) { 10231 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) {
10193 tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2; 10232 tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2;
10194 tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI; 10233 tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
10195 } else 10234 } else {
10196 tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1; 10235 tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1 |
10236 TG3_FLG2_HW_TSO_1_BUG;
10237 if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
10238 ASIC_REV_5750 &&
10239 tp->pci_chip_rev_id >= CHIPREV_ID_5750_C2)
10240 tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_1_BUG;
10241 }
10197 } 10242 }
10198 10243
10199 if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 && 10244 if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 97a860433b50..ba2c98711c88 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -125,6 +125,7 @@
125#define CHIPREV_ID_5750_A0 0x4000 125#define CHIPREV_ID_5750_A0 0x4000
126#define CHIPREV_ID_5750_A1 0x4001 126#define CHIPREV_ID_5750_A1 0x4001
127#define CHIPREV_ID_5750_A3 0x4003 127#define CHIPREV_ID_5750_A3 0x4003
128#define CHIPREV_ID_5750_C2 0x4202
128#define CHIPREV_ID_5752_A0_HW 0x5000 129#define CHIPREV_ID_5752_A0_HW 0x5000
129#define CHIPREV_ID_5752_A0 0x6000 130#define CHIPREV_ID_5752_A0 0x6000
130#define CHIPREV_ID_5752_A1 0x6001 131#define CHIPREV_ID_5752_A1 0x6001
@@ -2193,7 +2194,7 @@ struct tg3 {
2193#define TG3_FLAG_INIT_COMPLETE 0x80000000 2194#define TG3_FLAG_INIT_COMPLETE 0x80000000
2194 u32 tg3_flags2; 2195 u32 tg3_flags2;
2195#define TG3_FLG2_RESTART_TIMER 0x00000001 2196#define TG3_FLG2_RESTART_TIMER 0x00000001
2196/* 0x00000002 available */ 2197#define TG3_FLG2_HW_TSO_1_BUG 0x00000002
2197#define TG3_FLG2_NO_ETH_WIRE_SPEED 0x00000004 2198#define TG3_FLG2_NO_ETH_WIRE_SPEED 0x00000004
2198#define TG3_FLG2_IS_5788 0x00000008 2199#define TG3_FLG2_IS_5788 0x00000008
2199#define TG3_FLG2_MAX_RXPEND_64 0x00000010 2200#define TG3_FLG2_MAX_RXPEND_64 0x00000010