Assume natural alignment for IP & ether addrs
[akaros.git] / kern / src / net / ptclbsum.c
1  // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15 #include <endian.h>
16
17 static short endian = 1;
18 static uint8_t *aendian = (uint8_t *) & endian;
19 #define LITTLE  *aendian
20
21
22 #ifdef CONFIG_X86_64
23
24 /* $NetBSD: in_cksum.c,v 1.7 1997/09/02 13:18:15 thorpej Exp $ */
25
26 /*-
27  * Copyright (c) 1988, 1992, 1993
28  *      The Regents of the University of California.  All rights reserved.
29  * Copyright (c) 1996
30  *      Matt Thomas <matt@3am-software.com>
31  *
32  * Redistribution and use in source and binary forms, with or without
33  * modification, are permitted provided that the following conditions
34  * are met:
35  * 1. Redistributions of source code must retain the above copyright
36  *    notice, this list of conditions and the following disclaimer.
37  * 2. Redistributions in binary form must reproduce the above copyright
38  *    notice, this list of conditions and the following disclaimer in the
39  *    documentation and/or other materials provided with the distribution.
40  * 3. All advertising materials mentioning features or use of this software
41  *    must display the following acknowledgement:
42  *      This product includes software developed by the University of
43  *      California, Berkeley and its contributors.
44  * 4. Neither the name of the University nor the names of its contributors
45  *    may be used to endorse or promote products derived from this software
46  *    without specific prior written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58  * SUCH DAMAGE.
59  *
60  *      @(#)in_cksum.c  8.1 (Berkeley) 6/10/93
61  */
62
63 /*
64  * Checksum routine for Internet Protocol family headers
65  *    (Portable Alpha version).
66  *
67  * This routine is very heavily used in the network
68  * code and should be modified for each CPU to be as fast as possible.
69  */
70
71 #define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
72 #define REDUCE32                                                          \
73     {                                                                     \
74         q_util.q = sum;                                                   \
75         sum = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3];      \
76     }
77 #define REDUCE16                                                          \
78     {                                                                     \
79         q_util.q = sum;                                                   \
80         l_util.l = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
81         sum = l_util.s[0] + l_util.s[1];                                  \
82         ADDCARRY(sum);                                                    \
83     }
84
85 static const uint32_t in_masks[] = {
86         /*0 bytes*/ /*1 byte*/  /*2 bytes*/ /*3 bytes*/
87         0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF, /* offset 0 */
88         0x00000000, 0x0000FF00, 0x00FFFF00, 0xFFFFFF00, /* offset 1 */
89         0x00000000, 0x00FF0000, 0xFFFF0000, 0xFFFF0000, /* offset 2 */
90         0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, /* offset 3 */
91 };
92
93 union l_util {
94         uint16_t s[2];
95         uint32_t l;
96 };
97 union q_util {
98         uint16_t s[4];
99         uint32_t l[2];
100         uint64_t q;
101 };
102
103 static uint64_t
104 in_cksumdata(const void *buf, int len)
105 {
106         const uint32_t *lw = (const uint32_t *) buf;
107         uint64_t sum = 0;
108         uint64_t prefilled;
109         int offset;
110         union q_util q_util;
111
112         if ((3 & (long) lw) == 0 && len == 20) {
113              sum = (uint64_t) lw[0] + lw[1] + lw[2] + lw[3] + lw[4];
114              REDUCE32;
115              return sum;
116         }
117
118         if ((offset = 3 & (long) lw) != 0) {
119                 const uint32_t *masks = in_masks + (offset << 2);
120                 lw = (uint32_t *) (((long) lw) - offset);
121                 sum = *lw++ & masks[len >= 3 ? 3 : len];
122                 len -= 4 - offset;
123                 if (len <= 0) {
124                         REDUCE32;
125                         return sum;
126                 }
127         }
128 #if 0
129         /*
130          * Force to cache line boundary.
131          */
132         offset = 32 - (0x1f & (long) lw);
133         if (offset < 32 && len > offset) {
134                 len -= offset;
135                 if (4 & offset) {
136                         sum += (uint64_t) lw[0];
137                         lw += 1;
138                 }
139                 if (8 & offset) {
140                         sum += (uint64_t) lw[0] + lw[1];
141                         lw += 2;
142                 }
143                 if (16 & offset) {
144                         sum += (uint64_t) lw[0] + lw[1] + lw[2] + lw[3];
145                         lw += 4;
146                 }
147         }
148 #endif
149         /*
150          * access prefilling to start load of next cache line.
151          * then add current cache line
152          * save result of prefilling for loop iteration.
153          */
154         prefilled = lw[0];
155         while ((len -= 32) >= 4) {
156                 uint64_t prefilling = lw[8];
157                 sum += prefilled + lw[1] + lw[2] + lw[3]
158                         + lw[4] + lw[5] + lw[6] + lw[7];
159                 lw += 8;
160                 prefilled = prefilling;
161         }
162         if (len >= 0) {
163                 sum += prefilled + lw[1] + lw[2] + lw[3]
164                         + lw[4] + lw[5] + lw[6] + lw[7];
165                 lw += 8;
166         } else {
167                 len += 32;
168         }
169         while ((len -= 16) >= 0) {
170                 sum += (uint64_t) lw[0] + lw[1] + lw[2] + lw[3];
171                 lw += 4;
172         }
173         len += 16;
174         while ((len -= 4) >= 0) {
175                 sum += (uint64_t) *lw++;
176         }
177         len += 4;
178         if (len > 0)
179                 sum += (uint64_t) (in_masks[len] & *lw);
180         REDUCE32;
181         return sum;
182 }
183 uint16_t ptclbsum(uint8_t * addr, int len)
184 {
185         uint64_t sum = in_cksumdata(addr, len);
186         union q_util q_util;
187         union l_util l_util;
188         REDUCE16;
189         return cpu_to_be16(sum);
190 }
191 #else
192 uint16_t ptclbsum(uint8_t * addr, int len)
193 {
194         uint32_t losum, hisum, mdsum, x;
195         uint32_t t1, t2;
196
197         losum = 0;
198         hisum = 0;
199         mdsum = 0;
200
201         x = 0;
202         if ((uintptr_t) addr & 1) {
203                 if (len) {
204                         hisum += addr[0];
205                         len--;
206                         addr++;
207                 }
208                 x = 1;
209         }
210         while (len >= 16) {
211                 t1 = *(uint16_t *) (addr + 0);
212                 t2 = *(uint16_t *) (addr + 2);
213                 mdsum += t1;
214                 t1 = *(uint16_t *) (addr + 4);
215                 mdsum += t2;
216                 t2 = *(uint16_t *) (addr + 6);
217                 mdsum += t1;
218                 t1 = *(uint16_t *) (addr + 8);
219                 mdsum += t2;
220                 t2 = *(uint16_t *) (addr + 10);
221                 mdsum += t1;
222                 t1 = *(uint16_t *) (addr + 12);
223                 mdsum += t2;
224                 t2 = *(uint16_t *) (addr + 14);
225                 mdsum += t1;
226                 mdsum += t2;
227                 len -= 16;
228                 addr += 16;
229         }
230         while (len >= 2) {
231                 mdsum += *(uint16_t *) addr;
232                 len -= 2;
233                 addr += 2;
234         }
235         if (x) {
236                 if (len)
237                         losum += addr[0];
238                 if (LITTLE)
239                         losum += mdsum;
240                 else
241                         hisum += mdsum;
242         } else {
243                 if (len)
244                         hisum += addr[0];
245                 if (LITTLE)
246                         hisum += mdsum;
247                 else
248                         losum += mdsum;
249         }
250
251         losum += hisum >> 8;
252         losum += (hisum & 0xff) << 8;
253         while ((hisum = losum >> 16))
254                 losum = hisum + (losum & 0xffff);
255
256         return losum & 0xffff;
257 }
258 #endif