• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/arch/tile/lib/
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
19static 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);
100out:
101	return result;
102}
103