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