xref: /OK3568_Linux_fs/kernel/arch/x86/include/asm/checksum_64.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun #ifndef _ASM_X86_CHECKSUM_64_H
3*4882a593Smuzhiyun #define _ASM_X86_CHECKSUM_64_H
4*4882a593Smuzhiyun 
5*4882a593Smuzhiyun /*
6*4882a593Smuzhiyun  * Checksums for x86-64
7*4882a593Smuzhiyun  * Copyright 2002 by Andi Kleen, SuSE Labs
8*4882a593Smuzhiyun  * with some code from asm-x86/checksum.h
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/compiler.h>
12*4882a593Smuzhiyun #include <linux/uaccess.h>
13*4882a593Smuzhiyun #include <asm/byteorder.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun /**
16*4882a593Smuzhiyun  * csum_fold - Fold and invert a 32bit checksum.
17*4882a593Smuzhiyun  * sum: 32bit unfolded sum
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  * Fold a 32bit running checksum to 16bit and invert it. This is usually
20*4882a593Smuzhiyun  * the last step before putting a checksum into a packet.
21*4882a593Smuzhiyun  * Make sure not to mix with 64bit checksums.
22*4882a593Smuzhiyun  */
csum_fold(__wsum sum)23*4882a593Smuzhiyun static inline __sum16 csum_fold(__wsum sum)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun 	asm("  addl %1,%0\n"
26*4882a593Smuzhiyun 	    "  adcl $0xffff,%0"
27*4882a593Smuzhiyun 	    : "=r" (sum)
28*4882a593Smuzhiyun 	    : "r" ((__force u32)sum << 16),
29*4882a593Smuzhiyun 	      "0" ((__force u32)sum & 0xffff0000));
30*4882a593Smuzhiyun 	return (__force __sum16)(~(__force u32)sum >> 16);
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun /*
34*4882a593Smuzhiyun  *	This is a version of ip_compute_csum() optimized for IP headers,
35*4882a593Smuzhiyun  *	which always checksum on 4 octet boundaries.
36*4882a593Smuzhiyun  *
37*4882a593Smuzhiyun  *	By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
38*4882a593Smuzhiyun  *	Arnt Gulbrandsen.
39*4882a593Smuzhiyun  */
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun /**
42*4882a593Smuzhiyun  * ip_fast_csum - Compute the IPv4 header checksum efficiently.
43*4882a593Smuzhiyun  * iph: ipv4 header
44*4882a593Smuzhiyun  * ihl: length of header / 4
45*4882a593Smuzhiyun  */
ip_fast_csum(const void * iph,unsigned int ihl)46*4882a593Smuzhiyun static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun 	unsigned int sum;
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	asm("  movl (%1), %0\n"
51*4882a593Smuzhiyun 	    "  subl $4, %2\n"
52*4882a593Smuzhiyun 	    "  jbe 2f\n"
53*4882a593Smuzhiyun 	    "  addl 4(%1), %0\n"
54*4882a593Smuzhiyun 	    "  adcl 8(%1), %0\n"
55*4882a593Smuzhiyun 	    "  adcl 12(%1), %0\n"
56*4882a593Smuzhiyun 	    "1: adcl 16(%1), %0\n"
57*4882a593Smuzhiyun 	    "  lea 4(%1), %1\n"
58*4882a593Smuzhiyun 	    "  decl %2\n"
59*4882a593Smuzhiyun 	    "  jne	1b\n"
60*4882a593Smuzhiyun 	    "  adcl $0, %0\n"
61*4882a593Smuzhiyun 	    "  movl %0, %2\n"
62*4882a593Smuzhiyun 	    "  shrl $16, %0\n"
63*4882a593Smuzhiyun 	    "  addw %w2, %w0\n"
64*4882a593Smuzhiyun 	    "  adcl $0, %0\n"
65*4882a593Smuzhiyun 	    "  notl %0\n"
66*4882a593Smuzhiyun 	    "2:"
67*4882a593Smuzhiyun 	/* Since the input registers which are loaded with iph and ihl
68*4882a593Smuzhiyun 	   are modified, we must also specify them as outputs, or gcc
69*4882a593Smuzhiyun 	   will assume they contain their original values. */
70*4882a593Smuzhiyun 	    : "=r" (sum), "=r" (iph), "=r" (ihl)
71*4882a593Smuzhiyun 	    : "1" (iph), "2" (ihl)
72*4882a593Smuzhiyun 	    : "memory");
73*4882a593Smuzhiyun 	return (__force __sum16)sum;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun /**
77*4882a593Smuzhiyun  * csum_tcpup_nofold - Compute an IPv4 pseudo header checksum.
78*4882a593Smuzhiyun  * @saddr: source address
79*4882a593Smuzhiyun  * @daddr: destination address
80*4882a593Smuzhiyun  * @len: length of packet
81*4882a593Smuzhiyun  * @proto: ip protocol of packet
82*4882a593Smuzhiyun  * @sum: initial sum to be added in (32bit unfolded)
83*4882a593Smuzhiyun  *
84*4882a593Smuzhiyun  * Returns the pseudo header checksum the input data. Result is
85*4882a593Smuzhiyun  * 32bit unfolded.
86*4882a593Smuzhiyun  */
87*4882a593Smuzhiyun static inline __wsum
csum_tcpudp_nofold(__be32 saddr,__be32 daddr,__u32 len,__u8 proto,__wsum sum)88*4882a593Smuzhiyun csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
89*4882a593Smuzhiyun 		   __u8 proto, __wsum sum)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	asm("  addl %1, %0\n"
92*4882a593Smuzhiyun 	    "  adcl %2, %0\n"
93*4882a593Smuzhiyun 	    "  adcl %3, %0\n"
94*4882a593Smuzhiyun 	    "  adcl $0, %0\n"
95*4882a593Smuzhiyun 	    : "=r" (sum)
96*4882a593Smuzhiyun 	    : "g" (daddr), "g" (saddr),
97*4882a593Smuzhiyun 	      "g" ((len + proto)<<8), "0" (sum));
98*4882a593Smuzhiyun 	return sum;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun /**
103*4882a593Smuzhiyun  * csum_tcpup_magic - Compute an IPv4 pseudo header checksum.
104*4882a593Smuzhiyun  * @saddr: source address
105*4882a593Smuzhiyun  * @daddr: destination address
106*4882a593Smuzhiyun  * @len: length of packet
107*4882a593Smuzhiyun  * @proto: ip protocol of packet
108*4882a593Smuzhiyun  * @sum: initial sum to be added in (32bit unfolded)
109*4882a593Smuzhiyun  *
110*4882a593Smuzhiyun  * Returns the 16bit pseudo header checksum the input data already
111*4882a593Smuzhiyun  * complemented and ready to be filled in.
112*4882a593Smuzhiyun  */
csum_tcpudp_magic(__be32 saddr,__be32 daddr,__u32 len,__u8 proto,__wsum sum)113*4882a593Smuzhiyun static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
114*4882a593Smuzhiyun 					__u32 len, __u8 proto,
115*4882a593Smuzhiyun 					__wsum sum)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun /**
121*4882a593Smuzhiyun  * csum_partial - Compute an internet checksum.
122*4882a593Smuzhiyun  * @buff: buffer to be checksummed
123*4882a593Smuzhiyun  * @len: length of buffer.
124*4882a593Smuzhiyun  * @sum: initial sum to be added in (32bit unfolded)
125*4882a593Smuzhiyun  *
126*4882a593Smuzhiyun  * Returns the 32bit unfolded internet checksum of the buffer.
127*4882a593Smuzhiyun  * Before filling it in it needs to be csum_fold()'ed.
128*4882a593Smuzhiyun  * buff should be aligned to a 64bit boundary if possible.
129*4882a593Smuzhiyun  */
130*4882a593Smuzhiyun extern __wsum csum_partial(const void *buff, int len, __wsum sum);
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun /* Do not call this directly. Use the wrappers below */
133*4882a593Smuzhiyun extern __visible __wsum csum_partial_copy_generic(const void *src, void *dst, int len);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun extern __wsum csum_and_copy_from_user(const void __user *src, void *dst, int len);
136*4882a593Smuzhiyun extern __wsum csum_and_copy_to_user(const void *src, void __user *dst, int len);
137*4882a593Smuzhiyun extern __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len);
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun /**
140*4882a593Smuzhiyun  * ip_compute_csum - Compute an 16bit IP checksum.
141*4882a593Smuzhiyun  * @buff: buffer address.
142*4882a593Smuzhiyun  * @len: length of buffer.
143*4882a593Smuzhiyun  *
144*4882a593Smuzhiyun  * Returns the 16bit folded/inverted checksum of the passed buffer.
145*4882a593Smuzhiyun  * Ready to fill in.
146*4882a593Smuzhiyun  */
147*4882a593Smuzhiyun extern __sum16 ip_compute_csum(const void *buff, int len);
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun /**
150*4882a593Smuzhiyun  * csum_ipv6_magic - Compute checksum of an IPv6 pseudo header.
151*4882a593Smuzhiyun  * @saddr: source address
152*4882a593Smuzhiyun  * @daddr: destination address
153*4882a593Smuzhiyun  * @len: length of packet
154*4882a593Smuzhiyun  * @proto: protocol of packet
155*4882a593Smuzhiyun  * @sum: initial sum (32bit unfolded) to be added in
156*4882a593Smuzhiyun  *
157*4882a593Smuzhiyun  * Computes an IPv6 pseudo header checksum. This sum is added the checksum
158*4882a593Smuzhiyun  * into UDP/TCP packets and contains some link layer information.
159*4882a593Smuzhiyun  * Returns the unfolded 32bit checksum.
160*4882a593Smuzhiyun  */
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun struct in6_addr;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun #define _HAVE_ARCH_IPV6_CSUM 1
165*4882a593Smuzhiyun extern __sum16
166*4882a593Smuzhiyun csum_ipv6_magic(const struct in6_addr *saddr, const struct in6_addr *daddr,
167*4882a593Smuzhiyun 		__u32 len, __u8 proto, __wsum sum);
168*4882a593Smuzhiyun 
add32_with_carry(unsigned a,unsigned b)169*4882a593Smuzhiyun static inline unsigned add32_with_carry(unsigned a, unsigned b)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun 	asm("addl %2,%0\n\t"
172*4882a593Smuzhiyun 	    "adcl $0,%0"
173*4882a593Smuzhiyun 	    : "=r" (a)
174*4882a593Smuzhiyun 	    : "0" (a), "rm" (b));
175*4882a593Smuzhiyun 	return a;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun #define HAVE_ARCH_CSUM_ADD
csum_add(__wsum csum,__wsum addend)179*4882a593Smuzhiyun static inline __wsum csum_add(__wsum csum, __wsum addend)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun 	return (__force __wsum)add32_with_carry((__force unsigned)csum,
182*4882a593Smuzhiyun 						(__force unsigned)addend);
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun #endif /* _ASM_X86_CHECKSUM_64_H */
186