Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / include / asm-mips / checksum.h
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 1995, 96, 97, 98, 99, 2001 by Ralf Baechle
7  * Copyright (C) 1999 Silicon Graphics, Inc.
8  * Copyright (C) 2001 Thiemo Seufer.
9  * Copyright (C) 2002 Maciej W. Rozycki
10  */
11 #ifndef _ASM_CHECKSUM_H
12 #define _ASM_CHECKSUM_H
13
14 #include <linux/config.h>
15 #include <linux/in6.h>
16
17 #include <asm/uaccess.h>
18
19 /*
20  * computes the checksum of a memory block at buff, length len,
21  * and adds in "sum" (32-bit)
22  *
23  * returns a 32-bit number suitable for feeding into itself
24  * or csum_tcpudp_magic
25  *
26  * this function must be called with even lengths, except
27  * for the last fragment, which may be odd
28  *
29  * it's best to have buff aligned on a 32-bit boundary
30  */
31 unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum);
32
33 /*
34  * this is a new version of the above that records errors it finds in *errp,
35  * but continues and zeros the rest of the buffer.
36  */
37 unsigned int csum_partial_copy_from_user(const unsigned char __user *src,
38                                          unsigned char *dst, int len,
39                                          unsigned int sum, int *errp);
40
41 /*
42  * Copy and checksum to user
43  */
44 #define HAVE_CSUM_COPY_USER
45 static inline unsigned int csum_and_copy_to_user (const unsigned char *src,
46                                                   unsigned char __user *dst,
47                                                   int len, int sum,
48                                                   int *err_ptr)
49 {
50         might_sleep();
51         sum = csum_partial(src, len, sum);
52
53         if (copy_to_user(dst, src, len)) {
54                 *err_ptr = -EFAULT;
55                 return -1;
56         }
57
58         return sum;
59 }
60
61 /*
62  * the same as csum_partial, but copies from user space (but on MIPS
63  * we have just one address space, so this is identical to the above)
64  */
65 unsigned int csum_partial_copy_nocheck(const unsigned char *src, unsigned char *dst,
66                                        int len, unsigned int sum);
67
68 /*
69  *      Fold a partial checksum without adding pseudo headers
70  */
71 static inline unsigned short int csum_fold(unsigned int sum)
72 {
73         __asm__(
74         "       .set    push            # csum_fold\n"
75         "       .set    noat            \n"
76         "       sll     $1, %0, 16      \n"
77         "       addu    %0, $1          \n"
78         "       sltu    $1, %0, $1      \n"
79         "       srl     %0, %0, 16      \n"
80         "       addu    %0, $1          \n"
81         "       xori    %0, 0xffff      \n"
82         "       .set    pop"
83         : "=r" (sum)
84         : "0" (sum));
85
86         return sum;
87 }
88
89 /*
90  *      This is a version of ip_compute_csum() optimized for IP headers,
91  *      which always checksum on 4 octet boundaries.
92  *
93  *      By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
94  *      Arnt Gulbrandsen.
95  */
96 static inline unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl)
97 {
98         unsigned int *word = (unsigned int *) iph;
99         unsigned int *stop = word + ihl;
100         unsigned int csum;
101         int carry;
102
103         csum = word[0];
104         csum += word[1];
105         carry = (csum < word[1]);
106         csum += carry;
107
108         csum += word[2];
109         carry = (csum < word[2]);
110         csum += carry;
111
112         csum += word[3];
113         carry = (csum < word[3]);
114         csum += carry;
115
116         word += 4;
117         do {
118                 csum += *word;
119                 carry = (csum < *word);
120                 csum += carry;
121                 word++;
122         } while (word != stop);
123
124         return csum_fold(csum);
125 }
126
127 static inline unsigned int csum_tcpudp_nofold(unsigned long saddr,
128         unsigned long daddr, unsigned short len, unsigned short proto,
129         unsigned int sum)
130 {
131         __asm__(
132         "       .set    push            # csum_tcpudp_nofold\n"
133         "       .set    noat            \n"
134 #ifdef CONFIG_32BIT
135         "       addu    %0, %2          \n"
136         "       sltu    $1, %0, %2      \n"
137         "       addu    %0, $1          \n"
138
139         "       addu    %0, %3          \n"
140         "       sltu    $1, %0, %3      \n"
141         "       addu    %0, $1          \n"
142
143         "       addu    %0, %4          \n"
144         "       sltu    $1, %0, %4      \n"
145         "       addu    %0, $1          \n"
146 #endif
147 #ifdef CONFIG_64BIT
148         "       daddu   %0, %2          \n"
149         "       daddu   %0, %3          \n"
150         "       daddu   %0, %4          \n"
151         "       dsll32  $1, %0, 0       \n"
152         "       daddu   %0, $1          \n"
153         "       dsra32  %0, %0, 0       \n"
154 #endif
155         "       .set    pop"
156         : "=r" (sum)
157         : "0" (daddr), "r"(saddr),
158 #ifdef __MIPSEL__
159           "r" (((unsigned long)htons(len)<<16) + proto*256),
160 #else
161           "r" (((unsigned long)(proto)<<16) + len),
162 #endif
163           "r" (sum));
164
165         return sum;
166 }
167
168 /*
169  * computes the checksum of the TCP/UDP pseudo-header
170  * returns a 16-bit checksum, already complemented
171  */
172 static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
173                                                    unsigned long daddr,
174                                                    unsigned short len,
175                                                    unsigned short proto,
176                                                    unsigned int sum)
177 {
178         return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
179 }
180
181 /*
182  * this routine is used for miscellaneous IP-like checksums, mainly
183  * in icmp.c
184  */
185 static inline unsigned short ip_compute_csum(unsigned char * buff, int len)
186 {
187         return csum_fold(csum_partial(buff, len, 0));
188 }
189
190 #define _HAVE_ARCH_IPV6_CSUM
191 static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
192                                                      struct in6_addr *daddr,
193                                                      __u32 len,
194                                                      unsigned short proto,
195                                                      unsigned int sum)
196 {
197         __asm__(
198         "       .set    push            # csum_ipv6_magic\n"
199         "       .set    noreorder       \n"
200         "       .set    noat            \n"
201         "       addu    %0, %5          # proto (long in network byte order)\n"
202         "       sltu    $1, %0, %5      \n"
203         "       addu    %0, $1          \n"
204
205         "       addu    %0, %6          # csum\n"
206         "       sltu    $1, %0, %6      \n"
207         "       lw      %1, 0(%2)       # four words source address\n"
208         "       addu    %0, $1          \n"
209         "       addu    %0, %1          \n"
210         "       sltu    $1, %0, %1      \n"
211
212         "       lw      %1, 4(%2)       \n"
213         "       addu    %0, $1          \n"
214         "       addu    %0, %1          \n"
215         "       sltu    $1, %0, %1      \n"
216
217         "       lw      %1, 8(%2)       \n"
218         "       addu    %0, $1          \n"
219         "       addu    %0, %1          \n"
220         "       sltu    $1, %0, %1      \n"
221
222         "       lw      %1, 12(%2)      \n"
223         "       addu    %0, $1          \n"
224         "       addu    %0, %1          \n"
225         "       sltu    $1, %0, %1      \n"
226
227         "       lw      %1, 0(%3)       \n"
228         "       addu    %0, $1          \n"
229         "       addu    %0, %1          \n"
230         "       sltu    $1, %0, %1      \n"
231
232         "       lw      %1, 4(%3)       \n"
233         "       addu    %0, $1          \n"
234         "       addu    %0, %1          \n"
235         "       sltu    $1, %0, %1      \n"
236
237         "       lw      %1, 8(%3)       \n"
238         "       addu    %0, $1          \n"
239         "       addu    %0, %1          \n"
240         "       sltu    $1, %0, %1      \n"
241
242         "       lw      %1, 12(%3)      \n"
243         "       addu    %0, $1          \n"
244         "       addu    %0, %1          \n"
245         "       sltu    $1, %0, %1      \n"
246
247         "       addu    %0, $1          # Add final carry\n"
248         "       .set    pop"
249         : "=r" (sum), "=r" (proto)
250         : "r" (saddr), "r" (daddr),
251           "0" (htonl(len)), "1" (htonl(proto)), "r" (sum));
252
253         return csum_fold(sum);
254 }
255
256 #endif /* _ASM_CHECKSUM_H */