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.
13 * Alpha checksum c-code
14 * ix86 inline assembly
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
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
,
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
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 */
82 " nor %0, %0, %0\n" /* negate */
83 : "=&r" (sum
), "=&r" (saddr
)
84 : "0" (sum
), "1" (saddr
), "r" (ntohl(len
+proto
)), "r" (daddr
)
86 return ((unsigned short) sum
);
91 /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
94 extern inline unsigned short from32to16(unsigned long x
)
99 "cmpltu r15, %0, %1\n"
103 : "r" (x
<< 16), "0" (x
)
110 /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
113 extern inline unsigned long do_csum(const unsigned char * buff
, int len
)
116 unsigned long result
= 0;
121 odd
= 1 & (unsigned long) buff
;
123 ////result = *buff; // dgt: Big endian
124 result
= *buff
<< 8; // dgt: Little endian
129 count
= len
>> 1; /* nr of 16-bit words.. */
131 if (2 & (unsigned long) buff
) {
132 result
+= *(unsigned short *) buff
;
137 count
>>= 1; /* nr of 32-bit words.. */
139 unsigned long carry
= 0;
141 unsigned long w
= *(unsigned long *) buff
;
146 carry
= (w
> result
);
149 result
= (result
& 0xffff) + (result
>> 16);
152 result
+= *(unsigned short *) buff
;
157 result
+= *buff
; /* This is little machine, byte is right */
158 result
= from32to16(result
);
160 result
= ((result
>> 8) & 0xff) | ((result
& 0xff) << 8);
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
)
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 */
189 " addi %1, %1, 4\n" /* Bump ptr a long word */
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 */
209 " cmpltu r8, %0, %2\n"
213 : "=&r" (sum
), "=&r" (iph
), "=&r" (ihl
)
214 : "1" (iph
), "2" (ihl
)
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
)
236 if (csum_err
) *csum_err
= 0;
237 memcpy(dst
, src
, len
);
238 return csum_partial(dst
, len
, sum
);
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
251 extern inline unsigned short ip_compute_csum(unsigned char * buff
, int len
)
254 return ~from32to16(do_csum(buff
,len
));
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
)
275 __asm__
__volatile__(
277 "cmpltu r8, %0, %1\n"
282 : "r" (sum
<< 16), "0" (sum
)
289 /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
292 extern __inline__
unsigned long csum_tcpudp_nofold(unsigned long saddr
,
295 unsigned short proto
,
299 __asm__
__volatile__(
301 "cmpltu r8, %0, %1\n"
302 "add %0, %0, r8\n" /* add carry */
304 "cmpltu r8, %0, %2\n"
305 "add %0, %0, r8\n" /* add carry */
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) ),
320 #endif /* (__NIOS2_CHECKSUM_H) */