1 #ifndef __ASM_SH64_CHECKSUM_H
2 #define __ASM_SH64_CHECKSUM_H
5 * This file is subject to the terms and conditions of the GNU General Public
6 * License. See the file "COPYING" in the main directory of this archive
9 * include/asm-sh64/checksum.h
11 * Copyright (C) 2000, 2001 Paolo Alberelli
15 #include <asm/registers.h>
18 * computes the checksum of a memory block at buff, length len,
19 * and adds in "sum" (32-bit)
21 * returns a 32-bit number suitable for feeding into itself
22 * or csum_tcpudp_magic
24 * this function must be called with even lengths, except
25 * for the last fragment, which may be odd
27 * it's best to have buff aligned on a 32-bit boundary
29 asmlinkage unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
33 * Note: when you get a NULL pointer exception here this means someone
34 * passed in an incorrect kernel address to one of these functions.
36 * If you use these functions directly please don't forget the
41 #ifdef DJM_USE_ASM_CHECKSUM
44 * the same as csum_partial, but copies from src while it
45 * checksums, and handles user-space pointer exceptions correctly, when needed.
47 * here even more important to align src and dst on a 32-bit (or even
48 * better 64-bit) boundary
51 asmlinkage unsigned int csum_partial_copy_generic( const char *src, char *dst, int len, int sum,
52 int *src_err_ptr, int *dst_err_ptr);
54 unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
57 return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
61 //#define csum_partial_copy_nocheck csum_partial_copy
64 csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum);
67 #ifdef DJM_USE_ASM_CHECKSUM
70 unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
71 int len, unsigned int sum, int *err_ptr)
73 return csum_partial_copy_generic ( src, dst, len, sum, err_ptr, NULL);
76 unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
77 int len, int sum, int *err_ptr);
83 * These are the old (and unsafe) way of doing checksums, a warning message will be
84 * printed if they are used and an exeption occurs.
86 * these functions should go away after some time.
89 #define csum_partial_copy_fromuser csum_partial_copy
91 unsigned int csum_partial_copy( const char *src, char *dst, int len, unsigned int sum);
95 * Fold a partial checksum
98 #ifdef DJM_USE_ASM_CHECKSUM
99 static __inline__ unsigned int csum_fold(unsigned int sum)
101 unsigned long long __dummy;
102 __asm__("mshflo.w r63, %0, %0\n\t"
103 "mshflo.w %0, r63, %1\n\t"
104 "mshfhi.w %0, r63, %0\n\t"
106 "shlli %0, 16, %1\n\t"
108 "sub r63, %0, %0\n\t"
110 : "=r" (sum), "=&r" (__dummy)
116 static inline unsigned short csum_fold(unsigned int sum)
119 sum = (sum & 0xffff) + (sum >> 16);
120 sum = (sum & 0xffff) + (sum >> 16);
128 #ifdef DJM_USE_ASM_CHECKSUM
130 * This is a version of ip_compute_csum() optimized for IP headers,
131 * which always checksum on 4 octet boundaries.
133 * i386 version by Jorge Cwik <jorge@laser.satlink.net>, adapted
134 * for linux by * Arnt Gulbrandsen.
136 static __inline__ unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl)
138 unsigned long long sum, __dummy0, __dummy1;
140 __asm__ __volatile__(
141 "or r63, r63, %0\n\t" /* Clear upper part */
142 "or r63, r63, %3\n\t" /* Clear upper part */
143 "gettr " __t0 ", %4\n\t" /* t0 saving */
145 /* Less waste using .UW than removing sign extension */
146 "shlli %2, 1, %2\n\t" /* Longs -> Shorts */
147 "addi %2, -2, %2\n\t" /* Last Short to start from */
148 "ldx.uw %1, %2, %0\n\t" /* Get last */
149 "addi %2, -2, %2\n\t" /* Do it reverse */
150 "_pta 4, " __t0 "\n\t"
152 "ldx.uw %1, %2, %3\n\t"
153 "add %0, %3, %0\n\t" /* Do the sum */
154 "shlri %0, 16, %3\n\t"
155 "add %0, %3, %0\n\t" /* Fold it now */
156 "shlli %3, 16, %3\n\t"
157 "sub %0, %3, %0\n\t" /* Remove carry, if any */
158 "addi %2, -2, %2\n\t" /* Do it reverse */
159 "bnei %2, -2, " __t0 "\n\t"
161 "shlli %0, 48, %0\n\t" /* Not sure this is required */
162 "sub r63, %0, %0\n\t" /* Not */
163 "shlri %0, 48, %0\n\t" /* Not sure this is required */
164 "ptabs %4, " __t0 "\n\t"
166 : "=r" (sum), "=r" (iph), "=r" (ihl), "=r" (__dummy0), "=r" (__dummy1)
167 : "1" (iph), "2" (ihl));
169 return (unsigned short) sum;
172 unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl);
177 #ifdef DJM_USE_ASM_CHECKSUM
179 static __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr,
182 unsigned short proto,
185 #ifdef __LITTLE_ENDIAN__
186 unsigned long len_proto = (ntohs(len)<<16)+proto*256;
188 unsigned long len_proto = (proto<<16)+len;
190 __asm__("add %0, %1, %0\n\t"
193 "shlri %0, 32, %1\n\t"
194 "add %0, %1, %0\n\t" /* Fold it to a long */
195 "shlli %1, 32, %1\n\t"
196 "sub %0, %1, %0\n\t" /* Remove carry, if any */
197 : "=r" (sum), "=r" (len_proto)
198 : "r" (daddr), "r" (saddr), "1" (len_proto), "0" (sum));
203 unsigned long csum_tcpudp_nofold(unsigned long saddr,
206 unsigned short proto,
212 * computes the checksum of the TCP/UDP pseudo-header
213 * returns a 16-bit checksum, already complemented
215 static __inline__ unsigned short int csum_tcpudp_magic(unsigned long saddr,
218 unsigned short proto,
222 unsigned short int x;
223 //printk("csum_tcpudp_magic saddr %08x daddr %08x len %04x proto %04x sum %08x\n",
224 // saddr,daddr,len,proto,sum);
225 x = csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
226 //printk("csum_tcpudp_magic returning %04x\n", x);
231 * this routine is used for miscellaneous IP-like checksums, mainly
235 static __inline__ unsigned short ip_compute_csum(unsigned char * buff, int len)
238 return csum_fold (csum_partial(buff, len, 0));
242 #ifdef DJM_USE_ASM_CHECKSUM
243 #define _HAVE_ARCH_IPV6_CSUM
244 static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
245 struct in6_addr *daddr,
247 unsigned short proto,
250 unsigned int __dummy;
252 __asm__("ld.l %2, 0, %1\n\t"
258 "ld.l %2, 12, %1\n\t"
266 "ld.l %3, 12, %1\n\t"
270 "shlri %0, 32, %1\n\t"
271 "add %0, %1, %0\n\t" /* Fold it to a long */
272 "shlli %1, 32, %1\n\t"
273 "sub %0, %1, %0\n\t" /* Remove carry, if any */
274 : "=r" (sum), "=&r" (__dummy)
275 : "r" (saddr), "r" (daddr),
276 "r" (htonl(len)), "r" (htonl(proto)), "0" (sum));
278 return csum_fold(sum);
283 #ifdef DJM_USE_ASM_CHECKSUM
285 * Copy and checksum to user
289 #define HAVE_CSUM_COPY_USER
290 static __inline__ unsigned int csum_and_copy_to_user (const char *src, char *dst,
291 int len, int sum, int *err_ptr)
293 if (access_ok(VERIFY_WRITE, dst, len))
294 return csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr);
299 return -1; /* invalid checksum */
305 #endif /* __ASM_SH64_CHECKSUM_H */