xref: /netbsd/sys/arch/powerpc/powerpc/in_cksum.c (revision bf9ec67e)
1 /*	$NetBSD: in_cksum.c,v 1.3 2001/06/13 06:01:50 simonb Exp $	*/
2 
3 /*
4  * Copyright 2001 Wasabi Systems, Inc.
5  * All rights reserved.
6  *
7  * Written by Simon Burge and Eduardo Horvath for Wasabi Systems, Inc.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed for the NetBSD Project by
20  *      Wasabi Systems, Inc.
21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22  *    or promote products derived from this software without specific prior
23  *    written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 #include <sys/param.h>
39 #include <sys/mbuf.h>
40 #include <sys/systm.h>
41 #include <netinet/in_systm.h>
42 #include <netinet/in.h>
43 #include <netinet/ip.h>
44 #include <netinet/ip_var.h>
45 
46 /*
47  * Checksum routine for Internet Protocol family headers.
48  *
49  * This routine is very heavily used in the network
50  * code and should be modified for each CPU to be as fast as possible.
51  *
52  * PowerPC version.
53  */
54 
55 #define	REDUCE1		sum = (sum & 0xffff) + (sum >> 16)
56 /* Two REDUCE1s is faster than REDUCE1; if (sum > 65535) sum -= 65536; */
57 #define	REDUCE		{ REDUCE1; REDUCE1; }
58 
59 static __inline__ int
60 in_cksum_internal(struct mbuf *m, int off, int len, u_int sum)
61 {
62 	uint8_t *w;
63 	int mlen = 0;
64 	int byte_swapped = 0;
65 
66 	union {
67 		uint8_t  c[2];
68 		uint16_t s;
69 	} s_util;
70 
71 	for (;m && len; m = m->m_next) {
72 		if (m->m_len == 0)
73 			continue;
74 		w = mtod(m, uint8_t *) + off;
75 
76 		/*
77 		 * 'off' can only be non-zero on the first pass of this
78 		 * loop when mlen != -1, so we don't need to worry about
79 		 * 'off' in the if clause below.
80 		 */
81 		if (mlen == -1) {
82 			/*
83 			 * The first byte of this mbuf is the continuation
84 			 * of a word spanning between this mbuf and the
85 			 * last mbuf.
86 			 *
87 			 * s_util.c[0] is already saved when scanning previous
88 			 * mbuf.
89 			 */
90 			s_util.c[1] = *w++;
91 			sum += s_util.s;
92 			mlen = m->m_len - 1;
93 			len--;
94 		} else {
95 			mlen = m->m_len - off;
96 			off = 0;
97 		}
98 		if (len < mlen)
99 			mlen = len;
100 		len -= mlen;
101 
102 		/*
103 		 * Force to a word boundary.
104 		 */
105 		if ((3 & (long) w) && (mlen > 0)) {
106 			if ((1 & (long) w) && (mlen > 0)) {
107 				REDUCE;
108 				sum <<= 8;
109 				s_util.c[0] = *w++;
110 				mlen--;
111 				byte_swapped = 1;
112 			}
113 			if ((2 & (long) w) && (mlen > 1)) {
114 				sum += *(uint16_t *)w;
115 				w += 2;
116 				mlen -= 2;
117 			}
118 		}
119 
120 		if (mlen >= 64) {
121 			register int n __asm("r0");
122 			uint8_t *tmpw;
123 
124 			n = mlen >> 6;
125 			tmpw = w - 4;
126 			asm volatile(
127 				"addze 7,7;"		/* clear carry */
128 				"mtctr %1;"		/* load loop count */
129 				"1:"
130 				"lwzu 7,4(%2);"		/* load current data word */
131 				"lwzu 8,4(%2);"
132 				"lwzu 9,4(%2);"
133 				"lwzu 10,4(%2);"
134 				"adde %0,%0,7;"		/* add to sum */
135 				"adde %0,%0,8;"
136 				"adde %0,%0,9;"
137 				"adde %0,%0,10;"
138 				"lwzu 7,4(%2);"
139 				"lwzu 8,4(%2);"
140 				"lwzu 9,4(%2);"
141 				"lwzu 10,4(%2);"
142 				"adde %0,%0,7;"
143 				"adde %0,%0,8;"
144 				"adde %0,%0,9;"
145 				"adde %0,%0,10;"
146 				"lwzu 7,4(%2);"
147 				"lwzu 8,4(%2);"
148 				"lwzu 9,4(%2);"
149 				"lwzu 10,4(%2);"
150 				"adde %0,%0,7;"
151 				"adde %0,%0,8;"
152 				"adde %0,%0,9;"
153 				"adde %0,%0,10;"
154 				"lwzu 7,4(%2);"
155 				"lwzu 8,4(%2);"
156 				"lwzu 9,4(%2);"
157 				"lwzu 10,4(%2);"
158 				"adde %0,%0,7;"
159 				"adde %0,%0,8;"
160 				"adde %0,%0,9;"
161 				"adde %0,%0,10;"
162 				"bdnz 1b;"		/* loop */
163 				"addze %0,%0;"		/* add carry bit */
164 				: "+r"(sum)
165 				: "r"(n), "r"(tmpw)
166 				: "7", "8", "9", "10");	/* clobber r7, r8, r9, r10 */
167 			w += n * 64;
168 			mlen -= n * 64;
169 		}
170 
171 		if (mlen >= 8) {
172 			register int n __asm("r0");
173 			uint8_t *tmpw;
174 
175 			n = mlen >> 3;
176 			tmpw = w - 4;
177 			asm volatile(
178 				"addze %1,%1;"		/* clear carry */
179 				"mtctr %1;"		/* load loop count */
180 				"1:"
181 				"lwzu 7,4(%2);"		/* load current data word */
182 				"lwzu 8,4(%2);"
183 				"adde %0,%0,7;"		/* add to sum */
184 				"adde %0,%0,8;"
185 				"bdnz 1b;"		/* loop */
186 				"addze %0,%0;"		/* add carry bit */
187 				: "+r"(sum)
188 				: "r"(n), "r"(tmpw)
189 				: "7", "8");		/* clobber r7, r8 */
190 			w += n * 8;
191 			mlen -= n * 8;
192 		}
193 
194 		if (mlen == 0 && byte_swapped == 0)
195 			continue;
196 		REDUCE;
197 
198 		while ((mlen -= 2) >= 0) {
199 			sum += *(uint16_t *)w;
200 			w += 2;
201 		}
202 
203 		if (byte_swapped) {
204 			REDUCE;
205 			sum <<= 8;
206 			byte_swapped = 0;
207 			if (mlen == -1) {
208 				s_util.c[1] = *w;
209 				sum += s_util.s;
210 				mlen = 0;
211 			} else
212 				mlen = -1;
213 		} else if (mlen == -1)
214 			s_util.c[0] = *w;
215 	}
216 	if (len)
217 		printf("cksum: out of data\n");
218 	if (mlen == -1) {
219 		/* The last mbuf has odd # of bytes. Follow the
220 		   standard (the odd byte may be shifted left by 8 bits
221 		   or not as determined by endian-ness of the machine) */
222 		s_util.c[1] = 0;
223 		sum += s_util.s;
224 	}
225 	REDUCE;
226 	return (~sum & 0xffff);
227 }
228 
229 int
230 in_cksum(struct mbuf *m, int len)
231 {
232 	return (in_cksum_internal(m, 0, len, 0));
233 }
234 
235 int
236 in4_cksum(struct mbuf *m, uint8_t nxt, int off, int len)
237 {
238 	uint16_t *w;
239 	u_int sum = 0;
240 	struct ipovly ipov;
241 
242 	if (nxt != 0) {
243 		/* pseudo header */
244 		memset(&ipov, 0, sizeof(ipov));
245 		ipov.ih_len = htons(len);
246 		ipov.ih_pr = nxt;
247 		ipov.ih_src = mtod(m, struct ip *)->ip_src;
248 		ipov.ih_dst = mtod(m, struct ip *)->ip_dst;
249 		w = (uint16_t *)&ipov;
250 		/* assumes sizeof(ipov) == 20 */
251 		sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; sum += w[4];
252 		sum += w[5]; sum += w[6]; sum += w[7]; sum += w[8]; sum += w[9];
253 	}
254 
255 	/* skip unnecessary part */
256 	while (m && off > 0) {
257 		if (m->m_len > off)
258 			break;
259 		off -= m->m_len;
260 		m = m->m_next;
261 	}
262 
263 	return (in_cksum_internal(m, off, len, sum));
264 }
265