Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/tile/lib/checksum.c
10817 views
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
}
103
104