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