18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * include/asm-xtensa/checksum.h
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
58c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
68c2ecf20Sopenharmony_ci * for more details.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright (C) 2001 - 2005 Tensilica Inc.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#ifndef _XTENSA_CHECKSUM_H
128c2ecf20Sopenharmony_ci#define _XTENSA_CHECKSUM_H
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/in6.h>
158c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
168c2ecf20Sopenharmony_ci#include <asm/core.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/*
198c2ecf20Sopenharmony_ci * computes the checksum of a memory block at buff, length len,
208c2ecf20Sopenharmony_ci * and adds in "sum" (32-bit)
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * returns a 32-bit number suitable for feeding into itself
238c2ecf20Sopenharmony_ci * or csum_tcpudp_magic
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * this function must be called with even lengths, except
268c2ecf20Sopenharmony_ci * for the last fragment, which may be odd
278c2ecf20Sopenharmony_ci *
288c2ecf20Sopenharmony_ci * it's best to have buff aligned on a 32-bit boundary
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_ciasmlinkage __wsum csum_partial(const void *buff, int len, __wsum sum);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/*
338c2ecf20Sopenharmony_ci * the same as csum_partial, but copies from src while it
348c2ecf20Sopenharmony_ci * checksums, and handles user-space pointer exceptions correctly, when needed.
358c2ecf20Sopenharmony_ci *
368c2ecf20Sopenharmony_ci * here even more important to align src and dst on a 32-bit (or even
378c2ecf20Sopenharmony_ci * better 64-bit) boundary
388c2ecf20Sopenharmony_ci */
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ciasmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst, int len);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#define _HAVE_ARCH_CSUM_AND_COPY
438c2ecf20Sopenharmony_ci/*
448c2ecf20Sopenharmony_ci *	Note: when you get a NULL pointer exception here this means someone
458c2ecf20Sopenharmony_ci *	passed in an incorrect kernel address to one of these functions.
468c2ecf20Sopenharmony_ci */
478c2ecf20Sopenharmony_cistatic inline
488c2ecf20Sopenharmony_ci__wsum csum_partial_copy_nocheck(const void *src, void *dst, int len)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	return csum_partial_copy_generic(src, dst, len);
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
548c2ecf20Sopenharmony_cistatic inline
558c2ecf20Sopenharmony_ci__wsum csum_and_copy_from_user(const void __user *src, void *dst,
568c2ecf20Sopenharmony_ci				   int len)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	if (!access_ok(src, len))
598c2ecf20Sopenharmony_ci		return 0;
608c2ecf20Sopenharmony_ci	return csum_partial_copy_generic((__force const void *)src, dst, len);
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/*
648c2ecf20Sopenharmony_ci *	Fold a partial checksum
658c2ecf20Sopenharmony_ci */
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic __inline__ __sum16 csum_fold(__wsum sum)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	unsigned int __dummy;
708c2ecf20Sopenharmony_ci	__asm__("extui	%1, %0, 16, 16\n\t"
718c2ecf20Sopenharmony_ci		"extui	%0 ,%0, 0, 16\n\t"
728c2ecf20Sopenharmony_ci		"add	%0, %0, %1\n\t"
738c2ecf20Sopenharmony_ci		"slli	%1, %0, 16\n\t"
748c2ecf20Sopenharmony_ci		"add	%0, %0, %1\n\t"
758c2ecf20Sopenharmony_ci		"extui	%0, %0, 16, 16\n\t"
768c2ecf20Sopenharmony_ci		"neg	%0, %0\n\t"
778c2ecf20Sopenharmony_ci		"addi	%0, %0, -1\n\t"
788c2ecf20Sopenharmony_ci		"extui	%0, %0, 0, 16\n\t"
798c2ecf20Sopenharmony_ci		: "=r" (sum), "=&r" (__dummy)
808c2ecf20Sopenharmony_ci		: "0" (sum));
818c2ecf20Sopenharmony_ci	return (__force __sum16)sum;
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci/*
858c2ecf20Sopenharmony_ci *	This is a version of ip_compute_csum() optimized for IP headers,
868c2ecf20Sopenharmony_ci *	which always checksum on 4 octet boundaries.
878c2ecf20Sopenharmony_ci */
888c2ecf20Sopenharmony_cistatic __inline__ __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	unsigned int sum, tmp, endaddr;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	__asm__ __volatile__(
938c2ecf20Sopenharmony_ci		"sub		%0, %0, %0\n\t"
948c2ecf20Sopenharmony_ci#if XCHAL_HAVE_LOOPS
958c2ecf20Sopenharmony_ci		"loopgtz	%2, 2f\n\t"
968c2ecf20Sopenharmony_ci#else
978c2ecf20Sopenharmony_ci		"beqz		%2, 2f\n\t"
988c2ecf20Sopenharmony_ci		"slli		%4, %2, 2\n\t"
998c2ecf20Sopenharmony_ci		"add		%4, %4, %1\n\t"
1008c2ecf20Sopenharmony_ci		"0:\t"
1018c2ecf20Sopenharmony_ci#endif
1028c2ecf20Sopenharmony_ci		"l32i		%3, %1, 0\n\t"
1038c2ecf20Sopenharmony_ci		"add		%0, %0, %3\n\t"
1048c2ecf20Sopenharmony_ci		"bgeu		%0, %3, 1f\n\t"
1058c2ecf20Sopenharmony_ci		"addi		%0, %0, 1\n\t"
1068c2ecf20Sopenharmony_ci		"1:\t"
1078c2ecf20Sopenharmony_ci		"addi		%1, %1, 4\n\t"
1088c2ecf20Sopenharmony_ci#if !XCHAL_HAVE_LOOPS
1098c2ecf20Sopenharmony_ci		"blt		%1, %4, 0b\n\t"
1108c2ecf20Sopenharmony_ci#endif
1118c2ecf20Sopenharmony_ci		"2:\t"
1128c2ecf20Sopenharmony_ci	/* Since the input registers which are loaded with iph and ihl
1138c2ecf20Sopenharmony_ci	   are modified, we must also specify them as outputs, or gcc
1148c2ecf20Sopenharmony_ci	   will assume they contain their original values. */
1158c2ecf20Sopenharmony_ci		: "=r" (sum), "=r" (iph), "=r" (ihl), "=&r" (tmp),
1168c2ecf20Sopenharmony_ci		  "=&r" (endaddr)
1178c2ecf20Sopenharmony_ci		: "1" (iph), "2" (ihl)
1188c2ecf20Sopenharmony_ci		: "memory");
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	return	csum_fold(sum);
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic __inline__ __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
1248c2ecf20Sopenharmony_ci					    __u32 len, __u8 proto,
1258c2ecf20Sopenharmony_ci					    __wsum sum)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci#ifdef __XTENSA_EL__
1298c2ecf20Sopenharmony_ci	unsigned long len_proto = (len + proto) << 8;
1308c2ecf20Sopenharmony_ci#elif defined(__XTENSA_EB__)
1318c2ecf20Sopenharmony_ci	unsigned long len_proto = len + proto;
1328c2ecf20Sopenharmony_ci#else
1338c2ecf20Sopenharmony_ci# error processor byte order undefined!
1348c2ecf20Sopenharmony_ci#endif
1358c2ecf20Sopenharmony_ci	__asm__("add	%0, %0, %1\n\t"
1368c2ecf20Sopenharmony_ci		"bgeu	%0, %1, 1f\n\t"
1378c2ecf20Sopenharmony_ci		"addi	%0, %0, 1\n\t"
1388c2ecf20Sopenharmony_ci		"1:\t"
1398c2ecf20Sopenharmony_ci		"add	%0, %0, %2\n\t"
1408c2ecf20Sopenharmony_ci		"bgeu	%0, %2, 1f\n\t"
1418c2ecf20Sopenharmony_ci		"addi	%0, %0, 1\n\t"
1428c2ecf20Sopenharmony_ci		"1:\t"
1438c2ecf20Sopenharmony_ci		"add	%0, %0, %3\n\t"
1448c2ecf20Sopenharmony_ci		"bgeu	%0, %3, 1f\n\t"
1458c2ecf20Sopenharmony_ci		"addi	%0, %0, 1\n\t"
1468c2ecf20Sopenharmony_ci		"1:\t"
1478c2ecf20Sopenharmony_ci		: "=r" (sum), "=r" (len_proto)
1488c2ecf20Sopenharmony_ci		: "r" (daddr), "r" (saddr), "1" (len_proto), "0" (sum));
1498c2ecf20Sopenharmony_ci	return sum;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci/*
1538c2ecf20Sopenharmony_ci * computes the checksum of the TCP/UDP pseudo-header
1548c2ecf20Sopenharmony_ci * returns a 16-bit checksum, already complemented
1558c2ecf20Sopenharmony_ci */
1568c2ecf20Sopenharmony_cistatic __inline__ __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
1578c2ecf20Sopenharmony_ci					    __u32 len, __u8 proto,
1588c2ecf20Sopenharmony_ci					    __wsum sum)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci/*
1648c2ecf20Sopenharmony_ci * this routine is used for miscellaneous IP-like checksums, mainly
1658c2ecf20Sopenharmony_ci * in icmp.c
1668c2ecf20Sopenharmony_ci */
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic __inline__ __sum16 ip_compute_csum(const void *buff, int len)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	return csum_fold (csum_partial(buff, len, 0));
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci#define _HAVE_ARCH_IPV6_CSUM
1748c2ecf20Sopenharmony_cistatic __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
1758c2ecf20Sopenharmony_ci					  const struct in6_addr *daddr,
1768c2ecf20Sopenharmony_ci					  __u32 len, __u8 proto,
1778c2ecf20Sopenharmony_ci					  __wsum sum)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	unsigned int __dummy;
1808c2ecf20Sopenharmony_ci	__asm__("l32i	%1, %2, 0\n\t"
1818c2ecf20Sopenharmony_ci		"add	%0, %0, %1\n\t"
1828c2ecf20Sopenharmony_ci		"bgeu	%0, %1, 1f\n\t"
1838c2ecf20Sopenharmony_ci		"addi	%0, %0, 1\n\t"
1848c2ecf20Sopenharmony_ci		"1:\t"
1858c2ecf20Sopenharmony_ci		"l32i	%1, %2, 4\n\t"
1868c2ecf20Sopenharmony_ci		"add	%0, %0, %1\n\t"
1878c2ecf20Sopenharmony_ci		"bgeu	%0, %1, 1f\n\t"
1888c2ecf20Sopenharmony_ci		"addi	%0, %0, 1\n\t"
1898c2ecf20Sopenharmony_ci		"1:\t"
1908c2ecf20Sopenharmony_ci		"l32i	%1, %2, 8\n\t"
1918c2ecf20Sopenharmony_ci		"add	%0, %0, %1\n\t"
1928c2ecf20Sopenharmony_ci		"bgeu	%0, %1, 1f\n\t"
1938c2ecf20Sopenharmony_ci		"addi	%0, %0, 1\n\t"
1948c2ecf20Sopenharmony_ci		"1:\t"
1958c2ecf20Sopenharmony_ci		"l32i	%1, %2, 12\n\t"
1968c2ecf20Sopenharmony_ci		"add	%0, %0, %1\n\t"
1978c2ecf20Sopenharmony_ci		"bgeu	%0, %1, 1f\n\t"
1988c2ecf20Sopenharmony_ci		"addi	%0, %0, 1\n\t"
1998c2ecf20Sopenharmony_ci		"1:\t"
2008c2ecf20Sopenharmony_ci		"l32i	%1, %3, 0\n\t"
2018c2ecf20Sopenharmony_ci		"add	%0, %0, %1\n\t"
2028c2ecf20Sopenharmony_ci		"bgeu	%0, %1, 1f\n\t"
2038c2ecf20Sopenharmony_ci		"addi	%0, %0, 1\n\t"
2048c2ecf20Sopenharmony_ci		"1:\t"
2058c2ecf20Sopenharmony_ci		"l32i	%1, %3, 4\n\t"
2068c2ecf20Sopenharmony_ci		"add	%0, %0, %1\n\t"
2078c2ecf20Sopenharmony_ci		"bgeu	%0, %1, 1f\n\t"
2088c2ecf20Sopenharmony_ci		"addi	%0, %0, 1\n\t"
2098c2ecf20Sopenharmony_ci		"1:\t"
2108c2ecf20Sopenharmony_ci		"l32i	%1, %3, 8\n\t"
2118c2ecf20Sopenharmony_ci		"add	%0, %0, %1\n\t"
2128c2ecf20Sopenharmony_ci		"bgeu	%0, %1, 1f\n\t"
2138c2ecf20Sopenharmony_ci		"addi	%0, %0, 1\n\t"
2148c2ecf20Sopenharmony_ci		"1:\t"
2158c2ecf20Sopenharmony_ci		"l32i	%1, %3, 12\n\t"
2168c2ecf20Sopenharmony_ci		"add	%0, %0, %1\n\t"
2178c2ecf20Sopenharmony_ci		"bgeu	%0, %1, 1f\n\t"
2188c2ecf20Sopenharmony_ci		"addi	%0, %0, 1\n\t"
2198c2ecf20Sopenharmony_ci		"1:\t"
2208c2ecf20Sopenharmony_ci		"add	%0, %0, %4\n\t"
2218c2ecf20Sopenharmony_ci		"bgeu	%0, %4, 1f\n\t"
2228c2ecf20Sopenharmony_ci		"addi	%0, %0, 1\n\t"
2238c2ecf20Sopenharmony_ci		"1:\t"
2248c2ecf20Sopenharmony_ci		"add	%0, %0, %5\n\t"
2258c2ecf20Sopenharmony_ci		"bgeu	%0, %5, 1f\n\t"
2268c2ecf20Sopenharmony_ci		"addi	%0, %0, 1\n\t"
2278c2ecf20Sopenharmony_ci		"1:\t"
2288c2ecf20Sopenharmony_ci		: "=r" (sum), "=&r" (__dummy)
2298c2ecf20Sopenharmony_ci		: "r" (saddr), "r" (daddr),
2308c2ecf20Sopenharmony_ci		  "r" (htonl(len)), "r" (htonl(proto)), "0" (sum)
2318c2ecf20Sopenharmony_ci		: "memory");
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	return csum_fold(sum);
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci/*
2378c2ecf20Sopenharmony_ci *	Copy and checksum to user
2388c2ecf20Sopenharmony_ci */
2398c2ecf20Sopenharmony_ci#define HAVE_CSUM_COPY_USER
2408c2ecf20Sopenharmony_cistatic __inline__ __wsum csum_and_copy_to_user(const void *src,
2418c2ecf20Sopenharmony_ci					       void __user *dst, int len)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	if (!access_ok(dst, len))
2448c2ecf20Sopenharmony_ci		return 0;
2458c2ecf20Sopenharmony_ci	return csum_partial_copy_generic(src, (__force void *)dst, len);
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci#endif
248