• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2010 Tilera Corporation. All Rights Reserved.
3  *
4  *   This program is free software; you can redistribute it and/or
5  *   modify it under the terms of the GNU General Public License
6  *   as published by the Free Software Foundation, version 2.
7  *
8  *   This program is distributed in the hope that it will be useful, but
9  *   WITHOUT ANY WARRANTY; without even the implied warranty of
10  *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11  *   NON INFRINGEMENT.  See the GNU General Public License for
12  *   more details.
13  * Support code for the main lib/checksum.c.
14  */
15 
16 #include <net/checksum.h>
17 #include <linux/module.h>
18 
do_csum(const unsigned char * buff,int len)19 __wsum do_csum(const unsigned char *buff, int len)
20 {
21 	int odd, count;
22 	unsigned long result = 0;
23 
24 	if (len <= 0)
25 		goto out;
26 	odd = 1 & (unsigned long) buff;
27 	if (odd) {
28 		result = (*buff << 8);
29 		len--;
30 		buff++;
31 	}
32 	count = len >> 1;		/* nr of 16-bit words.. */
33 	if (count) {
34 		if (2 & (unsigned long) buff) {
35 			result += *(const unsigned short *)buff;
36 			count--;
37 			len -= 2;
38 			buff += 2;
39 		}
40 		count >>= 1;		/* nr of 32-bit words.. */
41 		if (count) {
42 #ifdef __tilegx__
43 			if (4 & (unsigned long) buff) {
44 				unsigned int w = *(const unsigned int *)buff;
45 				result = __insn_v2sadau(result, w, 0);
46 				count--;
47 				len -= 4;
48 				buff += 4;
49 			}
50 			count >>= 1;		/* nr of 64-bit words.. */
51 #endif
52 
53 			/*
54 			 * This algorithm could wrap around for very
55 			 * large buffers, but those should be impossible.
56 			 */
57 			BUG_ON(count >= 65530);
58 
59 			while (count) {
60 				unsigned long w = *(const unsigned long *)buff;
61 				count--;
62 				buff += sizeof(w);
63 #ifdef __tilegx__
64 				result = __insn_v2sadau(result, w, 0);
65 #else
66 				result = __insn_sadah_u(result, w, 0);
67 #endif
68 			}
69 #ifdef __tilegx__
70 			if (len & 4) {
71 				unsigned int w = *(const unsigned int *)buff;
72 				result = __insn_v2sadau(result, w, 0);
73 				buff += 4;
74 			}
75 #endif
76 		}
77 		if (len & 2) {
78 			result += *(const unsigned short *) buff;
79 			buff += 2;
80 		}
81 	}
82 	if (len & 1)
83 		result += *buff;
84 	result = csum_long(result);
85 	if (odd)
86 		result = swab16(result);
87 out:
88 	return result;
89 }
90