1 /* SPDX-License-Identifier: GPL-2.0 */
3 * S390 fast network checksum routines
6 * Copyright IBM Corp. 1999
7 * Author(s): Ulrich Hild (first version)
8 * Martin Schwidefsky (heavily optimized CKSM version)
9 * D.J. Barrow (third attempt)
12 #ifndef _S390_CHECKSUM_H
13 #define _S390_CHECKSUM_H
15 #include <linux/uaccess.h>
16 #include <linux/in6.h>
19 * Computes the checksum of a memory block at buff, length len,
20 * and adds in "sum" (32-bit).
22 * Returns a 32-bit number suitable for feeding into itself
23 * or csum_tcpudp_magic.
25 * This function must be called with even lengths, except
26 * for the last fragment, which may be odd.
28 * It's best to have buff aligned on a 32-bit boundary.
30 static inline __wsum
csum_partial(const void *buff
, int len
, __wsum sum
)
32 register unsigned long reg2
asm("2") = (unsigned long) buff
;
33 register unsigned long reg3
asm("3") = (unsigned long) len
;
36 "0: cksm %0,%1\n" /* do checksum on longs */
38 : "+d" (sum
), "+d" (reg2
), "+d" (reg3
) : : "cc", "memory");
43 * Fold a partial checksum without adding pseudo headers.
45 static inline __sum16
csum_fold(__wsum sum
)
47 u32 csum
= (__force u32
) sum
;
49 csum
+= (csum
>> 16) | (csum
<< 16);
51 return (__force __sum16
) ~csum
;
55 * This is a version of ip_compute_csum() optimized for IP headers,
56 * which always checksums on 4 octet boundaries.
58 static inline __sum16
ip_fast_csum(const void *iph
, unsigned int ihl
)
61 __u32
*ptr
= (u32
*)iph
;
70 csum
+= (csum
>> 32) | (csum
<< 32);
71 return csum_fold((__force __wsum
)(csum
>> 32));
75 * Computes the checksum of the TCP/UDP pseudo-header.
76 * Returns a 32-bit checksum.
78 static inline __wsum
csum_tcpudp_nofold(__be32 saddr
, __be32 daddr
, __u32 len
,
79 __u8 proto
, __wsum sum
)
81 __u64 csum
= (__force __u64
)sum
;
83 csum
+= (__force __u32
)saddr
;
84 csum
+= (__force __u32
)daddr
;
87 csum
+= (csum
>> 32) | (csum
<< 32);
88 return (__force __wsum
)(csum
>> 32);
92 * Computes the checksum of the TCP/UDP pseudo-header.
93 * Returns a 16-bit checksum, already complemented.
95 static inline __sum16
csum_tcpudp_magic(__be32 saddr
, __be32 daddr
, __u32 len
,
96 __u8 proto
, __wsum sum
)
98 return csum_fold(csum_tcpudp_nofold(saddr
, daddr
, len
, proto
, sum
));
102 * Used for miscellaneous IP-like checksums, mainly icmp.
104 static inline __sum16
ip_compute_csum(const void *buff
, int len
)
106 return csum_fold(csum_partial(buff
, len
, 0));
109 #define _HAVE_ARCH_IPV6_CSUM
110 static inline __sum16
csum_ipv6_magic(const struct in6_addr
*saddr
,
111 const struct in6_addr
*daddr
,
112 __u32 len
, __u8 proto
, __wsum csum
)
114 __u64 sum
= (__force __u64
)csum
;
116 sum
+= (__force __u32
)saddr
->s6_addr32
[0];
117 sum
+= (__force __u32
)saddr
->s6_addr32
[1];
118 sum
+= (__force __u32
)saddr
->s6_addr32
[2];
119 sum
+= (__force __u32
)saddr
->s6_addr32
[3];
120 sum
+= (__force __u32
)daddr
->s6_addr32
[0];
121 sum
+= (__force __u32
)daddr
->s6_addr32
[1];
122 sum
+= (__force __u32
)daddr
->s6_addr32
[2];
123 sum
+= (__force __u32
)daddr
->s6_addr32
[3];
126 sum
+= (sum
>> 32) | (sum
<< 32);
127 return csum_fold((__force __wsum
)(sum
>> 32));
130 #endif /* _S390_CHECKSUM_H */