MOXA linux-2.6.x / linux-2.6.19-uc1 from UC-7110-LX-BOOTLOADER-1.9_VERSION-4.2.tgz
[linux-2.6.19-moxart.git] / include / asm-nios2nommu / checksum.h
blob1f6879e5177a60a043b5cefae76cca5d10814bb3
1 #ifndef __NIOS2_CHECKSUM_H
2 #define __NIOS2_CHECKSUM_H
4 /* checksum.h: IP/UDP/TCP checksum routines on the NIOS.
6 * Copyright(C) 1995 Linus Torvalds
7 * Copyright(C) 1995 Miguel de Icaza
8 * Copyright(C) 1996 David S. Miller
9 * Copyright(C) 2001 Ken Hill
10 * Copyright(C) 2004 Microtronix Datacom Ltd.
12 * derived from:
13 * Alpha checksum c-code
14 * ix86 inline assembly
15 * Spar nommu
17 * All rights reserved.
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
24 * This program is distributed in the hope that it will be useful, but
25 * WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
27 * NON INFRINGEMENT. See the GNU General Public License for more
28 * details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
37 /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
40 * computes the checksum of the TCP/UDP pseudo-header
41 * returns a 16-bit checksum, already complemented
44 extern inline unsigned short csum_tcpudp_magic(unsigned long saddr,
45 unsigned long daddr,
46 unsigned short len,
47 unsigned short proto,
48 unsigned int sum)
50 barrier();
51 __asm__ __volatile__(
52 " add %0, %3, %0\n"
53 " bgeu %0, %3, 1f\n"
54 " addi %0, %0, 1\n"
55 "1: add %0, %4, %0\n"
56 " bgeu %0, %4, 1f\n"
57 " addi %0, %0, 1\n"
58 "1: add %0, %5, %0\n"
59 " bgeu %0, %5, 1f\n"
60 " addi %0, %0, 1\n"
61 "1:\n"
63 We need the carry from the addition of 16-bit
64 significant addition, so we zap out the low bits
65 in one half, zap out the high bits in another,
66 shift them both up to the top 16-bits of a word
67 and do the carry producing addition, finally
68 shift the result back down to the low 16-bits.
70 Actually, we can further optimize away two shifts
71 because we know the low bits of the original
72 value will be added to zero-only bits so cannot
73 affect the addition result nor the final carry
74 bit.
76 " slli %1,%0, 16\n" /* Need a copy to fold with */
77 /* Bring the LOW 16 bits up */
78 " add %0, %1, %0\n" /* add and set carry, neat eh? */
79 " cmpltu r15, %0, %1\n" /* get remaining carry bit */
80 " srli %0, %0, 16\n" /* shift back down the result */
81 " add %0, %0, r15\n"
82 " nor %0, %0, %0\n" /* negate */
83 : "=&r" (sum), "=&r" (saddr)
84 : "0" (sum), "1" (saddr), "r" (ntohl(len+proto)), "r" (daddr)
85 : "r15");
86 return ((unsigned short) sum);
87 barrier();
91 /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
94 extern inline unsigned short from32to16(unsigned long x)
96 barrier();
97 __asm__ __volatile__(
98 "add %0, %1, %0\n"
99 "cmpltu r15, %0, %1\n"
100 "srli %0, %0, 16\n"
101 "add %0, %0, r15\n"
102 : "=r" (x)
103 : "r" (x << 16), "0" (x)
104 : "r15");
105 return x;
106 barrier();
110 /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
113 extern inline unsigned long do_csum(const unsigned char * buff, int len)
115 int odd, count;
116 unsigned long result = 0;
118 barrier();
119 if (len <= 0)
120 goto out;
121 odd = 1 & (unsigned long) buff;
122 if (odd) {
123 ////result = *buff; // dgt: Big endian
124 result = *buff << 8; // dgt: Little endian
126 len--;
127 buff++;
129 count = len >> 1; /* nr of 16-bit words.. */
130 if (count) {
131 if (2 & (unsigned long) buff) {
132 result += *(unsigned short *) buff;
133 count--;
134 len -= 2;
135 buff += 2;
137 count >>= 1; /* nr of 32-bit words.. */
138 if (count) {
139 unsigned long carry = 0;
140 do {
141 unsigned long w = *(unsigned long *) buff;
142 count--;
143 buff += 4;
144 result += carry;
145 result += w;
146 carry = (w > result);
147 } while (count);
148 result += carry;
149 result = (result & 0xffff) + (result >> 16);
151 if (len & 2) {
152 result += *(unsigned short *) buff;
153 buff += 2;
156 if (len & 1)
157 result += *buff; /* This is little machine, byte is right */
158 result = from32to16(result);
159 if (odd)
160 result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
161 out:
162 return result;
163 barrier();
167 /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
170 /* ihl is always 5 or greater, almost always is 5, iph is always word
171 * aligned but can fail to be dword aligned very often.
174 extern inline unsigned short ip_fast_csum(const unsigned char *iph, unsigned int ihl)
176 unsigned int sum;
178 barrier();
179 __asm__ __volatile__(
180 " andi r8, %1, 2\n" /* Remember original alignment */
181 " ldw %0, (%1)\n" /* 16 or 32 bit boundary */
182 " beq r8, r0, 1f\n" /* Aligned on 32 bit boundary, go */
183 " srli %0, %0, 16\n" /* Get correct 16 bits */
184 " addi %2, %2, -1\n" /* Take off for 4 bytes, pickup last 2 at end */
185 " addi %1, %1, 2\n" /* Adjust pointer to 32 bit boundary */
186 " br 2f\n"
187 "1:\n"
188 " addi %2, %2, -1\n"
189 " addi %1, %1, 4\n" /* Bump ptr a long word */
190 "2:\n"
191 " ldw r9, (%1)\n"
192 "1:\n"
193 " add %0, r9, %0\n"
194 " bgeu %0, r9, 2f\n"
195 " addi %0, %0, 1\n"
196 "2:\n"
197 " addi %1, %1, 4\n"
198 " addi %2, %2, -1\n"
199 " ldw r9, (%1)\n"
200 " bne %2, r0, 1b\n"
201 " beq r8, r0, 1f\n" /* 32 bit boundary time to leave */
202 " srli r9, r9, 16\n" /* 16 bit boundary, get correct 16 bits */
203 " add %0, r9, %0\n"
204 " bgeu %0, r9, 1f\n"
205 " addi %0, %0, 1\n"
206 "1:\n"
207 " slli %2, %0, 16\n"
208 " add %0, %2, %0\n"
209 " cmpltu r8, %0, %2\n"
210 " srli %0, %0, 16\n"
211 " add %0, %0, r8\n"
212 " nor %0, %0, %0\n"
213 : "=&r" (sum), "=&r" (iph), "=&r" (ihl)
214 : "1" (iph), "2" (ihl)
215 : "r8", "r9");
216 return sum;
217 barrier();
220 /*these 2 functions are now in checksum.c */
221 unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
222 unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum);
224 /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
227 * the same as csum_partial_copy, but copies from user space.
229 * here even more important to align src and dst on a 32-bit (or even
230 * better 64-bit) boundary
232 extern inline unsigned int
233 csum_partial_copy_from_user(const char *src, char *dst, int len, int sum, int *csum_err)
235 barrier();
236 if (csum_err) *csum_err = 0;
237 memcpy(dst, src, len);
238 return csum_partial(dst, len, sum);
239 barrier();
242 #define csum_partial_copy_nocheck(src, dst, len, sum) \
243 csum_partial_copy ((src), (dst), (len), (sum))
247 * this routine is used for miscellaneous IP-like checksums, mainly
248 * in icmp.c
251 extern inline unsigned short ip_compute_csum(unsigned char * buff, int len)
253 barrier();
254 return ~from32to16(do_csum(buff,len));
255 barrier();
259 /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
262 #define csum_partial_copy_fromuser(s, d, l, w) \
263 csum_partial_copy((char *) (s), (d), (l), (w))
266 /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
270 * Fold a partial checksum without adding pseudo headers
272 extern __inline__ unsigned int csum_fold(unsigned int sum)
274 barrier();
275 __asm__ __volatile__(
276 "add %0, %1, %0\n"
277 "cmpltu r8, %0, %1\n"
278 "srli %0, %0, 16\n"
279 "add %0, %0, r8\n"
280 "nor %0, %0, %0\n"
281 : "=r" (sum)
282 : "r" (sum << 16), "0" (sum)
283 : "r8");
284 return sum;
285 barrier();
289 /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
292 extern __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr,
293 unsigned long daddr,
294 unsigned short len,
295 unsigned short proto,
296 unsigned int sum)
298 barrier();
299 __asm__ __volatile__(
300 "add %0, %1, %0\n"
301 "cmpltu r8, %0, %1\n"
302 "add %0, %0, r8\n" /* add carry */
303 "add %0, %2, %0\n"
304 "cmpltu r8, %0, %2\n"
305 "add %0, %0, r8\n" /* add carry */
306 "add %0, %3, %0\n"
307 "cmpltu r8, %0, %3\n"
308 "add %0, %0, r8\n" /* add carry */
309 : "=r" (sum), "=r" (saddr)
310 : "r" (daddr), "r" ( (ntohs(len)<<16) + (proto*256) ),
311 "0" (sum),
312 "1" (saddr)
313 : "r8");
315 return sum;
316 barrier();
320 #endif /* (__NIOS2_CHECKSUM_H) */