include upstream ip1000a driver version 2.09f
[linux-2.4.git] / include / asm-s390x / checksum.h
1 #ifndef _S390_CHECKSUM_H
2 #define _S390_CHECKSUM_H
3
4 /*
5  *  include/asm-s390/checksum.h
6  *    S390 fast network checksum routines
7  *    see also arch/S390/lib/checksum.c
8  *
9  *  S390 version
10  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
11  *    Author(s): Ulrich Hild        (first version)
12  *               Martin Schwidefsky (heavily optimized CKSM version)
13  *               D.J. Barrow        (third attempt) 
14  */
15
16 #include <asm/uaccess.h>
17
18 /*
19  * computes the checksum of a memory block at buff, length len,
20  * and adds in "sum" (32-bit)
21  *
22  * returns a 32-bit number suitable for feeding into itself
23  * or csum_tcpudp_magic
24  *
25  * this function must be called with even lengths, except
26  * for the last fragment, which may be odd
27  *
28  * it's best to have buff aligned on a 32-bit boundary
29  */
30 unsigned int
31 csum_partial(const unsigned char * buff, int len, unsigned int sum);
32
33 /*
34  * csum_partial as an inline function
35  */
36 extern inline unsigned int 
37 csum_partial_inline(const unsigned char * buff, int len, unsigned int sum)
38 {
39         __asm__ __volatile__ (
40                 "    lgr  2,%1\n"    /* address in gpr 2 */
41                 "    lgfr 3,%2\n"    /* length in gpr 3 */
42                 "0:  cksm %0,2\n"    /* do checksum on longs */
43                 "    jo   0b\n"
44                 : "+&d" (sum)
45                 : "d" (buff), "d" (len)
46                 : "cc", "2", "3" );
47         return sum;
48 }
49
50 /*
51  * the same as csum_partial, but copies from src while it
52  * checksums
53  *
54  * here even more important to align src and dst on a 32-bit (or even
55  * better 64-bit) boundary
56  */
57
58 extern inline unsigned int 
59 csum_partial_copy(const char *src, char *dst, int len,unsigned int sum)
60 {
61         memcpy(dst,src,len);
62         return csum_partial_inline(dst, len, sum);
63 }
64
65 /*
66  * the same as csum_partial_copy, but copies from user space.
67  *
68  * here even more important to align src and dst on a 32-bit (or even
69  * better 64-bit) boundary
70  *
71  * Copy from userspace and compute checksum.  If we catch an exception
72  * then zero the rest of the buffer.
73  */
74 extern inline unsigned int 
75 csum_partial_copy_from_user (const char *src, char *dst,
76                                           int len, unsigned int sum,
77                                           int *err_ptr)
78 {
79         int missing;
80
81         missing = copy_from_user(dst, src, len);
82         if (missing) {
83                 memset(dst + len - missing, 0, missing);
84                 *err_ptr = -EFAULT;
85         }
86                 
87         return csum_partial(dst, len, sum);
88 }
89
90 extern inline unsigned int
91 csum_partial_copy_nocheck (const char *src, char *dst, int len, unsigned int sum)
92 {
93         memcpy(dst,src,len);
94         return csum_partial_inline(dst, len, sum);
95 }
96
97 /*
98  *      Fold a partial checksum without adding pseudo headers
99  */
100 extern inline unsigned short
101 csum_fold(unsigned int sum)
102 {
103         __asm__ __volatile__ (
104                 "    sr   3,3\n"   /* %0 = H*65536 + L */
105                 "    lr   2,%0\n"  /* %0 = H L, R2/R3 = H L / 0 0 */
106                 "    srdl 2,16\n"  /* %0 = H L, R2/R3 = 0 H / L 0 */
107                 "    alr  2,3\n"   /* %0 = H L, R2/R3 = L H / L 0 */
108                 "    alr  %0,2\n"  /* %0 = H+L+C L+H */
109                 "    srl  %0,16\n" /* %0 = H+L+C */
110                 : "+&d" (sum) : : "cc", "2", "3");
111         return ((unsigned short) ~sum);
112 }
113
114 /*
115  *      This is a version of ip_compute_csum() optimized for IP headers,
116  *      which always checksum on 4 octet boundaries.
117  *
118  */
119 extern inline unsigned short
120 ip_fast_csum(unsigned char *iph, unsigned int ihl)
121 {
122         unsigned long sum;
123
124         __asm__ __volatile__ (
125                 "    slgr %0,%0\n"   /* set sum to zero */
126                 "    lgr  2,%1\n"    /* address in gpr 2 */
127                 "    lgfr 3,%2\n"    /* length in gpr 3 */
128                 "0:  cksm %0,2\n"    /* do checksum on ints */
129                 "    jo   0b\n"
130                 : "=&d" (sum)
131                 : "d" (iph), "d" (ihl*4)
132                 : "cc", "2", "3" );
133         return csum_fold(sum);
134 }
135
136 /*
137  * computes the checksum of the TCP/UDP pseudo-header
138  * returns a 32-bit checksum
139  */
140 extern inline unsigned int 
141 csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr,
142                    unsigned short len, unsigned short proto,
143                    unsigned int sum)
144 {
145         __asm__ __volatile__ (
146                 "    lgfr  %0,%0\n"
147                 "    algr  %0,%1\n"  /* sum += saddr */
148                 "    brc   12,0f\n"
149                 "    aghi  %0,1\n"   /* add carry */
150                 "0:  algr  %0,%2\n"  /* sum += daddr */
151                 "    brc   12,1f\n"
152                 "    aghi  %0,1\n"   /* add carry */
153                 "1:  algfr %0,%3\n"  /* sum += (len<<16) + proto */
154                 "    brc   12,2f\n"
155                 "    aghi  %0,1\n"   /* add carry */
156                 "2:  srlg  0,%0,32\n"
157                 "    alr   %0,0\n"   /* fold to 32 bits */
158                 "    brc   12,3f\n"
159                 "    ahi   %0,1\n"   /* add carry */
160                 "3:  llgfr %0,%0"
161                 : "+&d" (sum)
162                 : "d" (saddr), "d" (daddr),
163                   "d" (((unsigned int) len<<16) + (unsigned int) proto)
164                 : "cc", "0" );
165         return sum;
166 }
167
168 /*
169  * computes the checksum of the TCP/UDP pseudo-header
170  * returns a 16-bit checksum, already complemented
171  */
172
173 extern inline unsigned short int
174 csum_tcpudp_magic(unsigned long saddr, unsigned long daddr,
175                   unsigned short len, unsigned short proto,
176                   unsigned int sum)
177 {
178         return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
179 }
180
181 /*
182  * this routine is used for miscellaneous IP-like checksums, mainly
183  * in icmp.c
184  */
185
186 extern inline unsigned short
187 ip_compute_csum(unsigned char * buff, int len)
188 {
189         return csum_fold(csum_partial_inline(buff, len, 0));
190 }
191
192 #endif /* _S390_CHECKSUM_H */
193
194