[PATCH] x86_64 merge: arch + asm
[opensuse:kernel.git] / include / asm-x86_64 / checksum.h
1 #ifndef _X86_64_CHECKSUM_H
2 #define _X86_64_CHECKSUM_H
3
4
5 /*
6  *      This is a version of ip_compute_csum() optimized for IP headers,
7  *      which always checksum on 4 octet boundaries.
8  *
9  *      By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
10  *      Arnt Gulbrandsen.
11  */
12 static inline unsigned short ip_fast_csum(unsigned char * iph,
13                                           unsigned int ihl) {
14         unsigned int sum;
15
16         __asm__ __volatile__(
17 "\n         movl (%1), %0"
18 "\n         subl $4, %2"
19 "\n         jbe 2f"
20 "\n         addl 4(%1), %0"
21 "\n         adcl 8(%1), %0"
22 "\n         adcl 12(%1), %0"
23 "\n1:       adcl 16(%1), %0"
24 "\n         lea 4(%1), %1"
25 "\n         decl %2"
26 "\n         jne 1b"
27 "\n         adcl $0, %0"
28 "\n         movl %0, %2"
29 "\n         shrl $16, %0"
30 "\n         addw %w2, %w0"
31 "\n         adcl $0, %0"
32 "\n         notl %0"
33 "\n2:"
34         /* Since the input registers which are loaded with iph and ipl
35            are modified, we must also specify them as outputs, or gcc
36            will assume they contain their original values. */
37         : "=r" (sum), "=r" (iph), "=r" (ihl)
38         : "1" (iph), "2" (ihl));
39         return(sum);
40 }
41
42
43
44 /*
45  *      Fold a partial checksum. Note this works on a 32bit unfolded checksum. Make sure
46  *      to not mix with 64bit checksums!
47  */
48
49 static inline unsigned int csum_fold(unsigned int sum)
50 {
51         __asm__(
52 "\n             addl %1,%0"
53 "\n             adcl $0xffff,%0"
54                 : "=r" (sum)
55                 : "r" (sum << 16), "0" (sum & 0xffff0000)
56         );
57         return (~sum) >> 16;
58 }
59
60
61
62
63 static inline unsigned long csum_tcpudp_nofold(unsigned saddr,
64                                                    unsigned daddr,
65                                                    unsigned short len,
66                                                    unsigned short proto,
67                                                    unsigned int sum) 
68 {
69     __asm__(
70 "\n     addl %1, %0"
71 "\n     adcl %2, %0"
72 "\n     adcl %3, %0"
73 "\n     adcl $0, %0"
74         : "=r" (sum)
75         : "g" (daddr), "g"(saddr), "g"((ntohs(len)<<16)+proto*256), "0"(sum));
76     return sum;
77 }
78
79 /*
80  * computes the checksum of the TCP/UDP pseudo-header
81  * returns a 16-bit checksum, already complemented
82  */
83 static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
84                                                    unsigned long daddr,
85                                                    unsigned short len,
86                                                    unsigned short proto,
87                                                    unsigned int sum) 
88 {
89         return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
90 }
91
92
93 /*
94  * computes the checksum of a memory block at buff, length len,
95  * and adds in "sum" (32-bit)
96  *
97  * returns a 32-bit number suitable for feeding into itself
98  * or csum_tcpudp_magic
99  *
100  * this function must be called with even lengths, except
101  * for the last fragment, which may be odd
102  *
103  * it's best to have buff aligned on a 32-bit boundary
104  */
105 extern unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
106
107 /*
108  * the same as csum_partial, but copies from src while it
109  * checksums
110  *
111  * here even more important to align src and dst on a 32-bit (or even
112  * better 64-bit) boundary
113  */
114 unsigned int csum_partial_copy(const char *src, char *dst, int len, unsigned int sum);
115
116 /*
117  * this is a new version of the above that records errors it finds in *errp,
118  * but continues and zeros the rest of the buffer.
119  */
120 unsigned int csum_partial_copy_from_user(const char *src, char *dst, int len, unsigned int sum, int *errp);
121
122 unsigned int csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum);
123
124
125 /*
126  * this routine is used for miscellaneous IP-like checksums, mainly
127  * in icmp.c
128  */
129
130 extern unsigned short ip_compute_csum(unsigned char * buff, int len);
131
132 #define _HAVE_ARCH_IPV6_CSUM
133 static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
134                                                      struct in6_addr *daddr,
135                                                      __u32 len,
136                                                      unsigned short proto,
137                                                      unsigned int sum) 
138 {
139         __asm__(
140 "\n             addl 0(%1), %0"
141 "\n             adcl 4(%1), %0"
142 "\n             adcl 8(%1), %0"
143 "\n             adcl 12(%1), %0"
144 "\n             adcl 0(%2), %0"
145 "\n             adcl 4(%2), %0"
146 "\n             adcl 8(%2), %0"
147 "\n             adcl 12(%2), %0"
148 "\n             adcl %3, %0"
149 "\n             adcl %4, %0"
150 "\n             adcl $0, %0"
151                 : "=&r" (sum)
152                 : "r" (saddr), "r" (daddr), 
153                   "r"(htonl(len)), "r"(htonl(proto)), "0"(sum));
154
155         return csum_fold(sum);
156 }
157
158 #endif