Skip to content

Commit

Permalink
tg3: Prevent page allocation failure during TSO workaround
Browse files Browse the repository at this point in the history
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: Prashant Sreedharan <prashant@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Michael Chan authored and David S. Miller committed May 13, 2014
1 parent d71c0dc commit d3f6f3a
Showing 1 changed file with 26 additions and 7 deletions.
33 changes: 26 additions & 7 deletions drivers/net/ethernet/broadcom/tg3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)];
Expand Down Expand Up @@ -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))
Expand All @@ -7929,23 +7932,27 @@ 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);
}

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;
Expand Down Expand Up @@ -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.
*/
Expand Down

0 comments on commit d3f6f3a

Please sign in to comment.