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