Path: blob/master/arch/score/include/asm/checksum.h
10819 views
#ifndef _ASM_SCORE_CHECKSUM_H1#define _ASM_SCORE_CHECKSUM_H23#include <linux/in6.h>4#include <asm/uaccess.h>56/*7* computes the checksum of a memory block at buff, length len,8* and adds in "sum" (32-bit)9*10* returns a 32-bit number suitable for feeding into itself11* or csum_tcpudp_magic12*13* this function must be called with even lengths, except14* for the last fragment, which may be odd15*16* it's best to have buff aligned on a 32-bit boundary17*/18unsigned int csum_partial(const void *buff, int len, __wsum sum);19unsigned int csum_partial_copy_from_user(const char *src, char *dst, int len,20unsigned int sum, int *csum_err);21unsigned int csum_partial_copy(const char *src, char *dst,22int len, unsigned int sum);2324/*25* this is a new version of the above that records errors it finds in *errp,26* but continues and zeros the rest of the buffer.27*/2829/*30* Copy and checksum to user31*/32#define HAVE_CSUM_COPY_USER33static inline34__wsum csum_and_copy_to_user(const void *src, void __user *dst, int len,35__wsum sum, int *err_ptr)36{37sum = csum_partial(src, len, sum);38if (copy_to_user(dst, src, len)) {39*err_ptr = -EFAULT;40return (__force __wsum) -1; /* invalid checksum */41}42return sum;43}444546#define csum_partial_copy_nocheck csum_partial_copy47/*48* Fold a partial checksum without adding pseudo headers49*/5051static inline __sum16 csum_fold(__wsum sum)52{53/* the while loop is unnecessary really, it's always enough with two54iterations */55__asm__ __volatile__(56".set volatile\n\t"57".set\tr1\n\t"58"slli\tr1,%0, 16\n\t"59"add\t%0,%0, r1\n\t"60"cmp.c\tr1, %0\n\t"61"srli\t%0, %0, 16\n\t"62"bleu\t1f\n\t"63"addi\t%0, 0x1\n\t"64"1:ldi\tr30, 0xffff\n\t"65"xor\t%0, %0, r30\n\t"66"slli\t%0, %0, 16\n\t"67"srli\t%0, %0, 16\n\t"68".set\tnor1\n\t"69".set optimize\n\t"70: "=r" (sum)71: "0" (sum));72return sum;73}7475/*76* This is a version of ip_compute_csum() optimized for IP headers,77* which always checksum on 4 octet boundaries.78*79* By Jorge Cwik <[email protected]>, adapted for linux by80* Arnt Gulbrandsen.81*/82static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)83{84unsigned int sum;85unsigned long dummy;8687__asm__ __volatile__(88".set volatile\n\t"89".set\tnor1\n\t"90"lw\t%0, [%1]\n\t"91"subri\t%2, %2, 4\n\t"92"slli\t%2, %2, 2\n\t"93"lw\t%3, [%1, 4]\n\t"94"add\t%2, %2, %1\n\t"95"add\t%0, %0, %3\n\t"96"cmp.c\t%3, %0\n\t"97"lw\t%3, [%1, 8]\n\t"98"bleu\t1f\n\t"99"addi\t%0, 0x1\n\t"100"1:\n\t"101"add\t%0, %0, %3\n\t"102"cmp.c\t%3, %0\n\t"103"lw\t%3, [%1, 12]\n\t"104"bleu\t1f\n\t"105"addi\t%0, 0x1\n\t"106"1:add\t%0, %0, %3\n\t"107"cmp.c\t%3, %0\n\t"108"bleu\t1f\n\t"109"addi\t%0, 0x1\n"110111"1:\tlw\t%3, [%1, 16]\n\t"112"addi\t%1, 4\n\t"113"add\t%0, %0, %3\n\t"114"cmp.c\t%3, %0\n\t"115"bleu\t2f\n\t"116"addi\t%0, 0x1\n"117"2:cmp.c\t%2, %1\n\t"118"bne\t1b\n\t"119120".set\tr1\n\t"121".set optimize\n\t"122: "=&r" (sum), "=&r" (iph), "=&r" (ihl), "=&r" (dummy)123: "1" (iph), "2" (ihl));124125return csum_fold(sum);126}127128static inline __wsum129csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,130unsigned short proto, __wsum sum)131{132unsigned long tmp = (ntohs(len) << 16) + proto * 256;133__asm__ __volatile__(134".set volatile\n\t"135"add\t%0, %0, %2\n\t"136"cmp.c\t%2, %0\n\t"137"bleu\t1f\n\t"138"addi\t%0, 0x1\n\t"139"1:\n\t"140"add\t%0, %0, %3\n\t"141"cmp.c\t%3, %0\n\t"142"bleu\t1f\n\t"143"addi\t%0, 0x1\n\t"144"1:\n\t"145"add\t%0, %0, %4\n\t"146"cmp.c\t%4, %0\n\t"147"bleu\t1f\n\t"148"addi\t%0, 0x1\n\t"149"1:\n\t"150".set optimize\n\t"151: "=r" (sum)152: "0" (daddr), "r"(saddr),153"r" (tmp),154"r" (sum));155return sum;156}157158/*159* computes the checksum of the TCP/UDP pseudo-header160* returns a 16-bit checksum, already complemented161*/162static inline __sum16163csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len,164unsigned short proto, __wsum sum)165{166return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));167}168169/*170* this routine is used for miscellaneous IP-like checksums, mainly171* in icmp.c172*/173174static inline unsigned short ip_compute_csum(const void *buff, int len)175{176return csum_fold(csum_partial(buff, len, 0));177}178179#define _HAVE_ARCH_IPV6_CSUM180static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,181const struct in6_addr *daddr,182__u32 len, unsigned short proto,183__wsum sum)184{185__asm__ __volatile__(186".set\tnoreorder\t\t\t# csum_ipv6_magic\n\t"187".set\tnoat\n\t"188"addu\t%0, %5\t\t\t# proto (long in network byte order)\n\t"189"sltu\t$1, %0, %5\n\t"190"addu\t%0, $1\n\t"191"addu\t%0, %6\t\t\t# csum\n\t"192"sltu\t$1, %0, %6\n\t"193"lw\t%1, 0(%2)\t\t\t# four words source address\n\t"194"addu\t%0, $1\n\t"195"addu\t%0, %1\n\t"196"sltu\t$1, %0, %1\n\t"197"lw\t%1, 4(%2)\n\t"198"addu\t%0, $1\n\t"199"addu\t%0, %1\n\t"200"sltu\t$1, %0, %1\n\t"201"lw\t%1, 8(%2)\n\t"202"addu\t%0, $1\n\t"203"addu\t%0, %1\n\t"204"sltu\t$1, %0, %1\n\t"205"lw\t%1, 12(%2)\n\t"206"addu\t%0, $1\n\t"207"addu\t%0, %1\n\t"208"sltu\t$1, %0, %1\n\t"209"lw\t%1, 0(%3)\n\t"210"addu\t%0, $1\n\t"211"addu\t%0, %1\n\t"212"sltu\t$1, %0, %1\n\t"213"lw\t%1, 4(%3)\n\t"214"addu\t%0, $1\n\t"215"addu\t%0, %1\n\t"216"sltu\t$1, %0, %1\n\t"217"lw\t%1, 8(%3)\n\t"218"addu\t%0, $1\n\t"219"addu\t%0, %1\n\t"220"sltu\t$1, %0, %1\n\t"221"lw\t%1, 12(%3)\n\t"222"addu\t%0, $1\n\t"223"addu\t%0, %1\n\t"224"sltu\t$1, %0, %1\n\t"225"addu\t%0, $1\t\t\t# Add final carry\n\t"226".set\tnoat\n\t"227".set\tnoreorder"228: "=r" (sum), "=r" (proto)229: "r" (saddr), "r" (daddr),230"0" (htonl(len)), "1" (htonl(proto)), "r" (sum));231232return csum_fold(sum);233}234#endif /* _ASM_SCORE_CHECKSUM_H */235236237