162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci#ifndef _ASM_POWERPC_CHECKSUM_H
362306a36Sopenharmony_ci#define _ASM_POWERPC_CHECKSUM_H
462306a36Sopenharmony_ci#ifdef __KERNEL__
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci/*
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/bitops.h>
1062306a36Sopenharmony_ci#include <linux/in6.h>
1162306a36Sopenharmony_ci/*
1262306a36Sopenharmony_ci * Computes the checksum of a memory block at src, length len,
1362306a36Sopenharmony_ci * and adds in "sum" (32-bit), while copying the block to dst.
1462306a36Sopenharmony_ci * If an access exception occurs on src or dst, it stores -EFAULT
1562306a36Sopenharmony_ci * to *src_err or *dst_err respectively (if that pointer is not
1662306a36Sopenharmony_ci * NULL), and, for an error on src, zeroes the rest of dst.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * Like csum_partial, this must be called with even lengths,
1962306a36Sopenharmony_ci * except for the last fragment.
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_ciextern __wsum csum_partial_copy_generic(const void *src, void *dst, int len);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
2462306a36Sopenharmony_ciextern __wsum csum_and_copy_from_user(const void __user *src, void *dst,
2562306a36Sopenharmony_ci				      int len);
2662306a36Sopenharmony_ci#define HAVE_CSUM_COPY_USER
2762306a36Sopenharmony_ciextern __wsum csum_and_copy_to_user(const void *src, void __user *dst,
2862306a36Sopenharmony_ci				    int len);
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define _HAVE_ARCH_CSUM_AND_COPY
3162306a36Sopenharmony_ci#define csum_partial_copy_nocheck(src, dst, len)   \
3262306a36Sopenharmony_ci        csum_partial_copy_generic((src), (dst), (len))
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/*
3662306a36Sopenharmony_ci * turns a 32-bit partial checksum (e.g. from csum_partial) into a
3762306a36Sopenharmony_ci * 1's complement 16-bit checksum.
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_cistatic inline __sum16 csum_fold(__wsum sum)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	u32 tmp = (__force u32)sum;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	/*
4462306a36Sopenharmony_ci	 * swap the two 16-bit halves of sum
4562306a36Sopenharmony_ci	 * if there is a carry from adding the two 16-bit halves,
4662306a36Sopenharmony_ci	 * it will carry from the lower half into the upper half,
4762306a36Sopenharmony_ci	 * giving us the correct sum in the upper half.
4862306a36Sopenharmony_ci	 */
4962306a36Sopenharmony_ci	return (__force __sum16)(~(tmp + rol32(tmp, 16)) >> 16);
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic inline u32 from64to32(u64 x)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	return (x + ror64(x, 32)) >> 32;
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
5862306a36Sopenharmony_ci					__u8 proto, __wsum sum)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci#ifdef __powerpc64__
6162306a36Sopenharmony_ci	u64 s = (__force u32)sum;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	s += (__force u32)saddr;
6462306a36Sopenharmony_ci	s += (__force u32)daddr;
6562306a36Sopenharmony_ci#ifdef __BIG_ENDIAN__
6662306a36Sopenharmony_ci	s += proto + len;
6762306a36Sopenharmony_ci#else
6862306a36Sopenharmony_ci	s += (proto + len) << 8;
6962306a36Sopenharmony_ci#endif
7062306a36Sopenharmony_ci	return (__force __wsum) from64to32(s);
7162306a36Sopenharmony_ci#else
7262306a36Sopenharmony_ci    __asm__("\n\
7362306a36Sopenharmony_ci	addc %0,%0,%1 \n\
7462306a36Sopenharmony_ci	adde %0,%0,%2 \n\
7562306a36Sopenharmony_ci	adde %0,%0,%3 \n\
7662306a36Sopenharmony_ci	addze %0,%0 \n\
7762306a36Sopenharmony_ci	"
7862306a36Sopenharmony_ci	: "=r" (sum)
7962306a36Sopenharmony_ci	: "r" (daddr), "r"(saddr), "r"(proto + len), "0"(sum));
8062306a36Sopenharmony_ci	return sum;
8162306a36Sopenharmony_ci#endif
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci/*
8562306a36Sopenharmony_ci * computes the checksum of the TCP/UDP pseudo-header
8662306a36Sopenharmony_ci * returns a 16-bit checksum, already complemented
8762306a36Sopenharmony_ci */
8862306a36Sopenharmony_cistatic inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len,
8962306a36Sopenharmony_ci					__u8 proto, __wsum sum)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci#define HAVE_ARCH_CSUM_ADD
9562306a36Sopenharmony_cistatic __always_inline __wsum csum_add(__wsum csum, __wsum addend)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci#ifdef __powerpc64__
9862306a36Sopenharmony_ci	u64 res = (__force u64)csum;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	res += (__force u64)addend;
10162306a36Sopenharmony_ci	return (__force __wsum)((u32)res + (res >> 32));
10262306a36Sopenharmony_ci#else
10362306a36Sopenharmony_ci	if (__builtin_constant_p(csum) && csum == 0)
10462306a36Sopenharmony_ci		return addend;
10562306a36Sopenharmony_ci	if (__builtin_constant_p(addend) && addend == 0)
10662306a36Sopenharmony_ci		return csum;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	asm("addc %0,%0,%1;"
10962306a36Sopenharmony_ci	    "addze %0,%0;"
11062306a36Sopenharmony_ci	    : "+r" (csum) : "r" (addend) : "xer");
11162306a36Sopenharmony_ci	return csum;
11262306a36Sopenharmony_ci#endif
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci#define HAVE_ARCH_CSUM_SHIFT
11662306a36Sopenharmony_cistatic __always_inline __wsum csum_shift(__wsum sum, int offset)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	/* rotate sum to align it with a 16b boundary */
11962306a36Sopenharmony_ci	return (__force __wsum)rol32((__force u32)sum, (offset & 1) << 3);
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/*
12362306a36Sopenharmony_ci * This is a version of ip_compute_csum() optimized for IP headers,
12462306a36Sopenharmony_ci * which always checksum on 4 octet boundaries.  ihl is the number
12562306a36Sopenharmony_ci * of 32-bit words and is always >= 5.
12662306a36Sopenharmony_ci */
12762306a36Sopenharmony_cistatic inline __wsum ip_fast_csum_nofold(const void *iph, unsigned int ihl)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	const u32 *ptr = (const u32 *)iph + 1;
13062306a36Sopenharmony_ci#ifdef __powerpc64__
13162306a36Sopenharmony_ci	unsigned int i;
13262306a36Sopenharmony_ci	u64 s = *(const u32 *)iph;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	for (i = 0; i < ihl - 1; i++, ptr++)
13562306a36Sopenharmony_ci		s += *ptr;
13662306a36Sopenharmony_ci	return (__force __wsum)from64to32(s);
13762306a36Sopenharmony_ci#else
13862306a36Sopenharmony_ci	__wsum sum, tmp;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	asm("mtctr %3;"
14162306a36Sopenharmony_ci	    "addc %0,%4,%5;"
14262306a36Sopenharmony_ci	    "1: lwzu %1, 4(%2);"
14362306a36Sopenharmony_ci	    "adde %0,%0,%1;"
14462306a36Sopenharmony_ci	    "bdnz 1b;"
14562306a36Sopenharmony_ci	    "addze %0,%0;"
14662306a36Sopenharmony_ci	    : "=r" (sum), "=r" (tmp), "+b" (ptr)
14762306a36Sopenharmony_ci	    : "r" (ihl - 2), "r" (*(const u32 *)iph), "r" (*ptr)
14862306a36Sopenharmony_ci	    : "ctr", "xer", "memory");
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	return sum;
15162306a36Sopenharmony_ci#endif
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	return csum_fold(ip_fast_csum_nofold(iph, ihl));
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/*
16062306a36Sopenharmony_ci * computes the checksum of a memory block at buff, length len,
16162306a36Sopenharmony_ci * and adds in "sum" (32-bit)
16262306a36Sopenharmony_ci *
16362306a36Sopenharmony_ci * returns a 32-bit number suitable for feeding into itself
16462306a36Sopenharmony_ci * or csum_tcpudp_magic
16562306a36Sopenharmony_ci *
16662306a36Sopenharmony_ci * this function must be called with even lengths, except
16762306a36Sopenharmony_ci * for the last fragment, which may be odd
16862306a36Sopenharmony_ci *
16962306a36Sopenharmony_ci * it's best to have buff aligned on a 32-bit boundary
17062306a36Sopenharmony_ci */
17162306a36Sopenharmony_ci__wsum __csum_partial(const void *buff, int len, __wsum sum);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic __always_inline __wsum csum_partial(const void *buff, int len, __wsum sum)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	if (__builtin_constant_p(len) && len <= 16 && (len & 1) == 0) {
17662306a36Sopenharmony_ci		if (len == 2)
17762306a36Sopenharmony_ci			sum = csum_add(sum, (__force __wsum)*(const u16 *)buff);
17862306a36Sopenharmony_ci		if (len >= 4)
17962306a36Sopenharmony_ci			sum = csum_add(sum, (__force __wsum)*(const u32 *)buff);
18062306a36Sopenharmony_ci		if (len == 6)
18162306a36Sopenharmony_ci			sum = csum_add(sum, (__force __wsum)
18262306a36Sopenharmony_ci					    *(const u16 *)(buff + 4));
18362306a36Sopenharmony_ci		if (len >= 8)
18462306a36Sopenharmony_ci			sum = csum_add(sum, (__force __wsum)
18562306a36Sopenharmony_ci					    *(const u32 *)(buff + 4));
18662306a36Sopenharmony_ci		if (len == 10)
18762306a36Sopenharmony_ci			sum = csum_add(sum, (__force __wsum)
18862306a36Sopenharmony_ci					    *(const u16 *)(buff + 8));
18962306a36Sopenharmony_ci		if (len >= 12)
19062306a36Sopenharmony_ci			sum = csum_add(sum, (__force __wsum)
19162306a36Sopenharmony_ci					    *(const u32 *)(buff + 8));
19262306a36Sopenharmony_ci		if (len == 14)
19362306a36Sopenharmony_ci			sum = csum_add(sum, (__force __wsum)
19462306a36Sopenharmony_ci					    *(const u16 *)(buff + 12));
19562306a36Sopenharmony_ci		if (len >= 16)
19662306a36Sopenharmony_ci			sum = csum_add(sum, (__force __wsum)
19762306a36Sopenharmony_ci					    *(const u32 *)(buff + 12));
19862306a36Sopenharmony_ci	} else if (__builtin_constant_p(len) && (len & 3) == 0) {
19962306a36Sopenharmony_ci		sum = csum_add(sum, ip_fast_csum_nofold(buff, len >> 2));
20062306a36Sopenharmony_ci	} else {
20162306a36Sopenharmony_ci		sum = __csum_partial(buff, len, sum);
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci	return sum;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci/*
20762306a36Sopenharmony_ci * this routine is used for miscellaneous IP-like checksums, mainly
20862306a36Sopenharmony_ci * in icmp.c
20962306a36Sopenharmony_ci */
21062306a36Sopenharmony_cistatic inline __sum16 ip_compute_csum(const void *buff, int len)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	return csum_fold(csum_partial(buff, len, 0));
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci#define _HAVE_ARCH_IPV6_CSUM
21662306a36Sopenharmony_ci__sum16 csum_ipv6_magic(const struct in6_addr *saddr,
21762306a36Sopenharmony_ci			const struct in6_addr *daddr,
21862306a36Sopenharmony_ci			__u32 len, __u8 proto, __wsum sum);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci#endif /* __KERNEL__ */
22162306a36Sopenharmony_ci#endif
222