special usb hub handling, IDE disks, and retries all over the place
[linux-2.4.git] / include / asm-sh64 / checksum.h
1 #ifndef __ASM_SH64_CHECKSUM_H
2 #define __ASM_SH64_CHECKSUM_H
3
4 /*
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
7  * for more details.
8  *
9  * include/asm-sh64/checksum.h
10  *
11  * Copyright (C) 2000, 2001  Paolo Alberelli
12  *
13  */
14
15 #include <asm/registers.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 asmlinkage unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
30 //x
31
32 /*
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. 
35  *      
36  *      If you use these functions directly please don't forget the 
37  *      verify_area().
38  */
39
40
41 #ifdef DJM_USE_ASM_CHECKSUM
42
43 /*
44  * the same as csum_partial, but copies from src while it
45  * checksums, and handles user-space pointer exceptions correctly, when needed.
46  *
47  * here even more important to align src and dst on a 32-bit (or even
48  * better 64-bit) boundary
49  */
50
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);
53 extern __inline__
54 unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
55                                         int len, int sum)
56 {
57         return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
58 }
59 #else
60 // Pre SIM:
61 //#define csum_partial_copy_nocheck csum_partial_copy
62 // Post SIM:
63 unsigned int
64 csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum);
65 #endif
66
67 #ifdef DJM_USE_ASM_CHECKSUM
68
69 extern __inline__
70 unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
71                                                 int len, unsigned int sum, int *err_ptr)
72 {
73         return csum_partial_copy_generic ( src, dst, len, sum, err_ptr, NULL);
74 }
75 #else 
76 unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
77                                            int len, int sum, int *err_ptr);
78 //x
79 #endif
80
81
82 /*
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.
85  *
86  * these functions should go away after some time.
87  */
88
89 #define csum_partial_copy_fromuser csum_partial_copy
90 //x
91 unsigned int csum_partial_copy( const char *src, char *dst, int len, unsigned int sum);
92 //x
93
94 /*
95  *      Fold a partial checksum
96  */
97
98 #ifdef DJM_USE_ASM_CHECKSUM
99 static __inline__ unsigned int csum_fold(unsigned int sum)
100 {
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"
105                 "add            %0, %1, %0\n\t"
106                 "shlli          %0, 16, %1\n\t"
107                 "add            %0, %1, %0\n\t"
108                 "sub            r63, %0, %0\n\t"
109                 "shlri          %0, 48, %0"
110                 : "=r" (sum), "=&r" (__dummy)
111                 : "0" (sum));
112         return sum;
113 }
114 #else
115
116 static inline unsigned short csum_fold(unsigned int sum)
117 //x
118 {
119         sum = (sum & 0xffff) + (sum >> 16);
120         sum = (sum & 0xffff) + (sum >> 16);
121         return ~(sum);
122 }
123 #endif
124
125
126
127
128 #ifdef DJM_USE_ASM_CHECKSUM
129 /*
130  *      This is a version of ip_compute_csum() optimized for IP headers,
131  *      which always checksum on 4 octet boundaries.
132  *
133  *      i386 version by Jorge Cwik <jorge@laser.satlink.net>, adapted
134  *      for linux by * Arnt Gulbrandsen.
135  */
136 static __inline__ unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl)
137 {
138         unsigned long long sum, __dummy0, __dummy1;
139
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 */
144
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"
151
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"
160
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"
165         
166         : "=r" (sum), "=r" (iph), "=r" (ihl), "=r" (__dummy0), "=r" (__dummy1)
167         : "1" (iph), "2" (ihl));
168
169         return (unsigned short) sum;
170 }
171 #else
172 unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl);
173 //x
174 #endif
175
176
177 #ifdef DJM_USE_ASM_CHECKSUM
178
179 static __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr,
180                                                    unsigned long daddr,
181                                                    unsigned short len,
182                                                    unsigned short proto,
183                                                    unsigned int sum) 
184 {
185 #ifdef __LITTLE_ENDIAN__
186         unsigned long len_proto = (ntohs(len)<<16)+proto*256;
187 #else
188         unsigned long len_proto = (proto<<16)+len;
189 #endif
190         __asm__("add    %0, %1, %0\n\t"
191                 "add    %0, %2, %0\n\t"
192                 "add    %0, %3, %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));
199
200         return sum;
201 }
202 #else
203 unsigned long csum_tcpudp_nofold(unsigned long saddr,
204                                                    unsigned long daddr,
205                                                    unsigned short len,
206                                                    unsigned short proto,
207                                  unsigned int sum) ;
208 //x
209 #endif
210
211 /*
212  * computes the checksum of the TCP/UDP pseudo-header
213  * returns a 16-bit checksum, already complemented
214  */
215 static __inline__ unsigned short int csum_tcpudp_magic(unsigned long saddr,
216                                                        unsigned long daddr,
217                                                        unsigned short len,
218                                                        unsigned short proto,
219                                                        unsigned int sum) 
220 //x
221 {
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);
227   return x;
228 }
229
230 /*
231  * this routine is used for miscellaneous IP-like checksums, mainly
232  * in icmp.c
233  */
234
235 static __inline__ unsigned short ip_compute_csum(unsigned char * buff, int len)
236 //x
237 {
238     return csum_fold (csum_partial(buff, len, 0));
239 }
240
241
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,
246                                                      __u32 len,
247                                                      unsigned short proto,
248                                                      unsigned int sum) 
249 {
250         unsigned int __dummy;
251
252         __asm__("ld.l   %2, 0, %1\n\t"
253                 "add    %0, %1, %0\n\t"
254                 "ld.l   %2, 4, %1\n\t"
255                 "add    %0, %1, %0\n\t"
256                 "ld.l   %2, 8, %1\n\t"
257                 "add    %0, %1, %0\n\t"
258                 "ld.l   %2, 12, %1\n\t"
259                 "add    %0, %1, %0\n\t"
260                 "ld.l   %3, 0, %1\n\t"
261                 "add    %0, %1, %0\n\t"
262                 "ld.l   %3, 4, %1\n\t"
263                 "add    %0, %1, %0\n\t"
264                 "ld.l   %3, 8, %1\n\t"
265                 "add    %0, %1, %0\n\t"
266                 "ld.l   %3, 12, %1\n\t"
267                 "add    %0, %1, %0\n\t"
268                 "add    %0, %4, %0\n\t"
269                 "add    %0, %5, %0\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));
277
278         return csum_fold(sum);
279 }
280 #endif
281
282
283 #ifdef DJM_USE_ASM_CHECKSUM
284 /* 
285  *      Copy and checksum to user
286  */
287
288
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)
292 {
293         if (access_ok(VERIFY_WRITE, dst, len))
294                 return csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr);
295
296         if (len)
297                 *err_ptr = -EFAULT;
298
299         return -1; /* invalid checksum */
300 }
301
302 #endif
303
304
305 #endif /* __ASM_SH64_CHECKSUM_H */
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321