Path: blob/master/arch/m32r/include/asm/checksum.h
10818 views
#ifdef __KERNEL__1#ifndef _ASM_M32R_CHECKSUM_H2#define _ASM_M32R_CHECKSUM_H34/*5* include/asm-m32r/checksum.h6*7* IP/TCP/UDP checksum routines8*9* This file is subject to the terms and conditions of the GNU General Public10* License. See the file "COPYING" in the main directory of this archive11* for more details.12*13* Some code taken from mips and parisc architecture.14*15* Copyright (C) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata16* Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org>17*/1819#include <linux/in6.h>2021/*22* computes the checksum of a memory block at buff, length len,23* and adds in "sum" (32-bit)24*25* returns a 32-bit number suitable for feeding into itself26* or csum_tcpudp_magic27*28* this function must be called with even lengths, except29* for the last fragment, which may be odd30*31* it's best to have buff aligned on a 32-bit boundary32*/33asmlinkage __wsum csum_partial(const void *buff, int len, __wsum sum);3435/*36* The same as csum_partial, but copies from src while it checksums.37*38* Here even more important to align src and dst on a 32-bit (or even39* better 64-bit) boundary40*/41extern __wsum csum_partial_copy_nocheck(const void *src, void *dst,42int len, __wsum sum);4344/*45* This is a new version of the above that records errors it finds in *errp,46* but continues and zeros thre rest of the buffer.47*/48extern __wsum csum_partial_copy_from_user(const void __user *src, void *dst,49int len, __wsum sum,50int *err_ptr);5152/*53* Fold a partial checksum54*/5556static inline __sum16 csum_fold(__wsum sum)57{58unsigned long tmpreg;59__asm__(60" sll3 %1, %0, #16 \n"61" cmp %0, %0 \n"62" addx %0, %1 \n"63" ldi %1, #0 \n"64" srli %0, #16 \n"65" addx %0, %1 \n"66" xor3 %0, %0, #0x0000ffff \n"67: "=r" (sum), "=&r" (tmpreg)68: "0" (sum)69: "cbit"70);71return (__force __sum16)sum;72}7374/*75* This is a version of ip_compute_csum() optimized for IP headers,76* which always checksum on 4 octet boundaries.77*/78static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)79{80unsigned long tmpreg0, tmpreg1;81__wsum sum;8283__asm__ __volatile__(84" ld %0, @%1+ \n"85" addi %2, #-4 \n"86"# bgez %2, 2f \n"87" cmp %0, %0 \n"88" ld %3, @%1+ \n"89" ld %4, @%1+ \n"90" addx %0, %3 \n"91" ld %3, @%1+ \n"92" addx %0, %4 \n"93" addx %0, %3 \n"94" .fillinsn\n"95"1: \n"96" ld %4, @%1+ \n"97" addi %2, #-1 \n"98" addx %0, %4 \n"99" bgtz %2, 1b \n"100"\n"101" ldi %3, #0 \n"102" addx %0, %3 \n"103" .fillinsn\n"104"2: \n"105/* Since the input registers which are loaded with iph and ihl106are modified, we must also specify them as outputs, or gcc107will assume they contain their original values. */108: "=&r" (sum), "=r" (iph), "=r" (ihl), "=&r" (tmpreg0), "=&r" (tmpreg1)109: "1" (iph), "2" (ihl)110: "cbit", "memory");111112return csum_fold(sum);113}114115static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,116unsigned short len,117unsigned short proto,118__wsum sum)119{120#if defined(__LITTLE_ENDIAN)121unsigned long len_proto = (proto + len) << 8;122#else123unsigned long len_proto = proto + len;124#endif125unsigned long tmpreg;126127__asm__(128" cmp %0, %0 \n"129" addx %0, %2 \n"130" addx %0, %3 \n"131" addx %0, %4 \n"132" ldi %1, #0 \n"133" addx %0, %1 \n"134: "=r" (sum), "=&r" (tmpreg)135: "r" (daddr), "r" (saddr), "r" (len_proto), "0" (sum)136: "cbit"137);138139return sum;140}141142/*143* computes the checksum of the TCP/UDP pseudo-header144* returns a 16-bit checksum, already complemented145*/146static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,147unsigned short len,148unsigned short proto,149__wsum sum)150{151return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));152}153154/*155* this routine is used for miscellaneous IP-like checksums, mainly156* in icmp.c157*/158159static inline __sum16 ip_compute_csum(const void *buff, int len)160{161return csum_fold (csum_partial(buff, len, 0));162}163164#define _HAVE_ARCH_IPV6_CSUM165static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,166const struct in6_addr *daddr,167__u32 len, unsigned short proto,168__wsum sum)169{170unsigned long tmpreg0, tmpreg1, tmpreg2, tmpreg3;171__asm__(172" ld %1, @(%5) \n"173" ld %2, @(4,%5) \n"174" ld %3, @(8,%5) \n"175" ld %4, @(12,%5) \n"176" add %0, %1 \n"177" addx %0, %2 \n"178" addx %0, %3 \n"179" addx %0, %4 \n"180" ld %1, @(%6) \n"181" ld %2, @(4,%6) \n"182" ld %3, @(8,%6) \n"183" ld %4, @(12,%6) \n"184" addx %0, %1 \n"185" addx %0, %2 \n"186" addx %0, %3 \n"187" addx %0, %4 \n"188" addx %0, %7 \n"189" addx %0, %8 \n"190" ldi %1, #0 \n"191" addx %0, %1 \n"192: "=&r" (sum), "=&r" (tmpreg0), "=&r" (tmpreg1),193"=&r" (tmpreg2), "=&r" (tmpreg3)194: "r" (saddr), "r" (daddr),195"r" (htonl(len)), "r" (htonl(proto)), "0" (sum)196: "cbit"197);198199return csum_fold(sum);200}201202#endif /* _ASM_M32R_CHECKSUM_H */203#endif /* __KERNEL__ */204205206