1 /*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33 /*-
34 * Copyright (c) 2001 by Thomas Moestl <tmm@FreeBSD.org>.
35 * All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
49 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
50 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
51 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
52 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
53 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
54 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
55 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 *
57 * from tahoe: in_cksum.c 1.2 86/01/05
58 * from: @(#)in_cksum.c 1.3 (Berkeley) 1/19/91
59 * from: FreeBSD: src/sys/i386/i386/in_cksum.c,v 1.22 2000/11/25
60 *
61 * $FreeBSD: releng/5.2/sys/sparc64/sparc64/in_cksum.c 86144 2001-11-06 20:05:01Z tmm $
62 */
63
64 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/mbuf.h>
67
68 #include <netinet/in.h>
69 #include <netinet/in_systm.h>
70 #include <netinet/ip.h>
71
72 #include <machine/in_cksum.h>
73
74 /*
75 * Checksum routine for Internet Protocol family headers.
76 *
77 * This routine is very heavily used in the network
78 * code and should be modified for each CPU to be as fast as possible.
79 *
80 * This implementation is a sparc64 version. Most code was taken over and
81 * adapted from the i386. Some optimizations were changed to achieve (hopefully)
82 * better performance.
83 * This uses 64 bit loads, but 32 bit additions due to the lack of a 64-bit
84 * add-with-carry operation.
85 */
86
87 /*
88 * REDUCE() is actually not used that frequently... maybe a C implementation
89 * would suffice.
90 */
91 #define REDUCE(sum, tmp) __asm __volatile( \
92 "sll %2, 16, %1\n" \
93 "addcc %2, %1, %0\n" \
94 "srl %0, 16, %0\n" \
95 "addc %0, 0, %0" : "=r" (sum), "=r" (tmp) : "" (sum))
96
97 /*
98 * Note that some of these macros depend on the flags being preserved between
99 * calls, so they should not be intermixed with other C statements.
100 */
101 #define LD64_ADD32(sum, tmp, addr, n, mod) __asm __volatile( \
102 "ldx [%3 + " #n "], %1\n" \
103 "add" #mod " %2, %1, %0\n" \
104 "srlx %1, 32, %1\n" \
105 "addccc %0, %1, %0" : "=r" (sum), "=r" (tmp) : "" (sum), "r" (addr))
106
107 #define LD32_ADD32(sum, tmp, addr, n, mod) __asm __volatile( \
108 "lduw [%3 + " #n "], %1\n" \
109 "add" #mod " %2, %1, %0\n" \
110 : "=r" (sum), "=r" (tmp) : "" (sum), "r" (addr))
111
112 #define MOP(sum) __asm __volatile( \
113 "addc %1, 0, %0" : "=r" (sum) : "" (sum))
114
115 u_short
116 in_cksum_skip(struct mbuf *m, int len, int skip)
117 {
118 u_short *w;
119 unsigned long tmp, sum = 0;
120 int mlen = 0;
121 int byte_swapped = 0;
122 u_short su = 0;
123
124 len -= skip;
125 for (; skip > 0 && m != NULL; m = m->m_next) {
126 if (m->m_len > skip) {
127 mlen = m->m_len - skip;
128 w = (u_short *)(mtod(m, u_char *) + skip);
129 goto skip_start;
130 } else
131 skip -= m->m_len;
132 }
133
134 for (; m != NULL && len > 0; m = m->m_next) {
135 if (m->m_len == 0)
136 continue;
137 w = mtod(m, u_short *);
138 if (mlen == -1) {
139 /*
140 * The first byte of this mbuf is the continuation
141 * of a word spanning between this mbuf and the
142 * last mbuf.
143 *
144 * The high order byte of su is already saved when
145 * scanning previous mbuf. sum was REDUCEd when we
146 * found mlen == -1
147 */
148 sum += su | *(u_char *)w;
149 w = (u_short *)((u_char *)w + 1);
150 mlen = m->m_len - 1;
151 len--;
152 } else
153 mlen = m->m_len;
154 skip_start:
155 if (len < mlen)
156 mlen = len;
157 len -= mlen;
158 /*
159 * Force to a 8-byte boundary first so that we can use
160 * LD64_ADD32.
161 */
162 if (((u_long)w & 7) != 0) {
163 REDUCE(sum, tmp);
164 if (((u_long)w & 1) != 0 && mlen >= 1) {
165 sum <<= 8;
166 su = *(u_char *)w << 8;
167 w = (u_short *)((u_char *)w + 1);
168 mlen--;
169 byte_swapped = 1;
170 }
171 if (((u_long)w & 2) != 0 && mlen >= 2) {
172 sum += *w++;
173 mlen -= 2;
174 }
175 if (((u_long)w & 4) != 0 && mlen >= 4) {
176 LD32_ADD32(sum, tmp, w, 0, cc);
177 MOP(sum);
178 w += 2;
179 mlen -= 4;
180 }
181 }
182 /*
183 * Do as much of the checksum as possible 64 bits at at time.
184 * In fact, this loop is unrolled to make overhead from
185 * branches &c small.
186 */
187 for (; mlen >= 64; mlen -= 64) {
188 LD64_ADD32(sum, tmp, w, 0, cc);
189 LD64_ADD32(sum, tmp, w, 8, ccc);
190 LD64_ADD32(sum, tmp, w, 16, ccc);
191 LD64_ADD32(sum, tmp, w, 24, ccc);
192 LD64_ADD32(sum, tmp, w, 32, ccc);
193 LD64_ADD32(sum, tmp, w, 40, ccc);
194 LD64_ADD32(sum, tmp, w, 48, ccc);
195 LD64_ADD32(sum, tmp, w, 56, ccc);
196 MOP(sum);
197 w += 32;
198 }
199 if (mlen >= 32) {
200 LD64_ADD32(sum, tmp, w, 0, cc);
201 LD64_ADD32(sum, tmp, w, 8, ccc);
202 LD64_ADD32(sum, tmp, w, 16, ccc);
203 LD64_ADD32(sum, tmp, w, 24, ccc);
204 MOP(sum);
205 w += 16;
206 mlen -= 32;
207 }
208 if (mlen >= 16) {
209 LD64_ADD32(sum, tmp, w, 0, cc);
210 LD64_ADD32(sum, tmp, w, 8, ccc);
211 MOP(sum);
212 w += 8;
213 mlen -= 16;
214 }
215 if (mlen >= 8) {
216 LD64_ADD32(sum, tmp, w, 0, cc);
217 MOP(sum);
218 w += 4;
219 mlen -= 8;
220 }
221 REDUCE(sum, tmp);
222 while ((mlen -= 2) >= 0)
223 sum += *w++;
224 if (byte_swapped) {
225 sum <<= 8;
226 byte_swapped = 0;
227 if (mlen == -1) {
228 su |= *(u_char *)w;
229 sum += su;
230 mlen = 0;
231 } else
232 mlen = -1;
233 } else if (mlen == -1) {
234 /*
235 * This mbuf has odd number of bytes.
236 * There could be a word split betwen
237 * this mbuf and the next mbuf.
238 * Save the last byte (to prepend to next mbuf).
239 */
240 su = *(u_char *)w << 8;
241 }
242 }
243
244 if (len)
245 printf("%s: out of data by %d\n", __func__, len);
246 if (mlen == -1) {
247 /* The last mbuf has odd # of bytes. Follow the
248 standard (the odd byte is shifted left by 8 bits) */
249 sum += su & 0xff00;
250 }
251 REDUCE(sum, tmp);
252 return (~sum & 0xffff);
253 }
Cache object: f93c4da2bee67af46907fd649f2c7a74
|