0e061e1df26916b240799712fd28cfc79596f0d8
[linux-flexiantxendom0-3.2.10.git] / include / asm-mips64 / 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, 1996, 1997, 1998, 1999 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 <asm/uaccess.h>
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 unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum);
30
31 /*
32  * this is a new version of the above that records errors it finds in *errp,
33  * but continues and zeros the rest of the buffer.
34  */
35 unsigned int csum_partial_copy_from_user(const char *src, char *dst, int len,
36                                          unsigned int sum, int *errp);
37
38 /*
39  * Copy and checksum to user
40  */
41 #define HAVE_CSUM_COPY_USER
42 static inline unsigned int csum_and_copy_to_user (const char *src, char *dst,
43                                                   int len, int sum,
44                                                   int *err_ptr)
45 {
46         sum = csum_partial(src, len, sum);
47
48         if (copy_to_user(dst, src, len)) {
49                 *err_ptr = -EFAULT;
50                 return -1;
51         }
52
53         return sum;
54 }
55
56 /*
57  * the same as csum_partial, but copies from user space (but on MIPS
58  * we have just one address space, so this is identical to the above)
59  */
60 unsigned int csum_partial_copy_nocheck(const char *src, char *dst, int len,
61                                        unsigned int sum);
62
63 /*
64  *      Fold a partial checksum without adding pseudo headers
65  */
66 static inline unsigned short int csum_fold(unsigned int sum)
67 {
68         __asm__(
69         ".set\tnoat\t\t\t# csum_fold\n\t"
70         "sll\t$1,%0,16\n\t"
71         "addu\t%0,$1\n\t"
72         "sltu\t$1,%0,$1\n\t"
73         "srl\t%0,%0,16\n\t"
74         "addu\t%0,$1\n\t"
75         "xori\t%0,0xffff\n\t"
76         ".set\tat"
77         : "=r" (sum)
78         : "0" (sum));
79
80         return sum;
81 }
82
83 /*
84  *      This is a version of ip_compute_csum() optimized for IP headers,
85  *      which always checksum on 4 octet boundaries.
86  *
87  *      By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
88  *      Arnt Gulbrandsen.
89  */
90 static inline unsigned short ip_fast_csum(unsigned char *iph,
91                                           unsigned int ihl)
92 {
93         unsigned int sum;
94         unsigned long dummy;
95
96         /*
97          * This is for 32-bit processors ...  but works just fine for 64-bit
98          * processors for now ...  XXX
99          */
100         __asm__ __volatile__(
101         ".set\tnoreorder\t\t\t# ip_fast_csum\n\t"
102         ".set\tnoat\n\t"
103         "lw\t%0, (%1)\n\t"
104         "subu\t%2, 4\n\t"
105         "dsll\t%2, 2\n\t"
106         "lw\t%3, 4(%1)\n\t"
107         "daddu\t%2, %1\n\t"
108         "addu\t%0, %3\n\t"
109         "sltu\t$1, %0, %3\n\t"
110         "lw\t%3, 8(%1)\n\t"
111         "addu\t%0, $1\n\t"
112         "addu\t%0, %3\n\t"
113         "sltu\t$1, %0, %3\n\t"
114         "lw\t%3, 12(%1)\n\t"
115         "addu\t%0, $1\n\t"
116         "addu\t%0, %3\n\t"
117         "sltu\t$1, %0, %3\n\t"
118         "addu\t%0, $1\n"
119
120         "1:\tlw\t%3, 16(%1)\n\t"
121         "daddiu\t%1, 4\n"
122         "addu\t%0, %3\n\t"
123         "sltu\t$1, %0, %3\n\t"
124         "bne\t%2, %1, 1b\n\t"
125         " addu\t%0, $1\n"
126
127         "2:\t.set\tat\n\t"
128         ".set\treorder"
129         : "=&r" (sum), "=&r" (iph), "=&r" (ihl), "=&r" (dummy)
130         : "1" (iph), "2" (ihl));
131
132         return csum_fold(sum);
133 }
134
135 /*
136  * computes the checksum of the TCP/UDP pseudo-header
137  * returns a 16-bit checksum, already complemented
138  *
139  * Cast unsigned short expressions to unsigned long explicitly
140  * to avoid surprises resulting from implicit promotions to
141  * signed int.  --macro
142  */
143 static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
144                                                unsigned long daddr,
145                                                unsigned short len,
146                                                unsigned short proto,
147                                                unsigned int sum)
148 {
149         __asm__(
150         ".set\tnoat\t\t\t# csum_tcpudp_nofold\n\t"
151         "daddu\t%0, %2\n\t"
152         "daddu\t%0, %3\n\t"
153         "daddu\t%0, %4\n\t"
154         "dsll32\t$1, %0, 0\n\t"
155         "daddu\t%0, $1\n\t"
156         "dsrl32\t%0, %0, 0\n\t"
157         ".set\tat"
158         : "=&r" (sum)
159         : "0" (daddr), "r"(saddr),
160 #ifdef __MIPSEL__
161           "r" (((unsigned long)ntohs(len)<<16)+proto*256),
162 #else
163           "r" (((unsigned long)(proto)<<16)+len),
164 #endif
165           "r" (sum));
166
167         return sum;
168 }
169
170 /*
171  * computes the checksum of the TCP/UDP pseudo-header
172  * returns a 16-bit checksum, already complemented
173  */
174 static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
175                                                    unsigned long daddr,
176                                                    unsigned short len,
177                                                    unsigned short proto,
178                                                    unsigned int sum)
179 {
180         return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
181 }
182
183 /*
184  * this routine is used for miscellaneous IP-like checksums, mainly
185  * in icmp.c
186  */
187 static inline unsigned short ip_compute_csum(unsigned char * buff, int len)
188 {
189         return csum_fold(csum_partial(buff, len, 0));
190 }
191
192 #define _HAVE_ARCH_IPV6_CSUM
193 static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
194                                                      struct in6_addr *daddr,
195                                                      __u32 len,
196                                                      unsigned short proto,
197                                                      unsigned int sum)
198 {
199         __asm__(
200         ".set\tpush\t\t\t# csum_ipv6_magic\n\t"
201         ".set\tnoreorder\n\t"
202         ".set\tnoat\n\t"
203         "addu\t%0, %5\t\t\t# proto (long in network byte order)\n\t"
204         "sltu\t$1, %0, %5\n\t"
205         "addu\t%0, $1\n\t"
206
207         "addu\t%0, %6\t\t\t# csum\n\t"
208         "sltu\t$1, %0, %6\n\t"
209         "lw\t%1, 0(%2)\t\t\t# four words source address\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
214         "lw\t%1, 4(%2)\n\t"
215         "addu\t%0, $1\n\t"
216         "addu\t%0, %1\n\t"
217         "sltu\t$1, %0, %1\n\t"
218
219         "lw\t%1, 8(%2)\n\t"
220         "addu\t%0, $1\n\t"
221         "addu\t%0, %1\n\t"
222         "sltu\t$1, %0, %1\n\t"
223
224         "lw\t%1, 12(%2)\n\t"
225         "addu\t%0, $1\n\t"
226         "addu\t%0, %1\n\t"
227         "sltu\t$1, %0, %1\n\t"
228
229         "lw\t%1, 0(%3)\n\t"
230         "addu\t%0, $1\n\t"
231         "addu\t%0, %1\n\t"
232         "sltu\t$1, %0, %1\n\t"
233
234         "lw\t%1, 4(%3)\n\t"
235         "addu\t%0, $1\n\t"
236         "addu\t%0, %1\n\t"
237         "sltu\t$1, %0, %1\n\t"
238
239         "lw\t%1, 8(%3)\n\t"
240         "addu\t%0, $1\n\t"
241         "addu\t%0, %1\n\t"
242         "sltu\t$1, %0, %1\n\t"
243
244         "lw\t%1, 12(%3)\n\t"
245         "addu\t%0, $1\n\t"
246         "addu\t%0, %1\n\t"
247         "sltu\t$1, %0, %1\n\t"
248
249         "addu\t%0, $1\t\t\t# Add final carry\n\t"
250         ".set\tpop"
251         : "=&r" (sum), "=&r" (proto)
252         : "r" (saddr), "r" (daddr),
253           "0" (htonl(len)), "1" (htonl(proto)), "r" (sum));
254
255         return csum_fold(sum);
256 }
257
258 #endif /* _ASM_CHECKSUM_H */