Commit d3f6f3a1 authored by Michael Chan's avatar Michael Chan Committed by David S. Miller

tg3: Prevent page allocation failure during TSO workaround

If any TSO fragment hits hardware bug conditions (e.g. 4G boundary), the
driver will workaround by calling skb_copy() to copy to a linear SKB.  Users
have reported page allocation failures as the TSO packet can be up to 64K.
Copying such a large packet is also very inefficient.  We fix this by using
existing tg3_tso_bug() to transmit the packet using GSO.
Signed-off-by: default avatarPrashant Sreedharan <prashant@broadcom.com>
Signed-off-by: default avatarMichael Chan <mchan@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d71c0dc4
......@@ -7882,6 +7882,10 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct tg3_napi *tnapi;
struct netdev_queue *txq;
unsigned int last;
struct iphdr *iph = NULL;
struct tcphdr *tcph = NULL;
__sum16 tcp_csum = 0, ip_csum = 0;
__be16 ip_tot_len = 0;
txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
tnapi = &tp->napi[skb_get_queue_mapping(skb)];
......@@ -7913,7 +7917,6 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
mss = skb_shinfo(skb)->gso_size;
if (mss) {
struct iphdr *iph;
u32 tcp_opt_len, hdr_len;
if (skb_cow_head(skb, 0))
......@@ -7929,6 +7932,8 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
tg3_flag(tp, TSO_BUG))
return tg3_tso_bug(tp, skb);
ip_csum = iph->check;
ip_tot_len = iph->tot_len;
iph->check = 0;
iph->tot_len = htons(mss + hdr_len);
}
......@@ -7936,16 +7941,18 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
base_flags |= (TXD_FLAG_CPU_PRE_DMA |
TXD_FLAG_CPU_POST_DMA);
tcph = tcp_hdr(skb);
tcp_csum = tcph->check;
if (tg3_flag(tp, HW_TSO_1) ||
tg3_flag(tp, HW_TSO_2) ||
tg3_flag(tp, HW_TSO_3)) {
tcp_hdr(skb)->check = 0;
tcph->check = 0;
base_flags &= ~TXD_FLAG_TCPUDP_CSUM;
} else
tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
iph->daddr, 0,
IPPROTO_TCP,
0);
} else {
tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
0, IPPROTO_TCP, 0);
}
if (tg3_flag(tp, HW_TSO_3)) {
mss |= (hdr_len & 0xc) << 12;
......@@ -8045,6 +8052,18 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (would_hit_hwbug) {
tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, i);
if (mss) {
/* If it's a TSO packet, do GSO instead of
* allocating and copying to a large linear SKB
*/
if (ip_tot_len) {
iph->check = ip_csum;
iph->tot_len = ip_tot_len;
}
tcph->check = tcp_csum;
return tg3_tso_bug(tp, skb);
}
/* If the workaround fails due to memory/mapping
* failure, silently drop this packet.
*/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment