upload tizen1.0 source
[kernel/linux-2.6.36.git] / arch / tile / lib / checksum.c
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 static inline unsigned int longto16(unsigned long x)
20 {
21         unsigned long ret;
22 #ifdef __tilegx__
23         ret = __insn_v2sadu(x, 0);
24         ret = __insn_v2sadu(ret, 0);
25 #else
26         ret = __insn_sadh_u(x, 0);
27         ret = __insn_sadh_u(ret, 0);
28 #endif
29         return ret;
30 }
31
32 __wsum do_csum(const unsigned char *buff, int len)
33 {
34         int odd, count;
35         unsigned long result = 0;
36
37         if (len <= 0)
38                 goto out;
39         odd = 1 & (unsigned long) buff;
40         if (odd) {
41                 result = (*buff << 8);
42                 len--;
43                 buff++;
44         }
45         count = len >> 1;               /* nr of 16-bit words.. */
46         if (count) {
47                 if (2 & (unsigned long) buff) {
48                         result += *(const unsigned short *)buff;
49                         count--;
50                         len -= 2;
51                         buff += 2;
52                 }
53                 count >>= 1;            /* nr of 32-bit words.. */
54                 if (count) {
55 #ifdef __tilegx__
56                         if (4 & (unsigned long) buff) {
57                                 unsigned int w = *(const unsigned int *)buff;
58                                 result = __insn_v2sadau(result, w, 0);
59                                 count--;
60                                 len -= 4;
61                                 buff += 4;
62                         }
63                         count >>= 1;            /* nr of 64-bit words.. */
64 #endif
65
66                         /*
67                          * This algorithm could wrap around for very
68                          * large buffers, but those should be impossible.
69                          */
70                         BUG_ON(count >= 65530);
71
72                         while (count) {
73                                 unsigned long w = *(const unsigned long *)buff;
74                                 count--;
75                                 buff += sizeof(w);
76 #ifdef __tilegx__
77                                 result = __insn_v2sadau(result, w, 0);
78 #else
79                                 result = __insn_sadah_u(result, w, 0);
80 #endif
81                         }
82 #ifdef __tilegx__
83                         if (len & 4) {
84                                 unsigned int w = *(const unsigned int *)buff;
85                                 result = __insn_v2sadau(result, w, 0);
86                                 buff += 4;
87                         }
88 #endif
89                 }
90                 if (len & 2) {
91                         result += *(const unsigned short *) buff;
92                         buff += 2;
93                 }
94         }
95         if (len & 1)
96                 result += *buff;
97         result = longto16(result);
98         if (odd)
99                 result = swab16(result);
100 out:
101         return result;
102 }