Path: blob/master/arch/sh/include/asm/checksum_32.h
15126 views
#ifndef __ASM_SH_CHECKSUM_H1#define __ASM_SH_CHECKSUM_H23/*4* This file is subject to the terms and conditions of the GNU General Public5* License. See the file "COPYING" in the main directory of this archive6* for more details.7*8* Copyright (C) 1999 by Kaz Kojima & Niibe Yutaka9*/1011#include <linux/in6.h>1213/*14* computes the checksum of a memory block at buff, length len,15* and adds in "sum" (32-bit)16*17* returns a 32-bit number suitable for feeding into itself18* or csum_tcpudp_magic19*20* this function must be called with even lengths, except21* for the last fragment, which may be odd22*23* it's best to have buff aligned on a 32-bit boundary24*/25asmlinkage __wsum csum_partial(const void *buff, int len, __wsum sum);2627/*28* the same as csum_partial, but copies from src while it29* checksums, and handles user-space pointer exceptions correctly, when needed.30*31* here even more important to align src and dst on a 32-bit (or even32* better 64-bit) boundary33*/3435asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst,36int len, __wsum sum,37int *src_err_ptr, int *dst_err_ptr);3839/*40* Note: when you get a NULL pointer exception here this means someone41* passed in an incorrect kernel address to one of these functions.42*43* If you use these functions directly please don't forget the44* access_ok().45*/46static inline47__wsum csum_partial_copy_nocheck(const void *src, void *dst,48int len, __wsum sum)49{50return csum_partial_copy_generic(src, dst, len, sum, NULL, NULL);51}5253static inline54__wsum csum_partial_copy_from_user(const void __user *src, void *dst,55int len, __wsum sum, int *err_ptr)56{57return csum_partial_copy_generic((__force const void *)src, dst,58len, sum, err_ptr, NULL);59}6061/*62* Fold a partial checksum63*/6465static inline __sum16 csum_fold(__wsum sum)66{67unsigned int __dummy;68__asm__("swap.w %0, %1\n\t"69"extu.w %0, %0\n\t"70"extu.w %1, %1\n\t"71"add %1, %0\n\t"72"swap.w %0, %1\n\t"73"add %1, %0\n\t"74"not %0, %0\n\t"75: "=r" (sum), "=&r" (__dummy)76: "0" (sum)77: "t");78return (__force __sum16)sum;79}8081/*82* This is a version of ip_compute_csum() optimized for IP headers,83* which always checksum on 4 octet boundaries.84*85* i386 version by Jorge Cwik <[email protected]>, adapted86* for linux by * Arnt Gulbrandsen.87*/88static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)89{90unsigned int sum, __dummy0, __dummy1;9192__asm__ __volatile__(93"mov.l @%1+, %0\n\t"94"mov.l @%1+, %3\n\t"95"add #-2, %2\n\t"96"clrt\n\t"97"1:\t"98"addc %3, %0\n\t"99"movt %4\n\t"100"mov.l @%1+, %3\n\t"101"dt %2\n\t"102"bf/s 1b\n\t"103" cmp/eq #1, %4\n\t"104"addc %3, %0\n\t"105"addc %2, %0" /* Here %2 is 0, add carry-bit */106/* Since the input registers which are loaded with iph and ihl107are modified, we must also specify them as outputs, or gcc108will assume they contain their original values. */109: "=r" (sum), "=r" (iph), "=r" (ihl), "=&r" (__dummy0), "=&z" (__dummy1)110: "1" (iph), "2" (ihl)111: "t", "memory");112113return csum_fold(sum);114}115116static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,117unsigned short len,118unsigned short proto,119__wsum sum)120{121#ifdef __LITTLE_ENDIAN__122unsigned long len_proto = (proto + len) << 8;123#else124unsigned long len_proto = proto + len;125#endif126__asm__("clrt\n\t"127"addc %0, %1\n\t"128"addc %2, %1\n\t"129"addc %3, %1\n\t"130"movt %0\n\t"131"add %1, %0"132: "=r" (sum), "=r" (len_proto)133: "r" (daddr), "r" (saddr), "1" (len_proto), "0" (sum)134: "t");135136return sum;137}138139/*140* computes the checksum of the TCP/UDP pseudo-header141* returns a 16-bit checksum, already complemented142*/143static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,144unsigned short len,145unsigned short proto,146__wsum sum)147{148return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));149}150151/*152* this routine is used for miscellaneous IP-like checksums, mainly153* in icmp.c154*/155static inline __sum16 ip_compute_csum(const void *buff, int len)156{157return csum_fold(csum_partial(buff, len, 0));158}159160#define _HAVE_ARCH_IPV6_CSUM161static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,162const struct in6_addr *daddr,163__u32 len, unsigned short proto,164__wsum sum)165{166unsigned int __dummy;167__asm__("clrt\n\t"168"mov.l @(0,%2), %1\n\t"169"addc %1, %0\n\t"170"mov.l @(4,%2), %1\n\t"171"addc %1, %0\n\t"172"mov.l @(8,%2), %1\n\t"173"addc %1, %0\n\t"174"mov.l @(12,%2), %1\n\t"175"addc %1, %0\n\t"176"mov.l @(0,%3), %1\n\t"177"addc %1, %0\n\t"178"mov.l @(4,%3), %1\n\t"179"addc %1, %0\n\t"180"mov.l @(8,%3), %1\n\t"181"addc %1, %0\n\t"182"mov.l @(12,%3), %1\n\t"183"addc %1, %0\n\t"184"addc %4, %0\n\t"185"addc %5, %0\n\t"186"movt %1\n\t"187"add %1, %0\n"188: "=r" (sum), "=&r" (__dummy)189: "r" (saddr), "r" (daddr),190"r" (htonl(len)), "r" (htonl(proto)), "0" (sum)191: "t");192193return csum_fold(sum);194}195196/*197* Copy and checksum to user198*/199#define HAVE_CSUM_COPY_USER200static inline __wsum csum_and_copy_to_user(const void *src,201void __user *dst,202int len, __wsum sum,203int *err_ptr)204{205if (access_ok(VERIFY_WRITE, dst, len))206return csum_partial_copy_generic((__force const void *)src,207dst, len, sum, NULL, err_ptr);208209if (len)210*err_ptr = -EFAULT;211212return (__force __wsum)-1; /* invalid checksum */213}214#endif /* __ASM_SH_CHECKSUM_H */215216217