~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/include/asm-sparc64/checksum.h

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* $Id: checksum.h,v 1.16 2000/01/31 01:26:54 davem Exp $ */
  2 #ifndef __SPARC64_CHECKSUM_H
  3 #define __SPARC64_CHECKSUM_H
  4 
  5 /*  checksum.h:  IP/UDP/TCP checksum routines on the V9.
  6  *
  7  *  Copyright(C) 1995 Linus Torvalds
  8  *  Copyright(C) 1995 Miguel de Icaza
  9  *  Copyright(C) 1996 David S. Miller
 10  *  Copyright(C) 1996 Eddie C. Dost
 11  *  Copyright(C) 1997 Jakub Jelinek
 12  *
 13  * derived from:
 14  *      Alpha checksum c-code
 15  *      ix86 inline assembly
 16  *      RFC1071 Computing the Internet Checksum
 17  */
 18 
 19 #include <asm/uaccess.h> 
 20 
 21 /* computes the checksum of a memory block at buff, length len,
 22  * and adds in "sum" (32-bit)
 23  *
 24  * returns a 32-bit number suitable for feeding into itself
 25  * or csum_tcpudp_magic
 26  *
 27  * this function must be called with even lengths, except
 28  * for the last fragment, which may be odd
 29  *
 30  * it's best to have buff aligned on a 32-bit boundary
 31  */
 32 extern unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
 33 
 34 /* the same as csum_partial, but copies from user space while it
 35  * checksums
 36  *
 37  * here even more important to align src and dst on a 32-bit (or even
 38  * better 64-bit) boundary
 39  */
 40 extern unsigned int csum_partial_copy_sparc64(const char *src, char *dst, int len, unsigned int sum);
 41                         
 42 extern __inline__ unsigned int 
 43 csum_partial_copy_nocheck (const char *src, char *dst, int len, 
 44                            unsigned int sum)
 45 {
 46         int ret;
 47         unsigned char cur_ds = current->thread.current_ds.seg;
 48         __asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "i" (ASI_P));
 49         ret = csum_partial_copy_sparc64(src, dst, len, sum);
 50         __asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "r" (cur_ds));
 51         return ret;
 52 }
 53 
 54 extern __inline__ unsigned int 
 55 csum_partial_copy_from_user(const char *src, char *dst, int len, 
 56                             unsigned int sum, int *err)
 57 {
 58         __asm__ __volatile__ ("stx      %0, [%%sp + 0x7ff + 128]"
 59                               : : "r" (err));
 60         return csum_partial_copy_sparc64(src, dst, len, sum);
 61 }
 62 
 63 /* 
 64  *      Copy and checksum to user
 65  */
 66 #define HAVE_CSUM_COPY_USER
 67 extern unsigned int csum_partial_copy_user_sparc64(const char *src, char *dst, int len, unsigned int sum);
 68 extern __inline__ unsigned int 
 69 csum_and_copy_to_user(const char *src, char *dst, int len, 
 70                       unsigned int sum, int *err)
 71 {
 72         __asm__ __volatile__ ("stx      %0, [%%sp + 0x7ff + 128]"
 73                               : : "r" (err));
 74         return csum_partial_copy_user_sparc64(src, dst, len, sum);
 75 }
 76   
 77 /* ihl is always 5 or greater, almost always is 5, and iph is word aligned
 78  * the majority of the time.
 79  */
 80 extern __inline__ unsigned short ip_fast_csum(__const__ unsigned char *iph,
 81                                               unsigned int ihl)
 82 {
 83         unsigned short sum;
 84 
 85         /* Note: We must read %2 before we touch %0 for the first time,
 86          *       because GCC can legitimately use the same register for
 87          *       both operands.
 88          */
 89         __asm__ __volatile__("
 90         sub             %2, 4, %%g7             ! IEU0
 91         lduw            [%1 + 0x00], %0         ! Load  Group
 92         lduw            [%1 + 0x04], %%g2       ! Load  Group
 93         lduw            [%1 + 0x08], %%g3       ! Load  Group
 94         addcc           %%g2, %0, %0            ! IEU1  1 Load Bubble + Group
 95         lduw            [%1 + 0x0c], %%g2       ! Load
 96         addccc          %%g3, %0, %0            ! Sngle Group no Bubble
 97         lduw            [%1 + 0x10], %%g3       ! Load  Group
 98         addccc          %%g2, %0, %0            ! Sngle Group no Bubble
 99         addc            %0, %%g0, %0            ! Sngle Group
100 1:      addcc           %%g3, %0, %0            ! IEU1  Group no Bubble
101         add             %1, 4, %1               ! IEU0
102         addccc          %0, %%g0, %0            ! Sngle Group no Bubble
103         subcc           %%g7, 1, %%g7           ! IEU1  Group
104         be,a,pt         %%icc, 2f               ! CTI
105          sll            %0, 16, %%g2            ! IEU0
106         lduw            [%1 + 0x10], %%g3       ! Load  Group
107         ba,pt           %%xcc, 1b               ! CTI
108          nop                                    ! IEU0
109 2:      addcc           %0, %%g2, %%g2          ! IEU1  Group
110         srl             %%g2, 16, %0            ! IEU0  Group regdep    XXX Scheisse!
111         addc            %0, %%g0, %0            ! Sngle Group
112         xnor            %%g0, %0, %0            ! IEU0  Group
113         srl             %0, 0, %0               ! IEU0  Group           XXX Scheisse!
114 "       : "=r" (sum), "=&r" (iph)
115         : "r" (ihl), "1" (iph)
116         : "g2", "g3", "g7", "cc");
117         return sum;
118 }
119 
120 /* Fold a partial checksum without adding pseudo headers. */
121 extern __inline__ unsigned short csum_fold(unsigned int sum)
122 {
123         unsigned int tmp;
124 
125         __asm__ __volatile__("
126         addcc           %0, %1, %1
127         srl             %1, 16, %1
128         addc            %1, %%g0, %1
129         xnor            %%g0, %1, %0
130 "       : "=&r" (sum), "=r" (tmp)
131         : "" (sum), "1" (sum<<16)
132         : "cc");
133         return (sum & 0xffff);
134 }
135 
136 extern __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr,
137                                                    unsigned long daddr,
138                                                    unsigned int len,
139                                                    unsigned short proto,
140                                                    unsigned int sum)
141 {
142         __asm__ __volatile__("
143         addcc           %1, %0, %0
144         addccc          %2, %0, %0
145         addccc          %3, %0, %0
146         addc            %0, %%g0, %0
147 "       : "=r" (sum), "=r" (saddr)
148         : "r" (daddr), "r" ((proto<<16)+len), "" (sum), "1" (saddr)
149         : "cc");
150         return sum;
151 }
152 
153 /*
154  * computes the checksum of the TCP/UDP pseudo-header
155  * returns a 16-bit checksum, already complemented
156  */
157 static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
158                                                    unsigned long daddr,
159                                                    unsigned short len,
160                                                    unsigned short proto,
161                                                    unsigned int sum) 
162 {
163         return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
164 }
165 
166 #define _HAVE_ARCH_IPV6_CSUM
167 
168 static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
169                                                      struct in6_addr *daddr,
170                                                      __u32 len,
171                                                      unsigned short proto,
172                                                      unsigned int sum) 
173 {
174         __asm__ __volatile__ ("
175         addcc           %3, %4, %%g7
176         addccc          %5, %%g7, %%g7
177         lduw            [%2 + 0x0c], %%g2
178         lduw            [%2 + 0x08], %%g3
179         addccc          %%g2, %%g7, %%g7
180         lduw            [%2 + 0x04], %%g2
181         addccc          %%g3, %%g7, %%g7
182         lduw            [%2 + 0x00], %%g3
183         addccc          %%g2, %%g7, %%g7
184         lduw            [%1 + 0x0c], %%g2
185         addccc          %%g3, %%g7, %%g7
186         lduw            [%1 + 0x08], %%g3
187         addccc          %%g2, %%g7, %%g7
188         lduw            [%1 + 0x04], %%g2
189         addccc          %%g3, %%g7, %%g7
190         lduw            [%1 + 0x00], %%g3
191         addccc          %%g2, %%g7, %%g7
192         addccc          %%g3, %%g7, %0
193         addc            0, %0, %0
194 "       : "=&r" (sum)
195         : "r" (saddr), "r" (daddr), "r"(htonl(len)),
196           "r"(htonl(proto)), "r"(sum)
197         : "g2", "g3", "g7", "cc");
198 
199         return csum_fold(sum);
200 }
201 
202 /* this routine is used for miscellaneous IP-like checksums, mainly in icmp.c */
203 extern __inline__ unsigned short ip_compute_csum(unsigned char * buff, int len)
204 {
205         return csum_fold(csum_partial(buff, len, 0));
206 }
207 
208 #endif /* !(__SPARC64_CHECKSUM_H) */
209 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.