aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/e1000e/netdev.c
diff options
context:
space:
mode:
authorDave Graham <david.graham@intel.com>2008-10-09 17:28:58 -0400
committerDavid S. Miller <davem@davemloft.net>2008-10-09 17:28:58 -0400
commitaf807c82978ec1b8c5120b59b78ef951b3e4603b (patch)
tree5641d4f8c4a5117deeba86d5171d431c439e5367 /drivers/net/e1000e/netdev.c
parentec7e6fabbe72f1fe65eed14c106a0fbc00f6c2f1 (diff)
e1000e: don't generate bad checksums for tcp packets with 0 csum
When offloading transmit checksums only, the driver was not correctly configuring the hardware to handle the case of a zero checksum. For UDP the correct behavior is to leave it alone, but for tcp the checksum must be changed from 0x0000 to 0xFFFF. The hardware takes care of this case but only if it is told the packet is tcp. Signed-off-by: Dave Graham <david.graham@intel.com> Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/e1000e/netdev.c')
-rw-r--r--drivers/net/e1000e/netdev.c62
1 files changed, 39 insertions, 23 deletions
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 1b72749979c4..abd492b7336d 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -3749,34 +3749,50 @@ static bool e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
3749 struct e1000_buffer *buffer_info; 3749 struct e1000_buffer *buffer_info;
3750 unsigned int i; 3750 unsigned int i;
3751 u8 css; 3751 u8 css;
3752 u32 cmd_len = E1000_TXD_CMD_DEXT;
3752 3753
3753 if (skb->ip_summed == CHECKSUM_PARTIAL) { 3754 if (skb->ip_summed != CHECKSUM_PARTIAL)
3754 css = skb_transport_offset(skb); 3755 return 0;
3755
3756 i = tx_ring->next_to_use;
3757 buffer_info = &tx_ring->buffer_info[i];
3758 context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
3759
3760 context_desc->lower_setup.ip_config = 0;
3761 context_desc->upper_setup.tcp_fields.tucss = css;
3762 context_desc->upper_setup.tcp_fields.tucso =
3763 css + skb->csum_offset;
3764 context_desc->upper_setup.tcp_fields.tucse = 0;
3765 context_desc->tcp_seg_setup.data = 0;
3766 context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
3767 3756
3768 buffer_info->time_stamp = jiffies; 3757 switch (skb->protocol) {
3769 buffer_info->next_to_watch = i; 3758 case __constant_htons(ETH_P_IP):
3759 if (ip_hdr(skb)->protocol == IPPROTO_TCP)
3760 cmd_len |= E1000_TXD_CMD_TCP;
3761 break;
3762 case __constant_htons(ETH_P_IPV6):
3763 /* XXX not handling all IPV6 headers */
3764 if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
3765 cmd_len |= E1000_TXD_CMD_TCP;
3766 break;
3767 default:
3768 if (unlikely(net_ratelimit()))
3769 e_warn("checksum_partial proto=%x!\n", skb->protocol);
3770 break;
3771 }
3770 3772
3771 i++; 3773 css = skb_transport_offset(skb);
3772 if (i == tx_ring->count)
3773 i = 0;
3774 tx_ring->next_to_use = i;
3775 3774
3776 return 1; 3775 i = tx_ring->next_to_use;
3777 } 3776 buffer_info = &tx_ring->buffer_info[i];
3777 context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
3778
3779 context_desc->lower_setup.ip_config = 0;
3780 context_desc->upper_setup.tcp_fields.tucss = css;
3781 context_desc->upper_setup.tcp_fields.tucso =
3782 css + skb->csum_offset;
3783 context_desc->upper_setup.tcp_fields.tucse = 0;
3784 context_desc->tcp_seg_setup.data = 0;
3785 context_desc->cmd_and_length = cpu_to_le32(cmd_len);
3786
3787 buffer_info->time_stamp = jiffies;
3788 buffer_info->next_to_watch = i;
3789
3790 i++;
3791 if (i == tx_ring->count)
3792 i = 0;
3793 tx_ring->next_to_use = i;
3778 3794
3779 return 0; 3795 return 1;
3780} 3796}
3781 3797
3782#define E1000_MAX_PER_TXD 8192 3798#define E1000_MAX_PER_TXD 8192