Home | History | Annotate | Line # | Download | only in powerpc
      1 /*	$NetBSD: in_cksum.c,v 1.10 2005/12/24 23:24:01 perry 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/cdefs.h>
     39 __KERNEL_RCSID(0, "$NetBSD: in_cksum.c,v 1.10 2005/12/24 23:24:01 perry Exp $");
     40 
     41 #include <sys/param.h>
     42 #include <sys/mbuf.h>
     43 #include <sys/systm.h>
     44 #include <netinet/in_systm.h>
     45 #include <netinet/in.h>
     46 #include <netinet/ip.h>
     47 #include <netinet/ip_var.h>
     48 
     49 /*
     50  * Checksum routine for Internet Protocol family headers.
     51  *
     52  * This routine is very heavily used in the network
     53  * code and should be modified for each CPU to be as fast as possible.
     54  *
     55  * PowerPC version.
     56  */
     57 
     58 #define	REDUCE1		sum = (sum & 0xffff) + (sum >> 16)
     59 /* Two REDUCE1s is faster than REDUCE1; if (sum > 65535) sum -= 65536; */
     60 #define	REDUCE		{ REDUCE1; REDUCE1; }
     61 
     62 static inline int
     63 in_cksum_internal(struct mbuf *m, int off, int len, u_int sum)
     64 {
     65 	uint8_t *w;
     66 	int mlen = 0;
     67 	int byte_swapped = 0;
     68 	int n;
     69 
     70 	union {
     71 		uint8_t  c[2];
     72 		uint16_t s;
     73 	} s_util;
     74 
     75 	for (;m && len; m = m->m_next) {
     76 		if (m->m_len == 0)
     77 			continue;
     78 		w = mtod(m, uint8_t *) + off;
     79 
     80 		/*
     81 		 * 'off' can only be non-zero on the first pass of this
     82 		 * loop when mlen != -1, so we don't need to worry about
     83 		 * 'off' in the if clause below.
     84 		 */
     85 		if (mlen == -1) {
     86 			/*
     87 			 * The first byte of this mbuf is the continuation
     88 			 * of a word spanning between this mbuf and the
     89 			 * last mbuf.
     90 			 *
     91 			 * s_util.c[0] is already saved when scanning previous
     92 			 * mbuf.
     93 			 */
     94 			s_util.c[1] = *w++;
     95 			sum += s_util.s;
     96 			mlen = m->m_len - 1;
     97 			len--;
     98 		} else {
     99 			mlen = m->m_len - off;
    100 			off = 0;
    101 		}
    102 		if (len < mlen)
    103 			mlen = len;
    104 		len -= mlen;
    105 
    106 		/*
    107 		 * Force to a word boundary.
    108 		 */
    109 		if ((3 & (long) w) && (mlen > 0)) {
    110 			if ((1 & (long) w)) {
    111 				REDUCE;
    112 				sum <<= 8;
    113 				s_util.c[0] = *w++;
    114 				mlen--;
    115 				byte_swapped = 1;
    116 			}
    117 			if ((2 & (long) w) && (mlen > 1)) {
    118 				/*
    119 				 * Since the `sum' may contain full 32 bit
    120 				 * value, we can't simply add any value.
    121 				 */
    122 				__asm volatile(
    123 				    "lhz 7,0(%1);"	/* load current data
    124 							   half word */
    125 				    "addc %0,%0,7;"	/* add to sum */
    126 				    "addze %0,%0;"	/* add carry bit */
    127 				    : "+r"(sum)
    128 				    : "b"(w)
    129 				    : "7");		/* clobber r7 */
    130 				w += 2;
    131 				mlen -= 2;
    132 			}
    133 		}
    134 
    135 		if (mlen >= 64) {
    136 			n = mlen >> 6;
    137 			__asm volatile(
    138 			    "addic 0,0,0;"		/* clear carry */
    139 			    "mtctr %1;"			/* load loop count */
    140 			    "1:"
    141 			    "lwz 7,4(%2);"		/* load current data
    142 							   word */
    143 			    "lwz 8,8(%2);"
    144 			    "lwz 9,12(%2);"
    145 			    "lwz 10,16(%2);"
    146 			    "adde %0,%0,7;"		/* add to sum */
    147 			    "adde %0,%0,8;"
    148 			    "adde %0,%0,9;"
    149 			    "adde %0,%0,10;"
    150 			    "lwz 7,20(%2);"
    151 			    "lwz 8,24(%2);"
    152 			    "lwz 9,28(%2);"
    153 			    "lwz 10,32(%2);"
    154 			    "adde %0,%0,7;"
    155 			    "adde %0,%0,8;"
    156 			    "adde %0,%0,9;"
    157 			    "adde %0,%0,10;"
    158 			    "lwz 7,36(%2);"
    159 			    "lwz 8,40(%2);"
    160 			    "lwz 9,44(%2);"
    161 			    "lwz 10,48(%2);"
    162 			    "adde %0,%0,7;"
    163 			    "adde %0,%0,8;"
    164 			    "adde %0,%0,9;"
    165 			    "adde %0,%0,10;"
    166 			    "lwz 7,52(%2);"
    167 			    "lwz 8,56(%2);"
    168 			    "lwz 9,60(%2);"
    169 			    "lwzu 10,64(%2);"
    170 			    "adde %0,%0,7;"
    171 			    "adde %0,%0,8;"
    172 			    "adde %0,%0,9;"
    173 			    "adde %0,%0,10;"
    174 			    "bdnz 1b;"			/* loop */
    175 			    "addze %0,%0;"		/* add carry bit */
    176 			    : "+r"(sum)
    177 			    : "r"(n), "b"(w - 4)
    178 			    : "7", "8", "9", "10");	/* clobber r7, r8, r9,
    179 							   r10 */
    180 			w += n * 64;
    181 			mlen -= n * 64;
    182 		}
    183 
    184 		if (mlen >= 8) {
    185 			n = mlen >> 3;
    186 			__asm volatile(
    187 			    "addic 0,0,0;"		/* clear carry */
    188 			    "mtctr %1;"			/* load loop count */
    189 			    "1:"
    190 			    "lwz 7,4(%2);"		/* load current data
    191 							   word */
    192 			    "lwzu 8,8(%2);"
    193 			    "adde %0,%0,7;"		/* add to sum */
    194 			    "adde %0,%0,8;"
    195 			    "bdnz 1b;"			/* loop */
    196 			    "addze %0,%0;"		/* add carry bit */
    197 			    : "+r"(sum)
    198 			    : "r"(n), "b"(w - 4)
    199 			    : "7", "8");		/* clobber r7, r8 */
    200 			w += n * 8;
    201 			mlen -= n * 8;
    202 		}
    203 
    204 		if (mlen == 0 && byte_swapped == 0)
    205 			continue;
    206 		REDUCE;
    207 
    208 		while ((mlen -= 2) >= 0) {
    209 			sum += *(uint16_t *)w;
    210 			w += 2;
    211 		}
    212 
    213 		if (byte_swapped) {
    214 			REDUCE;
    215 			sum <<= 8;
    216 			byte_swapped = 0;
    217 			if (mlen == -1) {
    218 				s_util.c[1] = *w;
    219 				sum += s_util.s;
    220 				mlen = 0;
    221 			} else
    222 				mlen = -1;
    223 		} else if (mlen == -1)
    224 			s_util.c[0] = *w;
    225 	}
    226 	if (len)
    227 		printf("cksum: out of data\n");
    228 	if (mlen == -1) {
    229 		/* The last mbuf has odd # of bytes. Follow the
    230 		   standard (the odd byte may be shifted left by 8 bits
    231 		   or not as determined by endian-ness of the machine) */
    232 		s_util.c[1] = 0;
    233 		sum += s_util.s;
    234 	}
    235 	REDUCE;
    236 	return (~sum & 0xffff);
    237 }
    238 
    239 int
    240 in_cksum(struct mbuf *m, int len)
    241 {
    242 
    243 	return (in_cksum_internal(m, 0, len, 0));
    244 }
    245 
    246 int
    247 in4_cksum(struct mbuf *m, uint8_t nxt, int off, int len)
    248 {
    249 	uint16_t *w;
    250 	u_int sum = 0;
    251 	union {
    252 		struct ipovly ipov;
    253 		u_int16_t w[10];
    254 	} u;
    255 
    256 	if (nxt != 0) {
    257 		/* pseudo header */
    258 		memset(&u.ipov, 0, sizeof(u.ipov));
    259 		u.ipov.ih_len = htons(len);
    260 		u.ipov.ih_pr = nxt;
    261 		u.ipov.ih_src = mtod(m, struct ip *)->ip_src;
    262 		u.ipov.ih_dst = mtod(m, struct ip *)->ip_dst;
    263 		w = u.w;
    264 		/* assumes sizeof(ipov) == 20 */
    265 		sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; sum += w[4];
    266 		sum += w[5]; sum += w[6]; sum += w[7]; sum += w[8]; sum += w[9];
    267 	}
    268 
    269 	/* skip unnecessary part */
    270 	while (m && off > 0) {
    271 		if (m->m_len > off)
    272 			break;
    273 		off -= m->m_len;
    274 		m = m->m_next;
    275 	}
    276 
    277 	return (in_cksum_internal(m, off, len, sum));
    278 }
    279