1/* checksum.h: FRV checksumming 2 * 3 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12#ifndef _ASM_CHECKSUM_H 13#define _ASM_CHECKSUM_H 14 15#include <linux/in6.h> 16 17/* 18 * computes the checksum of a memory block at buff, length len, 19 * and adds in "sum" (32-bit) 20 * 21 * returns a 32-bit number suitable for feeding into itself 22 * or csum_tcpudp_magic 23 * 24 * this function must be called with even lengths, except 25 * for the last fragment, which may be odd 26 * 27 * it's best to have buff aligned on a 32-bit boundary 28 */ 29__wsum csum_partial(const void *buff, int len, __wsum sum); 30 31/* 32 * the same as csum_partial, but copies from src while it 33 * checksums 34 * 35 * here even more important to align src and dst on a 32-bit (or even 36 * better 64-bit) boundary 37 */ 38__wsum csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum); 39 40/* 41 * the same as csum_partial_copy, but copies from user space. 42 * 43 * here even more important to align src and dst on a 32-bit (or even 44 * better 64-bit) boundary 45 */ 46extern __wsum csum_partial_copy_from_user(const void __user *src, void *dst, 47 int len, __wsum sum, int *csum_err); 48 49/* 50 * This is a version of ip_compute_csum() optimized for IP headers, 51 * which always checksum on 4 octet boundaries. 52 * 53 */ 54static inline 55__sum16 ip_fast_csum(const void *iph, unsigned int ihl) 56{ 57 unsigned int tmp, inc, sum = 0; 58 59 asm(" addcc gr0,gr0,gr0,icc0\n" /* clear icc0.C */ 60 " subi %1,#4,%1 \n" 61 "0: \n" 62 " ldu.p @(%1,%3),%4 \n" 63 " subicc %2,#1,%2,icc1 \n" 64 " addxcc.p %4,%0,%0,icc0 \n" 65 " bhi icc1,#2,0b \n" 66 67 /* fold the 33-bit result into 16-bits */ 68 " addxcc gr0,%0,%0,icc0 \n" 69 " srli %0,#16,%1 \n" 70 " sethi #0,%0 \n" 71 " add %1,%0,%0 \n" 72 " srli %0,#16,%1 \n" 73 " add %1,%0,%0 \n" 74 75 : "=r" (sum), "=r" (iph), "=r" (ihl), "=r" (inc), "=&r"(tmp) 76 : "0" (sum), "1" (iph), "2" (ihl), "3" (4), 77 "m"(*(volatile struct { int _[100]; } *)iph) 78 : "icc0", "icc1", "memory" 79 ); 80 81 return (__force __sum16)~sum; 82} 83 84/* 85 * Fold a partial checksum 86 */ 87static inline __sum16 csum_fold(__wsum sum) 88{ 89 unsigned int tmp; 90 91 asm(" srli %0,#16,%1 \n" 92 " sethi #0,%0 \n" 93 " add %1,%0,%0 \n" 94 " srli %0,#16,%1 \n" 95 " add %1,%0,%0 \n" 96 : "=r"(sum), "=&r"(tmp) 97 : "0"(sum) 98 ); 99 100 return (__force __sum16)~sum; 101} 102 103/* 104 * computes the checksum of the TCP/UDP pseudo-header 105 * returns a 16-bit checksum, already complemented 106 */ 107static inline __wsum 108csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len, 109 unsigned short proto, __wsum sum) 110{ 111 asm(" addcc %1,%0,%0,icc0 \n" 112 " addxcc %2,%0,%0,icc0 \n" 113 " addxcc %3,%0,%0,icc0 \n" 114 " addxcc gr0,%0,%0,icc0 \n" 115 : "=r" (sum) 116 : "r" (daddr), "r" (saddr), "r" (len + proto), "0"(sum) 117 : "icc0" 118 ); 119 return sum; 120} 121 122static inline __sum16 123csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len, 124 unsigned short proto, __wsum sum) 125{ 126 return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); 127} 128 129/* 130 * this routine is used for miscellaneous IP-like checksums, mainly 131 * in icmp.c 132 */ 133extern __sum16 ip_compute_csum(const void *buff, int len); 134 135#define _HAVE_ARCH_IPV6_CSUM 136static inline __sum16 137csum_ipv6_magic(const struct in6_addr *saddr, const struct in6_addr *daddr, 138 __u32 len, unsigned short proto, __wsum sum) 139{ 140 unsigned long tmp, tmp2; 141 142 asm(" addcc %2,%0,%0,icc0 \n" 143 144 /* add up the source addr */ 145 " ldi @(%3,0),%1 \n" 146 " addxcc %1,%0,%0,icc0 \n" 147 " ldi @(%3,4),%2 \n" 148 " addxcc %2,%0,%0,icc0 \n" 149 " ldi @(%3,8),%1 \n" 150 " addxcc %1,%0,%0,icc0 \n" 151 " ldi @(%3,12),%2 \n" 152 " addxcc %2,%0,%0,icc0 \n" 153 154 /* add up the dest addr */ 155 " ldi @(%4,0),%1 \n" 156 " addxcc %1,%0,%0,icc0 \n" 157 " ldi @(%4,4),%2 \n" 158 " addxcc %2,%0,%0,icc0 \n" 159 " ldi @(%4,8),%1 \n" 160 " addxcc %1,%0,%0,icc0 \n" 161 " ldi @(%4,12),%2 \n" 162 " addxcc %2,%0,%0,icc0 \n" 163 164 /* fold the 33-bit result into 16-bits */ 165 " addxcc gr0,%0,%0,icc0 \n" 166 " srli %0,#16,%1 \n" 167 " sethi #0,%0 \n" 168 " add %1,%0,%0 \n" 169 " srli %0,#16,%1 \n" 170 " add %1,%0,%0 \n" 171 172 : "=r" (sum), "=&r" (tmp), "=r" (tmp2) 173 : "r" (saddr), "r" (daddr), "0" (sum), "2" (len + proto) 174 : "icc0" 175 ); 176 177 return (__force __sum16)~sum; 178} 179 180#endif /* _ASM_CHECKSUM_H */ 181