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 " lr 2,%1\n" /* address in gpr 2 */
41 " lr 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
72 extern inline unsigned int
73 csum_partial_copy_from_user(const char *src, char *dst,
74 int len, unsigned int sum, int *errp)
75 {
76 if (copy_from_user(dst, src, len)) {
77 *errp = -EFAULT;
78 memset(dst, 0, len);
79 return sum;
80 }
81 return csum_partial(dst, len, sum);
82 }
83
84 extern inline unsigned int
85 csum_partial_copy_nocheck (const char *src, char *dst, int len, unsigned int sum)
86 {
87 memcpy(dst,src,len);
88 return csum_partial_inline(dst, len, sum);
89 }
90
91 /*
92 * Fold a partial checksum without adding pseudo headers
93 */
94 #if 1
95 unsigned short csum_fold(unsigned int sum);
96 #else
97 extern inline unsigned short
98 csum_fold(unsigned int sum)
99 {
100 __asm__ __volatile__ (
101 " sr 3,3\n" /* %0 = H*65536 + L */
102 " lr 2,%0\n" /* %0 = H L, R2/R3 = H L / 0 0 */
103 " srdl 2,16\n" /* %0 = H L, R2/R3 = 0 H / L 0 */
104 " alr 2,3\n" /* %0 = H L, R2/R3 = L H / L 0 */
105 " alr %0,2\n" /* %0 = H+L+C L+H */
106 " srl %0,16\n" /* %0 = H+L+C */
107 : "+&d" (sum) : : "cc", "2", "3");
108 return ((unsigned short) ~sum);
109 }
110 #endif
111
112 /*
113 * This is a version of ip_compute_csum() optimized for IP headers,
114 * which always checksum on 4 octet boundaries.
115 *
116 */
117 extern inline unsigned short
118 ip_fast_csum(unsigned char *iph, unsigned int ihl)
119 {
120 unsigned long sum;
121
122 __asm__ __volatile__ (
123 " sr %0,%0\n" /* set sum to zero */
124 " lr 2,%1\n" /* address in gpr 2 */
125 " lr 3,%2\n" /* length in gpr 3 */
126 "0: cksm %0,2\n" /* do checksum on longs */
127 " jo 0b\n"
128 : "=&d" (sum)
129 : "d" (iph), "d" (ihl*4)
130 : "cc", "2", "3" );
131 return csum_fold(sum);
132 }
133
134 /*
135 * computes the checksum of the TCP/UDP pseudo-header
136 * returns a 32-bit checksum
137 */
138 extern inline unsigned int
139 csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr,
140 unsigned short len, unsigned short proto,
141 unsigned int sum)
142 {
143 __asm__ __volatile__ (
144 " sll %3,16\n"
145 " or %3,%4\n" /* newproto=proto<<16 in hiword, len in lowword */
146 " alr %1,%2\n" /* saddr+=daddr */
147 " brc 12,0f\n"
148 " ahi %1,1\n" /* add carry */
149 "0: alr %1,%3\n" /* add saddr+=newproto */
150 " brc 12,1f\n"
151 " ahi %1,1\n" /* add carry again */
152 "1: alr %0,%1\n" /* sum+=saddr */
153 " brc 12,2f\n"
154 " ahi %0,1\n" /* add carry again */
155 "2:"
156 : "+&d" (sum)
157 : "d" (saddr), "d" (daddr), "d" (proto), "d" (len)
158 : "cc" );
159 return sum;
160 }
161
162 /*
163 * computes the checksum of the TCP/UDP pseudo-header
164 * returns a 16-bit checksum, already complemented
165 */
166
167 extern inline unsigned short int
168 csum_tcpudp_magic(unsigned long saddr, unsigned long daddr,
169 unsigned short len, unsigned short proto,
170 unsigned int sum)
171 {
172 return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
173 }
174
175 /*
176 * this routine is used for miscellaneous IP-like checksums, mainly
177 * in icmp.c
178 */
179
180 extern inline unsigned short
181 ip_compute_csum(unsigned char * buff, int len)
182 {
183 return csum_fold(csum_partial(buff, len, 0));
184 }
185
186 #endif /* _S390_CHECKSUM_H */
187
188
189
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.