Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
checksum.c
Go to the documentation of this file.
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 
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 }