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); 87out: 88 return result; 89} 90