xref: /openbmc/linux/arch/x86/um/asm/checksum.h (revision 6e41c585)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
25c48b108SAl Viro #ifndef __UM_CHECKSUM_H
35c48b108SAl Viro #define __UM_CHECKSUM_H
45c48b108SAl Viro 
54301785cSAl Viro #include <linux/string.h>
64301785cSAl Viro #include <linux/in6.h>
7f8d65d27SRichard Weinberger #include <linux/uaccess.h>
84301785cSAl Viro 
94301785cSAl Viro /*
104301785cSAl Viro  * computes the checksum of a memory block at buff, length len,
114301785cSAl Viro  * and adds in "sum" (32-bit)
124301785cSAl Viro  *
134301785cSAl Viro  * returns a 32-bit number suitable for feeding into itself
144301785cSAl Viro  * or csum_tcpudp_magic
154301785cSAl Viro  *
164301785cSAl Viro  * this function must be called with even lengths, except
174301785cSAl Viro  * for the last fragment, which may be odd
184301785cSAl Viro  *
194301785cSAl Viro  * it's best to have buff aligned on a 32-bit boundary
204301785cSAl Viro  */
214301785cSAl Viro extern __wsum csum_partial(const void *buff, int len, __wsum sum);
224301785cSAl Viro 
234301785cSAl Viro /**
244301785cSAl Viro  * csum_fold - Fold and invert a 32bit checksum.
254301785cSAl Viro  * sum: 32bit unfolded sum
264301785cSAl Viro  *
274301785cSAl Viro  * Fold a 32bit running checksum to 16bit and invert it. This is usually
284301785cSAl Viro  * the last step before putting a checksum into a packet.
294301785cSAl Viro  * Make sure not to mix with 64bit checksums.
304301785cSAl Viro  */
csum_fold(__wsum sum)314301785cSAl Viro static inline __sum16 csum_fold(__wsum sum)
324301785cSAl Viro {
334301785cSAl Viro 	__asm__(
344301785cSAl Viro 		"  addl %1,%0\n"
354301785cSAl Viro 		"  adcl $0xffff,%0"
364301785cSAl Viro 		: "=r" (sum)
374301785cSAl Viro 		: "r" ((__force u32)sum << 16),
384301785cSAl Viro 		  "0" ((__force u32)sum & 0xffff0000)
394301785cSAl Viro 	);
404301785cSAl Viro 	return (__force __sum16)(~(__force u32)sum >> 16);
414301785cSAl Viro }
424301785cSAl Viro 
434301785cSAl Viro /**
444301785cSAl Viro  * csum_tcpup_nofold - Compute an IPv4 pseudo header checksum.
454301785cSAl Viro  * @saddr: source address
464301785cSAl Viro  * @daddr: destination address
474301785cSAl Viro  * @len: length of packet
484301785cSAl Viro  * @proto: ip protocol of packet
494301785cSAl Viro  * @sum: initial sum to be added in (32bit unfolded)
504301785cSAl Viro  *
514301785cSAl Viro  * Returns the pseudo header checksum the input data. Result is
524301785cSAl Viro  * 32bit unfolded.
534301785cSAl Viro  */
544301785cSAl Viro static inline __wsum
csum_tcpudp_nofold(__be32 saddr,__be32 daddr,__u32 len,__u8 proto,__wsum sum)5501cfbad7SAlexander Duyck csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
5601cfbad7SAlexander Duyck 		  __u8 proto, __wsum sum)
574301785cSAl Viro {
584301785cSAl Viro 	asm("  addl %1, %0\n"
594301785cSAl Viro 	    "  adcl %2, %0\n"
604301785cSAl Viro 	    "  adcl %3, %0\n"
614301785cSAl Viro 	    "  adcl $0, %0\n"
624301785cSAl Viro 		: "=r" (sum)
634301785cSAl Viro 	    : "g" (daddr), "g" (saddr), "g" ((len + proto) << 8), "0" (sum));
644301785cSAl Viro 	return sum;
654301785cSAl Viro }
664301785cSAl Viro 
674301785cSAl Viro /*
684301785cSAl Viro  * computes the checksum of the TCP/UDP pseudo-header
694301785cSAl Viro  * returns a 16-bit checksum, already complemented
704301785cSAl Viro  */
csum_tcpudp_magic(__be32 saddr,__be32 daddr,__u32 len,__u8 proto,__wsum sum)714301785cSAl Viro static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
7201cfbad7SAlexander Duyck 					__u32 len, __u8 proto,
734301785cSAl Viro 					__wsum sum)
744301785cSAl Viro {
754301785cSAl Viro 	return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
764301785cSAl Viro }
774301785cSAl Viro 
784301785cSAl Viro /**
794301785cSAl Viro  * ip_fast_csum - Compute the IPv4 header checksum efficiently.
804301785cSAl Viro  * iph: ipv4 header
814301785cSAl Viro  * ihl: length of header / 4
824301785cSAl Viro  */
ip_fast_csum(const void * iph,unsigned int ihl)834301785cSAl Viro static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
844301785cSAl Viro {
854301785cSAl Viro 	unsigned int sum;
864301785cSAl Viro 
874301785cSAl Viro 	asm(	"  movl (%1), %0\n"
884301785cSAl Viro 		"  subl $4, %2\n"
894301785cSAl Viro 		"  jbe 2f\n"
904301785cSAl Viro 		"  addl 4(%1), %0\n"
914301785cSAl Viro 		"  adcl 8(%1), %0\n"
924301785cSAl Viro 		"  adcl 12(%1), %0\n"
934301785cSAl Viro 		"1: adcl 16(%1), %0\n"
944301785cSAl Viro 		"  lea 4(%1), %1\n"
954301785cSAl Viro 		"  decl %2\n"
964301785cSAl Viro 		"  jne	1b\n"
974301785cSAl Viro 		"  adcl $0, %0\n"
984301785cSAl Viro 		"  movl %0, %2\n"
994301785cSAl Viro 		"  shrl $16, %0\n"
1004301785cSAl Viro 		"  addw %w2, %w0\n"
1014301785cSAl Viro 		"  adcl $0, %0\n"
1024301785cSAl Viro 		"  notl %0\n"
1034301785cSAl Viro 		"2:"
1044301785cSAl Viro 	/* Since the input registers which are loaded with iph and ipl
1054301785cSAl Viro 	   are modified, we must also specify them as outputs, or gcc
1064301785cSAl Viro 	   will assume they contain their original values. */
1074301785cSAl Viro 	: "=r" (sum), "=r" (iph), "=r" (ihl)
1084301785cSAl Viro 	: "1" (iph), "2" (ihl)
1094301785cSAl Viro 	: "memory");
1104301785cSAl Viro 	return (__force __sum16)sum;
1114301785cSAl Viro }
1124301785cSAl Viro 
1135c48b108SAl Viro #ifdef CONFIG_X86_32
1145c48b108SAl Viro # include "checksum_32.h"
1155c48b108SAl Viro #else
1165c48b108SAl Viro # include "checksum_64.h"
1175c48b108SAl Viro #endif
1185c48b108SAl Viro 
1195c48b108SAl Viro #endif
120