]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
i40e/i40evf: Fix TSO checksum pseudo-header adjustment
authorAlexander Duyck <aduyck@mirantis.com>
Wed, 25 May 2016 17:00:36 +0000 (13:00 -0400)
committerChuck Anderson <chuck.anderson@oracle.com>
Thu, 7 Jul 2016 17:40:57 +0000 (10:40 -0700)
Orabug: 23176970

With IPv4 and IPv6 now using the same format for checksums based on the
length of the frame we need to update the i40e and i40evf drivers so that
they correctly account for lengths greater than or equal to 64K.

With this patch the driver should now correctly update checksums for frames
up to 16776960 in length which should be more than large enough for all
possible TSO frames in the near future.

Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
(cherry picked from commit 24d41e5e2c9afe99b0584832206ba8779dfb783e)

Signed-off-by: Brian Maly <brian.maly@oracle.com>
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/kcompat.h [new file with mode: 0644]
drivers/net/ethernet/intel/i40evf/i40e_txrx.c
drivers/net/ethernet/intel/i40evf/kcompat.h [new file with mode: 0644]

index 6737f0d0738447d3bd1cce55a78a69d6a19ef81d..2ef327b78fc0ea0cabb6174c7eb62d60a13d2621 100644 (file)
@@ -28,6 +28,7 @@
 #include <net/busy_poll.h>
 #include "i40e.h"
 #include "i40e_prototype.h"
+#include "kcompat.h"
 
 static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
                                u32 td_tag)
@@ -2301,10 +2302,8 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
                        l4_offset = l4.hdr - skb->data;
 
                        /* remove payload length from outer checksum */
-                       paylen = (__force u16)l4.udp->check;
-                       paylen += ntohs((__force __be16)1) *
-                                       (u16)~(skb->len - l4_offset);
-                       l4.udp->check = ~csum_fold((__force __wsum)paylen);
+                       paylen = skb->len - l4_offset;
+                       csum_replace_by_diff(&l4.udp->check, htonl(paylen));
                }
 
                /* reset pointers to inner headers */
@@ -2324,9 +2323,8 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
        l4_offset = l4.hdr - skb->data;
 
        /* remove payload length from inner checksum */
-       paylen = (__force u16)l4.tcp->check;
-       paylen += ntohs((__force __be16)1) * (u16)~(skb->len - l4_offset);
-       l4.tcp->check = ~csum_fold((__force __wsum)paylen);
+       paylen = skb->len - l4_offset;
+       csum_replace_by_diff(&l4.tcp->check, htonl(paylen));
 
        /* compute length of segmentation header */
        *hdr_len = (l4.tcp->doff * 4) + l4_offset;
diff --git a/drivers/net/ethernet/intel/i40e/kcompat.h b/drivers/net/ethernet/intel/i40e/kcompat.h
new file mode 100644 (file)
index 0000000..efec554
--- /dev/null
@@ -0,0 +1,37 @@
+
+#ifndef _KCOMPAT_H_
+#define _KCOMPAT_H_
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#else
+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#endif
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/mii.h>
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+
+#endif
+
+static inline void csum_replace_by_diff(__sum16 *sum, __wsum diff)
+{
+       *sum = csum_fold(csum_add(diff, ~csum_unfold(*sum)));
+}
index 45c1367e8ff96f216cc4b55e071103bc68293a4c..47ceb5382193518274fc15989d864796c697457f 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "i40evf.h"
 #include "i40e_prototype.h"
+#include "kcompat.h"
 
 static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
                                u32 td_tag)
@@ -1568,10 +1569,8 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
                        l4_offset = l4.hdr - skb->data;
 
                        /* remove payload length from outer checksum */
-                       paylen = (__force u16)l4.udp->check;
-                       paylen += ntohs((__force __be16)1) *
-                                       (u16)~(skb->len - l4_offset);
-                       l4.udp->check = ~csum_fold((__force __wsum)paylen);
+                       paylen = skb->len - l4_offset;
+                       csum_replace_by_diff(&l4.udp->check, htonl(paylen));
                }
 
                /* reset pointers to inner headers */
@@ -1591,9 +1590,8 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
        l4_offset = l4.hdr - skb->data;
 
        /* remove payload length from inner checksum */
-       paylen = (__force u16)l4.tcp->check;
-       paylen += ntohs((__force __be16)1) * (u16)~(skb->len - l4_offset);
-       l4.tcp->check = ~csum_fold((__force __wsum)paylen);
+       paylen = skb->len - l4_offset;
+       csum_replace_by_diff(&l4.tcp->check, htonl(paylen));
 
        /* compute length of segmentation header */
        *hdr_len = (l4.tcp->doff * 4) + l4_offset;
diff --git a/drivers/net/ethernet/intel/i40evf/kcompat.h b/drivers/net/ethernet/intel/i40evf/kcompat.h
new file mode 100644 (file)
index 0000000..efec554
--- /dev/null
@@ -0,0 +1,37 @@
+
+#ifndef _KCOMPAT_H_
+#define _KCOMPAT_H_
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#else
+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#endif
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/mii.h>
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+
+#endif
+
+static inline void csum_replace_by_diff(__sum16 *sum, __wsum diff)
+{
+       *sum = csum_fold(csum_add(diff, ~csum_unfold(*sum)));
+}