Merge tag 's390-5.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
[linux-2.6-microblaze.git] / arch / s390 / include / asm / checksum.h
index 6813bfa..a8c02cf 100644 (file)
 #define _S390_CHECKSUM_H
 
 #include <linux/uaccess.h>
+#include <linux/in6.h>
 
 /*
- * computes the checksum of a memory block at buff, length len,
- * and adds in "sum" (32-bit)
+ * Computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit).
  *
- * returns a 32-bit number suitable for feeding into itself
- * or csum_tcpudp_magic
+ * Returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic.
  *
- * this function must be called with even lengths, except
- * for the last fragment, which may be odd
+ * This function must be called with even lengths, except
+ * for the last fragment, which may be odd.
  *
- * it's best to have buff aligned on a 32-bit boundary
+ * It's best to have buff aligned on a 32-bit boundary.
  */
-static inline __wsum
-csum_partial(const void *buff, int len, __wsum sum)
+static inline __wsum csum_partial(const void *buff, int len, __wsum sum)
 {
        register unsigned long reg2 asm("2") = (unsigned long) buff;
        register unsigned long reg3 asm("3") = (unsigned long) len;
@@ -40,74 +40,91 @@ csum_partial(const void *buff, int len, __wsum sum)
 }
 
 /*
- *      Fold a partial checksum without adding pseudo headers
+ * Fold a partial checksum without adding pseudo headers.
  */
 static inline __sum16 csum_fold(__wsum sum)
 {
        u32 csum = (__force u32) sum;
 
-       csum += (csum >> 16) + (csum << 16);
+       csum += (csum >> 16) | (csum << 16);
        csum >>= 16;
        return (__force __sum16) ~csum;
 }
 
 /*
- *     This is a version of ip_compute_csum() optimized for IP headers,
- *     which always checksum on 4 octet boundaries.
- *
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksums on 4 octet boundaries.
  */
 static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
 {
-       return csum_fold(csum_partial(iph, ihl*4, 0));
+       __u64 csum = 0;
+       __u32 *ptr = (u32 *)iph;
+
+       csum += *ptr++;
+       csum += *ptr++;
+       csum += *ptr++;
+       csum += *ptr++;
+       ihl -= 4;
+       while (ihl--)
+               csum += *ptr++;
+       csum += (csum >> 32) | (csum << 32);
+       return csum_fold((__force __wsum)(csum >> 32));
 }
 
 /*
- * computes the checksum of the TCP/UDP pseudo-header
- * returns a 32-bit checksum
+ * Computes the checksum of the TCP/UDP pseudo-header.
+ * Returns a 32-bit checksum.
  */
-static inline __wsum
-csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len, __u8 proto,
-                   __wsum sum)
+static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
+                                       __u8 proto, __wsum sum)
 {
-       __u32 csum = (__force __u32)sum;
+       __u64 csum = (__force __u64)sum;
 
        csum += (__force __u32)saddr;
-       if (csum < (__force __u32)saddr)
-               csum++;
-
        csum += (__force __u32)daddr;
-       if (csum < (__force __u32)daddr)
-               csum++;
-
-       csum += len + proto;
-       if (csum < len + proto)
-               csum++;
-
-       return (__force __wsum)csum;
+       csum += len;
+       csum += proto;
+       csum += (csum >> 32) | (csum << 32);
+       return (__force __wsum)(csum >> 32);
 }
 
 /*
- * computes the checksum of the TCP/UDP pseudo-header
- * returns a 16-bit checksum, already complemented
+ * Computes the checksum of the TCP/UDP pseudo-header.
+ * Returns a 16-bit checksum, already complemented.
  */
-
-static inline __sum16
-csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len, __u8 proto,
-                  __wsum sum)
+static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len,
+                                       __u8 proto, __wsum sum)
 {
-       return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+       return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
 }
 
 /*
- * this routine is used for miscellaneous IP-like checksums, mainly
- * in icmp.c
+ * Used for miscellaneous IP-like checksums, mainly icmp.
  */
-
 static inline __sum16 ip_compute_csum(const void *buff, int len)
 {
        return csum_fold(csum_partial(buff, len, 0));
 }
 
-#endif /* _S390_CHECKSUM_H */
-
+#define _HAVE_ARCH_IPV6_CSUM
+static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
+                                     const struct in6_addr *daddr,
+                                     __u32 len, __u8 proto, __wsum csum)
+{
+       __u64 sum = (__force __u64)csum;
+
+       sum += (__force __u32)saddr->s6_addr32[0];
+       sum += (__force __u32)saddr->s6_addr32[1];
+       sum += (__force __u32)saddr->s6_addr32[2];
+       sum += (__force __u32)saddr->s6_addr32[3];
+       sum += (__force __u32)daddr->s6_addr32[0];
+       sum += (__force __u32)daddr->s6_addr32[1];
+       sum += (__force __u32)daddr->s6_addr32[2];
+       sum += (__force __u32)daddr->s6_addr32[3];
+       sum += len;
+       sum += proto;
+       sum += (sum >> 32) | (sum << 32);
+       return csum_fold((__force __wsum)(sum >> 32));
+}
 
+#endif /* _S390_CHECKSUM_H */