blob: c3ca3e64d9d906b453a6be36979ef8d5e976447a [file] [log] [blame]
Chris Metcalf867e3592010-05-28 23:09:12 -04001/*
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
Chris Metcalf867e3592010-05-28 23:09:12 -040019__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;
Chris Metcalf10104a12012-04-28 15:41:39 -040084 result = csum_long(result);
Chris Metcalf867e3592010-05-28 23:09:12 -040085 if (odd)
86 result = swab16(result);
87out:
88 return result;
89}