0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef _S390_CHECKSUM_H
0013 #define _S390_CHECKSUM_H
0014
0015 #include <linux/uaccess.h>
0016 #include <linux/in6.h>
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030 static inline __wsum csum_partial(const void *buff, int len, __wsum sum)
0031 {
0032 union register_pair rp = {
0033 .even = (unsigned long) buff,
0034 .odd = (unsigned long) len,
0035 };
0036
0037 asm volatile(
0038 "0: cksm %[sum],%[rp]\n"
0039 " jo 0b\n"
0040 : [sum] "+&d" (sum), [rp] "+&d" (rp.pair) : : "cc", "memory");
0041 return sum;
0042 }
0043
0044
0045
0046
0047 static inline __sum16 csum_fold(__wsum sum)
0048 {
0049 u32 csum = (__force u32) sum;
0050
0051 csum += (csum >> 16) | (csum << 16);
0052 csum >>= 16;
0053 return (__force __sum16) ~csum;
0054 }
0055
0056
0057
0058
0059
0060 static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
0061 {
0062 __u64 csum = 0;
0063 __u32 *ptr = (u32 *)iph;
0064
0065 csum += *ptr++;
0066 csum += *ptr++;
0067 csum += *ptr++;
0068 csum += *ptr++;
0069 ihl -= 4;
0070 while (ihl--)
0071 csum += *ptr++;
0072 csum += (csum >> 32) | (csum << 32);
0073 return csum_fold((__force __wsum)(csum >> 32));
0074 }
0075
0076
0077
0078
0079
0080 static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
0081 __u8 proto, __wsum sum)
0082 {
0083 __u64 csum = (__force __u64)sum;
0084
0085 csum += (__force __u32)saddr;
0086 csum += (__force __u32)daddr;
0087 csum += len;
0088 csum += proto;
0089 csum += (csum >> 32) | (csum << 32);
0090 return (__force __wsum)(csum >> 32);
0091 }
0092
0093
0094
0095
0096
0097 static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len,
0098 __u8 proto, __wsum sum)
0099 {
0100 return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
0101 }
0102
0103
0104
0105
0106 static inline __sum16 ip_compute_csum(const void *buff, int len)
0107 {
0108 return csum_fold(csum_partial(buff, len, 0));
0109 }
0110
0111 #define _HAVE_ARCH_IPV6_CSUM
0112 static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
0113 const struct in6_addr *daddr,
0114 __u32 len, __u8 proto, __wsum csum)
0115 {
0116 __u64 sum = (__force __u64)csum;
0117
0118 sum += (__force __u32)saddr->s6_addr32[0];
0119 sum += (__force __u32)saddr->s6_addr32[1];
0120 sum += (__force __u32)saddr->s6_addr32[2];
0121 sum += (__force __u32)saddr->s6_addr32[3];
0122 sum += (__force __u32)daddr->s6_addr32[0];
0123 sum += (__force __u32)daddr->s6_addr32[1];
0124 sum += (__force __u32)daddr->s6_addr32[2];
0125 sum += (__force __u32)daddr->s6_addr32[3];
0126 sum += len;
0127 sum += proto;
0128 sum += (sum >> 32) | (sum << 32);
0129 return csum_fold((__force __wsum)(sum >> 32));
0130 }
0131
0132 #endif